@@ -68,77 +68,138 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) {
6868 var ySizeMode = coerce ( 'ysizemode' ) ;
6969
7070 // positioning
71- var axLetters = [ 'x' , 'y' ] ;
72- for ( var i = 0 ; i < 2 ; i ++ ) {
73- var axLetter = axLetters [ i ] ;
71+ const dflts = [ 0.25 , 0.75 ] ;
72+ const pixelDflts = [ 0 , 10 ] ;
73+
74+ [ 'x' , 'y' ] . forEach ( axLetter => {
7475 var attrAnchor = axLetter + 'anchor' ;
7576 var sizeMode = axLetter === 'x' ? xSizeMode : ySizeMode ;
7677 var gdMock = { _fullLayout : fullLayout } ;
7778 var ax ;
7879 var pos2r ;
7980 var r2pos ;
8081
81- // xref, yref
82- var axRef = Axes . coerceRef ( shapeIn , shapeOut , gdMock , axLetter , undefined , 'paper' ) ;
83- var axRefType = Axes . getRefType ( axRef ) ;
84-
85- if ( axRefType === 'range' ) {
86- ax = Axes . getFromId ( gdMock , axRef ) ;
87- ax . _shapeIndices . push ( shapeOut . _index ) ;
88- r2pos = helpers . rangeToShapePosition ( ax ) ;
89- pos2r = helpers . shapePositionToRange ( ax ) ;
90- if ( ax . type === 'category' || ax . type === 'multicategory' ) {
91- coerce ( axLetter + '0shift' ) ;
92- coerce ( axLetter + '1shift' ) ;
93- }
82+ // xref, yref - handle both string and array values
83+ var axRef ;
84+ const refAttr = axLetter + 'ref' ;
85+ const inputRef = shapeIn [ refAttr ] ;
86+
87+ if ( Array . isArray ( inputRef ) && inputRef . length > 0 ) {
88+ // Array case: use coerceRefArray for validation
89+ const expectedLen = helpers . countDefiningCoords ( shapeType , path , axLetter ) ;
90+ axRef = Axes . coerceRefArray ( shapeIn , shapeOut , gdMock , axLetter , undefined , 'paper' , expectedLen ) ;
91+ shapeOut [ '_' + axLetter + 'refArray' ] = true ;
9492 } else {
95- pos2r = r2pos = Lib . identity ;
93+ // String/undefined case: use coerceRef
94+ axRef = Axes . coerceRef ( shapeIn , shapeOut , gdMock , axLetter , undefined , 'paper' ) ;
9695 }
9796
98- // Coerce x0, x1, y0, y1
99- if ( noPath ) {
100- var dflt0 = 0.25 ;
101- var dflt1 = 0.75 ;
102-
103- // hack until V3.0 when log has regular range behavior - make it look like other
104- // ranges to send to coerce, then put it back after
105- // this is all to give reasonable default position behavior on log axes, which is
106- // a pretty unimportant edge case so we could just ignore this.
107- var attr0 = axLetter + '0' ;
108- var attr1 = axLetter + '1' ;
109- var in0 = shapeIn [ attr0 ] ;
110- var in1 = shapeIn [ attr1 ] ;
111- shapeIn [ attr0 ] = pos2r ( shapeIn [ attr0 ] , true ) ;
112- shapeIn [ attr1 ] = pos2r ( shapeIn [ attr1 ] , true ) ;
113-
114- if ( sizeMode === 'pixel' ) {
115- coerce ( attr0 , 0 ) ;
116- coerce ( attr1 , 10 ) ;
97+ if ( Array . isArray ( axRef ) ) {
98+ // Register the shape with all referenced axes for redrawing purposes
99+ axRef . forEach ( function ( ref ) {
100+ if ( Axes . getRefType ( ref ) === 'range' ) {
101+ ax = Axes . getFromId ( gdMock , ref ) ;
102+ if ( ax && ax . _shapeIndices . indexOf ( shapeOut . _index ) === - 1 ) {
103+ ax . _shapeIndices . push ( shapeOut . _index ) ;
104+ }
105+ }
106+ } ) ;
107+
108+ if ( noPath ) {
109+ [ 0 , 1 ] . forEach ( function ( i ) {
110+ const ref = axRef [ i ] ;
111+ const refType = Axes . getRefType ( ref ) ;
112+ if ( refType === 'range' ) {
113+ ax = Axes . getFromId ( gdMock , ref ) ;
114+ pos2r = helpers . shapePositionToRange ( ax ) ;
115+ r2pos = helpers . rangeToShapePosition ( ax ) ;
116+ if ( ax . type === 'category' || ax . type === 'multicategory' ) {
117+ coerce ( axLetter + i + 'shift' ) ;
118+ }
119+ } else {
120+ pos2r = r2pos = Lib . identity ;
121+ }
122+
123+ const attr = axLetter + i ;
124+ const inValue = shapeIn [ attr ] ;
125+ shapeIn [ attr ] = pos2r ( shapeIn [ attr ] , true ) ;
126+
127+ if ( sizeMode === 'pixel' ) {
128+ coerce ( attr , pixelDflts [ i ] ) ;
129+ } else {
130+ Axes . coercePosition ( shapeOut , gdMock , coerce , ref , attr , dflts [ i ] ) ;
131+ }
132+
133+ shapeOut [ attr ] = r2pos ( shapeOut [ attr ] ) ;
134+ shapeIn [ attr ] = inValue ;
135+
136+ if ( i === 0 && sizeMode === 'pixel' ) {
137+ const inAnchor = shapeIn [ attrAnchor ] ;
138+ shapeIn [ attrAnchor ] = pos2r ( shapeIn [ attrAnchor ] , true ) ;
139+ Axes . coercePosition ( shapeOut , gdMock , coerce , ref , attrAnchor , 0.25 ) ;
140+ shapeOut [ attrAnchor ] = r2pos ( shapeOut [ attrAnchor ] ) ;
141+ shapeIn [ attrAnchor ] = inAnchor ;
142+ }
143+ } ) ;
144+ }
145+ } else {
146+ const axRefType = Axes . getRefType ( axRef ) ;
147+
148+ if ( axRefType === 'range' ) {
149+ ax = Axes . getFromId ( gdMock , axRef ) ;
150+ ax . _shapeIndices . push ( shapeOut . _index ) ;
151+ r2pos = helpers . rangeToShapePosition ( ax ) ;
152+ pos2r = helpers . shapePositionToRange ( ax ) ;
153+ if ( noPath && ( ax . type === 'category' || ax . type === 'multicategory' ) ) {
154+ coerce ( axLetter + '0shift' ) ;
155+ coerce ( axLetter + '1shift' ) ;
156+ }
117157 } else {
118- Axes . coercePosition ( shapeOut , gdMock , coerce , axRef , attr0 , dflt0 ) ;
119- Axes . coercePosition ( shapeOut , gdMock , coerce , axRef , attr1 , dflt1 ) ;
158+ pos2r = r2pos = Lib . identity ;
120159 }
121160
122- // hack part 2
123- shapeOut [ attr0 ] = r2pos ( shapeOut [ attr0 ] ) ;
124- shapeOut [ attr1 ] = r2pos ( shapeOut [ attr1 ] ) ;
125- shapeIn [ attr0 ] = in0 ;
126- shapeIn [ attr1 ] = in1 ;
127- }
161+ // Coerce x0, x1, y0, y1
162+ if ( noPath ) {
163+ // hack until V3.0 when log has regular range behavior - make it look like other
164+ // ranges to send to coerce, then put it back after
165+ // this is all to give reasonable default position behavior on log axes, which is
166+ // a pretty unimportant edge case so we could just ignore this.
167+ const attr0 = axLetter + '0' ;
168+ const attr1 = axLetter + '1' ;
169+ const in0 = shapeIn [ attr0 ] ;
170+ const in1 = shapeIn [ attr1 ] ;
171+ shapeIn [ attr0 ] = pos2r ( shapeIn [ attr0 ] , true ) ;
172+ shapeIn [ attr1 ] = pos2r ( shapeIn [ attr1 ] , true ) ;
173+
174+ if ( sizeMode === 'pixel' ) {
175+ coerce ( attr0 , pixelDflts [ 0 ] ) ;
176+ coerce ( attr1 , pixelDflts [ 1 ] ) ;
177+ } else {
178+ Axes . coercePosition ( shapeOut , gdMock , coerce , axRef , attr0 , dflts [ 0 ] ) ;
179+ Axes . coercePosition ( shapeOut , gdMock , coerce , axRef , attr1 , dflts [ 1 ] ) ;
180+ }
181+
182+ // hack part 2
183+ shapeOut [ attr0 ] = r2pos ( shapeOut [ attr0 ] ) ;
184+ shapeOut [ attr1 ] = r2pos ( shapeOut [ attr1 ] ) ;
185+ shapeIn [ attr0 ] = in0 ;
186+ shapeIn [ attr1 ] = in1 ;
187+ }
128188
129- // Coerce xanchor and yanchor
130- if ( sizeMode === 'pixel' ) {
131- // Hack for log axis described above
132- var inAnchor = shapeIn [ attrAnchor ] ;
133- shapeIn [ attrAnchor ] = pos2r ( shapeIn [ attrAnchor ] , true ) ;
189+ // Coerce xanchor and yanchor
190+ if ( sizeMode === 'pixel' ) {
191+ // Hack for log axis described above
192+ const inAnchor = shapeIn [ attrAnchor ] ;
193+ shapeIn [ attrAnchor ] = pos2r ( shapeIn [ attrAnchor ] , true ) ;
134194
135- Axes . coercePosition ( shapeOut , gdMock , coerce , axRef , attrAnchor , 0.25 ) ;
195+ Axes . coercePosition ( shapeOut , gdMock , coerce , axRef , attrAnchor , 0.25 ) ;
136196
137- // Hack part 2
138- shapeOut [ attrAnchor ] = r2pos ( shapeOut [ attrAnchor ] ) ;
139- shapeIn [ attrAnchor ] = inAnchor ;
197+ // Hack part 2
198+ shapeOut [ attrAnchor ] = r2pos ( shapeOut [ attrAnchor ] ) ;
199+ shapeIn [ attrAnchor ] = inAnchor ;
200+ }
140201 }
141- }
202+ } ) ;
142203
143204 if ( noPath ) {
144205 Lib . noneOrAll ( shapeIn , shapeOut , [ 'x0' , 'x1' , 'y0' , 'y1' ] ) ;
0 commit comments