@@ -190,66 +190,104 @@ exports.makeSelectionsOptionsAndPlotinfo = function(gd, index) {
190190
191191
192192exports . getPathString = function ( gd , options ) {
193- var type = options . type ;
193+ var shapeType = options . type ;
194194 var xRefType = Axes . getRefType ( options . xref ) ;
195195 var yRefType = Axes . getRefType ( options . yref ) ;
196- var xa = Axes . getFromId ( gd , options . xref ) ;
197- var ya = Axes . getFromId ( gd , options . yref ) ;
198196 var gs = gd . _fullLayout . _size ;
199- var x2r , x2p , y2r , y2p ;
200- var xShiftStart = getPixelShift ( xa , options . x0shift ) ;
201- var xShiftEnd = getPixelShift ( xa , options . x1shift ) ;
202- var yShiftStart = getPixelShift ( ya , options . y0shift ) ;
203- var yShiftEnd = getPixelShift ( ya , options . y1shift ) ;
197+ var xa , ya ;
198+ var xShiftStart , xShiftEnd , yShiftStart , yShiftEnd ;
199+ var x2p , y2p ;
204200 var x0 , x1 , y0 , y1 ;
205201
206- if ( xa ) {
207- if ( xRefType === 'domain' ) {
208- x2p = function ( v ) { return xa . _offset + xa . _length * v ; } ;
202+ function getConverter ( axis , refType , shapeType , isVertical ) {
203+ var converter ;
204+ if ( axis ) {
205+ if ( refType === 'domain' ) {
206+ if ( isVertical ) {
207+ converter = function ( v ) { return axis . _offset + axis . _length * ( 1 - v ) ; } ;
208+ } else {
209+ converter = function ( v ) { return axis . _offset + axis . _length * v ; } ;
210+ }
211+ } else {
212+ var d2r = exports . shapePositionToRange ( axis ) ;
213+ converter = function ( v ) { return axis . _offset + axis . r2p ( d2r ( v , true ) ) ; } ;
214+
215+ if ( shapeType === 'path' && axis . type === 'date' ) converter = exports . decodeDate ( converter ) ;
216+ }
209217 } else {
210- x2r = exports . shapePositionToRange ( xa ) ;
211- x2p = function ( v ) { return xa . _offset + xa . r2p ( x2r ( v , true ) ) ; } ;
218+ if ( isVertical ) {
219+ converter = function ( v ) { return gs . t + gs . h * ( 1 - v ) ; } ;
220+ } else {
221+ converter = function ( v ) { return gs . l + gs . w * v ; } ;
222+ }
212223 }
213- } else {
214- x2p = function ( v ) { return gs . l + gs . w * v ; } ;
215- }
216224
217- if ( ya ) {
218- if ( yRefType === 'domain' ) {
219- y2p = function ( v ) { return ya . _offset + ya . _length * ( 1 - v ) ; } ;
220- } else {
221- y2r = exports . shapePositionToRange ( ya ) ;
222- y2p = function ( v ) { return ya . _offset + ya . r2p ( y2r ( v , true ) ) ; } ;
223- }
224- } else {
225- y2p = function ( v ) { return gs . t + gs . h * ( 1 - v ) ; } ;
225+ return converter ;
226226 }
227227
228- if ( type === 'path' ) {
229- if ( xa && xa . type === 'date' ) x2p = exports . decodeDate ( x2p ) ;
230- if ( ya && ya . type === 'date' ) y2p = exports . decodeDate ( y2p ) ;
231- return convertPath ( options , x2p , y2p ) ;
228+ // Build function(s) to convert data to pixel
229+ if ( xRefType === 'array' ) {
230+ x2p = [ ] ;
231+ xa = options . xref . map ( function ( ref ) { return Axes . getFromId ( gd , ref ) ; } ) ;
232+ x2p = options . xref . map ( function ( ref , i ) {
233+ return getConverter ( xa [ i ] , Axes . getRefType ( ref ) , shapeType , false ) ;
234+ } ) ;
235+ } else {
236+ xa = Axes . getFromId ( gd , options . xref ) ;
237+ x2p = getConverter ( xa , xRefType , shapeType , false ) ;
232238 }
233- if ( options . xsizemode === 'pixel' ) {
234- var xAnchorPos = x2p ( options . xanchor ) ;
235- x0 = xAnchorPos + options . x0 + xShiftStart ;
236- x1 = xAnchorPos + options . x1 + xShiftEnd ;
239+ if ( yRefType === 'array' ) {
240+ y2p = [ ] ;
241+ ya = options . yref . map ( function ( ref ) { return Axes . getFromId ( gd , ref ) ; } ) ;
242+ y2p = options . yref . map ( function ( ref , i ) {
243+ return getConverter ( ya [ i ] , Axes . getRefType ( ref ) , shapeType , true ) ;
244+ } ) ;
237245 } else {
238- x0 = x2p ( options . x0 ) + xShiftStart ;
239- x1 = x2p ( options . x1 ) + xShiftEnd ;
246+ ya = Axes . getFromId ( gd , options . yref ) ;
247+ y2p = getConverter ( ya , yRefType , shapeType , true ) ;
240248 }
241249
242- if ( options . ysizemode === 'pixel' ) {
243- var yAnchorPos = y2p ( options . yanchor ) ;
244- y0 = yAnchorPos - options . y0 + yShiftStart ;
245- y1 = yAnchorPos - options . y1 + yShiftEnd ;
250+ if ( shapeType === 'path' ) { return convertPath ( options , x2p , y2p ) ; }
251+
252+ // Calculate pixel coordinates for non-path shapes
253+ // Pixel sizemode for array refs is not supported for now
254+ if ( xRefType === 'array' ) {
255+ xShiftStart = getPixelShift ( xa [ 0 ] , options . x0shift ) ;
256+ xShiftEnd = getPixelShift ( xa [ 1 ] , options . x1shift ) ;
257+ x0 = x2p [ 0 ] ( options . x0 ) + xShiftStart ;
258+ x1 = x2p [ 1 ] ( options . x1 ) + xShiftEnd ;
259+ } else {
260+ xShiftStart = getPixelShift ( xa , options . x0shift ) ;
261+ xShiftEnd = getPixelShift ( xa , options . x1shift ) ;
262+ if ( options . xsizemode === 'pixel' ) {
263+ var xAnchorPos = x2p ( options . xanchor ) ;
264+ x0 = xAnchorPos + options . x0 + xShiftStart ;
265+ x1 = xAnchorPos + options . x1 + xShiftEnd ;
266+ } else {
267+ x0 = x2p ( options . x0 ) + xShiftStart ;
268+ x1 = x2p ( options . x1 ) + xShiftEnd ;
269+ }
270+ }
271+ if ( yRefType === 'array' ) {
272+ yShiftStart = getPixelShift ( ya [ 0 ] , options . y0shift ) ;
273+ yShiftEnd = getPixelShift ( ya [ 1 ] , options . y1shift ) ;
274+ y0 = y2p [ 0 ] ( options . y0 ) + yShiftStart ;
275+ y1 = y2p [ 1 ] ( options . y1 ) + yShiftEnd ;
246276 } else {
247- y0 = y2p ( options . y0 ) + yShiftStart ;
248- y1 = y2p ( options . y1 ) + yShiftEnd ;
277+ yShiftStart = getPixelShift ( ya , options . y0shift ) ;
278+ yShiftEnd = getPixelShift ( ya , options . y1shift ) ;
279+ if ( options . ysizemode === 'pixel' ) {
280+ var yAnchorPos = y2p ( options . yanchor ) ;
281+ y0 = yAnchorPos - options . y0 + yShiftStart ;
282+ y1 = yAnchorPos - options . y1 + yShiftEnd ;
283+ } else {
284+ y0 = y2p ( options . y0 ) + yShiftStart ;
285+ y1 = y2p ( options . y1 ) + yShiftEnd ;
286+ }
249287 }
250288
251- if ( type === 'line' ) return 'M' + x0 + ',' + y0 + 'L' + x1 + ',' + y1 ;
252- if ( type === 'rect' ) return 'M' + x0 + ',' + y0 + 'H' + x1 + 'V' + y1 + 'H' + x0 + 'Z' ;
289+ if ( shapeType === 'line' ) return 'M' + x0 + ',' + y0 + 'L' + x1 + ',' + y1 ;
290+ if ( shapeType === 'rect' ) return 'M' + x0 + ',' + y0 + 'H' + x1 + 'V' + y1 + 'H' + x0 + 'Z' ;
253291
254292 // circle
255293 var cx = ( x0 + x1 ) / 2 ;
@@ -263,28 +301,37 @@ exports.getPathString = function(gd, options) {
263301 rArc + ' 0 0,1 ' + rightPt + 'Z' ;
264302} ;
265303
266-
267304function convertPath ( options , x2p , y2p ) {
268305 var pathIn = options . path ;
269306 var xSizemode = options . xsizemode ;
270307 var ySizemode = options . ysizemode ;
271308 var xAnchor = options . xanchor ;
272309 var yAnchor = options . yanchor ;
310+ var isArrayXref = Array . isArray ( options . xref ) ;
311+ var isArrayYref = Array . isArray ( options . yref ) ;
312+ var xVertexIndex = 0 ;
313+ var yVertexIndex = 0 ;
273314
274315 return pathIn . replace ( constants . segmentRE , function ( segment ) {
275316 var paramNumber = 0 ;
276317 var segmentType = segment . charAt ( 0 ) ;
277318 var xParams = constants . paramIsX [ segmentType ] ;
278319 var yParams = constants . paramIsY [ segmentType ] ;
279320 var nParams = constants . numParams [ segmentType ] ;
321+ var hasDrawnX = xParams . drawn !== undefined ;
322+ var hasDrawnY = yParams . drawn !== undefined ;
323+
324+ // Use vertex indices for array refs (same converter for all params in segment)
325+ var segmentX2p = ( isArrayXref && xSizemode !== 'pixel' ) ? x2p [ xVertexIndex ] : x2p ;
326+ var segmentY2p = ( isArrayYref && ySizemode !== 'pixel' ) ? y2p [ yVertexIndex ] : y2p ;
280327
281328 var paramString = segment . substr ( 1 ) . replace ( constants . paramRE , function ( param ) {
282329 if ( xParams [ paramNumber ] ) {
283- if ( xSizemode === 'pixel' ) param = x2p ( xAnchor ) + Number ( param ) ;
284- else param = x2p ( param ) ;
330+ if ( xSizemode === 'pixel' ) param = segmentX2p ( xAnchor ) + Number ( param ) ;
331+ else param = segmentX2p ( param ) ;
285332 } else if ( yParams [ paramNumber ] ) {
286- if ( ySizemode === 'pixel' ) param = y2p ( yAnchor ) - Number ( param ) ;
287- else param = y2p ( param ) ;
333+ if ( ySizemode === 'pixel' ) param = segmentY2p ( yAnchor ) - Number ( param ) ;
334+ else param = segmentY2p ( param ) ;
288335 }
289336 paramNumber ++ ;
290337
@@ -297,6 +344,9 @@ function convertPath(options, x2p, y2p) {
297344 Lib . log ( 'Ignoring extra params in segment ' + segment ) ;
298345 }
299346
347+ if ( hasDrawnX ) xVertexIndex ++ ;
348+ if ( hasDrawnY ) yVertexIndex ++ ;
349+
300350 return segmentType + paramString ;
301351 } ) ;
302352}
0 commit comments