Skip to content

Commit 6011f0b

Browse files
authored
Merge pull request #2378 from plotly/bar-cliponaxis-false
Implement `cliponaxis: false` for bar text
2 parents 41c067a + 8406b1f commit 6011f0b

File tree

13 files changed

+321
-37
lines changed

13 files changed

+321
-37
lines changed

src/components/drawing/index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,11 @@ drawing.hideOutsideRangePoint = function(d, sel, xa, ya, xcalendar, ycalendar) {
100100
);
101101
};
102102

103-
drawing.hideOutsideRangePoints = function(traceGroups, subplot) {
103+
drawing.hideOutsideRangePoints = function(traceGroups, subplot, selector) {
104104
if(!subplot._hasClipOnAxisFalse) return;
105105

106+
selector = selector || '.point,.textpoint';
107+
106108
var xa = subplot.xaxis;
107109
var ya = subplot.yaxis;
108110

@@ -111,7 +113,7 @@ drawing.hideOutsideRangePoints = function(traceGroups, subplot) {
111113
var xcalendar = trace.xcalendar;
112114
var ycalendar = trace.ycalendar;
113115

114-
traceGroups.selectAll('.point,.textpoint').each(function(d) {
116+
traceGroups.selectAll(selector).each(function(d) {
115117
drawing.hideOutsideRangePoint(d, d3.select(this), xa, ya, xcalendar, ycalendar);
116118
});
117119
});

src/plot_api/subroutines.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ exports.lsInner = function(gd) {
216216

217217
for(i = 0; i < cartesianConstants.traceLayerClasses.length; i++) {
218218
var layer = cartesianConstants.traceLayerClasses[i];
219-
if(layer !== 'scatterlayer') {
219+
if(layer !== 'scatterlayer' && layer !== 'barlayer') {
220220
plotinfo.plot.selectAll('g.' + layer).call(Drawing.setClipUrl, layerClipId);
221221
}
222222
}

src/plots/cartesian/dragbox.js

+3
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,9 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) {
793793
.call(Drawing.setTextPointsScale, xScaleFactor2, yScaleFactor2);
794794
traceGroups
795795
.call(Drawing.hideOutsideRangePoints, subplot);
796+
797+
subplot.plot.selectAll('.barlayer .trace')
798+
.call(Drawing.hideOutsideRangePoints, subplot, '.bartext');
796799
}
797800
}
798801

src/traces/bar/attributes.js

+9
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ module.exports = {
104104
].join(' ')
105105
},
106106

107+
cliponaxis: extendFlat({}, scatterAttrs.cliponaxis, {
108+
description: [
109+
'Determines whether the text nodes',
110+
'are clipped about the subplot axes.',
111+
'To show the text nodes above axis lines and tick labels,',
112+
'make sure to set `xaxis.layer` and `yaxis.layer` to *below traces*.'
113+
].join(' ')
114+
}),
115+
107116
orientation: {
108117
valType: 'enumerated',
109118
role: 'info',

src/traces/bar/defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
5151
coerce('constraintext');
5252
coerce('selected.textfont.color');
5353
coerce('unselected.textfont.color');
54+
coerce('cliponaxis');
5455
}
5556

5657
handleStyleDefaults(traceIn, traceOut, coerce, defaultColor, layout);

src/traces/bar/plot.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,26 @@ module.exports = function plot(gd, plotinfo, cdbar) {
138138
bar.append('path')
139139
.style('vector-effect', 'non-scaling-stroke')
140140
.attr('d',
141-
'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z');
141+
'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z')
142+
.call(Drawing.setClipUrl, plotinfo.layerClipId);
142143

143144
appendBarText(gd, bar, d, i, x0, x1, y0, y1);
145+
146+
if(plotinfo.layerClipId) {
147+
Drawing.hideOutsideRangePoint(d[i], bar.select('text'), xa, ya, trace.xcalendar, trace.ycalendar);
148+
}
144149
});
145150
});
146151

147152
// error bars are on the top
148153
bartraces.call(ErrorBars.plot, plotinfo);
149154

155+
// lastly, clip points groups of `cliponaxis !== false` traces
156+
// on `plotinfo._hasClipOnAxisFalse === true` subplots
157+
bartraces.each(function(d) {
158+
var hasClipOnAxisFalse = d[0].trace.cliponaxis === false;
159+
Drawing.setClipUrl(d3.select(this), hasClipOnAxisFalse ? null : plotinfo.layerClipId);
160+
});
150161
};
151162

