Skip to content

Commit 387db82

Browse files
authored
Merge pull request #2681 from plotly/react-automargin
Automargin fixes
2 parents 8690ee7 + 230a782 commit 387db82

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1128
-791
lines changed

src/components/colorbar/connect.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright 2012-2018, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var Colorscale = require('../colorscale');
13+
var drawColorbar = require('./draw');
14+
15+
/**
16+
* connectColorbar: create a colorbar from a trace, using its module to
17+
* describe the connection.
18+
*
19+
* @param {DOM element} gd
20+
*
21+
* @param {Array} cd
22+
* calcdata entry for this trace. cd[0].trace is the trace itself, and the
23+
* colorbar object will be stashed in cd[0].t.cb
24+
*
25+
* @param {object|function} moduleOpts
26+
* may be a function(gd, cd) to override the standard handling below. If
27+
* an object, should have these keys:
28+
* @param {Optional(string)} moduleOpts.container
29+
* name of the container inside the trace where the colorbar and colorscale
30+
* attributes live (ie 'marker', 'line') - omit if they're at the trace root.
31+
* @param {string} moduleOpts.min
32+
* name of the attribute holding the value of the minimum color
33+
* @param {string} moduleOpts.max
34+
* name of the attribute holding the value of the maximum color
35+
* @param {Optional(string)} moduleOpts.vals
36+
* name of the attribute holding the (numeric) color data
37+
* used only if min/max fail. May be omitted if these are always
38+
* pre-calculated.
39+
*/
40+
module.exports = function connectColorbar(gd, cd, moduleOpts) {
41+
if(typeof moduleOpts === 'function') return moduleOpts(gd, cd);
42+
43+
var trace = cd[0].trace;
44+
var cbId = 'cb' + trace.uid;
45+
var containerName = moduleOpts.container;
46+
var container = containerName ? trace[containerName] : trace;
47+
48+
gd._fullLayout._infolayer.selectAll('.' + cbId).remove();
49+
if(!container || !container.showscale) return;
50+
51+
var zmin = container[moduleOpts.min];
52+
var zmax = container[moduleOpts.max];
53+
54+
var cb = cd[0].t.cb = drawColorbar(gd, cbId);
55+
var sclFunc = Colorscale.makeColorScaleFunc(
56+
Colorscale.extractScale(
57+
container.colorscale,
58+
zmin,
59+
zmax
60+
),
61+
{ noNumericCheck: true }
62+
);
63+
64+
cb.fillcolor(sclFunc)
65+
.filllevels({start: zmin, end: zmax, size: (zmax - zmin) / 254})
66+
.options(container.colorbar)();
67+
};

src/components/colorbar/draw.js

+41-19
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ var Drawing = require('../drawing');
2323
var Color = require('../color');
2424
var Titles = require('../titles');
2525
var svgTextUtils = require('../../lib/svg_text_utils');
26-
var LINE_SPACING = require('../../constants/alignment').LINE_SPACING;
26+
var alignmentConstants = require('../../constants/alignment');
27+
var LINE_SPACING = alignmentConstants.LINE_SPACING;
28+
var FROM_TL = alignmentConstants.FROM_TL;
29+
var FROM_BR = alignmentConstants.FROM_BR;
2730

2831
var handleAxisDefaults = require('../../plots/cartesian/axis_defaults');
2932
var handleAxisPositionDefaults = require('../../plots/cartesian/position_defaults');
@@ -122,13 +125,13 @@ module.exports = function draw(gd, id) {
122125
// when the colorbar itself is pushing the margins.
123126
// but then the fractional size is calculated based on the
124127
// actual graph size, so that the axes will size correctly.
125-
var originalPlotHeight = fullLayout.height - fullLayout.margin.t - fullLayout.margin.b,
126-
originalPlotWidth = fullLayout.width - fullLayout.margin.l - fullLayout.margin.r,
128+
var plotHeight = gs.h,
129+
plotWidth = gs.w,
127130
thickPx = Math.round(opts.thickness *
128-
(opts.thicknessmode === 'fraction' ? originalPlotWidth : 1)),
131+
(opts.thicknessmode === 'fraction' ? plotWidth : 1)),
129132
thickFrac = thickPx / gs.w,
130133
lenPx = Math.round(opts.len *
131-
(opts.lenmode === 'fraction' ? originalPlotHeight : 1)),
134+
(opts.lenmode === 'fraction' ? plotHeight : 1)),
132135
lenFrac = lenPx / gs.h,
133136
xpadFrac = opts.xpad / gs.w,
134137
yExtraPx = (opts.borderwidth + opts.outlinewidth) / 2,
@@ -447,12 +450,10 @@ module.exports = function draw(gd, id) {
447450
}
448451

