Skip to content
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

Rangeslider allow zoom on oppaxis #2364

Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
519e1a7
better visual cue of zoom on oppaxis with rangeslider
TomDemulierChevret Feb 14, 2018
044e633
add a new attributes to rangeslider to switch back to the old behaviour
TomDemulierChevret Feb 16, 2018
f335258
fix check when using new data
TomDemulierChevret Feb 16, 2018
707f432
fix default value rangeslider test
TomDemulierChevret Feb 16, 2018
6a7f652
renammed new attributes to "fixedyrange"
TomDemulierChevret Feb 16, 2018
fc4f082
Introduce new attributes to axes to allow to specifiy fixed range to …
TomDemulierChevret Feb 19, 2018
92c6550
Fix broken test from attribute removal
TomDemulierChevret Feb 19, 2018
b30167c
Add missing gl attribute
TomDemulierChevret Feb 19, 2018
91caff1
Merge branch 'master' into rangeslider-allow-zoom-on-oppaxis
TomDemulierChevret Feb 19, 2018
3dd91b5
Renammed new attributes for more clarity and portability
TomDemulierChevret Feb 20, 2018
00fd1d7
Coerce of new attributes is only made for y axis
TomDemulierChevret Feb 20, 2018
5e0486a
Merge remote-tracking branch 'upstream/master' into rangeslider-allow…
TomDemulierChevret Feb 20, 2018
32488f1
Changed rangeslidermode values for more clarity
TomDemulierChevret Feb 20, 2018
bc2a40a
Switch to new rangeslider range opts (default missing)
TomDemulierChevret Feb 28, 2018
d3b6071
Added default attributes
TomDemulierChevret Feb 28, 2018
b496641
Remove old attributes
TomDemulierChevret Feb 28, 2018
149ef70
Add autorange computation
TomDemulierChevret Feb 28, 2018
54d8b58
Merge remote-tracking branch 'upstream/master' into rangeslider-allow…
TomDemulierChevret Feb 28, 2018
dd48914
Add missing check
TomDemulierChevret Feb 28, 2018
a8a3ee5
Add missing catch to test to retrieve the tracebacks
TomDemulierChevret Mar 2, 2018
0ae2831
Change yAxis rangeslider rangeOpts computation + fix yAxis rangeslide…
TomDemulierChevret Mar 2, 2018
8764e4d
Add missing check
TomDemulierChevret Mar 2, 2018
a17d3a8
Fix rangeslider test
TomDemulierChevret Mar 2, 2018
e85e3d0
Renamed parameter to keep name consistency across the file
TomDemulierChevret Mar 2, 2018
0dd8562
Merge remote-tracking branch 'upstream/master' into rangeslider-allow…
TomDemulierChevret Mar 2, 2018
3929be6
Changes requested by @alexcjohnson
TomDemulierChevret Mar 2, 2018
e2ad33d
Changes requested by @alexcjohnson
TomDemulierChevret Mar 2, 2018
df85f35
Changes requested by @etpinard
TomDemulierChevret Mar 5, 2018
fe83e07
Default range for 'fixed' rangemode value is now the range of the axe
TomDemulierChevret Mar 5, 2018
3b6b81a
Changes requested by @etpinard
TomDemulierChevret Mar 6, 2018
9de4e3e
Changes requested by @etpinard
TomDemulierChevret Mar 6, 2018
f2819c8
Changes requested by @etpinard
TomDemulierChevret Mar 6, 2018
df96a13
Merge branch 'master' into rangeslider-allow-zoom-on-oppaxis
TomDemulierChevret Mar 6, 2018
9c66f81
Add test for new attributes default and coerce
TomDemulierChevret Mar 7, 2018
f092c44
Add interaction test for new attributes
TomDemulierChevret Mar 7, 2018
041ce3d
Fixed autorange test precision
TomDemulierChevret Mar 7, 2018
23c8401
Fixed autorange test precision
TomDemulierChevret Mar 7, 2018
73560f6
Merge branch 'master' into rangeslider-allow-zoom-on-oppaxis
alexcjohnson Mar 7, 2018
c556f8c
rename range_attributes file -> oppaxis_attributes
etpinard Mar 7, 2018
43f15a7
add rangeslider.yaxis? to schema flagging it with _isSubplotObj
etpinard Mar 7, 2018
ccb6091
fix rangeslider.y.rangemode=auto and add a test image
alexcjohnson Mar 7, 2018
6a88b24
Merge branch 'rangeslider-allow-zoom-on-oppaxis' of github.com:TomDem…
alexcjohnson Mar 7, 2018
95b8c10
test turning on autorange via rangeslider attrs
alexcjohnson Mar 7, 2018
4f54f62
drop rangeslider style attributes to editType: plot and test
alexcjohnson Mar 7, 2018
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
4 changes: 4 additions & 0 deletions src/components/rangeslider/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,13 @@ module.exports = {
grabAreaMaxClassName: 'rangeslider-grabarea-max',
handleMaxClassName: 'rangeslider-handle-max',

maskMinOppAxisClassName: 'rangeslider-mask-min-opp-axis',
maskMaxOppAxisClassName: 'rangeslider-mask-max-opp-axis',

// style constants

maskColor: 'rgba(0,0,0,0.4)',
maskOppColor: 'rgba(0,0,0,0.2)',
Copy link
Contributor

Choose a reason for hiding this comment

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

Just noticed this. Why pick a different opacity value here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I like this effect - you see that the y axis is constrained, but it's not shaded as darkly as the x axis constraint, which aligns with the fact that you can only affect the x axis constraint with the range slider handles.

But a different thought occurred to me on looking at this: this is semitransparent black, so does that mean range sliders don't work on a black background? That's a totally separate issue, doesn't need to be addressed in this PR, but we should look into it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, that's what I wanted to show with the 2 different values of opacity.

And yeah, the black backgrond will be an issue.


slideBoxFill: 'transparent',
slideBoxCursor: 'ew-resize',
Expand Down
72 changes: 67 additions & 5 deletions src/components/rangeslider/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,21 +136,31 @@ module.exports = function(gd) {

opts._rl = [range0, range1];

if(oppAxisOpts.rangeslidermode === 'auto' || oppAxisOpts.rangeslidermode === 'fixed') {
var range0OppAxis = oppAxisOpts.r2l(oppAxisOpts.rangesliderrange[0]),
range1OppAxis = oppAxisOpts.r2l(oppAxisOpts.rangesliderrange[1]),
distOppAxis = range1OppAxis - range0OppAxis;

opts.d2pOppAxis = function(v) {
return (v - range0OppAxis) / distOppAxis * opts._height;
};
}

// update inner nodes

rangeSlider
.call(drawBg, gd, axisOpts, opts)
.call(addClipPath, gd, axisOpts, opts)
.call(drawRangePlot, gd, axisOpts, opts)
.call(drawMasks, gd, axisOpts, opts)
.call(drawMasks, gd, axisOpts, opts, oppAxisOpts)
.call(drawSlideBox, gd, axisOpts, opts)
.call(drawGrabbers, gd, axisOpts, opts);

// setup drag element
setupDragElement(rangeSlider, gd, axisOpts, opts);

// update current range
setPixelRange(rangeSlider, gd, axisOpts, opts);
setPixelRange(rangeSlider, gd, axisOpts, opts, oppAxisOpts);

// update margins

Expand Down Expand Up @@ -266,13 +276,17 @@ function setDataRange(rangeSlider, gd, axisOpts, opts) {
});
}

