Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 2k
Multi-axis Shapes#7666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Multi-axis Shapes #7666
Changes from all commits
c8be45fa7b3bb2ace820ba910d424d70fd3d3208e9e5a71ad4a571aa5f7eedf777cded0a5093fde1e72ce089cdfbe959e9ef9409928016cf13c28664cbfb3f81aab228489819b2a246f3262220296bd55d940675f8dfb397645c4035a00017fa1164e61a178a78674a1736f46fe4576ea9aa1fcd70b23dFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| - Add support for shapes to reference multiple axes [[#7666](https://github.com/plotly/plotly.js/pull/7666)] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -68,77 +68,138 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) { | ||
| var ySizeMode = coerce('ysizemode'); | ||
| // positioning | ||
| var axLetters = ['x', 'y']; | ||
| for (var i = 0; i < 2; i++) { | ||
| var axLetter = axLetters[i]; | ||
| const dflts = [0.25, 0.75]; | ||
| const pixelDflts = [0, 10]; | ||
| ['x', 'y'].forEach(axLetter => { | ||
| var attrAnchor = axLetter + 'anchor'; | ||
| var sizeMode = axLetter === 'x' ? xSizeMode : ySizeMode; | ||
| var gdMock = { _fullLayout: fullLayout }; | ||
| var ax; | ||
| var pos2r; | ||
| var r2pos; | ||
| // xref, yref | ||
| var axRef = Axes.coerceRef(shapeIn, shapeOut, gdMock, axLetter, undefined, 'paper'); | ||
| var axRefType = Axes.getRefType(axRef); | ||
| if (axRefType === 'range') { | ||
| ax = Axes.getFromId(gdMock, axRef); | ||
| ax._shapeIndices.push(shapeOut._index); | ||
| r2pos = helpers.rangeToShapePosition(ax); | ||
| pos2r = helpers.shapePositionToRange(ax); | ||
| if (ax.type === 'category' || ax.type === 'multicategory') { | ||
| coerce(axLetter + '0shift'); | ||
| coerce(axLetter + '1shift'); | ||
| } | ||
| // xref, yref - handle both string and array values | ||
| var axRef; | ||
| const refAttr = axLetter + 'ref'; | ||
| const inputRef = shapeIn[refAttr]; | ||
| if(Array.isArray(inputRef) && inputRef.length > 0) { | ||
| // Array case: use coerceRefArray for validation | ||
| const expectedLen = helpers.countDefiningCoords(shapeType, path, axLetter); | ||
| axRef = Axes.coerceRefArray(shapeIn, shapeOut, gdMock, axLetter, undefined, 'paper', expectedLen); | ||
| shapeOut['_' + axLetter + 'refArray'] = true; | ||
| } else { | ||
| pos2r = r2pos = Lib.identity; | ||
| // String/undefined case: use coerceRef | ||
| axRef = Axes.coerceRef(shapeIn, shapeOut, gdMock, axLetter, undefined, 'paper'); | ||
| } | ||
| // Coerce x0, x1, y0, y1 | ||
| if (noPath) { | ||
| var dflt0 = 0.25; | ||
| var dflt1 = 0.75; | ||
| // hack until V3.0 when log has regular range behavior - make it look like other | ||
| // ranges to send to coerce, then put it back after | ||
| // this is all to give reasonable default position behavior on log axes, which is | ||
| // a pretty unimportant edge case so we could just ignore this. | ||
| var attr0 = axLetter + '0'; | ||
| var attr1 = axLetter + '1'; | ||
| var in0 = shapeIn[attr0]; | ||
| var in1 = shapeIn[attr1]; | ||
| shapeIn[attr0] = pos2r(shapeIn[attr0], true); | ||
| shapeIn[attr1] = pos2r(shapeIn[attr1], true); | ||
| if (sizeMode === 'pixel') { | ||
| coerce(attr0, 0); | ||
| coerce(attr1, 10); | ||
| if(Array.isArray(axRef)) { | ||
| // Register the shape with all referenced axes for redrawing purposes | ||
| axRef.forEach(function(ref) { | ||
| if(Axes.getRefType(ref) === 'range') { | ||
| ax = Axes.getFromId(gdMock, ref); | ||
| if(ax && ax._shapeIndices.indexOf(shapeOut._index) === -1) { | ||
| ax._shapeIndices.push(shapeOut._index); | ||
alexshoe marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| } | ||
alexshoe marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| }); | ||
| if(noPath) { | ||
| [0, 1].forEach(function(i) { | ||
| const ref = axRef[i]; | ||
| const refType = Axes.getRefType(ref); | ||
| if(refType === 'range') { | ||
| ax = Axes.getFromId(gdMock, ref); | ||
| pos2r = helpers.shapePositionToRange(ax); | ||
| r2pos = helpers.rangeToShapePosition(ax); | ||
| if(ax.type === 'category' || ax.type === 'multicategory') { | ||
| coerce(axLetter + i + 'shift'); | ||
| } | ||
| } else { | ||
| pos2r = r2pos = Lib.identity; | ||
| } | ||
| const attr = axLetter + i; | ||
| const inValue = shapeIn[attr]; | ||
| shapeIn[attr] = pos2r(shapeIn[attr], true); | ||
| if(sizeMode === 'pixel') { | ||
| coerce(attr, pixelDflts[i]); | ||
| } else { | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, ref, attr, dflts[i]); | ||
| } | ||
| shapeOut[attr] = r2pos(shapeOut[attr]); | ||
| shapeIn[attr] = inValue; | ||
| if(i === 0 && sizeMode === 'pixel') { | ||
| const inAnchor = shapeIn[attrAnchor]; | ||
| shapeIn[attrAnchor] = pos2r(shapeIn[attrAnchor], true); | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, ref, attrAnchor, 0.25); | ||
| shapeOut[attrAnchor] = r2pos(shapeOut[attrAnchor]); | ||
| shapeIn[attrAnchor] = inAnchor; | ||
| } | ||
| }); | ||
| } | ||
| } else { | ||
| const axRefType = Axes.getRefType(axRef); | ||
| if(axRefType === 'range') { | ||
| ax = Axes.getFromId(gdMock, axRef); | ||
| ax._shapeIndices.push(shapeOut._index); | ||
| r2pos = helpers.rangeToShapePosition(ax); | ||
| pos2r = helpers.shapePositionToRange(ax); | ||
| if(noPath && (ax.type === 'category' || ax.type === 'multicategory')) { | ||
| coerce(axLetter + '0shift'); | ||
| coerce(axLetter + '1shift'); | ||
| } | ||
| } else { | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attr0, dflt0); | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attr1, dflt1); | ||
| pos2r = r2pos = Lib.identity; | ||
| } | ||
| // hack part 2 | ||
| shapeOut[attr0] = r2pos(shapeOut[attr0]); | ||
| shapeOut[attr1] = r2pos(shapeOut[attr1]); | ||
| shapeIn[attr0] = in0; | ||
| shapeIn[attr1] = in1; | ||
| } | ||
| // Coerce x0, x1, y0, y1 | ||
| if(noPath) { | ||
| // hack until V3.0 when log has regular range behavior - make it look like other | ||
| // ranges to send to coerce, then put it back after | ||
| // this is all to give reasonable default position behavior on log axes, which is | ||
| // a pretty unimportant edge case so we could just ignore this. | ||
| const attr0 = axLetter + '0'; | ||
| const attr1 = axLetter + '1'; | ||
| const in0 = shapeIn[attr0]; | ||
| const in1 = shapeIn[attr1]; | ||
| shapeIn[attr0] = pos2r(shapeIn[attr0], true); | ||
| shapeIn[attr1] = pos2r(shapeIn[attr1], true); | ||
| if(sizeMode === 'pixel') { | ||
| coerce(attr0, pixelDflts[0]); | ||
| coerce(attr1, pixelDflts[1]); | ||
| } else { | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attr0, dflts[0]); | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attr1, dflts[1]); | ||
| } | ||
| // hack part 2 | ||
| shapeOut[attr0] = r2pos(shapeOut[attr0]); | ||
| shapeOut[attr1] = r2pos(shapeOut[attr1]); | ||
| shapeIn[attr0] = in0; | ||
| shapeIn[attr1] = in1; | ||
| } | ||
| // Coerce xanchor and yanchor | ||
| if (sizeMode === 'pixel') { | ||
| // Hack for log axis described above | ||
| var inAnchor = shapeIn[attrAnchor]; | ||
| shapeIn[attrAnchor] = pos2r(shapeIn[attrAnchor], true); | ||
| // Coerce xanchor and yanchor | ||
| if(sizeMode === 'pixel') { | ||
| // Hack for log axis described above | ||
| const inAnchor = shapeIn[attrAnchor]; | ||
| shapeIn[attrAnchor] = pos2r(shapeIn[attrAnchor], true); | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attrAnchor, 0.25); | ||
| Axes.coercePosition(shapeOut, gdMock, coerce, axRef, attrAnchor, 0.25); | ||
| // Hack part 2 | ||
| shapeOut[attrAnchor] = r2pos(shapeOut[attrAnchor]); | ||
| shapeIn[attrAnchor] = inAnchor; | ||
| // Hack part 2 | ||
| shapeOut[attrAnchor] = r2pos(shapeOut[attrAnchor]); | ||
| shapeIn[attrAnchor] = inAnchor; | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| if (noPath) { | ||
| Lib.noneOrAll(shapeIn, shapeOut, ['x0', 'x1', 'y0', 'y1']); | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.