Skip to content

Commit 007dbd5

Browse files
committed
[poc] rangeselectors split pushMargin from draw
... fix range_selector baselines to new more precise positioning computations.
1 parent 66a4b90 commit 007dbd5

File tree

4 files changed

+125
-111
lines changed

4 files changed

+125
-111
lines changed

src/components/rangeselector/draw.js

+123-110
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ var FROM_BR = alignmentConstants.FROM_BR;
2626
var constants = require('./constants');
2727
var getUpdateObject = require('./get_update_object');
2828

29-
module.exports = function draw(gd) {
29+
function draw(gd) {
3030
var fullLayout = gd._fullLayout;
31+
var gs = fullLayout._size;
3132

3233
var selectors = fullLayout._infolayer.selectAll('.rangeselector')
3334
.data(makeSelectorData(gd), selectorKeyFunc);
@@ -42,58 +43,82 @@ module.exports = function draw(gd) {
4243
'pointer-events': 'all'
4344
});
4445

45-
selectors.each(function(d) {
46+
selectors.each(function(ax) {
4647
var selector = d3.select(this);
47-
var axisLayout = d;
48-
var selectorLayout = axisLayout.rangeselector;
48+
var opts = ax.rangeselector;
49+
var dims = opts._dims;
50+
var bw = opts.borderwidth;
51+
52+
var lx = Math.round(
53+
gs.l + gs.w * opts.x -
54+
dims.width * FROM_TL[Lib.getXanchor(opts)]
55+
);
56+
var ly = Math.round(
57+
gs.t + gs.h * (1 - opts.y) -
58+
dims.height * FROM_TL[Lib.getYanchor(opts)]
59+
);
60+
61+
selector.attr('transform', 'translate(' + lx + ',' + ly + ')');
4962

5063
var buttons = selector.selectAll('g.button')
51-
.data(Lib.filterVisible(selectorLayout.buttons));
64+
.data(Lib.filterVisible(opts.buttons));
5265

5366
buttons.enter().append('g')
5467
.classed('button', true);
5568

5669
buttons.exit().remove();
5770

58-
buttons.each(function(d) {
71+
var posX = 0;
72+
73+
buttons.each(function(d, i) {
5974
var button = d3.select(this);
60-
var update = getUpdateObject(axisLayout, d);
75+
var update = getUpdateObject(ax, d);
6176

62-
d._isActive = isActive(axisLayout, d, update);
77+
d._isActive = isActive(ax, d, update);
6378

64-
button.call(drawButtonRect, selectorLayout, d);
65-
button.call(drawButtonText, selectorLayout, d, gd);
79+
button.call(drawButtonRect, opts, d);
80+
button.call(drawButtonText, opts, d, gd);
81+
82+
button.attr('transform', 'translate(' + [bw + posX, bw] + ')');
83+
posX += dims.widths[i] + 5;
84+
85+
Drawing.setRect(button.select('.selector-rect'), 0, 0,
86+
dims.widths[i],
87+
dims.height
88+
);
89+
90+
svgTextUtils.positionText(button.select('.selector-text'),
91+
dims.widths[i] / 2,
92+
dims.height / 2 + dims.tyOffsets[i]
93+
);
6694

6795
button.on('click', function() {
6896
if(gd._dragged) return;
69-
7097
Registry.call('_guiRelayout', gd, update);
7198
});
7299

73100
button.on('mouseover', function() {
74101
d._isHovered = true;
75-
button.call(drawButtonRect, selectorLayout, d);
102+
button.call(drawButtonRect, opts, d);
76103
});
77104

78105
button.on('mouseout', function() {
79106
d._isHovered = false;
80-
button.call(drawButtonRect, selectorLayout, d);
107+
button.call(drawButtonRect, opts, d);
81108
});
82109
});
83-
84-
reposition(gd, buttons, selectorLayout, axisLayout._name, selector);
85110
});
86-
};
111+
}
87112

88113
function makeSelectorData(gd) {
89-
var axes = axisIds.list(gd, 'x', true);
114+
var axList = axisIds.list(gd, 'x', true);
90115
var data = [];
91116

92-
for(var i = 0; i < axes.length; i++) {
93-
var axis = axes[i];
117+
for(var i = 0; i < axList.length; i++) {
118+
var ax = axList[i];
94119

95-
if(axis.rangeselector && axis.rangeselector.visible) {
96-
data.push(axis);
120+
if(ax.rangeselector && ax.rangeselector.visible) {
121+
data.push(ax);
97122
}
98123
}
99124

@@ -117,7 +142,7 @@ function isActive(axisLayout, opts, update) {
117142
}
118143
}
119144

120-
function drawButtonRect(button, selectorLayout, d) {
145+
function drawButtonRect(button, opts, d) {
121146
var rect = Lib.ensureSingle(button, 'rect', 'selector-rect', function(s) {
122147
s.attr('shape-rendering', 'crispEdges');
123148
});
@@ -127,129 +152,117 @@ function drawButtonRect(button, selectorLayout, d) {
127152
'ry': constants.ry
128153
});
129154

130-
rect.call(Color.stroke, selectorLayout.bordercolor)
131-
.call(Color.fill, getFillColor(selectorLayout, d))
132-
.style('stroke-width', selectorLayout.borderwidth + 'px');
155+
rect.call(Color.stroke, opts.bordercolor)
156+
.call(Color.fill, getFillColor(opts, d))
157+
.style('stroke-width', opts.borderwidth + 'px');
133158
}
134159

135-
function getFillColor(selectorLayout, d) {
160+
function getFillColor(opts, d) {
136161
return (d._isActive || d._isHovered) ?
137-
selectorLayout.activecolor :
138-
selectorLayout.bgcolor;
162+
opts.activecolor :
163+
opts.bgcolor;
139164
}
140165

141-
function drawButtonText(button, selectorLayout, d, gd) {
166+
function drawButtonText(button, opts, d, gd) {
142167
function textLayout(s) {
143168
svgTextUtils.convertToTspans(s, gd);
144169
}
145170

171+
// TODO add MathJax support
172+
146173
var text = Lib.ensureSingle(button, 'text', 'selector-text', function(s) {
147174
s.classed('user-select-none', true)
148175
.attr('text-anchor', 'middle');
149176
});
150177

151-
text.call(Drawing.font, selectorLayout.font)
178+
text.call(Drawing.font, opts.font)
152179
.text(getLabel(d, gd._fullLayout._meta))
153180
.call(textLayout);
154181
}
155182

156-
function getLabel(opts, _meta) {
157-
if(opts.label) {
183+
function getLabel(d, _meta) {
184+
if(d.label) {
158185
return _meta ?
159-
Lib.templateString(opts.label, _meta) :
160-
opts.label;
186+
Lib.templateString(d.label, _meta) :
187+
d.label;
161188
}
162189

163-
if(opts.step === 'all') return 'all';
190+
if(d.step === 'all') return 'all';
164191

165-
return opts.count + opts.step.charAt(0);
192+
return d.count + d.step.charAt(0);
166193
}
167194

168-
function reposition(gd, buttons, opts, axName, selector) {
169-
var width = 0;
170-
var height = 0;
171-
172-
var borderWidth = opts.borderwidth;
173-
174-
buttons.each(function() {
195+
function findDimensions(gd, ax) {
196+
var opts = ax.rangeselector;
197+
var buttonData = Lib.filterVisible(opts.buttons);
198+
var nButtons = buttonData.length;
199+
200+
var dims = opts._dims = {
201+
// width of each button
202+
widths: new Array(nButtons),
203+
// y offset for multi-line button text
204+
tyOffsets: new Array(nButtons),
205+
// height of range selector
206+
height: 0,
207+
// (total) width of range selector
208+
width: 0
209+
};
210+
211+
var fakeButtons = Drawing.tester.selectAll('g.button')
212+
.data(Lib.filterVisible(opts.buttons));
213+
214+
fakeButtons.enter().append('g')
215+
.classed('g.button', true);
216+
217+
fakeButtons.each(function(d, i) {
175218
var button = d3.select(this);
219+
drawButtonText(button, opts, d, gd);
176220
var text = button.select('.selector-text');
177221

222+
var tLines = svgTextUtils.lineCount(text);
178223
var tHeight = opts.font.size * LINE_SPACING;
179-
var hEff = Math.max(tHeight * svgTextUtils.lineCount(text), 16) + 3;
180-
181-
height = Math.max(height, hEff);
182-
});
183-
184-
buttons.each(function() {
185-
var button = d3.select(this);
186-
var rect = button.select('.selector-rect');
187-
var text = button.select('.selector-text');
188-
189224
var tWidth = text.node() && Drawing.bBox(text.node()).width;
190-
var tHeight = opts.font.size * LINE_SPACING;
191-
var tLines = svgTextUtils.lineCount(text);
192-
193-
var wEff = Math.max(tWidth + 10, constants.minButtonWidth);
194225

195-
// TODO add MathJax support
226+
var hEff = Math.ceil(Math.max(tHeight * tLines, 16) + 3);
227+
var wEff = Math.ceil(Math.max(tWidth + 10, constants.minButtonWidth));
196228

197-
// TODO add buttongap attribute
229+
dims.widths[i] = wEff;
230+
dims.tyOffsets[i] = 3 - (tLines - 1) * tHeight / 2;
198231

199-
button.attr('transform', 'translate(' +
200-
(borderWidth + width) + ',' + borderWidth +
201-
')');
202-
203-
rect.attr({
204-
x: 0,
205-
y: 0,
206-
width: wEff,
207-
height: height
208-
});
209-
210-
svgTextUtils.positionText(text, wEff / 2,
211-
height / 2 - ((tLines - 1) * tHeight / 2) + 3);
212-
213-
width += wEff + 5;
232+
dims.width += wEff + 5;
233+
dims.height = Math.max(dims.height, hEff);
214234
});
215235

216-
var graphSize = gd._fullLayout._size;
217-
var lx = graphSize.l + graphSize.w * opts.x;
218-
var ly = graphSize.t + graphSize.h * (1 - opts.y);
219-
220-
var xanchor = 'left';
221-
if(Lib.isRightAnchor(opts)) {
222-
lx -= width;
223-
xanchor = 'right';
224-
}
225-
if(Lib.isCenterAnchor(opts)) {
226-
lx -= width / 2;
227-
xanchor = 'center';
228-
}
236+
fakeButtons.remove();
229237

230-
var yanchor = 'top';
231-
if(Lib.isBottomAnchor(opts)) {
232-
ly -= height;
233-
yanchor = 'bottom';
234-
}
235-
if(Lib.isMiddleAnchor(opts)) {
236-
ly -= height / 2;
237-
yanchor = 'middle';
238-
}
238+
dims.width = Math.ceil(dims.width);
239+
dims.height = Math.ceil(dims.height);
239240

240-
width = Math.ceil(width);
241-
height = Math.ceil(height);
242-
lx = Math.round(lx);
243-
ly = Math.round(ly);
244-
245-
Plots.autoMargin(gd, axName + '-range-selector', {
246-
x: opts.x,
247-
y: opts.y,
248-
l: width * FROM_TL[xanchor],
249-
r: width * FROM_BR[xanchor],
250-
b: height * FROM_BR[yanchor],
251-
t: height * FROM_TL[yanchor]
252-
});
241+
return dims;
242+
}
253243

254-
selector.attr('transform', 'translate(' + lx + ',' + ly + ')');
244+
function pushMargin(gd) {
245+
var selectorData = makeSelectorData(gd);
246+
247+
for(var i = 0; i < selectorData.length; i++) {
248+
var ax = selectorData[i];
249+
var opts = ax.rangeselector;
250+
var xanchor = Lib.getXanchor(opts);
251+
var yanchor = Lib.getYanchor(opts);
252+
var dims = findDimensions(gd, ax);
253+
254+
Plots.autoMargin(gd, ax._id + '-range-selector', {
255+
x: opts.x,
256+
y: opts.y,
257+
l: dims.width * FROM_TL[xanchor],
258+
r: dims.width * FROM_BR[xanchor],
259+
b: dims.height * FROM_BR[yanchor],
260+
t: dims.height * FROM_TL[yanchor]
261+
});
262+
}
255263
}
264+
265+
module.exports = {
266+
pushMargin: pushMargin,
267+
draw: draw
268+
};

src/components/rangeselector/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ module.exports = {
2121
layoutAttributes: require('./attributes'),
2222
handleDefaults: require('./defaults'),
2323

24-
draw: require('./draw')
24+
pushMargin: require('./draw').pushMargin,
25+
draw: require('./draw').draw
2526
};
-20 Bytes
Loading
-53 Bytes
Loading

0 commit comments

Comments
 (0)