@carbon/charts
Version:
Carbon charting components
330 lines • 14.9 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
// Internal Imports
import { Component } from '../component';
import { DOMUtils } from '../../services';
import { Roles, Events, GaugeTypes, ArrowDirections, ColorClassNameTypes, Alignments, } from '../../interfaces';
import { Tools } from '../../tools';
// D3 Imports
import { select } from 'd3-selection';
import { arc } from 'd3-shape';
// arrow paths for delta
var ARROW_UP_PATH_STRING = '4,10 8,6 12,10';
var ARROW_DOWN_PATH_STRING = '12,6 8,10 4,6';
var Gauge = /** @class */ (function (_super) {
__extends(Gauge, _super);
function Gauge() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = 'gauge';
return _this;
}
Gauge.prototype.init = function () {
var eventsFragment = this.services.events;
};
Gauge.prototype.getValue = function () {
var _a, _b;
var data = this.model.getData();
var value = (_b = (_a = data.find(function (d) { return d.group === 'value'; })) === null || _a === void 0 ? void 0 : _a.value, (_b !== null && _b !== void 0 ? _b : null));
return value;
};
Gauge.prototype.getValueRatio = function () {
var value = Tools.clamp(this.getValue(), 0, 100);
return value / 100;
};
Gauge.prototype.getDelta = function () {
var _a, _b;
var data = this.model.getData();
var delta = (_b = (_a = data.find(function (d) { return d.group === 'delta'; })) === null || _a === void 0 ? void 0 : _a.value, (_b !== null && _b !== void 0 ? _b : null));
return delta;
};
Gauge.prototype.getArcRatio = function () {
var options = this.getOptions();
var type = Tools.getProperty(options, 'gauge', 'type');
var arcRatio = type === GaugeTypes.FULL ? 1 : 0.5;
return arcRatio;
};
Gauge.prototype.getArcSize = function () {
return this.getArcRatio() * Math.PI * 2;
};
Gauge.prototype.getStartAngle = function () {
var arcSize = this.getArcSize();
if (arcSize === 2 * Math.PI) {
return 0;
}
return -arcSize / 2;
};
// use provided arrow direction or default to using the delta
Gauge.prototype.getArrow = function (delta) {
var options = this.getOptions();
var arrowDirection = Tools.getProperty(options, 'gauge', 'deltaArrow', 'direction');
switch (arrowDirection) {
case ArrowDirections.UP:
return ARROW_UP_PATH_STRING;
case ArrowDirections.DOWN:
return ARROW_DOWN_PATH_STRING;
default:
return delta > 0
? ARROW_UP_PATH_STRING
: ARROW_DOWN_PATH_STRING;
}
};
Gauge.prototype.render = function (animate) {
var _this = this;
if (animate === void 0) { animate = true; }
var self = this;
var svg = this.getContainerSVG();
var options = this.getOptions();
var groupMapsTo = options.data.groupMapsTo;
var value = this.getValue();
var valueRatio = this.getValueRatio();
var arcSize = this.getArcSize();
// angles for drawing the gauge
var startAngle = this.getStartAngle();
var rotationAngle = valueRatio * arcSize;
var currentAngle = startAngle + rotationAngle;
var endAngle = startAngle + arcSize;
// Compute the outer radius needed
var radius = this.computeRadius();
var innerRadius = this.getInnerRadius();
// draw the container and arc
this.backgroundArc = arc()
.innerRadius(innerRadius)
.outerRadius(radius)
.startAngle(currentAngle)
.endAngle(endAngle);
this.arc = arc()
.innerRadius(innerRadius)
.outerRadius(radius)
.startAngle(startAngle)
.endAngle(currentAngle);
// draw the container
DOMUtils.appendOrSelect(svg, 'path.arc-background')
.attr('d', this.backgroundArc)
.attr('role', Roles.GROUP);
// Add data arc
var arcValue = svg.selectAll('path.arc-foreground').data([value]);
var arcEnter = arcValue.enter().append('path');
arcEnter
.merge(arcValue)
.attr('class', this.model.getColorClassName({
classNameTypes: [ColorClassNameTypes.FILL],
dataGroupName: 'value',
originalClassName: 'arc-foreground',
}))
.style('fill', function (d) {
return Tools.getProperty(_this.getOptions(), 'color', 'scale', 'value');
})
.attr('d', this.arc)
// a11y
.attr('role', Roles.GRAPHICS_SYMBOL)
.attr('aria-roledescription', 'value')
.attr('aria-label', function (d) { return d.value; });
// draw the value and delta to the center
this.drawValueNumber();
this.drawDelta();
arcValue.exit().remove();
var alignment = Tools.getProperty(options, 'gauge', 'alignment');
var width = DOMUtils.getSVGElementSize(this.getParent(), {
useAttr: true,
}).width;
// Position gauge
var gaugeTranslateX = radius;
if (alignment === Alignments.CENTER) {
gaugeTranslateX = width / 2;
}
else if (alignment === Alignments.RIGHT) {
gaugeTranslateX = width - radius;
}
svg.attr('transform', "translate(" + gaugeTranslateX + ", " + radius + ")");
// Add event listeners
this.addEventListeners();
};
/**
* draws the value number associated with the Gauge component in the center
*/
Gauge.prototype.drawValueNumber = function () {
var svg = this.getContainerSVG();
var options = this.getOptions();
var arcType = Tools.getProperty(options, 'gauge', 'type');
var value = this.getValue();
var delta = this.getDelta();
// Sizing and positions relative to the radius
var radius = this.computeRadius();
var valueFontSize = Tools.getProperty(options, 'gauge', 'valueFontSize');
// if there is a delta, use the size to center the numbers, otherwise center the valueNumber
var deltaFontSize = Tools.getProperty(options, 'gauge', 'deltaFontSize');
var numberSpacing = Tools.getProperty(options, 'gauge', 'numberSpacing');
var showPercentageSymbol = Tools.getProperty(options, 'gauge', 'showPercentageSymbol');
// circular gauge without delta should have valueNumber centered
var numbersYPosition = 0;
if (arcType === GaugeTypes.FULL && !delta) {
numbersYPosition = deltaFontSize(radius);
}
else if (arcType === GaugeTypes.SEMI && delta) {
// semi circular gauge we want the numbers aligned to the chart container
numbersYPosition = -(deltaFontSize(radius) + numberSpacing);
}
// Add the numbers at the center
var numbersGroup = DOMUtils.appendOrSelect(svg, 'g.gauge-numbers').attr('transform', "translate(0, " + numbersYPosition + ")");
var fontSize = valueFontSize(radius);
// Add the big number
var valueNumberGroup = DOMUtils.appendOrSelect(numbersGroup, 'g.gauge-value-number');
var numberFormatter = Tools.getProperty(options, 'gauge', 'numberFormatter');
var valueNumber = valueNumberGroup
.selectAll('text.gauge-value-number')
.data([value]);
valueNumber
.enter()
.append('text')
.attr('class', 'gauge-value-number')
.merge(valueNumber)
.style('font-size', fontSize + "px")
.attr('text-anchor', 'middle')
.text(function (d) { return numberFormatter(d); });
// add the percentage symbol beside the valueNumber
var valueNumberWidth = DOMUtils.getSVGElementSize(DOMUtils.appendOrSelect(svg, 'text.gauge-value-number'), { useBBox: true }).width;
var symbolFontSize = fontSize / 2;
var gaugeSymbol = showPercentageSymbol ? '%' : '';
var symbol = DOMUtils.appendOrSelect(valueNumberGroup, 'text.gauge-value-symbol')
.style('font-size', symbolFontSize + "px")
.attr('x', valueNumberWidth / 2)
.text(gaugeSymbol);
var _a = DOMUtils.getSVGElementSize(symbol, { useBBox: true }), symbolWidth = _a.width, symbolHeight = _a.height;
// adjust the symbol to superscript using the bbox instead of the font-size cause
// we want to align the actual character to the value number
symbol.attr('y', "-" + symbolHeight / 2 + "px");
// move the value group depending on the symbol's drawn size
valueNumberGroup.attr('transform', "translate(-" + symbolWidth / 2 + ", 0)"); // Optical centering for the presence of the smaller % symbol
};
/**
* adds the delta number for the gauge
*/
Gauge.prototype.drawDelta = function () {
var self = this;
var svg = this.getContainerSVG();
var options = this.getOptions();
var delta = this.getDelta();
// Sizing and positions relative to the radius
var radius = this.computeRadius();
var deltaFontSize = delta
? Tools.getProperty(options, 'gauge', 'deltaFontSize')
: function () { return 0; };
// use numberFormatter here only if there is a delta supplied
var numberFormatter = delta
? Tools.getProperty(options, 'gauge', 'numberFormatter')
: function () { return null; };
var arrowSize = Tools.getProperty(options, 'gauge', 'deltaArrow', 'size');
var numberSpacing = Tools.getProperty(options, 'gauge', 'numberSpacing');
var showPercentageSymbol = Tools.getProperty(options, 'gauge', 'showPercentageSymbol');
var numbersGroup = DOMUtils.appendOrSelect(svg, 'g.gauge-numbers');
// Add the smaller number of the delta
var deltaGroup = DOMUtils.appendOrSelect(numbersGroup, 'g.gauge-delta').attr('transform', "translate(0, " + (deltaFontSize(radius) + numberSpacing) + ")");
var deltaNumber = DOMUtils.appendOrSelect(deltaGroup, 'text.gauge-delta-number');
var gaugeSymbol = showPercentageSymbol ? '%' : '';
deltaNumber.data(delta === null ? [] : [delta]);
deltaNumber
.enter()
.append('text')
.classed('gauge-delta-number', true)
.merge(deltaNumber)
.attr('text-anchor', 'middle')
.style('font-size', deltaFontSize(radius) + "px")
.text(function (d) { return "" + numberFormatter(d) + gaugeSymbol; });
// Add the caret for the delta number
var deltaNumberWidth = DOMUtils.getSVGElementSize(DOMUtils.appendOrSelect(svg, '.gauge-delta-number'), { useBBox: true }).width;
// check if delta arrow is disabled
var arrowEnabled = Tools.getProperty(options, 'gauge', 'deltaArrow', 'enabled');
var deltaArrow = deltaGroup
.selectAll('svg.gauge-delta-arrow')
.data(delta !== null && arrowEnabled ? [delta] : []);
deltaArrow
.enter()
.append('svg')
.merge(deltaArrow)
.attr('class', 'gauge-delta-arrow')
.attr('x', -arrowSize(radius) - deltaNumberWidth / 2)
.attr('y', -arrowSize(radius) / 2 - deltaFontSize(radius) * 0.35)
.attr('width', arrowSize(radius))
.attr('height', arrowSize(radius))
.attr('viewBox', '0 0 16 16');
// Needed to correctly size SVG in Firefox
DOMUtils.appendOrSelect(deltaArrow, 'rect.gauge-delta-arrow-backdrop')
.attr('width', '16')
.attr('height', '16')
.attr('fill', 'none');
// Draw the arrow with status
var status = Tools.getProperty(options, 'gauge', 'status');
DOMUtils.appendOrSelect(deltaArrow, 'polygon.gauge-delta-arrow')
.attr('class', status !== null ? "gauge-delta-arrow status--" + status : '')
.attr('points', self.getArrow(delta));
deltaArrow.exit().remove();
deltaNumber.exit().remove();
};
Gauge.prototype.getInnerRadius = function () {
// Compute the outer radius needed
var radius = this.computeRadius();
var arcWidth = Tools.getProperty(this.getOptions(), 'gauge', 'arcWidth');
return radius - arcWidth;
};
Gauge.prototype.addEventListeners = function () {
var self = this;
this.parent
.selectAll('path.arc-foreground')
.on('mouseover', function (datum) {
// Dispatch mouse event
self.services.events.dispatchEvent(Events.Gauge.ARC_MOUSEOVER, {
element: select(this),
datum: datum,
});
})
.on('mousemove', function (datum) {
var hoveredElement = select(this);
// Dispatch mouse event
self.services.events.dispatchEvent(Events.Gauge.ARC_MOUSEMOVE, {
element: hoveredElement,
datum: datum,
});
})
.on('click', function (datum) {
// Dispatch mouse event
self.services.events.dispatchEvent(Events.Gauge.ARC_CLICK, {
element: select(this),
datum: datum,
});
})
.on('mouseout', function (datum) {
var hoveredElement = select(this);
// Dispatch mouse event
self.services.events.dispatchEvent(Events.Gauge.ARC_MOUSEOUT, {
element: hoveredElement,
datum: datum,
});
});
};
// Helper functions
Gauge.prototype.computeRadius = function () {
var options = this.getOptions();
var arcType = Tools.getProperty(options, 'gauge', 'type');
var _a = DOMUtils.getSVGElementSize(this.parent, {
useAttrs: true,
}), width = _a.width, height = _a.height;
var radius = arcType === GaugeTypes.SEMI
? Math.min(width / 2, height)
: Math.min(width / 2, height / 2);
return radius;
};
return Gauge;
}(Component));
export { Gauge };
//# sourceMappingURL=../../../src/components/graphs/gauge.js.map