Skip to content

Commit 9aa3df9

Browse files
authored
Merge pull request #4568 from plotly/fix4567-display-narrow-bars
Fix for displaying narrow bars in interactive mode
2 parents acc9c21 + 494775b commit 9aa3df9

File tree

4 files changed

+315
-41
lines changed

4 files changed

+315
-41
lines changed

src/traces/bar/plot.js

+40-26
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
114114
}
115115

116116
var isHorizontal = (trace.orientation === 'h');
117+
var withTransition = hasTransition(opts);
117118

118119
var pointGroup = Lib.ensureSingle(plotGroup, 'g', 'points');
119120

@@ -139,26 +140,35 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
139140
var y0 = xy[1][0];
140141
var y1 = xy[1][1];
141142

142-
var isBlank = (
143-
x0 === x1 ||
144-
y0 === y1 ||
145-
!isNumeric(x0) ||
146-
!isNumeric(x1) ||
147-
!isNumeric(y0) ||
148-
!isNumeric(y1)
149-
);
143+
// empty bars
144+
var isBlank = (isHorizontal ? x1 - x0 : y1 - y0) === 0;
150145

151146
// display zeros if line.width > 0
152-
if(isBlank && shouldDisplayZeros && helpers.getLineWidth(trace, di) && (isHorizontal ? x1 - x0 === 0 : y1 - y0 === 0)) {
147+
if(isBlank && shouldDisplayZeros && helpers.getLineWidth(trace, di)) {
153148
isBlank = false;
154149
}
155-
di.isBlank = isBlank;
156150

157-
if(isBlank && isHorizontal) x1 = x0;
158-
if(isBlank && !isHorizontal) y1 = y0;
151+
// skip nulls
152+
if(!isBlank) {
153+
isBlank = (
154+
!isNumeric(x0) ||
155+
!isNumeric(x1) ||
156+
!isNumeric(y0) ||
157+
!isNumeric(y1)
158+
);
159+
}
160+
161+
// record isBlank
162+
di.isBlank = isBlank;
159163

160-
var spansHorizontal = isHorizontal && (x0 !== x1);
161-
var spansVertical = !isHorizontal && (y0 !== y1);
164+
// for blank bars, ensure start and end positions are equal - important for smooth transitions
165+
if(isBlank) {
166+
if(isHorizontal) {
167+
x1 = x0;
168+
} else {
169+
y1 = y0;
170+
}
171+
}
162172

163173
// in waterfall mode `between` we need to adjust bar end points to match the connector width
164174
if(adjustPixel && !isBlank) {
@@ -185,16 +195,24 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
185195
mc = di.mc || trace.marker.color;
186196
}
187197

188-
var offset = d3.round((lw / 2) % 1, 2);
189-
190198
function roundWithLine(v) {
199+
var offset = d3.round((lw / 2) % 1, 2);
200+
191201
// if there are explicit gaps, don't round,
192202
// it can make the gaps look crappy
193203
return (opts.gap === 0 && opts.groupgap === 0) ?
194204
d3.round(Math.round(v) - offset, 2) : v;
195205
}
196206

197-
function expandToVisible(v, vc) {
207+
function expandToVisible(v, vc, hideZeroSpan) {
208+
if(hideZeroSpan && v === vc) {
209+
// should not expand zero span bars
210+
// when start and end positions are identical
211+
// i.e. for vertical when y0 === y1
212+
// and for horizontal when x0 === x1
213+
return v;
214+
}
215+
198216
// if it's not in danger of disappearing entirely,
199217
// round more precisely
200218
return Math.abs(v - vc) >= 2 ? roundWithLine(v) :
@@ -215,14 +233,10 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
215233
var op = Color.opacity(mc);
216234
var fixpx = (op < 1 || lw > 0.01) ? roundWithLine : expandToVisible;
217235

218-
if(spansHorizontal) {
219-
x0 = fixpx(x0, x1);
220-
x1 = fixpx(x1, x0);
221-
}
222-
if(spansVertical) {
223-
y0 = fixpx(y0, y1);
224-
y1 = fixpx(y1, y0);
225-
}
236+
x0 = fixpx(x0, x1, isHorizontal);
237+
x1 = fixpx(x1, x0, isHorizontal);
238+
y0 = fixpx(y0, y1, !isHorizontal);
239+
y1 = fixpx(y1, y0, !isHorizontal);
226240
}
227241

228242
var sel = transition(Lib.ensureSingle(bar, 'path'), fullLayout, opts, makeOnCompleteCallback);
@@ -231,7 +245,7 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
231245
.attr('d', 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z')
232246
.call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
233247

234-
if(!fullLayout.uniformtext.mode && hasTransition(opts)) {
248+
if(!fullLayout.uniformtext.mode && withTransition) {
235249
var styleFns = Drawing.makePointStyleFns(trace);
236250
Drawing.singlePointStyle(di, sel, trace, styleFns, gd);
237251
}
28.6 KB
Loading

test/image/mocks/bar_show_narrow.json

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
{
2+
"data": [
3+
{
4+
"type": "bar",
5+
"width": 0.001,
6+
"x": [
7+
"A",
8+
"B",
9+
"C",
10+
"D"
11+
],
12+
"y": [
13+
0.001,
14+
0.01,
15+
0.1,
16+
1
17+
]
18+
},
19+
{
20+
"type": "bar",
21+
"width": 0.001,
22+
"x": [
23+
"A",
24+
"B",
25+
"C",
26+
"D"
27+
],
28+
"y": [
29+
0.001,
30+
0.01,
31+
0.1,
32+
1
33+
],
34+
"xaxis": "x2",
35+
"yaxis": "y2"
36+
},
37+
{
38+
"type": "bar",
39+
"width": 0.001,
40+
"orientation": "h",
41+
"x": [
42+
0.001,
43+
0.01,
44+
0.1,
45+
1
46+
],
47+
"y": [
48+
"A",
49+
"B",
50+
"C",
51+
"D"
52+
],
53+
"text": [
54+
0,
55+
null,
56+
0.001,
57+
1
58+
],
59+
"xaxis": "x3",
60+
"yaxis": "y3"
61+
},
62+
{
63+
"type": "bar",
64+
"width": 0.001,
65+
"orientation": "h",
66+
"x": [
67+
0.001,
68+
0.01,
69+
0.1,
70+
1
71+
],
72+
"y": [
73+
"A",
74+
"B",
75+
"C",
76+
"D"
77+
],
78+
"xaxis": "x4",
79+
"yaxis": "y4"
80+
}
81+
],
82+
"layout": {
83+
"showlegend": false,
84+
"width": 800,
85+
"height": 800,
86+
"dragmode": "pan",
87+
"xaxis": {
88+
"domain": [
89+
0,
90+
0.48
91+
]
92+
},
93+
"xaxis2": {
94+
"autorange": "reversed",
95+
"anchor": "y2",
96+
"domain": [
97+
0.52,
98+
1
99+
]
100+
},
101+
"xaxis3": {
102+
"range": [
103+
-0.01,
104+
1
105+
],
106+
"zeroline": false,
107+
"anchor": "y3",
108+
"domain": [
109+
0,
110+
0.48
111+
]
112+
},
113+
"xaxis4": {
114+
"range": [
115+
-0.01,
116+
1
117+
],
118+
"zeroline": false,
119+
"autorange": "reversed",
120+
"anchor": "y4",
121+
"domain": [
122+
0.52,
123+
1
124+
]
125+
},
126+
"yaxis": {
127+
"range": [
128+
-0.01,
129+
1
130+
],
131+
"zeroline": false,
132+
"domain": [
133+
0,
134+
0.48
135+
]
136+
},
137+
"yaxis2": {
138+
"range": [
139+
-0.01,
140+
1
141+
],
142+
"zeroline": false,
143+
"autorange": "reversed",
144+
"anchor": "x2",
145+
"domain": [
146+
0.52,
147+
1
148+
]
149+
},
150+
"yaxis3": {
151+
"anchor": "x3",
152+
"domain": [
153+
0.52,
154+
1
155+
]
156+
},
157+
"yaxis4": {
158+
"autorange": "reversed",
159+
"anchor": "x4",
160+
"domain": [
161+
0,
162+
0.48
163+
]
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)