Skip to content

Commit 87b17dc

Browse files
committed
Merge branch 'master' into bump-surface3d
2 parents d10c8cd + 1dbaea5 commit 87b17dc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1706
-371
lines changed

devtools/test_dashboard/index.html

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
<script type="text/javascript" src="../../dist/extras/mathjax/MathJax.js?config=TeX-AMS-MML_SVG"></script>
2323
<script id="source" type="text/javascript" src="../../build/plotly.js"></script>
24-
<script type="text/javascript" src="../../test/image/strict-d3.js" charset="utf-8"></script>
2524
<script type="text/javascript" src="../../build/test_dashboard-bundle.js"></script>
2625
</body>
2726
</html>

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"gl-shader": "4.2.0",
8484
"gl-spikes2d": "^1.0.1",
8585
"gl-surface3d": "^1.3.1",
86+
"has-hover": "^1.0.0",
8687
"mapbox-gl": "^0.22.0",
8788
"matrix-camera-controller": "^2.1.3",
8889
"mouse-change": "^1.4.0",

src/components/dragelement/index.js

+52-18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
'use strict';
1111

12+
var mouseOffset = require('mouse-event-offset');
13+
var hasHover = require('has-hover');
14+
1215
var Plotly = require('../../plotly');
1316
var Lib = require('../../lib');
1417

