diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index 61d6e9f50fe..7edd7e0da32 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -16,6 +16,7 @@ var Plots = require('../../plots/plots'); var Lib = require('../../lib'); var Drawing = require('../drawing'); var Color = require('../color'); +var Titles = require('../titles'); var Cartesian = require('../../plots/cartesian'); var Axes = require('../../plots/cartesian/axes'); @@ -76,8 +77,7 @@ module.exports = function(gd) { // for all present range sliders rangeSliders.each(function(axisOpts) { var rangeSlider = d3.select(this), - opts = axisOpts[constants.name], - oppAxisOpts = fullLayout[Axes.id2name(axisOpts.anchor)]; + opts = axisOpts[constants.name]; // update range // Expand slider range to the axis range @@ -96,11 +96,17 @@ module.exports = function(gd) { // update range slider dimensions - var margin = fullLayout.margin, - graphSize = fullLayout._size, - domain = axisOpts.domain, - oppDomain = oppAxisOpts.domain, - tickHeight = (axisOpts._boundingBox || {}).height || 0; + var margin = fullLayout.margin; + var graphSize = fullLayout._size; + 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; @@ -112,7 +118,7 @@ module.exports = function(gd) { var x = Math.round(margin.l + (graphSize.w * domain[0])); var y = Math.round( - margin.t + graphSize.h * (1 - oppDomain[0]) + + graphSize.t + graphSize.h * (1 - oppBottom) + tickHeight + opts._offsetShift + constants.extraPad ); @@ -151,18 +157,31 @@ module.exports = function(gd) { // update current range setPixelRange(rangeSlider, gd, axisOpts, opts); - // update margins + // title goes next to range slider instead of tick labels, so + // just take it over and draw it from here + if(axisOpts.side === 'bottom') { + Titles.draw(gd, axisOpts._id + 'title', { + propContainer: axisOpts, + propName: axisOpts._name + '.title', + placeholder: fullLayout._dfltTitle.x, + attributes: { + x: axisOpts._offset + axisOpts._length / 2, + y: y + opts._height + opts._offsetShift + 10 + 1.5 * axisOpts.titlefont.size, + 'text-anchor': 'middle' + } + }); + } + // update margins Plots.autoMargin(gd, opts._id, { x: domain[0], - y: oppDomain[0], + y: oppBottom, l: 0, r: 0, t: 0, b: opts._height + margin.b + tickHeight, pad: constants.extraPad + opts._offsetShift * 2 }); - }); }; diff --git a/src/components/titles/index.js b/src/components/titles/index.js index 8b66cbacaf3..b30bdc7f547 100644 --- a/src/components/titles/index.js +++ b/src/components/titles/index.js @@ -20,7 +20,9 @@ var Color = require('../color'); var svgTextUtils = require('../../lib/svg_text_utils'); var interactConstants = require('../../constants/interactions'); -var Titles = module.exports = {}; +module.exports = { + draw: draw +}; var numStripRE = / [XY][0-9]* /; @@ -54,7 +56,7 @@ var numStripRE = / [XY][0-9]* /; * * @return {selection} d3 selection of title container group */ -Titles.draw = function(gd, titleClass, options) { +function draw(gd, titleClass, options) { var cont = options.propContainer; var prop = options.propName; var placeholder = options.placeholder; @@ -255,4 +257,4 @@ Titles.draw = function(gd, titleClass, options) { el.classed('js-placeholder', isplaceholder); return group; -}; +} diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 0e3eb681ce2..5209eada538 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -2008,20 +2008,23 @@ axes.doTicks = function(gd, axid, skipTitle) { // now this only applies to regular cartesian axes; colorbars and // others ALWAYS call doTicks with skipTitle=true so they can // configure their own titles. - var ax = axisIds.getFromId(gd, axid), - avoidSelection = d3.select(gd).selectAll('g.' + axid + 'tick'), - avoid = { - selection: avoidSelection, - side: ax.side - }, - axLetter = axid.charAt(0), - gs = gd._fullLayout._size, - offsetBase = 1.5, - fontSize = ax.titlefont.size, - transform, - counterAxis, - x, - y; + var ax = axisIds.getFromId(gd, axid); + + // rangeslider takes over a bottom title so drop it here + if(ax.rangeslider && ax.rangeslider.visible && ax._boundingBox && ax.side === 'bottom') return; + + var avoidSelection = d3.select(gd).selectAll('g.' + axid + 'tick'); + var avoid = { + selection: avoidSelection, + side: ax.side + }; + var axLetter = axid.charAt(0); + var gs = gd._fullLayout._size; + var offsetBase = 1.5; + var fontSize = ax.titlefont.size; + + var transform, counterAxis, x, y; + if(avoidSelection.size()) { var translation = Drawing.getTranslate(avoidSelection.node().parentNode); avoid.offsetLeft = translation.x; @@ -2037,6 +2040,7 @@ axes.doTicks = function(gd, axid, skipTitle) { axisIds.getFromId(gd, ax.anchor); x = ax._offset + ax._length / 2; + if(ax.side === 'top') { y = -titleStandoff - fontSize * (ax.showticklabels ? 1 : 0); } @@ -2046,11 +2050,6 @@ axes.doTicks = function(gd, axid, skipTitle) { } y += counterAxis._offset; - if(ax.rangeslider && ax.rangeslider.visible && ax._boundingBox) { - y += (fullLayout.height - fullLayout.margin.b - fullLayout.margin.t) * - ax.rangeslider.thickness + ax._boundingBox.height; - } - if(!avoid.side) avoid.side = 'bottom'; } else { diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js index e4c0cfbdff3..2d312a50ca3 100644 --- a/src/plots/cartesian/index.js +++ b/src/plots/cartesian/index.js @@ -88,11 +88,9 @@ exports.finalizeSubplots = function(layoutIn, layoutOut) { // so if there are NO subplots at all, make one from the first // x & y axes in the input layout if(!spAll.length) { - var keys = Object.keys(layoutIn); xi = ''; yi = ''; - for(i = 0; i < keys.length; i++) { - var ki = keys[i]; + for(var ki in layoutIn) { if(constants.attrRegex.test(ki)) { var axLetter = ki.charAt(0); if(axLetter === 'x') { diff --git a/src/plots/plots.js b/src/plots/plots.js index 745e4e29bcf..d567aa09371 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -701,11 +701,6 @@ plots.linkSubplots = function(newFullData, newFullLayout, oldFullData, oldFullLa var i, j, id, ax; - // sort subplot lists - for(var subplotType in newSubplotList) { - newSubplotList[subplotType].sort(Lib.subplotSort); - } - for(i = 0; i < ids.length; i++) { id = ids[i]; var oldSubplot = oldSubplots[id]; @@ -1390,6 +1385,11 @@ plots.supplyLayoutModuleDefaults = function(layoutIn, layoutOut, fullData, trans Cartesian.finalizeSubplots(layoutIn, layoutOut); } + // sort subplot lists + for(var subplotType in layoutOut._subplots) { + layoutOut._subplots[subplotType].sort(Lib.subplotSort); + } + // base plot module layout defaults for(i = 0; i < basePlotModules.length; i++) { _module = basePlotModules[i]; diff --git a/test/image/baselines/candlestick_rangeslider_thai.png b/test/image/baselines/candlestick_rangeslider_thai.png index 9e79776b5bf..76894bfb9de 100644 Binary files a/test/image/baselines/candlestick_rangeslider_thai.png and b/test/image/baselines/candlestick_rangeslider_thai.png differ diff --git a/test/image/baselines/range_slider.png b/test/image/baselines/range_slider.png index 17fe0ca48cd..29e44cb026a 100644 Binary files a/test/image/baselines/range_slider.png and b/test/image/baselines/range_slider.png differ diff --git a/test/image/baselines/range_slider_axes_double.png b/test/image/baselines/range_slider_axes_double.png index 5b604a29766..e229362757a 100644 Binary files a/test/image/baselines/range_slider_axes_double.png and b/test/image/baselines/range_slider_axes_double.png differ diff --git a/test/image/baselines/range_slider_axes_stacked.png b/test/image/baselines/range_slider_axes_stacked.png new file mode 100644 index 00000000000..fcf3de9e668 Binary files /dev/null and b/test/image/baselines/range_slider_axes_stacked.png differ diff --git a/test/image/baselines/range_slider_box.png b/test/image/baselines/range_slider_box.png index e1024d7357a..ab16195a328 100644 Binary files a/test/image/baselines/range_slider_box.png and b/test/image/baselines/range_slider_box.png differ diff --git a/test/image/baselines/range_slider_initial_expanded.png b/test/image/baselines/range_slider_initial_expanded.png index b2e6ad5d813..cd4639e40b9 100644 Binary files a/test/image/baselines/range_slider_initial_expanded.png and b/test/image/baselines/range_slider_initial_expanded.png differ diff --git a/test/image/baselines/range_slider_initial_valid.png b/test/image/baselines/range_slider_initial_valid.png index 28f419638cf..ae79d9e748a 100644 Binary files a/test/image/baselines/range_slider_initial_valid.png and b/test/image/baselines/range_slider_initial_valid.png differ diff --git a/test/image/baselines/range_slider_multiple.png b/test/image/baselines/range_slider_multiple.png index 23af1953709..5761b38161d 100644 Binary files a/test/image/baselines/range_slider_multiple.png and b/test/image/baselines/range_slider_multiple.png differ diff --git a/test/image/mocks/range_slider_axes_stacked.json b/test/image/mocks/range_slider_axes_stacked.json new file mode 100644 index 00000000000..d7a3c97d0ed --- /dev/null +++ b/test/image/mocks/range_slider_axes_stacked.json @@ -0,0 +1,11 @@ +{ + "data": [ + {"y": [1, 2, 3], "yaxis": "y2"}, + {"fill": "tozeroy", "y": [30, 20, 10]} + ], + "layout": { + "xaxis": {"rangeslider": {}, "title": "x"}, + "yaxis": {"title": "y", "domain": [0, 0.25]}, + "yaxis2": {"title": "y2", "domain": [ 0.3, 1]} + } +} diff --git a/test/image/mocks/range_slider_multiple.json b/test/image/mocks/range_slider_multiple.json index 09f7490bd17..ae19deee98e 100644 --- a/test/image/mocks/range_slider_multiple.json +++ b/test/image/mocks/range_slider_multiple.json @@ -20,14 +20,17 @@ "xaxis": { "domain": [ 0, 0.45 ], "range": [ 1, 2 ], - "rangeslider": {} + "rangeslider": {}, + "title": "X", + "side": "top" }, "xaxis2": { "anchor": "y2", "domain": [ 0.55, 1 ], "rangeslider": { "range": [ -2, 4 ] - } + }, + "title": "X2" }, "yaxis": { "domain": [ 0.3, 0.8 ],