@@ -37,136 +37,139 @@ module.exports = function plot(gd, plotinfo, cdbar) {
3737
3838 var bartraces = plotinfo . plot . select ( '.barlayer' )
3939 . selectAll ( 'g.trace.bars' )
40- . data ( cdbar ) ;
40+ . data ( cdbar , function ( d ) { return d [ 0 ] . trace . uid ; } ) ;
4141
4242 bartraces . enter ( ) . append ( 'g' )
43- . attr ( 'class' , 'trace bars' ) ;
43+ . attr ( 'class' , 'trace bars' )
44+ . append ( 'g' )
45+ . attr ( 'class' , 'points' ) ;
4446
45- if ( ! plotinfo . isRangePlot ) {
46- bartraces . each ( function ( d ) {
47- d [ 0 ] . node3 = d3 . select ( this ) ;
48- } ) ;
49- }
47+ bartraces . exit ( ) . remove ( ) ;
5048
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 ( ) ;
15650
157- // lastly, clip points groups of `cliponaxis !== false` traces
158- // on `plotinfo._hasClipOnAxisFalse === true` subplots
15951 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
160160 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 ) ;
162162 } ) ;
163+
164+ // error bars are on the top
165+ Registry . getComponentMethod ( 'errorbars' , 'plot' ) ( bartraces , plotinfo ) ;
163166} ;
164167
165168function appendBarText ( gd , bar , calcTrace , i , x0 , x1 , y0 , y1 ) {
166169 var textPosition ;
167170
168171 function appendTextNode ( bar , text , textFont ) {
169- var textSelection = bar . append ( 'text' )
172+ var textSelection = Lib . ensureSingle ( bar , 'text' )
170173 . text ( text )
171174 . attr ( {
172175 'class' : 'bartext bartext-' + textPosition ,
0 commit comments