@@ -61,18 +64,25 @@ dragElement.init = function init(options) {
6164
startX,
6265
startY,
6366
newMouseDownTime,
67+
cursor,
6468
dragCover,
6569
initialTarget;
6670

6771
if(!gd._mouseDownTime) gd._mouseDownTime = 0;
6872

73+
options.element.style.pointerEvents = 'all';
74+
75+
options.element.onmousedown = onStart;
76+
options.element.ontouchstart = onStart;
77+
6978
function onStart(e) {
7079
// make dragging and dragged into properties of gd
7180
// so that others can look at and modify them
7281
gd._dragged = false;
7382
gd._dragging = true;
74-
startX = e.clientX;
75-
startY = e.clientY;
83+
var offset = pointerOffset(e);
84+
startX = offset[0];
85+
startY = offset[1];
7686
initialTarget = e.target;
7787

7888
newMouseDownTime = (new Date()).getTime();
@@ -88,20 +98,30 @@ dragElement.init = function init(options) {
8898

8999
if(options.prepFn) options.prepFn(e, startX, startY);
90100

91-
dragCover = coverSlip();
92-
93-
dragCover.onmousemove = onMove;
94-
dragCover.onmouseup = onDone;
95-
dragCover.onmouseout = onDone;
101+
if(hasHover) {
102+
dragCover = coverSlip();
103+
dragCover.style.cursor = window.getComputedStyle(options.element).cursor;
104+
}
105+
else {
106+
// document acts as a dragcover for mobile, bc we can't create dragcover dynamically
107+
dragCover = document;
108+
cursor = window.getComputedStyle(document.documentElement).cursor;
109+
document.documentElement.style.cursor = window.getComputedStyle(options.element).cursor;
110+
}
96111

97-
dragCover.style.cursor = window.getComputedStyle(options.element).cursor;
112+
dragCover.addEventListener('mousemove', onMove);
113+
dragCover.addEventListener('mouseup', onDone);
114+
dragCover.addEventListener('mouseout', onDone);
115+
dragCover.addEventListener('touchmove', onMove);
116+
dragCover.addEventListener('touchend', onDone);
98117

99118
return Lib.pauseEvent(e);
100119
}
101120

102121
function onMove(e) {
103-
var dx = e.clientX - startX,
104-
dy = e.clientY - startY,
122+
var offset = pointerOffset(e),
123+
dx = offset[0] - startX,
124+
dy = offset[1] - startY,
105125
minDrag = options.minDrag || constants.MINDRAG;
106126

107127
if(Math.abs(dx) < minDrag) dx = 0;
@@ -117,10 +137,19 @@ dragElement.init = function init(options) {
117137
}
118138

119139
function onDone(e) {
120-
dragCover.onmousemove = null;
121-
dragCover.onmouseup = null;
122-
dragCover.onmouseout = null;
123-
Lib.removeElement(dragCover);
140+
dragCover.removeEventListener('mousemove', onMove);
141+
dragCover.removeEventListener('mouseup', onDone);
142+
dragCover.removeEventListener('mouseout', onDone);
143+
dragCover.removeEventListener('touchmove', onMove);
144+
dragCover.removeEventListener('touchend', onDone);
145+
146+
if(hasHover) {
147+
Lib.removeElement(dragCover);
148+
}
149+
else if(cursor) {
150+
dragCover.documentElement.style.cursor = cursor;
151+
cursor = null;
152+
}
124153

125154
if(!gd._dragging) {
126155
gd._dragged = false;
@@ -143,12 +172,13 @@ dragElement.init = function init(options) {
143172
e2 = new MouseEvent('click', e);
144173
}
145174
catch(err) {
175+
var offset = pointerOffset(e);
146176
e2 = document.createEvent('MouseEvents');
147177
e2.initMouseEvent('click',
148178
e.bubbles, e.cancelable,
149179
e.view, e.detail,
150180
e.screenX, e.screenY,
151-
e.clientX, e.clientY,
181+
offset[0], offset[1],
152182
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
153183
e.button, e.relatedTarget);
154184
}
@@ -162,9 +192,6 @@ dragElement.init = function init(options) {
162192

163193
return Lib.pauseEvent(e);
164194
}
165-
166-
options.element.onmousedown = onStart;
167-
options.element.style.pointerEvents = 'all';
168195
};
169196

170197
function coverSlip() {
@@ -191,3 +218,10 @@ function finishDrag(gd) {
191218
gd._dragging = false;
192219
if(gd._replotPending) Plotly.plot(gd);
193220
}
221+
222+
function pointerOffset(e) {
223+
return mouseOffset(
224+
e.changedTouches ? e.changedTouches[0] : e,
225+
document.body
226+
);
227+
}

src/components/drawing/index.js

+22-5
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,8 @@ drawing.setRect = function(s, x, y, w, h) {
6868
* false if selection could not get translated
6969
*/
7070
drawing.translatePoint = function(d, sel, xa, ya) {
71-
// put xp and yp into d if pixel scaling is already done
72-
var x = d.xp || xa.c2p(d.x),
73-
y = d.yp || ya.c2p(d.y);
71+
var x = xa.c2p(d.x);
72+
var y = ya.c2p(d.y);
7473

7574
if(isNumeric(x) && isNumeric(y) && sel.node()) {
7675
// for multiline text this works better
@@ -86,10 +85,28 @@ drawing.translatePoint = function(d, sel, xa, ya) {
8685
return true;
8786
};
8887

89-
drawing.translatePoints = function(s, xa, ya, trace) {
88+
drawing.translatePoints = function(s, xa, ya) {
9089
s.each(function(d) {
9190
var sel = d3.select(this);
92-
drawing.translatePoint(d, sel, xa, ya, trace);
91+
drawing.translatePoint(d, sel, xa, ya);
92+
});
93+
};
94+
95+
drawing.hideOutsideRangePoint = function(d, sel, xa, ya) {
96+
sel.attr(
97+
'display',
98+
xa.isPtWithinRange(d) && ya.isPtWithinRange(d) ? null : 'none'
99+
);
100+
};
101+
102+
drawing.hideOutsideRangePoints = function(points, subplot) {
103+
if(!subplot._hasClipOnAxisFalse) return;
104+
105+
var xa = subplot.xaxis;
106+
var ya = subplot.yaxis;
107+
108+
points.each(function(d) {
109+
drawing.hideOutsideRangePoint(d, d3.select(this), xa, ya);
93110
});
94111
};
95112

src/components/errorbars/plot.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
var d3 = require('d3');
1313
var isNumeric = require('fast-isnumeric');
1414

15+
var Drawing = require('../drawing');
1516
var subTypes = require('../../traces/scatter/subtypes');
1617

1718
module.exports = function plot(traces, plotinfo, transitionOpts) {
1819
var isNew;
1920

20-
var xa = plotinfo.xaxis,
21-
ya = plotinfo.yaxis;
21+
var xa = plotinfo.xaxis;
22+
var ya = plotinfo.yaxis;
2223

2324
var hasAnimation = transitionOpts && transitionOpts.duration > 0;
2425

@@ -60,6 +61,8 @@ module.exports = function plot(traces, plotinfo, transitionOpts) {
6061
.style('opacity', 1);
6162
}
6263

64+
Drawing.setClipUrl(errorbars, plotinfo.layerClipId);
65+
6366
errorbars.each(function(d) {
6467
var errorbar = d3.select(this);
6568
var coords = errorCoords(d, xa, ya);

src/components/fx/layout_defaults.js

+8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
2828
else hovermodeDflt = 'closest';
2929

3030
coerce('hovermode', hovermodeDflt);
31+
32+
// if only mapbox subplots is present on graph,
33+
// reset 'zoom' dragmode to 'pan' until 'zoom' is implemented,
34+
// so that the correct modebar button is active
35+
if(layoutOut._has('mapbox') && layoutOut._basePlotModules.length === 1 &&
36+
layoutOut.dragmode === 'zoom') {
37+
layoutOut.dragmode = 'pan';
38+
}
3139
};
3240

3341
function isHoriz(fullData) {

src/components/modebar/manage.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
var Axes = require('../../plots/cartesian/axes');
1313
var scatterSubTypes = require('../../traces/scatter/subtypes');
14+
var Registry = require('../../registry');
1415

1516
var createModeBar = require('./modebar');
1617
var modeBarButtons = require('./buttons');
@@ -78,7 +79,8 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) {
7879
hasGeo = fullLayout._has('geo'),
7980
hasPie = fullLayout._has('pie'),
8081
hasGL2D = fullLayout._has('gl2d'),
81-
hasTernary = fullLayout._has('ternary');
82+
hasTernary = fullLayout._has('ternary'),
83+
hasMapbox = fullLayout._has('mapbox');
8284

8385
var groups = [];
8486

@@ -121,7 +123,10 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) {
121123
if(((hasCartesian || hasGL2D) && !allAxesFixed) || hasTernary) {
122124
dragModeGroup = ['zoom2d', 'pan2d'];
123125
}
124-
if((hasCartesian || hasTernary || hasGL2D) && isSelectable(fullData)) {
126+
if(hasMapbox) {
127+
dragModeGroup = ['pan2d'];
128+
}
129+
if(isSelectable(fullData)) {
125130
dragModeGroup.push('select2d');
126131
dragModeGroup.push('lasso2d');
127132
}
@@ -173,7 +178,7 @@ function isSelectable(fullData) {
173178

174179
if(!trace._module || !trace._module.selectPoints) continue;
175180

176-
if(trace.type === 'scatter' || trace.type === 'scatterternary' || trace.type === 'scattergl') {
181+
if(Registry.traceIs(trace, 'scatter-like')) {
177182
if(scatterSubTypes.hasMarkers(trace) || scatterSubTypes.hasText(trace)) {
178183
selectable = true;
179184
}

src/constants/interactions.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@ module.exports = {
1818

1919
// ms between first mousedown and 2nd mouseup to constitute dblclick...
2020
// we don't seem to have access to the system setting
21-
DBLCLICKDELAY: 300
21+
DBLCLICKDELAY: 300,
22+
23+
// opacity dimming fraction for points that are not in selection
24+
DESELECTDIM: 0.2
2225
};

src/lib/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ lib.minExtend = function(obj1, obj2) {
458458
for(i = 0; i < keys.length; i++) {
459459
k = keys[i];
460460
v = obj1[k];
461-
if(k.charAt(0) === '_' || typeof v === 'function' || k === 'glTrace') continue;
461+
if(k.charAt(0) === '_' || typeof v === 'function') continue;
462462
else if(k === 'module') objOut[k] = v;
463463
else if(Array.isArray(v)) objOut[k] = v.slice(0, arrayLen);
464464
else if(v && (typeof v === 'object')) objOut[k] = lib.minExtend(obj1[k], obj2[k]);

src/plot_api/plot_api.js

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
var d3 = require('d3');
1414
var isNumeric = require('fast-isnumeric');
15+
var hasHover = require('has-hover');
1516

1617
var Plotly = require('../plotly');
1718
var Lib = require('../lib');
@@ -425,6 +426,11 @@ function setPlotContext(gd, config) {
425426
context.showLink = false;
426427
context.displayModeBar = false;
427428
}
429+
430+
// make sure hover-only devices have mode bar visible
431+
if(context.displayModeBar === 'hover' && !hasHover) {
432+
context.displayModeBar = true;
433+
}
428434
}
429435

430436
function plotPolar(gd, data, layout) {

src/plot_api/subroutines.js

+36-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var Drawing = require('../components/drawing');
2020
var Titles = require('../components/titles');
2121
var ModeBar = require('../components/modebar');
2222
var initInteractions = require('../plots/cartesian/graph_interact');
23+
var cartesianConstants = require('../plots/cartesian/constants');
2324

2425
exports.layoutStyles = function(gd) {
2526
return Lib.syncOrAsync([Plots.doAutoMargin, exports.lsInner], gd);
@@ -164,9 +165,31 @@ exports.lsInner = function(gd) {
164165
'height': ya._length
165166
});
166167

167-
168168
plotinfo.plot.call(Drawing.setTranslate, xa._offset, ya._offset);
169-
plotinfo.plot.call(Drawing.setClipUrl, plotinfo.clipId);
169+
170+
var plotClipId;
171+
var layerClipId;
172+
173+
if(plotinfo._hasClipOnAxisFalse) {
174+
plotClipId = null;
175+
layerClipId = plotinfo.clipId;
176+
} else {
177+
plotClipId = plotinfo.clipId;
178+
layerClipId = null;
179+
}
180+
181+
Drawing.setClipUrl(plotinfo.plot, plotClipId);
182+
183+
for(i = 0; i < cartesianConstants.traceLayerClasses.length; i++) {
184+
var layer = cartesianConstants.traceLayerClasses[i];
185+
if(layer !== 'scatterlayer') {
186+
plotinfo.plot.selectAll('g.' + layer).call(Drawing.setClipUrl, layerClipId);
187+
}
188+
}
189+
190+
// stash layer clipId value (null or same as clipId)
191+
// to DRY up Drawing.setClipUrl calls downstream
192+
plotinfo.layerClipId = layerClipId;
170193

171194
var xlw = Drawing.crispRound(gd, xa.linewidth, 1),
172195
ylw = Drawing.crispRound(gd, ya.linewidth, 1),
@@ -378,21 +401,27 @@ exports.doTicksRelayout = function(gd) {
378401

379402
exports.doModeBar = function(gd) {
380403
var fullLayout = gd._fullLayout;
381-
var subplotIds, scene, i;
404+
var subplotIds, subplotObj, i;
382405

383406
ModeBar.manage(gd);
384407
initInteractions(gd);
385408

386409
subplotIds = Plots.getSubplotIds(fullLayout, 'gl3d');
387410
for(i = 0; i < subplotIds.length; i++) {
388-
scene = fullLayout[subplotIds[i]]._scene;
389-
scene.updateFx(fullLayout.dragmode, fullLayout.hovermode);
411+
subplotObj = fullLayout[subplotIds[i]]._scene;
412+
subplotObj.updateFx(fullLayout.dragmode, fullLayout.hovermode);
390413
}
391414

392415
subplotIds = Plots.getSubplotIds(fullLayout, 'gl2d');
393416
for(i = 0; i < subplotIds.length; i++) {
394-
scene = fullLayout._plots[subplotIds[i]]._scene2d;
395-
scene.updateFx(fullLayout.dragmode);
417+
subplotObj = fullLayout._plots[subplotIds[i]]._scene2d;
418+
subplotObj.updateFx(fullLayout.dragmode);
419+
}
420+
421+
subplotIds = Plots.getSubplotIds(fullLayout, 'mapbox');
422+
for(i = 0; i < subplotIds.length; i++) {
423+
subplotObj = fullLayout[subplotIds[i]]._subplot;
424+
subplotObj.updateFx(fullLayout);
396425
}
397426

398427
return Plots.previousPromises(gd);

0 commit comments

Comments
 (0)