Skip to content

Commit df67a27

Browse files
authored
Merge pull request #2641 from plotly/cone-traces
3D cone traces
2 parents fb75158 + 2c08357 commit df67a27

28 files changed

+130274
-74
lines changed

lib/cone.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright 2012-2018, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
module.exports = require('../src/traces/cone');

lib/index-gl3d.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ var Plotly = require('./core');
1313
Plotly.register([
1414
require('./scatter3d'),
1515
require('./surface'),
16-
require('./mesh3d')
16+
require('./mesh3d'),
17+
require('./cone')
1718
]);
1819

1920
module.exports = Plotly;

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Plotly.register([
2626
require('./scatter3d'),
2727
require('./surface'),
2828
require('./mesh3d'),
29+
require('./cone'),
2930

3031
require('./scattergeo'),
3132
require('./choropleth'),

package-lock.json

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
"es6-promise": "^3.0.2",
7171
"fast-isnumeric": "^1.1.1",
7272
"font-atlas-sdf": "^1.3.3",
73+
"gl-cone3d": "^v1.0.0",
7374
"gl-contour2d": "^1.1.4",
7475
"gl-error3d": "^1.0.7",
7576
"gl-heatmap2d": "^1.0.4",

src/lib/gl_format_color.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
'use strict';
1111

1212
var isNumeric = require('fast-isnumeric');
13+
var tinycolor = require('tinycolor2');
1314
var rgba = require('color-normalize');
1415

1516
var Colorscale = require('../components/colorscale');
@@ -85,4 +86,21 @@ function formatColor(containerIn, opacityIn, len) {
8586
return colorOut;
8687
}
8788

88-
module.exports = formatColor;
89+
function parseColorScale(colorscale, alpha) {
90+
if(alpha === undefined) alpha = 1;
91+
92+
return colorscale.map(function(elem) {
93+
var index = elem[0];
94+
var color = tinycolor(elem[1]);
95+
var rgb = color.toRgb();
96+
return {
97+
index: index,
98+
rgb: [rgb.r, rgb.g, rgb.b, alpha]
99+
};
100+
});
101+
}
102+
103+
module.exports = {
104+
formatColor: formatColor,
105+
parseColorScale: parseColorScale
106+
};

src/plots/gl3d/scene.js

+68-37
Original file line numberDiff line numberDiff line change
@@ -71,28 +71,53 @@ function render(scene) {
7171
trace = lastPicked.data;
7272
var ptNumber = selection.index;
7373
var hoverinfo = Fx.castHoverinfo(trace, scene.fullLayout, ptNumber);
74+
var hoverinfoParts = hoverinfo.split('+');
75+
var isHoverinfoAll = hoverinfo === 'all';
7476

75-
var xVal = formatter('xaxis', selection.traceCoordinate[0]),
76-
yVal = formatter('yaxis', selection.traceCoordinate[1]),
77-
zVal = formatter('zaxis', selection.traceCoordinate[2]);
77+
var xVal = formatter('xaxis', selection.traceCoordinate[0]);
78+
var yVal = formatter('yaxis', selection.traceCoordinate[1]);
79+
var zVal = formatter('zaxis', selection.traceCoordinate[2]);
7880

79-
if(hoverinfo !== 'all') {
80-
var hoverinfoParts = hoverinfo.split('+');
81+
if(!isHoverinfoAll) {
8182
if(hoverinfoParts.indexOf('x') === -1) xVal = undefined;
8283
if(hoverinfoParts.indexOf('y') === -1) yVal = undefined;
8384
if(hoverinfoParts.indexOf('z') === -1) zVal = undefined;
8485
if(hoverinfoParts.indexOf('text') === -1) selection.textLabel = undefined;
8586
if(hoverinfoParts.indexOf('name') === -1) lastPicked.name = undefined;
8687
}
8788

89+
var tx;
90+
91+
if(trace.type === 'cone') {
92+
var coneTx = [];
93+
if(isHoverinfoAll || hoverinfoParts.indexOf('u') !== -1) {
94+
coneTx.push('u: ' + formatter('xaxis', selection.traceCoordinate[3]));
95+
}
96+
if(isHoverinfoAll || hoverinfoParts.indexOf('v') !== -1) {
97+
coneTx.push('v: ' + formatter('yaxis', selection.traceCoordinate[4]));
98+
}
99+
if(isHoverinfoAll || hoverinfoParts.indexOf('w') !== -1) {
100+
coneTx.push('w: ' + formatter('zaxis', selection.traceCoordinate[5]));
101+
}
102+
if(isHoverinfoAll || hoverinfoParts.indexOf('norm') !== -1) {
103+
coneTx.push('norm: ' + selection.traceCoordinate[6].toPrecision(3));
104+
}
105+
if(selection.textLabel) {
106+
coneTx.push(selection.textLabel);
107+
}
108+
tx = coneTx.join('<br>');
109+
} else {
110+
tx = selection.textLabel;
111+
}
112+
88113
if(scene.fullSceneLayout.hovermode) {
89114
Fx.loneHover({
90115
x: (0.5 + 0.5 * pdata[0] / pdata[3]) * width,
91116
y: (0.5 - 0.5 * pdata[1] / pdata[3]) * height,
92117
xLabel: xVal,
93118
yLabel: yVal,
94119
zLabel: zVal,
95-
text: selection.textLabel,
120+
text: tx,
96121
name: lastPicked.name,
97122
color: Fx.castHoverOption(trace, ptNumber, 'bgcolor') || lastPicked.color,
98123
borderColor: Fx.castHoverOption(trace, ptNumber, 'bordercolor'),
@@ -306,41 +331,44 @@ proto.recoverContext = function() {
306331

307332
var axisProperties = [ 'xaxis', 'yaxis', 'zaxis' ];
308333

309-
function coordinateBound(axis, coord, len, d, bounds, calendar) {
310-
var x;
311-
if(!Lib.isArrayOrTypedArray(coord)) {
312-
bounds[0][d] = Math.min(bounds[0][d], 0);
313-
bounds[1][d] = Math.max(bounds[1][d], len - 1);
314-
return;
315-
}
334+
function computeTraceBounds(scene, trace, bounds) {
335+
var sceneLayout = scene.fullSceneLayout;
316336

317-
for(var i = 0; i < (len || coord.length); ++i) {
318-
if(Lib.isArrayOrTypedArray(coord[i])) {
319-
for(var j = 0; j < coord[i].length; ++j) {
320-
x = axis.d2l(coord[i][j], 0, calendar);
321-
if(!isNaN(x) && isFinite(x)) {
322-
bounds[0][d] = Math.min(bounds[0][d], x);
323-
bounds[1][d] = Math.max(bounds[1][d], x);
337+
for(var d = 0; d < 3; d++) {
338+
var axisName = axisProperties[d];
339+
var axLetter = axisName.charAt(0);
340+
var ax = sceneLayout[axisName];
341+
var coords = trace[axLetter];
342+
var calendar = trace[axLetter + 'calendar'];
343+
var len = trace['_' + axLetter + 'length'];
344+
345+
if(!Lib.isArrayOrTypedArray(coords)) {
346+
bounds[0][d] = Math.min(bounds[0][d], 0);
347+
bounds[1][d] = Math.max(bounds[1][d], len - 1);
348+
} else {
349+
var v;
350+
351+
for(var i = 0; i < (len || coords.length); i++) {
352+
if(Lib.isArrayOrTypedArray(coords[i])) {
353+
for(var j = 0; j < coords[i].length; ++j) {
354+
v = ax.d2l(coords[i][j], 0, calendar);
355+
if(!isNaN(v) && isFinite(v)) {
356+
bounds[0][d] = Math.min(bounds[0][d], v);
357+
bounds[1][d] = Math.max(bounds[1][d], v);
358+
}
359+
}
360+
} else {
361+
v = ax.d2l(coords[i], 0, calendar);
362+
if(!isNaN(v) && isFinite(v)) {
363+
bounds[0][d] = Math.min(bounds[0][d], v);
364+
bounds[1][d] = Math.max(bounds[1][d], v);
365+
}
324366
}
325367
}
326368
}
327-
else {
328-
x = axis.d2l(coord[i], 0, calendar);
329-
if(!isNaN(x) && isFinite(x)) {
330-
bounds[0][d] = Math.min(bounds[0][d], x);
331-
bounds[1][d] = Math.max(bounds[1][d], x);
332-
}
333-
}
334369
}
335370
}
336371

337-
function computeTraceBounds(scene, trace, bounds) {
338-
var sceneLayout = scene.fullSceneLayout;
339-
coordinateBound(sceneLayout.xaxis, trace.x, trace._xlength, 0, bounds, trace.xcalendar);
340-
coordinateBound(sceneLayout.yaxis, trace.y, trace._ylength, 1, bounds, trace.ycalendar);
341-
coordinateBound(sceneLayout.zaxis, trace.z, trace._zlength, 2, bounds, trace.zcalendar);
342-
}
343-
344372
proto.plot = function(sceneData, fullLayout, layout) {
345373

346374
// Save parameters
@@ -477,9 +505,12 @@ proto.plot = function(sceneData, fullLayout, layout) {
477505
var axLetter = axis._name.charAt(0);
478506

479507
for(j = 0; j < objects.length; j++) {
480-
var objBounds = objects[j].bounds;
481-
sceneBounds[0][i] = Math.min(sceneBounds[0][i], objBounds[0][i] / dataScale[i]);
482-
sceneBounds[1][i] = Math.max(sceneBounds[1][i], objBounds[1][i] / dataScale[i]);
508+
var obj = objects[j];
509+
var objBounds = obj.bounds;
510+
var pad = obj._trace.data._pad || 0;
511+
512+
sceneBounds[0][i] = Math.min(sceneBounds[0][i], objBounds[0][i] / dataScale[i] - pad);
513+
sceneBounds[1][i] = Math.max(sceneBounds[1][i], objBounds[1][i] / dataScale[i] + pad);
483514
}
484515

485516
for(j = 0; j < annotations.length; j++) {

0 commit comments

Comments
 (0)