UNPKG

@carbon/charts

Version:
295 lines 14.2 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 { Tools } from '../../tools'; import { ColorClassNameTypes } from '../../interfaces/enums'; import { LegendOrientations, Roles, Events, TruncationTypes, } from '../../interfaces'; import { DOMUtils } from '../../services'; import * as Configuration from '../../configuration'; // D3 Imports import { select, event } from 'd3-selection'; var Legend = /** @class */ (function (_super) { __extends(Legend, _super); function Legend() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.type = 'legend'; return _this; } Legend.prototype.render = function () { var _this = this; var svg = this.getContainerSVG() .attr('role', Roles.GROUP) .attr('data-name', 'legend-items'); var options = this.getOptions(); var legendOptions = Tools.getProperty(options, 'legend'); var dataGroups = this.model.getDataGroups(); var legendOrder = Tools.getProperty(legendOptions, 'order'); if (legendOrder) { dataGroups = this.sortDataGroups(dataGroups, legendOrder); } var legendItems = svg .selectAll('g.legend-item') .data(dataGroups, function (dataGroup) { return dataGroup.name; }); // this.getLegendItemArray() var addedLegendItems = legendItems .enter() .append('g') .classed('legend-item', true) .classed('active', function (d, i) { return d.status === Configuration.legend.items.status.ACTIVE; }); // Configs var checkboxRadius = Configuration.legend.checkbox.radius; // Truncation // get user provided custom values for truncation var truncationType = Tools.getProperty(legendOptions, 'truncation', 'type'); var truncationThreshold = Tools.getProperty(legendOptions, 'truncation', 'threshold'); var truncationNumCharacter = Tools.getProperty(legendOptions, 'truncation', 'numCharacter'); var paletteOption = Tools.getProperty(options, 'color', 'pairing', 'option'); var legendClickable = Tools.getProperty(this.getOptions(), 'legend', 'clickable'); svg.classed('clickable', legendClickable); addedLegendItems .append('rect') .classed('checkbox', true) .merge(legendItems.select('rect.checkbox')) .attr('role', Roles.CHECKBOX) .attr('tabindex', legendClickable ? 0 : -1) .attr('aria-label', function (d) { return d.name; }) .attr('aria-checked', function (_a) { var status = _a.status; return status === Configuration.legend.items.status.ACTIVE; }) .attr('width', checkboxRadius * 2) .attr('height', checkboxRadius * 2) .attr('rx', 1) .attr('ry', 1) .attr('class', function (d, i) { return _this.model.getColorClassName({ classNameTypes: [ColorClassNameTypes.FILL], dataGroupName: d.name, originalClassName: 'checkbox', }); }) .style('fill', function (d) { return d.status === Configuration.legend.items.status.ACTIVE ? _this.model.getFillColor(d.name) || _this.model.getStrokeColor(d.name) : null; }) .classed('active', function (d, i) { return d.status === Configuration.legend.items.status.ACTIVE; }); var addedLegendItemsText = addedLegendItems .append('text') .merge(legendItems.select('text')); // truncate the legend label if it's too long if (truncationType !== TruncationTypes.NONE) { addedLegendItemsText.html(function (d) { if (d.name.length > truncationThreshold) { return Tools.truncateLabel(d.name, truncationType, truncationNumCharacter); } else { return d.name; } }); } else { addedLegendItemsText.html(function (d) { return d.name; }); } this.breakItemsIntoLines(addedLegendItems); // Remove old elements as needed. legendItems .exit() .on('mouseover', null) .on('click', null) .on('mouseout', null) .remove(); if (legendClickable && addedLegendItems.size() > 0) { this.addEventListeners(); } var alignment = Tools.getProperty(legendOptions, 'alignment'); var alignmentOffset = DOMUtils.getAlignmentOffset(alignment, svg, this.getParent()); svg.attr('transform', "translate(" + alignmentOffset + ", 0)"); }; Legend.prototype.sortDataGroups = function (dataGroups, legendOrder) { // Sort data in user defined order dataGroups.sort(function (dataA, dataB) { return legendOrder.indexOf(dataA.name) - legendOrder.indexOf(dataB.name); }); // If user only defined partial ordering, ordered items are placed before unordered ones if (legendOrder.length < dataGroups.length) { var definedOrderIndex = dataGroups.length - legendOrder.length; var definedOrder = dataGroups.slice(definedOrderIndex); return definedOrder.concat(dataGroups.slice(0, definedOrderIndex)); } return dataGroups; }; Legend.prototype.breakItemsIntoLines = function (addedLegendItems) { var self = this; var svg = this.getContainerSVG(); var options = this.getOptions(); // Configs var checkboxRadius = Configuration.legend.checkbox.radius; var legendItemsHorizontalSpacing = Configuration.legend.items.horizontalSpace; var legendItemsVerticalSpacing = Configuration.legend.items.verticalSpace; var legendTextYOffset = Configuration.legend.items.textYOffset; var spaceNeededForCheckbox = checkboxRadius * 2 + Configuration.legend.checkbox.spaceAfter; // Check if there are disabled legend items var DISABLED = Configuration.legend.items.status.DISABLED; var dataGroups = this.model.getDataGroups(); var hasDeactivatedItems = dataGroups.some(function (dataGroup) { return dataGroup.status === DISABLED; }); var legendOrientation = Tools.getProperty(options, 'legend', 'orientation'); // Keep track of line numbers and positions var startingPoint = 0; var lineNumber = 0; var itemIndexInLine = 0; var lastYPosition; addedLegendItems .merge(svg.selectAll('g.legend-item')) .each(function (d, i) { var legendItem = select(this); var previousLegendItem = select(svg.selectAll('g.legend-item').nodes()[i - 1]); if (itemIndexInLine === 0 || previousLegendItem.empty() || legendOrientation === LegendOrientations.VERTICAL) { if (legendOrientation === LegendOrientations.VERTICAL && i !== 0) { lineNumber++; } } else { var svgDimensions = DOMUtils.getSVGElementSize(self.parent, { useAttr: true }); var legendItemTextDimensions = DOMUtils.getSVGElementSize(select(this).select('text'), { useBBox: true }); var lastLegendItemTextDimensions = DOMUtils.getSVGElementSize(previousLegendItem.select('text'), { useBBox: true }); startingPoint = startingPoint + lastLegendItemTextDimensions.width + spaceNeededForCheckbox + legendItemsHorizontalSpacing; if (startingPoint + spaceNeededForCheckbox + legendItemTextDimensions.width > svgDimensions.width) { lineNumber++; startingPoint = 0; itemIndexInLine = 0; } } var yOffset = 0; // Position checkbox // TODO - Replace with layout component margins legendItem .select('rect.checkbox') .attr('x', startingPoint) .attr('y', yOffset + lineNumber * legendItemsVerticalSpacing); // Position text // TODO - Replace with layout component margins var yPosition = legendTextYOffset + lineNumber * legendItemsVerticalSpacing; legendItem .select('text') .attr('x', startingPoint + spaceNeededForCheckbox) .attr('y', yOffset + yPosition + 3); lastYPosition = yPosition; // Test if legendItems are placed in the correct direction var testHorizontal = (!legendOrientation || legendOrientation === LegendOrientations.HORIZONTAL) && legendItem.select('rect.checkbox').attr('y') === '0'; var testVertical = legendOrientation === LegendOrientations.VERTICAL && legendItem.select('rect.checkbox').attr('x') === '0'; var hasCorrectLegendDirection = testHorizontal || testVertical; // Render checkbox check icon if (hasDeactivatedItems && legendItem.select('g.check').empty() && hasCorrectLegendDirection) { legendItem.append('g').classed('check', true).html("\n\t\t\t\t\t\t\t<svg focusable=\"false\" preserveAspectRatio=\"xMidYMid meet\"\n\t\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\"\n\t\t\t\t\t\t\t\tviewBox=\"0 0 32 32\" aria-hidden=\"true\"\n\t\t\t\t\t\t\t\tstyle=\"will-change: transform;\">\n\t\t\t\t\t\t\t\t<path d=\"M13 21.2l-7.1-7.1-1.4 1.4 7.1 7.1L13 24 27.1 9.9l-1.4-1.5z\"></path>\n\t\t\t\t\t\t\t\t<title>Checkmark</title>\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t"); legendItem .select('g.check svg') .attr('width', checkboxRadius * 2 - 1) .attr('height', checkboxRadius * 2 - 1) .attr('x', parseFloat(legendItem.select('rect.checkbox').attr('x')) + 0.5) .attr('y', parseFloat(legendItem.select('rect.checkbox').attr('y')) + 0.5); } else if (!hasDeactivatedItems && !legendItem.select('g.check').empty()) { legendItem.select('g.check').remove(); } itemIndexInLine++; }); }; Legend.prototype.addEventListeners = function () { var self = this; var svg = this.getContainerSVG(); var options = this.getOptions(); var legendOptions = Tools.getProperty(options, 'legend'); var truncationThreshold = Tools.getProperty(legendOptions, 'truncation', 'threshold'); svg.selectAll('g.legend-item') .on('mouseover', function () { self.services.events.dispatchEvent(Events.Legend.ITEM_HOVER, { hoveredElement: select(this), }); // Configs var checkboxRadius = Configuration.legend.checkbox.radius; var hoveredItem = select(this); hoveredItem.select('rect.checkbox').classed('hovered', true); hoveredItem .append('rect') .classed('hover-stroke', true) .attr('x', parseFloat(hoveredItem.select('rect.checkbox').attr('x')) - 2) .attr('y', parseFloat(hoveredItem.select('rect.checkbox').attr('y')) - 2) .attr('width', checkboxRadius * 2 + 4) .attr('height', checkboxRadius * 2 + 4) .attr('rx', 3) .attr('ry', 3) .lower(); var hoveredItemData = hoveredItem.datum(); if (hoveredItemData.name.length > truncationThreshold) { self.services.events.dispatchEvent(Events.Tooltip.SHOW, { hoveredElement: hoveredItem, content: hoveredItemData.name, }); } }) .on('mousemove', function () { self.services.events.dispatchEvent(Events.Tooltip.MOVE); }) .on('click', function () { self.services.events.dispatchEvent(Events.Legend.ITEM_CLICK, { clickedElement: select(this), }); var clickedItem = select(this); var clickedItemData = clickedItem.datum(); self.model.toggleDataLabel(clickedItemData.name); }) .on('mouseout', function () { var hoveredItem = select(this); hoveredItem.select('rect.hover-stroke').remove(); hoveredItem.select('rect.checkbox').classed('hovered', false); self.services.events.dispatchEvent(Events.Tooltip.HIDE); self.services.events.dispatchEvent(Events.Legend.ITEM_MOUSEOUT, { hoveredElement: hoveredItem, }); }); svg.selectAll('g.legend-item rect.checkbox').on('keyup', function (d) { if (event.key && (event.key === 'Enter' || event.key === ' ')) { event.preventDefault(); self.model.toggleDataLabel(d.name); } }); }; return Legend; }(Component)); export { Legend }; //# sourceMappingURL=../../../src/components/essentials/legend.js.map