UNPKG

@carbon/charts

Version:
330 lines 14.9 kB
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