449452
function drawTitle(titleClass, titleOpts) {
450-
var trace = getTrace(),
451-
propName;
452-
if(Registry.traceIs(trace, 'markerColorscale')) {
453-
propName = 'marker.colorbar.title';
454-
}
455-
else propName = 'colorbar.title';
453+
var trace = getTrace();
454+
var propName = 'colorbar.title';
455+
var containerName = trace._module.colorbar.container;
456+
if(containerName) propName = containerName + '.' + propName;
456457

457458
var dfltTitleOpts = {
458459
propContainer: cbAxisOut,
@@ -539,14 +540,35 @@ module.exports = function draw(gd, id) {
539540
'translate(' + (gs.l - xoffset) + ',' + gs.t + ')');
540541

541542
// auto margin adjustment
542-
Plots.autoMargin(gd, id, {
543-
x: opts.x,
544-
y: opts.y,
545-
l: outerwidth * ({right: 1, center: 0.5}[opts.xanchor] || 0),
546-
r: outerwidth * ({left: 1, center: 0.5}[opts.xanchor] || 0),
547-
t: outerheight * ({bottom: 1, middle: 0.5}[opts.yanchor] || 0),
548-
b: outerheight * ({top: 1, middle: 0.5}[opts.yanchor] || 0)
549-
});
543+
var marginOpts = {};
544+
var tFrac = FROM_TL[opts.yanchor];
545+
var bFrac = FROM_BR[opts.yanchor];
546+
if(opts.lenmode === 'pixels') {
547+
marginOpts.y = opts.y;
548+
marginOpts.t = outerheight * tFrac;
549+
marginOpts.b = outerheight * bFrac;
550+
}
551+
else {
552+
marginOpts.t = marginOpts.b = 0;
553+
marginOpts.yt = opts.y + opts.len * tFrac;
554+
marginOpts.yb = opts.y - opts.len * bFrac;
555+
}
556+
557+
var lFrac = FROM_TL[opts.xanchor];
558+
var rFrac = FROM_BR[opts.xanchor];
559+
if(opts.thicknessmode === 'pixels') {
560+
marginOpts.x = opts.x;
561+
marginOpts.l = outerwidth * lFrac;
562+
marginOpts.r = outerwidth * rFrac;
563+
}
564+
else {
565+
var extraThickness = outerwidth - thickPx;
566+
marginOpts.l = extraThickness * lFrac;
567+
marginOpts.r = extraThickness * rFrac;
568+
marginOpts.xl = opts.x - opts.thickness * lFrac;
569+
marginOpts.xr = opts.x + opts.thickness * rFrac;
570+
}
571+
Plots.autoMargin(gd, id, marginOpts);
550572
}
551573

552574
var cbDone = Lib.syncOrAsync([

src/components/colorbar/index.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111

1212

1313
exports.attributes = require('./attributes');
14-
1514
exports.supplyDefaults = require('./defaults');
16-
15+
exports.connect = require('./connect');
1716
exports.draw = require('./draw');
18-
1917
exports.hasColorbar = require('./has_colorbar');

src/components/rangeslider/draw.js

+2-21
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,9 @@ module.exports = function(gd) {
6161

6262
// remove exiting sliders and their corresponding clip paths
6363
rangeSliders.exit().each(function(axisOpts) {
64-
var rangeSlider = d3.select(this),
65-
opts = axisOpts[constants.name];
66-
67-
rangeSlider.remove();
64+
var opts = axisOpts[constants.name];
6865
fullLayout._topdefs.select('#' + opts._clipId).remove();
69-
});
70-
71-
// remove push margin object(s)
72-
if(rangeSliders.exit().size()) clearPushMargins(gd);
66+
}).remove();
7367

7468
// return early if no range slider is visible
7569
if(rangeSliderData.length === 0) return;
@@ -602,16 +596,3 @@ function drawGrabbers(rangeSlider, gd, axisOpts, opts) {
602596
});
603597
grabAreaMax.attr('height', opts._height);
604598
}
605-
606-
function clearPushMargins(gd) {
607-
var pushMargins = gd._fullLayout._pushmargin || {},
608-
keys = Object.keys(pushMargins);
609-
610-
for(var i = 0; i < keys.length; i++) {
611-
var k = keys[i];
612-
613-
if(k.indexOf(constants.name) !== -1) {
614-
Plots.autoMargin(gd, k);
615-
}
616-
}
617-
}

