Skip to content

Commit 7e2448e

Browse files
authored
Merge pull request #855 from plotly/gl2d-reset-axes
Improve gl2d interactions
2 parents f21a522 + d918264 commit 7e2448e

File tree

8 files changed

+121
-43
lines changed

8 files changed

+121
-43
lines changed

src/plots/gl2d/camera.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ function createCamera(scene) {
3232
plot = scene.glplot,
3333
result = new Camera2D(element, plot);
3434

35+
function unSetAutoRange() {
36+
scene.xaxis.autorange = false;
37+
scene.yaxis.autorange = false;
38+
}
39+
3540
result.mouseListener = mouseChange(element, function(buttons, x, y) {
3641
var xrange = scene.xaxis.range,
3742
yrange = scene.yaxis.range,
@@ -84,7 +89,7 @@ function createCamera(scene) {
8489
else if(result.boxEnabled) {
8590
updateRange(xrange, result.boxStart[0], result.boxEnd[0]);
8691
updateRange(yrange, result.boxStart[1], result.boxEnd[1]);
87-
92+
unSetAutoRange();
8893
result.boxEnabled = false;
8994
}
9095
break;
@@ -104,7 +109,7 @@ function createCamera(scene) {
104109
yrange[1] += dy;
105110

106111
result.lastInputTime = Date.now();
107-
112+
unSetAutoRange();
108113
scene.cameraChanged();
109114
}
110115
break;
@@ -142,6 +147,7 @@ function createCamera(scene) {
142147
yrange[1] = (yrange[1] - cy) * scale + cy;
143148

144149
result.lastInputTime = Date.now();
150+
unSetAutoRange();
145151
scene.cameraChanged();
146152
break;
147153
}

src/plots/gl2d/scene2d.js

+47-36
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,9 @@ var relayoutCallback = function(scene) {
275275
yrange = scene.yaxis.range;
276276

277277
// Update the layout on the DIV
278+
scene.graphDiv.layout.xaxis.autorange = scene.xaxis.autorange;
278279
scene.graphDiv.layout.xaxis.range = xrange.slice(0);
280+
scene.graphDiv.layout.yaxis.autorange = scene.yaxis.autorange;
279281
scene.graphDiv.layout.yaxis.range = yrange.slice(0);
280282

281283
// Make a meaningful value to be passed on to the possible 'plotly_relayout' subscriber(s)
@@ -310,7 +312,6 @@ proto.cameraChanged = function() {
310312
};
311313

312314
proto.destroy = function() {
313-
314315
var traces = this.traces;
315316

316317
if(traces) {
@@ -334,10 +335,9 @@ proto.plot = function(fullData, calcData, fullLayout) {
334335
var glplot = this.glplot,
335336
pixelRatio = this.pixelRatio;
336337

337-
var i, j, trace;
338-
339338
this.fullLayout = fullLayout;
340339
this.updateAxes(fullLayout);
340+
this.updateTraces(fullData, calcData);
341341

342342
var width = fullLayout.width,
343343
height = fullLayout.height,
@@ -351,34 +351,6 @@ proto.plot = function(fullData, calcData, fullLayout) {
351351
canvas.height = pixelHeight;
352352
}
353353

354-
// update traces
355-
for(i = 0; i < fullData.length; ++i) {
356-
var fullTrace = fullData[i],
357-
calcTrace = calcData[i];
358-
trace = this.traces[fullTrace.uid];
359-
360-
if(trace) trace.update(fullTrace, calcTrace);
361-
else {
362-
trace = fullTrace._module.plot(this, fullTrace, calcTrace);
363-
}
364-
365-
this.traces[fullTrace.uid] = trace;
366-
}
367-
368-
// remove empty traces
369-
var traceIds = Object.keys(this.traces);
370-
371-
trace_id_loop:
372-
for(i = 0; i < traceIds.length; ++i) {
373-
for(j = 0; j < calcData.length; ++j) {
374-
if(calcData[j][0].trace.uid === traceIds[i]) continue trace_id_loop;
375-
}
376-
377-
trace = this.traces[traceIds[i]];
378-
trace.dispose();
379-
delete this.traces[traceIds[i]];
380-
}
381-
382354
var options = this.glplotOptions;
383355
options.merge(fullLayout);
384356
options.screenBox = [0, 0, width, height];
@@ -404,16 +376,18 @@ proto.plot = function(fullData, calcData, fullLayout) {
404376
bounds[0] = bounds[1] = Infinity;
405377
bounds[2] = bounds[3] = -Infinity;
406378

407-
traceIds = Object.keys(this.traces);
379+
var traceIds = Object.keys(this.traces);
380+
var ax, i;
381+
408382
for(i = 0; i < traceIds.length; ++i) {
409-
trace = this.traces[traceIds[i]];
383+
var traceObj = this.traces[traceIds[i]];
384+
410385
for(var k = 0; k < 2; ++k) {
411-
bounds[k] = Math.min(bounds[k], trace.bounds[k]);
412-
bounds[k + 2] = Math.max(bounds[k + 2], trace.bounds[k + 2]);
386+
bounds[k] = Math.min(bounds[k], traceObj.bounds[k]);
387+
bounds[k + 2] = Math.max(bounds[k + 2], traceObj.bounds[k + 2]);
413388
}
414389
}
415390

416-
var ax;
417391
for(i = 0; i < 2; ++i) {
418392
if(bounds[i] > bounds[i + 2]) {
419393
bounds[i] = -1;
@@ -439,6 +413,43 @@ proto.plot = function(fullData, calcData, fullLayout) {
439413
this.glplot.draw();
440414
};
441415

416+
proto.updateTraces = function(fullData, calcData) {
417+
var traceIds = Object.keys(this.traces);
418+
var i, j, fullTrace;
419+
420+
// remove empty traces
421+
trace_id_loop:
422+
for(i = 0; i < traceIds.length; i++) {
423+
var oldUid = traceIds[i],
424+
oldTrace = this.traces[oldUid];
425+
426+
for(j = 0; j < fullData.length; j++) {
427+
fullTrace = fullData[j];
428+
429+
if(fullTrace.uid === oldUid && fullTrace.type === oldTrace.type) {
430+
continue trace_id_loop;
431+
}
432+
}
433+
434+
oldTrace.dispose();
435+
delete this.traces[oldUid];
436+
}
437+
438+
// update / create trace objects
439+
for(i = 0; i < fullData.length; i++) {
440+
fullTrace = fullData[i];
441+
442+
var calcTrace = calcData[i],
443+
traceObj = this.traces[fullTrace.uid];
444+
445+
if(traceObj) traceObj.update(fullTrace, calcTrace);
446+
else {
447+
traceObj = fullTrace._module.plot(this, fullTrace, calcTrace);
448+
this.traces[fullTrace.uid] = traceObj;
449+
}
450+
}
451+
};
452+
442453
proto.draw = function() {
443454
if(this.stopped) return;
444455

src/traces/contourgl/convert.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
var createContour2D = require('gl-contour2d');
1313
var createHeatmap2D = require('gl-heatmap2d');
1414

15+
var Axes = require('../../plots/cartesian/axes');
1516
var makeColorMap = require('../contour/make_color_map');
1617
var str2RGBArray = require('../../lib/str2rgbarray');
1718

1819

1920
function Contour(scene, uid) {
2021
this.scene = scene;
2122
this.uid = uid;
23+
this.type = 'contourgl';
2224

2325
this.name = '';
2426
this.hoverinfo = 'all';
@@ -96,7 +98,6 @@ proto.update = function(fullTrace, calcTrace) {
9698
this.contourOptions.x = this.heatmapOptions.x = calcPt.x;
9799
this.contourOptions.y = this.heatmapOptions.y = calcPt.y;
98100

99-
100101
// pass on fill information
101102
if(fullTrace.contours.coloring === 'fill') {
102103
colorOptions = convertColorScale(fullTrace, {fill: true});
@@ -118,6 +119,10 @@ proto.update = function(fullTrace, calcTrace) {
118119

119120
this.contour.update(this.contourOptions);
120121
this.heatmap.update(this.heatmapOptions);
122+
123+
// expand axes
124+
Axes.expand(this.scene.xaxis, calcPt.x);
125+
Axes.expand(this.scene.yaxis, calcPt.y);
121126
};
122127

123128
proto.dispose = function() {

src/traces/heatmap/calc.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module.exports = function calc(gd, trace) {
2929
ya = Axes.getFromId(gd, trace.yaxis || 'y'),
3030
isContour = Plots.traceIs(trace, 'contour'),
3131
isHist = Plots.traceIs(trace, 'histogram'),
32+
isGL2D = Plots.traceIs(trace, 'gl2d'),
3233
zsmooth = isContour ? 'best' : trace.zsmooth,
3334
x,
3435
x0,
@@ -112,8 +113,11 @@ module.exports = function calc(gd, trace) {
112113
yIn = trace.ytype === 'scaled' ? '' : trace.y,
113114
yArray = makeBoundArray(trace, yIn, y0, dy, z.length, ya);
114115

115-
Axes.expand(xa, xArray);
116-
Axes.expand(ya, yArray);
116+
// handled in gl2d convert step
117+
if(!isGL2D) {
118+
Axes.expand(xa, xArray);
119+
Axes.expand(ya, yArray);
120+
}
117121

118122
var cd0 = {x: xArray, y: yArray, z: z};
119123

src/traces/heatmapgl/convert.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
'use strict';
1111

1212
var createHeatmap2D = require('gl-heatmap2d');
13-
13+
var Axes = require('../../plots/cartesian/axes');
1414
var str2RGBArray = require('../../lib/str2rgbarray');
1515

1616

1717
function Heatmap(scene, uid) {
1818
this.scene = scene;
1919
this.uid = uid;
20+
this.type = 'heatmapgl';
2021

2122
this.name = '';
2223
this.hoverinfo = 'all';
@@ -87,6 +88,9 @@ proto.update = function(fullTrace, calcTrace) {
8788
this.textLabels = [].concat.apply([], fullTrace.text);
8889

8990
this.heatmap.update(this.options);
91+
92+
Axes.expand(this.scene.xaxis, calcPt.x);
93+
Axes.expand(this.scene.yaxis, calcPt.y);
9094
};
9195

9296
proto.dispose = function() {

src/traces/scattergl/convert.js

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ var AXES = ['xaxis', 'yaxis'];
3232
function LineWithMarkers(scene, uid) {
3333
this.scene = scene;
3434
this.uid = uid;
35+
this.type = 'scattergl';
3536

3637
this.pickXData = [];
3738
this.pickYData = [];

test/jasmine/tests/gl2d_scatterplot_contour_test.js

+43-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ var Plotly = require('@lib/index');
44
var Lib = require('@src/lib');
55
var d3 = require('d3');
66

7-
// contourgl is not part of the dist plotly.js bundle initially
7+
// heatmapgl & contourgl is not part of the dist plotly.js bundle initially
88
Plotly.register(
9+
require('@lib/heatmapgl'),
910
require('@lib/contourgl')
1011
);
1112

@@ -208,4 +209,45 @@ describe('contourgl plots', function() {
208209
mock.data[0].line = {smoothing: 0};
209210
makePlot(gd, mock, done);
210211
});
212+
213+
it('should update properly', function(done) {
214+
var mock = plotDataElliptical(0);
215+
var scene2d;
216+
217+
Plotly.plot(gd, mock.data, mock.layout).then(function() {
218+
scene2d = gd._fullLayout._plots.xy._scene2d;
219+
220+
expect(scene2d.traces[mock.data[0].uid].type).toEqual('contourgl');
221+
expect(scene2d.xaxis._min).toEqual([{ val: -1, pad: 0}]);
222+
expect(scene2d.xaxis._max).toEqual([{ val: 1, pad: 0}]);
223+
224+
return Plotly.relayout(gd, 'xaxis.range', [0, -10]);
225+
}).then(function() {
226+
expect(scene2d.xaxis._min).toEqual([]);
227+
expect(scene2d.xaxis._max).toEqual([]);
228+
229+
return Plotly.relayout(gd, 'xaxis.autorange', true);
230+
}).then(function() {
231+
expect(scene2d.xaxis._min).toEqual([{ val: -1, pad: 0}]);
232+
expect(scene2d.xaxis._max).toEqual([{ val: 1, pad: 0}]);
233+
234+
return Plotly.restyle(gd, 'type', 'heatmapgl');
235+
}).then(function() {
236+
expect(scene2d.traces[mock.data[0].uid].type).toEqual('heatmapgl');
237+
expect(scene2d.xaxis._min).toEqual([{ val: -1, pad: 0}]);
238+
expect(scene2d.xaxis._max).toEqual([{ val: 1, pad: 0}]);
239+
240+
return Plotly.relayout(gd, 'xaxis.range', [0, -10]);
241+
}).then(function() {
242+
expect(scene2d.xaxis._min).toEqual([]);
243+
expect(scene2d.xaxis._max).toEqual([]);
244+
245+
return Plotly.relayout(gd, 'xaxis.autorange', true);
246+
}).then(function() {
247+
expect(scene2d.xaxis._min).toEqual([{ val: -1, pad: 0}]);
248+
expect(scene2d.xaxis._max).toEqual([{ val: 1, pad: 0}]);
249+
250+
done();
251+
});
252+
});
211253
});

test/jasmine/tests/gl_plot_interact_test.js

+5
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ describe('Test gl plot interactions', function() {
248248
var newX = [-0.23224043715846995, 4.811895754518705];
249249
var newY = [-1.2962655110623016, 4.768255474123081];
250250

251+
expect(gd.layout.xaxis.autorange).toBe(true);
252+
expect(gd.layout.yaxis.autorange).toBe(true);
251253
expect(gd.layout.xaxis.range).toBeCloseToArray(originalX, precision);
252254
expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
253255

@@ -270,6 +272,9 @@ describe('Test gl plot interactions', function() {
270272

271273
mouseEvent('mousemove', 220, 200, {buttons: 1});
272274

275+
expect(gd.layout.xaxis.autorange).toBe(false);
276+
expect(gd.layout.yaxis.autorange).toBe(false);
277+
273278
expect(gd.layout.xaxis.range).toBeCloseToArray(newX, precision);
274279
expect(gd.layout.yaxis.range).toBeCloseToArray(originalY, precision);
275280

0 commit comments

Comments
 (0)