Skip to content

Commit 893588d

Browse files
committed
Merge branch 'master' into axis-lines
2 parents 16bae9c + f17c0af commit 893588d

Some content is hidden

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

43 files changed

+961
-214
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-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"gl-select-box": "^1.0.1",
8383
"gl-shader": "4.2.0",
8484
"gl-spikes2d": "^1.0.1",
85-
"gl-surface3d": "^1.3.0",
85+
"gl-surface3d": "^1.3.1",
8686
"has-hover": "^1.0.0",
8787
"mapbox-gl": "^0.22.0",
8888
"matrix-camera-controller": "^2.1.3",

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/plot_api/subroutines.js

+25-3
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);
@@ -167,10 +168,31 @@ exports.lsInner = function(gd) {
167168
'height': ya._length
168169
});
169170

171+
Drawing.setTranslate(plotinfo.plot, xa._offset, ya._offset);
170172

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

175197
var xIsFree = !xa._anchorAxis;
176198
var showFreeX = xIsFree && !freeFinished[xa._id];

src/plots/cartesian/constants.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,26 @@ module.exports = {
4949

5050
// last resort axis ranges for x and y axes if we have no data
5151
DFLTRANGEX: [-1, 6],
52-
DFLTRANGEY: [-1, 4]
52+
DFLTRANGEY: [-1, 4],
53+
54+
// Layers to keep trace types in the right order.
55+
// from back to front:
56+
// 1. heatmaps, 2D histos and contour maps
57+
// 2. bars / 1D histos
58+
// 3. errorbars for bars and scatter
59+
// 4. scatter
60+
// 5. box plots
61+
traceLayerClasses: [
62+
'imagelayer',
63+
'maplayer',
64+
'barlayer',
65+
'carpetlayer',
66+
'boxlayer',
67+
'scatterlayer'
68+
],
69+
70+
layerValue2layerClass: {
71+
'above traces': 'above',
72+
'below traces': 'below'
73+
}
5374
};

src/plots/cartesian/dragbox.js

+15-12
Original file line numberDiff line numberDiff line change
@@ -743,23 +743,26 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
743743
var plotDx = xa2._offset - clipDx / xScaleFactor2,
744744
plotDy = ya2._offset - clipDy / yScaleFactor2;
745745

746-
fullLayout._defs.selectAll('#' + subplot.clipId)
746+
fullLayout._defs.select('#' + subplot.clipId + '> rect')
747747
.call(Drawing.setTranslate, clipDx, clipDy)
748748
.call(Drawing.setScale, xScaleFactor2, yScaleFactor2);
749749

750+
var scatterPoints = subplot.plot.select('.scatterlayer').selectAll('.points');
751+
750752
subplot.plot
751753
.call(Drawing.setTranslate, plotDx, plotDy)
752-
.call(Drawing.setScale, 1 / xScaleFactor2, 1 / yScaleFactor2)
753-
754-
// This is specifically directed at scatter traces, applying an inverse
755-
// scale to individual points to counteract the scale of the trace
756-
// as a whole:
757-
.select('.scatterlayer').selectAll('.points').selectAll('.point')
758-
.call(Drawing.setPointGroupScale, xScaleFactor2, yScaleFactor2);
759-
760-
subplot.plot.select('.scatterlayer')
761-
.selectAll('.points').selectAll('.textpoint')
762-
.call(Drawing.setTextPointsScale, xScaleFactor2, yScaleFactor2);
754+
.call(Drawing.setScale, 1 / xScaleFactor2, 1 / yScaleFactor2);
755+
756+
// This is specifically directed at scatter traces, applying an inverse
757+
// scale to individual points to counteract the scale of the trace
758+
// as a whole:
759+
scatterPoints.selectAll('.point')
760+
.call(Drawing.setPointGroupScale, xScaleFactor2, yScaleFactor2)
761+
.call(Drawing.hideOutsideRangePoints, subplot);
762+
763+
scatterPoints.selectAll('.textpoint')
764+
.call(Drawing.setTextPointsScale, xScaleFactor2, yScaleFactor2)
765+
.call(Drawing.hideOutsideRangePoints, subplot);
763766
}
764767
}
765768

src/plots/cartesian/index.js

+47-29
Original file line numberDiff line numberDiff line change
@@ -265,24 +265,10 @@ function makeSubplotData(gd) {
265265
}
266266

