Skip to content

trace type indicator #3978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jun 28, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions src/traces/indicator/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

'use strict';

// var plotAttrs = require('../../plots/attributes');
// var domainAttrs = require('../../plots/domain').attributes;

var extendFlat = require('../../lib/extend').extendFlat;
var extendDeep = require('../../lib/extend').extendDeep;
var overrideAll = require('../../plot_api/edit_types').overrideAll;
Expand Down Expand Up @@ -102,7 +99,13 @@ module.exports = {
editType: 'calc',
role: 'info',
flags: ['number', 'delta', 'gauge'],
dflt: 'number'
dflt: 'number',
description: [
'Determines how the value is displayed on the graph.',
'`number` displays the value numerically in text.',
'`delta` displays the difference to a reference value in text.',
'Finally, `gauge` displays the value graphically on an axis.',
].join(' ')
},
value: {
valType: 'number',
Expand Down Expand Up @@ -189,6 +192,15 @@ module.exports = {
'Set the font used to display main number'
].join(' ')
}),
prefix: {
valType: 'string',
dflt: '',
role: 'info',
editType: 'plot',
description: [
'Sets a prefix appearing before the number.'
].join(' ')
},
suffix: {
valType: 'string',
dflt: '',
Expand All @@ -206,7 +218,8 @@ module.exports = {
role: 'info',
editType: 'calc',
description: [
'Sets the reference value to compute the delta.'
'Sets the reference value to compute the delta.',
'By default, it is set to the current value.'
].join(' ')
},
position: {
Expand Down Expand Up @@ -327,6 +340,9 @@ module.exports = {
description: 'Sets the width (in px) of the border enclosing the gauge.'
},
axis: overrideAll({
visible: extendDeep({}, axesAttrs.visible, {
dflt: true
}),
// tick and title properties named and function exactly as in axes
tickmode: axesAttrs.tickmode,
nticks: axesAttrs.nticks,
Expand Down
3 changes: 0 additions & 3 deletions src/traces/indicator/calc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
function calc(gd, trace) {
var cd = [];

// var singleValue = len === 1;
// var lastReading = trace.values[len - 1];
// var secondLastReading = singleValue ? lastReading : trace.values[len - 2];
var lastReading = trace.value;
var secondLastReading = trace.delta ? trace.delta.reference : trace._lastValue || trace.value;
cd[0] = {
Expand Down
12 changes: 7 additions & 5 deletions src/traces/indicator/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,18 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
coerce('vmax', 1.5 * traceOut.value);

// Number attributes
var auto = [];
var auto = new Array(2);
var bignumberFontSize;
if(traceOut._hasNumber) {
coerce('number.valueformat');
coerce('number.font.color', layout.font.color);
coerce('number.font.family', layout.font.family);
coerce('number.font.size', 'auto');
if(traceOut.number.font.size === 'auto') {
coerce('number.font.size');
if(!traceOut.number.font.size) {
traceOut.number.font.size = cn.defaultNumberFontSize;
auto[0] = true;
}
coerce('number.prefix');
coerce('number.suffix');
bignumberFontSize = traceOut.number.font.size;
}
Expand All @@ -57,8 +58,8 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
if(traceOut._hasDelta) {
coerce('delta.font.color', layout.font.color);
coerce('delta.font.family', layout.font.family);
coerce('delta.font.size', 'auto');
if(traceOut.delta.font.size === 'auto') {
coerce('delta.font.size');
if(!traceOut.delta.font.size) {
traceOut.delta.font.size = (traceOut._hasNumber ? 0.5 : 1) * (bignumberFontSize || cn.defaultNumberFontSize);
auto[1] = true;
}
Expand Down Expand Up @@ -133,6 +134,7 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
axisIn = {};
if(gaugeIn) axisIn = gaugeIn.axis || {};
axisOut = Template.newContainer(gaugeOut, 'axis');
coerceGaugeAxis('visible');
handleTickValueDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear');

var opts = {outerTicks: false, font: layout.font};
Expand Down
107 changes: 42 additions & 65 deletions src/traces/indicator/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var handleAxisDefaults = require('../../plots/cartesian/axis_defaults');
var handleAxisPositionDefaults = require('../../plots/cartesian/position_defaults');
var axisLayoutAttrs = require('../../plots/cartesian/layout_attributes');

var Color = require('../../components/color');
var anchor = {
'left': 'start',
'center': 'middle',
Expand Down Expand Up @@ -86,7 +87,7 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb
if(!hasGauge) {
numbersX = size.l + position[numbersAlign] * size.w;
numbersScaler = function(el) {
return fitTextInsideBox(el, 0.9 * size.w, 0.9 * size.h);
return fitTextInsideBox(el, size.w, size.h);
};
} else {
if(isAngular) {
Expand Down Expand Up @@ -142,10 +143,9 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb
}

// Prepare angular gauge layers
var data = cd.filter(function() {return isAngular;});
var angularGauge = plotGroup.selectAll('g.angular').data(data);
var angularGauge = plotGroup.selectAll('g.angular').data(isAngular ? cd : []);
angularGauge.exit().remove();
var angularaxisLayer = plotGroup.selectAll('g.angularaxis').data(data);
var angularaxisLayer = plotGroup.selectAll('g.angularaxis').data(isAngular ? cd : []);
angularaxisLayer.exit().remove();

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

// Prepare bullet layers
data = cd.filter(function() {return isBullet;});
var bulletGauge = plotGroup.selectAll('g.bullet').data(data);
var bulletGauge = plotGroup.selectAll('g.bullet').data(isBullet ? cd : []);
bulletGauge.exit().remove();
var bulletaxisLayer = plotGroup.selectAll('g.bulletaxis').data(data);
var bulletaxisLayer = plotGroup.selectAll('g.bulletaxis').data(isBullet ? cd : []);
bulletaxisLayer.exit().remove();

gaugeOpts = {
Expand Down Expand Up @@ -202,8 +201,12 @@ module.exports = function plot(gd, cdModule, transitionOpts, makeOnCompleteCallb
if(hasGauge) {
if(isAngular) {
// position above axis ticks/labels
var bBox = Drawing.bBox(angularaxisLayer.node());
titleY = (bBox.top - titlePadding) - titlebBox.bottom;
if(trace.gauge.axis.visible) {
var bBox = Drawing.bBox(angularaxisLayer.node());
titleY = (bBox.top - titlePadding) - titlebBox.bottom;
} else {
titleY = size.t + size.h / 2 - radius / 2 - titlebBox.bottom - titlePadding;
}
}
if(isBullet) {
// position outside domain
Expand Down Expand Up @@ -244,7 +247,7 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) {
bulletaxis.enter().append('g')
.classed('bulletaxis', true)
.classed('crisp', true);
bulletaxis.selectAll('g.' + 'xbulletaxis' + 'tick,path').remove();
bulletaxis.selectAll('g.' + 'xbulletaxis' + 'tick,path,text').remove();

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

// Draw bullet background, steps
var boxes = [gaugeBg].concat(trace.gauge.steps);
var targetBullet = bullet.selectAll('g.targetBullet').data(boxes);
targetBullet.enter().append('g').classed('targetBullet', true).append('rect');
var targetBullet = bullet.selectAll('g.target-bullet').data(boxes);
targetBullet.enter().append('g').classed('target-bullet', true).append('rect');
targetBullet.select('rect')
.call(drawRect)
.call(styleShape);
targetBullet.exit().remove();

// Draw value bar with transitions
var fgBullet = bullet.selectAll('g.fgBullet').data([trace.gauge.value]);
fgBullet.enter().append('g').classed('fgBullet', true).append('rect');
var fgBullet = bullet.selectAll('g.fg-bullet').data([trace.gauge.value]);
fgBullet.enter().append('g').classed('fg-bullet', true).append('rect');
fgBullet.select('rect')
.attr('height', innerBulletHeight)
.attr('y', (bulletHeight - innerBulletHeight) / 2)
Expand All @@ -324,12 +327,12 @@ function drawBulletGauge(gd, plotGroup, cd, gaugeOpts) {
.attr('x2', ax.c2p(trace.gauge.threshold.value))
.attr('y1', (1 - trace.gauge.threshold.thickness) / 2 * bulletHeight)
.attr('y2', (1 - (1 - trace.gauge.threshold.thickness) / 2) * bulletHeight)
.style('stroke', trace.gauge.threshold.line.color)
.call(Color.stroke, trace.gauge.threshold.line.color)
.style('stroke-width', trace.gauge.threshold.line.width);
threshold.exit().remove();

var bulletOutline = bullet.selectAll('g.bulletOutline').data([gaugeOutline]);
bulletOutline.enter().append('g').classed('bulletOutline', true).append('rect');
var bulletOutline = bullet.selectAll('g.bullet-outline').data([gaugeOutline]);
bulletOutline.enter().append('g').classed('bullet-outline', true).append('rect');
bulletOutline.select('rect')
.call(drawRect)
.call(styleShape);
Expand Down Expand Up @@ -388,12 +391,12 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
angularaxisLayer.enter().append('g')
.classed('angularaxis', true)
.classed('crisp', true);
angularaxisLayer.selectAll('g.' + 'angularaxis' + 'tick,path').remove();
angularaxisLayer.selectAll('g.' + 'xangularaxis' + 'tick,path,text').remove();

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

// 't'ick to 'g'eometric radians is used all over the place here
Expand Down Expand Up @@ -426,26 +429,28 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
return -0.5 * (1 + Math.sin(rad)) * h;
};
var _transFn = function(rad) {
return strTranslate(gaugePosition[0] + radius * Math.cos(rad), gaugePosition[1] - radius * Math.sin(rad));
return strTranslate(
gaugePosition[0] + radius * Math.cos(rad),
gaugePosition[1] - radius * Math.sin(rad)
);
};
transFn = function(d) {
return _transFn(t2g(d));
};
var transFn2 = function(d) {
var rad = t2g(d);
return _transFn(rad) + strRotate(-rad2deg(rad));
return _transFn(rad) + 'rotate(' + -rad2deg(rad) + ')';
};
vals = Axes.calcTicks(ax);
tickSign;
tickSign = Axes.getTickSigns(ax)[2];
if(ax.visible) {
tickSign = ax.ticks === 'inside' ? -1 : 1;
var pad = (ax.linewidth || 1) / 2;
Axes.drawTicks(gd, ax, {
vals: vals,
layer: angularaxisLayer,
path: 'M' + (tickSign * pad) + ',0h' + (tickSign * ax.ticklen),
transFn: transFn2,
crips: true
transFn: transFn2
});
Axes.drawLabels(gd, ax, {
vals: vals,
Expand All @@ -470,14 +475,14 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
// Draw background + steps
var arcs = [gaugeBg].concat(trace.gauge.steps);
if(v) arcs.push(thresholdArc);
var targetArc = angularGauge.selectAll('g.targetArc').data(arcs);
targetArc.enter().append('g').classed('targetArc', true).append('path');
var targetArc = angularGauge.selectAll('g.target-arc').data(arcs);
targetArc.enter().append('g').classed('target-arc', true).append('path');
targetArc.select('path').call(drawArc).call(styleShape);
targetArc.exit().remove();
// Draw foreground with transition
var valueArcPath = arcPathGenerator(trace.gauge.value.thickness);
var fgArc = angularGauge.selectAll('g.fgArc').data([trace.gauge.value]);
fgArc.enter().append('g').classed('fgArc', true).append('path');
var fgArc = angularGauge.selectAll('g.fg-arc').data([trace.gauge.value]);
fgArc.enter().append('g').classed('fgarc', true).append('path');
var fgArcPath = fgArc.select('path');
if(hasTransition) {
fgArcPath
Expand All @@ -493,8 +498,8 @@ function drawAngularGauge(gd, plotGroup, cd, gaugeOpts) {
}
fgArcPath.call(styleShape);
fgArc.exit().remove();
var gaugeBorder = angularGauge.selectAll('g.gaugeOutline').data([gaugeOutline]);
gaugeBorder.enter().append('g').classed('gaugeOutline', true).append('path');
var gaugeBorder = angularGauge.selectAll('g.gauge-outline').data([gaugeOutline]);
gaugeBorder.enter().append('g').classed('gauge-outline', true).append('path');
gaugeBorder.select('path').call(drawArc).call(styleShape);
gaugeBorder.exit().remove();
}
Expand Down Expand Up @@ -564,7 +569,7 @@ function drawNumbers(gd, plotGroup, cd, opts) {
var bignumberAx = mockAxis(gd, {tickformat: trace.number.valueformat});
var fmt = function(v) { return Axes.tickText(bignumberAx, v).text;};
var bignumberSuffix = trace.number.suffix;
if(bignumberSuffix) bignumberSuffix = ' ' + bignumberSuffix;
var bignumberPrefix = trace.number.prefix;

var number = numbers.select('tspan.number');
number
Expand All @@ -583,11 +588,11 @@ function drawNumbers(gd, plotGroup, cd, opts) {
var that = d3.select(this);
var interpolator = d3.interpolateNumber(cd[0].lastY, cd[0].y);
return function(t) {
that.text(fmt(interpolator(t)) + bignumberSuffix);
that.text(bignumberPrefix + fmt(interpolator(t)) + bignumberSuffix);
};
});
} else {
number.text(fmt(cd[0].y) + bignumberSuffix);
number.text(bignumberPrefix + fmt(cd[0].y) + bignumberSuffix);
}
}

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

Expand Down Expand Up @@ -669,8 +674,8 @@ function drawNumbers(gd, plotGroup, cd, opts) {
// Apply fill, stroke, stroke-width to SVG shape
function styleShape(p) {
p
.style('fill', function(d) { return d.color;})
.style('stroke', function(d) { return d.line.color;})
.each(function(d) { Color.stroke(d3.select(this), d.line.color);})
.each(function(d) { Color.fill(d3.select(this), d.color);})
.style('stroke-width', function(d) { return d.line.width;});
}

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

var axisIn = {
visible: opts.visible,
type: 'linear',
ticks: 'outside',
range: zrange,
Expand Down Expand Up @@ -743,10 +749,6 @@ function strTranslate(x, y) {
return 'translate(' + x + ',' + y + ')';
}

function strRotate(angle) {
return 'rotate(' + angle + ')';
}

function fitTextInsideBox(el, width, height) {
// compute scaling ratio to have text fit within specified width and height
var textBB = Drawing.bBox(el.node());
Expand All @@ -761,28 +763,3 @@ function fitTextInsideCircle(el, radius) {
var ratio = radius / elRadius;
return [ratio, textBB, radius];
}

// Draw gauge's min and max in text
// var minText = gauge.selectAll('text.min').data(cd);
// minText.enter().append('text').classed('min', true);
// minText
// .call(Drawing.font, trace.number.font)
// .style('font-size', gaugeFontSize)
// .attr({
// x: - (innerRadius + radius) / 2,
// y: gaugeFontSize,
// 'text-anchor': 'middle'
// })
// .text(fmt(trace.vmin));
//
// var maxText = gauge.selectAll('text.max').data(cd);
// maxText.enter().append('text').classed('max', true);
// maxText
// .call(Drawing.font, trace.number.font)
// .style('font-size', gaugeFontSize)
// .attr({
// x: (innerRadius + radius) / 2,
// y: gaugeFontSize,
// 'text-anchor': 'middle'
// })
// .text(fmt(trace.vmax));
Binary file modified test/image/baselines/indicator_datacard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/indicator_datacard2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading