From aa0cd7a04e6f34a5963e28d177e2718632fdddfd Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 27 May 2024 11:43:05 +0200 Subject: [PATCH 01/23] property shape.x_shift/y_shift for adjusting the shape coordinates Only for shapes with reference to (multi-)category axis --- src/components/shapes/attributes.js | 23 ++++- src/components/shapes/calc_autorange.js | 13 ++- src/components/shapes/defaults.js | 3 + src/components/shapes/display_labels.js | 6 +- src/components/shapes/helpers.js | 37 +++++--- .../mocks/zzz_shape_shift_horizontal.json | 87 +++++++++++++++++++ .../image/mocks/zzz_shape_shift_vertical.json | 56 ++++++++++++ test/plot-schema.json | 16 ++++ 8 files changed, 223 insertions(+), 18 deletions(-) create mode 100644 test/image/mocks/zzz_shape_shift_horizontal.json create mode 100644 test/image/mocks/zzz_shape_shift_vertical.json diff --git a/src/components/shapes/attributes.js b/src/components/shapes/attributes.js index 6a6e5a3a846..2c507e3ac5f 100644 --- a/src/components/shapes/attributes.js +++ b/src/components/shapes/attributes.js @@ -220,7 +220,28 @@ module.exports = templatedArray('shape', { 'See `type` and `ysizemode` for more info.' ].join(' ') }, - + x_shift: { + valType: 'number', + dflt: 0, + min: -0.5, + max: 0.5, + editType: 'calc', + description: [ + 'Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of', + 'the reference unit.' + ].join(' ') + }, + y_shift: { + valType: 'number', + dflt: 0, + min: -0.5, + max: 0.5, + editType: 'calc', + description: [ + 'Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of', + 'the reference unit.' + ].join(' ') + }, path: { valType: 'string', editType: 'calc+arraydraw', diff --git a/src/components/shapes/calc_autorange.js b/src/components/shapes/calc_autorange.js index 7892bceb12f..b4e79d69b69 100644 --- a/src/components/shapes/calc_autorange.js +++ b/src/components/shapes/calc_autorange.js @@ -27,7 +27,7 @@ module.exports = function calcAutorange(gd) { var vx1 = shape.xsizemode === 'pixel' ? shape.xanchor : shape.x1; ax = Axes.getFromId(gd, shape.xref); - bounds = shapeBounds(ax, vx0, vx1, shape.path, constants.paramIsX); + bounds = shapeBounds(ax, vx0, vx1, shape.path, shape.x_shift, constants.paramIsX); if(bounds) { shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcXPaddingOptions(shape)); } @@ -38,7 +38,7 @@ module.exports = function calcAutorange(gd) { var vy1 = shape.ysizemode === 'pixel' ? shape.yanchor : shape.y1; ax = Axes.getFromId(gd, shape.yref); - bounds = shapeBounds(ax, vy0, vy1, shape.path, constants.paramIsY); + bounds = shapeBounds(ax, vy0, vy1, shape.path, shape.y_shift, constants.paramIsY); if(bounds) { shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcYPaddingOptions(shape)); } @@ -77,8 +77,13 @@ function calcPaddingOptions(lineWidth, sizeMode, v0, v1, path, isYAxis) { } } -function shapeBounds(ax, v0, v1, path, paramsToUse) { - var convertVal = (ax.type === 'category' || ax.type === 'multicategory') ? ax.r2c : ax.d2c; +function shapeBounds(ax, v0, v1, path, shift, paramsToUse) { + var convertVal; + if(ax.type === 'category' || ax.type === 'multicategory') { + convertVal = function(v) { return ax.r2c(v) + shift; }; + } else { + convertVal = ax.d2c; + } if(v0 !== undefined) return [convertVal(v0), convertVal(v1)]; if(!path) return; diff --git a/src/components/shapes/defaults.js b/src/components/shapes/defaults.js index 3f52437b654..057198d3eaa 100644 --- a/src/components/shapes/defaults.js +++ b/src/components/shapes/defaults.js @@ -75,6 +75,9 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) { var pos2r; var r2pos; + coerce('x_shift'); + coerce('y_shift'); + // xref, yref var axRef = Axes.coerceRef(shapeIn, shapeOut, gdMock, axLetter, undefined, 'paper'); diff --git a/src/components/shapes/display_labels.js b/src/components/shapes/display_labels.js index 82c0856d943..894c69aa230 100644 --- a/src/components/shapes/display_labels.js +++ b/src/components/shapes/display_labels.js @@ -89,10 +89,12 @@ module.exports = function drawLabel(gd, index, options, shapeGroup) { // Setup conversion functions var xa = Axes.getFromId(gd, options.xref); var xRefType = Axes.getRefType(options.xref); + var xShift = options.x_shift; var ya = Axes.getFromId(gd, options.yref); var yRefType = Axes.getRefType(options.yref); - var x2p = helpers.getDataToPixel(gd, xa, false, xRefType); - var y2p = helpers.getDataToPixel(gd, ya, true, yRefType); + var yShift = options.y_shift; + var x2p = helpers.getDataToPixel(gd, xa, false, xRefType, xShift); + var y2p = helpers.getDataToPixel(gd, ya, true, yRefType, yShift); shapex0 = x2p(options.x0); shapex1 = x2p(options.x1); shapey0 = y2p(options.y0); diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index d07fe6948eb..6a9224d065a 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -53,7 +53,7 @@ exports.extractPathCoords = function(path, paramsToUse, isRaw) { return extractedCoordinates; }; -exports.getDataToPixel = function(gd, axis, isVertical, refType) { +exports.getDataToPixel = function(gd, axis, isVertical, refType, shift) { var gs = gd._fullLayout._size; var dataToPixel; @@ -66,7 +66,15 @@ exports.getDataToPixel = function(gd, axis, isVertical, refType) { var d2r = exports.shapePositionToRange(axis); dataToPixel = function(v) { - return axis._offset + axis.r2p(d2r(v, true)); + var shiftPixels = 0; + if(axis.type === 'category' || axis.type === 'multicategory') { + if(isVertical) { + shiftPixels = -1 * ((gs.h - axis.r2p(d2r(0.5, true))) * shift); + } else { + shiftPixels = axis.r2p(d2r(0.5, true)) * shift; + } + } + return axis._offset + axis.r2p(d2r(v, true)) + shiftPixels; }; if(axis.type === 'date') dataToPixel = exports.decodeDate(dataToPixel); @@ -179,6 +187,8 @@ exports.getPathString = function(gd, options) { var ya = Axes.getFromId(gd, options.yref); var gs = gd._fullLayout._size; var x2r, x2p, y2r, y2p; + var shiftUnitX = 0; + var shiftUnitY = 0; var x0, x1, y0, y1; if(xa) { @@ -187,6 +197,9 @@ exports.getPathString = function(gd, options) { } else { x2r = exports.shapePositionToRange(xa); x2p = function(v) { return xa._offset + xa.r2p(x2r(v, true)); }; + if(xa.type === 'category' || xa.type === 'multicategory') { + shiftUnitX = xa.r2p(x2r(0.5, true)); + } } } else { x2p = function(v) { return gs.l + gs.w * v; }; @@ -198,6 +211,9 @@ exports.getPathString = function(gd, options) { } else { y2r = exports.shapePositionToRange(ya); y2p = function(v) { return ya._offset + ya.r2p(y2r(v, true)); }; + if(ya.type === 'category' || ya.type === 'multicategory') { + shiftUnitY = gs.h - ya.r2p(y2r(0.5, true)); + } } } else { y2p = function(v) { return gs.t + gs.h * (1 - v); }; @@ -208,23 +224,22 @@ exports.getPathString = function(gd, options) { if(ya && ya.type === 'date') y2p = exports.decodeDate(y2p); return convertPath(options, x2p, y2p); } - if(options.xsizemode === 'pixel') { var xAnchorPos = x2p(options.xanchor); - x0 = xAnchorPos + options.x0; - x1 = xAnchorPos + options.x1; + x0 = xAnchorPos + options.x0 + shiftUnitX * options.x_shift; + x1 = xAnchorPos + options.x1 + shiftUnitX * options.x_shift; } else { - x0 = x2p(options.x0); - x1 = x2p(options.x1); + x0 = x2p(options.x0) + shiftUnitX * options.x_shift; + x1 = x2p(options.x1) + shiftUnitX * options.x_shift; } if(options.ysizemode === 'pixel') { var yAnchorPos = y2p(options.yanchor); - y0 = yAnchorPos - options.y0; - y1 = yAnchorPos - options.y1; + y0 = yAnchorPos - options.y0 - shiftUnitY * options.y_shift; + y1 = yAnchorPos - options.y1 - shiftUnitY * options.y_shift; } else { - y0 = y2p(options.y0); - y1 = y2p(options.y1); + y0 = y2p(options.y0) - shiftUnitY * options.y_shift; + y1 = y2p(options.y1) - shiftUnitY * options.y_shift; } if(type === 'line') return 'M' + x0 + ',' + y0 + 'L' + x1 + ',' + y1; diff --git a/test/image/mocks/zzz_shape_shift_horizontal.json b/test/image/mocks/zzz_shape_shift_horizontal.json new file mode 100644 index 00000000000..73c37364904 --- /dev/null +++ b/test/image/mocks/zzz_shape_shift_horizontal.json @@ -0,0 +1,87 @@ +{ + "data": [ + { + "y": [ + ["A", "A", "B", "B"], ["C", "D", "C", "D"] + ], + "x": [ + 1, 2, 3, 4 + ], + "type": "bar", + "marker": { + "color": "rgba(153, 217, 234, 1)" + }, + "orientation": "h" + }, + { + "y": [ + ["A", "A", "B", "B"], ["C", "D", "C", "D"] + ], + "x": [ + 4, 3, 2, 1 + ], + "type": "bar", + "orientation": "h" + } + ], + "layout": { + "shapes": [ + { + "layer": "above", + "type": "rect", + "label": { + "text": "around A,D", + "textposition": "bottom center", + "textangle": 0 + }, + "line": { + "color": "black", + "width": 3.0 + }, + "y0": ["A", "C"], + "y1": ["A", "D"], + "x0": 0, + "x1": 0.25, + "y_shift": 0.5, + "xref": "paper" + }, + { + "layer": "above", + "type": "line", + "label": { + "text": "on B,D", + "textposition": "middle", + "textangle": 0 + }, + "line": { + "color": "blue", + "width": 3.0 + }, + "y0": ["B", "D"], + "y1": ["B", "D"], + "x0": 0, + "x1": 0.25, + "xref": "paper" + }, + { + "layer": "above", + "type": "line", + "label": { + "text": "Before B,D", + "textposition": "middle", + "textangle": 0 + }, + "line": { + "color": "green", + "width": 3.0 + }, + "y0": ["B", "D"], + "y1": ["B", "D"], + "x0": 0, + "x1": 0.25, + "y_shift": -0.5, + "xref": "paper" + } + ] + } +} diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json new file mode 100644 index 00000000000..190af51ec79 --- /dev/null +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -0,0 +1,56 @@ +{ + "data": [ + { + "x": [ + "A", "B", "C", "D" + ], + "y": [ + 1, 2, 3, 4 + ], + "type": "bar" + } + ], + "layout": { + "width": 600, + "shapes": [ + { + "layer": "above", + "type": "line", + "label": { + "text": "right from A", + "textposition": "end", + "textangle": 0 + }, + "line": { + "color": "yellow", + "width": 3.0 + }, + "x0": "A", + "x1": "A", + "y0": 0, + "y1": 0.5, + "x_shift": 0.5, + "yref": "paper" + }, + { + "layer": "above", + "type": "line", + "label": { + "text": "slightly left from D", + "textposition": "end", + "textangle": 0 + }, + "line": { + "color": "pink", + "width": 3.0 + }, + "x0": 3, + "x1": 3, + "y0": 0, + "y1": 0.5, + "x_shift": -0.25, + "yref": "paper" + } + ] + } +} diff --git a/test/plot-schema.json b/test/plot-schema.json index fd2b1659e37..8fc3eb49083 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -10000,6 +10000,14 @@ "legendonly" ] }, + "x_shift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 0.5, + "min": -0.5, + "valType": "number" + }, "x0": { "description": "Sets the shape's starting x position. See `type` and `xsizemode` for more info.", "editType": "calc+arraydraw", @@ -10034,6 +10042,14 @@ "pixel" ] }, + "y_shift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 0.5, + "min": -0.5, + "valType": "number" + }, "y0": { "description": "Sets the shape's starting y position. See `type` and `ysizemode` for more info.", "editType": "calc+arraydraw", From 44d1858ea7a2d657a8cc51cbf72f976af1d0bf22 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 27 May 2024 12:18:17 +0200 Subject: [PATCH 02/23] Add draftlog for PR 7005 --- draftlogs/7005_add.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 draftlogs/7005_add.md diff --git a/draftlogs/7005_add.md b/draftlogs/7005_add.md new file mode 100644 index 00000000000..35be877cc3a --- /dev/null +++ b/draftlogs/7005_add.md @@ -0,0 +1 @@ + - Add property shape.x_shift/shape.y_shift for shapes referencing (multi-)category axes [[#7005](https://github.com/plotly/plotly.js/pull/7005)] From 7abea61e253a20291b1f7a12bed13e3ea5c97441 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 27 May 2024 12:51:33 +0200 Subject: [PATCH 03/23] Add x_shift/y_shift for selections as well, add selection example to mock --- draftlogs/7005_add.md | 2 +- src/components/selections/attributes.js | 23 ++++++++++++++++++- src/components/selections/defaults.js | 2 ++ .../image/mocks/zzz_shape_shift_vertical.json | 9 ++++++++ test/plot-schema.json | 16 +++++++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/draftlogs/7005_add.md b/draftlogs/7005_add.md index 35be877cc3a..e50081e3dfc 100644 --- a/draftlogs/7005_add.md +++ b/draftlogs/7005_add.md @@ -1 +1 @@ - - Add property shape.x_shift/shape.y_shift for shapes referencing (multi-)category axes [[#7005](https://github.com/plotly/plotly.js/pull/7005)] + - Add property x_shift/y_shift for shapes/selections referencing (multi-)category axes [[#7005](https://github.com/plotly/plotly.js/pull/7005)] diff --git a/src/components/selections/attributes.js b/src/components/selections/attributes.js index 443eda366ce..79c53b99bad 100644 --- a/src/components/selections/attributes.js +++ b/src/components/selections/attributes.js @@ -53,7 +53,28 @@ module.exports = overrideAll(templatedArray('selection', { valType: 'any', description: 'Sets the selection\'s end y position.' }, - + x_shift: { + valType: 'number', + dflt: 0, + min: -0.5, + max: 0.5, + editType: 'calc', + description: [ + 'Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of', + 'the reference unit.' + ].join(' ') + }, + y_shift: { + valType: 'number', + dflt: 0, + min: -0.5, + max: 0.5, + editType: 'calc', + description: [ + 'Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of', + 'the reference unit.' + ].join(' ') + }, path: { valType: 'string', editType: 'arraydraw', diff --git a/src/components/selections/defaults.js b/src/components/selections/defaults.js index 9a6a2ddc11a..ee251f4c3cc 100644 --- a/src/components/selections/defaults.js +++ b/src/components/selections/defaults.js @@ -49,6 +49,8 @@ function handleSelectionDefaults(selectionIn, selectionOut, fullLayout) { coerce('line.color'); coerce('line.width'); coerce('line.dash'); + coerce('x_shift'); + coerce('y_shift'); // positioning var axLetters = ['x', 'y']; diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json index 190af51ec79..fc29b8ffab8 100644 --- a/test/image/mocks/zzz_shape_shift_vertical.json +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -51,6 +51,15 @@ "x_shift": -0.25, "yref": "paper" } + ], + "selections": [ + { + "x0": 0, + "x1": 4, + "y0": 1, + "y1": 3, + "x_shift": -0.5 + } ] } } diff --git a/test/plot-schema.json b/test/plot-schema.json index 8fc3eb49083..50c8fcc6ca8 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -9550,6 +9550,14 @@ "path" ] }, + "x_shift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "arraydraw", + "max": 0.5, + "min": -0.5, + "valType": "number" + }, "x0": { "description": "Sets the selection's starting x position.", "editType": "arraydraw", @@ -9569,6 +9577,14 @@ "/^x([2-9]|[1-9][0-9]+)?( domain)?$/" ] }, + "y_shift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "arraydraw", + "max": 0.5, + "min": -0.5, + "valType": "number" + }, "y0": { "description": "Sets the selection's starting y position.", "editType": "arraydraw", From a617017fe0b2633588633eb2295bfeb81e83dda4 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 27 May 2024 13:09:24 +0200 Subject: [PATCH 04/23] baseline images zzz_shape_shift_horizontal and zzz_shape_shift_vertical --- .../baselines/zzz_shape_shift_horizontal.png | Bin 0 -> 20751 bytes .../baselines/zzz_shape_shift_vertical.png | Bin 0 -> 20710 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/image/baselines/zzz_shape_shift_horizontal.png create mode 100644 test/image/baselines/zzz_shape_shift_vertical.png diff --git a/test/image/baselines/zzz_shape_shift_horizontal.png b/test/image/baselines/zzz_shape_shift_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..427911e789b537a850a9bab844e9db00db4c8010 GIT binary patch literal 20751 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%0Ais< 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 literal 0 HcmV?d00001 From c2f7f27153344f7645f6f99c9de84c1800021be0 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 27 May 2024 14:26:19 +0200 Subject: [PATCH 05/23] Update shapes_test after adding shift param to getDataToPixel If the passed shift param is undefined, use shift 0 instead. --- src/components/shapes/display_labels.js | 4 ++-- src/components/shapes/draw.js | 6 ++++-- src/components/shapes/helpers.js | 4 ++-- test/jasmine/tests/shapes_test.js | 17 ++++++++--------- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/components/shapes/display_labels.js b/src/components/shapes/display_labels.js index 894c69aa230..116aa377c05 100644 --- a/src/components/shapes/display_labels.js +++ b/src/components/shapes/display_labels.js @@ -93,8 +93,8 @@ module.exports = function drawLabel(gd, index, options, shapeGroup) { var ya = Axes.getFromId(gd, options.yref); var yRefType = Axes.getRefType(options.yref); var yShift = options.y_shift; - var x2p = helpers.getDataToPixel(gd, xa, false, xRefType, xShift); - var y2p = helpers.getDataToPixel(gd, ya, true, yRefType, yShift); + var x2p = helpers.getDataToPixel(gd, xa, xShift, false, xRefType); + var y2p = helpers.getDataToPixel(gd, ya, yShift, true, yRefType); shapex0 = x2p(options.x0); shapex1 = x2p(options.x1); shapey0 = y2p(options.y0); diff --git a/src/components/shapes/draw.js b/src/components/shapes/draw.js index 417c884c3f2..1c6871b436c 100644 --- a/src/components/shapes/draw.js +++ b/src/components/shapes/draw.js @@ -225,10 +225,12 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer, editHe // setup conversion functions var xa = Axes.getFromId(gd, shapeOptions.xref); var xRefType = Axes.getRefType(shapeOptions.xref); + var xShift = shapeOptions.x_shift; var ya = Axes.getFromId(gd, shapeOptions.yref); var yRefType = Axes.getRefType(shapeOptions.yref); - var x2p = helpers.getDataToPixel(gd, xa, false, xRefType); - var y2p = helpers.getDataToPixel(gd, ya, true, yRefType); + var yShift = shapeOptions.y_shift; + var x2p = helpers.getDataToPixel(gd, xa, xShift, false, xRefType); + var y2p = helpers.getDataToPixel(gd, ya, yShift, true, yRefType); var p2x = helpers.getPixelToData(gd, xa, false, xRefType); var p2y = helpers.getPixelToData(gd, ya, true, yRefType); diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index 6a9224d065a..51ac858fc54 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -53,7 +53,7 @@ exports.extractPathCoords = function(path, paramsToUse, isRaw) { return extractedCoordinates; }; -exports.getDataToPixel = function(gd, axis, isVertical, refType, shift) { +exports.getDataToPixel = function(gd, axis, shift, isVertical, refType) { var gs = gd._fullLayout._size; var dataToPixel; @@ -74,7 +74,7 @@ exports.getDataToPixel = function(gd, axis, isVertical, refType, shift) { shiftPixels = axis.r2p(d2r(0.5, true)) * shift; } } - return axis._offset + axis.r2p(d2r(v, true)) + shiftPixels; + return axis._offset + axis.r2p(d2r(v, true)) + (shiftPixels || 0); }; if(axis.type === 'date') dataToPixel = exports.decodeDate(dataToPixel); diff --git a/test/jasmine/tests/shapes_test.js b/test/jasmine/tests/shapes_test.js index 112add2bee7..664b21d8d6b 100644 --- a/test/jasmine/tests/shapes_test.js +++ b/test/jasmine/tests/shapes_test.js @@ -1487,8 +1487,8 @@ describe('Test shapes', function() { function testShapeDrag(dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa); - var y2p = helpers.getDataToPixel(gd, ya, true); + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); var initialCoordinates = getShapeCoordinates(layoutShape, x2p, y2p); @@ -1514,8 +1514,8 @@ describe('Test shapes', function() { function testPathDrag(dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa); - var y2p = helpers.getDataToPixel(gd, ya, true); + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); var initialPath = layoutShape.path; var initialCoordinates = getPathCoordinates(initialPath, x2p, y2p); @@ -1546,8 +1546,8 @@ describe('Test shapes', function() { function testShapeResize(direction, dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa); - var y2p = helpers.getDataToPixel(gd, ya, true); + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); var initialCoordinates = getShapeCoordinates(layoutShape, x2p, y2p); @@ -1590,9 +1590,8 @@ describe('Test shapes', function() { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa); - var y2p = helpers.getDataToPixel(gd, ya, true); - + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); promise = promise.then(function() { var dragHandle = pointToMove === 'start' ? From fdcaa0c8c02f67dc54386c49fd998f2df45fa956 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Fri, 31 May 2024 11:10:18 +0200 Subject: [PATCH 06/23] =?UTF-8?q?Rename=20x=5Fshift/y=5Fshift=20=E2=86=92?= =?UTF-8?q?=20xshift/yshift?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/selections/attributes.js | 6 ++- src/components/selections/defaults.js | 4 +- src/components/shapes/attributes.js | 25 +++++---- src/components/shapes/calc_autorange.js | 4 +- src/components/shapes/defaults.js | 4 +- src/components/shapes/display_labels.js | 4 +- src/components/shapes/draw.js | 4 +- src/components/shapes/helpers.js | 16 +++--- .../mocks/zzz_shape_shift_horizontal.json | 4 +- .../image/mocks/zzz_shape_shift_vertical.json | 6 +-- test/jasmine/tests/shapes_test.js | 16 +++--- test/plot-schema.json | 52 +++++++++---------- 12 files changed, 73 insertions(+), 72 deletions(-) diff --git a/src/components/selections/attributes.js b/src/components/selections/attributes.js index 79c53b99bad..0ad3d07e6ca 100644 --- a/src/components/selections/attributes.js +++ b/src/components/selections/attributes.js @@ -53,7 +53,8 @@ module.exports = overrideAll(templatedArray('selection', { valType: 'any', description: 'Sets the selection\'s end y position.' }, - x_shift: { + + xshift: { valType: 'number', dflt: 0, min: -0.5, @@ -64,7 +65,7 @@ module.exports = overrideAll(templatedArray('selection', { 'the reference unit.' ].join(' ') }, - y_shift: { + yshift: { valType: 'number', dflt: 0, min: -0.5, @@ -75,6 +76,7 @@ module.exports = overrideAll(templatedArray('selection', { 'the reference unit.' ].join(' ') }, + path: { valType: 'string', editType: 'arraydraw', diff --git a/src/components/selections/defaults.js b/src/components/selections/defaults.js index ee251f4c3cc..c5079c21c55 100644 --- a/src/components/selections/defaults.js +++ b/src/components/selections/defaults.js @@ -49,8 +49,8 @@ function handleSelectionDefaults(selectionIn, selectionOut, fullLayout) { coerce('line.color'); coerce('line.width'); coerce('line.dash'); - coerce('x_shift'); - coerce('y_shift'); + coerce('xshift'); + coerce('yshift'); // positioning var axLetters = ['x', 'y']; diff --git a/src/components/shapes/attributes.js b/src/components/shapes/attributes.js index 2c507e3ac5f..7effdda36e3 100644 --- a/src/components/shapes/attributes.js +++ b/src/components/shapes/attributes.js @@ -169,7 +169,17 @@ module.exports = templatedArray('shape', { 'See `type` and `xsizemode` for more info.' ].join(' ') }, - + xshift: { + valType: 'number', + dflt: 0, + min: -0.5, + max: 0.5, + editType: 'calc', + description: [ + 'Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of', + 'the reference unit.' + ].join(' ') + }, yref: extendFlat({}, annAttrs.yref, { description: [ 'Sets the shape\'s y coordinate axis.', @@ -220,18 +230,7 @@ module.exports = templatedArray('shape', { 'See `type` and `ysizemode` for more info.' ].join(' ') }, - x_shift: { - valType: 'number', - dflt: 0, - min: -0.5, - max: 0.5, - editType: 'calc', - description: [ - 'Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of', - 'the reference unit.' - ].join(' ') - }, - y_shift: { + yshift: { valType: 'number', dflt: 0, min: -0.5, diff --git a/src/components/shapes/calc_autorange.js b/src/components/shapes/calc_autorange.js index b4e79d69b69..307c1eef171 100644 --- a/src/components/shapes/calc_autorange.js +++ b/src/components/shapes/calc_autorange.js @@ -27,7 +27,7 @@ module.exports = function calcAutorange(gd) { var vx1 = shape.xsizemode === 'pixel' ? shape.xanchor : shape.x1; ax = Axes.getFromId(gd, shape.xref); - bounds = shapeBounds(ax, vx0, vx1, shape.path, shape.x_shift, constants.paramIsX); + bounds = shapeBounds(ax, vx0, vx1, shape.path, shape.xshift, constants.paramIsX); if(bounds) { shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcXPaddingOptions(shape)); } @@ -38,7 +38,7 @@ module.exports = function calcAutorange(gd) { var vy1 = shape.ysizemode === 'pixel' ? shape.yanchor : shape.y1; ax = Axes.getFromId(gd, shape.yref); - bounds = shapeBounds(ax, vy0, vy1, shape.path, shape.y_shift, constants.paramIsY); + bounds = shapeBounds(ax, vy0, vy1, shape.path, shape.yshift, constants.paramIsY); if(bounds) { shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcYPaddingOptions(shape)); } diff --git a/src/components/shapes/defaults.js b/src/components/shapes/defaults.js index 057198d3eaa..69e8fc0521e 100644 --- a/src/components/shapes/defaults.js +++ b/src/components/shapes/defaults.js @@ -75,8 +75,8 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) { var pos2r; var r2pos; - coerce('x_shift'); - coerce('y_shift'); + coerce('xshift'); + coerce('yshift'); // xref, yref var axRef = Axes.coerceRef(shapeIn, shapeOut, gdMock, axLetter, undefined, diff --git a/src/components/shapes/display_labels.js b/src/components/shapes/display_labels.js index 116aa377c05..a080ad5f3da 100644 --- a/src/components/shapes/display_labels.js +++ b/src/components/shapes/display_labels.js @@ -89,10 +89,10 @@ module.exports = function drawLabel(gd, index, options, shapeGroup) { // Setup conversion functions var xa = Axes.getFromId(gd, options.xref); var xRefType = Axes.getRefType(options.xref); - var xShift = options.x_shift; + var xShift = options.xshift; var ya = Axes.getFromId(gd, options.yref); var yRefType = Axes.getRefType(options.yref); - var yShift = options.y_shift; + var yShift = options.yshift; var x2p = helpers.getDataToPixel(gd, xa, xShift, false, xRefType); var y2p = helpers.getDataToPixel(gd, ya, yShift, true, yRefType); shapex0 = x2p(options.x0); diff --git a/src/components/shapes/draw.js b/src/components/shapes/draw.js index 1c6871b436c..d83cb081a3f 100644 --- a/src/components/shapes/draw.js +++ b/src/components/shapes/draw.js @@ -225,10 +225,10 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer, editHe // setup conversion functions var xa = Axes.getFromId(gd, shapeOptions.xref); var xRefType = Axes.getRefType(shapeOptions.xref); - var xShift = shapeOptions.x_shift; + var xShift = shapeOptions.xshift; var ya = Axes.getFromId(gd, shapeOptions.yref); var yRefType = Axes.getRefType(shapeOptions.yref); - var yShift = shapeOptions.y_shift; + var yShift = shapeOptions.yshift; var x2p = helpers.getDataToPixel(gd, xa, xShift, false, xRefType); var y2p = helpers.getDataToPixel(gd, ya, yShift, true, yRefType); var p2x = helpers.getPixelToData(gd, xa, false, xRefType); diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index 51ac858fc54..7a114f734e5 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -226,20 +226,20 @@ exports.getPathString = function(gd, options) { } if(options.xsizemode === 'pixel') { var xAnchorPos = x2p(options.xanchor); - x0 = xAnchorPos + options.x0 + shiftUnitX * options.x_shift; - x1 = xAnchorPos + options.x1 + shiftUnitX * options.x_shift; + x0 = xAnchorPos + options.x0 + shiftUnitX * options.xshift; + x1 = xAnchorPos + options.x1 + shiftUnitX * options.xshift; } else { - x0 = x2p(options.x0) + shiftUnitX * options.x_shift; - x1 = x2p(options.x1) + shiftUnitX * options.x_shift; + x0 = x2p(options.x0) + shiftUnitX * options.xshift; + x1 = x2p(options.x1) + shiftUnitX * options.xshift; } if(options.ysizemode === 'pixel') { var yAnchorPos = y2p(options.yanchor); - y0 = yAnchorPos - options.y0 - shiftUnitY * options.y_shift; - y1 = yAnchorPos - options.y1 - shiftUnitY * options.y_shift; + y0 = yAnchorPos - options.y0 - shiftUnitY * options.yshift; + y1 = yAnchorPos - options.y1 - shiftUnitY * options.yshift; } else { - y0 = y2p(options.y0) - shiftUnitY * options.y_shift; - y1 = y2p(options.y1) - shiftUnitY * options.y_shift; + y0 = y2p(options.y0) - shiftUnitY * options.yshift; + y1 = y2p(options.y1) - shiftUnitY * options.yshift; } if(type === 'line') return 'M' + x0 + ',' + y0 + 'L' + x1 + ',' + y1; diff --git a/test/image/mocks/zzz_shape_shift_horizontal.json b/test/image/mocks/zzz_shape_shift_horizontal.json index 73c37364904..64896c1c24d 100644 --- a/test/image/mocks/zzz_shape_shift_horizontal.json +++ b/test/image/mocks/zzz_shape_shift_horizontal.json @@ -42,7 +42,7 @@ "y1": ["A", "D"], "x0": 0, "x1": 0.25, - "y_shift": 0.5, + "yshift": 0.5, "xref": "paper" }, { @@ -79,7 +79,7 @@ "y1": ["B", "D"], "x0": 0, "x1": 0.25, - "y_shift": -0.5, + "yshift": -0.5, "xref": "paper" } ] diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json index fc29b8ffab8..d51c1957362 100644 --- a/test/image/mocks/zzz_shape_shift_vertical.json +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -29,7 +29,7 @@ "x1": "A", "y0": 0, "y1": 0.5, - "x_shift": 0.5, + "xshift": 0.5, "yref": "paper" }, { @@ -48,7 +48,7 @@ "x1": 3, "y0": 0, "y1": 0.5, - "x_shift": -0.25, + "xshift": -0.25, "yref": "paper" } ], @@ -58,7 +58,7 @@ "x1": 4, "y0": 1, "y1": 3, - "x_shift": -0.5 + "xshift": -0.5 } ] } diff --git a/test/jasmine/tests/shapes_test.js b/test/jasmine/tests/shapes_test.js index 664b21d8d6b..dbacd383679 100644 --- a/test/jasmine/tests/shapes_test.js +++ b/test/jasmine/tests/shapes_test.js @@ -1487,8 +1487,8 @@ describe('Test shapes', function() { function testShapeDrag(dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); var initialCoordinates = getShapeCoordinates(layoutShape, x2p, y2p); @@ -1514,8 +1514,8 @@ describe('Test shapes', function() { function testPathDrag(dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); var initialPath = layoutShape.path; var initialCoordinates = getPathCoordinates(initialPath, x2p, y2p); @@ -1546,8 +1546,8 @@ describe('Test shapes', function() { function testShapeResize(direction, dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); var initialCoordinates = getShapeCoordinates(layoutShape, x2p, y2p); @@ -1590,8 +1590,8 @@ describe('Test shapes', function() { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.x_shift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.y_shift, true); + var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); + var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); promise = promise.then(function() { var dragHandle = pointToMove === 'start' ? diff --git a/test/plot-schema.json b/test/plot-schema.json index 50c8fcc6ca8..da4118713e7 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -9550,14 +9550,6 @@ "path" ] }, - "x_shift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", - "dflt": 0, - "editType": "arraydraw", - "max": 0.5, - "min": -0.5, - "valType": "number" - }, "x0": { "description": "Sets the selection's starting x position.", "editType": "arraydraw", @@ -9577,8 +9569,8 @@ "/^x([2-9]|[1-9][0-9]+)?( domain)?$/" ] }, - "y_shift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", + "xshift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", "dflt": 0, "editType": "arraydraw", "max": 0.5, @@ -9603,6 +9595,14 @@ "paper", "/^y([2-9]|[1-9][0-9]+)?( domain)?$/" ] + }, + "yshift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "arraydraw", + "max": 0.5, + "min": -0.5, + "valType": "number" } } }, @@ -10016,14 +10016,6 @@ "legendonly" ] }, - "x_shift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", - "dflt": 0, - "editType": "calc", - "max": 0.5, - "min": -0.5, - "valType": "number" - }, "x0": { "description": "Sets the shape's starting x position. See `type` and `xsizemode` for more info.", "editType": "calc+arraydraw", @@ -10048,6 +10040,14 @@ "/^x([2-9]|[1-9][0-9]+)?( domain)?$/" ] }, + "xshift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 0.5, + "min": -0.5, + "valType": "number" + }, "xsizemode": { "description": "Sets the shapes's sizing mode along the x axis. If set to *scaled*, `x0`, `x1` and x coordinates within `path` refer to data values on the x axis or a fraction of the plot area's width (`xref` set to *paper*). If set to *pixel*, `xanchor` specifies the x position in terms of data or plot fraction but `x0`, `x1` and x coordinates within `path` are pixels relative to `xanchor`. This way, the shape can have a fixed width while maintaining a position relative to data or plot fraction.", "dflt": "scaled", @@ -10058,14 +10058,6 @@ "pixel" ] }, - "y_shift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", - "dflt": 0, - "editType": "calc", - "max": 0.5, - "min": -0.5, - "valType": "number" - }, "y0": { "description": "Sets the shape's starting y position. See `type` and `ysizemode` for more info.", "editType": "calc+arraydraw", @@ -10090,6 +10082,14 @@ "/^y([2-9]|[1-9][0-9]+)?( domain)?$/" ] }, + "yshift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 0.5, + "min": -0.5, + "valType": "number" + }, "ysizemode": { "description": "Sets the shapes's sizing mode along the y axis. If set to *scaled*, `y0`, `y1` and y coordinates within `path` refer to data values on the y axis or a fraction of the plot area's height (`yref` set to *paper*). If set to *pixel*, `yanchor` specifies the y position in terms of data or plot fraction but `y0`, `y1` and y coordinates within `path` are pixels relative to `yanchor`. This way, the shape can have a fixed height while maintaining a position relative to data or plot fraction.", "dflt": "scaled", From 99215223b704aed8f5cc63bea367e31a014f881e Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 10 Jun 2024 11:01:10 +0200 Subject: [PATCH 07/23] Replace xshift and yshift with x0shift and y0shift --- src/components/selections/attributes.js | 42 ++++++-- src/components/selections/defaults.js | 6 +- src/components/shapes/attributes.js | 42 ++++++-- src/components/shapes/calc_autorange.js | 39 +++++--- src/components/shapes/defaults.js | 6 +- src/components/shapes/display_labels.js | 24 +++-- src/components/shapes/draw.js | 24 +++-- src/components/shapes/helpers.js | 36 ++++--- .../mocks/zzz_shape_shift_horizontal.json | 8 +- .../image/mocks/zzz_shape_shift_vertical.json | 11 ++- test/jasmine/tests/shapes_test.js | 18 ++-- test/plot-schema.json | 96 ++++++++++++------- 12 files changed, 238 insertions(+), 114 deletions(-) diff --git a/src/components/selections/attributes.js b/src/components/selections/attributes.js index 0ad3d07e6ca..efbee353e04 100644 --- a/src/components/selections/attributes.js +++ b/src/components/selections/attributes.js @@ -54,26 +54,48 @@ module.exports = overrideAll(templatedArray('selection', { description: 'Sets the selection\'s end y position.' }, - xshift: { + x0shift: { valType: 'number', dflt: 0, - min: -0.5, - max: 0.5, + min: -1, + max: 1, + editType: 'calc', + description: [ + 'Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the', + 'reference unit.' + ].join(' ') + }, + x1shift: { + valType: 'number', + dflt: 0, + min: -1, + max: 1, editType: 'calc', description: [ - 'Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of', - 'the reference unit.' + 'Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the', + 'reference unit.' ].join(' ') }, - yshift: { + y0shift: { valType: 'number', dflt: 0, - min: -0.5, - max: 0.5, + min: -1, + max: 1, + editType: 'calc', + description: [ + 'Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the', + 'reference unit.' + ].join(' ') + }, + y1shift: { + valType: 'number', + dflt: 0, + min: -1, + max: 1, editType: 'calc', description: [ - 'Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of', - 'the reference unit.' + 'Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the', + 'reference unit.' ].join(' ') }, diff --git a/src/components/selections/defaults.js b/src/components/selections/defaults.js index c5079c21c55..de7c8890c07 100644 --- a/src/components/selections/defaults.js +++ b/src/components/selections/defaults.js @@ -49,8 +49,10 @@ function handleSelectionDefaults(selectionIn, selectionOut, fullLayout) { coerce('line.color'); coerce('line.width'); coerce('line.dash'); - coerce('xshift'); - coerce('yshift'); + coerce('x0shift'); + coerce('x1shift'); + coerce('y0shift'); + coerce('y1shift'); // positioning var axLetters = ['x', 'y']; diff --git a/src/components/shapes/attributes.js b/src/components/shapes/attributes.js index 7effdda36e3..6771c320051 100644 --- a/src/components/shapes/attributes.js +++ b/src/components/shapes/attributes.js @@ -169,15 +169,26 @@ module.exports = templatedArray('shape', { 'See `type` and `xsizemode` for more info.' ].join(' ') }, - xshift: { + x0shift: { valType: 'number', dflt: 0, - min: -0.5, - max: 0.5, + min: -1, + max: 1, + editType: 'calc', + description: [ + 'Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the', + 'reference unit.' + ].join(' ') + }, + x1shift: { + valType: 'number', + dflt: 0, + min: -1, + max: 1, editType: 'calc', description: [ - 'Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of', - 'the reference unit.' + 'Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the', + 'reference unit.' ].join(' ') }, yref: extendFlat({}, annAttrs.yref, { @@ -230,15 +241,26 @@ module.exports = templatedArray('shape', { 'See `type` and `ysizemode` for more info.' ].join(' ') }, - yshift: { + y0shift: { valType: 'number', dflt: 0, - min: -0.5, - max: 0.5, + min: -1, + max: 1, + editType: 'calc', + description: [ + 'Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the', + 'reference unit.' + ].join(' ') + }, + y1shift: { + valType: 'number', + dflt: 0, + min: -1, + max: 1, editType: 'calc', description: [ - 'Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of', - 'the reference unit.' + 'Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the', + 'reference unit.' ].join(' ') }, path: { diff --git a/src/components/shapes/calc_autorange.js b/src/components/shapes/calc_autorange.js index 307c1eef171..9e66dd7f021 100644 --- a/src/components/shapes/calc_autorange.js +++ b/src/components/shapes/calc_autorange.js @@ -23,22 +23,18 @@ module.exports = function calcAutorange(gd) { // paper and axis domain referenced shapes don't affect autorange if(shape.xref !== 'paper' && xRefType !== 'domain') { - var vx0 = shape.xsizemode === 'pixel' ? shape.xanchor : shape.x0; - var vx1 = shape.xsizemode === 'pixel' ? shape.xanchor : shape.x1; ax = Axes.getFromId(gd, shape.xref); - bounds = shapeBounds(ax, vx0, vx1, shape.path, shape.xshift, constants.paramIsX); + bounds = shapeBounds(ax, shape, constants.paramIsX); if(bounds) { shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcXPaddingOptions(shape)); } } if(shape.yref !== 'paper' && yRefType !== 'domain') { - var vy0 = shape.ysizemode === 'pixel' ? shape.yanchor : shape.y0; - var vy1 = shape.ysizemode === 'pixel' ? shape.yanchor : shape.y1; ax = Axes.getFromId(gd, shape.yref); - bounds = shapeBounds(ax, vy0, vy1, shape.path, shape.yshift, constants.paramIsY); + bounds = shapeBounds(ax, shape, constants.paramIsY); if(bounds) { shape._extremes[ax._id] = Axes.findExtremes(ax, bounds, calcYPaddingOptions(shape)); } @@ -77,20 +73,35 @@ function calcPaddingOptions(lineWidth, sizeMode, v0, v1, path, isYAxis) { } } -function shapeBounds(ax, v0, v1, path, shift, paramsToUse) { - var convertVal; - if(ax.type === 'category' || ax.type === 'multicategory') { - convertVal = function(v) { return ax.r2c(v) + shift; }; +function shapeBounds(ax, shape, paramsToUse) { + var dim = ax._id.charAt(0) === 'x' ? 'x' : 'y'; + var isCategory = ax.type === 'category' || ax.type === 'multicategory'; + var v0; + var v1; + var shiftStart = 0; + var shiftEnd = 0; + + var convertVal = isCategory ? ax.r2c : ax.d2c; + + var isSizeModeScale = shape[dim + 'sizemode'] === 'scale'; + if(isSizeModeScale) { + v0 = shape[dim + '0']; + v1 = shape[dim + '1']; + if(isCategory) { + shiftStart = shape[dim + '0shift']; + shiftEnd = shape[dim + '1shift']; + } } else { - convertVal = ax.d2c; + v0 = shape[dim + 'anchor']; + v1 = shape[dim + 'anchor']; } - if(v0 !== undefined) return [convertVal(v0), convertVal(v1)]; - if(!path) return; + if(v0 !== undefined) return [convertVal(v0) + shiftStart, convertVal(v1) + shiftEnd]; + if(!shape.path) return; var min = Infinity; var max = -Infinity; - var segments = path.match(constants.segmentRE); + var segments = shape.path.match(constants.segmentRE); var i; var segment; var drawnParam; diff --git a/src/components/shapes/defaults.js b/src/components/shapes/defaults.js index 69e8fc0521e..e1914138f5d 100644 --- a/src/components/shapes/defaults.js +++ b/src/components/shapes/defaults.js @@ -75,8 +75,10 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) { var pos2r; var r2pos; - coerce('xshift'); - coerce('yshift'); + coerce('x0shift'); + coerce('x1shift'); + coerce('y0shift'); + coerce('y1shift'); // xref, yref var axRef = Axes.coerceRef(shapeIn, shapeOut, gdMock, axLetter, undefined, diff --git a/src/components/shapes/display_labels.js b/src/components/shapes/display_labels.js index a080ad5f3da..53c9d96228b 100644 --- a/src/components/shapes/display_labels.js +++ b/src/components/shapes/display_labels.js @@ -88,17 +88,25 @@ module.exports = function drawLabel(gd, index, options, shapeGroup) { // and convert them to pixel coordinates // Setup conversion functions var xa = Axes.getFromId(gd, options.xref); + var xShiftStart = options.x0shift; + var xShiftEnd = options.x1shift; var xRefType = Axes.getRefType(options.xref); - var xShift = options.xshift; var ya = Axes.getFromId(gd, options.yref); + var yShiftStart = options.y0shift; + var yShiftEnd = options.y1shift; var yRefType = Axes.getRefType(options.yref); - var yShift = options.yshift; - var x2p = helpers.getDataToPixel(gd, xa, xShift, false, xRefType); - var y2p = helpers.getDataToPixel(gd, ya, yShift, true, yRefType); - shapex0 = x2p(options.x0); - shapex1 = x2p(options.x1); - shapey0 = y2p(options.y0); - shapey1 = y2p(options.y1); + var x2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, xa, shift, false, xRefType); + return dataToPixel(v); + }; + var y2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, ya, shift, true, yRefType); + return dataToPixel(v); + }; + shapex0 = x2p(options.x0, xShiftStart); + shapex1 = x2p(options.x1, xShiftEnd); + shapey0 = y2p(options.y0, yShiftStart); + shapey1 = y2p(options.y1, yShiftEnd); } // Handle `auto` angle diff --git a/src/components/shapes/draw.js b/src/components/shapes/draw.js index d83cb081a3f..4cc75dc920e 100644 --- a/src/components/shapes/draw.js +++ b/src/components/shapes/draw.js @@ -225,12 +225,20 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer, editHe // setup conversion functions var xa = Axes.getFromId(gd, shapeOptions.xref); var xRefType = Axes.getRefType(shapeOptions.xref); - var xShift = shapeOptions.xshift; var ya = Axes.getFromId(gd, shapeOptions.yref); var yRefType = Axes.getRefType(shapeOptions.yref); - var yShift = shapeOptions.yshift; - var x2p = helpers.getDataToPixel(gd, xa, xShift, false, xRefType); - var y2p = helpers.getDataToPixel(gd, ya, yShift, true, yRefType); + var shiftXStart = shapeOptions.x0shift; + var shiftXEnd = shapeOptions.x1shift; + var shiftYStart = shapeOptions.y0shift; + var shiftYEnd = shapeOptions.y1shift; + var x2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, xa, shift, false, xRefType); + return dataToPixel(v); + }; + var y2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, ya, shift, true, yRefType); + return dataToPixel(v); + }; var p2x = helpers.getPixelToData(gd, xa, false, xRefType); var p2y = helpers.getPixelToData(gd, ya, true, yRefType); @@ -281,8 +289,8 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer, editHe g.append('circle') .attr({ 'data-line-point': 'start-point', - cx: xPixelSized ? x2p(shapeOptions.xanchor) + shapeOptions.x0 : x2p(shapeOptions.x0), - cy: yPixelSized ? y2p(shapeOptions.yanchor) - shapeOptions.y0 : y2p(shapeOptions.y0), + cx: xPixelSized ? x2p(shapeOptions.xanchor) + shapeOptions.x0 : x2p(shapeOptions.x0, shiftXStart), + cy: yPixelSized ? y2p(shapeOptions.yanchor) - shapeOptions.y0 : y2p(shapeOptions.y0, shiftYStart), r: circleRadius }) .style(circleStyle) @@ -291,8 +299,8 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer, editHe g.append('circle') .attr({ 'data-line-point': 'end-point', - cx: xPixelSized ? x2p(shapeOptions.xanchor) + shapeOptions.x1 : x2p(shapeOptions.x1), - cy: yPixelSized ? y2p(shapeOptions.yanchor) - shapeOptions.y1 : y2p(shapeOptions.y1), + cx: xPixelSized ? x2p(shapeOptions.xanchor) + shapeOptions.x1 : x2p(shapeOptions.x1, shiftXEnd), + cy: yPixelSized ? y2p(shapeOptions.yanchor) - shapeOptions.y1 : y2p(shapeOptions.y1, shiftYEnd), r: circleRadius }) .style(circleStyle) diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index 7a114f734e5..c648138d5d1 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -69,12 +69,12 @@ exports.getDataToPixel = function(gd, axis, shift, isVertical, refType) { var shiftPixels = 0; if(axis.type === 'category' || axis.type === 'multicategory') { if(isVertical) { - shiftPixels = -1 * ((gs.h - axis.r2p(d2r(0.5, true))) * shift); + shiftPixels = ((axis.r2p(1) - axis.r2p(0)) * shift); } else { - shiftPixels = axis.r2p(d2r(0.5, true)) * shift; + shiftPixels = axis.r2p(0.5) * shift; } } - return axis._offset + axis.r2p(d2r(v, true)) + (shiftPixels || 0); + return axis._offset + axis.r2p(d2r(v, true)) + shiftPixels; }; if(axis.type === 'date') dataToPixel = exports.decodeDate(dataToPixel); @@ -187,8 +187,10 @@ exports.getPathString = function(gd, options) { var ya = Axes.getFromId(gd, options.yref); var gs = gd._fullLayout._size; var x2r, x2p, y2r, y2p; - var shiftUnitX = 0; - var shiftUnitY = 0; + var xShiftStart = 0; + var xShiftEnd = 0; + var yShiftStart = 0; + var yShiftEnd = 0; var x0, x1, y0, y1; if(xa) { @@ -198,7 +200,9 @@ exports.getPathString = function(gd, options) { x2r = exports.shapePositionToRange(xa); x2p = function(v) { return xa._offset + xa.r2p(x2r(v, true)); }; if(xa.type === 'category' || xa.type === 'multicategory') { - shiftUnitX = xa.r2p(x2r(0.5, true)); + var shiftUnitX = xa.r2p(0.5); + xShiftStart = shiftUnitX * options.x0shift; + xShiftEnd = shiftUnitX * options.x1shift; } } } else { @@ -212,7 +216,9 @@ exports.getPathString = function(gd, options) { y2r = exports.shapePositionToRange(ya); y2p = function(v) { return ya._offset + ya.r2p(y2r(v, true)); }; if(ya.type === 'category' || ya.type === 'multicategory') { - shiftUnitY = gs.h - ya.r2p(y2r(0.5, true)); + var shiftUnitY = ya.r2p(0) - ya.r2p(1); + yShiftStart = shiftUnitY * options.y0shift; + yShiftEnd = shiftUnitY * options.y1shift; } } } else { @@ -226,20 +232,20 @@ exports.getPathString = function(gd, options) { } if(options.xsizemode === 'pixel') { var xAnchorPos = x2p(options.xanchor); - x0 = xAnchorPos + options.x0 + shiftUnitX * options.xshift; - x1 = xAnchorPos + options.x1 + shiftUnitX * options.xshift; + x0 = xAnchorPos + options.x0 + xShiftStart; + x1 = xAnchorPos + options.x1 + xShiftEnd; } else { - x0 = x2p(options.x0) + shiftUnitX * options.xshift; - x1 = x2p(options.x1) + shiftUnitX * options.xshift; + x0 = x2p(options.x0) + xShiftStart; + x1 = x2p(options.x1) + xShiftEnd; } if(options.ysizemode === 'pixel') { var yAnchorPos = y2p(options.yanchor); - y0 = yAnchorPos - options.y0 - shiftUnitY * options.yshift; - y1 = yAnchorPos - options.y1 - shiftUnitY * options.yshift; + y0 = yAnchorPos - options.y0 - yShiftStart; + y1 = yAnchorPos - options.y1 - yShiftEnd; } else { - y0 = y2p(options.y0) - shiftUnitY * options.yshift; - y1 = y2p(options.y1) - shiftUnitY * options.yshift; + y0 = y2p(options.y0) - yShiftStart; + y1 = y2p(options.y1) - yShiftEnd; } if(type === 'line') return 'M' + x0 + ',' + y0 + 'L' + x1 + ',' + y1; diff --git a/test/image/mocks/zzz_shape_shift_horizontal.json b/test/image/mocks/zzz_shape_shift_horizontal.json index 64896c1c24d..2ce25466211 100644 --- a/test/image/mocks/zzz_shape_shift_horizontal.json +++ b/test/image/mocks/zzz_shape_shift_horizontal.json @@ -38,11 +38,12 @@ "color": "black", "width": 3.0 }, - "y0": ["A", "C"], + "y0": ["A", "D"], "y1": ["A", "D"], "x0": 0, "x1": 0.25, - "yshift": 0.5, + "y0shift": -0.5, + "y1shift": 0.5, "xref": "paper" }, { @@ -79,7 +80,8 @@ "y1": ["B", "D"], "x0": 0, "x1": 0.25, - "yshift": -0.5, + "y0shift": -0.5, + "y1shift": -0.5, "xref": "paper" } ] diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json index d51c1957362..cfc808f773e 100644 --- a/test/image/mocks/zzz_shape_shift_vertical.json +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -29,7 +29,8 @@ "x1": "A", "y0": 0, "y1": 0.5, - "xshift": 0.5, + "x0shift": 0.5, + "x1shift": 0.5, "yref": "paper" }, { @@ -48,17 +49,19 @@ "x1": 3, "y0": 0, "y1": 0.5, - "xshift": -0.25, + "x0shift": -0.25, + "x1shift": -0.25, "yref": "paper" } ], "selections": [ { "x0": 0, - "x1": 4, + "x1": 3, "y0": 1, "y1": 3, - "xshift": -0.5 + "x0shift": -0.5, + "x1shift": 0.5 } ] } diff --git a/test/jasmine/tests/shapes_test.js b/test/jasmine/tests/shapes_test.js index dbacd383679..e29372073b3 100644 --- a/test/jasmine/tests/shapes_test.js +++ b/test/jasmine/tests/shapes_test.js @@ -1487,8 +1487,14 @@ describe('Test shapes', function() { function testShapeDrag(dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); + var x2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, xa, shift); + return dataToPixel(v); + }; + var y2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, ya, shift, true); + return dataToPixel(v); + }; var initialCoordinates = getShapeCoordinates(layoutShape, x2p, y2p); @@ -1504,10 +1510,10 @@ describe('Test shapes', function() { function getShapeCoordinates(layoutShape, x2p, y2p) { return { - x0: x2p(layoutShape.x0), - x1: x2p(layoutShape.x1), - y0: y2p(layoutShape.y0), - y1: y2p(layoutShape.y1) + x0: x2p(layoutShape.x0, layoutShape.x0shift), + x1: x2p(layoutShape.x1, layoutShape.x1shift), + y0: y2p(layoutShape.y0, layoutShape.y0shift), + y1: y2p(layoutShape.y1, layoutShape.y1shift) }; } diff --git a/test/plot-schema.json b/test/plot-schema.json index da4118713e7..b7b37ca4af5 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -9555,11 +9555,27 @@ "editType": "arraydraw", "valType": "any" }, + "x0shift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the reference unit.", + "dflt": 0, + "editType": "arraydraw", + "max": 1, + "min": -1, + "valType": "number" + }, "x1": { "description": "Sets the selection's end x position.", "editType": "arraydraw", "valType": "any" }, + "x1shift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "arraydraw", + "max": 1, + "min": -1, + "valType": "number" + }, "xref": { "description": "Sets the selection's x coordinate axis. If set to a x axis id (e.g. *x* or *x2*), the `x` position refers to a x coordinate. If set to *paper*, the `x` position refers to the distance from the left of the plotting area in normalized coordinates where *0* (*1*) corresponds to the left (right). If set to a x axis ID followed by *domain* (separated by a space), the position behaves like for *paper*, but refers to the distance in fractions of the domain length from the left of the domain of that axis: e.g., *x2 domain* refers to the domain of the second x axis and a x position of 0.5 refers to the point between the left and the right of the domain of the second x axis.", "editType": "arraydraw", @@ -9569,24 +9585,32 @@ "/^x([2-9]|[1-9][0-9]+)?( domain)?$/" ] }, - "xshift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", - "dflt": 0, - "editType": "arraydraw", - "max": 0.5, - "min": -0.5, - "valType": "number" - }, "y0": { "description": "Sets the selection's starting y position.", "editType": "arraydraw", "valType": "any" }, + "y0shift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the reference unit.", + "dflt": 0, + "editType": "arraydraw", + "max": 1, + "min": -1, + "valType": "number" + }, "y1": { "description": "Sets the selection's end y position.", "editType": "arraydraw", "valType": "any" }, + "y1shift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "arraydraw", + "max": 1, + "min": -1, + "valType": "number" + }, "yref": { "description": "Sets the selection's x coordinate axis. If set to a y axis id (e.g. *y* or *y2*), the `y` position refers to a y coordinate. If set to *paper*, the `y` position refers to the distance from the bottom of the plotting area in normalized coordinates where *0* (*1*) corresponds to the bottom (top). If set to a y axis ID followed by *domain* (separated by a space), the position behaves like for *paper*, but refers to the distance in fractions of the domain length from the bottom of the domain of that axis: e.g., *y2 domain* refers to the domain of the second y axis and a y position of 0.5 refers to the point between the bottom and the top of the domain of the second y axis.", "editType": "arraydraw", @@ -9595,14 +9619,6 @@ "paper", "/^y([2-9]|[1-9][0-9]+)?( domain)?$/" ] - }, - "yshift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", - "dflt": 0, - "editType": "arraydraw", - "max": 0.5, - "min": -0.5, - "valType": "number" } } }, @@ -10021,11 +10037,27 @@ "editType": "calc+arraydraw", "valType": "any" }, + "x0shift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 1, + "min": -1, + "valType": "number" + }, "x1": { "description": "Sets the shape's end x position. See `type` and `xsizemode` for more info.", "editType": "calc+arraydraw", "valType": "any" }, + "x1shift": { + "description": "Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 1, + "min": -1, + "valType": "number" + }, "xanchor": { "description": "Only relevant in conjunction with `xsizemode` set to *pixel*. Specifies the anchor point on the x axis to which `x0`, `x1` and x coordinates within `path` are relative to. E.g. useful to attach a pixel sized shape to a certain data value. No effect when `xsizemode` not set to *pixel*.", "editType": "calc+arraydraw", @@ -10040,14 +10072,6 @@ "/^x([2-9]|[1-9][0-9]+)?( domain)?$/" ] }, - "xshift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 and x1 by a fraction of the reference unit.", - "dflt": 0, - "editType": "calc", - "max": 0.5, - "min": -0.5, - "valType": "number" - }, "xsizemode": { "description": "Sets the shapes's sizing mode along the x axis. If set to *scaled*, `x0`, `x1` and x coordinates within `path` refer to data values on the x axis or a fraction of the plot area's width (`xref` set to *paper*). If set to *pixel*, `xanchor` specifies the x position in terms of data or plot fraction but `x0`, `x1` and x coordinates within `path` are pixels relative to `xanchor`. This way, the shape can have a fixed width while maintaining a position relative to data or plot fraction.", "dflt": "scaled", @@ -10063,11 +10087,27 @@ "editType": "calc+arraydraw", "valType": "any" }, + "y0shift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 1, + "min": -1, + "valType": "number" + }, "y1": { "description": "Sets the shape's end y position. See `type` and `ysizemode` for more info.", "editType": "calc+arraydraw", "valType": "any" }, + "y1shift": { + "description": "Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the reference unit.", + "dflt": 0, + "editType": "calc", + "max": 1, + "min": -1, + "valType": "number" + }, "yanchor": { "description": "Only relevant in conjunction with `ysizemode` set to *pixel*. Specifies the anchor point on the y axis to which `y0`, `y1` and y coordinates within `path` are relative to. E.g. useful to attach a pixel sized shape to a certain data value. No effect when `ysizemode` not set to *pixel*.", "editType": "calc+arraydraw", @@ -10082,14 +10122,6 @@ "/^y([2-9]|[1-9][0-9]+)?( domain)?$/" ] }, - "yshift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 and y1 by a fraction of the reference unit.", - "dflt": 0, - "editType": "calc", - "max": 0.5, - "min": -0.5, - "valType": "number" - }, "ysizemode": { "description": "Sets the shapes's sizing mode along the y axis. If set to *scaled*, `y0`, `y1` and y coordinates within `path` refer to data values on the y axis or a fraction of the plot area's height (`yref` set to *paper*). If set to *pixel*, `yanchor` specifies the y position in terms of data or plot fraction but `y0`, `y1` and y coordinates within `path` are pixels relative to `yanchor`. This way, the shape can have a fixed height while maintaining a position relative to data or plot fraction.", "dflt": "scaled", From 3ac32f30002a6bdec39a348f9c19a9d914bd3b9b Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 10 Jun 2024 11:03:56 +0200 Subject: [PATCH 08/23] Only coerce x0/x1/y0/y1shift if referenced axis is category/multicategory --- src/components/selections/defaults.js | 9 +++++---- src/components/shapes/defaults.js | 9 ++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/selections/defaults.js b/src/components/selections/defaults.js index de7c8890c07..c29998c8424 100644 --- a/src/components/selections/defaults.js +++ b/src/components/selections/defaults.js @@ -49,10 +49,6 @@ function handleSelectionDefaults(selectionIn, selectionOut, fullLayout) { coerce('line.color'); coerce('line.width'); coerce('line.dash'); - coerce('x0shift'); - coerce('x1shift'); - coerce('y0shift'); - coerce('y1shift'); // positioning var axLetters = ['x', 'y']; @@ -74,6 +70,11 @@ function handleSelectionDefaults(selectionIn, selectionOut, fullLayout) { // Coerce x0, x1, y0, y1 if(noPath) { + if(ax.type === 'category' || ax.type === 'multicategory') { + coerce(axLetter + '0shift'); + coerce(axLetter + '1shift'); + } + // 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 diff --git a/src/components/shapes/defaults.js b/src/components/shapes/defaults.js index e1914138f5d..e725b336678 100644 --- a/src/components/shapes/defaults.js +++ b/src/components/shapes/defaults.js @@ -75,11 +75,6 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) { var pos2r; var r2pos; - coerce('x0shift'); - coerce('x1shift'); - coerce('y0shift'); - coerce('y1shift'); - // xref, yref var axRef = Axes.coerceRef(shapeIn, shapeOut, gdMock, axLetter, undefined, 'paper'); @@ -90,6 +85,10 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) { 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'); + } } else { pos2r = r2pos = Lib.identity; } From 66807458c231f604a9bc56a2dcd177823ad32c5e Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 10 Jun 2024 11:32:37 +0200 Subject: [PATCH 09/23] Fix typo in calc_autorange: x/ysizemode "scale" -> "scaled" --- src/components/shapes/calc_autorange.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/shapes/calc_autorange.js b/src/components/shapes/calc_autorange.js index 9e66dd7f021..17c6ce23a2f 100644 --- a/src/components/shapes/calc_autorange.js +++ b/src/components/shapes/calc_autorange.js @@ -83,7 +83,7 @@ function shapeBounds(ax, shape, paramsToUse) { var convertVal = isCategory ? ax.r2c : ax.d2c; - var isSizeModeScale = shape[dim + 'sizemode'] === 'scale'; + var isSizeModeScale = shape[dim + 'sizemode'] === 'scaled'; if(isSizeModeScale) { v0 = shape[dim + '0']; v1 = shape[dim + '1']; From ada22891cde1b146fe9a1940a1c3da7c29c62760 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 10 Jun 2024 12:03:20 +0200 Subject: [PATCH 10/23] Add scatter to zzz_shape_shift_vertical mock --- test/image/mocks/zzz_shape_shift_vertical.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json index cfc808f773e..b5ba37f4027 100644 --- a/test/image/mocks/zzz_shape_shift_vertical.json +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -8,6 +8,15 @@ 1, 2, 3, 4 ], "type": "bar" + }, + { + "x": [ + "A", "B", "C", "D" + ], + "y": [ + 3, 2, 4, 1 + ], + "type": "scatter" } ], "layout": { From 1bfb22db31813875241975282e08b4f80332f576 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 10 Jun 2024 12:21:27 +0200 Subject: [PATCH 11/23] Updated baseline image after adding scatter to zzz_shape_shift_vertical_mock --- .../baselines/zzz_shape_shift_vertical.png | Bin 20710 -> 29699 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/image/baselines/zzz_shape_shift_vertical.png b/test/image/baselines/zzz_shape_shift_vertical.png index 2c762bf9f3a7640c27b1f52e8458e3eb1e88c298..d0afefacf3fa59f3468d9889f1046f9fe19c2431 100644 GIT binary patch literal 29699 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 z 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 From 04466db7e287b5d3f8287eb06729600bc99ea436 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 10 Jun 2024 14:24:42 +0200 Subject: [PATCH 12/23] getDataToPixel: If shift is undefined, set it to 0 --- src/components/shapes/helpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index c648138d5d1..9021a62d4f2 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -56,6 +56,7 @@ exports.extractPathCoords = function(path, paramsToUse, isRaw) { exports.getDataToPixel = function(gd, axis, shift, isVertical, refType) { var gs = gd._fullLayout._size; var dataToPixel; + shift = shift || 0; if(axis) { if(refType === 'domain') { From 91db7c872de329a5c49f89071d896b028a526680 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 12 Jun 2024 10:26:59 +0200 Subject: [PATCH 13/23] Update draftlog with final property names --- draftlogs/7005_add.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draftlogs/7005_add.md b/draftlogs/7005_add.md index e50081e3dfc..f010c7bcda0 100644 --- a/draftlogs/7005_add.md +++ b/draftlogs/7005_add.md @@ -1 +1 @@ - - Add property x_shift/y_shift for shapes/selections referencing (multi-)category axes [[#7005](https://github.com/plotly/plotly.js/pull/7005)] + - Add property x0shift, x1shift, y0shift, y1shift for shapes/selections referencing (multi-)category axes [[#7005](https://github.com/plotly/plotly.js/pull/7005)] From 4bbb66929b9c1ae878d25da27d79a1b184026787 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 12 Jun 2024 10:33:46 +0200 Subject: [PATCH 14/23] Adjust attribute descriptions with property formatting and mention of -0.5 and 0.5 for category start/end --- src/components/selections/attributes.js | 16 ++++++++-------- src/components/shapes/attributes.js | 16 ++++++++-------- test/plot-schema.json | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/components/selections/attributes.js b/src/components/selections/attributes.js index efbee353e04..df051bb3a47 100644 --- a/src/components/selections/attributes.js +++ b/src/components/selections/attributes.js @@ -61,8 +61,8 @@ module.exports = overrideAll(templatedArray('selection', { max: 1, editType: 'calc', description: [ - 'Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the', - 'reference unit.' + 'Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, x1shift: { @@ -72,8 +72,8 @@ module.exports = overrideAll(templatedArray('selection', { max: 1, editType: 'calc', description: [ - 'Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the', - 'reference unit.' + 'Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, y0shift: { @@ -83,8 +83,8 @@ module.exports = overrideAll(templatedArray('selection', { max: 1, editType: 'calc', description: [ - 'Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the', - 'reference unit.' + 'Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, y1shift: { @@ -94,8 +94,8 @@ module.exports = overrideAll(templatedArray('selection', { max: 1, editType: 'calc', description: [ - 'Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the', - 'reference unit.' + 'Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, diff --git a/src/components/shapes/attributes.js b/src/components/shapes/attributes.js index 6771c320051..eed805b2928 100644 --- a/src/components/shapes/attributes.js +++ b/src/components/shapes/attributes.js @@ -176,8 +176,8 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the', - 'reference unit.' + 'Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, x1shift: { @@ -187,8 +187,8 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the', - 'reference unit.' + 'Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, yref: extendFlat({}, annAttrs.yref, { @@ -248,8 +248,8 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the', - 'reference unit.' + 'Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, y1shift: { @@ -259,8 +259,8 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the', - 'reference unit.' + 'Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the', + 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' ].join(' ') }, path: { diff --git a/test/plot-schema.json b/test/plot-schema.json index b7b37ca4af5..70345b9e3da 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -9556,7 +9556,7 @@ "valType": "any" }, "x0shift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the reference unit.", + "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "arraydraw", "max": 1, @@ -9569,7 +9569,7 @@ "valType": "any" }, "x1shift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the reference unit.", + "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "arraydraw", "max": 1, @@ -9591,7 +9591,7 @@ "valType": "any" }, "y0shift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the reference unit.", + "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "arraydraw", "max": 1, @@ -9604,7 +9604,7 @@ "valType": "any" }, "y1shift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the reference unit.", + "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "arraydraw", "max": 1, @@ -10038,7 +10038,7 @@ "valType": "any" }, "x0shift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x0 by a fraction of the reference unit.", + "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1, @@ -10051,7 +10051,7 @@ "valType": "any" }, "x1shift": { - "description": "Only relevant if xref is a (multi-)category axes. Shifts x1 by a fraction of the reference unit.", + "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1, @@ -10088,7 +10088,7 @@ "valType": "any" }, "y0shift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y0 by a fraction of the reference unit.", + "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1, @@ -10101,7 +10101,7 @@ "valType": "any" }, "y1shift": { - "description": "Only relevant if yref is a (multi-)category axes. Shifts y1 by a fraction of the reference unit.", + "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1, From ab935acea405076d761a7f3ed264e3124c5cd4e0 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Tue, 18 Jun 2024 14:26:24 +0200 Subject: [PATCH 15/23] Move calculation of shape shift into a dedicated function --- src/components/shapes/helpers.js | 52 +++++++++++++++----------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index 9021a62d4f2..998979bff0e 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -56,7 +56,6 @@ exports.extractPathCoords = function(path, paramsToUse, isRaw) { exports.getDataToPixel = function(gd, axis, shift, isVertical, refType) { var gs = gd._fullLayout._size; var dataToPixel; - shift = shift || 0; if(axis) { if(refType === 'domain') { @@ -67,14 +66,7 @@ exports.getDataToPixel = function(gd, axis, shift, isVertical, refType) { var d2r = exports.shapePositionToRange(axis); dataToPixel = function(v) { - var shiftPixels = 0; - if(axis.type === 'category' || axis.type === 'multicategory') { - if(isVertical) { - shiftPixels = ((axis.r2p(1) - axis.r2p(0)) * shift); - } else { - shiftPixels = axis.r2p(0.5) * shift; - } - } + var shiftPixels = getPixelShift(axis, shift); return axis._offset + axis.r2p(d2r(v, true)) + shiftPixels; }; @@ -188,10 +180,10 @@ exports.getPathString = function(gd, options) { var ya = Axes.getFromId(gd, options.yref); var gs = gd._fullLayout._size; var x2r, x2p, y2r, y2p; - var xShiftStart = 0; - var xShiftEnd = 0; - var yShiftStart = 0; - var yShiftEnd = 0; + var xShiftStart = getPixelShift(xa, options.x0shift); + var xShiftEnd = getPixelShift(xa, options.x1shift); + var yShiftStart = getPixelShift(ya, options.y0shift); + var yShiftEnd = getPixelShift(ya, options.y1shift); var x0, x1, y0, y1; if(xa) { @@ -200,11 +192,6 @@ exports.getPathString = function(gd, options) { } else { x2r = exports.shapePositionToRange(xa); x2p = function(v) { return xa._offset + xa.r2p(x2r(v, true)); }; - if(xa.type === 'category' || xa.type === 'multicategory') { - var shiftUnitX = xa.r2p(0.5); - xShiftStart = shiftUnitX * options.x0shift; - xShiftEnd = shiftUnitX * options.x1shift; - } } } else { x2p = function(v) { return gs.l + gs.w * v; }; @@ -216,11 +203,6 @@ exports.getPathString = function(gd, options) { } else { y2r = exports.shapePositionToRange(ya); y2p = function(v) { return ya._offset + ya.r2p(y2r(v, true)); }; - if(ya.type === 'category' || ya.type === 'multicategory') { - var shiftUnitY = ya.r2p(0) - ya.r2p(1); - yShiftStart = shiftUnitY * options.y0shift; - yShiftEnd = shiftUnitY * options.y1shift; - } } } else { y2p = function(v) { return gs.t + gs.h * (1 - v); }; @@ -242,11 +224,11 @@ exports.getPathString = function(gd, options) { if(options.ysizemode === 'pixel') { var yAnchorPos = y2p(options.yanchor); - y0 = yAnchorPos - options.y0 - yShiftStart; - y1 = yAnchorPos - options.y1 - yShiftEnd; + y0 = yAnchorPos - options.y0 + yShiftStart; + y1 = yAnchorPos - options.y1 + yShiftEnd; } else { - y0 = y2p(options.y0) - yShiftStart; - y1 = y2p(options.y1) - yShiftEnd; + y0 = y2p(options.y0) + yShiftStart; + y1 = y2p(options.y1) + yShiftEnd; } if(type === 'line') return 'M' + x0 + ',' + y0 + 'L' + x1 + ',' + y1; @@ -301,3 +283,19 @@ function convertPath(options, x2p, y2p) { return segmentType + paramString; }); } + +function getPixelShift(axis, shift) { + shift = shift || 0; + var shiftPixels = 0; + if(axis) { + var isVertical = axis._id.charAt(0) === 'y'; + if(axis.type === 'category' || axis.type === 'multicategory') { + if(isVertical) { + shiftPixels = ((axis.r2p(1) - axis.r2p(0)) * shift); + } else { + shiftPixels = axis.r2p(0.5) * shift; + } + } + } + return shiftPixels; +} From f9c44bf962858c403147a2f93bdc45172488477b Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 3 Jul 2024 17:14:21 +0200 Subject: [PATCH 16/23] Update overlooked test after changing xshift/yshift to x0shift,x1shift/y0shift,y1shift --- test/jasmine/tests/shapes_test.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/test/jasmine/tests/shapes_test.js b/test/jasmine/tests/shapes_test.js index e29372073b3..1ea56af23ee 100644 --- a/test/jasmine/tests/shapes_test.js +++ b/test/jasmine/tests/shapes_test.js @@ -1520,8 +1520,8 @@ describe('Test shapes', function() { function testPathDrag(dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); + var x2p = helpers.getDataToPixel(gd, xa); + var y2p = helpers.getDataToPixel(gd, ya, undefined, true); var initialPath = layoutShape.path; var initialCoordinates = getPathCoordinates(initialPath, x2p, y2p); @@ -1552,8 +1552,14 @@ describe('Test shapes', function() { function testShapeResize(direction, dx, dy, layoutShape, node) { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); + var x2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, xa, shift, false); + return dataToPixel(v); + }; + var y2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, ya, shift, true); + return dataToPixel(v); + }; var initialCoordinates = getShapeCoordinates(layoutShape, x2p, y2p); @@ -1596,8 +1602,14 @@ describe('Test shapes', function() { var xa = Axes.getFromId(gd, layoutShape.xref); var ya = Axes.getFromId(gd, layoutShape.yref); - var x2p = helpers.getDataToPixel(gd, xa, layoutShape.xshift); - var y2p = helpers.getDataToPixel(gd, ya, layoutShape.yshift, true); + var x2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, xa, shift); + return dataToPixel(v); + }; + var y2p = function(v, shift) { + var dataToPixel = helpers.getDataToPixel(gd, ya, shift, true); + return dataToPixel(v); + }; promise = promise.then(function() { var dragHandle = pointToMove === 'start' ? From b00d4d806fc2f1a531db414c53365032f537317a Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 10 Jul 2024 23:34:53 +0200 Subject: [PATCH 17/23] Remove shift properties from selection for now --- draftlogs/7005_add.md | 2 +- src/components/selections/attributes.js | 45 ------------------- src/components/selections/defaults.js | 5 --- src/components/shapes/helpers.js | 2 +- .../image/mocks/zzz_shape_shift_vertical.json | 10 ----- test/plot-schema.json | 32 ------------- 6 files changed, 2 insertions(+), 94 deletions(-) diff --git a/draftlogs/7005_add.md b/draftlogs/7005_add.md index f010c7bcda0..af079090b96 100644 --- a/draftlogs/7005_add.md +++ b/draftlogs/7005_add.md @@ -1 +1 @@ - - Add property x0shift, x1shift, y0shift, y1shift for shapes/selections referencing (multi-)category axes [[#7005](https://github.com/plotly/plotly.js/pull/7005)] + - Add property x0shift, x1shift, y0shift, y1shift for shapes referencing (multi-)category axes, with thanks to @my-tien for the contribution! [[#7005](https://github.com/plotly/plotly.js/pull/7005)] diff --git a/src/components/selections/attributes.js b/src/components/selections/attributes.js index df051bb3a47..443eda366ce 100644 --- a/src/components/selections/attributes.js +++ b/src/components/selections/attributes.js @@ -54,51 +54,6 @@ module.exports = overrideAll(templatedArray('selection', { description: 'Sets the selection\'s end y position.' }, - x0shift: { - valType: 'number', - dflt: 0, - min: -1, - max: 1, - editType: 'calc', - description: [ - 'Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' - ].join(' ') - }, - x1shift: { - valType: 'number', - dflt: 0, - min: -1, - max: 1, - editType: 'calc', - description: [ - 'Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' - ].join(' ') - }, - y0shift: { - valType: 'number', - dflt: 0, - min: -1, - max: 1, - editType: 'calc', - description: [ - 'Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' - ].join(' ') - }, - y1shift: { - valType: 'number', - dflt: 0, - min: -1, - max: 1, - editType: 'calc', - description: [ - 'Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' - ].join(' ') - }, - path: { valType: 'string', editType: 'arraydraw', diff --git a/src/components/selections/defaults.js b/src/components/selections/defaults.js index c29998c8424..9a6a2ddc11a 100644 --- a/src/components/selections/defaults.js +++ b/src/components/selections/defaults.js @@ -70,11 +70,6 @@ function handleSelectionDefaults(selectionIn, selectionOut, fullLayout) { // Coerce x0, x1, y0, y1 if(noPath) { - if(ax.type === 'category' || ax.type === 'multicategory') { - coerce(axLetter + '0shift'); - coerce(axLetter + '1shift'); - } - // 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 diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index 998979bff0e..c22109cc193 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -287,7 +287,7 @@ function convertPath(options, x2p, y2p) { function getPixelShift(axis, shift) { shift = shift || 0; var shiftPixels = 0; - if(axis) { + if(axis && shift) { var isVertical = axis._id.charAt(0) === 'y'; if(axis.type === 'category' || axis.type === 'multicategory') { if(isVertical) { diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json index b5ba37f4027..ded993bda79 100644 --- a/test/image/mocks/zzz_shape_shift_vertical.json +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -62,16 +62,6 @@ "x1shift": -0.25, "yref": "paper" } - ], - "selections": [ - { - "x0": 0, - "x1": 3, - "y0": 1, - "y1": 3, - "x0shift": -0.5, - "x1shift": 0.5 - } ] } } diff --git a/test/plot-schema.json b/test/plot-schema.json index 70345b9e3da..5c15f36db0c 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -9555,27 +9555,11 @@ "editType": "arraydraw", "valType": "any" }, - "x0shift": { - "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", - "dflt": 0, - "editType": "arraydraw", - "max": 1, - "min": -1, - "valType": "number" - }, "x1": { "description": "Sets the selection's end x position.", "editType": "arraydraw", "valType": "any" }, - "x1shift": { - "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", - "dflt": 0, - "editType": "arraydraw", - "max": 1, - "min": -1, - "valType": "number" - }, "xref": { "description": "Sets the selection's x coordinate axis. If set to a x axis id (e.g. *x* or *x2*), the `x` position refers to a x coordinate. If set to *paper*, the `x` position refers to the distance from the left of the plotting area in normalized coordinates where *0* (*1*) corresponds to the left (right). If set to a x axis ID followed by *domain* (separated by a space), the position behaves like for *paper*, but refers to the distance in fractions of the domain length from the left of the domain of that axis: e.g., *x2 domain* refers to the domain of the second x axis and a x position of 0.5 refers to the point between the left and the right of the domain of the second x axis.", "editType": "arraydraw", @@ -9590,27 +9574,11 @@ "editType": "arraydraw", "valType": "any" }, - "y0shift": { - "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", - "dflt": 0, - "editType": "arraydraw", - "max": 1, - "min": -1, - "valType": "number" - }, "y1": { "description": "Sets the selection's end y position.", "editType": "arraydraw", "valType": "any" }, - "y1shift": { - "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", - "dflt": 0, - "editType": "arraydraw", - "max": 1, - "min": -1, - "valType": "number" - }, "yref": { "description": "Sets the selection's x coordinate axis. If set to a y axis id (e.g. *y* or *y2*), the `y` position refers to a y coordinate. If set to *paper*, the `y` position refers to the distance from the bottom of the plotting area in normalized coordinates where *0* (*1*) corresponds to the bottom (top). If set to a y axis ID followed by *domain* (separated by a space), the position behaves like for *paper*, but refers to the distance in fractions of the domain length from the bottom of the domain of that axis: e.g., *y2 domain* refers to the domain of the second y axis and a y position of 0.5 refers to the point between the bottom and the top of the domain of the second y axis.", "editType": "arraydraw", From 78a7e5ebd785a7d6f3d91653355a2e7499af455e Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Thu, 11 Jul 2024 12:11:34 +0200 Subject: [PATCH 18/23] Fix getPixelShift for reversed axes, add reversed axis to mock --- src/components/shapes/helpers.js | 11 ++--------- test/image/mocks/zzz_shape_shift_vertical.json | 7 +++++-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/components/shapes/helpers.js b/src/components/shapes/helpers.js index c22109cc193..ad22a48df8c 100644 --- a/src/components/shapes/helpers.js +++ b/src/components/shapes/helpers.js @@ -287,15 +287,8 @@ function convertPath(options, x2p, y2p) { function getPixelShift(axis, shift) { shift = shift || 0; var shiftPixels = 0; - if(axis && shift) { - var isVertical = axis._id.charAt(0) === 'y'; - if(axis.type === 'category' || axis.type === 'multicategory') { - if(isVertical) { - shiftPixels = ((axis.r2p(1) - axis.r2p(0)) * shift); - } else { - shiftPixels = axis.r2p(0.5) * shift; - } - } + if(shift && axis && (axis.type === 'category' || axis.type === 'multicategory')) { + shiftPixels = (axis.r2p(1) - axis.r2p(0)) * shift; } return shiftPixels; } diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json index ded993bda79..71582632a7f 100644 --- a/test/image/mocks/zzz_shape_shift_vertical.json +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -21,12 +21,15 @@ ], "layout": { "width": 600, + "xaxis": { + "autorange": "reversed" + }, "shapes": [ { "layer": "above", "type": "line", "label": { - "text": "right from A", + "text": "after A", "textposition": "end", "textangle": 0 }, @@ -46,7 +49,7 @@ "layer": "above", "type": "line", "label": { - "text": "slightly left from D", + "text": "slightly before D", "textposition": "end", "textangle": 0 }, From 18e7c84fe8252984e02b4e11616dec8dcd22f8ec Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Thu, 11 Jul 2024 14:03:32 +0200 Subject: [PATCH 19/23] Update baseline image of zzz_shape_shift_vertical - removed selection - reversed axis --- .../baselines/zzz_shape_shift_vertical.png | Bin 29699 -> 27064 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/image/baselines/zzz_shape_shift_vertical.png b/test/image/baselines/zzz_shape_shift_vertical.png index d0afefacf3fa59f3468d9889f1046f9fe19c2431..5f37e785ad21510b95835c792f278ce386620551 100644 GIT binary patch literal 27064 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 literal 29699 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 z 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 Date: Mon, 15 Jul 2024 16:26:30 +0200 Subject: [PATCH 20/23] Account for shift when dragging a shape --- src/components/shapes/draw_newshape/newshapes.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/shapes/draw_newshape/newshapes.js b/src/components/shapes/draw_newshape/newshapes.js index 9db9a237a4d..831a270e9ab 100644 --- a/src/components/shapes/draw_newshape/newshapes.js +++ b/src/components/shapes/draw_newshape/newshapes.js @@ -84,10 +84,10 @@ function newShapes(outlines, dragOptions) { case 'line': case 'rect': case 'circle': - modifyItem('x0', afterEdit.x0); - modifyItem('x1', afterEdit.x1); - modifyItem('y0', afterEdit.y0); - modifyItem('y1', afterEdit.y1); + modifyItem('x0', afterEdit.x0 - (beforeEdit.x0shift || 0)); + modifyItem('x1', afterEdit.x1 - (beforeEdit.x1shift || 0)); + modifyItem('y0', afterEdit.y0 - (beforeEdit.y0shift || 0)); + modifyItem('y1', afterEdit.y1 - (beforeEdit.y1shift || 0)); break; case 'path': From 6f8e5a644abb10a83162b116529b33a5b02cbd0e Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 15 Jul 2024 17:12:31 +0200 Subject: [PATCH 21/23] Support shape shift in texttemplate as well - Add texttemplate with slope and xcenter to mock --- src/components/shapes/label_texttemplate.js | 13 +++++++--- .../image/mocks/zzz_shape_shift_vertical.json | 26 +++++++++++++++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/components/shapes/label_texttemplate.js b/src/components/shapes/label_texttemplate.js index 47328f89d00..445a8541247 100644 --- a/src/components/shapes/label_texttemplate.js +++ b/src/components/shapes/label_texttemplate.js @@ -16,12 +16,17 @@ function x1Fn(shape) { return shape.x1; } function y0Fn(shape) { return shape.y0; } function y1Fn(shape) { return shape.y1; } +function x0shiftFn(shape) { return shape.x0shift || 0; } +function x1shiftFn(shape) { return shape.x1shift || 0; } +function y0shiftFn(shape) { return shape.y0shift || 0; } +function y1shiftFn(shape) { return shape.y1shift || 0; } + function dxFn(shape, xa) { - return d2l(shape.x1, xa) - d2l(shape.x0, xa); + return d2l(shape.x1, xa) + x1shiftFn(shape) - d2l(shape.x0, xa) - x0shiftFn(shape); } function dyFn(shape, xa, ya) { - return d2l(shape.y1, ya) - d2l(shape.y0, ya); + return d2l(shape.y1, ya) + y1shiftFn(shape) - d2l(shape.y0, ya) - y0shiftFn(shape); } function widthFn(shape, xa) { @@ -41,11 +46,11 @@ function lengthFn(shape, xa, ya) { } function xcenterFn(shape, xa) { - return l2d((d2l(shape.x1, xa) + d2l(shape.x0, xa)) / 2, xa); + return l2d((d2l(shape.x1, xa) + x1shiftFn(shape) + d2l(shape.x0, xa) + x0shiftFn(shape)) / 2, xa); } function ycenterFn(shape, xa, ya) { - return l2d((d2l(shape.y1, ya) + d2l(shape.y0, ya)) / 2, ya); + return l2d((d2l(shape.y1, ya) + y1shiftFn(shape) + d2l(shape.y0, ya) + y0shiftFn(shape)) / 2, ya); } function slopeFn(shape, xa, ya) { diff --git a/test/image/mocks/zzz_shape_shift_vertical.json b/test/image/mocks/zzz_shape_shift_vertical.json index 71582632a7f..46715c8175b 100644 --- a/test/image/mocks/zzz_shape_shift_vertical.json +++ b/test/image/mocks/zzz_shape_shift_vertical.json @@ -5,7 +5,7 @@ "A", "B", "C", "D" ], "y": [ - 1, 2, 3, 4 + 1, 2, 2.5, 4 ], "type": "bar" }, @@ -14,7 +14,7 @@ "A", "B", "C", "D" ], "y": [ - 3, 2, 4, 1 + 3, 2, 1.5, 1 ], "type": "scatter" } @@ -24,6 +24,9 @@ "xaxis": { "autorange": "reversed" }, + "yaxis": { + "range": [0, 5] + }, "shapes": [ { "layer": "above", @@ -64,6 +67,25 @@ "x0shift": -0.25, "x1shift": -0.25, "yref": "paper" + }, + { + "label": { + "texttemplate": "dy/dx = -1.5 / 1 = %{slope}. xcenter: %{xcenter}" + + }, + "layer": "above", + "x0": "A", + "x1": "C", + "x0shift": 0.5, + "x1shift": -0.5, + "y0": 4.5, + "y1": 3, + "type": "line", + "line": { + "width": 3, + "color": "pink" + }, + "editable": true } ] } From 7de45c3a4b7f93b2341b1ef11b1113cf1be0bf43 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 15 Jul 2024 23:43:06 +0200 Subject: [PATCH 22/23] Update baseline image after updated mock for texttemplate shape --- .../baselines/zzz_shape_shift_vertical.png | Bin 27064 -> 24870 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/image/baselines/zzz_shape_shift_vertical.png b/test/image/baselines/zzz_shape_shift_vertical.png index 5f37e785ad21510b95835c792f278ce386620551..9e5bc4162c9274f1e63ebbed748e3fd5a5b616d8 100644 GIT binary patch literal 24870 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 From 9ac970a8bc90f24c3aa4f0c90402aba2a9108366 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Tue, 16 Jul 2024 17:32:07 +0200 Subject: [PATCH 23/23] Refine description for x0shift/x1shift/y0shift/y1shift --- src/components/shapes/attributes.js | 20 ++++++++++++-------- test/plot-schema.json | 8 ++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/components/shapes/attributes.js b/src/components/shapes/attributes.js index eed805b2928..71a5475aee0 100644 --- a/src/components/shapes/attributes.js +++ b/src/components/shapes/attributes.js @@ -176,8 +176,9 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' + 'Shifts `x0` away from the center of the category when `xref` is a *category* or', + '*multicategory* axis. -0.5 corresponds to the start of the category and 0.5', + 'corresponds to the end of the category.' ].join(' ') }, x1shift: { @@ -187,8 +188,9 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' + 'Shifts `x1` away from the center of the category when `xref` is a *category* or', + '*multicategory* axis. -0.5 corresponds to the start of the category and 0.5', + 'corresponds to the end of the category.' ].join(' ') }, yref: extendFlat({}, annAttrs.yref, { @@ -248,8 +250,9 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' + 'Shifts `y0` away from the center of the category when `yref` is a *category* or', + '*multicategory* axis. -0.5 corresponds to the start of the category and 0.5', + 'corresponds to the end of the category.' ].join(' ') }, y1shift: { @@ -259,8 +262,9 @@ module.exports = templatedArray('shape', { max: 1, editType: 'calc', description: [ - 'Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the', - 'reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.' + 'Shifts `y1` away from the center of the category when `yref` is a *category* or', + '*multicategory* axis. -0.5 corresponds to the start of the category and 0.5', + 'corresponds to the end of the category.' ].join(' ') }, path: { diff --git a/test/plot-schema.json b/test/plot-schema.json index 584bdd8680a..a105ef852ba 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -10006,7 +10006,7 @@ "valType": "any" }, "x0shift": { - "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", + "description": "Shifts `x0` away from the center of the category when `xref` is a *category* or *multicategory* axis. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1, @@ -10019,7 +10019,7 @@ "valType": "any" }, "x1shift": { - "description": "Only relevant if `xref` is a (multi-)category axes. Shifts `x1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", + "description": "Shifts `x1` away from the center of the category when `xref` is a *category* or *multicategory* axis. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1, @@ -10056,7 +10056,7 @@ "valType": "any" }, "y0shift": { - "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y0` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", + "description": "Shifts `y0` away from the center of the category when `yref` is a *category* or *multicategory* axis. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1, @@ -10069,7 +10069,7 @@ "valType": "any" }, "y1shift": { - "description": "Only relevant if `yref` is a (multi-)category axes. Shifts `y1` by a fraction of the reference unit. E.g. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", + "description": "Shifts `y1` away from the center of the category when `yref` is a *category* or *multicategory* axis. -0.5 corresponds to the start of the category and 0.5 corresponds to the end of the category.", "dflt": 0, "editType": "calc", "max": 1,