Skip to content

Commit 84a5695

Browse files
committed
fix and test slider x positioning when they push margins
Also includes a generalization of `Plots.autoMargin` so an object can have extent in plot fraction, as opposed to just position in plot fraction and extent in pixels. We could use this to allow for example colorbars to be sized based on the actual margins, not the pre-margin-pushing plot size as they are now, see note at colorbar/draw:119-124
1 parent bd07df7 commit 84a5695

File tree

3 files changed

+72
-15
lines changed

3 files changed

+72
-15
lines changed

src/components/sliders/draw.js

+16-5
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,25 @@ function findDimensions(gd, sliderOpts) {
221221
dims.lx = Math.round(dims.lx);
222222
dims.ly = Math.round(dims.ly);
223223

224-
Plots.autoMargin(gd, constants.autoMarginIdRoot + sliderOpts._index, {
225-
x: sliderOpts.x,
224+
var marginOpts = {
226225
y: sliderOpts.y,
227-
l: dims.outerLength * FROM_TL[xanchor],
228-
r: dims.outerLength * FROM_BR[xanchor],
229226
b: dims.height * FROM_BR[yanchor],
230227
t: dims.height * FROM_TL[yanchor]
231-
});
228+
};
229+
230+
if(sliderOpts.lenmode === 'fraction') {
231+
marginOpts.l = 0;
232+
marginOpts.xl = sliderOpts.x - sliderOpts.len * FROM_TL[xanchor];
233+
marginOpts.r = 0;
234+
marginOpts.xr = sliderOpts.x + sliderOpts.len * FROM_BR[xanchor];
235+
}
236+
else {
237+
marginOpts.x = sliderOpts.x;
238+
marginOpts.l = dims.outerLength * FROM_TL[xanchor];
239+
marginOpts.r = dims.outerLength * FROM_BR[xanchor];
240+
}
241+
242+
Plots.autoMargin(gd, constants.autoMarginIdRoot + sliderOpts._index, marginOpts);
232243
}
233244

234245
function drawSlider(gd, sliderGroup, sliderOpts) {

src/plots/plots.js

+24-9
Original file line numberDiff line numberDiff line change
@@ -1603,11 +1603,21 @@ function setupAutoMargin(fullLayout) {
16031603
if(!fullLayout._pushmarginIds) fullLayout._pushmarginIds = {};
16041604
}
16051605

1606-
// called by components to see if we need to
1607-
// expand the margins to show them
1608-
// o is {x,l,r,y,t,b} where x and y are plot fractions,
1609-
// the rest are pixels in each direction
1610-
// or leave o out to delete this entry (like if it's hidden)
1606+
/**
1607+
* autoMargin: called by components that may need to expand the margins to
1608+
* be rendered on-plot.
1609+
*
1610+
* @param {DOM element} gd
1611+
* @param {string} id - an identifier unique (within this plot) to this object,
1612+
* so we can remove a previous margin expansion from the same object.
1613+
* @param {object} o - the margin requirements of this object, or omit to delete
1614+
* this entry (like if it's hidden). Keys are:
1615+
* x, y: plot fraction of the anchor point.
1616+
* xl, xr, yt, yb: if the object has an extent defined in plot fraction,
1617+
* you can specify both edges as plot fractions in each dimension
1618+
* l, r, t, b: the pixels to pad past the plot fraction x[l|r] and y[t|b]
1619+
* pad: extra pixels to add in all directions, default 12 (why?)
1620+
*/
16111621
plots.autoMargin = function(gd, id, o) {
16121622
var fullLayout = gd._fullLayout;
16131623

@@ -1629,11 +1639,16 @@ plots.autoMargin = function(gd, id, o) {
16291639
if(o.l + o.r > fullLayout.width * 0.5) o.l = o.r = 0;
16301640
if(o.b + o.t > fullLayout.height * 0.5) o.b = o.t = 0;
16311641

1642+
var xl = o.xl !== undefined ? o.xl : o.x;
1643+
var xr = o.xr !== undefined ? o.xr : o.x;
1644+
var yt = o.yt !== undefined ? o.yt : o.y;
1645+
var yb = o.yb !== undefined ? o.yb : o.y;
1646+
16321647
pushMargin[id] = {
1633-
l: {val: o.x, size: o.l + pad},
1634-
r: {val: o.x, size: o.r + pad},
1635-
b: {val: o.y, size: o.b + pad},
1636-
t: {val: o.y, size: o.t + pad}
1648+
l: {val: xl, size: o.l + pad},
1649+
r: {val: xr, size: o.r + pad},
1650+
b: {val: yb, size: o.b + pad},
1651+
t: {val: yt, size: o.t + pad}
16371652
};
16381653
pushMarginIds[id] = 1;
16391654
}

test/jasmine/tests/sliders_test.js

+32-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ describe('sliders interactions', function() {
312312
beforeEach(function(done) {
313313
gd = createGraphDiv();
314314

315-
mockCopy = Lib.extendDeep({}, mock);
315+
mockCopy = Lib.extendDeep({}, mock, {layout: {sliders: [{x: 0.25}, {}]}});
316316

317317
Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
318318
});
@@ -322,6 +322,37 @@ describe('sliders interactions', function() {
322322
destroyGraphDiv();
323323
});
324324

325+
it('positions sliders repeatably when they push margins', function(done) {
326+
function checkPositions(msg) {
327+
d3.select(gd).selectAll('.slider-group').each(function(d, i) {
328+
var sliderBB = this.getBoundingClientRect();
329+
var gdBB = gd.getBoundingClientRect();
330+
if(i === 0) {
331+
expect(sliderBB.left - gdBB.left)
332+
.toBeWithin(12, 3, 'left: ' + msg);
333+
}
334+
else {
335+
expect(gdBB.bottom - sliderBB.bottom)
336+
.toBeWithin(8, 3, 'bottom: ' + msg);
337+
}
338+
});
339+
}
340+
341+
checkPositions('initial');
342+
343+
Plotly.relayout(gd, {'sliders[0].x': 0.35, 'sliders[1].y': -0.3})
344+
.then(function() {
345+
checkPositions('increased left & bottom');
346+
347+
return Plotly.relayout(gd, {'sliders[0].x': 0.1, 'sliders[1].y': -0.1});
348+
})
349+
.then(function() {
350+
checkPositions('back to original');
351+
})
352+
.catch(failTest)
353+
.then(done);
354+
});
355+
325356
it('should draw only visible sliders', function(done) {
326357
expect(gd._fullLayout._pushmargin['slider-0']).toBeDefined();
327358
expect(gd._fullLayout._pushmargin['slider-1']).toBeDefined();

0 commit comments

Comments
 (0)