-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Range slider second iteration (part 2: on-par range plots !!!) #1017
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
by Cartesian.rangePlot which uses the same subplot layer creation and plot command as 'regular' cartesian subplots. - rm obsolete rangeslider/range_plot.js and rangeslider/helpers.js - add test for clipPath deletion
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,14 +12,18 @@ var d3 = require('d3'); | |
|
||
var Plotly = require('../../plotly'); | ||
var Plots = require('../../plots/plots'); | ||
var Axes = require('../../plots/cartesian/axes'); | ||
|
||
var Lib = require('../../lib'); | ||
var Drawing = require('../drawing'); | ||
var Color = require('../color'); | ||
|
||
var Cartesian = require('../../plots/cartesian'); | ||
var Axes = require('../../plots/cartesian/axes'); | ||
|
||
var dragElement = require('../dragelement'); | ||
var setCursor = require('../../lib/setcursor'); | ||
|
||
var constants = require('./constants'); | ||
var rangePlot = require('./range_plot'); | ||
|
||
|
||
module.exports = function(gd) { | ||
|
@@ -55,7 +59,14 @@ module.exports = function(gd) { | |
.classed(constants.containerClassName, true) | ||
.attr('pointer-events', 'all'); | ||
|
||
rangeSliders.exit().remove(); | ||
// remove exiting sliders and their corresponding clip paths | ||
rangeSliders.exit().each(function(axisOpts) { | ||
var rangeSlider = d3.select(this), | ||
opts = axisOpts[constants.name]; | ||
|
||
rangeSlider.remove(); | ||
fullLayout._topdefs.select('#' + opts._clipId).remove(); | ||
}); | ||
|
||
// remove push margin object(s) | ||
if(rangeSliders.exit().size()) clearPushMargins(gd); | ||
|
@@ -82,6 +93,8 @@ module.exports = function(gd) { | |
domain = axisOpts.domain; | ||
|
||
opts._id = constants.name + axisOpts._id; | ||
opts._clipId = opts._id + '-' + fullLayout._uid; | ||
|
||
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); | ||
|
@@ -95,6 +108,7 @@ module.exports = function(gd) { | |
|
||
rangeSlider | ||
.call(drawBg, gd, axisOpts, opts) | ||
.call(addClipPath, gd, axisOpts, opts) | ||
.call(drawRangePlot, gd, axisOpts, opts) | ||
.call(drawMasks, gd, axisOpts, opts) | ||
.call(drawSlideBox, gd, axisOpts, opts) | ||
|
@@ -279,17 +293,102 @@ function drawBg(rangeSlider, gd, axisOpts, opts) { | |
}); | ||
} | ||
|
||
function drawRangePlot(rangeSlider, gd, axisOpts, opts) { | ||
var rangePlots = rangePlot(gd, opts._width, opts._height); | ||
function addClipPath(rangeSlider, gd, axisOpts, opts) { | ||
var fullLayout = gd._fullLayout; | ||
|
||
var gRangePlot = rangeSlider.selectAll('g.' + constants.rangePlotClassName) | ||
var clipPath = fullLayout._topdefs.selectAll('#' + opts._clipId) | ||
.data([0]); | ||
|
||
gRangePlot.enter().append('g') | ||
.classed(constants.rangePlotClassName, true); | ||
clipPath.enter().append('clipPath') | ||
.attr('id', opts._clipId) | ||
.append('rect') | ||
.attr({ x: 0, y: 0 }); | ||
|
||
clipPath.select('rect').attr({ | ||
width: opts._width, | ||
height: opts._height | ||
}); | ||
} | ||
|
||
function drawRangePlot(rangeSlider, gd, axisOpts, opts) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, the algorithm is as follows:
|
||
var subplotData = Axes.getSubplots(gd, axisOpts), | ||
calcData = gd.calcdata; | ||
|
||
var rangePlots = rangeSlider.selectAll('g.' + constants.rangePlotClassName) | ||
.data(subplotData, Lib.identity); | ||
|
||
rangePlots.enter().append('g') | ||
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; }) | ||
.call(Drawing.setClipUrl, opts._clipId); | ||
|
||
rangePlots.order(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Nice. The order is important to manage (and easy to neglect) with all of these d3 joins. |
||
|
||
rangePlots.exit().remove(); | ||
|
||
var mainplotinfo; | ||
|
||
rangePlots.each(function(id, i) { | ||
var plotgroup = d3.select(this), | ||
isMainPlot = (i === 0); | ||
|
||
var oppAxisOpts = Axes.getFromId(gd, id, 'y'), | ||
oppAxisName = oppAxisOpts._name; | ||
|
||
var mockFigure = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. There's something I always like the usage of |
||
data: [], | ||
layout: { | ||
xaxis: { | ||
domain: [0, 1], | ||
range: opts.range.slice() | ||
}, | ||
width: opts._width, | ||
height: opts._height, | ||
margin: { t: 0, b: 0, l: 0, r: 0 } | ||
} | ||
}; | ||
|
||
mockFigure.layout[oppAxisName] = { | ||
domain: [0, 1], | ||
range: oppAxisOpts.range.slice() | ||
}; | ||
|
||
Plots.supplyDefaults(mockFigure); | ||
|
||
var xa = mockFigure._fullLayout.xaxis, | ||
ya = mockFigure._fullLayout[oppAxisName]; | ||
|
||
var plotinfo = { | ||
id: id, | ||
plotgroup: plotgroup, | ||
xaxis: xa, | ||
yaxis: ya | ||
}; | ||
|
||
if(isMainPlot) mainplotinfo = plotinfo; | ||
else { | ||
plotinfo.mainplot = 'xy'; | ||
plotinfo.mainplotinfo = mainplotinfo; | ||
} | ||
|
||
Cartesian.rangePlot(gd, plotinfo, filterRangePlotCalcData(calcData, id)); | ||
|
||
if(isMainPlot) plotinfo.bg.call(Color.fill, opts.bgcolor); | ||
}); | ||
} | ||
|
||
function filterRangePlotCalcData(calcData, subplotId) { | ||
var out = []; | ||
|
||
for(var i = 0; i < calcData.length; i++) { | ||
var calcTrace = calcData[i], | ||
trace = calcTrace[0].trace; | ||
|
||
if(trace.xaxis + trace.yaxis === subplotId) { | ||
out.push(calcTrace); | ||
} | ||
} | ||
|
||
gRangePlot.html(null); | ||
gRangePlot.node().appendChild(rangePlots); | ||
return out; | ||
} | ||
|
||
function drawMasks(rangeSlider, gd, axisOpts, opts) { | ||
|
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -206,6 +206,12 @@ exports.drawFramework = function(gd) { | |
}); | ||
}; | ||
|
||
exports.rangePlot = function(gd, plotinfo, cdSubplot) { | ||
makeSubplotLayer(plotinfo); | ||
plotOne(gd, plotinfo, cdSubplot); | ||
Plots.style(gd); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only tangentially relevant, but I'm not a huge fan of In other words, for most d3 things that animate, I had to copy the styling into the inner join loop along with positioning instead of just applying styles on a completely separate pass (but to make sure it's robust and since the cost is probably small, I didn't remove styling from It's fine as-is, just something to think about since the separate-pass styling approach wasn't fully compatible with what I needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I'm not a fan of As soon as we'll find a solution for removing this ugly block if(plotinfo.plot) {
plotinfo.plot.selectAll('g:not(.scatterlayer)').selectAll('g.trace').remove();
} in the main cartesian plot routine, we'll get rid of |
||
}; | ||
|
||
function makeSubplotData(gd) { | ||
var fullLayout = gd._fullLayout, | ||
subplots = Axes.getSubplots(gd); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you manage to factor out the
.data([0])
pattern? I suppose it would be a function with a name likevar clipPath = createOrAppend(fullLayout._topdefs, '#' + opts._clipId);
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet. I'll do that in a PR of its own. Hopefully this week.