function setPixelRange(rangeSlider, gd, axisOpts, opts) {
function setPixelRange(rangeSlider, gd, axisOpts, opts, oppAxisOpts) {
var hw2 = constants.handleWidth / 2;

function clamp(v) {
return Lib.constrain(v, 0, opts._width);
}

function clampOppAxis(v) {
return Lib.constrain(v, 0, opts._height);
}

function clampHandle(v) {
return Lib.constrain(v, -hw2, opts._width + hw2);
}
Expand All @@ -291,6 +305,26 @@ function setPixelRange(rangeSlider, gd, axisOpts, opts) {
.attr('x', pixelMax)
.attr('width', opts._width - pixelMax);

if(oppAxisOpts.rangeslidermode === 'auto' || oppAxisOpts.rangeslidermode === 'fixed') {
var pixelMinOppAxis = opts._height - clampOppAxis(opts.d2pOppAxis(oppAxisOpts._rl[1])),
pixelMaxOppAxis = opts._height - clampOppAxis(opts.d2pOppAxis(oppAxisOpts._rl[0]));

rangeSlider.select('rect.' + constants.maskMinOppAxisClassName)
.attr('x', pixelMin)
.attr('height', pixelMinOppAxis)
.attr('width', pixelMax - pixelMin);

rangeSlider.select('rect.' + constants.maskMaxOppAxisClassName)
.attr('x', pixelMin)
.attr('y', pixelMaxOppAxis)
.attr('height', opts._height - pixelMaxOppAxis)
.attr('width', pixelMax - pixelMin);

rangeSlider.select('rect.' + constants.slideBoxClassName)
.attr('y', pixelMinOppAxis)
.attr('height', pixelMaxOppAxis - pixelMinOppAxis);
}

// add offset for crispier corners
// https://github.com/plotly/plotly.js/pull/1409
var offset = 0.5;
Expand Down Expand Up @@ -394,7 +428,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
mockFigure.layout[oppAxisName] = {
type: oppAxisOpts.type,
domain: [0, 1],
range: oppAxisOpts.range.slice(),
range: (oppAxisOpts.rangeslidermode === 'auto' || oppAxisOpts.rangeslidermode === 'fixed') ? oppAxisOpts.rangesliderrange.slice() : oppAxisOpts.range.slice(),
calendar: oppAxisOpts.calendar
};

Expand Down Expand Up @@ -435,7 +469,7 @@ function filterRangePlotCalcData(calcData, subplotId) {
return out;
}

function drawMasks(rangeSlider, gd, axisOpts, opts) {
function drawMasks(rangeSlider, gd, axisOpts, opts, oppAxisOpts) {
var maskMin = rangeSlider.selectAll('rect.' + constants.maskMinClassName)
.data([0]);

Expand All @@ -459,6 +493,34 @@ function drawMasks(rangeSlider, gd, axisOpts, opts) {
maskMax
.attr('height', opts._height)
.call(Color.fill, constants.maskColor);

// masks used for oppAxis zoom
if(oppAxisOpts.rangeslidermode === 'auto' || oppAxisOpts.rangeslidermode === 'fixed') {
var maskMinOppAxis = rangeSlider.selectAll('rect.' + constants.maskMinOppAxisClassName)
.data([0]);

maskMinOppAxis.enter().append('rect')
.classed(constants.maskMinOppAxisClassName, true)
.attr('y', 0)
.attr('shape-rendering', 'crispEdges');

maskMinOppAxis
.attr('width', opts._width)
.call(Color.fill, constants.maskOppColor);

var maskMaxOppAxis = rangeSlider.selectAll('rect.' + constants.maskMaxOppAxisClassName)
.data([0]);

maskMaxOppAxis.enter().append('rect')
.classed(constants.maskMaxOppAxisClassName, true)
.attr('y', 0)
.attr('shape-rendering', 'crispEdges');

maskMaxOppAxis
.attr('width', opts._width)
.style('border-top', constants.maskOppBorder)
.call(Color.fill, constants.maskOppColor);
}
}

function drawSlideBox(rangeSlider, gd, axisOpts, opts) {
Expand Down
9 changes: 8 additions & 1 deletion src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ axes.doAutoRange = function(ax) {

// TODO do we really need this?
var hasDeps = (ax._min && ax._max && ax._min.length && ax._max.length);
var axIn;

if(ax.autorange && hasDeps) {
ax.range = axes.getAutoRange(ax);
Expand All @@ -362,10 +363,16 @@ axes.doAutoRange = function(ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

var axIn = ax._input;
axIn = ax._input;
axIn.range = ax.range.slice();
axIn.autorange = ax.autorange;
}

if(ax.rangeslidermode === 'auto') {
ax.rangesliderrange = hasDeps ? axes.getAutoRange(ax) : ax.range.slice();
axIn = ax._input;
axIn.rangesliderrange = ax.rangesliderrange.slice();
}
};

// save a copy of the initial axis ranges in fullLayout
Expand Down
13 changes: 13 additions & 0 deletions src/plots/cartesian/axis_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
coerce('range');
containerOut.cleanRange();

if(letter === 'y') {
if(containerIn.rangesliderrange) {
coerce('rangeslidermode', 'auto');
} else if(containerOut.isValidRange(containerIn.rangesliderrange)) {
coerce('rangeslidermode', 'fixed');
} else {
coerce('rangeslidermode', 'match');
}

coerce('rangesliderrange');
containerOut.cleanRange('rangesliderrange');
}

handleCategoryOrderDefaults(containerIn, containerOut, coerce);
containerOut._initialCategories = axType === 'category' ?
orderedCategories(letter, containerOut.categoryorder, containerOut.categoryarray, options.data) :
Expand Down
27 changes: 27 additions & 0 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,33 @@ module.exports = {
'If true, then zoom is disabled.'
].join(' ')
},
rangeslidermode: {
valType: 'enumerated',
values: ['auto', 'fixed', 'match'],
dflt: 'auto',
role: 'style',
editType: 'calc',
description: [
'Determines whether or not the range of this axis in',
'the rangeslider use the same value than in the main plot',
'when zooming in/out.',
'If *auto*, the autorange will be used.',
'If *fixed*, the `rangesliderrange` is used.',
'If *match*, the current range is used.'
].join(' ')
},
rangesliderrange: {
valType: 'info_array',
role: 'style',
items: [
{valType: 'any', editType: 'calc'},
{valType: 'any', editType: 'calc'}
],
editType: 'calc',
description: [
'Sets the range of this axis for the rangeslider.'
].join(' ')
},
// scaleanchor: not used directly, just put here for reference
// values are any opposite-letter axis id
scaleanchor: {
Expand Down
2 changes: 2 additions & 0 deletions src/plots/gl3d/layout/axis_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ module.exports = overrideAll({
autorange: axesAttrs.autorange,
rangemode: axesAttrs.rangemode,
range: axesAttrs.range,
rangeslidermode: axesAttrs.rangeslidermode,
rangesliderrange: axesAttrs.rangesliderrange,
// ticks
tickmode: axesAttrs.tickmode,
nticks: axesAttrs.nticks,
Expand Down