Skip to content

add attributes xshift, yshift to annotations #1590

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/components/annotations/annotation_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ module.exports = function handleAnnotationDefaults(annIn, annOut, fullLayout, op

// xanchor, yanchor
coerce(axLetter + 'anchor');

// xshift, yshift
coerce(axLetter + 'shift');
}

// if you have one coordinate you should have both
Expand Down
22 changes: 21 additions & 1 deletion src/components/annotations/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,9 @@ module.exports = {
description: [
'Sets a distance, in pixels, to move the arrowhead away from the',
'position it is pointing at, for example to point at the edge of',
'a marker independent of zoom.'
'a marker independent of zoom. Note that this shortens the arrow',
'from the `ax` / `ay` vector, in contrast to `xshift` / `yshift`',
'which moves everything by this amount.'
].join(' ')
},
ax: {
Expand Down Expand Up @@ -292,6 +294,15 @@ module.exports = {
'corresponds to the closest side.'
].join(' ')
},
xshift: {
valType: 'number',
dflt: 0,
role: 'style',
description: [
'Shifts the position of the whole annotation and arrow to the',
'right (positive) or left (negative) by this many pixels.'
].join(' ')
},
yref: {
valType: 'enumerated',
values: [
Expand Down Expand Up @@ -342,6 +353,15 @@ module.exports = {
'corresponds to the closest side.'
].join(' ')
},
yshift: {
valType: 'number',
dflt: 0,
role: 'style',
description: [
'Shifts the position of the whole annotation and arrow up',
'(positive) or down (negative) by this many pixels.'
].join(' ')
},
clicktoshow: {
valType: 'enumerated',
values: [false, 'onoff', 'onout'],
Expand Down
24 changes: 16 additions & 8 deletions src/components/annotations/calc_autorange.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,17 @@ function annAutorange(gd) {
ya = Axes.getFromId(gd, ann.yref),
headSize = 3 * ann.arrowsize * ann.arrowwidth || 0;

var headPlus, headMinus;

if(xa && xa.autorange) {
headPlus = headSize + ann.xshift;
headMinus = headSize - ann.xshift;

if(ann.axref === ann.xref) {
// expand for the arrowhead (padded by arrowhead)
Axes.expand(xa, [xa.r2c(ann.x)], {
ppadplus: headSize,
ppadminus: headSize
ppadplus: headPlus,
ppadminus: headMinus
});
// again for the textbox (padded by textbox)
Axes.expand(xa, [xa.r2c(ann.ax)], {
Expand All @@ -65,17 +70,20 @@ function annAutorange(gd) {
}
else {
Axes.expand(xa, [xa.r2c(ann.x)], {
ppadplus: Math.max(ann._xpadplus, headSize),
ppadminus: Math.max(ann._xpadminus, headSize)
ppadplus: Math.max(ann._xpadplus, headPlus),
ppadminus: Math.max(ann._xpadminus, headMinus)
});
}
}

if(ya && ya.autorange) {
headPlus = headSize - ann.yshift;
headMinus = headSize + ann.yshift;

if(ann.ayref === ann.yref) {
Axes.expand(ya, [ya.r2c(ann.y)], {
ppadplus: headSize,
ppadminus: headSize
ppadplus: headPlus,
ppadminus: headMinus
});
Axes.expand(ya, [ya.r2c(ann.ay)], {
ppadplus: ann._ypadplus,
Expand All @@ -84,8 +92,8 @@ function annAutorange(gd) {
}
else {
Axes.expand(ya, [ya.r2c(ann.y)], {
ppadplus: Math.max(ann._ypadplus, headSize),
ppadminus: Math.max(ann._ypadminus, headSize)
ppadplus: Math.max(ann._ypadplus, headPlus),
ppadminus: Math.max(ann._ypadminus, headMinus)
});
}
}
Expand Down
26 changes: 16 additions & 10 deletions src/components/annotations/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ function drawOne(gd, index) {
// but this one is the positive total size
annSize = Math.abs(annSizeFromWidth) + Math.abs(annSizeFromHeight),
anchor = options[axLetter + 'anchor'],
overallShift = options[axLetter + 'shift'] * (axLetter === 'x' ? 1 : -1),
posPx = annPosPx[axLetter],
basePx,
textPadShift,
Expand Down Expand Up @@ -326,6 +327,9 @@ function drawOne(gd, index) {
posPx.text -= shiftMinus;
}
}

posPx.tail += overallShift;
posPx.head += overallShift;
}
else {
// with no arrow, the text rotates and *then* we put the anchor
Expand All @@ -335,6 +339,10 @@ function drawOne(gd, index) {
posPx.text = basePx + textShift;
}

posPx.text += overallShift;
textShift += overallShift;
textPadShift += overallShift;

// padplus/minus are used by autorange
options['_' + axLetter + 'padplus'] = (annSize / 2) + textPadShift;
options['_' + axLetter + 'padminus'] = (annSize / 2) - textPadShift;
Expand Down Expand Up @@ -524,21 +532,17 @@ function drawOne(gd, index) {

update[annbase + '.x'] = xa ?
xa.p2r(xa.r2p(options.x) + dx) :
((headX + dx - gs.l) / gs.w);
(options.x + (dx / gs.w));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice simplification 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

motivated by the fact that the old way would have needed to explicitly account for shift - notice though in the showarrow: false case I did need to just include shift, due to the auto-anchor business...

update[annbase + '.y'] = ya ?
ya.p2r(ya.r2p(options.y) + dy) :
(1 - ((headY + dy - gs.t) / gs.h));
(options.y - (dy / gs.h));

if(options.axref === options.xref) {
update[annbase + '.ax'] = xa ?
xa.p2r(xa.r2p(options.ax) + dx) :
((headX + dx - gs.l) / gs.w);
update[annbase + '.ax'] = xa.p2r(xa.r2p(options.ax) + dx);
}

if(options.ayref === options.yref) {
update[annbase + '.ay'] = ya ?
ya.p2r(ya.r2p(options.ay) + dy) :
(1 - ((headY + dy - gs.t) / gs.h));
update[annbase + '.ay'] = ya.p2r(ya.r2p(options.ay) + dy);
}

arrowGroup.attr('transform', 'translate(' + dx + ',' + dy + ')');
Expand Down Expand Up @@ -594,7 +598,8 @@ function drawOne(gd, index) {
if(xa) update[annbase + '.x'] = options.x + dx / xa._m;
else {
var widthFraction = options._xsize / gs.w,
xLeft = options.x + options._xshift / gs.w - widthFraction / 2;
xLeft = options.x + (options._xshift - options.xshift) / gs.w -
widthFraction / 2;

update[annbase + '.x'] = dragElement.align(xLeft + dx / gs.w,
widthFraction, 0, 1, options.xanchor);
Expand All @@ -603,7 +608,8 @@ function drawOne(gd, index) {
if(ya) update[annbase + '.y'] = options.y + dy / ya._m;
else {
var heightFraction = options._ysize / gs.h,
yBottom = options.y - options._yshift / gs.h - heightFraction / 2;
yBottom = options.y - (options._yshift + options.yshift) / gs.h -
heightFraction / 2;

update[annbase + '.y'] = dragElement.align(yBottom - dy / gs.h,
heightFraction, 0, 1, options.yanchor);
Expand Down
Binary file modified test/image/baselines/annotations-autorange.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 26 additions & 14 deletions test/image/mocks/annotations-autorange.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,49 +52,61 @@
"width":800,
"margin":{"r":40,"b":100,"l":40,"t":40},
"annotations":[
{"ay":0,"ax":50,"x":1,"y":1.5,"text":"Left"},
{"ay":0,"ax":-50,"x":2,"y":1.5,"text":"Right"},
{"x":1.5,"y":2,"text":"Top","ay":50,"ax":0},
{"x":1.5,"y":1,"text":"Bottom","ay":-50,"ax":0},
{"ay":0,"ax":50,"x":1,"y":1.5,"text":"Left", "xshift": -10, "yshift": -10},
{"ay":0,"ax":-50,"x":2,"y":1.5,"text":"Right", "xshift": 10, "yshift": 10},
{"x":1.5,"y":2,"text":"Top","ay":50,"ax":0, "xshift": -10, "yshift": 10},
{"x":1.5,"y":1,"text":"Bottom","ay":-50,"ax":0, "xshift": 10, "yshift": -10},
{
"xref":"x2","yref":"y2","text":"From left","y":2,"ax":-17,"ay":0,"x":"2001-01-01",
"xanchor": "right", "yanchor": "top", "textangle": 35, "bordercolor": "#444"
"xanchor": "right", "yanchor": "top", "textangle": 35, "bordercolor": "#444",
"xshift": 10
},
{
"xref":"x2","yref":"y2","text":"From<br>right","y":2,"x":"2001-03-01","ay":0,"ax":50,
"bgcolor": "#eee", "width": 50, "height": 40, "textangle": 70
"bgcolor": "#eee", "width": 50, "height": 40, "textangle": 70,
"xshift": -10
},
{
"xref":"x2","yref":"y2","text":"From top","y":3,"ax":0,"ay":-27,"x":"2001-02-01",
"xanchor": "left", "yanchor": "bottom", "textangle": -15, "bordercolor": "#444"
"xanchor": "left", "yanchor": "bottom", "textangle": -15, "bordercolor": "#444",
"yshift": -10
},
{
"xref":"x2","yref":"y2","text":"From Bottom","y":1,"ax":0,"ay":50,"x":"2001-02-01",
"bordercolor": "#444", "borderwidth": 3, "height": 30
"bordercolor": "#444", "borderwidth": 3, "height": 30,
"yshift": 10
},
{
"xref":"x3","yref":"y3","text":"Left<br>no<br>arrow","y":1.5,"x":1,"showarrow":false,
"bordercolor": "#444", "bgcolor": "#eee", "width": 50, "height": 60, "textangle": 10,
"align": "right", "valign": "bottom"
"align": "right", "valign": "bottom", "xshift": 10
},
{
"xref":"x3","yref":"y3","text":"Right<br>no<br>arrow","y":1.5,"x":2,"showarrow":false,
"xshift": -10
},
{"xref":"x3","yref":"y3","text":"Right<br>no<br>arrow","y":1.5,"x":2,"showarrow":false},
{
"xref":"x3","yref":"y3","text":"Bottom<br>no<br>arrow","y":1,"x":1.5,"showarrow":false,
"bgcolor": "#eee", "width": 30, "height": 40, "textangle":-10,
"align": "left", "valign": "top"
"align": "left", "valign": "top", "yshift": 10
},
{
"xref":"x3","yref":"y3","text":"Top<br>no<br>arrow","y":2,"x":1.5,"showarrow":false,
"yshift": -10
},
{"xref":"x3","yref":"y3","text":"Top<br>no<br>arrow","y":2,"x":1.5,"showarrow":false},
{
"xref": "paper", "yref": "paper", "text": "On the<br>bottom of the plot",
"x": 0.3, "y": -0.1, "showarrow": false,
"xanchor": "right", "yanchor": "top", "width": 200, "height": 60,
"bgcolor": "#eee", "bordercolor": "#444"
"bgcolor": "#eee", "bordercolor": "#444",
"xshift": -5, "yshift": 5
},
{
"xref": "paper", "yref": "paper", "text": "blah blah blah blah<br>blah<br>blah<br>blah<br>blah<br>blah",
"x": 0.3, "y": -0.25, "ax": 100, "ay": 0, "textangle": 40, "borderpad": 4,
"xanchor": "left", "yanchor": "bottom", "align": "left", "valign": "top",
"width": 60, "height": 40, "bgcolor": "#eee", "bordercolor": "#444"
"width": 60, "height": 40, "bgcolor": "#eee", "bordercolor": "#444",
"xshift": -5, "yshift": 5
}
]
}
Expand Down
47 changes: 26 additions & 21 deletions test/jasmine/tests/annotations_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -554,9 +554,9 @@ describe('annotations autorange', function() {
it('should adapt to relayout calls', function(done) {
Plotly.plot(gd, mock).then(function() {
assertRanges(
[0.97, 2.03], [0.97, 2.03],
['2000-10-01 08:23:18.0583', '2001-06-05 19:20:23.301'], [-0.245, 4.245],
[0.9, 2.1], [0.86, 2.14]
[0.91, 2.09], [0.91, 2.09],
Copy link
Contributor

@etpinard etpinard Apr 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so these values changed because the annotations-autorange mock changed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so these values changed because the annotations-autorange mock changed?

correct. I guess that's a hazard of reusing mocks for both images and jasmine tests...

['2000-11-13', '2001-04-21'], [-0.069, 3.917],
[0.88, 2.05], [0.92, 2.08]
);

return Plotly.relayout(gd, {
Expand All @@ -567,9 +567,9 @@ describe('annotations autorange', function() {
})
.then(function() {
assertRanges(
[1.44, 2.02], [0.97, 2.03],
['2001-01-18 15:06:04.0449', '2001-03-27 14:01:20.8989'], [-0.245, 4.245],
[1.44, 2.1], [0.86, 2.14]
[1.44, 2.02], [0.91, 2.09],
['2001-01-18', '2001-03-27'], [-0.069, 3.917],
[1.44, 2.1], [0.92, 2.08]
);

return Plotly.relayout(gd, {
Expand All @@ -581,8 +581,8 @@ describe('annotations autorange', function() {
.then(function() {
assertRanges(
[1.44, 2.02], [0.99, 1.52],
['2001-01-31 23:59:59.999', '2001-02-01 00:00:00.001'], [-0.245, 4.245],
[0.5, 2.5], [0.86, 2.14]
['2001-01-31 23:59:59.999', '2001-02-01 00:00:00.001'], [-0.069, 3.917],
[0.5, 2.5], [0.92, 2.08]
);

return Plotly.relayout(gd, {
Expand All @@ -596,9 +596,9 @@ describe('annotations autorange', function() {
})
.then(function() {
assertRanges(
[0.97, 2.03], [0.97, 2.03],
['2000-10-01 08:23:18.0583', '2001-06-05 19:20:23.301'], [-0.245, 4.245],
[0.9, 2.1], [0.86, 2.14]
[0.91, 2.09], [0.91, 2.09],
['2000-11-13', '2001-04-21'], [-0.069, 3.917],
[0.88, 2.05], [0.92, 2.08]
);
})
.catch(failTest)
Expand All @@ -619,10 +619,10 @@ describe('annotations autorange', function() {
})
.then(function() {
assertRanges(
[-1.09, 2.09], [0.94, 3.06],
[-1.09, 2.25], [0.84, 3.06],
// the other axes shouldn't change
['2000-10-01 08:23:18.0583', '2001-06-05 19:20:23.301'], [-0.245, 4.245],
[0.9, 2.1], [0.86, 2.14]
['2000-11-13', '2001-04-21'], [-0.069, 3.917],
[0.88, 2.05], [0.92, 2.08]
);
})
.catch(failTest)
Expand Down Expand Up @@ -961,7 +961,8 @@ describe('annotation effects', function() {
showarrow: false,
text: 'blah<br>blah blah',
xref: 'paper',
yref: 'paper'
yref: 'paper',
xshift: 5, yshift: 5
}])
.then(function() {
var bbox = textBox().getBoundingClientRect();
Expand All @@ -981,7 +982,8 @@ describe('annotation effects', function() {
xref: 'paper',
yref: 'paper',
xanchor: 'left',
yanchor: 'top'
yanchor: 'top',
xshift: 5, yshift: 5
}])
.then(function() {
// with offsets 0, 0 because the anchor doesn't change now
Expand All @@ -999,7 +1001,8 @@ describe('annotation effects', function() {
xref: 'paper',
yref: 'paper',
ax: 30,
ay: 30
ay: 30,
xshift: 5, yshift: 5
}])
.then(function() {
return checkDragging(arrowDrag, 0, 0, 1);
Expand All @@ -1014,7 +1017,8 @@ describe('annotation effects', function() {
x: 0,
y: 0,
showarrow: false,
text: 'blah<br>blah blah'
text: 'blah<br>blah blah',
xshift: 5, yshift: 5
}])
.then(function() {
return checkDragging(textDrag, 0, 0, 100);
Expand All @@ -1029,7 +1033,8 @@ describe('annotation effects', function() {
y: 0,
text: 'blah<br>blah blah',
ax: 30,
ay: -30
ay: -30,
xshift: 5, yshift: 5
}])
.then(function() {
return checkDragging(arrowDrag, 0, 0, 100);
Expand Down Expand Up @@ -1127,7 +1132,7 @@ describe('annotation effects', function() {
}

makePlot([
{x: 50, y: 50, text: 'hi', width: 50, ax: 0, ay: -40},
{x: 50, y: 50, text: 'hi', width: 50, ax: 0, ay: -40, xshift: -50, yshift: 50},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is editable: true tested with xshift / yshift? It's a little hard to tell from the diff.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, all the other tests above this in describe('annotation effects', to which I added xshift: 5, yshift: 5, are editable and failed before I fixed dragging with shifts.

{x: 20, y: 20, text: 'bye', height: 40, showarrow: false},
{x: 80, y: 80, text: 'why?', ax: 0, ay: -40}
], {}) // turn off the default editable: true
Expand All @@ -1136,7 +1141,7 @@ describe('annotation effects', function() {
gd.on('plotly_clickannotation', function(evt) { clickData.push(evt); });

gdBB = gd.getBoundingClientRect();
pos0Head = [gdBB.left + 250, gdBB.top + 250];
pos0Head = [gdBB.left + 200, gdBB.top + 200];
pos0 = [pos0Head[0], pos0Head[1] - 40];
pos1 = [gdBB.left + 160, gdBB.top + 340];
pos2Head = [gdBB.left + 340, gdBB.top + 160];
Expand Down