Skip to content

Commit 3523464

Browse files
authored
Merge pull request #3732 from plotly/legend-itemsizing
Add legend `itemsizing`
2 parents 1dcee93 + c6301a1 commit 3523464

File tree

11 files changed

+260
-45
lines changed

11 files changed

+260
-45
lines changed

Diff for: src/components/drawing/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ drawing.crispRound = function(gd, lineWidth, dflt) {
136136
drawing.singleLineStyle = function(d, s, lw, lc, ld) {
137137
s.style('fill', 'none');
138138
var line = (((d || [])[0] || {}).trace || {}).line || {};
139-
var lw1 = lw || line.width||0;
139+
var lw1 = lw || line.width || 0;
140140
var dash = ld || line.dash || '';
141141

142142
Color.stroke(s, lc || line.color);
@@ -147,7 +147,7 @@ drawing.lineGroupStyle = function(s, lw, lc, ld) {
147147
s.style('fill', 'none')
148148
.each(function(d) {
149149
var line = (((d || [])[0] || {}).trace || {}).line || {};
150-
var lw1 = lw || line.width||0;
150+
var lw1 = lw || line.width || 0;
151151
var dash = ld || line.dash || '';
152152

153153
d3.select(this)

Diff for: src/components/legend/attributes.js

+12
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ module.exports = {
7878
'Sets the amount of vertical space (in px) between legend groups.'
7979
].join(' ')
8080
},
81+
itemsizing: {
82+
valType: 'enumerated',
83+
values: ['trace', 'constant'],
84+
dflt: 'trace',
85+
role: 'style',
86+
editType: 'legend',
87+
description: [
88+
'Determines if the legend items symbols scale with their corresponding *trace* attributes',
89+
'or remain *constant* independent of the symbol size on the graph.'
90+
].join(' ')
91+
},
92+
8193
x: {
8294
valType: 'number',
8395
min: -2,

Diff for: src/components/legend/defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
103103
coerce('traceorder', defaultOrder);
104104
if(helpers.isGrouped(layoutOut.legend)) coerce('tracegroupgap');
105105

106+
coerce('itemsizing');
107+
106108
coerce('x', defaultX);
107109
coerce('xanchor', defaultXAnchor);
108110
coerce('y', defaultY);

Diff for: src/components/legend/style.js

+69-38
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,38 @@ var Color = require('../color');
1717

1818
var subTypes = require('../../traces/scatter/subtypes');
1919
var stylePie = require('../../traces/pie/style_one');
20+
var pieCastOption = require('../../traces/pie/helpers').castOption;
21+
22+
var CST_MARKER_SIZE = 12;
23+
var CST_LINE_WIDTH = 5;
24+
var CST_MARKER_LINE_WIDTH = 2;
25+
var MAX_LINE_WIDTH = 10;
26+
var MAX_MARKER_LINE_WIDTH = 5;
2027

2128
module.exports = function style(s, gd) {
29+
var fullLayout = gd._fullLayout;
30+
var legend = fullLayout.legend;
31+
var constantItemSizing = legend.itemsizing === 'constant';
32+
33+
function boundLineWidth(mlw, cont, max, cst) {
34+
var v;
35+
if(mlw + 1) {
36+
v = mlw;
37+
} else if(cont && cont.width > 0) {
38+
v = cont.width;
39+
} else {
40+
return 0;
41+
}
42+
return constantItemSizing ? cst : Math.min(v, max);
43+
}
44+
2245
s.each(function(d) {
2346
var traceGroup = d3.select(this);
2447

2548
var layers = Lib.ensureSingle(traceGroup, 'g', 'layers');
2649
layers.style('opacity', d[0].trace.opacity);
2750

28-
// Marker vertical alignment
29-
var valign = gd._fullLayout.legend.valign;
51+
var valign = legend.valign;
3052
var lineHeight = d[0].lineHeight;
3153
var height = d[0].height;
3254

@@ -71,28 +93,27 @@ module.exports = function style(s, gd) {
7193
.each(styleOHLC);
7294

7395
function styleLines(d) {
74-
var trace = d[0].trace;
96+
var d0 = d[0];
97+
var trace = d0.trace;
7598
var showFill = trace.visible && trace.fill && trace.fill !== 'none';
7699
var showLine = subTypes.hasLines(trace);
77100
var contours = trace.contours;
78101
var showGradientLine = false;
79102
var showGradientFill = false;
103+
var dMod, tMod;
80104

81105
if(contours) {
82106
var coloring = contours.coloring;
83107

84108
if(coloring === 'lines') {
85109
showGradientLine = true;
86-
}
87-
else {
88-
showLine = coloring === 'none' || coloring === 'heatmap' ||
89-
contours.showlines;
110+
} else {
111+
showLine = coloring === 'none' || coloring === 'heatmap' || contours.showlines;
90112
}
91113

92114
if(contours.type === 'constraint') {
93115
showFill = contours._operation !== '=';
94-
}
95-
else if(coloring === 'fill' || coloring === 'heatmap') {
116+
} else if(coloring === 'fill' || coloring === 'heatmap') {
96117
showGradientFill = true;
97118
}
98119
}
@@ -116,8 +137,14 @@ module.exports = function style(s, gd) {
116137
fill.attr('d', pathStart + 'h30v6h-30z')
117138
.call(showFill ? Drawing.fillGroupStyle : fillGradient);
118139

140+
if(showLine || showGradientLine) {
141+
var lw = boundLineWidth(undefined, trace.line, MAX_LINE_WIDTH, CST_LINE_WIDTH);
142+
tMod = Lib.minExtend(trace, {line: {width: lw}});
143+
dMod = [Lib.minExtend(d0, {trace: tMod})];
144+
}
145+
119146
var line = this3.select('.legendlines').selectAll('path')
120-
.data(showLine || showGradientLine ? [d] : []);
147+
.data(showLine || showGradientLine ? [dMod] : []);
121148
line.enter().append('path').classed('js-line', true);
122149
line.exit().remove();
123150

@@ -159,12 +186,16 @@ module.exports = function style(s, gd) {
159186
// 'scatter3d' don't use gd.calcdata,
160187
// use d0.trace to infer arrayOk attributes
161188

162-
function boundVal(attrIn, arrayToValFn, bounds) {
189+
function boundVal(attrIn, arrayToValFn, bounds, cst) {
163190
var valIn = Lib.nestedProperty(trace, attrIn).get();
164191
var valToBound = (Lib.isArrayOrTypedArray(valIn) && arrayToValFn) ?
165192
arrayToValFn(valIn) :
166193
valIn;
167194

195+
if(constantItemSizing && valToBound && cst !== undefined) {
196+
valToBound = cst;
197+
}
198+
168199
if(bounds) {
169200
if(valToBound < bounds[0]) return bounds[0];
170201
else if(valToBound > bounds[1]) return bounds[1];
@@ -184,21 +215,21 @@ module.exports = function style(s, gd) {
184215
dEdit.mx = boundVal('marker.symbol', pickFirst);
185216
dEdit.mo = boundVal('marker.opacity', Lib.mean, [0.2, 1]);
186217
dEdit.mlc = boundVal('marker.line.color', pickFirst);
187-
dEdit.mlw = boundVal('marker.line.width', Lib.mean, [0, 5]);
218+
dEdit.mlw = boundVal('marker.line.width', Lib.mean, [0, 5], CST_MARKER_LINE_WIDTH);
188219
tEdit.marker = {
189220
sizeref: 1,
190221
sizemin: 1,
191222
sizemode: 'diameter'
192223
};
193224

194-
var ms = boundVal('marker.size', Lib.mean, [2, 16]);
225+
var ms = boundVal('marker.size', Lib.mean, [2, 16], CST_MARKER_SIZE);
195226
dEdit.ms = ms;
196227
tEdit.marker.size = ms;
197228
}
198229

199230
if(showLines) {
200231
tEdit.line = {
201-
width: boundVal('line.width', pickFirst, [0, 10])
232+
width: boundVal('line.width', pickFirst, [0, 10], CST_LINE_WIDTH)
202233
};
203234
}
204235

@@ -262,12 +293,13 @@ module.exports = function style(s, gd) {
262293
pts.each(function(dd) {
263294
var pt = d3.select(this);
264295
var cont = trace[dd[0]].marker;
296+
var lw = boundLineWidth(undefined, cont.line, MAX_MARKER_LINE_WIDTH, CST_MARKER_LINE_WIDTH);
265297

266298
pt.attr('d', dd[1])
267-
.style('stroke-width', cont.line.width + 'px')
299+
.style('stroke-width', lw + 'px')
268300
.call(Color.fill, cont.color);
269301

270-
if(cont.line.width) {
302+
if(lw) {
271303
pt.call(Color.stroke, cont.line.color);
272304
}
273305
});
@@ -289,14 +321,12 @@ module.exports = function style(s, gd) {
289321
barpath.each(function(d) {
290322
var p = d3.select(this);
291323
var d0 = d[0];
292-
var w = (d0.mlw + 1 || markerLine.width + 1) - 1;
324+
var w = boundLineWidth(d0.mlw, marker.line, MAX_MARKER_LINE_WIDTH, CST_MARKER_LINE_WIDTH);
293325

294326
p.style('stroke-width', w + 'px')
295327
.call(Color.fill, d0.mc || marker.color);
296328

297-
if(w) {
298-
p.call(Color.stroke, d0.mlc || markerLine.color);
299-
}
329+
if(w) Color.stroke(p, d0.mlc || markerLine.color);
300330
});
301331
}
302332

@@ -313,15 +343,13 @@ module.exports = function style(s, gd) {
313343
pts.exit().remove();
314344

315345
pts.each(function() {
316-
var w = trace.line.width;
317346
var p = d3.select(this);
347+
var w = boundLineWidth(undefined, trace.line, MAX_MARKER_LINE_WIDTH, CST_MARKER_LINE_WIDTH);
318348

319349
p.style('stroke-width', w + 'px')
320350
.call(Color.fill, trace.fillcolor);
321351

322-
if(w) {
323-
Color.stroke(p, trace.line.color);
324-
}
352+
if(w) Color.stroke(p, trace.line.color);
325353
});
326354
}
327355

@@ -341,16 +369,14 @@ module.exports = function style(s, gd) {
341369
pts.exit().remove();
342370

343371
pts.each(function(_, i) {
344-
var container = trace[i ? 'increasing' : 'decreasing'];
345-
var w = container.line.width;
346372
var p = d3.select(this);
373+
var cont = trace[i ? 'increasing' : 'decreasing'];
374+
var w = boundLineWidth(undefined, cont.line, MAX_MARKER_LINE_WIDTH, CST_MARKER_LINE_WIDTH);
347375

348376
p.style('stroke-width', w + 'px')
349-
.call(Color.fill, container.fillcolor);
377+
.call(Color.fill, cont.fillcolor);
350378

351-
if(w) {
352-
Color.stroke(p, container.line.color);
353-
}
379+
if(w) Color.stroke(p, cont.line.color);
354380
});
355381
}
356382

@@ -370,21 +396,20 @@ module.exports = function style(s, gd) {
370396
pts.exit().remove();
371397

372398
pts.each(function(_, i) {
373-
var container = trace[i ? 'increasing' : 'decreasing'];
374-
var w = container.line.width;
375399
var p = d3.select(this);
400+
var cont = trace[i ? 'increasing' : 'decreasing'];
401+
var w = boundLineWidth(undefined, cont.line, MAX_MARKER_LINE_WIDTH, CST_MARKER_LINE_WIDTH);
376402

377403
p.style('fill', 'none')
378-
.call(Drawing.dashLine, container.line.dash, w);
404+
.call(Drawing.dashLine, cont.line.dash, w);
379405

380-
if(w) {
381-
Color.stroke(p, container.line.color);
382-
}
406+
if(w) Color.stroke(p, cont.line.color);
383407
});
384408
}
385409

386410
function stylePies(d) {
387-
var trace = d[0].trace;
411+
var d0 = d[0];
412+
var trace = d0.trace;
388413

389414
var pts = d3.select(this).select('g.legendpoints')
390415
.selectAll('path.legendpie')
@@ -394,6 +419,12 @@ module.exports = function style(s, gd) {
394419
.attr('transform', 'translate(20,0)');
395420
pts.exit().remove();
396421

397-
if(pts.size()) pts.call(stylePie, d[0], trace);
422+
if(pts.size()) {
423+
var cont = (trace.marker || {}).line;
424+
var lw = boundLineWidth(pieCastOption(cont.width, d0.pts), cont, MAX_MARKER_LINE_WIDTH, CST_MARKER_LINE_WIDTH);
425+
var tMod = Lib.minExtend(trace, {marker: {line: {width: lw}}});
426+
var d0Mod = Lib.minExtend(d0, {trace: tMod});
427+
stylePie(pts, d0Mod, tMod);
428+
}
398429
}
399430
};

Diff for: src/traces/pie/style_one.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = function styleOne(s, pt, trace) {
1616
var lineColor = castOption(line.color, pt.pts) || Color.defaultLine;
1717
var lineWidth = castOption(line.width, pt.pts) || 0;
1818

19-
s.style({'stroke-width': lineWidth})
19+
s.style('stroke-width', lineWidth)
2020
.call(Color.fill, pt.color)
2121
.call(Color.stroke, lineColor);
2222
};

Diff for: test/image/baselines/gl3d_line_rectangle_render.png

-109 Bytes
Loading

Diff for: test/image/baselines/gl3d_log-axis-big.png

-29 Bytes
Loading

Diff for: test/image/baselines/gl3d_log-axis.png

-25 Bytes
Loading

Diff for: test/image/baselines/legend-constant-itemsizing.png

28.5 KB
Loading

0 commit comments

Comments
 (0)