'use strict'; var conePlot = require('../../../stackgl_modules').gl_cone3d; var createConeMesh = require('../../../stackgl_modules').gl_cone3d.createConeMesh; var simpleMap = require('../../lib').simpleMap; var parseColorScale = require('../../lib/gl_format_color').parseColorScale; var extractOpts = require('../../components/colorscale').extractOpts; var isArrayOrTypedArray = require('../../lib').isArrayOrTypedArray; var zip3 = require('../../plots/gl3d/zip3'); function Cone(scene, uid) { this.scene = scene; this.uid = uid; this.mesh = null; this.data = null; } var proto = Cone.prototype; proto.handlePick = function(selection) { if(selection.object === this.mesh) { var selectIndex = selection.index = selection.data.index; var xx = this.data.x[selectIndex]; var yy = this.data.y[selectIndex]; var zz = this.data.z[selectIndex]; var uu = this.data.u[selectIndex]; var vv = this.data.v[selectIndex]; var ww = this.data.w[selectIndex]; selection.traceCoordinate = [ xx, yy, zz, uu, vv, ww, Math.sqrt(uu * uu + vv * vv + ww * ww) ]; var text = this.data.hovertext || this.data.text; if(isArrayOrTypedArray(text) && text[selectIndex] !== undefined) { selection.textLabel = text[selectIndex]; } else if(text) { selection.textLabel = text; } return true; } }; var axisName2scaleIndex = {xaxis: 0, yaxis: 1, zaxis: 2}; var anchor2coneOffset = {tip: 1, tail: 0, cm: 0.25, center: 0.5}; var anchor2coneSpan = {tip: 1, tail: 1, cm: 0.75, center: 0.5}; function convert(scene, trace) { var sceneLayout = scene.fullSceneLayout; var dataScale = scene.dataScale; var coneOpts = {}; function toDataCoords(arr, axisName) { var ax = sceneLayout[axisName]; var scale = dataScale[axisName2scaleIndex[axisName]]; return simpleMap(arr, function(v) { return ax.d2l(v) * scale; }); } coneOpts.vectors = zip3( toDataCoords(trace.u, 'xaxis'), toDataCoords(trace.v, 'yaxis'), toDataCoords(trace.w, 'zaxis'), trace._len ); coneOpts.positions = zip3( toDataCoords(trace.x, 'xaxis'), toDataCoords(trace.y, 'yaxis'), toDataCoords(trace.z, 'zaxis'), trace._len ); var cOpts = extractOpts(trace); coneOpts.colormap = parseColorScale(trace); coneOpts.vertexIntensityBounds = [cOpts.min / trace._normMax, cOpts.max / trace._normMax]; coneOpts.coneOffset = anchor2coneOffset[trace.anchor]; var sizemode = trace.sizemode; if(sizemode === 'scaled') { // unitless sizeref coneOpts.coneSize = trace.sizeref || 0.5; } else if(sizemode === 'absolute') { // sizeref here has unit of velocity coneOpts.coneSize = trace.sizeref && trace._normMax ? trace.sizeref / trace._normMax : 0.5; } else if(sizemode === 'raw') { coneOpts.coneSize = trace.sizeref; } coneOpts.coneSizemode = sizemode; var meshData = conePlot(coneOpts); // pass gl-mesh3d lighting attributes var lp = trace.lightposition; meshData.lightPosition = [lp.x, lp.y, lp.z]; meshData.ambient = trace.lighting.ambient; meshData.diffuse = trace.lighting.diffuse; meshData.specular = trace.lighting.specular; meshData.roughness = trace.lighting.roughness; meshData.fresnel = trace.lighting.fresnel; meshData.opacity = trace.opacity; // stash autorange pad value trace._pad = anchor2coneSpan[trace.anchor] * meshData.vectorScale * meshData.coneScale * trace._normMax; return meshData; } proto.update = function(data) { this.data = data; var meshData = convert(this.scene, data); this.mesh.update(meshData); }; proto.dispose = function() { this.scene.glplot.remove(this.mesh); this.mesh.dispose(); }; function createConeTrace(scene, data) { var gl = scene.glplot.gl; var meshData = convert(scene, data); var mesh = createConeMesh(gl, meshData); var cone = new Cone(scene, data.uid); cone.mesh = mesh; cone.data = data; mesh._trace = cone; scene.glplot.add(mesh); return cone; } module.exports = createConeTrace;