152163
function appendBarText(gd, bar, calcTrace, i, x0, x1, y0, y1) {
22 KB
Loading
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
"data": [
3+
{
4+
"type": "bar",
5+
"name": "not clipped",
6+
"x": ["apple", "banana", "clementine"],
7+
"y": [1.9, 2, 2.1],
8+
"text": ["apple", "banana", "x"],
9+
"textposition": "outside",
10+
"cliponaxis": false,
11+
"textfont": {
12+
"size": [60, 40, 20]
13+
}
14+
},
15+
{
16+
"type": "bar",
17+
"name": "same but clipped",
18+
"x": ["apple", "banana", "clementine"],
19+
"y": [1.9, 2, 2.1],
20+
"text": ["apple", "banana", "clementine"],
21+
"textposition": "outside",
22+
"cliponaxis": true,
23+
"textfont": {
24+
"size": [60, 40, 20]
25+
},
26+
"xaxis": "x2",
27+
"yaxis": "y2"
28+
},
29+
{
30+
"type": "bar",
31+
"name": "should <b>not</b> see text",
32+
"x": ["banana"],
33+
"y": [2],
34+
"text": ["X"],
35+
"textposition": "outside",
36+
"cliponaxis": true,
37+
"textfont": {"size": [20]},
38+
"marker": {"opacity": 0.3}
39+
}
40+
],
41+
"layout": {
42+
"barmode": "overlay",
43+
"legend": {
44+
"x": 0.5,
45+
"xanchor": "center",
46+
"y": -0.05,
47+
"yanchor": "top"
48+
},
49+
"xaxis": {
50+
"showline": true,
51+
"showticklabels": false,
52+
"mirror": true,
53+
"layer": "below traces",
54+
"domain": [0, 0.48]
55+
},
56+
"xaxis2": {
57+
"anchor": "y2",
58+
"showline": true,
59+
"showticklabels": false,
60+
"mirror": true,
61+
"layer": "below traces",
62+
"domain": [0.52, 1]
63+
},
64+
"yaxis": {
65+
"showline": true,
66+
"mirror": true,
67+
"layer": "below traces",
68+
"range": [0, 2]
69+
},
70+
"yaxis2": {
71+
"anchor": "x2",
72+
"showline": true,
73+
"mirror": true,
74+
"layer": "below traces",
75+
"range": [0, 2]
76+
},
77+
"width": 700,
78+
"height": 400,
79+
"margin": {"t": 40},
80+
"dragmode": "pan"
81+
}
82+
}

test/jasmine/tests/bar_test.js

+94
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ var fail = require('../assets/fail_test');
1313
var checkTicks = require('../assets/custom_assertions').checkTicks;
1414
var supplyAllDefaults = require('../assets/supply_defaults');
1515

16+
var customAssertions = require('../assets/custom_assertions');
17+
var assertClip = customAssertions.assertClip;
18+
var assertNodeDisplay = customAssertions.assertNodeDisplay;
19+
1620
var d3 = require('d3');
1721

1822
describe('Bar.supplyDefaults', function() {
@@ -1509,6 +1513,96 @@ describe('bar hover', function() {
15091513
.then(done);
15101514
});
15111515
});
1516+
1517+
it('should show/hide text in clipped and non-clipped layers', function(done) {
1518+
var fig = Lib.extendDeep({}, require('@mocks/bar_cliponaxis-false.json'));
1519+
gd = createGraphDiv();
1520+
1521+
// only show one trace
1522+
fig.data = [fig.data[0]];
1523+
1524+
function _assert(layerClips, barDisplays, barTextDisplays, barClips) {
1525+
var subplotLayer = d3.select('.plot');
1526+
var barLayer = subplotLayer.select('.barlayer');
1527+
1528+
assertClip(subplotLayer, layerClips[0], 1, 'subplot layer');
1529+
assertClip(subplotLayer.select('.maplayer'), layerClips[1], 1, 'some other trace layer');
1530+
assertClip(barLayer, layerClips[2], 1, 'bar layer');
1531+
1532+
assertNodeDisplay(
1533+
barLayer.selectAll('.point'),
1534+
barDisplays,
1535+
'bar points (never hidden by display attr)'
1536+
);
1537+
assertNodeDisplay(
1538+
barLayer.selectAll('.bartext'),
1539+
barTextDisplays,
1540+
'bar text'
1541+
);
1542+
1543+
assertClip(
1544+
barLayer.selectAll('.point > path'),
1545+
barClips[0], barClips[1],
1546+
'bar clips'
1547+
);
1548+
}
1549+
1550+
Plotly.newPlot(gd, fig).then(function() {
1551+
_assert(
1552+
[false, true, false],
1553+
[null, null, null],
1554+
[null, null, 'none'],
1555+
[true, 3]
1556+
);
1557+
return Plotly.restyle(gd, 'visible', false);
1558+
})
1559+
.then(function() {
1560+
_assert(
1561+
[true, false, false],
1562+
[],
1563+
[],
1564+
[false, 0]
1565+
);
1566+
return Plotly.restyle(gd, {visible: true, cliponaxis: null});
1567+
})
1568+
.then(function() {
1569+
_assert(
1570+
[true, false, false],
1571+
[null, null, null],
1572+
[null, null, null],
1573+
[false, 3]
1574+
);
1575+
return Plotly.restyle(gd, 'cliponaxis', false);
1576+
})
1577+
.then(function() {
1578+
_assert(
1579+
[false, true, false],
1580+
[null, null, null],
1581+
[null, null, 'none'],
1582+
[true, 3]
1583+
);
1584+
return Plotly.relayout(gd, 'yaxis.range', [0, 1]);
1585+
})
1586+
.then(function() {
1587+
_assert(
1588+
[false, true, false],
1589+
[null, null, null],
1590+
['none', 'none', 'none'],
1591+
[true, 3]
1592+
);
1593+
return Plotly.relayout(gd, 'yaxis.range', [0, 4]);
1594+
})
1595+
.then(function() {
1596+
_assert(
1597+
[false, true, false],
1598+
[null, null, null],
1599+
[null, null, null],
1600+
[true, 3]
1601+
);
1602+
})
1603+
.catch(fail)
1604+
.then(done);
1605+
});
15121606
});
15131607

15141608
function mockBarPlot(dataWithoutTraceType, layout) {

0 commit comments

Comments
 (0)