Skip to content

Commit e6d8525

Browse files
committed
add number.prefix, gauge.axis.visible, reuse Color.(fill|stroke), 🔒 toSVG
1 parent 0b44789 commit e6d8525

11 files changed

+154
-118
lines changed

src/traces/indicator/attributes.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88

99
'use strict';
1010

11-
// var plotAttrs = require('../../plots/attributes');
12-
// var domainAttrs = require('../../plots/domain').attributes;
13-
1411
var extendFlat = require('../../lib/extend').extendFlat;
1512
var extendDeep = require('../../lib/extend').extendDeep;
1613
var overrideAll = require('../../plot_api/edit_types').overrideAll;
@@ -102,7 +99,13 @@ module.exports = {
10299
editType: 'calc',
103100
role: 'info',
104101
flags: ['number', 'delta', 'gauge'],
105-
dflt: 'number'
102+
dflt: 'number',
103+
description: [
104+
'Determines how the value is displayed on the graph.',
105+
'`number` displays the value numerically in text.',
106+
'`delta` displays the difference to a reference value in text.',
107+
'Finally, `gauge` displays the value graphically on an axis.',
108+
].join(' ')
106109
},
107110
value: {
108111
valType: 'number',
@@ -189,6 +192,15 @@ module.exports = {
189192
'Set the font used to display main number'
190193
].join(' ')
191194
}),
195+
prefix: {
196+
valType: 'string',
197+
dflt: '',
198+
role: 'info',
199+
editType: 'plot',
200+
description: [
201+
'Sets a prefix appearing before the number.'
202+
].join(' ')
203+
},
192204
suffix: {
193205
valType: 'string',
194206
dflt: '',
@@ -206,7 +218,8 @@ module.exports = {
206218
role: 'info',
207219
editType: 'calc',
208220
description: [
209-
'Sets the reference value to compute the delta.'
221+
'Sets the reference value to compute the delta.',
222+
'By default, it is set to the current value.'
210223
].join(' ')
211224
},
212225
position: {
@@ -327,6 +340,9 @@ module.exports = {
327340
description: 'Sets the width (in px) of the border enclosing the gauge.'
328341
},
329342
axis: overrideAll({
343+
visible: extendDeep({}, axesAttrs.visible, {
344+
dflt: true
345+
}),
330346
// tick and title properties named and function exactly as in axes
331347
tickmode: axesAttrs.tickmode,
332348
nticks: axesAttrs.nticks,

src/traces/indicator/calc.js

-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
function calc(gd, trace) {
1414
var cd = [];
1515

16-
// var singleValue = len === 1;
17-
// var lastReading = trace.values[len - 1];
18-
// var secondLastReading = singleValue ? lastReading : trace.values[len - 2];
1916
var lastReading = trace.value;
2017
var secondLastReading = trace.delta ? trace.delta.reference : trace._lastValue || trace.value;
2118
cd[0] = {

src/traces/indicator/defaults.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,18 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
3737
coerce('vmax', 1.5 * traceOut.value);
3838

3939
// Number attributes
40-
var auto = [];
40+
var auto = new Array(2);
4141
var bignumberFontSize;
4242
if(traceOut._hasNumber) {
4343
coerce('number.valueformat');
4444
coerce('number.font.color', layout.font.color);
4545
coerce('number.font.family', layout.font.family);
46-
coerce('number.font.size', 'auto');
47-
if(traceOut.number.font.size === 'auto') {
46+
coerce('number.font.size');
47+
if(!traceOut.number.font.size) {
4848
traceOut.number.font.size = cn.defaultNumberFontSize;
4949
auto[0] = true;
5050
}
51+
coerce('number.prefix');
5152
coerce('number.suffix');
5253
bignumberFontSize = traceOut.number.font.size;
5354
}
@@ -57,8 +58,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
5758
if(traceOut._hasDelta) {
5859
coerce('delta.font.color', layout.font.color);
5960
coerce('delta.font.family', layout.font.family);
60-
coerce('delta.font.size', 'auto');
61-
if(traceOut.delta.font.size === 'auto') {
61+
coerce('delta.font.size');
62+
if(!traceOut.delta.font.size) {
6263
traceOut.delta.font.size = (traceOut._hasNumber ? 0.5 : 1) * (bignumberFontSize || cn.defaultNumberFontSize);
6364
auto[1] = true;
6465
}
@@ -133,6 +134,7 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
133134
axisIn = {};
134135
if(gaugeIn) axisIn = gaugeIn.axis || {};
135136
axisOut = Template.newContainer(gaugeOut, 'axis');
137+
coerceGaugeAxis('visible');
136138
handleTickValueDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear');
137139

138140
var opts = {outerTicks: false, font: layout.font};

src/traces/indicator/plot.js

+42-65
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var handleAxisDefaults = require('../../plots/cartesian/axis_defaults');
2222
var handleAxisPositionDefaults = require('../../plots/cartesian/position_defaults');
2323
var axisLayoutAttrs = require('../../plots/cartesian/layout_attributes');
2424

25+
var Color = require('../../components/color');
2526
var anchor = {
2627
'left': 'start',
2728
'center': 'middle',
@@ -86,7 +87,7 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb
8687
if(!hasGauge) {
8788
numbersX = size.l + position[numbersAlign] * size.w;
8889
numbersScaler = function(el) {
89-
return fitTextInsideBox(el, 0.9 * size.w, 0.9 * size.h);
90+
return fitTextInsideBox(el, size.w, size.h);
9091
};
9192
} else {
9293
if(isAngular) {
@@ -142,10 +143,9 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb
142143
}
143144

144145
// Prepare angular gauge layers
145-
var data = cd.filter(function() {return isAngular;});
146-
var angularGauge = plotGroup.selectAll('g.angular').data(data);
146+
var angularGauge = plotGroup.selectAll('g.angular').data(isAngular ? cd : []);
147147
angularGauge.exit().remove();
148-
var angularaxisLayer = plotGroup.selectAll('g.angularaxis').data(data);
148+
var angularaxisLayer = plotGroup.selectAll('g.angularaxis').data(isAngular ? cd : []);
149149
angularaxisLayer.exit().remove();
150150

151151
var gaugeOpts = {
@@ -163,10 +163,9 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb
163163
if(isAngular) drawAngularGauge(gd, plotGroup, cd, gaugeOpts);
164164

165165
// Prepare bullet layers
166-
data = cd.filter(function() {return isBullet;});
167-
var bulletGauge = plotGroup.selectAll('g.bullet').data(data);
166+
var bulletGauge = plotGroup.selectAll('g.bullet').data(isBullet ? cd : []);
168167
bulletGauge.exit().remove();
169-
var bulletaxisLayer = plotGroup.selectAll('g.bulletaxis').data(data);
168+
var bulletaxisLayer = plotGroup.selectAll('g.bulletaxis').data(isBullet ? cd : []);
170169
bulletaxisLayer.exit().remove();
171170

172171
gaugeOpts = {
@@ -202,8 +201,12 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb
202201
if(hasGauge) {
203202
if(isAngular) {
204203
// position above axis ticks/labels
205-
var bBox = Drawing.bBox(angularaxisLayer.node());
206-
titleY = (bBox.top - titlePadding) - titlebBox.bottom;
204+
if(trace.gauge.axis.visible) {
205+
var bBox = Drawing.bBox(angularaxisLayer.node());
206+
titleY = (bBox.top - titlePadding) - titlebBox.bottom;
207+
} else {
208+
titleY = size.t + size.h / 2 - radius / 2 - titlebBox.bottom - titlePadding;
209+
}
207210
}
208211
if(isBullet) {
209212
// position outside domain
@@ -244,7 +247,7 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) {
244247
bulletaxis.enter().append('g')
245248
.classed('bulletaxis', true)
246249
.classed('crisp', true);
247-
bulletaxis.selectAll('g.' + 'xbulletaxis' + 'tick,path').remove();
250+
bulletaxis.selectAll('g.' + 'xbulletaxis' + 'tick,path,text').remove();
248251

249252
// Draw bullet
250253
var bulletHeight = size.h; // use all vertical domain
@@ -288,16 +291,16 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) {
288291

289292
// Draw bullet background, steps
290293
var boxes = [gaugeBg].concat(trace.gauge.steps);
291-
var targetBullet = bullet.selectAll('g.targetBullet').data(boxes);
292-
targetBullet.enter().append('g').classed('targetBullet', true).append('rect');
294+
var targetBullet = bullet.selectAll('g.target-bullet').data(boxes);
295+
targetBullet.enter().append('g').classed('target-bullet', true).append('rect');
293296
targetBullet.select('rect')
294297
.call(drawRect)
295298
.call(styleShape);
296299
targetBullet.exit().remove();
297300

298301
// Draw value bar with transitions
299-
var fgBullet = bullet.selectAll('g.fgBullet').data([trace.gauge.value]);
300-
fgBullet.enter().append('g').classed('fgBullet', true).append('rect');
302+
var fgBullet = bullet.selectAll('g.fg-bullet').data([trace.gauge.value]);
303+
fgBullet.enter().append('g').classed('fg-bullet', true).append('rect');
301304
fgBullet.select('rect')
302305
.attr('height', innerBulletHeight)
303306
.attr('y', (bulletHeight - innerBulletHeight) / 2)
@@ -324,12 +327,12 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) {
324327
.attr('x2', ax.c2p(trace.gauge.threshold.value))
325328
.attr('y1', (1 - trace.gauge.threshold.thickness) / 2 * bulletHeight)
326329
.attr('y2', (1 - (1 - trace.gauge.threshold.thickness) / 2) * bulletHeight)
327-
.style('stroke', trace.gauge.threshold.line.color)
330+
.call(Color.stroke, trace.gauge.threshold.line.color)
328331
.style('stroke-width', trace.gauge.threshold.line.width);
329332
threshold.exit().remove();
330333

331-
var bulletOutline = bullet.selectAll('g.bulletOutline').data([gaugeOutline]);
332-
bulletOutline.enter().append('g').classed('bulletOutline', true).append('rect');
334+
var bulletOutline = bullet.selectAll('g.bullet-outline').data([gaugeOutline]);
335+
bulletOutline.enter().append('g').classed('bullet-outline', true).append('rect');
333336
bulletOutline.select('rect')
334337
.call(drawRect)
335338
.call(styleShape);
@@ -388,12 +391,12 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
388391
angularaxisLayer.enter().append('g')
389392
.classed('angularaxis', true)
390393
.classed('crisp', true);
391-
angularaxisLayer.selectAll('g.' + 'angularaxis' + 'tick,path').remove();
394+
angularaxisLayer.selectAll('g.' + 'xangularaxis' + 'tick,path,text').remove();
392395

393396
ax = mockAxis(gd, opts);
394397
ax.type = 'linear';
395398
ax.range = [trace.vmin, trace.vmax];
396-
ax._id = 'x'; // or 'y', but I don't think this makes a difference here
399+
ax._id = 'xangularaxis'; // or 'y', but I don't think this makes a difference here
397400
ax.setScale();
398401

399402
// 't'ick to 'g'eometric radians is used all over the place here
@@ -426,26 +429,28 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
426429
return -0.5 * (1 + Math.sin(rad)) * h;
427430
};
428431
var _transFn = function(rad) {
429-
return strTranslate(gaugePosition[0] + radius * Math.cos(rad), gaugePosition[1] - radius * Math.sin(rad));
432+
return strTranslate(
433+
gaugePosition[0] + radius * Math.cos(rad),
434+
gaugePosition[1] - radius * Math.sin(rad)
435+
);
430436
};
431437
transFn = function(d) {
432438
return _transFn(t2g(d));
433439
};
434440
var transFn2 = function(d) {
435441
var rad = t2g(d);
436-
return _transFn(rad) + strRotate(-rad2deg(rad));
442+
return _transFn(rad) + 'rotate(' + -rad2deg(rad) + ')';
437443
};
438444
vals = Axes.calcTicks(ax);
439-
tickSign;
445+
tickSign = Axes.getTickSigns(ax)[2];
440446
if(ax.visible) {
441447
tickSign = ax.ticks === 'inside' ? -1 : 1;
442448
var pad = (ax.linewidth || 1) / 2;
443449
Axes.drawTicks(gd, ax, {
444450
vals: vals,
445451
layer: angularaxisLayer,
446452
path: 'M' + (tickSign * pad) + ',0h' + (tickSign * ax.ticklen),
447-
transFn: transFn2,
448-
crips: true
453+
transFn: transFn2
449454
});
450455
Axes.drawLabels(gd, ax, {
451456
vals: vals,
@@ -470,14 +475,14 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
470475
// Draw background + steps
471476
var arcs = [gaugeBg].concat(trace.gauge.steps);
472477
if(v) arcs.push(thresholdArc);
473-
var targetArc = angularGauge.selectAll('g.targetArc').data(arcs);
474-
targetArc.enter().append('g').classed('targetArc', true).append('path');
478+
var targetArc = angularGauge.selectAll('g.target-arc').data(arcs);
479+
targetArc.enter().append('g').classed('target-arc', true).append('path');
475480
targetArc.select('path').call(drawArc).call(styleShape);
476481
targetArc.exit().remove();
477482
// Draw foreground with transition
478483
var valueArcPath = arcPathGenerator(trace.gauge.value.thickness);
479-
var fgArc = angularGauge.selectAll('g.fgArc').data([trace.gauge.value]);
480-
fgArc.enter().append('g').classed('fgArc', true).append('path');
484+
var fgArc = angularGauge.selectAll('g.fg-arc').data([trace.gauge.value]);
485+
fgArc.enter().append('g').classed('fgarc', true).append('path');
481486
var fgArcPath = fgArc.select('path');
482487
if(hasTransition) {
483488
fgArcPath
@@ -493,8 +498,8 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
493498
}
494499
fgArcPath.call(styleShape);
495500
fgArc.exit().remove();
496-
var gaugeBorder = angularGauge.selectAll('g.gaugeOutline').data([gaugeOutline]);
497-
gaugeBorder.enter().append('g').classed('gaugeOutline', true).append('path');
501+
var gaugeBorder = angularGauge.selectAll('g.gauge-outline').data([gaugeOutline]);
502+
gaugeBorder.enter().append('g').classed('gauge-outline', true).append('path');
498503
gaugeBorder.select('path').call(drawArc).call(styleShape);
499504
gaugeBorder.exit().remove();
500505
}
@@ -564,7 +569,7 @@ function drawNumbers(gd, plotGroup, cd, opts) {
564569
var bignumberAx = mockAxis(gd, {tickformat: trace.number.valueformat});
565570
var fmt = function(v) { return Axes.tickText(bignumberAx, v).text;};
566571
var bignumberSuffix = trace.number.suffix;
567-
if(bignumberSuffix) bignumberSuffix = ' ' + bignumberSuffix;
572+
var bignumberPrefix = trace.number.prefix;
568573

569574
var number = numbers.select('tspan.number');
570575
number
@@ -583,11 +588,11 @@ function drawNumbers(gd, plotGroup, cd, opts) {
583588
var that = d3.select(this);
584589
var interpolator = d3.interpolateNumber(cd[0].lastY, cd[0].y);
585590
return function(t) {
586-
that.text(fmt(interpolator(t)) + bignumberSuffix);
591+
that.text(bignumberPrefix + fmt(interpolator(t)) + bignumberSuffix);
587592
};
588593
});
589594
} else {
590-
number.text(fmt(cd[0].y) + bignumberSuffix);
595+
number.text(bignumberPrefix + fmt(cd[0].y) + bignumberSuffix);
591596
}
592597
}
593598

@@ -610,7 +615,7 @@ function drawNumbers(gd, plotGroup, cd, opts) {
610615
var delta = numbers.select('tspan.delta');
611616
delta
612617
.call(Drawing.font, trace.delta.font)
613-
.style('fill', deltaFill)
618+
.each(function(d) { Color.fill(d3.select(this), deltaFill(d));})
614619
.attr('x', deltaX)
615620
.attr('dy', deltaDy);
616621

@@ -669,8 +674,8 @@ function drawNumbers(gd, plotGroup, cd, opts) {
669674
// Apply fill, stroke, stroke-width to SVG shape
670675
function styleShape(p) {
671676
p
672-
.style('fill', function(d) { return d.color;})
673-
.style('stroke', function(d) { return d.line.color;})
677+
.each(function(d) { Color.stroke(d3.select(this), d.line.color);})
678+
.each(function(d) { Color.fill(d3.select(this), d.color);})
674679
.style('stroke-width', function(d) { return d.line.width;});
675680
}
676681

@@ -690,6 +695,7 @@ function mockAxis(gd, opts, zrange) {
690695
var fullLayout = gd._fullLayout;
691696

692697
var axisIn = {
698+
visible: opts.visible,
693699
type: 'linear',
694700
ticks: 'outside',
695701
range: zrange,
@@ -743,10 +749,6 @@ function strTranslate(x, y) {
743749
return 'translate(' + x + ',' + y + ')';
744750
}
745751

746-
function strRotate(angle) {
747-
return 'rotate(' + angle + ')';
748-
}
749-
750752
function fitTextInsideBox(el, width, height) {
751753
// compute scaling ratio to have text fit within specified width and height
752754
var textBB = Drawing.bBox(el.node());
@@ -761,28 +763,3 @@ function fitTextInsideCircle(el, radius) {
761763
var ratio = radius / elRadius;
762764
return [ratio, textBB, radius];
763765
}
764-
765-
// Draw gauge's min and max in text
766-
// var minText = gauge.selectAll('text.min').data(cd);
767-
// minText.enter().append('text').classed('min', true);
768-
// minText
769-
// .call(Drawing.font, trace.number.font)
770-
// .style('font-size', gaugeFontSize)
771-
// .attr({
772-
// x: - (innerRadius + radius) / 2,
773-
// y: gaugeFontSize,
774-
// 'text-anchor': 'middle'
775-
// })
776-
// .text(fmt(trace.vmin));
777-
//
778-
// var maxText = gauge.selectAll('text.max').data(cd);
779-
// maxText.enter().append('text').classed('max', true);
780-
// maxText
781-
// .call(Drawing.font, trace.number.font)
782-
// .style('font-size', gaugeFontSize)
783-
// .attr({
784-
// x: (innerRadius + radius) / 2,
785-
// y: gaugeFontSize,
786-
// 'text-anchor': 'middle'
787-
// })
788-
// .text(fmt(trace.vmax));
4.28 KB
Loading
1.09 KB
Loading

0 commit comments

Comments
 (0)