UNPKG

@carbon/charts

Version:
314 lines 15.1 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 { Roles, Events, ColorClassNameTypes } from '../../interfaces'; import { Tools } from '../../tools'; // D3 Imports import { select } from 'd3-selection'; var Scatter = /** @class */ (function (_super) { __extends(Scatter, _super); function Scatter() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.type = 'scatter'; _this.handleChartHolderOnHover = function (event) { _this.parent .selectAll('circle.dot') .transition(_this.services.transitions.getTransition('chart-holder-hover-scatter')) .attr('opacity', 1); }; _this.handleChartHolderOnMouseOut = function (event) { _this.parent .selectAll('circle.dot') .transition(_this.services.transitions.getTransition('chart-holder-mouseout-scatter')) .attr('opacity', 0); }; _this.handleLegendOnHover = function (event) { var hoveredElement = event.detail.hoveredElement; var groupMapsTo = _this.getOptions().data.groupMapsTo; _this.parent .selectAll('circle.dot') .transition(_this.services.transitions.getTransition('legend-hover-scatter')) .attr('opacity', function (d) { return d[groupMapsTo] !== hoveredElement.datum()['name'] ? 0.3 : 1; }); }; _this.handleLegendMouseOut = function (event) { _this.parent .selectAll('circle.dot') .transition(_this.services.transitions.getTransition('legend-mouseout-scatter')) .attr('opacity', 1); }; return _this; } Scatter.prototype.init = function () { var events = this.services.events; // Highlight correct circle on legend item hovers events.addEventListener(Events.Legend.ITEM_HOVER, this.handleLegendOnHover); // Un-highlight circles on legend item mouseouts events.addEventListener(Events.Legend.ITEM_MOUSEOUT, this.handleLegendMouseOut); var fadeInOnChartHolderMouseover = this.configs.fadeInOnChartHolderMouseover; if (fadeInOnChartHolderMouseover) { // Fade-in scatter circles events.addEventListener(Events.Chart.MOUSEOVER, this.handleChartHolderOnHover); // Fade-out scatter circles events.addEventListener(Events.Chart.MOUSEOUT, this.handleChartHolderOnMouseOut); } }; Scatter.prototype.filterBasedOnZoomDomain = function (data) { var domainIdentifier = this.services.cartesianScales.getDomainIdentifier(data); var zoomDomain = this.model.get('zoomDomain'); if (zoomDomain !== undefined) { return data.filter(function (d) { return d[domainIdentifier].getTime() > zoomDomain[0].getTime() && d[domainIdentifier].getTime() < zoomDomain[1].getTime(); }); } return data; }; Scatter.prototype.getScatterData = function () { var _this = this; var options = this.getOptions(); var stacked = this.configs.stacked; var scatterData; if (stacked) { var percentage = Object.keys(options.axes).some(function (axis) { return options.axes[axis].percentage; }); scatterData = this.model.getStackedData({ groups: this.configs.groups, percentage: percentage, }); } else { scatterData = this.model .getDisplayData(this.configs.groups) .filter(function (d) { var rangeIdentifier = _this.services.cartesianScales.getRangeIdentifier(d); return (d[rangeIdentifier] !== undefined && d[rangeIdentifier] !== null); }); } // filter out datapoints that aren't part of the zoomed domain return this.filterBasedOnZoomDomain(scatterData); }; Scatter.prototype.render = function (animate) { var isScatterEnabled = Tools.getProperty(this.getOptions(), 'points', 'enabled') || Tools.getProperty(this.getOptions(), 'bubble', 'enabled'); if (!isScatterEnabled) { return; } // Grab container SVG var svg = this.getContainerSVG({ withinChartClip: true }); var options = this.getOptions(); var groupMapsTo = options.data.groupMapsTo; var domainIdentifier = this.services.cartesianScales.getDomainIdentifier(); // Update data on dot groups var circles = svg .selectAll('circle.dot') .data(this.getScatterData(), function (datum) { return datum[groupMapsTo] + "-" + datum[domainIdentifier]; }); // Remove circles that need to be removed circles.exit().attr('opacity', 0).remove(); // Add the dot groups that need to be introduced var enteringCircles = circles .enter() .append('circle') .classed('dot', true) .attr('opacity', 0); // Apply styling & position var circlesToStyle = enteringCircles.merge(circles); this.styleCircles(circlesToStyle, animate); // Add event listeners to elements drawn this.addEventListeners(); }; // A value is an anomaly if is above all defined domain and range thresholds Scatter.prototype.isDatapointThresholdAnomaly = function (datum, index) { var _this = this; var handleThresholds = this.configs.handleThresholds; if (!handleThresholds) { return false; } var cartesianScales = this.services.cartesianScales; var orientation = cartesianScales.getOrientation(); // Get highest domain and range thresholds var _a = Tools.flipDomainAndRangeBasedOnOrientation(this.services.cartesianScales.getHighestDomainThreshold(), this.services.cartesianScales.getHighestRangeThreshold(), orientation), xThreshold = _a[0], yThreshold = _a[1]; var _b = Tools.flipDomainAndRangeBasedOnOrientation(function (d, i) { return _this.services.cartesianScales.getDomainValue(d, i); }, function (d, i) { return _this.services.cartesianScales.getRangeValue(d, i); }, orientation), getXValue = _b[0], getYValue = _b[1]; // Get datum x and y values var xValue = getXValue(datum, index); var yValue = getYValue(datum, index); // To be an anomaly, the value has to be higher or equal than the threshold value // (if are present, both range and domain threshold values) if (yThreshold && xThreshold) { return (yValue <= yThreshold.scaleValue && xValue >= xThreshold.scaleValue); } if (yThreshold) { return yValue <= yThreshold.scaleValue; } if (xThreshold) { return xValue >= xThreshold.scaleValue; } }; Scatter.prototype.styleCircles = function (selection, animate) { var _this = this; // Chart options mixed with the internal configurations var options = this.getOptions(); var _a = options.points, filled = _a.filled, fillOpacity = _a.fillOpacity; var _b = this.services, cartesianScales = _b.cartesianScales, transitions = _b.transitions; var groupMapsTo = options.data.groupMapsTo; var getDomainValue = function (d, i) { return cartesianScales.getDomainValue(d, i); }; var getRangeValue = function (d, i) { return cartesianScales.getRangeValue(d, i); }; var _c = Tools.flipDomainAndRangeBasedOnOrientation(getDomainValue, getRangeValue, cartesianScales.getOrientation()), getXValue = _c[0], getYValue = _c[1]; var fadeInOnChartHolderMouseover = this.configs.fadeInOnChartHolderMouseover; selection .raise() .classed('dot', true) .attr('class', function (d) { var domainIdentifier = cartesianScales.getDomainIdentifier(d); var isFilled = _this.model.getIsFilled(d[groupMapsTo], d[domainIdentifier], d, filled); var classNamesNeeded = isFilled ? [ColorClassNameTypes.FILL, ColorClassNameTypes.STROKE] : [ColorClassNameTypes.STROKE]; return _this.model.getColorClassName({ classNameTypes: classNamesNeeded, dataGroupName: d[groupMapsTo], originalClassName: 'dot', }); }) // Set class to highlight the dots that are above all the thresholds, in both directions (vertical and horizontal) .classed('threshold-anomaly', function (d, i) { return _this.isDatapointThresholdAnomaly(d, i); }) .classed('filled', function (d) { var domainIdentifier = cartesianScales.getDomainIdentifier(d); return _this.model.getIsFilled(d[groupMapsTo], d[domainIdentifier], d, filled); }) .classed('unfilled', function (d) { var domainIdentifier = cartesianScales.getDomainIdentifier(d); return !_this.model.getIsFilled(d[groupMapsTo], d[domainIdentifier], d, filled); }) .transition(transitions.getTransition('scatter-update-enter', animate)) .attr('cx', getXValue) .attr('cy', getYValue) .attr('r', options.points.radius) .style('fill', function (d) { var domainIdentifier = cartesianScales.getDomainIdentifier(d); if (_this.model.getIsFilled(d[groupMapsTo], d[domainIdentifier], d, filled)) { return _this.model.getFillColor(d[groupMapsTo], d[domainIdentifier], d); } }) .style('stroke', function (d) { var domainIdentifier = cartesianScales.getDomainIdentifier(d); return _this.model.getStrokeColor(d[groupMapsTo], d[domainIdentifier], d); }) .attr('fill-opacity', filled ? fillOpacity : 1) .attr('opacity', fadeInOnChartHolderMouseover ? 0 : 1) // a11y .attr('role', Roles.GRAPHICS_SYMBOL) .attr('aria-roledescription', 'point') .attr('aria-label', function (d) { var rangeIdentifier = cartesianScales.getRangeIdentifier(d); return d[rangeIdentifier]; }); // Add event listeners to elements drawn this.addEventListeners(); }; Scatter.prototype.addEventListeners = function () { var self = this; var groupMapsTo = self.getOptions().data.groupMapsTo; this.parent .selectAll('circle') .on('mouseover', function (datum) { var hoveredElement = select(this); hoveredElement .classed('hovered', true) .attr('class', function (d) { return self.model.getColorClassName({ classNameTypes: [ColorClassNameTypes.FILL], dataGroupName: d[groupMapsTo], originalClassName: hoveredElement.attr('class'), }); }) .style('fill', function (d) { var domainIdentifier = self.services.cartesianScales.getDomainIdentifier(d); return self.model.getFillColor(d[groupMapsTo], d[domainIdentifier], d); }) .classed('unfilled', false); // Show tooltip for single datapoint self.services.events.dispatchEvent(Events.Tooltip.SHOW, { hoveredElement: hoveredElement, data: [datum], }); // Dispatch mouse event self.services.events.dispatchEvent(Events.Scatter.SCATTER_MOUSEOVER, { element: hoveredElement, datum: datum, }); }) .on('mousemove', function (datum) { var hoveredElement = select(this); // Dispatch mouse event self.services.events.dispatchEvent(Events.Scatter.SCATTER_MOUSEMOVE, { element: hoveredElement, datum: datum, }); self.services.events.dispatchEvent(Events.Tooltip.MOVE); }) .on('click', function (datum) { // Dispatch mouse event self.services.events.dispatchEvent(Events.Scatter.SCATTER_CLICK, { element: select(this), datum: datum, }); }) .on('mouseout', function (datum) { var hoveredElement = select(this); hoveredElement.classed('hovered', false); if (!self.configs.filled) { var filled_1 = self.getOptions().points.filled; var domainIdentifier_1 = self.services.cartesianScales.getDomainIdentifier(datum); hoveredElement .classed('unfilled', !self.model.getIsFilled(datum[groupMapsTo], datum[domainIdentifier_1], datum, filled_1)) .style('fill', function (d) { return filled_1 ? self.model.getFillColor(d[groupMapsTo], d[domainIdentifier_1], d) : null; }); } // Dispatch mouse event self.services.events.dispatchEvent(Events.Scatter.SCATTER_MOUSEOUT, { element: hoveredElement, datum: datum, }); // Hide tooltip self.services.events.dispatchEvent(Events.Tooltip.HIDE, { hoveredElement: hoveredElement, }); }); }; Scatter.prototype.destroy = function () { // Remove event listeners this.parent .selectAll('circle') .on('mousemove', null) .on('mouseout', null); // Remove legend listeners var events = this.services.events; events.removeEventListener(Events.Legend.ITEM_HOVER, this.handleLegendOnHover); events.removeEventListener(Events.Legend.ITEM_MOUSEOUT, this.handleLegendMouseOut); events.removeEventListener(Events.Chart.MOUSEOVER, this.handleChartHolderOnHover); events.removeEventListener(Events.Chart.MOUSEOUT, this.handleChartHolderOnMouseOut); }; return Scatter; }(Component)); export { Scatter }; //# sourceMappingURL=../../../src/components/graphs/scatter.js.map