UNPKG

veritatisquam

Version:
224 lines (188 loc) 6.65 kB
// Internal Imports import { Title } from './title'; import { DOMUtils } from '../../services'; import { Tools } from '../../tools'; import { Statuses } from './../../interfaces/enums'; import * as Configuration from '../../configuration'; export class MeterTitle extends Title { type = 'meter-title'; render() { const dataset = this.model.getDisplayData(); const options = this.getOptions(); const svg = this.getContainerSVG(); const { groupMapsTo } = options.data; // the title for a meter, is the label for that dataset const title = svg .selectAll('text.meter-title') .data([dataset[groupMapsTo]]); title .enter() .append('text') .classed('meter-title', true) .merge(title) .attr('x', 0) .attr('y', '1em') .text((d) => d); title.exit().remove(); // appends the associated percentage after title this.appendPercentage(); // if status ranges are provided (custom or default), display indicator this.displayStatus(); // get the max width of a title (with consideration for the status/percentage) const maxWidth = this.getMaxTitleWidth(); const titleElement = DOMUtils.appendOrSelect(svg, 'text.meter-title'); if ( maxWidth > 0 && titleElement.node().getComputedTextLength() > maxWidth ) { this.truncateTitle(titleElement, maxWidth); } } /** * Appends the corresponding status based on the value and the peak. */ displayStatus() { const self = this; const svg = this.getContainerSVG(); const options = this.getOptions(); const containerBounds = DOMUtils.getSVGElementSize( this.services.domUtils.getMainSVG(), { useAttr: true } ); // need to check if the width is 0, and try to use the parent attribute // this can happen if the chart is toggled on/off and the height is 0 for the parent, it wont validateDimensions const containerWidth = containerBounds.width ? containerBounds.width : this.parent.node().getAttribute('width'); // get the status from the model const status = this.model.getStatus(); const radius = Configuration.meter.status.indicatorSize / 2; // create a group for the icon/inner path const statusGroup = DOMUtils.appendOrSelect(svg, `g.status-indicator`) .attr( 'class', status !== null ? `status-indicator status--${status}` : '' ) .attr('transform', `translate(${containerWidth - radius}, 0)`); const data = status ? [status] : []; const icon = statusGroup.selectAll('circle.status').data(data); icon.enter() .append('circle') .merge(icon) .attr('class', 'status') .attr('r', radius) .attr('cx', 0) .attr('cy', `calc(1em / 2)`); const innerIcon = statusGroup.selectAll('path.innerFill').data(data); innerIcon .enter() .append('path') .merge(innerIcon) .attr('d', self.getStatusIconPathString(status)) .attr('transform', `translate(-${radius}, 0)`) .attr('class', 'innerFill'); innerIcon.exit().remove(); icon.exit().remove(); } /** * Appends the associated percentage to the end of the title */ appendPercentage() { const dataValue = this.model.getDisplayData().value; // use the title's position to append the percentage to the end const svg = this.getContainerSVG(); const title = DOMUtils.appendOrSelect(svg, 'text.meter-title'); // check if it is enabled const data = Tools.getProperty( this.getOptions(), 'meter', 'statusBar', 'percentageIndicator', 'enabled' ) === true ? [dataValue] : []; // append a percentage if it is enabled, update it const percentage = svg.selectAll('text.percent-value').data(data); // the horizontal offset of the percentage value from the title const offset = Configuration.meter.statusBar.paddingRight; percentage .enter() .append('text') .classed('percent-value', true) .merge(percentage) .text((d) => `${d}%`) .attr( 'x', +title.attr('x') + title.node().getComputedTextLength() + offset ) // set the position to after the title .attr('y', title.attr('y')); percentage.exit().remove(); } /** * Uses the parent class truncate logic * @param title d3 selection of title element that will be truncated * @param titlestring the original string that needs truncation * @param maxWidth the max width the title can take */ truncateTitle(title, maxWidth) { super.truncateTitle(title, maxWidth); // update the position on the percentage to be inline with the title const tspan = DOMUtils.appendOrSelect(this.parent, 'tspan'); const offset = Configuration.meter.statusBar.paddingRight; const tspanLength = Math.ceil(tspan.node().getComputedTextLength()); const percentage = DOMUtils.appendOrSelect( this.parent, 'text.percent-value' ); percentage.attr( 'x', +title.attr('x') + title.node().getComputedTextLength() + tspanLength + offset ); } // computes the maximum space a title can take protected getMaxTitleWidth() { // get a reference to the title elements to calculate the size the title can be const containerBounds = DOMUtils.getSVGElementSize( this.services.domUtils.getMainSVG(), { useAttr: true } ); // need to check if the width is 0, and try to use the parent attribute const containerWidth = containerBounds.width ? containerBounds.width : this.parent.node().getAttribute('width'); const percentage = DOMUtils.appendOrSelect( this.parent, 'text.percent-value' ); // the title needs to fit the width of the container without crowding the status, and percentage value const offset = Configuration.meter.statusBar.paddingRight; const percentageWidth = percentage.node().getComputedTextLength(); const statusGroup = DOMUtils.appendOrSelect( this.parent, 'g.status-indicator' ).node(); const statusWidth = DOMUtils.getSVGElementSize(statusGroup, { useBBox: true }).width + Configuration.meter.status.paddingLeft; return containerWidth - percentageWidth - offset - statusWidth; } /** * Get the associated status icon for the data * @param status the active status for the meter chart */ protected getStatusIconPathString(status) { switch (status) { case Statuses.SUCCESS: return 'M6.875 11.3125 3.75 8.1875 4.74375 7.25 6.875 9.34375 11.50625 4.75 12.5 5.7375 Z'; case Statuses.DANGER: return 'M10.7 11.5 4.5 5.3 5.3 4.5 11.5 10.7 Z'; case Statuses.WARNING: return 'M7.9375,11.125 C7.41973305,11.125 7,11.544733 7,12.0625 C7,12.580267 7.41973305,13 7.9375,13 C8.45526695,13 8.875,12.580267 8.875,12.0625 C8.875,11.544733 8.45526695,11.125 7.9375,11.125 M7.3125, 3 8.5625, 3 8.5625, 9.875 7.3125, 9.875, 7.3125, 3 Z'; } } }