Skip to content

Commit 6408944

Browse files
authored
Merge pull request #6735 from plotly/range-inside-ticklables
Add `insiderange` to cartesian axes
2 parents 630b092 + 121a664 commit 6408944

18 files changed

+635
-36
lines changed

src/components/colorbar/draw.js

+1
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,7 @@ function mockColorBarAxis(gd, opts, zrange) {
10041004
noHover: true,
10051005
noTickson: true,
10061006
noTicklabelmode: true,
1007+
noInsideRange: true,
10071008
calendar: fullLayout.calendar // not really necessary (yet?)
10081009
};
10091010

src/plot_api/helpers.js

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ exports.cleanLayout = function(layout) {
7272
ax.autorange = true;
7373
ax.rangemode = 'tozero';
7474
}
75+
76+
if(ax.insiderange) delete ax.range;
77+
7578
delete ax.islog;
7679
delete ax.isdate;
7780
delete ax.categories; // replaced by _categories

src/plot_api/plot_api.js

+6-11
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,12 @@ function _doPlot(gd, data, layout, config) {
357357
seq.push(
358358
drawAxes,
359359
function insideTickLabelsAutorange(gd) {
360-
if(gd._fullLayout._insideTickLabelsAutorange) {
361-
relayout(gd, gd._fullLayout._insideTickLabelsAutorange).then(function() {
362-
gd._fullLayout._insideTickLabelsAutorange = undefined;
360+
var insideTickLabelsUpdaterange = gd._fullLayout._insideTickLabelsUpdaterange;
361+
if(insideTickLabelsUpdaterange) {
362+
gd._fullLayout._insideTickLabelsUpdaterange = undefined;
363+
364+
return relayout(gd, insideTickLabelsUpdaterange).then(function() {
365+
Axes.saveRangeInitial(gd, true);
363366
});
364367
}
365368
}
@@ -379,16 +382,9 @@ function _doPlot(gd, data, layout, config) {
379382
// calculated. Would be much better to separate margin calculations from
380383
// component drawing - see https://github.com/plotly/plotly.js/issues/2704
381384
Plots.doAutoMargin,
382-
saveRangeInitialForInsideTickLabels,
383385
Plots.previousPromises
384386
);
385387

386-
function saveRangeInitialForInsideTickLabels(gd) {
387-
if(gd._fullLayout._insideTickLabelsAutorange) {
388-
if(graphWasEmpty) Axes.saveRangeInitial(gd, true);
389-
}
390-
}
391-
392388
// even if everything we did was synchronous, return a promise
393389
// so that the caller doesn't care which route we took
394390
var plotDone = Lib.syncOrAsync(seq, gd);
@@ -1793,7 +1789,6 @@ function relayout(gd, astr, val) {
17931789
// something may have happened within relayout that we
17941790
// need to wait for
17951791
var seq = [Plots.previousPromises];
1796-
17971792
if(flags.layoutReplot) {
17981793
seq.push(subroutines.layoutReplot);
17991794
} else if(Object.keys(aobj).length) {

src/plots/cartesian/axes.js

+92-15
Original file line numberDiff line numberDiff line change
@@ -3821,28 +3821,105 @@ axes.drawLabels = function(gd, ax, opts) {
38213821
});
38223822
}
38233823

3824+
var computeTickLabelBoundingBoxes = function() {
3825+
var labelsMaxW = 0;
3826+
var labelsMaxH = 0;
3827+
tickLabels.each(function(d, i) {
3828+
var thisLabel = selectTickLabel(this);
3829+
var mathjaxGroup = thisLabel.select('.text-math-group');
3830+
3831+
if(mathjaxGroup.empty()) {
3832+
var bb;
3833+
3834+
if(ax._vals[i]) {
3835+
bb = ax._vals[i].bb || Drawing.bBox(thisLabel.node());
3836+
ax._vals[i].bb = bb;
3837+
}
3838+
3839+
labelsMaxW = Math.max(labelsMaxW, bb.width);
3840+
labelsMaxH = Math.max(labelsMaxH, bb.height);
3841+
}
3842+
});
3843+
3844+
return {
3845+
labelsMaxW: labelsMaxW,
3846+
labelsMaxH: labelsMaxH
3847+
};
3848+
};
3849+
38243850
var anchorAx = ax._anchorAxis;
38253851
if(
3826-
anchorAx && anchorAx.autorange &&
3852+
anchorAx && (anchorAx.autorange || anchorAx.insiderange) &&
38273853
insideTicklabelposition(ax) &&
38283854
!isLinked(fullLayout, ax._id)
38293855
) {
3830-
if(!fullLayout._insideTickLabelsAutorange) {
3831-
fullLayout._insideTickLabelsAutorange = {};
3856+
if(!fullLayout._insideTickLabelsUpdaterange) {
3857+
fullLayout._insideTickLabelsUpdaterange = {};
38323858
}
3833-
fullLayout._insideTickLabelsAutorange[anchorAx._name + '.autorange'] = anchorAx.autorange;
3834-
3835-
seq.push(
3836-
function computeFinalTickLabelBoundingBoxes() {
3837-
tickLabels.each(function(d, i) {
3838-
var thisLabel = selectTickLabel(this);
3839-
var mathjaxGroup = thisLabel.select('.text-math-group');
3840-
if(mathjaxGroup.empty()) {
3841-
ax._vals[i].bb = Drawing.bBox(thisLabel.node());
3842-
}
3843-
});
3859+
3860+
if(anchorAx.autorange) {
3861+
fullLayout._insideTickLabelsUpdaterange[anchorAx._name + '.autorange'] = anchorAx.autorange;
3862+
3863+
seq.push(computeTickLabelBoundingBoxes);
3864+
}
3865+
3866+
if(anchorAx.insiderange) {
3867+
var BBs = computeTickLabelBoundingBoxes();
3868+
var move = ax._id.charAt(0) === 'y' ?
3869+
BBs.labelsMaxW :
3870+
BBs.labelsMaxH;
3871+
3872+
move += 2 * TEXTPAD;
3873+
3874+
if(ax.ticklabelposition === 'inside') {
3875+
move += ax.ticklen || 0;
38443876
}
3845-
);
3877+
3878+
var sgn = (ax.side === 'right' || ax.side === 'top') ? 1 : -1;
3879+
var index = sgn === 1 ? 1 : 0;
3880+
var otherIndex = sgn === 1 ? 0 : 1;
3881+
3882+
var newRange = [];
3883+
newRange[otherIndex] = anchorAx.range[otherIndex];
3884+
3885+
var p0 = anchorAx.d2p(anchorAx.range[index]);
3886+
var p1 = anchorAx.d2p(anchorAx.range[otherIndex]);
3887+
var dist = Math.abs(p1 - p0);
3888+
if(dist - move > 0) {
3889+
dist -= move;
3890+
move *= 1 + move / dist;
3891+
} else {
3892+
move = 0;
3893+
}
3894+
3895+
if(ax._id.charAt(0) !== 'y') move = -move;
3896+
3897+
newRange[index] = anchorAx.p2d(
3898+
anchorAx.d2p(anchorAx.range[index]) +
3899+
sgn * move
3900+
);
3901+
3902+
// handle partial ranges in insiderange
3903+
if(
3904+
anchorAx.autorange === 'min' ||
3905+
anchorAx.autorange === 'max reversed'
3906+
) {
3907+
newRange[0] = null;
3908+
3909+
anchorAx._rangeInitial0 = undefined;
3910+
anchorAx._rangeInitial1 = undefined;
3911+
} else if(
3912+
anchorAx.autorange === 'max' ||
3913+
anchorAx.autorange === 'min reversed'
3914+
) {
3915+
newRange[1] = null;
3916+
3917+
anchorAx._rangeInitial0 = undefined;
3918+
anchorAx._rangeInitial1 = undefined;
3919+
}
3920+
3921+
fullLayout._insideTickLabelsUpdaterange[anchorAx._name + '.range'] = newRange;
3922+
}
38463923
}
38473924

38483925
var done = Lib.syncOrAsync(seq);

src/plots/cartesian/layout_attributes.js

+15
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,21 @@ module.exports = {
398398
'If true, then zoom is disabled.'
399399
].join(' ')
400400
},
401+
insiderange: {
402+
valType: 'info_array',
403+
items: [
404+
{valType: 'any', editType: 'plot'},
405+
{valType: 'any', editType: 'plot'}
406+
],
407+
editType: 'plot',
408+
description: [
409+
'Could be used to set the desired inside range of this axis',
410+
'(excluding the labels) when `ticklabelposition` of',
411+
'the anchored axis has *inside*.',
412+
'Not implemented for axes with `type` *log*.',
413+
'This would be ignored when `range` is provided.'
414+
].join(' ')
415+
},
401416
// scaleanchor: not used directly, just put here for reference
402417
// values are any opposite-letter axis id, or `false`.
403418
scaleanchor: {

src/plots/cartesian/range_defaults.js

+19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,25 @@ module.exports = function handleRangeDefaults(containerIn, containerOut, coerce,
1010
coerce('maxallowed');
1111

1212
var range = coerce('range');
13+
if(!range) {
14+
var insiderange;
15+
if(!options.noInsiderange && axType !== 'log') {
16+
insiderange = coerce('insiderange');
17+
18+
// We may support partial insideranges in future
19+
// For now it is out of scope
20+
if(insiderange && (
21+
insiderange[0] === null ||
22+
insiderange[1] === null
23+
)) {
24+
containerOut.insiderange = false;
25+
insiderange = undefined;
26+
}
27+
28+
if(insiderange) range = coerce('range', insiderange);
29+
}
30+
}
31+
1332
var autorangeDflt = containerOut.getAutorangeDflt(range, options);
1433
var autorange = coerce('autorange', autorangeDflt);
1534

src/plots/gl3d/layout/axis_defaults.js

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, options) {
4646
noTicklabelstep: true,
4747
noTicklabelposition: true,
4848
noTicklabeloverflow: true,
49+
noInsiderange: true,
4950
bgColor: options.bgColor,
5051
calendar: options.calendar
5152
},
32.8 KB
Loading
57.4 KB
Loading
26.2 KB
Loading
74.3 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"data": [{
3+
"xaxis": "x",
4+
"yaxis": "y",
5+
"y": [1000, 10, 100, 1]
6+
}, {
7+
"xaxis": "x2",
8+
"yaxis": "y2",
9+
"y": [1000, 10, 100, 1]
10+
}, {
11+
"xaxis": "x3",
12+
"yaxis": "y3",
13+
"x": [2000, 2001, 2002, 2003],
14+
"y": [1000, 10, 100, 1]
15+
}, {
16+
"xaxis": "x4",
17+
"yaxis": "y4",
18+
"x": [2000, 2001, 2002, 2003],
19+
"y": [1000, 10, 100, 1]
20+
}],
21+
"layout": {
22+
"xaxis": {
23+
"insiderange": [1, 2],
24+
"anchor": "y",
25+
"domain": [0, 0.45],
26+
"gridcolor": "white"
27+
},
28+
"yaxis": {
29+
"anchor": "x",
30+
"domain": [0, 0.45],
31+
"side": "right",
32+
"ticks": "inside",
33+
"ticklabelposition": "inside",
34+
"ticklen": 8,
35+
"tickwidth": 3,
36+
"gridcolor": "white"
37+
},
38+
"xaxis2": {
39+
"insiderange": [2, 1],
40+
"anchor": "y2",
41+
"domain": [0, 0.45],
42+
"gridcolor": "white"
43+
},
44+
"yaxis2": {
45+
"anchor": "x2",
46+
"domain": [0.55, 1],
47+
"side": "left",
48+
"ticks": "inside",
49+
"ticklabelposition": "inside",
50+
"ticklen": 8,
51+
"tickwidth": 3,
52+
"gridcolor": "white"
53+
},
54+
"xaxis3": {
55+
"type": "date",
56+
"insiderange": ["2001-01", "2002-01"],
57+
"anchor": "y3",
58+
"domain": [0.55, 1],
59+
"gridcolor": "white"
60+
},
61+
"yaxis3": {
62+
"anchor": "x3",
63+
"domain": [0, 0.45],
64+
"side": "right",
65+
"ticks": "inside",
66+
"ticklabelposition": "inside",
67+
"ticklen": 8,
68+
"tickwidth": 3,
69+
"gridcolor": "white"
70+
},
71+
"xaxis4": {
72+
"type": "date",
73+
"insiderange": ["2002-01", "2001-01"],
74+
"anchor": "y4",
75+
"domain": [0.55, 1],
76+
"gridcolor": "white"
77+
},
78+
"yaxis4": {
79+
"anchor": "x4",
80+
"domain": [0.55, 1],
81+
"side": "left",
82+
"ticks": "inside",
83+
"ticklabelposition": "inside",
84+
"ticklen": 8,
85+
"tickwidth": 3,
86+
"gridcolor": "white"
87+
},
88+
"plot_bgcolor": "lightblue",
89+
"showlegend": false,
90+
"width": 300,
91+
"height": 900,
92+
"margin": {
93+
"t": 60,
94+
"b": 60,
95+
"l": 60,
96+
"r": 60
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)