@@ -22,8 +22,6 @@ function crossTraceCalc(gd, plotinfo) {
22
22
var orientation = orientations [ i ] ;
23
23
var posAxis = orientation === 'h' ? ya : xa ;
24
24
var boxList = [ ] ;
25
- var minPad = 0 ;
26
- var maxPad = 0 ;
27
25
28
26
// make list of boxes / candlesticks
29
27
// For backward compatibility, candlesticks are treated as if they *are* box traces here
@@ -40,72 +38,173 @@ function crossTraceCalc(gd, plotinfo) {
40
38
trace . yaxis === ya . _id
41
39
) {
42
40
boxList . push ( j ) ;
43
-
44
- if ( trace . boxpoints ) {
45
- minPad = Math . max ( minPad , trace . jitter - trace . pointpos - 1 ) ;
46
- maxPad = Math . max ( maxPad , trace . jitter + trace . pointpos - 1 ) ;
47
- }
48
41
}
49
42
}
50
43
51
- setPositionOffset ( 'box' , gd , boxList , posAxis , [ minPad , maxPad ] ) ;
44
+ setPositionOffset ( 'box' , gd , boxList , posAxis ) ;
52
45
}
53
46
}
54
47
55
- function setPositionOffset ( traceType , gd , boxList , posAxis , pad ) {
48
+ function setPositionOffset ( traceType , gd , boxList , posAxis ) {
56
49
var calcdata = gd . calcdata ;
57
50
var fullLayout = gd . _fullLayout ;
58
- var pointList = [ ] ;
51
+ var axId = posAxis . _id ;
52
+ var axLetter = axId . charAt ( 0 ) ;
59
53
60
54
// N.B. reused in violin
61
55
var numKey = traceType === 'violin' ? '_numViolins' : '_numBoxes' ;
62
56
63
57
var i , j , calcTrace ;
58
+ var pointList = [ ] ;
59
+ var shownPts = 0 ;
64
60
65
61
// make list of box points
66
62
for ( i = 0 ; i < boxList . length ; i ++ ) {
67
63
calcTrace = calcdata [ boxList [ i ] ] ;
68
64
for ( j = 0 ; j < calcTrace . length ; j ++ ) {
69
65
pointList . push ( calcTrace [ j ] . pos ) ;
66
+ shownPts += ( calcTrace [ j ] . pts2 || [ ] ) . length ;
70
67
}
71
68
}
72
69
73
70
if ( ! pointList . length ) return ;
74
71
75
72
// box plots - update dPos based on multiple traces
76
- // and then use for posAxis autorange
77
73
var boxdv = Lib . distinctVals ( pointList ) ;
78
- var dPos = boxdv . minDiff / 2 ;
79
-
80
- // if there's no duplication of x points,
81
- // disable 'group' mode by setting counter to 1
82
- if ( pointList . length === boxdv . vals . length ) {
83
- fullLayout [ numKey ] = 1 ;
84
- }
74
+ var dPos0 = boxdv . minDiff / 2 ;
85
75
86
76
// check for forced minimum dtick
87
77
Axes . minDtick ( posAxis , boxdv . minDiff , boxdv . vals [ 0 ] , true ) ;
88
78
89
- var gap = fullLayout [ traceType + 'gap' ] ;
90
- var groupgap = fullLayout [ traceType + 'groupgap' ] ;
91
- var padfactor = ( 1 - gap ) * ( 1 - groupgap ) * dPos / fullLayout [ numKey ] ;
92
-
93
- // autoscale the x axis - including space for points if they're off the side
94
- // TODO: this will overdo it if the outermost boxes don't have
95
- // their points as far out as the other boxes
96
- var extremes = Axes . findExtremes ( posAxis , boxdv . vals , {
97
- vpadminus : dPos + pad [ 0 ] * padfactor ,
98
- vpadplus : dPos + pad [ 1 ] * padfactor
99
- } ) ;
79
+ var num = fullLayout [ numKey ] ;
80
+ var group = ( fullLayout [ traceType + 'mode' ] === 'group' && num > 1 ) ;
81
+ var groupFraction = 1 - fullLayout [ traceType + 'gap' ] ;
82
+ var groupGapFraction = 1 - fullLayout [ traceType + 'groupgap' ] ;
100
83
101
84
for ( i = 0 ; i < boxList . length ; i ++ ) {
102
85
calcTrace = calcdata [ boxList [ i ] ] ;
103
- // set the width of all boxes
104
- calcTrace [ 0 ] . t . dPos = dPos ;
105
- // link extremes to all boxes
106
- calcTrace [ 0 ] . trace . _extremes [ posAxis . _id ] = extremes ;
107
- }
108
86
87
+ var trace = calcTrace [ 0 ] . trace ;
88
+ var t = calcTrace [ 0 ] . t ;
89
+ var width = trace . width ;
90
+ var side = trace . side ;
91
+
92
+ // position coordinate delta
93
+ var dPos ;
94
+ // box half width;
95
+ var bdPos ;
96
+ // box center offset
97
+ var bPos ;
98
+ // half-width within which to accept hover for this box/violin
99
+ // always split the distance to the closest box/violin
100
+ var wHover ;
101
+
102
+ if ( width ) {
103
+ dPos = bdPos = wHover = width / 2 ;
104
+ bPos = 0 ;
105
+ } else {
106
+ dPos = dPos0 ;
107
+ bdPos = dPos * groupFraction * groupGapFraction / ( group ? num : 1 ) ;
108
+ bPos = group ? 2 * dPos * ( - 0.5 + ( t . num + 0.5 ) / num ) * groupFraction : 0 ;
109
+ wHover = dPos * ( group ? groupFraction / num : 1 ) ;
110
+ }
111
+ t . dPos = dPos ;
112
+ t . bPos = bPos ;
113
+ t . bdPos = bdPos ;
114
+ t . wHover = wHover ;
115
+
116
+ // box/violin-only value-space push value
117
+ var pushplus ;
118
+ var pushminus ;
119
+ // edge of box/violin
120
+ var edge = bPos + bdPos ;
121
+ var edgeplus ;
122
+ var edgeminus ;
123
+
124
+ if ( side === 'positive' ) {
125
+ pushplus = dPos * ( width ? 1 : 0.5 ) ;
126
+ edgeplus = edge ;
127
+ pushminus = edgeplus = bPos ;
128
+ } else if ( side === 'negative' ) {
129
+ pushplus = edgeplus = bPos ;
130
+ pushminus = dPos * ( width ? 1 : 0.5 ) ;
131
+ edgeminus = edge ;
132
+ } else {
133
+ pushplus = pushminus = dPos ;
134
+ edgeplus = edgeminus = edge ;
135
+ }
136
+
137
+ // value-space padding
138
+ var vpadplus ;
139
+ var vpadminus ;
140
+ // pixel-space padding
141
+ var ppadplus ;
142
+ var ppadminus ;
143
+ // do we add 5% of both sides (for points beyond box/violin)
144
+ var padded = false ;
145
+ // does this trace show points?
146
+ var hasPts = ( trace . boxpoints || trace . points ) && ( shownPts > 0 ) ;
147
+
148
+ if ( hasPts ) {
149
+ var pointpos = trace . pointpos ;
150
+ var jitter = trace . jitter ;
151
+ var ms = trace . marker . size / 2 ;
152
+
153
+ var pp = 0 ;
154
+ if ( ( pointpos + jitter ) >= 0 ) {
155
+ pp = edge * ( pointpos + jitter ) ;
156
+ if ( pp > pushplus ) {
157
+ // (++) beyond plus-value, use pp
158
+ padded = true ;
159
+ ppadplus = ms ;
160
+ vpadplus = pp ;
161
+ } else if ( pp > edgeplus ) {
162
+ // (+), use push-value (it's bigger), but add px-pad
163
+ ppadplus = ms ;
164
+ vpadplus = pushplus ;
165
+ }
166
+ }
167
+ if ( pp <= pushplus ) {
168
+ // (->) fallback to push value
169
+ vpadplus = pushplus ;
170
+ }
171
+
172
+ var pm = 0 ;
173
+ if ( ( pointpos - jitter ) <= 0 ) {
174
+ pm = - edge * ( pointpos - jitter ) ;
175
+ if ( pm > pushminus ) {
176
+ // (--) beyond plus-value, use pp
177
+ padded = true ;
178
+ ppadminus = ms ;
179
+ vpadminus = pm ;
180
+ } else if ( pm > edgeminus ) {
181
+ // (-), use push-value (it's bigger), but add px-pad
182
+ ppadminus = ms ;
183
+ vpadminus = pushminus ;
184
+ }
185
+ }
186
+ if ( pm <= pushminus ) {
187
+ // (<-) fallback to push value
188
+ vpadminus = pushminus ;
189
+ }
190
+ } else {
191
+ vpadplus = pushplus ;
192
+ vpadminus = pushminus ;
193
+ }
194
+
195
+ // calcdata[i][j] are in ascending order
196
+ var firstPos = calcTrace [ 0 ] . pos ;
197
+ var lastPos = calcTrace [ calcTrace . length - 1 ] . pos ;
198
+
199
+ trace . _extremes [ axId ] = Axes . findExtremes ( posAxis , [ firstPos , lastPos ] , {
200
+ padded : padded ,
201
+ vpadminus : vpadminus ,
202
+ vpadplus : vpadplus ,
203
+ // N.B. SVG px-space positive/negative
204
+ ppadminus : { x : ppadminus , y : ppadplus } [ axLetter ] ,
205
+ ppadplus : { x : ppadplus , y : ppadminus } [ axLetter ] ,
206
+ } ) ;
207
+ }
109
208
}
110
209
111
210
module . exports = {
0 commit comments