267267
function makeSubplotLayer(plotinfo) {
268-
var plotgroup = plotinfo.plotgroup,
269-
id = plotinfo.id;
270-
271-
// Layers to keep plot types in the right order.
272-
// from back to front:
273-
// 1. heatmaps, 2D histos and contour maps
274-
// 2. bars / 1D histos
275-
// 3. errorbars for bars and scatter
276-
// 4. scatter
277-
// 5. box plots
278-
function joinPlotLayers(parent) {
279-
joinLayer(parent, 'g', 'imagelayer');
280-
joinLayer(parent, 'g', 'maplayer');
281-
joinLayer(parent, 'g', 'barlayer');
282-
joinLayer(parent, 'g', 'carpetlayer');
283-
joinLayer(parent, 'g', 'boxlayer');
284-
joinLayer(parent, 'g', 'scatterlayer');
285-
}
268+
var plotgroup = plotinfo.plotgroup;
269+
var id = plotinfo.id;
270+
var xLayer = constants.layerValue2layerClass[plotinfo.xaxis.layer];
271+
var yLayer = constants.layerValue2layerClass[plotinfo.yaxis.layer];
286272

287273
if(!plotinfo.mainplot) {
288274
var backLayer = joinLayer(plotgroup, 'g', 'layer-subplot');
@@ -295,19 +281,36 @@ function makeSubplotLayer(plotinfo) {
295281
plotinfo.zerolinelayer = joinLayer(plotgroup, 'g', 'zerolinelayer');
296282
plotinfo.overzero = joinLayer(plotgroup, 'g', 'overzero');
297283

284+
joinLayer(plotgroup, 'path', 'xlines-below');
285+
joinLayer(plotgroup, 'path', 'ylines-below');
286+
plotinfo.overlinesBelow = joinLayer(plotgroup, 'g', 'overlines-below');
287+
288+
joinLayer(plotgroup, 'g', 'xaxislayer-below');
289+
joinLayer(plotgroup, 'g', 'yaxislayer-below');
290+
plotinfo.overaxesBelow = joinLayer(plotgroup, 'g', 'overaxes-below');
291+
298292
plotinfo.plot = joinLayer(plotgroup, 'g', 'plot');
299293
plotinfo.overplot = joinLayer(plotgroup, 'g', 'overplot');
300294

301-
plotinfo.xlines = joinLayer(plotgroup, 'path', 'xlines');
302-
plotinfo.ylines = joinLayer(plotgroup, 'path', 'ylines');
303-
plotinfo.overlines = joinLayer(plotgroup, 'g', 'overlines');
295+
joinLayer(plotgroup, 'path', 'xlines-above');
296+
joinLayer(plotgroup, 'path', 'ylines-above');
297+
plotinfo.overlinesAbove = joinLayer(plotgroup, 'g', 'overlines-above');
304298

305-
plotinfo.xaxislayer = joinLayer(plotgroup, 'g', 'xaxislayer');
306-
plotinfo.yaxislayer = joinLayer(plotgroup, 'g', 'yaxislayer');
307-
plotinfo.overaxes = joinLayer(plotgroup, 'g', 'overaxes');
299+
joinLayer(plotgroup, 'g', 'xaxislayer-above');
300+
joinLayer(plotgroup, 'g', 'yaxislayer-above');
301+
plotinfo.overaxesAbove = joinLayer(plotgroup, 'g', 'overaxes-above');
302+
303+
// set refs to correct layers as determined by 'axis.layer'
304+
plotinfo.xlines = plotgroup.select('.xlines-' + xLayer);
305+
plotinfo.ylines = plotgroup.select('.ylines-' + yLayer);
306+
plotinfo.xaxislayer = plotgroup.select('.xaxislayer-' + xLayer);
307+
plotinfo.yaxislayer = plotgroup.select('.yaxislayer-' + yLayer);
308308
}
309309
else {
310310
var mainplotinfo = plotinfo.mainplotinfo;
311+
var mainplotgroup = mainplotinfo.plotgroup;
312+
var xId = id + '-x';
313+
var yId = id + '-y';
311314

312315
// now make the components of overlaid subplots
313316
// overlays don't have backgrounds, and append all
@@ -317,15 +320,30 @@ function makeSubplotLayer(plotinfo) {
317320
plotinfo.gridlayer = joinLayer(mainplotinfo.overgrid, 'g', id);
318321
plotinfo.zerolinelayer = joinLayer(mainplotinfo.overzero, 'g', id);
319322

323+
joinLayer(mainplotinfo.overlinesBelow, 'path', xId);
324+
joinLayer(mainplotinfo.overlinesBelow, 'path', yId);
325+
joinLayer(mainplotinfo.overaxesBelow, 'g', xId);
326+
joinLayer(mainplotinfo.overaxesBelow, 'g', yId);
327+
320328
plotinfo.plot = joinLayer(mainplotinfo.overplot, 'g', id);
321-
plotinfo.xlines = joinLayer(mainplotinfo.overlines, 'path', id + '-x');
322-
plotinfo.ylines = joinLayer(mainplotinfo.overlines, 'path', id + '-y');
323-
plotinfo.xaxislayer = joinLayer(mainplotinfo.overaxes, 'g', id + '-x');
324-
plotinfo.yaxislayer = joinLayer(mainplotinfo.overaxes, 'g', id + '-y');
329+
330+
joinLayer(mainplotinfo.overlinesAbove, 'path', xId);
331+
joinLayer(mainplotinfo.overlinesAbove, 'path', yId);
332+
joinLayer(mainplotinfo.overaxesAbove, 'g', xId);
333+
joinLayer(mainplotinfo.overaxesAbove, 'g', yId);
334+
335+
// set refs to correct layers as determined by 'abovetraces'
336+
plotinfo.xlines = mainplotgroup.select('.overlines-' + xLayer).select('.' + xId);
337+
plotinfo.ylines = mainplotgroup.select('.overlines-' + yLayer).select('.' + yId);
338+
plotinfo.xaxislayer = mainplotgroup.select('.overaxes-' + xLayer).select('.' + xId);
339+
plotinfo.yaxislayer = mainplotgroup.select('.overaxes-' + yLayer).select('.' + yId);
325340
}
326341

327342
// common attributes for all subplots, overlays or not
328-
plotinfo.plot.call(joinPlotLayers);
343+
344+
for(var i = 0; i < constants.traceLayerClasses.length; i++) {
345+
joinLayer(plotinfo.plot, 'g', constants.traceLayerClasses[i]);
346+
}
329347

330348
plotinfo.xlines
331349
.style('fill', 'none')

src/plots/cartesian/layout_attributes.js

+14
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,20 @@ module.exports = {
573573
'If *false*, this axis does not overlay any same-letter axes.'
574574
].join(' ')
575575
},
576+
layer: {
577+
valType: 'enumerated',
578+
values: ['above traces', 'below traces'],
579+
dflt: 'above traces',
580+
role: 'info',
581+
description: [
582+
'Sets the layer on which this axis is displayed.',
583+
'If *above traces*, this axis is displayed above all the subplot\'s traces',
584+
'If *below traces*, this axis is displayed below all the subplot\'s traces,',
585+
'but above the grid lines.',
586+
'Useful when used together with scatter-like traces with `cliponaxis`',
587+
'set to *false* to show markers and/or text nodes above this axis.'
588+
].join(' ')
589+
},
576590
domain: {
577591
valType: 'info_array',
578592
role: 'info',

src/plots/cartesian/position_defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,7 @@ module.exports = function handlePositionDefaults(containerIn, containerOut, coer
5959
Lib.noneOrAll(containerIn.domain, containerOut.domain, [0, 1]);
6060
}
6161

62+
coerce('layer');
63+
6264
return containerOut;
6365
};

src/plots/cartesian/set_convert.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ function fromLog(v) {
5858
module.exports = function setConvert(ax, fullLayout) {
5959
fullLayout = fullLayout || {};
6060

61+
var axLetter = (ax._id || 'x').charAt(0);
62+
6163
// clipMult: how many axis lengths past the edge do we render?
6264
// for panning, 1-2 would suffice, but for zooming more is nice.
6365
// also, clipping can affect the direction of lines off the edge...
@@ -277,7 +279,6 @@ module.exports = function setConvert(ax, fullLayout) {
277279
ax.cleanRange = function(rangeAttr) {
278280
if(!rangeAttr) rangeAttr = 'range';
279281
var range = Lib.nestedProperty(ax, rangeAttr).get(),
280-
axLetter = (ax._id || 'x').charAt(0),
281282
i, dflt;
282283

283284
if(ax.type === 'date') dflt = Lib.dfltRange(ax.calendar);
@@ -341,8 +342,7 @@ module.exports = function setConvert(ax, fullLayout) {
341342

342343
// set scaling to pixels
343344
ax.setScale = function(usePrivateRange) {
344-
var gs = fullLayout._size,
345-
axLetter = ax._id.charAt(0);
345+
var gs = fullLayout._size;
346346

347347
// TODO cleaner way to handle this case
348348
if(!ax._categories) ax._categories = [];
@@ -435,6 +435,18 @@ module.exports = function setConvert(ax, fullLayout) {
435435
);
436436
};
437437

438+
if(axLetter === 'x') {
439+
ax.isPtWithinRange = function(d) {
440+
var x = d.x;
441+
return x >= ax.range[0] && x <= ax.range[1];
442+
};
443+
} else {
444+
ax.isPtWithinRange = function(d) {
445+
var y = d.y;
446+
return y >= ax.range[0] && y <= ax.range[1];
447+
};
448+
}
449+
438450
// for autoranging: arrays of objects:
439451
// {val: axis value, pad: pixel padding}
440452
// on the low and high sides

0 commit comments

Comments
 (0)