Skip to content

Faster axis autorange + remove calcIfAutorange edit type #2823

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 15 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from 6 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
44 changes: 22 additions & 22 deletions src/components/annotations/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module.exports = templatedArray('annotation', {
valType: 'boolean',
role: 'info',
dflt: true,
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not for now of course, but annotations (showing, hiding, dragging in GUI) are a great argument in favor of each trace and item tracking its own autorange contributions, so it doesn't take a full recalc to move one annotation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so it doesn't take a full recalc to move one annotation.

Absolutely! I'll open an issue about this once this PR is merged.

description: [
'Determines whether or not this annotation is visible.'
].join(' ')
Expand All @@ -28,7 +28,7 @@ module.exports = templatedArray('annotation', {
text: {
valType: 'string',
role: 'info',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the text associated with this annotation.',
'Plotly uses a subset of HTML tags to do things like',
Expand All @@ -41,14 +41,14 @@ module.exports = templatedArray('annotation', {
valType: 'angle',
dflt: 0,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the angle at which the `text` is drawn',
'with respect to the horizontal.'
].join(' ')
},
font: fontAttrs({
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
colorEditType: 'arraydraw',
description: 'Sets the annotation text font.'
}),
Expand All @@ -57,7 +57,7 @@ module.exports = templatedArray('annotation', {
min: 1,
dflt: null,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets an explicit width for the text box. null (default) lets the',
'text set the box width. Wider text will be clipped.',
Expand All @@ -69,7 +69,7 @@ module.exports = templatedArray('annotation', {
min: 1,
dflt: null,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets an explicit height for the text box. null (default) lets the',
'text set the box height. Taller text will be clipped.'
Expand Down Expand Up @@ -130,7 +130,7 @@ module.exports = templatedArray('annotation', {
min: 0,
dflt: 1,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the padding (in px) between the `text`',
'and the enclosing border.'
Expand All @@ -141,7 +141,7 @@ module.exports = templatedArray('annotation', {
min: 0,
dflt: 1,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the width (in px) of the border enclosing',
'the annotation `text`.'
Expand All @@ -152,7 +152,7 @@ module.exports = templatedArray('annotation', {
valType: 'boolean',
dflt: true,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Determines whether or not the annotation is drawn with an arrow.',
'If *true*, `text` is placed near the arrow\'s tail.',
Expand Down Expand Up @@ -197,7 +197,7 @@ module.exports = templatedArray('annotation', {
min: 0.3,
dflt: 1,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the size of the end annotation arrow head, relative to `arrowwidth`.',
'A value of 1 (default) gives a head about 3x as wide as the line.'
Expand All @@ -208,7 +208,7 @@ module.exports = templatedArray('annotation', {
min: 0.3,
dflt: 1,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the size of the start annotation arrow head, relative to `arrowwidth`.',
'A value of 1 (default) gives a head about 3x as wide as the line.'
Expand All @@ -218,15 +218,15 @@ module.exports = templatedArray('annotation', {
valType: 'number',
min: 0.1,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: 'Sets the width (in px) of annotation arrow line.'
},
standoff: {
valType: 'number',
min: 0,
dflt: 0,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets a distance, in pixels, to move the end arrowhead away from the',
'position it is pointing at, for example to point at the edge of',
Expand All @@ -240,7 +240,7 @@ module.exports = templatedArray('annotation', {
min: 0,
dflt: 0,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets a distance, in pixels, to move the start arrowhead away from the',
'position it is pointing at, for example to point at the edge of',
Expand All @@ -252,7 +252,7 @@ module.exports = templatedArray('annotation', {
ax: {
valType: 'any',
role: 'info',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the x component of the arrow tail about the arrow head.',
'If `axref` is `pixel`, a positive (negative) ',
Expand All @@ -265,7 +265,7 @@ module.exports = templatedArray('annotation', {
ay: {
valType: 'any',
role: 'info',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the y component of the arrow tail about the arrow head.',
'If `ayref` is `pixel`, a positive (negative) ',
Expand Down Expand Up @@ -332,7 +332,7 @@ module.exports = templatedArray('annotation', {
x: {
valType: 'any',
role: 'info',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the annotation\'s x position.',
'If the axis `type` is *log*, then you must take the',
Expand All @@ -350,7 +350,7 @@ module.exports = templatedArray('annotation', {
values: ['auto', 'left', 'center', 'right'],
dflt: 'auto',
role: 'info',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the text box\'s horizontal position anchor',
'This anchor binds the `x` position to the *left*, *center*',
Expand All @@ -369,7 +369,7 @@ module.exports = templatedArray('annotation', {
valType: 'number',
dflt: 0,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Shifts the position of the whole annotation and arrow to the',
'right (positive) or left (negative) by this many pixels.'
Expand All @@ -395,7 +395,7 @@ module.exports = templatedArray('annotation', {
y: {
valType: 'any',
role: 'info',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the annotation\'s y position.',
'If the axis `type` is *log*, then you must take the',
Expand All @@ -413,7 +413,7 @@ module.exports = templatedArray('annotation', {
values: ['auto', 'top', 'middle', 'bottom'],
dflt: 'auto',
role: 'info',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Sets the text box\'s vertical position anchor',
'This anchor binds the `y` position to the *top*, *middle*',
Expand All @@ -432,7 +432,7 @@ module.exports = templatedArray('annotation', {
valType: 'number',
dflt: 0,
role: 'style',
editType: 'calcIfAutorange+arraydraw',
editType: 'calc+arraydraw',
description: [
'Shifts the position of the whole annotation and arrow up',
'(positive) or down (negative) by this many pixels.'
Expand Down
34 changes: 10 additions & 24 deletions src/components/annotations/calc_autorange.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,11 @@ var draw = require('./draw').draw;


module.exports = function calcAutorange(gd) {
var fullLayout = gd._fullLayout,
annotationList = Lib.filterVisible(fullLayout.annotations);

if(!annotationList.length || !gd._fullData.length) return;

var annotationAxes = {};
annotationList.forEach(function(ann) {
annotationAxes[ann.xref] = 1;
annotationAxes[ann.yref] = 1;
});
var fullLayout = gd._fullLayout;
var annotationList = Lib.filterVisible(fullLayout.annotations);

for(var axId in annotationAxes) {
var ax = Axes.getFromId(gd, axId);
if(ax && ax.autorange) {
return Lib.syncOrAsync([
draw,
annAutorange
], gd);
}
if(annotationList.length && gd._fullData.length) {
return Lib.syncOrAsync([draw, annAutorange], gd);
}
};

Expand All @@ -46,14 +32,14 @@ function annAutorange(gd) {
// use the arrow and the text bg rectangle,
// as the whole anno may include hidden text in its bbox
Lib.filterVisible(fullLayout.annotations).forEach(function(ann) {
var xa = Axes.getFromId(gd, ann.xref),
ya = Axes.getFromId(gd, ann.yref),
headSize = 3 * ann.arrowsize * ann.arrowwidth || 0,
startHeadSize = 3 * ann.startarrowsize * ann.arrowwidth || 0;
var xa = Axes.getFromId(gd, ann.xref);
var ya = Axes.getFromId(gd, ann.yref);
var headSize = 3 * ann.arrowsize * ann.arrowwidth || 0;
var startHeadSize = 3 * ann.startarrowsize * ann.arrowwidth || 0;

var headPlus, headMinus, startHeadPlus, startHeadMinus;

if(xa && xa.autorange) {
if(xa) {
headPlus = headSize + ann.xshift;
headMinus = headSize - ann.xshift;
startHeadPlus = startHeadSize + ann.xshift;
Expand Down Expand Up @@ -81,7 +67,7 @@ function annAutorange(gd) {
}
}

if(ya && ya.autorange) {
if(ya) {
headPlus = headSize - ann.yshift;
headMinus = headSize + ann.yshift;
startHeadPlus = startHeadSize - ann.yshift;
Expand Down
18 changes: 6 additions & 12 deletions src/components/annotations/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,25 +300,17 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
* otherwise the text anchor point
*/
if(ax) {
/*
* hide the annotation if it's pointing outside the visible plot
* as long as the axis isn't autoranged - then we need to draw it
* anyway to get its bounding box. When we're dragging, an axis can
* still look autoranged even though it won't be when the drag finishes.
*/
// check if annotation is off screen, to bypass DOM manipulations
var posFraction = ax.r2fraction(options[axLetter]);
if((gd._dragging || !ax.autorange) && (posFraction < 0 || posFraction > 1)) {
if(posFraction < 0 || posFraction > 1) {
if(tailRef === axRef) {
posFraction = ax.r2fraction(options['a' + axLetter]);
if(posFraction < 0 || posFraction > 1) {
annotationIsOffscreen = true;
}
}
else {
} else {
annotationIsOffscreen = true;
}

if(annotationIsOffscreen) continue;
}
basePx = ax._offset + ax.r2p(options[axLetter]);
autoAlignFraction = 0.5;
Expand Down Expand Up @@ -402,7 +394,9 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
options['_' + axLetter + 'shift'] = textShift;
}

if(annotationIsOffscreen) {
// We have everything we need for calcAutorange at this point,
// we can safely exit - unless we're currently dragging the plot
if(!gd._dragging && annotationIsOffscreen) {
annTextGroupInner.remove();
return;
}
Expand Down
5 changes: 0 additions & 5 deletions src/plots/cartesian/autorange.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,6 @@ function doAutoRange(ax) {
}
}

function needsAutorange(ax) {
return ax.autorange || ax._rangesliderAutorange;
}

/*
* expand: if autoranging, include new data in the outer limits for this axis.
* Note that `expand` is called during `calc`, when we don't yet know the axis
Expand All @@ -236,7 +232,6 @@ function needsAutorange(ax) {
* and make it a tight bound if possible
*/
function expand(ax, data, options) {
if(!needsAutorange(ax) || !data) return;

if(!ax._min) ax._min = [];
if(!ax._max) ax._max = [];
Expand Down
6 changes: 3 additions & 3 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ module.exports = {
valType: 'enumerated',
values: [true, false, 'reversed'],
dflt: true,
role: 'style',
editType: 'calc',
role: 'info',
editType: 'plot',
impliedEdits: {'range[0]': undefined, 'range[1]': undefined},
description: [
'Determines whether or not the range of this axis is',
Expand All @@ -91,7 +91,7 @@ module.exports = {
valType: 'enumerated',
values: ['normal', 'tozero', 'nonnegative'],
dflt: 'normal',
role: 'style',
role: 'info',
editType: 'plot',
description: [
'If *normal*, the range is computed in relation to the extrema',
Expand Down
5 changes: 3 additions & 2 deletions src/traces/scatter/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ function calcAxisExpansion(gd, trace, xa, ya, x, y, ppad) {
yOptions.padded = false;
}

Axes.expand(xa, x, xOptions);
Axes.expand(ya, y, yOptions);
// N.B. asymmetric splom traces call this with undefined xa or ya
Copy link
Collaborator

Choose a reason for hiding this comment

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

not undefined, that would error here as well as above... it's {}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch -> 026cd53

if(xa._id) Axes.expand(xa, x, xOptions);
if(ya._id) Axes.expand(ya, y, yOptions);
}

function calcMarkerSize(trace, serieslen) {
Expand Down
37 changes: 37 additions & 0 deletions test/jasmine/tests/annotations_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,43 @@ describe('annotations autorange', function() {
.catch(failTest)
.then(done);
});

it('should propagate axis autorange changes when axis ranges are set', function(done) {
function _assert(msg, xrng, yrng) {
var fullLayout = gd._fullLayout;
expect(fullLayout.xaxis.range).toBeCloseToArray(xrng, 1, msg + ' xrng');
expect(fullLayout.yaxis.range).toBeCloseToArray(yrng, 1, msg + ' yrng');
}

Plotly.plot(gd, [{y: [1, 2]}], {
xaxis: {range: [0, 2]},
yaxis: {range: [0, 2]},
annotations: [{
text: 'a',
x: 3, y: 3
}]
})
.then(function() {
_assert('set rng / small tx', [0, 2], [0, 2]);
return Plotly.relayout(gd, 'annotations[0].text', 'loooooooooooooooooooooooong');
})
.then(function() {
_assert('set rng / big tx', [0, 2], [0, 2]);
return Plotly.relayout(gd, {
'xaxis.autorange': true,
'yaxis.autorange': true
});
})
.then(function() {
_assert('auto rng / big tx', [-0.22, 3.57], [0.84, 3.365]);
return Plotly.relayout(gd, 'annotations[0].text', 'a');
})
.then(function() {
_assert('auto rng / small tx', [-0.18, 3.035], [0.84, 3.365]);
})
.catch(failTest)
.then(done);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Beautiful test!

});
});

describe('annotation clicktoshow', function() {
Expand Down
Loading