UNPKG

@syncfusion/ej2-charts

Version:

Feature-rich chart control with built-in support for over 25 chart types, technical indictors, trendline, zooming, tooltip, selection, crosshair and trackball.

892 lines 106 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 __()); }; })(); /** * Selection src file */ import { Animation, Browser } from '@syncfusion/ej2-base'; import { remove } from '@syncfusion/ej2-base'; import { extend, isNullOrUndefined } from '@syncfusion/ej2-base'; import { ChartLocation, RectOption, CircleOption, withInBounds, getDraggedRectLocation, removeElement, getElement } from '../../common/utils/helper'; import { Rect, PathOption } from '@syncfusion/ej2-svg-base'; import { Index } from '../../common/model/base'; import { dragComplete, selectionComplete } from '../../common/model/constants'; import { BaseSelection } from '../../common/user-interaction/selection'; /** * The `Selection` module handles the selection of chart elements. * * @private */ var Selection = /** @class */ (function (_super) { __extends(Selection, _super); /** * Constructor for selection module. * * @private */ function Selection(chart) { var _this = _super.call(this, chart) || this; _this.isdrawRect = true; _this.multiDataIndexes = []; _this.pathIndex = 0; _this.seriesIndex = 0; _this.count = -1; _this.dragRectArray = []; _this.filterArray = []; _this.totalSelectedPoints = []; _this.chart = chart; _this.renderer = chart.renderer; var mode = chart.selectionMode; _this.isMultiDrag = chart.isMultiSelect && (mode.indexOf('Drag') > -1); _this.addEventListener(); return _this; } /** * Adds event listeners for the chart. * * @returns {void} */ Selection.prototype.addEventListener = function () { if (this.chart.isDestroyed || (this.chart.stockChart && this.chart.stockChart.onPanning)) { return; } var cancelEvent = Browser.isPointer ? 'pointerleave' : 'mouseleave'; this.chart.on(Browser.touchMoveEvent, this.mouseMove, this); this.chart.on(cancelEvent, this.mouseLeave, this); this.chart.on('click', this.mouseClick, this); this.chart.on(Browser.touchStartEvent, this.mousedown, this); this.chart.on(Browser.touchEndEvent, this.mouseLeave, this); }; /** * Handles the mousedown event. * * @private * @param {Event} e - The event object. * @returns {void} */ Selection.prototype.mousedown = function (e) { var chart = this.chart; if (chart.isPointMouseDown || chart.selectionMode === 'None' || chart.isChartDrag) { return; } if (chart.isDoubleTap || !chart.isTouch || this.rectPoints) { this.dragStart(chart, chart.chartAxisLayoutPanel.seriesClipRect, chart.mouseDownX, chart.mouseDownY, e); } }; /** * UnBinding events for selection module. * * @returns {void} */ Selection.prototype.removeEventListener = function () { if (this.chart.isDestroyed) { return; } this.chart.off(Browser.touchMoveEvent, this.mouseMove); this.chart.off('pointerleave' || 'mouseleave', this.mouseLeave); this.chart.off('click', this.mouseClick); this.chart.off(Browser.touchStartEvent, this.mousedown); this.chart.off(Browser.touchEndEvent, this.mouseLeave); }; /** * Initializes private variables for the chart. * * @private * @param {Chart} chart - The chart instance. * @returns {void} */ Selection.prototype.initPrivateVariables = function (chart) { this.styleId = chart.element.id + '_ej2_chart_selection'; this.unselected = chart.element.id + '_ej2_deselected'; this.closeIconId = chart.element.id + '_ej2_drag_close'; this.draggedRectGroup = chart.element.id + '_ej2_drag_group'; this.multiRectGroup = chart.element.id + '_ej2_drag_multi_group'; this.draggedRect = chart.element.id + '_ej2_drag_rect'; this.lassoPath = chart.element.id + '_ej2_drag_path'; this.selectedDataIndexes = []; this.rectPoints = null; this.isSeriesMode = chart.selectionMode === 'Series'; }; /** * Method to select the point and series. * * @param {Chart} chart - The chart instance. * @returns {void} */ Selection.prototype.invokeSelection = function (chart) { this.initPrivateVariables(chart); this.series = extend({}, chart.visibleSeries, null, true); this.seriesStyles(); this.currentMode = chart.selectionMode; if (!(chart.selectionMode.indexOf('Drag') > -1)) { this.selectDataIndex(chart, this.concatIndexes(chart.selectedDataIndexes, this.selectedDataIndexes)); } }; Selection.prototype.generateStyle = function (series) { if (series) { if (this.styleId.indexOf('selection') > 1 && this.chart.selectionMode !== 'None') { this.unselected = series.unSelectedStyle || this.unselected; } if (this.styleId.indexOf('highlight') > 0 && (this.chart.highlightMode !== 'None' || this.chart.legendSettings.enableHighlight)) { this.unselected = series.nonHighlightStyle || this.unselected; } return (series.selectionStyle || this.styleId + '_series_' + series.index); } return 'undefined'; }; /** * Selects data points in the chart based on the provided indexes. * * @param {Chart} chart - The chart instance. * @param {Index[]} indexes - An array of Index objects specifying the series and point indexes to be selected. * @returns {void} */ Selection.prototype.selectDataIndex = function (chart, indexes) { for (var _i = 0, indexes_1 = indexes; _i < indexes_1.length; _i++) { var index = indexes_1[_i]; this.performSelection(index, chart, this.getElementByIndex(chart, index, '', this.series[index.series].marker.visible)[0]); } }; /** * Retrieves the DOM elements corresponding to the specified data point index. * * @param {Chart} chart - The chart instance. * @param {Index} index - The index object specifying the series and point indexes. * @param {string} [suffix=''] - Optional suffix to be appended to the element IDs. * @param {boolean} [marker] - Optional parameter to specify whether to retrieve marker elements. Default is false. * @param {boolean} [dataLabel] - Optional parameter to specify whether to retrieve datalabel elements. Default is false. * @returns {Element[]} - An array of DOM elements corresponding to the specified data point index. */ Selection.prototype.getElementByIndex = function (chart, index, suffix, marker, dataLabel) { if (suffix === void 0) { suffix = ''; } var elementId = chart.element.id + '_Series_' + index.series + '_Point' + '_' + index.point; var series = chart.series[index.series]; elementId = (series.type !== 'Scatter' && series.type !== 'Bubble' && marker) ? (elementId + '_Symbol' + suffix) : elementId; if (!marker && dataLabel) { return [getElement(elementId + '_Text_0' + suffix), getElement(elementId + '_TextShape_0' + suffix)]; } return [getElement(elementId), ((series.type === 'RangeArea' || series.type === 'SplineRangeArea' || series.type === 'RangeStepArea') && series.marker.visible) ? getElement(elementId + '1') : null]; }; /** * Retrieves the DOM elements corresponding to the cluster of data points at the specified index. * * @param {Chart} chart - The chart instance. * @param {Index} index - The index object specifying the series and point indexes. * @returns {Element[]} - An array of DOM elements corresponding to the cluster of data points at the specified index. */ Selection.prototype.getClusterElements = function (chart, index) { var clusters = []; var seriesStyle; var selectedElements; for (var _i = 0, _a = chart.visibleSeries; _i < _a.length; _i++) { var series = _a[_i]; if (series.visible) { index = new Index(series.index, index.point); if (series.isRectSeries) { clusters.push(this.getElementByIndex(chart, index)[0]); } clusters.push(this.getElementByIndex(chart, index, '', series.marker.visible)[0]); var dataLabelTextElement = document.getElementById(chart.element.id + '_Series_' + series.index + '_Point_' + index.point + '_Text_0'); var dataLabelShapeElement = document.getElementById(chart.element.id + '_Series_' + series.index + '_Point_' + index.point + '_TextShape_0'); if (dataLabelTextElement) { clusters.push(dataLabelTextElement); } if (dataLabelShapeElement) { clusters.push(dataLabelShapeElement); } seriesStyle = this.generateStyle(chart.visibleSeries[index.series]); selectedElements = document.querySelectorAll('.' + seriesStyle); this.findTrackballElements(selectedElements, seriesStyle); var clusterIndex = series.marker.visible && series.isRectSeries ? 2 : 1; clusterIndex += (dataLabelTextElement && dataLabelShapeElement) ? 2 : (dataLabelTextElement || dataLabelShapeElement) ? 1 : 0; if (!chart.isMultiSelect && selectedElements.length > 0 && selectedElements[0].id !== (clusters[clusters.length - clusterIndex] ? clusters[clusters.length - clusterIndex].id : '')) { this.removeSelection(chart, index.series, selectedElements, seriesStyle, true); } } } return clusters; }; /** * Finds the elements within the selected elements that match the specified class name. * * @param {Element[] | NodeListOf<HTMLElement>} selectedElements - The elements to search within. * @param {string} className - The class name to search for. * @returns {void} */ Selection.prototype.findTrackballElements = function (selectedElements, className) { var trackballElements; var elements; for (var i = 0; i < selectedElements.length; i++) { if (!isNullOrUndefined(selectedElements[i])) { trackballElements = !isNullOrUndefined(selectedElements[i].parentNode) ? [].slice.call(selectedElements[0].parentNode.querySelectorAll('.' + className)) : []; if (trackballElements.length > 0) { elements = []; for (var i_1 = 0; i_1 < trackballElements.length; i_1++) { if (trackballElements[i_1].id.indexOf('Trackball') > -1) { elements.push(trackballElements[i_1]); } } this.removeStyles(elements); } } } }; /** * Finds the elements in the chart corresponding to the specified series and data point index. * * @param {Chart} chart - The chart instance. * @param {SeriesModel} series - The series for which to find the elements. * @param {Index} index - The index of the data point. * @param {string} [suffix=''] - A suffix to append to the element IDs. * @param {boolean} [marker] - Specifies whether to include marker elements. * @param {boolean} [dataLabel] - Specifies whether to include datalabel elements. * @returns {Element[]} - An array of elements corresponding to the specified series and data point index. */ Selection.prototype.findElements = function (chart, series, index, suffix, marker, dataLabel) { if (suffix === void 0) { suffix = ''; } if (this.isSeriesMode) { return this.getSeriesElements(series); } else if (this.currentMode === 'Cluster') { return this.getClusterElements(chart, index); } else { return this.getElementByIndex(chart, index, suffix, marker, dataLabel); } }; /** * Checks if the target element is already selected for the specified event type. * * @param {Element} targetElem - The target element to check. * @param {string} eventType - The type of event (e.g., 'mouse move', 'touch move'). * @returns {boolean} - A boolean value indicating whether the target element is already selected for the specified event type. */ Selection.prototype.isAlreadySelected = function (targetElem, eventType) { if (eventType === 'click') { this.currentMode = this.chart.selectionMode; this.styleId = this.chart.element.id + (this.chart.selectionModule && this.chart.selectionMode !== 'None' ? '_ej2_chart_selection' : '_ej2_chart_highlight'); } else if (eventType === 'mousemove' || eventType === 'pointermove') { this.currentMode = this.chart.highlightMode; this.highlightDataIndexes = []; this.styleId = this.chart.element.id + '_ej2_chart_highlight'; } if (this.chart.highlightMode !== 'None' && this.chart.selectionMode === 'None') { if (eventType === 'click') { return false; } } if (((this.chart.highlightMode !== 'None' || this.chart.legendSettings.enableHighlight) && this.previousSelectedEle && this.previousSelectedEle[0])) { var parentNodeId = targetElem.parentNode ? targetElem.parentNode.id : ''; var isElement = void 0; if (targetElem.parentNode) { isElement = (parentNodeId.indexOf('SeriesGroup') > 0 || parentNodeId.indexOf('SymbolGroup') > 0) ? true : false; } for (var i = 0; i < this.previousSelectedEle.length; i++) { if (this.previousSelectedEle[i] && this.previousSelectedEle[i].hasAttribute('class')) { if (this.previousSelectedEle[i].getAttribute('class').indexOf('highlight') > -1 && (isElement || eventType === 'click')) { this.previousSelectedEle[i].removeAttribute('class'); if (this.previousSelectedEle[i].id.indexOf('Group') > 0) { for (var j = 0; j < this.previousSelectedEle[i].children.length; j++) { if (this.chart.highlightColor !== '' && !isNullOrUndefined(this.chart.highlightColor) && this.chart.highlightPattern === 'None') { this.previousSelectedEle[i].children[j].setAttribute('fill', (this.previousSelectedEle[i].children[j].id.indexOf('Text') > -1 || this.previousSelectedEle[i].children[j].id.indexOf('TextShape') > -1) ? this.previousSelectedEle[i].children[j].getAttribute('fill') : this.control.visibleSeries[this.indexFinder(this.previousSelectedEle[i].id).series].interior); } this.previousSelectedEle[i].children[j].removeAttribute('style'); } } else { if (this.chart.highlightColor !== '' && !isNullOrUndefined(this.chart.highlightColor) && this.chart.highlightPattern === 'None') { this.previousSelectedEle[i].setAttribute('fill', (this.previousSelectedEle[i].id.indexOf('Text') > -1 || this.previousSelectedEle[i].id.indexOf('TextShape') > -1) ? this.previousSelectedEle[i].getAttribute('fill') : this.control.visibleSeries[this.indexFinder(this.previousSelectedEle[i].id).series].interior); } this.previousSelectedEle[i].removeAttribute('style'); } this.addOrRemoveIndex(this.highlightDataIndexes, this.indexFinder(this.previousSelectedEle[i].id)); } else if (!isElement && this.previousSelectedEle[i].getAttribute('class').indexOf('highlight') > -1) { this.performSelection(this.indexFinder(this.previousSelectedEle[i].id), this.chart, this.previousSelectedEle[i]); } } } } return true; }; Selection.prototype.mouseClick = function (event) { this.calculateSelectedElements(event.target, event.type, true); if (this.chart.highlightModule && this.chart.highlightModule.highlightDataIndexes && this.chart.highlightModule.highlightDataIndexes.length > 0 && event.target.id.indexOf('_chart_legend_') === -1 && this.chart.isTouch && Browser.isDevice) { this.removeLegendHighlightStyles(); } }; /** * Calculates the selected elements based on the target element and event type. * * @param {HTMLElement} targetElement - The target element for which to calculate selected elements. * @param {string} eventType - The type of event (e.g., 'mouse move', 'touch move'). * @param {boolean} pointClick - Selection of series points. * @returns {void} */ Selection.prototype.calculateSelectedElements = function (targetElement, eventType, pointClick) { if (isNullOrUndefined(targetElement)) { return; } if ((this.chart.selectionMode === 'None' && this.chart.highlightMode === 'None') || targetElement.id && targetElement.id.indexOf(this.chart.element.id + '_') === -1) { return; } if (eventType === 'mousemove' || eventType === 'pointermove') { if (targetElement.hasAttribute('class') && (targetElement.getAttribute('class').indexOf('highlight') > -1 || targetElement.getAttribute('class').indexOf('selection') > -1)) { return; } if (!isNullOrUndefined(targetElement.parentNode) && targetElement.parentNode.hasAttribute('class') && (targetElement.parentNode.getAttribute('class').indexOf('highlight') > 0 || targetElement.parentNode.getAttribute('class').indexOf('selection') > 0)) { return; } } this.isAlreadySelected(targetElement, eventType); if (targetElement.id && targetElement.id.indexOf('_Series_') > -1 && targetElement.id.indexOf('_Text_') === -1) { var element = void 0; if (targetElement.id.indexOf('_Trackball_1') > -1) { element = getElement(targetElement.id.split('_Trackball_')[0] + '_Symbol'); element = isNullOrUndefined(element) ? getElement(targetElement.id.split('_Trackball_')[0]) : element; } else if (targetElement.id.indexOf('_Trackball_0') > -1) { return null; } this.performSelection(this.indexFinder(targetElement.id), this.chart, element || targetElement, pointClick); } }; /** * Performs selection based on the provided index and chart. * * @param {Index} index - The index for which to perform the selection. * @param {Chart} chart - The chart instance. * @param {Element} [element] - Optional. The element associated with the selection. * @param {boolean} pointClick - Selection of series points. * @returns {void} */ Selection.prototype.performSelection = function (index, chart, element, pointClick) { this.isSeriesMode = this.currentMode === 'Series'; if (chart.visibleSeries[index.series].type === 'BoxAndWhisker' && element && element.id === chart.element.id + '_Series_' + index.series + '_Point_' + index.point + '_BoxPath') { element = element.parentNode; } if (chart.visibleSeries[index.series].type === 'Area' && (this.currentMode === 'Point' || this.currentMode === 'Cluster') && element && (element.id === this.chart.element.id + '_Series_' + index.series)) { var className = this.generateStyle(chart.series[index.series]); var selectionEle = document.querySelectorAll('.' + className); this.findTrackballElements(selectionEle, className); this.blurEffect(chart.element.id, chart.visibleSeries, false, index.point); } switch (this.currentMode) { case 'Series': this.selection(chart, index, this.getSeriesElements(chart.series[index.series])); this.selectionComplete(chart, index, this.currentMode); this.blurEffect(chart.element.id, chart.visibleSeries, false, index.point); break; case 'Point': if ((!isNaN(index.point) && element) || (!pointClick && isNaN(index.point))) { var pointElements = []; pointElements.push(element); var series = this.chart.visibleSeries[index.series]; var baseId = chart.element.id + "_Series_" + index.series + "_Point_" + index.point; var textElement = document.getElementById(baseId + "_Text_0"); if (series.marker.dataLabel.visible && textElement !== null) { pointElements.push(textElement); pointElements.push(document.getElementById(baseId + "_TextShape_0")); } if (pointElements[0] !== null && chart.series[index.series].marker.visible && (chart.series[index.series].type.indexOf('Column') !== -1 || chart.series[index.series].type.indexOf('Bar') !== -1)) { if (!(element.id.indexOf('_Symbol') !== -1) && getElement(element.id + '_Symbol')) { pointElements.push(getElement(element.id + '_Symbol')); } else if (element.id.indexOf('_Symbol') !== -1 && getElement(element.id.replace('_Symbol', ''))) { pointElements.push(getElement(element.id.replace('_Symbol', ''))); } } this.selection(chart, index, (!pointClick && isNaN(index.point)) ? this.getSeriesElements(chart.series[index.series]) : pointElements); this.selectionComplete(chart, index, this.currentMode); this.blurEffect(chart.element.id, chart.visibleSeries, false, index.point); } break; case 'Cluster': if (!isNaN(index.point) || (!pointClick && isNaN(index.point))) { if (!pointClick && isNaN(index.point)) { this.selection(chart, index, this.getSeriesElements(chart.series[index.series])); } else { this.clusterSelection(chart, index); } this.selectionComplete(chart, index, this.currentMode); this.blurEffect(chart.element.id, chart.visibleSeries, false, index.point); } break; } }; /** * Completes the selection process based on the provided index and selection mode. * * @param {Chart} chart - The chart instance. * @param {Index} index - The index for which the selection is completed. * @param {SelectionMode | HighlightMode} selectionMode - The selection mode. * @returns {void} */ Selection.prototype.selectionComplete = function (chart, index, selectionMode) { var points; var pointIndex; var seriesIndex; var selectedPointValues = []; var yValue; var selectedPointX; if (selectionMode === 'Cluster') { for (var _i = 0, _a = chart.visibleSeries; _i < _a.length; _i++) { var series = _a[_i]; if (series.visible) { for (var i = 0; i < this.selectedDataIndexes.length; i++) { pointIndex = chart.isMultiSelect ? this.selectedDataIndexes[i].point : index.point; seriesIndex = series.index; points = series.points; if (!isNaN(pointIndex) && (pointIndex < points.length)) { yValue = (series.type !== 'RangeArea' || series.type.indexOf('SplineRangeArea') > -1 || series.type.indexOf('RangeStepArea') > -1) ? points[pointIndex].yValue : points[pointIndex].regions[0].y; selectedPointX = points[pointIndex].xValue; if (chart.primaryXAxis.valueType === 'Category') { selectedPointX = points[pointIndex].x.toLocaleString(); } else if (chart.primaryXAxis.valueType === 'DateTime') { selectedPointX = new Date(points[pointIndex].xValue); } if (series.category !== 'Indicator') { selectedPointValues.push({ x: selectedPointX, y: yValue, seriesIndex: seriesIndex, pointIndex: pointIndex }); } if (series.type === 'RangeArea' || series.type === 'SplineRangeArea' || series.type === 'RangeStepArea') { selectedPointValues.push({ x: selectedPointX, y: points[pointIndex].regions[0].y, seriesIndex: seriesIndex, pointIndex: pointIndex }); } } } } } } else if (selectionMode === 'Series') { if (chart.isMultiSelect) { for (var i = 0; i < this.selectedDataIndexes.length; i++) { seriesIndex = this.selectedDataIndexes[i].series; if (this.selectedDataIndexes.length > 0) { selectedPointValues.push({ seriesIndex: seriesIndex }); } } } else { seriesIndex = (this.selectedDataIndexes.length > 0) ? this.selectedDataIndexes[0].series : (this.highlightDataIndexes && this.highlightDataIndexes.length > 0) ? this.highlightDataIndexes[0].series : 0; if (this.selectedDataIndexes.length > 0 || (this.highlightDataIndexes && this.highlightDataIndexes.length > 0)) { selectedPointValues.push({ seriesIndex: seriesIndex }); } } } else if (selectionMode === 'Point') { var selectedData = []; if (this.styleId.indexOf('highlight') > -1) { selectedData = this.highlightDataIndexes; } else { selectedData = this.selectedDataIndexes; } for (var i = 0; i < selectedData.length; i++) { pointIndex = selectedData[i].point; seriesIndex = selectedData[i].series; var series = chart.series[seriesIndex]; points = series.points; if (!isNaN(pointIndex)) { selectedPointX = points[pointIndex].xValue; yValue = (series.type !== 'RangeArea' || series.type.indexOf('SplineRangeArea') > -1 || series.type.indexOf('RangeStepArea') > -1) ? points[pointIndex].yValue : points[pointIndex].regions[0].y; if (chart.primaryXAxis.valueType === 'Category') { selectedPointX = points[pointIndex].x.toLocaleString(); } else if (chart.primaryXAxis.valueType === 'DateTime') { selectedPointX = new Date(points[pointIndex].xValue); } selectedPointValues.push({ x: selectedPointX, y: yValue, seriesIndex: seriesIndex, pointIndex: pointIndex }); } } } var args = { name: selectionComplete, selectedDataValues: selectedPointValues, cancel: false, chart: chart }; chart.trigger(selectionComplete, args); }; /** * Handles the selection logic for the chart. * * @param {Chart} chart - The chart instance. * @param {Index} index - The index of the selected data point. * @param {Element[]} selectedElements - The elements representing the selected data point. * @returns {void} */ Selection.prototype.selection = function (chart, index, selectedElements) { if (!(this.currentMode === 'Lasso')) { if (!chart.isMultiSelect && (this.currentMode.indexOf('Drag') === -1 && this.styleId.indexOf('highlight') === -1 && chart.selectionMode !== 'None')) { this.removeMultiSelectElements(chart, this.selectedDataIndexes, index, chart.series); } } var indexValue = (this.rangeColorMappingEnabled()) ? 0 : index.series; if (!isNullOrUndefined(selectedElements[0])) { if (chart.visibleSeries[indexValue].isRectSeries) { if (selectedElements[0].id) { if (document.getElementById(selectedElements[0].id + '_Symbol')) { selectedElements.push(getElement(selectedElements[0].id + '_Symbol')); } else if (selectedElements[0].id.indexOf('SeriesGroup') !== -1) { if (document.getElementById(selectedElements[0].id.replace('SeriesGroup', 'SymbolGroup'))) { selectedElements.push(getElement(selectedElements[0].id.replace('SeriesGroup', 'SymbolGroup'))); } } } } var isAdd = void 0; var className = selectedElements[0] && (selectedElements[0].getAttribute('class') || ''); className = className.replace('e-chart-focused', '').trim(); var pClassName = selectedElements[0].parentNode && (selectedElements[0].parentNode.getAttribute('class') || ''); if (className !== '' && this.currentMode !== 'Cluster') { this.findTrackballElements(selectedElements, className); } if (selectedElements[0] && className.indexOf(this.getSelectionClass(selectedElements[0].id)) > -1) { this.removeStyles(selectedElements); } else if (selectedElements[0].parentNode && pClassName.indexOf(this.getSelectionClass(selectedElements[0].id)) > -1) { this.removeStyles([selectedElements[0].parentNode]); } else { this.previousSelectedEle = (chart.highlightMode !== 'None' || chart.legendSettings.enableHighlight) ? selectedElements : []; this.applyStyles(selectedElements); isAdd = true; } if (this.styleId.indexOf('highlight') > 0 && (chart.highlightMode !== 'None' || chart.legendSettings.enableHighlight)) { this.addOrRemoveIndex(this.highlightDataIndexes, index, isAdd); } else { this.addOrRemoveIndex(this.selectedDataIndexes, index, isAdd); } } }; /** * Handles the selection logic for clustered data points in the chart. * * @param {Chart} chart - The chart instance. * @param {Index} index - The index of the selected clustered data point. * @returns {void} */ Selection.prototype.clusterSelection = function (chart, index) { this.selection(chart, index, this.getClusterElements(chart, new Index(index.series, index.point))); }; /** * Removes the multi-selected elements from the chart. * * @param {Chart} chart - The chart instance. * @param {Index[]} index - The indices of the multi-selected elements to be removed. * @param {Index} currentIndex - The index of the current selected element. * @param {SeriesModel[]} seriesCollection - The collection of series in the chart. * @returns {void} */ Selection.prototype.removeMultiSelectElements = function (chart, index, currentIndex, seriesCollection) { var series; for (var i = 0; i < index.length; i++) { series = seriesCollection[index[i].series]; if ((this.isSeriesMode && !this.toEquals(index[i], currentIndex, this.isSeriesMode)) || (this.currentMode === 'Cluster' && !this.toEquals(index[i], currentIndex, false)) || (!this.isSeriesMode && this.toEquals(index[i], currentIndex, true) && !this.toEquals(index[i], currentIndex, false))) { this.removeStyles(this.findElements(chart, series, index[i], '', false)); if (series.marker.visible) { this.removeStyles(this.findElements(chart, series, index[i], '', true)); } if (series.marker.dataLabel.visible) { this.removeStyles(this.findElements(chart, series, index[i], '', false, true)); } index.splice(i, 1); i--; } } }; /** * Applies a blur effect to a specific chart or legend. * * @param {string} chartId - The ID of the chart or legend. * @param {Series[]} visibleSeries - The collection of visible series in the chart. * @param {boolean} isLegend - Indicates whether the blur effect should be applied to a legend. Defaults to false. * @param {number} index - The index of the series or legend item to which the blur effect should be applied. Defaults to 0. * @returns {void} */ Selection.prototype.blurEffect = function (chartId, visibleSeries, isLegend, index) { if (isLegend === void 0) { isLegend = false; } if (index === void 0) { index = 0; } var visibility = (this.checkVisibility(this.highlightDataIndexes, this.chart) || this.checkVisibility(this.selectedDataIndexes, this.chart)); // legend click scenario for (var _i = 0, visibleSeries_1 = visibleSeries; _i < visibleSeries_1.length; _i++) { var series = visibleSeries_1[_i]; var legendIndex = void 0; var legendStrokeColor = void 0; if (this.rangeColorMappingEnabled()) { if (isLegend === false) { legendIndex = Object.keys(series.rangeColorPoints).indexOf(series.points[index].interior); legendStrokeColor = series.points[index].interior; } else { legendIndex = index; legendStrokeColor = document.getElementById(chartId + '_chart_legend_shape_' + index).getAttribute('fill'); } } else { legendIndex = series.index; legendStrokeColor = this.chart.visibleSeries[series.index].interior; } if (series.visible) { this.checkSelectionElements(getElement(chartId + 'SeriesGroup' + series.index), this.generateStyle(series), visibility, isLegend, legendIndex, legendStrokeColor); if (series.marker.dataLabel.visible && !isNullOrUndefined(series.shapeElement)) { this.checkSelectionElements(series.shapeElement, this.generateStyle(series), visibility, isLegend, legendIndex, legendStrokeColor); this.checkSelectionElements(series.textElement, this.generateStyle(series), visibility, isLegend, legendIndex, legendStrokeColor); } if (!isNullOrUndefined(getElement(chartId + 'SymbolGroup' + series.index))) { this.checkSelectionElements(getElement(chartId + 'SymbolGroup' + series.index), this.generateStyle(series), visibility, isLegend, legendIndex, legendStrokeColor); } } } }; /** * Checks and updates the selection state of elements based on the provided criteria. * * @param {Element} element - The element to check for selection. * @param {string} className - The class name used for selecting elements. * @param {boolean} visibility - The visibility state of the element. * @param {boolean} isLegend - Indicates whether the element is a legend. Defaults to true. * @param {number} series - The index of the series associated with the element. Defaults to 0. * @param {string} legendStrokeColor - The stroke color of the legend. Defaults to '#D3D3D3'. * @returns {void} */ Selection.prototype.checkSelectionElements = function (element, className, visibility, isLegend, series, legendStrokeColor) { if (isLegend === void 0) { isLegend = true; } if (series === void 0) { series = 0; } if (legendStrokeColor === void 0) { legendStrokeColor = '#D3D3D3'; } var children = (this.isSeriesMode ? element.childNodes || [element] : element.childNodes || element); if (this.chart.selectionMode !== 'None' && (this.chart.highlightMode !== 'None' || this.chart.legendSettings.enableHighlight)) { children = (element.childNodes || element); } if (this.chart.selectionMode === 'Cluster' && element.tagName.toLowerCase() === 'text' && element.id.indexOf('_Text_') >= 0) { children = [element]; } var elementClassName; var parentClassName; var legendShape; var selectElement = element; var isDataLabelTextElement = (this.chart.visibleSeries[this.rangeColorMappingEnabled() ? 0 : series].marker.dataLabel.visible && (element.id.indexOf('Text') > -1 || element.id.indexOf('TextShape') > -1) && element.tagName !== 'g'); for (var i = 0; i < children.length && !isDataLabelTextElement; i++) { elementClassName = children[i].getAttribute('class') || ''; parentClassName = children[i].parentNode.getAttribute('class') || ''; if (this.chart.selectionMode !== 'None' && (this.chart.highlightMode !== 'None' || this.chart.legendSettings.enableHighlight)) { className = elementClassName.indexOf('selection') > 0 || elementClassName.indexOf('highlight') > 0 ? elementClassName : className; className = (parentClassName.indexOf('selection') > 0 || parentClassName.indexOf('highlight') > 0) ? parentClassName : className; } if (elementClassName.indexOf(className) === -1 && parentClassName.indexOf(className) === -1 && visibility) { this.addSvgClass(children[i], this.unselected); } else { selectElement = children[i]; this.removeSvgClass(children[i], this.unselected); this.removeSvgClass(children[i].parentNode, this.unselected); if (children[i].id !== '' && elementClassName.indexOf(this.unselected) !== -1 && parentClassName.indexOf(className) === -1) { this.highlightAnimation(children[i], this.chart.series.length === 1 ? 0 : this.indexFinder(children[i].id).series, 700, 0.3); } } if (children[i].id.indexOf('Trackball') > 0 && selectElement.classList[0] === className) { this.removeSvgClass(children[i], this.unselected); this.removeSvgClass(children[i].parentNode, this.unselected); this.addSvgClass(children[i], className); } } if (element.id.indexOf('Symbol') > -1) { if ((element.querySelectorAll('.' + className)[0]) && element.querySelectorAll('.' + className)[0].getAttribute('class') === className) { var symbolEle = getElement(this.control.element.id + '_Series_' + element.id[element.id.length - 1]); var seriesClassName = symbolEle && symbolEle.hasAttribute('class') ? symbolEle.getAttribute('class') : ''; if (seriesClassName.indexOf(this.unselected) > -1) { this.removeSvgClass(symbolEle, this.unselected); } } } if (this.control.legendModule && this.control.legendSettings.visible && this.control.legendSettings.visible && !(isLegend && this.rangeColorMappingEnabled && (element === this.control.visibleSeries[0].textElement || element === this.control.visibleSeries[0].shapeElement))) { legendShape = getElement(this.control.element.id + '_chart_legend_shape_' + series); if (legendShape) { if (legendShape.hasAttribute('class')) { this.removeSvgClass(legendShape, legendShape.getAttribute('class')); if (!isNullOrUndefined(this.chart.highlightColor && this.chart.highlightColor !== '') && !this.chart.legendSettings.enableHighlight) { legendShape.setAttribute('stroke', legendStrokeColor); if (this.chart.highlightPattern === 'None') { legendShape.setAttribute('fill', legendStrokeColor); } } } elementClassName = selectElement.getAttribute('class') || ''; parentClassName = selectElement.parentNode.getAttribute('class') || ''; if (elementClassName.indexOf(className) === -1 && parentClassName.indexOf(className) === -1 && visibility) { this.addSvgClass(legendShape, (this.chart.highlightMode === 'None' && this.chart.legendSettings.enableHighlight && (!this.chart.selectionModule || this.chart.selectionModule.selectedDataIndexes.length === 0)) ? className : this.unselected); this.removeSvgClass(legendShape, className); if (this.chart.highlightColor !== '' && !isNullOrUndefined(this.chart.highlightColor)) { legendShape.setAttribute('stroke', this.control.visibleSeries[series].interior); if (this.chart.highlightPattern === 'None') { legendShape.setAttribute('fill', this.control.visibleSeries[series].interior); } } } else { this.removeSvgClass(legendShape, this.unselected); if (!isNullOrUndefined(this.chart.highlightColor) && this.chart.highlightColor !== '') { legendShape.setAttribute('stroke', this.control.visibleSeries[series].interior); if (this.chart.highlightPattern === 'None') { legendShape.setAttribute('fill', this.control.visibleSeries[series].interior); } } if ((elementClassName === '' && parentClassName === '') || elementClassName.trim() === 'EJ2-Trackball') { this.removeSvgClass(legendShape, className); } else { this.addSvgClass(legendShape, className); if (className.indexOf('highlight') > 0 && this.chart.highlightColor !== '' && this.chart.highlightColor !== 'transparent' && !isNullOrUndefined(this.chart.highlightColor)) { legendShape.setAttribute('stroke', this.chart.highlightColor); if (this.styleId.indexOf('highlight') > 0 && this.chart.highlightPattern === 'None') { legendShape.setAttribute('fill', this.chart.highlightColor); } } } } var legendItemsId = void 0; if (this.rangeColorMappingEnabled()) { for (var i = 0; i < this.chart.rangeColorSettings.length; i++) { legendItemsId = document.getElementById(this.chart.element.id + '_chart_legend_shape_' + i); if (legendShape !== legendItemsId) { this.addSvgClass(legendItemsId, this.unselected); this.removeSvgClass(legendItemsId, className); } else if (isLegend === true) { this.addSvgClass(legendItemsId, className); } if (elementClassName.indexOf(className) === -1 && isLegend === false) { this.removeSvgClass(legendItemsId, this.unselected); } } } if (isLegend && parentClassName.indexOf(className) > -1) { this.addSvgClass(legendShape, className); } } } }; /** * Applies styles to the specified elements. * * @param {Element[]} elements - The elements to which styles will be applied. * @returns {void} */ Selection.prototype.applyStyles = function (elements) { for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) { var element = elements_1[_i]; if (element) { this.removeSvgClass(element.parentNode, this.unselected); this.removeSvgClass(element, this.unselected); if (this.chart.series[0].pointColorMapping === 'fill' || this.rangeColorMappingEnabled()) { var className = this.getSelectionClass(element.id); var index = className.indexOf('highlight') > -1 ? parseInt(className.split(this.chart.element.id + '_ej2_chart_highlight_series_')[1], 10) : parseInt(className.split(this.chart.element.id + '_ej2_chart_selection_series_')[1], 10); var patternName = this.styleId.indexOf('highlight') > 0 ? this.chart.highlightPattern : this.chart.selectionPattern; var pattern = void 0; if (className.indexOf('highlight') > -1 || className.indexOf('selection') > -1) { pattern = document.getElementById(this.chart.element.id + '_' + patternName + '_' + 'Selection' + '_' + index); } if (element.id.indexOf('legend') === -1 && element.id.indexOf('Text') === -1 && element.id.indexOf('TextShape') === -1 && element.id.indexOf('Group') === -1 && pattern != null) { for (var i = 1; i < pattern.children.length; i++) { pattern.children[i].setAttribute('fill', element.getAttribute('fill')); pattern.children[i].setAttribute('stroke', element.getAttribute('fill')); } } } this.addSvgClass(element, this.getSelectionClass(element.id)); if (element.id.indexOf('Group') > 0) { var seriesIndex = this.indexFinder(element.id); for (var i = 0; i < element.children.length; i++) { if (element.children[i].nodeName !== 'defs') { this.stopElementAnimation(element.children[i], seriesIndex.series); } } } if (this.styleId.indexOf('highlight') > 0 && this.chart.highlightColor !== '' && !isNullOrUndefined(this.chart.highlightColor) && this.chart.highlightPattern === 'None' && this.chart.highlightColor !== 'transparent') { if (element.id.indexOf('Group') > 0) { for (var i = 0; i < element.children.length; i++) { element.children[i].setAttribute('fill', (element.id.indexOf('Text') > -1 || element.id.indexOf('TextShape') > -1) ? element.children[i].getAttribute('fill') : this.chart.highlightColor); } } else { element.setAttribute('fill', (element.id.indexOf('Text') > -1 || element.id.indexOf('TextShape') > -1) ? element.getAttribute('fill') : this.chart.highlightColor); } } } } }; /** * Gets the CSS class for selection based on the provided identifier. * * @param {string} id - The identifier used to determine the selection class. * @returns {string} - The CSS class for selection. */ Selection.prototype.getSelectionClass = function (id) { return this.generateStyle(this.control.visibleSeries[this.indexFinder(id).series]); }; /** * Removes styles from the provided elements. * *