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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
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
2 changes: 1 addition & 1 deletion src/components/legend/defaults.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -86,7 +86,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
coerce('orientation');
if(containerOut.orientation === 'h') {
var xaxis = layoutIn.xaxis;
if(xaxis && xaxis.rangeslider && xaxis.rangeslider.visible) {
if(Registry.getComponentMethod('rangeslider', 'isVisible')(xaxis)) {
defaultX = 0;
defaultXAnchor = 'left';
defaultY = 1.1;
Expand Down
78 changes: 25 additions & 53 deletions src/components/rangeslider/draw.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,16 +19,21 @@ var Color = require('../color');
var Titles = require('../titles');

var Cartesian = require('../../plots/cartesian');
var Axes = require('../../plots/cartesian/axes');
var axisIDs = require('../../plots/cartesian/axis_ids');

var dragElement = require('../dragelement');
var setCursor = require('../../lib/setcursor');

var constants = require('./constants');

module.exports = function(gd) {
var fullLayout = gd._fullLayout,
rangeSliderData = makeRangeSliderData(fullLayout);
var fullLayout = gd._fullLayout;
var rangeSliderData = fullLayout._rangeSliderData;
for(var i = 0; i < rangeSliderData.length; i++) {
var opts = rangeSliderData[i][constants.name];
// fullLayout._uid may not exist when we call makeData
opts._clipId = opts._id + '-' + fullLayout._uid;
}

/*
* <g container />
Expand All@@ -55,10 +60,6 @@ module.exports = function(gd) {
.selectAll('g.' + constants.containerClassName)
.data(rangeSliderData, keyFunction);

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// remove exiting sliders and their corresponding clip paths
rangeSliders.exit().each(function(axisOpts) {
var opts = axisOpts[constants.name];
Expand All@@ -68,12 +69,16 @@ module.exports = function(gd) {
// return early if no range slider is visible
if(rangeSliderData.length === 0) return;

rangeSliders.enter().append('g')
.classed(constants.containerClassName, true)
.attr('pointer-events', 'all');

// for all present range sliders
rangeSliders.each(function(axisOpts) {
var rangeSlider = d3.select(this),
opts = axisOpts[constants.name],
oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)],
oppAxisRangeOpts = opts[Axes.id2name(axisOpts.anchor)];
var rangeSlider = d3.select(this);
var opts = axisOpts[constants.name];
var oppAxisOpts = fullLayout[axisIDs.id2name(axisOpts.anchor)];
var oppAxisRangeOpts = opts[axisIDs.id2name(axisOpts.anchor)];

// update range
// Expand slider range to the axis range
Expand All@@ -97,19 +102,9 @@ module.exports = function(gd) {
var domain = axisOpts.domain;
var tickHeight = (axisOpts._boundingBox || {}).height || 0;

var oppBottom = Infinity;
var subplotData = Axes.getSubplots(gd, axisOpts);
for(var i = 0; i < subplotData.length; i++) {
var oppAxis = Axes.getFromId(gd, subplotData[i].substr(subplotData[i].indexOf('y')));
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}

opts._id = constants.name + axisOpts._id;
opts._clipId = opts._id + '-' + fullLayout._uid;
var oppBottom = opts._oppBottom;

opts._width = graphSize.w * (domain[1] - domain[0]);
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);

var x = Math.round(margin.l + (graphSize.w * domain[0]));

Expand DownExpand Up@@ -177,36 +172,9 @@ module.exports = function(gd) {
}
});
}

// update margins
Plots.autoMargin(gd, opts._id, {
x: domain[0],
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
});
});
};

function makeRangeSliderData(fullLayout) {
var axes = Axes.list({ _fullLayout: fullLayout }, 'x', true),
name = constants.name,
out = [];

if(fullLayout._has('gl2d')) return out;

for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(ax[name] && ax[name].visible) out.push(ax);
}

return out;
}

function setupDragElement(rangeSlider, gd, axisOpts, opts) {
var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(),
grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(),
Expand DownExpand Up@@ -393,11 +361,10 @@ function addClipPath(rangeSlider, gd, axisOpts, opts) {
}

function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var subplotData = Axes.getSubplots(gd, axisOpts),
calcData = gd.calcdata;
var calcData = gd.calcdata;

var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName)
.data(subplotData, Lib.identity);
.data(axisOpts._subplotsWith, Lib.identity);

rangePlots.enter().append('g')
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
Expand All@@ -413,7 +380,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var plotgroup = d3.select(this),
isMainPlot = (i === 0);

var oppAxisOpts = Axes.getFromId(gd, id, 'y'),
var oppAxisOpts = axisIDs.getFromId(gd, id, 'y'),
oppAxisName = oppAxisOpts._name,
oppAxisRangeOpts = opts[oppAxisName];

Expand DownExpand Up@@ -445,6 +412,11 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
var xa = mockFigure._fullLayout.xaxis;
var ya = mockFigure._fullLayout[oppAxisName];

xa.clearCalc();
xa.setScale();
ya.clearCalc();
ya.setScale();

var plotinfo = {
id: id,
plotgroup: plotgroup,
Expand Down
67 changes: 67 additions & 0 deletions src/components/rangeslider/helpers.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var axisIDs = require('../../plots/cartesian/axis_ids');
var constants = require('./constants');
var name = constants.name;

function isVisible(ax) {
var rangeSlider = ax && ax[name];
return rangeSlider && rangeSlider.visible;
}
exports.isVisible = isVisible;

exports.makeData = function(fullLayout) {
var axes = axisIDs.list({ _fullLayout: fullLayout }, 'x', true);
var margin = fullLayout.margin;
var rangeSliderData = [];

if(!fullLayout._has('gl2d')) {
for(var i = 0; i < axes.length; i++) {
var ax = axes[i];

if(isVisible(ax)) {
rangeSliderData.push(ax);

var opts = ax[name];
opts._id = name + ax._id;
opts._height = (fullLayout.height - margin.b - margin.t) * opts.thickness;
opts._offsetShift = Math.floor(opts.borderwidth / 2);
}
}
}

fullLayout._rangeSliderData = rangeSliderData;
};

exports.autoMarginOpts = function(gd, ax) {
var opts = ax[name];

var oppBottom = Infinity;
var counterAxes = ax._counterAxes;
for(var j = 0; j < counterAxes.length; j++) {
var counterId = counterAxes[j];
var oppAxis = axisIDs.getFromId(gd, counterId);
oppBottom = Math.min(oppBottom, oppAxis.domain[0]);
}
opts._oppBottom = oppBottom;

var tickHeight = (ax.side === 'bottom' && ax._boundingBox.height) || 0;

return {
x: 0,
y: oppBottom,
l: 0,
r: 0,
t: 0,
b: opts._height + gd._fullLayout.margin.b + tickHeight,
pad: constants.extraPad + opts._offsetShift * 2
};
};
6 changes: 5 additions & 1 deletion src/components/rangeslider/index.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@
var Lib = require('../../lib');
var attrs = require('./attributes');
var oppAxisAttrs = require('./oppaxis_attributes');
var helpers = require('./helpers');

module.exports = {
moduleType: 'component',
Expand All@@ -29,5 +30,8 @@ module.exports = {
layoutAttributes: require('./attributes'),
handleDefaults: require('./defaults'),
calcAutorange: require('./calc_autorange'),
draw: require('./draw')
draw: require('./draw'),
isVisible: helpers.isVisible,
makeData: helpers.makeData,
autoMarginOpts: helpers.autoMarginOpts
};
8 changes: 6 additions & 2 deletions src/plot_api/plot_api.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,8 +332,7 @@ exports.plot = function(gd, data, layout, config) {
return Lib.syncOrAsync([
Registry.getComponentMethod('shapes', 'calcAutorange'),
Registry.getComponentMethod('annotations', 'calcAutorange'),
doAutoRangeAndConstraints,
Registry.getComponentMethod('rangeslider', 'calcAutorange')
doAutoRangeAndConstraints
], gd);
}

Expand All@@ -345,6 +344,11 @@ exports.plot = function(gd, data, layout, config) {
// store initial ranges *after* enforcing constraints, otherwise
// we will never look like we're at the initial ranges
if(graphWasEmpty) Axes.saveRangeInitial(gd);

// this one is different from shapes/annotations calcAutorange
// the others incorporate those components into ax._extremes,
// this one actually sets the ranges in rangesliders.
Registry.getComponentMethod('rangeslider', 'calcAutorange')(gd);
}

// draw ticks, titles, and calculate axis scaling (._b, ._m)
Expand Down
56 changes: 4 additions & 52 deletions src/plot_api/subroutines.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,7 +55,7 @@ function lsInner(gd) {
var gs = fullLayout._size;
var pad = gs.p;
var axList = Axes.list(gd, '', true);
var i, subplot, plotinfo, xa, ya;
var i, subplot, plotinfo, ax, xa, ya;

fullLayout._paperdiv.style({
width: (gd._context.responsive && fullLayout.autosize && !gd._context._hasZeroWidth && !gd.layout.width) ? '100%' : fullLayout.width + 'px',
Expand DownExpand Up@@ -91,10 +91,7 @@ function lsInner(gd) {

// some preparation of axis position info
for(i = 0; i < axList.length; i++) {
var ax = axList[i];

// reset scale in case the margins have changed
ax.setScale();
ax = axList[i];

var counterAx = ax._anchorAxis;

Expand All@@ -113,11 +110,6 @@ function lsInner(gd) {
ax._mainMirrorPosition = (ax.mirror && counterAx) ?
getLinePosition(ax, counterAx,
alignmentConstants.OPPOSITE_SIDE[ax.side]) : null;

// Figure out which subplot to draw ticks, labels, & axis lines on
// do this as a separate loop so we already have all the
// _mainAxis and _anchorAxis links set
ax._mainSubplot = findMainSubplot(ax, fullLayout);

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

moved this into plots.linkSubplots, which is both a more obvious place for it and happens earlier (in supplyDefaults) so _mainSubplot is available sooner.

}

// figure out which backgrounds we need to draw,
Expand DownExpand Up@@ -358,48 +350,6 @@ function lsInner(gd) {
return gd._promises.length && Promise.all(gd._promises);
}

function findMainSubplot(ax, fullLayout) {
var subplotList = fullLayout._subplots;
var ids = subplotList.cartesian.concat(subplotList.gl2d || []);
var mockGd = {_fullLayout: fullLayout};

var isX = ax._id.charAt(0) === 'x';
var anchorAx = ax._mainAxis._anchorAxis;
var mainSubplotID = '';
var nextBestMainSubplotID = '';
var anchorID = '';

// First try the main ID with the anchor
if(anchorAx) {
anchorID = anchorAx._mainAxis._id;
mainSubplotID = isX ? (ax._id + anchorID) : (anchorID + ax._id);
}

// Then look for a subplot with the counteraxis overlaying the anchor
// If that fails just use the first subplot including this axis
if(!mainSubplotID || !fullLayout._plots[mainSubplotID]) {
mainSubplotID = '';

for(var j = 0; j < ids.length; j++) {
var id = ids[j];
var yIndex = id.indexOf('y');
var idPart = isX ? id.substr(0, yIndex) : id.substr(yIndex);
var counterPart = isX ? id.substr(yIndex) : id.substr(0, yIndex);

if(idPart === ax._id) {
if(!nextBestMainSubplotID) nextBestMainSubplotID = id;
var counterAx = Axes.getFromId(mockGd, counterPart);
if(anchorID && counterAx.overlaying === anchorID) {
mainSubplotID = id;
break;
}
}
}
}

return mainSubplotID || nextBestMainSubplotID;
}

function shouldShowLinesOrTicks(ax, subplot) {
return (ax.ticks || ax.showline) &&
(subplot === ax._mainSubplot || ax.mirror === 'all' || ax.mirror === 'allticks');
Expand DownExpand Up@@ -752,6 +702,8 @@ exports.doAutoRangeAndConstraints = function(gd) {
for(var i = 0; i < axList.length; i++) {
var ax = axList[i];
cleanAxisConstraints(gd, ax);
// in case margins changed, update scale
ax.setScale();
doAutoRange(gd, ax);
}

Expand Down
15 changes: 6 additions & 9 deletions src/plots/cartesian/autorange.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -237,10 +237,6 @@ function concatExtremes(gd, ax) {
}

function doAutoRange(gd, ax) {
if(!ax._length) ax.setScale();

var axIn;

if(ax.autorange) {
ax.range = getAutoRange(gd, ax);

Expand All@@ -250,7 +246,7 @@ function doAutoRange(gd, ax) {
// doAutoRange will get called on fullLayout,
// but we want to report its results back to layout

axIn = ax._input;
var axIn = ax._input;

// before we edit _input, store preGUI values
var edits = {};
Expand All@@ -262,15 +258,16 @@ function doAutoRange(gd, ax) {
axIn.autorange = ax.autorange;
}

if(ax._anchorAxis && ax._anchorAxis.rangeslider) {
var axeRangeOpts = ax._anchorAxis.rangeslider[ax._name];
var anchorAx = ax._anchorAxis;

if(anchorAx && anchorAx.rangeslider) {
var axeRangeOpts = anchorAx.rangeslider[ax._name];
if(axeRangeOpts) {
if(axeRangeOpts.rangemode === 'auto') {
axeRangeOpts.range = getAutoRange(gd, ax);
}
}
axIn = ax._anchorAxis._input;
axIn.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
anchorAx._input.rangeslider[ax._name] = Lib.extendFlat({}, axeRangeOpts);
}
}

Expand Down
Loading