@@ -37,136 +37,139 @@ module.exports = function plot(gd, plotinfo, cdbar) {
37
37
38
38
var bartraces = plotinfo . plot . select ( '.barlayer' )
39
39
. selectAll ( 'g.trace.bars' )
40
- . data ( cdbar ) ;
40
+ . data ( cdbar , function ( d ) { return d [ 0 ] . trace . uid ; } ) ;
41
41
42
42
bartraces . enter ( ) . append ( 'g' )
43
- . attr ( 'class' , 'trace bars' ) ;
43
+ . attr ( 'class' , 'trace bars' )
44
+ . append ( 'g' )
45
+ . attr ( 'class' , 'points' ) ;
44
46
45
- if ( ! plotinfo . isRangePlot ) {
46
- bartraces . each ( function ( d ) {
47
- d [ 0 ] . node3 = d3 . select ( this ) ;
48
- } ) ;
49
- }
47
+ bartraces . exit ( ) . remove ( ) ;
50
48
51
- bartraces . append ( 'g' )
52
- . attr ( 'class' , 'points' )
53
- . each ( function ( d ) {
54
- var sel = d3 . select ( this ) ;
55
- var t = d [ 0 ] . t ;
56
- var trace = d [ 0 ] . trace ;
57
- var poffset = t . poffset ;
58
- var poffsetIsArray = Array . isArray ( poffset ) ;
59
-
60
- sel . selectAll ( 'g.point' )
61
- . data ( Lib . identity )
62
- . enter ( ) . append ( 'g' ) . classed ( 'point' , true )
63
- . each ( function ( di , i ) {
64
- // now display the bar
65
- // clipped xf/yf (2nd arg true): non-positive
66
- // log values go off-screen by plotwidth
67
- // so you see them continue if you drag the plot
68
- var p0 = di . p + ( ( poffsetIsArray ) ? poffset [ i ] : poffset ) ,
69
- p1 = p0 + di . w ,
70
- s0 = di . b ,
71
- s1 = s0 + di . s ;
72
-
73
- var x0 , x1 , y0 , y1 ;
74
- if ( trace . orientation === 'h' ) {
75
- y0 = ya . c2p ( p0 , true ) ;
76
- y1 = ya . c2p ( p1 , true ) ;
77
- x0 = xa . c2p ( s0 , true ) ;
78
- x1 = xa . c2p ( s1 , true ) ;
79
-
80
- // for selections
81
- di . ct = [ x1 , ( y0 + y1 ) / 2 ] ;
82
- }
83
- else {
84
- x0 = xa . c2p ( p0 , true ) ;
85
- x1 = xa . c2p ( p1 , true ) ;
86
- y0 = ya . c2p ( s0 , true ) ;
87
- y1 = ya . c2p ( s1 , true ) ;
88
-
89
- // for selections
90
- di . ct = [ ( x0 + x1 ) / 2 , y1 ] ;
91
- }
92
-
93
- if ( ! isNumeric ( x0 ) || ! isNumeric ( x1 ) ||
94
- ! isNumeric ( y0 ) || ! isNumeric ( y1 ) ||
95
- x0 === x1 || y0 === y1 ) {
96
- d3 . select ( this ) . remove ( ) ;
97
- return ;
98
- }
99
-
100
- var lw = ( di . mlw + 1 || trace . marker . line . width + 1 ||
101
- ( di . trace ? di . trace . marker . line . width : 0 ) + 1 ) - 1 ,
102
- offset = d3 . round ( ( lw / 2 ) % 1 , 2 ) ;
103
-
104
- function roundWithLine ( v ) {
105
- // if there are explicit gaps, don't round,
106
- // it can make the gaps look crappy
107
- return ( fullLayout . bargap === 0 && fullLayout . bargroupgap === 0 ) ?
108
- d3 . round ( Math . round ( v ) - offset , 2 ) : v ;
109
- }
110
-
111
- function expandToVisible ( v , vc ) {
112
- // if it's not in danger of disappearing entirely,
113
- // round more precisely
114
- return Math . abs ( v - vc ) >= 2 ? roundWithLine ( v ) :
115
- // but if it's very thin, expand it so it's
116
- // necessarily visible, even if it might overlap
117
- // its neighbor
118
- ( v > vc ? Math . ceil ( v ) : Math . floor ( v ) ) ;
119
- }
120
-
121
- if ( ! gd . _context . staticPlot ) {
122
- // if bars are not fully opaque or they have a line
123
- // around them, round to integer pixels, mainly for
124
- // safari so we prevent overlaps from its expansive
125
- // pixelation. if the bars ARE fully opaque and have
126
- // no line, expand to a full pixel to make sure we
127
- // can see them
128
- var op = Color . opacity ( di . mc || trace . marker . color ) ,
129
- fixpx = ( op < 1 || lw > 0.01 ) ?
130
- roundWithLine : expandToVisible ;
131
- x0 = fixpx ( x0 , x1 ) ;
132
- x1 = fixpx ( x1 , x0 ) ;
133
- y0 = fixpx ( y0 , y1 ) ;
134
- y1 = fixpx ( y1 , y0 ) ;
135
- }
136
-
137
- // append bar path and text
138
- var bar = d3 . select ( this ) ;
139
-
140
- bar . append ( 'path' )
141
- . style ( 'vector-effect' , 'non-scaling-stroke' )
142
- . attr ( 'd' ,
143
- 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z' )
144
- . call ( Drawing . setClipUrl , plotinfo . layerClipId ) ;
145
-
146
- appendBarText ( gd , bar , d , i , x0 , x1 , y0 , y1 ) ;
147
-
148
- if ( plotinfo . layerClipId ) {
149
- Drawing . hideOutsideRangePoint ( d [ i ] , bar . select ( 'text' ) , xa , ya , trace . xcalendar , trace . ycalendar ) ;
150
- }
151
- } ) ;
152
- } ) ;
153
-
154
- // error bars are on the top
155
- Registry . getComponentMethod ( 'errorbars' , 'plot' ) ( bartraces , plotinfo ) ;
49
+ bartraces . order ( ) ;
156
50
157
- // lastly, clip points groups of `cliponaxis !== false` traces
158
- // on `plotinfo._hasClipOnAxisFalse === true` subplots
159
51
bartraces . each ( function ( d ) {
52
+ var cd0 = d [ 0 ] ;
53
+ var t = cd0 . t ;
54
+ var trace = cd0 . trace ;
55
+ var sel = d3 . select ( this ) ;
56
+
57
+ if ( ! plotinfo . isRangePlot ) cd0 . node3 = sel ;
58
+
59
+ var poffset = t . poffset ;
60
+ var poffsetIsArray = Array . isArray ( poffset ) ;
61
+
62
+ var bars = sel . select ( 'g.points' ) . selectAll ( 'g.point' ) . data ( Lib . identity ) ;
63
+
64
+ bars . enter ( ) . append ( 'g' )
65
+ . classed ( 'point' , true ) ;
66
+
67
+ bars . exit ( ) . remove ( ) ;
68
+
69
+ bars . each ( function ( di , i ) {
70
+ var bar = d3 . select ( this ) ;
71
+
72
+ // now display the bar
73
+ // clipped xf/yf (2nd arg true): non-positive
74
+ // log values go off-screen by plotwidth
75
+ // so you see them continue if you drag the plot
76
+ var p0 = di . p + ( ( poffsetIsArray ) ? poffset [ i ] : poffset ) ,
77
+ p1 = p0 + di . w ,
78
+ s0 = di . b ,
79
+ s1 = s0 + di . s ;
80
+
81
+ var x0 , x1 , y0 , y1 ;
82
+ if ( trace . orientation === 'h' ) {
83
+ y0 = ya . c2p ( p0 , true ) ;
84
+ y1 = ya . c2p ( p1 , true ) ;
85
+ x0 = xa . c2p ( s0 , true ) ;
86
+ x1 = xa . c2p ( s1 , true ) ;
87
+
88
+ // for selections
89
+ di . ct = [ x1 , ( y0 + y1 ) / 2 ] ;
90
+ }
91
+ else {
92
+ x0 = xa . c2p ( p0 , true ) ;
93
+ x1 = xa . c2p ( p1 , true ) ;
94
+ y0 = ya . c2p ( s0 , true ) ;
95
+ y1 = ya . c2p ( s1 , true ) ;
96
+
97
+ // for selections
98
+ di . ct = [ ( x0 + x1 ) / 2 , y1 ] ;
99
+ }
100
+
101
+ if ( ! isNumeric ( x0 ) || ! isNumeric ( x1 ) ||
102
+ ! isNumeric ( y0 ) || ! isNumeric ( y1 ) ||
103
+ x0 === x1 || y0 === y1 ) {
104
+ bar . remove ( ) ;
105
+ return ;
106
+ }
107
+
108
+ var lw = ( di . mlw + 1 || trace . marker . line . width + 1 ||
109
+ ( di . trace ? di . trace . marker . line . width : 0 ) + 1 ) - 1 ,
110
+ offset = d3 . round ( ( lw / 2 ) % 1 , 2 ) ;
111
+
112
+ function roundWithLine ( v ) {
113
+ // if there are explicit gaps, don't round,
114
+ // it can make the gaps look crappy
115
+ return ( fullLayout . bargap === 0 && fullLayout . bargroupgap === 0 ) ?
116
+ d3 . round ( Math . round ( v ) - offset , 2 ) : v ;
117
+ }
118
+
119
+ function expandToVisible ( v , vc ) {
120
+ // if it's not in danger of disappearing entirely,
121
+ // round more precisely
122
+ return Math . abs ( v - vc ) >= 2 ? roundWithLine ( v ) :
123
+ // but if it's very thin, expand it so it's
124
+ // necessarily visible, even if it might overlap
125
+ // its neighbor
126
+ ( v > vc ? Math . ceil ( v ) : Math . floor ( v ) ) ;
127
+ }
128
+
129
+ if ( ! gd . _context . staticPlot ) {
130
+ // if bars are not fully opaque or they have a line
131
+ // around them, round to integer pixels, mainly for
132
+ // safari so we prevent overlaps from its expansive
133
+ // pixelation. if the bars ARE fully opaque and have
134
+ // no line, expand to a full pixel to make sure we
135
+ // can see them
136
+ var op = Color . opacity ( di . mc || trace . marker . color ) ,
137
+ fixpx = ( op < 1 || lw > 0.01 ) ?
138
+ roundWithLine : expandToVisible ;
139
+ x0 = fixpx ( x0 , x1 ) ;
140
+ x1 = fixpx ( x1 , x0 ) ;
141
+ y0 = fixpx ( y0 , y1 ) ;
142
+ y1 = fixpx ( y1 , y0 ) ;
143
+ }
144
+
145
+ Lib . ensureSingle ( bar , 'path' )
146
+ . style ( 'vector-effect' , 'non-scaling-stroke' )
147
+ . attr ( 'd' ,
148
+ 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z' )
149
+ . call ( Drawing . setClipUrl , plotinfo . layerClipId ) ;
150
+
151
+ appendBarText ( gd , bar , d , i , x0 , x1 , y0 , y1 ) ;
152
+
153
+ if ( plotinfo . layerClipId ) {
154
+ Drawing . hideOutsideRangePoint ( d [ i ] , bar . select ( 'text' ) , xa , ya , trace . xcalendar , trace . ycalendar ) ;
155
+ }
156
+ } ) ;
157
+
158
+ // lastly, clip points groups of `cliponaxis !== false` traces
159
+ // on `plotinfo._hasClipOnAxisFalse === true` subplots
160
160
var hasClipOnAxisFalse = d [ 0 ] . trace . cliponaxis === false ;
161
- Drawing . setClipUrl ( d3 . select ( this ) , hasClipOnAxisFalse ? null : plotinfo . layerClipId ) ;
161
+ Drawing . setClipUrl ( sel , hasClipOnAxisFalse ? null : plotinfo . layerClipId ) ;
162
162
} ) ;
163
+
164
+ // error bars are on the top
165
+ Registry . getComponentMethod ( 'errorbars' , 'plot' ) ( bartraces , plotinfo ) ;
163
166
} ;
164
167
165
168
function appendBarText ( gd , bar , calcTrace , i , x0 , x1 , y0 , y1 ) {
166
169
var textPosition ;
167
170
168
171
function appendTextNode ( bar , text , textFont ) {
169
- var textSelection = bar . append ( 'text' )
172
+ var textSelection = Lib . ensureSingle ( bar , 'text' )
170
173
. text ( text )
171
174
. attr ( {
172
175
'class' : 'bartext bartext-' + textPosition ,
0 commit comments