@carbon/charts
Version:
Carbon charting components
295 lines • 14.2 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 { 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