UNPKG

@syncfusion/ej2-heatmap

Version:

Feature rich data visulization control used to visualize the matrix data where the individual values are represented as colors

827 lines (826 loc) 65.7 kB
import { Rect, Size, measureText, TextOption, rotateTextSize, textTrim, CanvasTooltip, PathOption, textWrap, getIsLineBreakLabel } from '../utils/helper'; import { sum, titlePositionX, LineOption, Line, DrawSvgCanvas, TextBasic, titlePositionY, getTitle } from '../utils/helper'; import { extend, Browser, isNullOrUndefined, SanitizeHtmlHelper } from '@syncfusion/ej2-base'; var AxisHelper = /** @class */ (function () { function AxisHelper(heatMap) { this.heatMap = heatMap; this.padding = 10; this.drawSvgCanvas = new DrawSvgCanvas(heatMap); } /** * To render the x and y axis. * * @private */ AxisHelper.prototype.renderAxes = function () { this.initialClipRect = this.heatMap.initialClipRect; var heatMap = this.heatMap; var axisElement; var element; if (!heatMap.enableCanvasRendering) { axisElement = this.heatMap.renderer.createGroup({ id: heatMap.element.id + 'AxisCollection' }); } var axes = this.heatMap.axisCollections; for (var i = 0, len = axes.length; i < len; i++) { var axis = axes[i]; if (axis.orientation === 'Horizontal') { if (!heatMap.enableCanvasRendering) { element = this.heatMap.renderer.createGroup({ id: heatMap.element.id + 'XAxisGroup' }); } this.drawXAxisLine(element, axis); this.drawXAxisTitle(axis, element, axis.rect); this.drawXAxisLabels(axis, element, axis.rect); } else { element = heatMap.renderer.createGroup({ id: heatMap.element.id + 'YAxisGroup' }); this.drawYAxisLine(element, axis); this.drawYAxisTitle(axis, element, axis.rect); this.drawYAxisLabels(axis, element, axis.rect); } if (axis.multiLevelLabels.length > 0) { this.drawMultiLevels(element, axis); } if (!heatMap.enableCanvasRendering) { axisElement.appendChild(element); } } if (!heatMap.enableCanvasRendering) { this.heatMap.svgObject.appendChild(axisElement); } }; AxisHelper.prototype.drawXAxisLine = function (parent, axis) { var y = this.initialClipRect.y + (!axis.opposedPosition ? this.initialClipRect.height : 0); var line = new LineOption(this.heatMap.element.id + '_XAxisLine', new Line(this.initialClipRect.x, y, this.initialClipRect.x + this.initialClipRect.width, y), 'transparent', 0); this.drawSvgCanvas.drawLine(line, parent); }; AxisHelper.prototype.drawYAxisLine = function (parent, axis) { var x = this.initialClipRect.x + ((!axis.opposedPosition) ? 0 : this.initialClipRect.width); var line = new LineOption(this.heatMap.element.id + '_YAxisLine', new Line(x, this.initialClipRect.y, x, this.initialClipRect.height + this.initialClipRect.y), 'transparent', 0); this.drawSvgCanvas.drawLine(line, parent); }; AxisHelper.prototype.drawXAxisTitle = function (axis, parent, rect) { var titlepadding = (axis.textStyle.size === '0px' ? 0 : 10); var y = rect.y + (!axis.opposedPosition ? (axis.maxLabelSize.height + titlepadding + sum(axis.xAxisMultiLabelHeight)) : -(axis.maxLabelSize.height + titlepadding + sum(axis.xAxisMultiLabelHeight))); if (axis.title.text) { var heatMap = this.heatMap; var title = axis.title; var axisTitleText = this.heatMap.enableHtmlSanitizer ? (SanitizeHtmlHelper.sanitize(title.text)) : title.text; var elementSize = measureText(axisTitleText, title.textStyle); var padding = this.padding; var anchor = title.textStyle.textAlignment === 'Near' ? 'start' : title.textStyle.textAlignment === 'Far' ? 'end' : 'middle'; padding = axis.opposedPosition ? -(padding + elementSize.height / 4) : (padding + (3 * elementSize.height / 4)); var options = new TextOption(heatMap.element.id + '_XAxisTitle', new TextBasic(rect.x + titlePositionX(rect.width, 0, 0, title.textStyle), y + padding, anchor, axisTitleText), title.textStyle, title.textStyle.color || heatMap.themeStyle.axisTitle); this.drawSvgCanvas.createText(options, parent, axisTitleText); } }; AxisHelper.prototype.drawYAxisTitle = function (axis, parent, rect) { if (axis.title.text) { var title = axis.title; var heatMap = this.heatMap; var labelRotation = (axis.opposedPosition) ? 90 : -90; var anchor = title.textStyle.textAlignment === 'Near' ? 'start' : title.textStyle.textAlignment === 'Far' ? 'end' : 'middle'; var padding = 10; padding = axis.opposedPosition ? padding : -padding; var titlepadding = (axis.textStyle.size === '0px' ? 0 : padding); var x = rect.x + titlepadding + ((axis.opposedPosition) ? axis.maxLabelSize.width + sum(axis.yAxisMultiLabelHeight) : -(axis.maxLabelSize.width + sum(axis.yAxisMultiLabelHeight))); var y = rect.y + titlePositionY(rect, 0, 0, title.textStyle) + (axis.opposedPosition ? this.padding : -this.padding); var axisTitleText = this.heatMap.enableHtmlSanitizer ? (SanitizeHtmlHelper.sanitize(title.text)) : title.text; var options = new TextOption(heatMap.element.id + '_YAxisTitle', new TextBasic(x, y - this.padding, anchor, axisTitleText, labelRotation, 'rotate(' + labelRotation + ',' + (x) + ',' + (y) + ')', 'auto'), title.textStyle, title.textStyle.color || heatMap.themeStyle.axisTitle); if (!this.heatMap.enableCanvasRendering) { this.drawSvgCanvas.createText(options, parent, axisTitleText); } else { this.drawSvgCanvas.canvasDrawText(options, axisTitleText, x, y); } } }; /** * Get the visible labels for both x and y axis * * @private */ AxisHelper.prototype.calculateVisibleLabels = function () { var heatmap = this.heatMap; var axis; var axisCollection = heatmap.axisCollections; var data = this.heatMap.dataSourceSettings; var processLabels = !(data && data.isJsonData && data.adaptorType === 'Cell'); for (var i = 0, len = axisCollection.length; i < len; i++) { axis = axisCollection[i]; if (axis.valueType === 'Numeric' && processLabels) { axis.clearAxisLabel(); axis.calculateNumericAxisLabels(this.heatMap); } else if (axis.valueType === 'DateTime' && processLabels) { axis.clearAxisLabel(); axis.calculateDateTimeAxisLabel(this.heatMap); } else if (axis.valueType === 'Category') { axis.clearAxisLabel(); axis.calculateCategoryAxisLabels(); } axis.tooltipLabels = axis.isInversed ? axis.tooltipLabels.reverse() : axis.tooltipLabels; } }; /** * Measure the title and labels rendering position for both X and Y axis. * * @param rect * @private */ AxisHelper.prototype.measureAxis = function (rect) { var heatmap = this.heatMap; var axis; var axisCollection = heatmap.axisCollections; for (var i = axisCollection.length - 1; i >= 0; i--) { axis = axisCollection[i]; var padding = axis.textStyle.size === '0px' ? 0 : this.padding; axis.nearSizes = []; axis.farSizes = []; axis.computeSize(axis, heatmap, rect); if (!axis.opposedPosition) { if (axis.orientation === 'Horizontal') { rect.height -= (sum(axis.nearSizes) + padding); } else { rect.x += sum(axis.nearSizes) + padding; rect.width -= sum(axis.nearSizes) + padding; } } else { if (axis.orientation === 'Horizontal') { rect.y += sum(axis.farSizes) + padding; rect.height -= sum(axis.farSizes) + padding; } else { rect.width -= sum(axis.farSizes) + padding; } } } }; /** * Calculate the X and Y axis line position * * @param rect * @private */ AxisHelper.prototype.calculateAxisSize = function (rect) { var heatmap = this.heatMap; var axisCollection = heatmap.axisCollections; for (var i = 0, len = axisCollection.length; i < len; i++) { var axis = axisCollection[i]; axis.rect = extend({}, rect, null, true); if (axis.orientation === 'Horizontal' && axis.multiLevelLabels.length !== 0) { if (axis.opposedPosition) { axis.rect.y += (axis.angle === 0 || axis.angle === 180 || axis.angle === 360 ? 0 : this.padding); this.heatMap.initialClipRect.y += (axis.angle === 0 || axis.angle === 180 || axis.angle === 360 ? 0 : this.padding); } rect.height -= (axis.angle === 0 || axis.angle === 180 || axis.angle === 360 ? 0 : this.padding); } if (axis.orientation === 'Horizontal' && !axis.opposedPosition) { axis.rect.y = rect.y + rect.height; axis.rect.height = 0; } if (axis.orientation === 'Vertical' && axis.opposedPosition) { axis.rect.x = rect.x + rect.width; axis.rect.width = 0; } axis.multiLevelPosition = []; for (var i_1 = 0; i_1 < axis.multiLevelLabels.length; i_1++) { var multiPosition = axis.multiPosition(axis, i_1); axis.multiLevelPosition.push(multiPosition); } } }; AxisHelper.prototype.drawXAxisLabels = function (axis, parent, rect) { var heatMap = this.heatMap; var labels = axis.axisLabels; var isLineBreak = false; var borderWidth = this.heatMap.cellSettings.border.width > 5 ? (this.heatMap.cellSettings.border.width / 2) : 0; var interval = (rect.width - borderWidth) / axis.axisLabelSize; var compactInterval = 0; var axisInterval = axis.interval ? axis.interval : 1; var tempintervel = rect.width / (axis.axisLabelSize / axis.axisLabelInterval); var temp = axis.axisLabelInterval; if (tempintervel > 0) { while (tempintervel < parseInt(axis.textStyle.size, 10)) { temp = temp + 1; tempintervel = rect.width / (axis.axisLabelSize / temp); } } else { temp = axis.tooltipLabels.length; } if (axis.axisLabelInterval < temp) { compactInterval = temp; labels = axis.tooltipLabels; axisInterval = temp; } var y; var padding = 10; var lableStrtX = rect.x + (!axis.isInversed ? 0 : rect.width); var labelPadding; var angle = axis.angle; padding = this.padding; var labelElement; var borderElement; if (!heatMap.enableCanvasRendering) { labelElement = this.heatMap.renderer.createGroup({ id: heatMap.element.id + 'XAxisLabels' }); borderElement = this.heatMap.renderer.createGroup({ id: heatMap.element.id + 'XAxisLabelBorder' }); } if (axis.isInversed && axis.labelIntersectAction === 'MultipleRows') { axis.multipleRow.reverse(); } isLineBreak = getIsLineBreakLabel(labels); for (var i = 0, len = labels.length; i < len; i++) { var lableRect = new Rect(lableStrtX, rect.y, interval, rect.height); var elementSize = measureText(labels[i], axis.textStyle); var label = (axis.textStyle.textOverflow !== 'Wrap' && !(isLineBreak) && axis.textStyle.textOverflow !== 'Trim' && axis.labelIntersectAction === 'Trim' && (axis.isIntersect || elementSize.width > interval)) ? axis.valueType !== 'DateTime' || axis.showLabelOn === 'None' ? textTrim(interval * axisInterval, labels[i], axis.textStyle) : textTrim(axis.dateTimeAxisLabelInterval[i] * interval, labels[i], axis.textStyle) : labels[i]; label = ((axis.enableTrim || axis.textStyle.textOverflow === 'Trim') && !isLineBreak) ? textTrim((axis.textStyle.textOverflow === 'Trim' ? interval - (axis.border.width / 2) : axis.maxLabelLength), labels[i], axis.textStyle) : label; if (heatMap.enableHtmlSanitizer) { label = SanitizeHtmlHelper.sanitize(label); } var wrappedLabel = label; var wrappedlabels = []; var rotateSize = new Size(0, 0); if ((axis.textStyle.textOverflow === 'Wrap' || isLineBreak) && !axis.enableTrim) { wrappedlabels = this.getLabels(wrappedLabel, interval - (axis.border.width / 2), axis, isLineBreak); wrappedLabel = this.getMaxLabel(wrappedlabels, axis); } else { if (isLineBreak && axis.enableTrim) { wrappedlabels = this.getLabels(wrappedLabel, interval - (axis.border.width / 2), axis, isLineBreak); wrappedLabel = textTrim(axis.maxLabelLength, wrappedlabels[0], axis.textStyle); wrappedLabel = (label.indexOf('<br>') !== -1 || label.indexOf('<br/>') !== -1) && wrappedLabel.indexOf('...') === -1 ? wrappedLabel + '...' : wrappedLabel; wrappedlabels = []; } wrappedlabels.push(wrappedLabel); } elementSize = measureText(wrappedLabel, axis.textStyle); var transform = void 0; labelPadding = (axis.opposedPosition) ? -(padding) : (padding + ((angle % 360) === 0 ? (elementSize.height / 2) : 0)); elementSize.width = axis.isInversed ? (elementSize.width > interval ? interval : elementSize.width) : elementSize.width; var x = lableRect.x + ((!axis.isInversed) ? (lableRect.width / 2) - (elementSize.width / 2) : -((lableRect.width / 2) + (elementSize.width / 2))); if (axis.textStyle.textAlignment === 'Near') { x = lableRect.x - ((!axis.isInversed) ? 0 : lableRect.width); } else if (axis.textStyle.textAlignment === 'Far') { x = lableRect.x + ((!axis.isInversed) ? (lableRect.width - elementSize.width) : -(elementSize.width)); } if (axis.labelIntersectAction === 'Trim') { x = (!axis.isInversed) ? (x >= lableRect.x ? x : lableRect.x) : (x > (lableStrtX - interval) ? x : (lableStrtX - interval)); } else if (angle % 180 === 0) { x = x < rect.x ? rect.x : x; x = ((x + elementSize.width) > (rect.x + rect.width)) ? (rect.x + rect.width - elementSize.width) : x; } if ((axis.textStyle.textOverflow === 'Wrap' || isLineBreak) && !axis.isInversed) { x = x < lableRect.x ? lableRect.x : x; } if (axis.labelIntersectAction === 'MultipleRows' && axis.textStyle.textOverflow !== 'Wrap' && axis.textStyle.textOverflow !== 'Trim' && axis.labelRotation === 0) { var a = axis.opposedPosition ? -(axis.multipleRow[i].index - 1) : (axis.multipleRow[i].index - 1); if (axis.multipleRow[i].index > 1) { y = rect.y + labelPadding + (elementSize.height * a) + (axis.opposedPosition ? -(((elementSize.height * 0.5) / 2) * axis.multipleRow[i].index) : (((elementSize.height * 0.5) / 2) * axis.multipleRow[i].index)); } else { y = rect.y + labelPadding + (axis.opposedPosition ? -((elementSize.height * 0.5) / 2) : ((elementSize.height * 0.5) / 2)); } } else { y = rect.y + ((axis.textStyle.textOverflow === 'Wrap' || isLineBreak) && axis.opposedPosition && angle % 360 === 0 ? -(axis.farSizes.length >= 1 ? axis.farSizes[1] : 0) + padding : labelPadding); } this.drawXAxisBorder(axis, borderElement, axis.rect, x, elementSize.width, i); x = (axis.textStyle.textAlignment === 'Center' && wrappedlabels.length > 1) ? x + (elementSize.width / 2) : axis.textStyle.textAlignment === 'Near' ? x + padding / 2 : axis.textStyle.textAlignment === 'Far' ? x - padding / 2 : x; if (angle % 360 !== 0) { angle = (angle > 360) ? angle % 360 : angle; rotateSize = rotateTextSize(axis.textStyle, wrappedlabels, angle); /* eslint-disable max-len */ x = lableRect.x + (axis.isInversed ? -(lableRect.width / 2) : (lableRect.width / 2)) + (angle === 90 ? (elementSize.height * ((wrappedlabels.length - 1) / 2)) : angle === 270 ? -(elementSize.height * (wrappedlabels.length - 1) / 2) : 0); /* eslint-disable max-len */ y = y + (axis.opposedPosition ? (((axis.textStyle.textOverflow === 'Wrap' || isLineBreak) && !axis.enableTrim ? (((angle % 360) === 180) ? padding : 0) + (rotateSize.height / 2) - (axis.farSizes.length >= 1 ? axis.farSizes[1] : 0) : -(rotateSize.height / 2)) + (axis.border.width / 2)) : (((angle % 360) === 0) ? 0 : ((angle % 360) === 180) ? (rotateSize.height / 2) - (axis.border.width) + padding : (rotateSize.height / 2) - (axis.border.width))); if (wrappedlabels.length > 1) { y = y - ((angle > 0 && angle < 80) || (angle > 300 && angle < 360) ? elementSize.height * ((wrappedlabels.length - 1) / 2) : (angle > 120 && angle < 240) && angle !== 180 && wrappedlabels.length > 2 ? -(elementSize.height * ((wrappedlabels.length - 2) / 2)) : 0); x = x + ((angle > 0 && angle < 70) ? elementSize.height * ((wrappedlabels.length - 1) / 2) : 0); } transform = 'rotate(' + angle + ',' + x + ',' + y + ')'; } if (this.heatMap.cellSettings.border.width > 5 && axis.opposedPosition) { y = y - (this.heatMap.cellSettings.border.width / 2); } if (this.heatMap.yAxis.opposedPosition && this.heatMap.cellSettings.border.width > 5) { x = x + (this.heatMap.cellSettings.border.width / 2); } if (this.heatMap.xAxis.isInversed && this.heatMap.cellSettings.border.width > 5) { x = x - (this.heatMap.cellSettings.border.width / 2); } if (elementSize.width >= interval) { x = axis.border.width ? x + (axis.border.width / 2) : x; } x = axis.textStyle.textAlignment === 'Near' ? x + (axis.border.width / 2) : axis.textStyle.textAlignment === 'Far' ? x - (axis.border.width / 2) : x; x = (angle % 360 === 0) && axis.textStyle.textAlignment === 'Center' && elementSize.width > interval ? lableRect.x + ((!axis.isInversed) ? (elementSize.width / 2) : -((elementSize.width / 2))) : x; var options = new TextOption(heatMap.element.id + '_XAxis_Label' + i, new TextBasic(x, y, (angle % 360 === 0) ? (axis.textStyle.textAlignment === 'Center' && wrappedlabels.length > 1) ? 'middle' : 'start' : 'middle', label, angle, transform), axis.textStyle, axis.textStyle.color || heatMap.themeStyle.axisLabel); /* eslint-disable max-len */ options.text = isLineBreak ? wrappedlabels : getTitle(options.text, axis.textStyle, lableRect.width - (axis.border.width / 2)); if (angle !== 0 && this.heatMap.enableCanvasRendering) { this.drawSvgCanvas.canvasDrawText(options, null, null, null, wrappedlabels, elementSize.height, true); } else { if (axis.textStyle.textOverflow === 'Wrap' || isLineBreak) { this.drawSvgCanvas.createWrapText(options, axis.textStyle, labelElement); } else { this.drawSvgCanvas.createText(options, labelElement, label); } } if (compactInterval === 0) { var labelInterval = (axis.valueType === 'DateTime' && axis.showLabelOn !== 'None') ? axis.dateTimeAxisLabelInterval[i] : axis.axisLabelInterval; lableStrtX = lableStrtX + (!axis.isInversed ? (labelInterval * interval) : -(labelInterval * interval)); } else { lableStrtX = lableStrtX + (!axis.isInversed ? (compactInterval * interval) : -(compactInterval * interval)); } if (wrappedLabel.indexOf('...') !== -1) { var xValue = axis.angle % 360 !== 0 ? x - (rotateSize.width / 2) : (axis.textStyle.textAlignment === 'Center' ? x - (elementSize.width / 2) : x); var yValue = y - (axis.angle % 360 !== 0 ? (rotateSize.height / 2) : elementSize.height); label = labels[i].indexOf('<br>') !== -1 || labels[i].indexOf('<br/>') !== -1 ? labels[i].replace(/<br\s*\/?>/g, ' ') : labels[i]; this.heatMap.tooltipCollection.push(new CanvasTooltip(label, new Rect(xValue, yValue, axis.angle % 360 !== 0 ? rotateSize.width : elementSize.width, axis.angle % 360 !== 0 ? rotateSize.height : elementSize.height * wrappedlabels.length))); } if (compactInterval !== 0) { i = i + (compactInterval - 1); } } if (!heatMap.enableCanvasRendering) { parent.appendChild(labelElement); parent.appendChild(borderElement); } }; AxisHelper.prototype.getWrappedLabels = function (wrappedLabel, labelInterval, axis) { var wrappedlabels = wrappedLabel.split(/<br\s*\/?>/, -1); for (var i = 0; i < wrappedlabels.length; i++) { var label = wrappedlabels[i]; wrappedlabels[i] = textTrim(labelInterval, label, axis.textStyle); } return wrappedlabels; }; AxisHelper.prototype.getMaxLabel = function (wrappedlabels, axis) { var label = ''; var labelWidth = 0; var wrappedlabelSize = new Size(0, 0); for (var index = 0; index < wrappedlabels.length; index++) { wrappedlabelSize = measureText(wrappedlabels[index], axis.textStyle); if (wrappedlabelSize.width > labelWidth) { labelWidth = wrappedlabelSize.width; label = wrappedlabels[index]; } } return label; }; AxisHelper.prototype.getLabels = function (label, labelInterval, axis, isLineBreak) { var wrappedlabels = []; if (isLineBreak) { wrappedlabels = this.getWrappedLabels(label, labelInterval, axis); } else { wrappedlabels = textWrap(label, labelInterval, axis.textStyle); } return wrappedlabels; }; AxisHelper.prototype.drawYAxisLabels = function (axis, parent, rect) { var heatMap = this.heatMap; var labels = axis.axisLabels; var interval = rect.height / axis.axisLabelSize; var compactInterval = 0; var tempintervel = rect.height / (axis.axisLabelSize / axis.axisLabelInterval); var temp = axis.axisLabelInterval; var label; if (tempintervel > 0) { while (tempintervel < parseInt(axis.textStyle.size, 10)) { temp = temp + 1; tempintervel = rect.height / (axis.axisLabelSize / temp); } } else { temp = axis.tooltipLabels.length; } if (axis.axisLabelInterval < temp) { compactInterval = temp; labels = axis.tooltipLabels; } var padding = 10; var labelPadding = 5; var lableStartY = rect.y + (axis.isInversed ? 0 : rect.height); var anchor = axis.opposedPosition ? 'start' : 'end'; padding = axis.opposedPosition ? padding : -padding; var labelElement; var borderElement; if (!heatMap.enableCanvasRendering) { labelElement = this.heatMap.renderer.createGroup({ id: heatMap.element.id + 'YAxisLabels' }); borderElement = this.heatMap.renderer.createGroup({ id: heatMap.element.id + 'YAxisLabelBorder' }); } var isLineBreak = getIsLineBreakLabel(labels); for (var i = 0, len = labels.length; i < len; i++) { var labelRect = new Rect(rect.x, lableStartY, rect.width, interval); var position = axis.isInversed ? labelRect.height / 2 : -(labelRect.height / 2); //titlePositionY(lableRect, 0, 0, axis.textStyle); var axisWidth = this.heatMap.cellSettings.border.width >= 20 ? (this.heatMap.cellSettings.border.width / 2) : 0; var indexValue = this.heatMap.cellSettings.border.width > 5 ? (((this.heatMap.cellSettings.border.width / 2) / len) * (axis.isInversed ? (i) : (len - i))) : 0; label = (axis.enableTrim || axis.textStyle.textOverflow === 'Trim') && !isLineBreak ? textTrim(axis.maxLabelLength, labels[i], axis.textStyle) : labels[i]; if (heatMap.enableHtmlSanitizer) { label = SanitizeHtmlHelper.sanitize(label); } var elementSize = measureText(label, axis.textStyle); var labelLength = 1; var wrappedLabel = []; var rotateSize = new Size(0, 0); if ((axis.textStyle.textOverflow === 'Wrap' || isLineBreak) && !axis.enableTrim) { wrappedLabel = this.getLabels(label, axis.maxLabelLength, axis, isLineBreak); for (var index = 0; index < wrappedLabel.length; index++) { if ((elementSize.height * wrappedLabel.length) > (tempintervel + (labelPadding)) && wrappedLabel.length > 0 && (axis.angle !== 90 && axis.angle !== 270)) { wrappedLabel.pop(); if (wrappedLabel.length > 0) { wrappedLabel[wrappedLabel.length - 1] = wrappedLabel[wrappedLabel.length - 1] + '...'; /* eslint-disable max-len */ wrappedLabel[wrappedLabel.length - 1] = textTrim(axis.maxLabelLength, wrappedLabel[wrappedLabel.length - 1], axis.textStyle); } } } if (!(isLineBreak)) { label = wrappedLabel.length !== 0 ? '' : label; for (var labelIndex = 0; labelIndex < wrappedLabel.length; labelIndex++) { label = isNullOrUndefined(label) ? wrappedLabel[labelIndex] : label + ' ' + wrappedLabel[labelIndex]; } } labelLength = wrappedLabel.length; } else { if (isLineBreak && axis.enableTrim) { wrappedLabel = this.getLabels(label, axis.maxLabelLength, axis, isLineBreak); var trimmedLabel = textTrim(axis.maxLabelLength, wrappedLabel[0], axis.textStyle); label = (label.indexOf('<br>') !== -1 || label.indexOf('<br/>') !== -1) && trimmedLabel.indexOf('...') === -1 ? trimmedLabel + '...' : trimmedLabel; wrappedLabel = []; } wrappedLabel.push(label); } var x = labelRect.x + padding + (axis.opposedPosition ? (axis.textStyle.textOverflow === 'Wrap' && axis.angle % 360 !== 0 ? labelLength * (elementSize.height / 2) : 0) + axisWidth : -axisWidth); if (axis.textStyle.textAlignment === 'Far' && axis.angle % 360 === 0) { /* eslint-disable max-len */ position = axis.isInversed ? labelRect.height - (labelLength > 1 ? (elementSize.height * labelLength) - (elementSize.height / 2) : (elementSize.height / 2)) : -(labelLength > 1 ? (elementSize.height * labelLength) - (elementSize.height / 2) : (elementSize.height / 2)); } else if (axis.textStyle.textAlignment === 'Near' && axis.angle % 360 === 0) { /* eslint-disable max-len */ position = (axis.isInversed ? elementSize.height / 2 : ((elementSize.height / 2) - labelRect.height)) + (axis.border.width / 2); } var y = (labelRect.y - indexValue) + position - ((labelLength > 1 && axis.textStyle.textAlignment === 'Center') || (axis.angle % 360 !== 0 && axis.opposedPosition) ? (((elementSize.height * labelLength) / 2) - (elementSize.height / 2)) : 0); if (axis.angle % 360 !== 0) { anchor = 'middle'; axis.angle = (axis.angle > 360) ? axis.angle % 360 : axis.angle; rotateSize = rotateTextSize(axis.textStyle, wrappedLabel, axis.angle); x = labelRect.x + (axis.opposedPosition ? (rotateSize.width / 2 + padding) : -(rotateSize.width / 2 - padding)) + (axis.angle === 90 ? (elementSize.height * ((wrappedLabel.length - 1) / 2)) : axis.angle === 270 ? -(elementSize.height * (wrappedLabel.length - 1) / 2) : 0); y = labelRect.y + (axis.isInversed ? (labelRect.height / 2) : (-labelRect.height / 2)) + (axis.angle === 180 ? (elementSize.height * ((wrappedLabel.length - 1) / 2)) : 0); if (wrappedLabel.length > 1) { var value = elementSize.height * ((wrappedLabel.length - 1) / 2); y = y - ((axis.angle > 0 && axis.angle < 60) || (axis.angle > 290 && axis.angle < 360) ? value : (axis.angle > 115 && axis.angle < 240) && axis.angle !== 180 ? -value : 0); x = x + (axis.angle > 20 && axis.angle < 160 && axis.angle !== 90 ? value : axis.angle > 200 && axis.angle < 330 && axis.angle !== 270 ? -value - (axis.angle > 200 && axis.angle < 240 && !axis.opposedPosition && wrappedLabel.length > 2 ? -(elementSize.height * ((wrappedLabel.length - 2) / 2)) : 0) : (axis.angle >= 330 && axis.angle < 350 ? -value / 2 : 0)); } } var options = new TextOption(heatMap.element.id + '_YAxis_Label' + i, new TextBasic(x, y, anchor, label, axis.angle, 'rotate(' + axis.angle + ',' + (x) + ',' + (y) + ')', 'middle'), axis.textStyle, axis.textStyle.color || heatMap.themeStyle.axisLabel); if (Browser.isIE && !heatMap.enableCanvasRendering) { options.dy = '1ex'; } options.text = isLineBreak ? wrappedLabel : getTitle(options.text, axis.textStyle, axis.maxLabelLength); if (axis.angle !== 0 && this.heatMap.enableCanvasRendering) { this.drawSvgCanvas.canvasDrawText(options, null, null, null, wrappedLabel, elementSize.height, true); } else { if (axis.textStyle.textOverflow === 'Wrap' || isLineBreak) { this.drawSvgCanvas.createWrapText(options, axis.textStyle, labelElement); } else { this.drawSvgCanvas.createText(options, labelElement, label); } } label = this.getMaxLabel(wrappedLabel, axis); if (label.indexOf('...') !== -1) { var xValue = axis.opposedPosition ? x : (x - (axis.angle % 360 !== 0 ? (rotateSize.width / 2) : elementSize.width)); var yValue = y - (axis.angle % 360 !== 0 ? (rotateSize.height / 2) : elementSize.height); label = labels[i].indexOf('<br>') !== -1 || labels[i].indexOf('<br/>') !== -1 ? labels[i].replace(/<br\s*\/?>/g, ' ') : labels[i]; this.heatMap.tooltipCollection.push(new CanvasTooltip(label, new Rect(xValue, yValue, (axis.angle % 360 !== 0 ? rotateSize.width : elementSize.width), (axis.angle % 360 !== 0 ? rotateSize.height : elementSize.height * wrappedLabel.length)))); } if (compactInterval === 0) { var labelInterval = (axis.valueType === 'DateTime' && axis.showLabelOn !== 'None') ? axis.dateTimeAxisLabelInterval[i] : axis.axisLabelInterval; lableStartY = lableStartY + (axis.isInversed ? (labelInterval * interval) : -(labelInterval * interval)); } else { lableStartY = lableStartY + (axis.isInversed ? (compactInterval * interval) : -(compactInterval * interval)); i = i + (compactInterval - 1); } this.drawYAxisBorder(axis, borderElement, axis.rect, y, elementSize.height, i); } if (!heatMap.enableCanvasRendering) { parent.appendChild(labelElement); parent.appendChild(borderElement); } }; AxisHelper.prototype.drawXAxisBorder = function (axis, parent, rect, lableX, width, index) { var interval = rect.width / axis.axisLabelSize; var path = ''; var padding = 10; var axisInterval = axis.interval ? axis.interval : 1; var startX = axis.isInversed ? rect.x + rect.width - (interval * index * axisInterval) : rect.x + (interval * index * axisInterval); var startY = rect.y; var endX; var endY; endY = startY + (axis.opposedPosition ? -(axis.maxLabelSize.height + padding) : axis.maxLabelSize.height + padding); // eslint-disable-next-line prefer-const endX = axis.isInversed ? startX - interval : startX + interval; var endY1 = axis.isInversed ? (lableX + width + padding) : (lableX - padding); var endY2 = axis.isInversed ? (lableX - padding) : (lableX + width + padding); endY2 = axis.textStyle.textAlignment === 'Near' && axis.isInversed ? endY2 + padding : axis.textStyle.textAlignment === 'Far' && !axis.isInversed ? endY2 - padding : endY2; endY1 = axis.textStyle.textAlignment === 'Far' && axis.isInversed ? endY1 - padding : axis.textStyle.textAlignment === 'Near' && !axis.isInversed ? endY1 + padding : endY1; switch (axis.border.type) { case 'Rectangle': path = ('M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + startY); break; case 'WithoutTopBorder': path = 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' '; break; case 'WithoutBottomBorder': path = 'M' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' '; break; case 'WithoutTopandBottomBorder': path = 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'M' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' '; break; case 'Brace': endY = startY + ((endY - startY) / 2) + (axis.opposedPosition ? 0 : 5); path = 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + endY1 + ' ' + endY + ' ' + 'M' + ' ' + endY2 + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' '; break; } if (axis.border.width > 0 && axis.border.type !== 'WithoutBorder') { this.createAxisBorderElement(axis, path, parent, index); } }; AxisHelper.prototype.drawYAxisBorder = function (axis, parent, rect, lableY, height, index) { var interval = rect.height / axis.axisLabelSize; var path = ''; var padding = 20; var axisInterval = axis.interval ? axis.interval : 1; var startX = rect.x; var startY = axis.isInversed ? rect.y + (interval * index * axisInterval) : rect.y + rect.height - (interval * index * axisInterval); var endX; var endY; endX = startX + (!axis.opposedPosition ? -(axis.maxLabelSize.width + padding) : axis.maxLabelSize.width + padding); // eslint-disable-next-line prefer-const endY = axis.isInversed ? startY + interval : startY - interval; var endY1 = axis.isInversed ? lableY - height / 2 : lableY + height / 2; var endY2 = axis.isInversed ? lableY + height / 2 : lableY - height / 2; switch (axis.border.type) { case 'Rectangle': path = 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + startY; break; case 'WithoutTopBorder': path = 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' '; break; case 'WithoutBottomBorder': path = 'M' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' '; break; case 'WithoutTopandBottomBorder': path = 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'M' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' '; break; case 'Brace': endX = startX - (startX - endX) / 2; path = 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + endY1 + ' ' + 'M' + ' ' + endX + ' ' + endY2 + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + startX + ' ' + endY; break; } if (axis.border.width > 0 && axis.border.type !== 'WithoutBorder') { this.createAxisBorderElement(axis, path, parent, index); } }; /** * To create border element for axis. * * @returns {void} * @private */ AxisHelper.prototype.createAxisBorderElement = function (axis, labelBorder, parent, index) { var canvasTranslate; var id = axis.orientation === 'Horizontal' ? '_XAxis_Label_Border' : '_YAxis_Label_Border'; var pathOptions = new PathOption(this.heatMap.element.id + id + index, 'transparent', axis.border.width, axis.border.color, 1, 'none', labelBorder); if (!this.heatMap.enableCanvasRendering) { var borderElement = this.heatMap.renderer.drawPath(pathOptions); parent.appendChild(borderElement); } else { this.heatMap.canvasRenderer.drawPath(pathOptions, canvasTranslate); } }; AxisHelper.prototype.drawMultiLevels = function (parent, axis) { var element; if (!this.heatMap.enableCanvasRendering) { element = this.heatMap.renderer.createGroup({ id: this.heatMap.element.id + '_' + axis.orientation + '_MultiLevelLabel' }); } if (axis.orientation === 'Horizontal') { this.renderXAxisMultiLevelLabels(axis, element); } else { this.renderYAxisMultiLevelLabels(axis, element); } if (!this.heatMap.enableCanvasRendering) { parent.appendChild(element); } }; /** * render x axis multi level labels * * @private * @returns {void} */ AxisHelper.prototype.renderXAxisMultiLevelLabels = function (axis, parent) { var _this = this; var x = 0; var y; var padding = 10; var startX; var startY; var endX = 0; var tooltip; var start; var end; var labelSize; var anchor; var isInversed = axis.isInversed; var labelElement; var opposedPosition = axis.opposedPosition; var pathRect = ''; var gap; var textLength; var position = (isInversed ? axis.rect.width : 0) + axis.rect.x; axis.multiLevelLabels.map(function (multiLevel, level) { labelElement = _this.heatMap.renderer.createGroup({ id: _this.heatMap.element.id + '_XAxisMultiLevelLabel' + level }); multiLevel.categories.map(function (categoryLabel, i) { if (!isNullOrUndefined(categoryLabel.start) && !isNullOrUndefined(categoryLabel.end)) { if (_this.heatMap.theme === 'Tailwind' || _this.heatMap.theme === 'TailwindDark') { // eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { fontFamily: 'Inter' } }, true); } if (_this.heatMap.theme === 'Tailwind3' || _this.heatMap.theme === 'Tailwind3Dark') { // eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { color: _this.heatMap.themeStyle.axisLabel, fontFamily: 'Inter', fontWeight: '400' } }, true); } if (_this.heatMap.theme === 'Material3' || _this.heatMap.theme === 'Material3Dark') { // eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { fontFamily: 'Roboto' } }, true); } if (_this.heatMap.theme === 'Fluent' || _this.heatMap.theme === 'FluentDark') { // eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { fontFamily: '"Segoe UI", -apple-system, BlinkMacSystemFont, "Roboto", "Helvetica Neue", sans-serif' } }, true); } if (_this.heatMap.theme === 'Fluent2') { // eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { color: '#242424', size: '12px', fontWeight: '400', fontFamily: 'Segoe UI' } }, true); } if (_this.heatMap.theme === 'Fluent2Dark' || _this.heatMap.theme === 'Fluent2HighContrast') { // eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { color: '#FFFFFF', size: '12px', fontWeight: '400', fontFamily: 'Segoe UI' } }, true); } if (_this.heatMap.theme === 'Bootstrap5') { // eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { color: '#212529', size: '12px', fontWeight: '400', fontFamily: 'Segoe UI' } }, true); } if (_this.heatMap.theme === 'Bootstrap5Dark') { //eslint-disable-next-line @typescript-eslint/no-explicit-any multiLevel.setProperties({ textStyle: { color: '#DEE2E6', size: '12px', fontWeight: '400', fontFamily: 'Segoe UI' } }, true); } tooltip = false; start = typeof categoryLabel.start === 'number' ? categoryLabel.start : Number(new Date(categoryLabel.start)); end = typeof categoryLabel.end === 'number' ? categoryLabel.end : Number(new Date(categoryLabel.end)); startX = position + _this.calculateLeftPosition(axis, start, categoryLabel.start, axis.rect); startY = axis.multiLevelPosition[level].y; endX = position + _this.calculateWidth(axis, categoryLabel.end, end, axis.rect); var text = _this.heatMap.enableHtmlSanitizer ? SanitizeHtmlHelper.sanitize(categoryLabel.text) : categoryLabel.text; labelSize = measureText(text, multiLevel.textStyle); gap = ((categoryLabel.maximumTextWidth === null) ? Math.abs(endX - startX) : categoryLabel.maximumTextWidth) - padding; y = startY + (opposedPosition ? -((axis.xAxisMultiLabelHeight[level] - labelSize.height)) : labelSize.height); x = !isInversed ? startX + padding : startX - gap; if (multiLevel.alignment === 'Center') { x = ((endX - startX) / 2) + startX; x -= (labelSize.width > gap ? gap : labelSize.width) / 2; } else if (multiLevel.alignment === 'Far') { x = !isInversed ? endX - padding : startX - padding; x -= (labelSize.width > gap ? gap : labelSize.width); } else { x = !isInversed ? startX + padding : endX + padding; } if (multiLevel.overflow === 'None' && labelSize.width > Math.abs(endX - startX)) { x = !isInversed ? startX + padding : startX - labelSize.width - padding; anchor = 'start'; } var textBasic = new TextBasic(x, y, anchor, text, 0, 'translate(0,0)'); var options = new TextOption(_this.heatMap.element.id + '_XAxis_MultiLevel' + level + '_Text' + i, textBasic, multiLevel.textStyle, multiLevel.textStyle.color || _this.heatMap.themeStyle.axisLabel); if (multiLevel.overflow === 'Wrap') { options.text = textWrap(text, gap, multiLevel.textStyle); textLength = options.text.length; } else if (multiLevel.overflow === 'Trim') { options.text = textTrim(gap, text, multiLevel.textStyle); textLength = 1; } if (multiLevel.overflow === 'Wrap' && options.text.length > 1) { _this.drawSvgCanvas.createWrapText(options, multiLevel.textStyle, labelElement); for (var i_2 = 0; i_2 < options.text.length; i_2++) { if (options.text[i_2].indexOf('...') !== -1) { tooltip = true; break; } } } else { _this.drawSvgCanvas.createText(options, labelElement, options.text); } if (!_this.heatMap.enableCanvasRendering) { parent.appendChild(labelElement); } if (options.text.indexOf('...') !== -1 || options.text[0].indexOf('...') !== -1 || tooltip) { _this.heatMap.tooltipCollection.push(new CanvasTooltip(categoryLabel.text, new Rect(x, y - labelSize.height, gap, labelSize.height * textLength))); } if (multiLevel.border.width > 0 && multiLevel.border.type !== 'WithoutBorder') { pathRect = _this.renderXAxisLabelBorder(level, axis, startX, startY, endX, pathRect, level, labelSize, gap, x); } } }); if (pathRect !== '') { _this.createBorderElement(level, axis, pathRect, parent); pathRect = ''; } }); if (!this.heatMap.enableCanvasRendering) { parent.appendChild(labelElement); } }; /** * render x axis multi level labels border * * @private * @returns {void} */ AxisHelper.prototype.renderXAxisLabelBorder = function (labelIndex, axis, startX, startY, endX, path, level, labelSize, gap, x) { var path1; var path2; var endY = startY + (axis.opposedPosition ? -(axis.xAxisMultiLabelHeight[labelIndex]) : axis.xAxisMultiLabelHeight[labelIndex]); var padding = 3; switch (axis.multiLevelLabels[level].border.type) { case 'Rectangle': path += 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + startY + ' '; break; case 'WithoutTopBorder': path += 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' '; break; case 'WithoutBottomBorder': path += 'M' + ' ' + startX + ' ' + endY + ' ' + 'L' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' '; break; case 'WithoutTopandBottomBorder': path += 'M' + ' ' + startX + ' ' + startY + ' ' + 'L' + ' ' + startX + ' ' + endY + ' ' + 'M' + ' ' + endX + ' ' + startY + ' ' + 'L' + ' ' + endX + ' ' + endY + ' '; break;