src/components/sliders/draw.js

+39-29
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,23 @@ module.exports = function draw(gd) {
3636
.classed(constants.containerClassName, true)
3737
.style('cursor', 'ew-resize');
3838

39-
sliders.exit().remove();
39+
function clearSlider(sliderOpts) {
40+
if(sliderOpts._commandObserver) {
41+
sliderOpts._commandObserver.remove();
42+
delete sliderOpts._commandObserver;
43+
}
44+
45+
// Most components don't need to explicitly remove autoMargin, because
46+
// marginPushers does this - but slider updates don't go through
47+
// a full replot so we need to explicitly remove it.
48+
Plots.autoMargin(gd, autoMarginId(sliderOpts));
49+
}
4050

41-
// If no more sliders, clear the margisn:
42-
if(sliders.exit().size()) clearPushMargins(gd);
51+
sliders.exit().each(function() {
52+
d3.select(this).selectAll('g.' + constants.groupClassName)
53+
.each(clearSlider);
54+
})
55+
.remove();
4356

4457
// Return early if no menus visible:
4558
if(sliderData.length === 0) return;
@@ -50,14 +63,9 @@ module.exports = function draw(gd) {
5063
sliderGroups.enter().append('g')
5164
.classed(constants.groupClassName, true);
5265

53-
sliderGroups.exit().each(function(sliderOpts) {
54-
d3.select(this).remove();
55-
56-
sliderOpts._commandObserver.remove();
57-
delete sliderOpts._commandObserver;
58-
59-
Plots.autoMargin(gd, constants.autoMarginIdRoot + sliderOpts._index);
60-
});
66+
sliderGroups.exit()
67+
.each(clearSlider)
68+
.remove();
6169

6270
// Find the dimensions of the sliders:
6371
for(var i = 0; i < sliderData.length; i++) {
@@ -92,6 +100,10 @@ module.exports = function draw(gd) {
92100
});
93101
};
94102

103+
function autoMarginId(sliderOpts) {
104+
return constants.autoMarginIdRoot + sliderOpts._index;
105+
}
106+
95107
// This really only just filters by visibility:
96108
function makeSliderData(fullLayout, gd) {
97109
var contOpts = fullLayout[constants.name],
@@ -221,14 +233,25 @@ function findDimensions(gd, sliderOpts) {
221233
dims.lx = Math.round(dims.lx);
222234
dims.ly = Math.round(dims.ly);
223235

224-
Plots.autoMargin(gd, constants.autoMarginIdRoot + sliderOpts._index, {
225-
x: sliderOpts.x,
236+
var marginOpts = {
226237
y: sliderOpts.y,
227-
l: dims.outerLength * FROM_TL[xanchor],
228-
r: dims.outerLength * FROM_BR[xanchor],
229238
b: dims.height * FROM_BR[yanchor],
230239
t: dims.height * FROM_TL[yanchor]
231-
});
240+
};
241+
242+
if(sliderOpts.lenmode === 'fraction') {
243+
marginOpts.l = 0;
244+
marginOpts.xl = sliderOpts.x - sliderOpts.len * FROM_TL[xanchor];
245+
marginOpts.r = 0;
246+
marginOpts.xr = sliderOpts.x + sliderOpts.len * FROM_BR[xanchor];
247+
}
248+
else {
249+
marginOpts.x = sliderOpts.x;
250+
marginOpts.l = dims.outerLength * FROM_TL[xanchor];
251+
marginOpts.r = dims.outerLength * FROM_BR[xanchor];
252+
}
253+
254+
Plots.autoMargin(gd, autoMarginId(sliderOpts), marginOpts);
232255
}
233256

234257
function drawSlider(gd, sliderGroup, sliderOpts) {
@@ -594,16 +617,3 @@ function drawRail(sliderGroup, sliderOpts) {
594617
(dims.inputAreaWidth - constants.railWidth) * 0.5 + dims.currentValueTotalHeight
595618
);
596619
}
597-
598-
function clearPushMargins(gd) {
599-
var pushMargins = gd._fullLayout._pushmargin || {},
600-
keys = Object.keys(pushMargins);
601-
602-
for(var i = 0; i < keys.length; i++) {
603-
var k = keys[i];
604-
605-
if(k.indexOf(constants.autoMarginIdRoot) !== -1) {
606-
Plots.autoMargin(gd, k);
607-
}
608-
}
609-
}

0 commit comments

Comments
 (0)