@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.
1,108 lines • 108 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 __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Component, Property, NotifyPropertyChanges, Internationalization, remove, Complex, Collection, Browser, EventHandler, extend, Animation, animationMode } from '@syncfusion/ej2-base';
import { L10n, isNullOrUndefined, Touch } from '@syncfusion/ej2-base';
import { Event } from '@syncfusion/ej2-base';
import { Rect, Size, SvgRenderer, TextOption, measureText, removeElement } from '@syncfusion/ej2-svg-base';
import { ImageOption, RectOption, appendChildElement, createSvg, getElement, getTextAnchor, getTitle, redrawElement, textElement, titlePositionX, showTooltip, appendClipElement, getAnimationFunction, withInBounds } from '../common/utils/helper';
import { beforeResize, load, pointClick, pointMove, resized } from '../common/model/constants';
import { TitleSettings } from './model/chart3d-Interface';
import { CartesianAxisLayoutPanel } from './axis/cartesian-panel';
import { get3DSeriesColor, get3DThemeColor } from './model/theme';
import { Border, Indexes, Margin } from '../common/model/base';
import { Vector3D, Matrix3D, Graphics3D, BinaryTreeBuilder, Polygon3D, ChartTransform3D, Svg3DRenderer, Chart3DRender } from './utils/chart3dRender';
import { AxisRenderer, WallRenderer } from './utils/renderer';
import { Chart3DAxis, Chart3DColumn, Chart3DRow } from './axis/axis';
import { Data } from '../common/model/data';
import { Chart3DSeries } from './series/chart-series';
import { Chart3DTooltipSettings } from './user-interaction/tooltip';
import { Chart3DLegendSettings } from './legend/legend';
import { PrintUtils } from '../common/utils/print';
/**
* The Chart3D class represents a 3D chart component that extends the Component class
* and implements the INotifyPropertyChanged interface.
*
* @public
* @class
* @extends Component<HTMLElement>
* @implements {INotifyPropertyChanged} INotifyPropertyChanged
*/
var Chart3D = /** @class */ (function (_super) {
__extends(Chart3D, _super);
/**
* Constructor for creating the 3D chart
*
* @param {Chart3DModel} options - Specifies the 3D chart model.
* @param {string | HTMLElement} element - Specifies the element for the 3D chart.
* @hidden
*/
function Chart3D(options, element) {
var _this = _super.call(this, options, element) || this;
_this.previousTargetId = '';
_this.currentPointIndex = 0;
_this.currentSeriesIndex = 0;
_this.currentLegendIndex = 0;
/** @public */
_this.animated = false;
/** @private */
_this.isPointMouseDown = false;
/** @private */
_this.visible = 0;
/** @private */
_this.clickCount = 0;
/** @private */
_this.maxPointCount = 0;
/** @private */
_this.singleClickTimer = 0;
/** @private */
_this.isRtlEnabled = false;
/** @private */
_this.scaleX = 1;
/** @private */
_this.scaleY = 1;
_this.chartId = 57723;
/** @private */
_this.isLegendClicked = false;
/** @private */
_this.rotateActivate = false;
/** @private */
_this.isRemove = false;
/** @private */
_this.polygons = [];
return _this;
}
/**
* Checks if the given elementId has special characters and modifies it if necessary.
*
* @param {string} elementId - The input elementId to be checked.
* @returns {string} - The modified elementId.
*/
Chart3D.prototype.isIdHasSpecialCharacter = function (elementId) {
var regex = /^[A-Za-z ]+$/;
var numberRegex = /^[0-9 ]+$/;
var childElementId = '';
if (!regex.test(elementId)) {
var start = 0;
if (numberRegex.test(elementId[0])) {
childElementId += ('\\3' + elementId[0]);
start = 1;
}
for (var i = start; i < elementId.length; i++) {
if (!regex.test(elementId[i]) && elementId.indexOf('-') === -1 &&
elementId.indexOf('_') === -1 && elementId.indexOf('\\') === -1 && !numberRegex.test(elementId[i])) {
childElementId += ('\\' + elementId[i]);
}
else {
childElementId += elementId[i];
}
}
return childElementId;
}
else {
return elementId;
}
};
/**
* For internal use only - Initialize the event handler;
*
* @returns {void}
*/
Chart3D.prototype.preRender = function () {
this.element.id = this.isIdHasSpecialCharacter(this.element.id);
this.allowServerDataBinding = false;
this.unWireEvents();
this.initPrivateVariable();
this.setCulture();
this.wireEvents();
this.element.setAttribute('dir', this.enableRtl ? 'rtl' : '');
};
/**
* Initializes private variables and prepares the chart component for rendering.
*
* @returns {void}
*/
Chart3D.prototype.initPrivateVariable = function () {
this.delayRedraw = false;
this.animateSeries = true;
this.horizontalAxes = [];
this.verticalAxes = [];
this.polygons = [];
this.vector = new Vector3D(0, 0, 0);
this.wallRender = new WallRenderer();
this.matrixObj = new Matrix3D();
this.bspTreeObj = new BinaryTreeBuilder();
this.polygon = new Polygon3D();
this.graphics = new Graphics3D();
this.transform3D = new ChartTransform3D();
this.svg3DRenderer = new Svg3DRenderer();
this.axisRender = new AxisRenderer();
this.chart3DRender = new Chart3DRender();
this.chartAxisLayoutPanel = new CartesianAxisLayoutPanel(this);
this.refreshAxis();
this.refreshDefinition(this.rows);
this.refreshDefinition(this.columns);
if (this.tooltip3DModule) {
this.tooltip3DModule.previousPoints = [];
}
this.element.setAttribute('role', 'region');
this.element.setAttribute('tabindex', '0');
this.element.style.outline = 'none';
this.element.setAttribute('aria-label', this.description || this.title + '. Syncfusion interactive chart.');
if (!(this.element.classList.contains('e-chart-focused'))) {
this.element.setAttribute('class', this.element.getAttribute('class') + ' e-chart-focused');
}
if (this.element.id === '') {
var collection = document.getElementsByClassName('e-chart').length;
this.element.id = 'chart_' + this.chartId + '_' + collection;
}
this.svgId = this.element.id + '_svg';
};
/**
* Method to set culture for chart.
*
* @returns {void}
*/
Chart3D.prototype.setCulture = function () {
this.intl = new Internationalization();
this.localeObject = new L10n(this.getModuleName(), this.defaultLocalConstants, this.locale);
};
/**
* To Initialize the 3D chart rendering.
*
* @returns {void}
*/
Chart3D.prototype.render = function () {
var _this = this;
this.svgRenderer = new SvgRenderer(this.element.id);
var loadEventData = {
chart: this, theme: this.theme, cancel: false
};
/**
* Load event for the 3D chart componet.
*/
this.trigger(load, loadEventData, function () {
if (!loadEventData.cancel) {
_this.cartesianChartRendering();
}
});
};
/**
* Renders the chart using a Cartesian coordinate system.
*
* This function is responsible for rendering the chart's graphical elements and data points using a Cartesian coordinate system.
* It may include actions such as drawing axes, plotting data, and applying visual styles.
*
* @returns {void}
*/
Chart3D.prototype.cartesianChartRendering = function () {
this.setTheme();
this.createChartSvg();
this.calculateVisibleSeries();
this.calculateVisibleAxis();
this.processData();
this.renderComplete();
this.allowServerDataBinding = true;
};
/**
* Method to create SVG element.
*
* @returns {void}
*/
Chart3D.prototype.createChartSvg = function () {
this.removeSvg();
createSvg(this);
};
/**
* Method to remove the SVG.
*
* @returns {void}
* @private
*/
Chart3D.prototype.removeSvg = function () {
if (this.redraw) {
return null;
}
removeElement(this.element.id + '_Secondary_Element');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (this.isReact) {
this.clearTemplate();
}
var removeLength = 0;
if (this.svgObject) {
while (this.svgObject.childNodes.length > removeLength) {
this.svgObject.removeChild(this.svgObject.firstChild);
}
if (!this.svgObject.hasChildNodes() && this.svgObject.parentNode) {
remove(this.svgObject);
}
}
};
/**
* Processes and prepares data for rendering.
*
* @param {boolean} render - (Optional) Indicates whether to trigger rendering after data processing.
* @returns {void}
*/
Chart3D.prototype.processData = function (render) {
if (render === void 0) { render = true; }
this.visibleSeriesCount = 0;
var check = true;
for (var _i = 0, _a = this.visibleSeries; _i < _a.length; _i++) {
var series = _a[_i];
if (!series.visible && !this.legendSettings.visible) {
this.visibleSeriesCount++;
continue;
}
this.initializeDataModule(series);
}
if (render && (!this.visibleSeries.length || this.visibleSeriesCount === this.visibleSeries.length && check)) {
this.refreshBound();
this.trigger('loaded', { chart: this });
}
};
/**
* Initializes the data module for a three-dimensional series.
*
* @param {Chart3DSeries} series - The series for which data module is initialized.
* @returns {void}
*/
Chart3D.prototype.initializeDataModule = function (series) {
series.xData = [];
series.yData = [];
var dataSource;
var isAngular = 'isAngular';
if (this[isAngular]) {
dataSource = Object.keys(series.dataSource).length ? series.dataSource : this.dataSource;
}
else {
dataSource = series.dataSource || this.dataSource;
}
series.dataModule = new Data(dataSource, series.query);
series.points = [];
series.refreshDataManager(this);
};
/**
* Animate the series bounds.
*
* @param {number} duration - Specifies the duration of the animation.
* @private
* @returns {void}
*/
Chart3D.prototype.animate = function (duration) {
this.redraw = true;
this.animated = true; //used to set duration as 1000 for animation at default 300
this.duration = duration ? duration : 1000;
};
/**
* Refresh the chart bounds.
*
* @private
* @returns {void}
*/
Chart3D.prototype.refreshBound = function () {
if (this.legend3DModule && this.legendSettings.visible) {
this.legend3DModule.getLegendOptions(this.visibleSeries, this);
}
if (this.tooltip.enable && this.tooltip3DModule) {
this.tooltip3DModule.previousPoints = [];
}
this.calculateStackValues();
this.calculateBounds();
this.renderElements();
removeElement('chartmeasuretext');
this.removeSelection();
};
/**
* Clears the selection state in the chart.
*
* @returns {void}
*/
Chart3D.prototype.removeSelection = function () {
for (var _i = 0, _a = this.visibleSeries; _i < _a.length; _i++) {
var series = _a[_i];
if (series.visible) {
for (var _b = 0, _c = series.points; _b < _c.length; _b++) {
var point = _c[_b];
point.isSelect = false;
}
}
}
};
/**
* Calculates stacked values for three-dimensional series in the chart.
*
* @returns {void}
*/
Chart3D.prototype.calculateStackValues = function () {
var series;
var isCalculateStacking = false;
for (var i = 0, len = this.visibleSeries.length; i < len; i++) {
series = this.visibleSeries[i];
series.position = series.rectCount = undefined;
if (((series.type.indexOf('Stacking') !== -1)) && !isCalculateStacking) {
series.calculateStackedValue(series.type.indexOf('100') > -1, this);
isCalculateStacking = true;
}
}
};
/**
* Calculates the bounds and dimensions for the chart area.
*
* @returns {void}
*/
Chart3D.prototype.calculateBounds = function () {
var margin = this.margin;
// Title Height;
var titleHeight = 0;
var subTitleHeight = 0;
var titleWidth = 0;
var padding = this.titleStyle.position === 'Top' || (this.titleStyle.position === 'Bottom') ? 15 : 5;
var left = margin.left + this.border.width;
var width = this.availableSize.width - left - margin.right - this.border.width;
var elementSpacing = 0;
var top = margin.top + this.border.width;
var height = this.availableSize.height - top - this.border.width - margin.bottom;
this.titleCollection = [];
this.subTitleCollection = [];
if (this.title) {
this.titleCollection = getTitle(this.title, this.titleStyle, (this.titleStyle.position === 'Left' || this.titleStyle.position === 'Right' ? height : width), this.enableRtl, this.themeStyle.chartTitleFont);
titleHeight = (measureText(this.title, this.titleStyle, this.themeStyle.chartTitleFont).height * this.titleCollection.length) + padding;
if (this.subTitle) {
var maxWidth = 0;
for (var _i = 0, _a = this.titleCollection; _i < _a.length; _i++) {
var titleText = _a[_i];
titleWidth = measureText(titleText, this.titleStyle, this.themeStyle.chartSubTitleFont).width;
maxWidth = titleWidth > maxWidth ? titleWidth : maxWidth;
}
this.subTitleCollection = getTitle(this.subTitle, this.subTitleStyle, maxWidth, this.enableRtl, this.themeStyle.chartSubTitleFont);
subTitleHeight = (measureText(this.subTitle, this.subTitleStyle, this.themeStyle.chartSubTitleFont).height * this.subTitleCollection.length) +
padding;
}
}
else if (this.legendSettings.position !== 'Top' && this.border.width) {
elementSpacing = 10;
}
top = margin.top + elementSpacing + this.border.width;
height = this.availableSize.height - top - this.border.width - margin.bottom;
var marginTotal = subTitleHeight + titleHeight + this.titleStyle.border.width + this.subTitleStyle.border.width;
switch (this.titleStyle.position) {
case 'Top':
top += marginTotal;
height -= marginTotal;
break;
case 'Bottom':
height -= marginTotal;
break;
case 'Left':
left += marginTotal;
width -= marginTotal;
break;
case 'Right':
left -= (this.titleStyle.border.width + this.subTitleStyle.border.width);
width -= marginTotal;
break;
}
this.initialClipRect = new Rect(left, top, width, height);
if (this.legend3DModule && this.legendSettings.visible) {
this.legend3DModule.calculateLegendBounds(this.initialClipRect, this.availableSize, null);
}
this.chartAxisLayoutPanel.measureAxis(this.initialClipRect);
};
/**
* Renders various chart elements, including the border, title, series, legend, and datalabel etc.
*
* @returns {void}
*/
Chart3D.prototype.renderElements = function () {
this.renderBorder();
this.renderTitle();
this.createSeriesElements();
this.render3DChart();
this.renderLegend();
this.performSelection();
this.setSecondaryElementPosition();
this.doAnimation();
};
/**
* Animates the height of an SVG element.
*
* @param {HTMLElement} element - The SVG element to animate.
* @param {Chart3DSeries} series - The series related to the animation.
* @param {Chart3DPoint} point - The point related to the animation.
* @param {HTMLElement} dataLabelElement - The data label element related to the animation.
* @param {HTMLElement} shapeElement - The shape element related to the animation.
* @param {HTMLElement} templateElement - The template element related to the animation.
* @returns {void}
*/
Chart3D.prototype.animateRect = function (element, series, point, dataLabelElement, shapeElement, templateElement) {
var option = series.animation;
var duration = series.chart.animated ? series.chart.duration : option.duration;
var effect = getAnimationFunction('Linear');
var elementHeight = element.getAttribute('height') ? +element.getAttribute('height') : 0;
var elementWidth = element.getAttribute('width') ? +element.getAttribute('width') : 0;
var isPlot = point.yValue < 0;
var centerX;
var centerY;
var x = +element.getAttribute('x');
var y = +element.getAttribute('y');
if (!series.chart.requireInvertedAxis) {
centerY = (isPlot !== series.yAxis.isAxisInverse) ? y : y + elementHeight;
centerX = isPlot ? x : x + elementWidth;
}
else {
if (series.type.indexOf('Stacking') > -1) {
centerX = x;
centerY = y;
}
else {
centerY = isPlot ? y : y + elementHeight;
centerX = (isPlot !== series.yAxis.isAxisInverse) ? x + elementWidth : x;
}
}
var value;
if (!isNullOrUndefined(element)) {
element.style.visibility = 'hidden';
if (dataLabelElement) {
dataLabelElement.style.visibility = 'hidden';
}
if (shapeElement) {
shapeElement.style.visibility = 'hidden';
}
if (templateElement) {
templateElement.style.visibility = 'hidden';
}
new Animation({}).animate(element, {
duration: (duration === 0 && animationMode === 'Enable') ? 1000 : duration,
delay: option.delay,
progress: function (args) {
if (args.timeStamp >= args.delay) {
element.style.visibility = 'visible';
if (!series.chart.requireInvertedAxis) {
elementHeight = elementHeight ? elementHeight : 1;
value = effect(args.timeStamp - args.delay, 0, elementHeight, args.duration);
element.setAttribute('transform', 'translate(' + centerX + ' ' + centerY +
') scale(1,' + (value / elementHeight) + ') translate(' + (-centerX) + ' ' + (-centerY) + ')');
}
else {
elementWidth = elementWidth ? elementWidth : 1;
value = effect(args.timeStamp - args.delay, 0, elementWidth, args.duration);
element.setAttribute('transform', 'translate(' + centerX + ' ' + centerY +
') scale(' + (value / elementWidth) + ', 1) translate(' + (-centerX) + ' ' + (-centerY) + ')');
}
}
},
end: function () {
element.setAttribute('transform', 'translate(0,0)');
if (dataLabelElement) {
dataLabelElement.style.visibility = 'visible';
}
if (shapeElement) {
shapeElement.style.visibility = 'visible';
}
if (templateElement) {
templateElement.style.visibility = 'visible';
}
series.chart.trigger('animationComplete', { series: series });
}
});
}
};
/**
* Animates the series.
*
* @returns {void}
*/
Chart3D.prototype.doAnimation = function () {
var _this = this;
var _loop_1 = function (i) {
var series = this_1.visibleSeries[i];
if (series.visible && series.animation.enable && this_1.animateSeries && !this_1.rotateActivate) {
var dataLabelElement = void 0;
var shapeElement = void 0;
var templateElement = void 0;
var options = new RectOption(this_1.element.id + '_ChartSeriesClipRect_' + i, 'transparent', { width: 1, color: 'Gray' }, 1, {
x: 0, y: 0,
width: this_1.availableSize.width,
height: this_1.availableSize.height
});
var clipRectElement = appendClipElement(this_1.redraw, options, this_1.svgRenderer);
appendChildElement(false, this_1.chart3D, clipRectElement.children[0], this_1.redraw);
for (var k = 0; series.visiblePoints && k < series.visiblePoints.length; k++) {
var point = series.visiblePoints[k];
var elements = document.querySelectorAll("[id*=\"region-series-" + i + "\"]");
elements.forEach(function (element) {
element.setAttribute('clip-path', 'url(#' + _this.element.id + '_ChartSeriesClipRect_' + i + ')');
});
if (series.dataLabel.visible) {
dataLabelElement = getElement(this_1.element.id + '-svg-series-' + series.index + '-point-' + k + '-data-label');
shapeElement = getElement(this_1.element.id + '-svg-data-label-series-' + series.index + '-point-' + k);
templateElement = getElement(this_1.element.id + '-series-' + series.index + '-data-label-' + k);
}
this_1.animateRect(document.getElementById(this_1.element.id + '_ChartSeriesClipRect_' + i).children[0], series, point, dataLabelElement, shapeElement, templateElement);
}
}
};
var this_1 = this;
for (var i = 0; i < this.visibleSeries.length; i++) {
_loop_1(i);
}
};
/**
* Performs data selection based on selected data indexes.
*
* @returns {void}
*/
Chart3D.prototype.performSelection = function () {
var selectedDataIndexes = [];
if (this.selection3DModule) {
selectedDataIndexes = extend([], this.selection3DModule.selectedDataIndexes, null, true);
this.selection3DModule.invokeSelection(this);
}
if (this.highlight3DModule) {
this.highlight3DModule.invokeHighlight(this);
}
if ((!this.highlight3DModule || (this.legendSettings.enableHighlight && this.highlightMode === 'None')) && this.tooltip3DModule) {
this.tooltip3DModule.seriesStyles();
}
if (selectedDataIndexes.length > 0) {
this.selection3DModule.selectedDataIndexes = selectedDataIndexes;
this.selection3DModule.redrawSelection(this, this.selectionMode);
}
};
/**
* To render the legend.
*
* @returns {void}
*/
Chart3D.prototype.renderLegend = function () {
if (this.legend3DModule && this.legend3DModule.legendCollections.length && this.legendSettings.visible) {
this.legend3DModule.calTotalPage = true;
var bounds = this.legend3DModule.legendBounds;
this.legend3DModule.renderLegend(this, this.legendSettings, bounds);
}
if (!this.redraw) {
this.element.appendChild(this.svgObject);
}
};
/**
* To set the left and top position for secondary element in chart.
*
* @returns {void}
*/
Chart3D.prototype.setSecondaryElementPosition = function () {
var element = getElement(this.element.id + '_Secondary_Element');
if (!element) {
return;
}
var rect = this.element.getBoundingClientRect();
var svgRect = getElement(this.svgId).getBoundingClientRect();
element.style.left = Math.max(svgRect.left - rect.left, 0) + 'px';
element.style.top = Math.max(svgRect.top - rect.top, 0) + 'px';
};
/**
* Initializes module-specific elements and settings for the chart.
*
* @returns {void}
*/
Chart3D.prototype.initializeModuleElements = function () {
this.dataLabelCollections = [];
var elementId = this.element.id;
if (this.series.length) {
this.seriesElements = this.svgRenderer.createGroup({ id: elementId + 'SeriesCollection' });
}
this.dataLabelElements = this.renderer.createGroup({ id: elementId + 'DataLabelCollection' });
};
/**
* Renders elements specific to chart series.
*
* @returns {void}
*/
Chart3D.prototype.createSeriesElements = function () {
// Initialize the series elements values
this.initializeModuleElements();
var elementId = this.element.id;
var tooltipDiv = redrawElement(this.redraw, elementId + '_Secondary_Element') ||
this.createElement('div');
tooltipDiv.id = elementId + '_Secondary_Element';
tooltipDiv.style.cssText = 'position: relative';
appendChildElement(false, this.element, tooltipDiv, this.redraw);
// For userInteraction
if (this.tooltip.enable) {
appendChildElement(false, this.svgObject, this.renderer.createGroup({ id: elementId + '_UserInteraction', style: 'pointer-events:none;' }), this.redraw);
}
};
/**
* Renders the chart title.
*
* @returns {void}
*/
Chart3D.prototype.renderTitle = function () {
var rect;
var margin = this.margin;
var elementSpacing = 5;
if (this.title) {
var getAnchor = getTextAnchor(this.titleStyle.textAlignment, this.enableRtl);
var elementSize = measureText(this.title, this.titleStyle, this.themeStyle.chartTitleFont);
rect = new Rect(margin.left, 0, this.availableSize.width - margin.left - margin.right, 0);
var borderWidth = this.titleStyle.border.width;
var positionY = this.margin.top + ((elementSize.height) * 3 / 4);
var positionX = titlePositionX(rect, this.titleStyle || this.themeStyle.chartTitleFont) + borderWidth;
var rotation = void 0;
var alignment = this.titleStyle.textAlignment;
var subtitleSize = measureText(this.subTitle, this.subTitleStyle, this.themeStyle.chartSubTitleFont);
switch (this.titleStyle.position) {
case 'Top':
positionY += borderWidth * 0.5;
positionX += getAnchor === 'start' ? borderWidth * 0.5 + this.border.width :
getAnchor === 'end' ? ((-borderWidth * 2) - this.border.width) : 0;
break;
case 'Bottom':
positionX += getAnchor === 'start' ? (borderWidth * 0.5) + this.border.width :
getAnchor === 'end' ? (-borderWidth * 2) - this.border.width : 0;
positionY = this.availableSize.height - this.margin.bottom - subtitleSize.height - (elementSize.height / 2) -
(borderWidth * 0.5) - (this.subTitleStyle.border.width * 0.5);
break;
case 'Left':
positionX = this.margin.left + ((elementSize.height) * 3 / 4) + (borderWidth * 0.5);
positionY = alignment === 'Near' ? margin.bottom + (borderWidth * 0.5) + this.border.width :
alignment === 'Far' ? this.availableSize.height - margin.bottom - (borderWidth * 0.5) - this.border.width : this.availableSize.height / 2;
getAnchor = alignment === 'Near' ? 'end' : alignment === 'Far' ? 'start' : 'middle';
getAnchor = this.enableRtl ? (getAnchor === 'end' ? 'start' : getAnchor === 'start' ? 'end' : getAnchor) : getAnchor;
rotation = 'rotate(' + -90 + ',' + positionX + ',' + positionY + ')';
break;
case 'Right':
positionX = this.availableSize.width - this.margin.right - ((elementSize.height) * 3 / 4) - (borderWidth * 0.5);
positionY = alignment === 'Near' ? margin.bottom + (borderWidth * 0.5) + this.border.width :
alignment === 'Far' ? this.availableSize.height - margin.bottom - (borderWidth * 0.5) - this.border.width : this.availableSize.height / 2;
getAnchor = alignment === 'Near' ? 'start' : alignment === 'Far' ? 'end' : 'middle';
getAnchor = this.enableRtl ? (getAnchor === 'end' ? 'start' : getAnchor === 'start' ? 'end' : getAnchor) : getAnchor;
rotation = 'rotate(' + 90 + ',' + positionX + ',' + positionY + ')';
break;
case 'Custom':
positionX = this.titleStyle.x;
positionY = this.titleStyle.y;
getAnchor = 'middle';
break;
}
var borderOptions = {
'id': this.element.id + '-chart-title-border',
'x': positionX - (getAnchor === 'middle' ? (elementSize.width / 2) + elementSpacing : getAnchor === 'end' ? elementSize.width + elementSpacing : elementSpacing),
'y': positionY - elementSize.height + (elementSize.height / 4),
'rx': this.titleStyle.border.cornerRadius,
'ry': this.titleStyle.border.cornerRadius,
'width': elementSize.width + (elementSpacing * 2),
'height': elementSize.height * this.titleCollection.length,
'fill': this.titleStyle.background,
'stroke-width': borderWidth,
'stroke': this.titleStyle.border.color,
'transform': rotation ? rotation : ''
};
var htmlObject = redrawElement(this.redraw, this.element.id + '-chart-title-border', borderOptions, this.renderer)
|| this.renderer.drawRectangle(borderOptions);
appendChildElement(false, this.svgObject, htmlObject, this.redraw);
var options = new TextOption(this.element.id + '-chart-title', positionX, positionY, getAnchor, this.titleCollection, rotation, 'auto');
var element = redrawElement(this.redraw, this.element.id + '-chart-title', options, this.renderer) ||
textElement(this.renderer, options, this.titleStyle, this.titleStyle.color || this.themeStyle.chartTitleFont.color, this.svgObject, null, null, null, null, null, null, null, null, false, null, this.themeStyle.chartTitleFont);
if (element) {
element.setAttribute('tabindex', '0');
element.style.outline = 'none';
element.setAttribute('class', 'e-chart-focused');
}
if (this.subTitle) {
this.renderSubTitle(options);
}
}
};
/**
* Renders the chart sub title.
*
* @param {TextOption} options - Specifies the text option.
* @returns {void}
*/
Chart3D.prototype.renderSubTitle = function (options) {
var maxWidth = 0;
var titleWidth = 0;
var padding = 10;
var alignment = this.titleStyle.textAlignment;
for (var _i = 0, _a = this.titleCollection; _i < _a.length; _i++) {
var titleText = _a[_i];
titleWidth = measureText(titleText, this.titleStyle, this.themeStyle.chartTitleFont).width;
maxWidth = titleWidth > maxWidth ? titleWidth : maxWidth;
}
var subTitleElementSize = measureText(this.subTitleCollection.
reduce(function (a, b) { return (a.length > b.length ? a : b); }), this.subTitleStyle, this.themeStyle.chartSubTitleFont);
var getAnchor = getTextAnchor(this.subTitleStyle.textAlignment, this.enableRtl);
var rect = new Rect(alignment === 'Center' ? (options.x - maxWidth * 0.5) : alignment === 'Far' ? options.x - maxWidth : options.x, 0, maxWidth, 0);
if (this.titleStyle.position === 'Left') {
rect.x = alignment === 'Center' ? (options.x - maxWidth * 0.5) : alignment === 'Far' ? this.margin.left + ((subTitleElementSize.height) * 3 / 4) : (options.x - maxWidth);
}
var elementSize = measureText(this.title, this.titleStyle, this.themeStyle.chartTitleFont);
var positionY = options.y * options.text.length + subTitleElementSize.height + (padding / 2) +
this.titleStyle.border.width + (this.subTitleStyle.border.width * 0.5);
if (this.titleStyle.position === 'Bottom') {
positionY = options.y * options.text.length + (padding / 2) + (elementSize.height / 2) + (subTitleElementSize.height / 2);
}
var borderOptions = {
'id': this.element.id + '-chart-sub-title-border',
'x': titlePositionX(rect, this.subTitleStyle) - (getAnchor === 'middle' ? (subTitleElementSize.width / 2) + padding / 2 : getAnchor === 'end' ? subTitleElementSize.width + padding / 2 : padding / 2),
'y': positionY - subTitleElementSize.height + (subTitleElementSize.height / 4),
'rx': this.subTitleStyle.border.cornerRadius,
'ry': this.subTitleStyle.border.cornerRadius,
'width': subTitleElementSize.width + padding,
'height': subTitleElementSize.height * this.subTitleCollection.length,
'fill': this.subTitleStyle.background,
'stroke-width': this.subTitleStyle.border.width,
'stroke': this.subTitleStyle.border.color,
'transform': options.transform
};
var htmlObject = redrawElement(this.redraw, this.element.id + '-chart-sub-title-border', borderOptions, this.renderer)
|| this.renderer.drawRectangle(borderOptions);
appendChildElement(false, this.svgObject, htmlObject, this.redraw);
var subTitleOptions = new TextOption(this.element.id + '-chart-sub-title', titlePositionX(rect, this.subTitleStyle), positionY, getTextAnchor(this.subTitleStyle.textAlignment, this.enableRtl), this.subTitleCollection, options.transform, 'auto');
var element = redrawElement(this.redraw, this.element.id + '-chart-sub-title', subTitleOptions, this.renderer) ||
textElement(this.renderer, subTitleOptions, this.subTitleStyle, this.subTitleStyle.color || this.themeStyle.chartSubTitleFont.color, this.svgObject, null, null, null, null, null, null, null, null, false, null, this.themeStyle.chartSubTitleFont);
};
/**
* Renders the chart border.
*
* @returns {void}
*/
Chart3D.prototype.renderBorder = function () {
var x = 0;
var y = 0;
var width = this.border.width;
var backGroundImage = this.backgroundImage;
var fillColor = backGroundImage ? 'transparent' : (this.background || this.themeStyle.background);
var rect = new RectOption(this.element.id + '-chart-border', fillColor, this.border, 1, new Rect(width * 0.5 + x, width * 0.5 + y, this.availableSize.width - width, this.availableSize.height - width), 0, 0, '', this.border.dashArray);
this.htmlObject = redrawElement(this.redraw, this.element.id + '-chart-border', rect, this.renderer)
|| this.renderer.drawRectangle(rect);
this.htmlObject.setAttribute('aria-hidden', 'true');
appendChildElement(false, this.svgObject, this.htmlObject, this.redraw);
// to draw back ground image for chart
if (backGroundImage) {
var image = new ImageOption(this.availableSize.height - width, this.availableSize.width - width, backGroundImage, 0, 0, this.element.id + '-chart-background', 'visible', 'none');
this.htmlObject = redrawElement(this.redraw, this.element.id + '-chart-background', image, this.renderer)
|| this.renderer.drawImage(image);
appendChildElement(false, this.svgObject, this.htmlObject, this.redraw);
}
};
/**
* To provide the array of modules needed for control rendering
*
* @returns {ModuleDeclaration[]} - Array of modules needed for control rendering
* @private
*/
Chart3D.prototype.requiredModules = function () {
var _this = this;
var modules = [];
var series = this.series;
var moduleName;
var dataLabelEnable = false;
if (this.tooltip.enable) {
modules.push({
member: 'Tooltip3D',
args: [this]
});
}
series.map(function (value) {
_this.isLegend = (_this.legendSettings.visible && ((value.name !== '') || !!_this.isLegend));
moduleName = value.type.indexOf('100') !== -1 ? value.type.replace('100', '') + 'Series3D' : value.type + 'Series3D';
dataLabelEnable = value.dataLabel.visible || dataLabelEnable;
if (!modules.some(function (currentModule) {
return currentModule.member === moduleName;
})) {
modules.push({
member: moduleName,
args: [_this, series]
});
}
});
if (dataLabelEnable) {
modules.push({
member: 'DataLabel3D',
args: [this, series]
});
}
modules = this.findAxisModule(modules);
if (this.isLegend) {
modules.push({
member: 'Legend3D',
args: [this]
});
}
if (this.enableExport) {
modules.push({
member: 'Export3D',
args: [this]
});
}
if (this.selectionMode !== 'None') {
modules.push({
member: 'Selection3D',
args: [this]
});
}
if (this.highlightMode !== 'None' || this.legendSettings.enableHighlight) {
modules.push({
member: 'Highlight3D',
args: [this]
});
}
return modules;
};
/**
* Finds axis modules within a collection of module declarations.
*
* @param {ModuleDeclaration[]} modules - The collection of module declarations to search for axis modules.
* @returns {ModuleDeclaration[]} - An array of module declarations representing axis modules.
*/
Chart3D.prototype.findAxisModule = function (modules) {
var axisCollections = [];
axisCollections.push(this.primaryXAxis);
axisCollections.push(this.primaryYAxis);
axisCollections = axisCollections.concat(this.axes);
var datetimeEnabled = false;
var categoryEnabled = false;
var logarithmicEnabled = false;
var dateTimeCategoryEnabled = false;
for (var _i = 0, axisCollections_1 = axisCollections; _i < axisCollections_1.length; _i++) {
var axis = axisCollections_1[_i];
datetimeEnabled = axis.valueType === 'DateTime' || datetimeEnabled;
categoryEnabled = axis.valueType === 'Category' || categoryEnabled;
logarithmicEnabled = axis.valueType === 'Logarithmic' || logarithmicEnabled;
dateTimeCategoryEnabled = axis.valueType === 'DateTimeCategory' || dateTimeCategoryEnabled;
}
if (datetimeEnabled) {
modules.push({
member: 'DateTime3D',
args: [this]
});
}
if (categoryEnabled) {
modules.push({
member: 'Category3D',
args: [this]
});
}
if (logarithmicEnabled) {
modules.push({
member: 'Logarithmic3D',
args: [this]
});
}
if (dateTimeCategoryEnabled) {
modules.push({
member: 'DateTimeCategory3D',
args: [this]
});
}
return modules;
};
/**
* Sets the theme for the chart.
*
* @returns {void}
*/
Chart3D.prototype.setTheme = function () {
/** Set theme */
this.themeStyle = get3DThemeColor(this.theme);
};
/**
* Handles to set style for key event on the document.
*
* @param {target} target - element which currently focused.
* @returns {void}
* @private
*/
Chart3D.prototype.setNavigationStyle = function (target) {
var currentElement = document.getElementById(target);
if (currentElement) {
currentElement.style.setProperty('outline', "1.5px solid " + this.themeStyle.tabColor);
}
};
/**
* Handles to remove style for key event on the document.
*
* @returns {void}
* @private
*/
Chart3D.prototype.removeNavigationStyle = function () {
var currentElement = document.querySelectorAll("[id*=_Point_], [id*=" + this.element.id + "], [id*=_ChartBorder], text[id*=_ChartTitle],g[id*=_chart_legend], text[id*=_ChartSubTitle], div[id*=_Annotation]");
if (currentElement) {
currentElement.forEach(function (element) {
if (element instanceof HTMLElement || element instanceof SVGElement) {
element.style.setProperty('outline', 'none');
}
});
}
};
/**
* Renders the three-dimensional chart, creating a 3D visualization.
*
* The function sets up a 3D perspective, depth, rotation, and tilt to create a 3D visualization of the chart.
*
* @returns {void}
*/
Chart3D.prototype.render3DChart = function () {
this.chart3D = this.svgRenderer.createGroup({ 'id': this.element.id + '-svg-chart-3d' });
this.chart3D.setAttribute('role', 'region');
this.chart3D.setAttribute('aria-hidden', 'false');
this.draw3DAxis();
this.wallRender.update3DWall(this);
this.renderSeries();
appendChildElement(false, this.svgObject, this.chart3D, this.redraw);
var size = new Size(this.availableSize.width, this.availableSize.height);
this.graphics.prepareView(this.perspectiveAngle, this.depth, this.rotation, this.tilt, size, this);
this.graphics.view(this.svgObject, this);
};
/**
* Draws three-dimensional axes for the chart.
*
* @returns {void}
*/
Chart3D.prototype.draw3DAxis = function () {
for (var i = 0; i < this.axisCollections.length; i++) {
this.axisRender.drawAxes(i, this.axisCollections[i], this);
}
};
/**
* Renders chart series elements.
*
* @private
* @returns {void}
*/
Chart3D.prototype.renderSeries = function () {
var visibility;
for (var _i = 0, _a = this.visibleSeries; _i < _a.length; _i++) {
var item = _a[_i];
visibility = item.visible;
if (visibility) {
this.visible++;
item.renderSeries(this);
}
}
this.visible = 0;
};
/**
* Initializes the configuration for an axis within a three-dimensional chart series.
*
* @param {Chart3DSeries} series - The series to which the axis belongs.
* @param {Chart3DAxis} axis - The axis to be configured and initialized.
* @param {boolean} isSeries - Indicates whether the axis configuration is for the series.
* @returns {void}
*/
Chart3D.prototype.initAxis = function (series, axis, isSeries) {
if (series.xAxisName === axis.name || (series.xAxisName == null && axis.name === 'primaryXAxis')) {
axis.orientation = this.requireInvertedAxis ? 'Vertical' : 'Horizontal';
series.xAxis = axis;
if (isSeries) {
axis.series.push(series);
}
}
else if (series.yAxisName === axis.name || (series.yAxisName == null && axis.name === 'primaryYAxis')) {
axis.orientation = this.requireInvertedAxis ? 'Horizontal' : 'Vertical';
series.yAxis = axis;
if (isSeries) {
axis.series.push(series);
}
}
};
/**
* Calculate the visible axis.
*
* @private
* @returns {void}
*/
Chart3D.prototype.calculateVisibleAxis = function () {
var axis;
var axes = [this.primaryXAxis, this.primaryYAxis];
axes = axes.concat(this.axes);
this.axisCollections = [];
for (var i = 0, len = axes.length; i < len; i++) {
axis = axes[i];
axis.series = [];
axis.labels = [];
axis.indexLabels = {};
axis.orientation = (i === 0) ? (this.requireInvertedAxis ? 'Vertical' : 'Horizontal') :
(i === 1) ? (this.requireInvertedAxis ? 'Horizontal' : 'Vertical') : axis.orientation;
for (var _i = 0, _a = this.visibleSeries; _i < _a.length; _i++) {
var series = _a[_i];
this.initAxis(series, axis, true);
}
if (axis.orientation != null) {
this.axisCollections.push(axis);
}
}
if (this.rows.length > 0 && this.columns.length > 0) {
this.chartAxisLayoutPanel.measure();
}
};
/**
* Unbinding events from the element while component destroy.
*
* @hidden
* @returns {void}
*/
Chart3D.prototype.unWireEvents = function () {
var startEvent = Browser.touchStartEvent;
var moveEvent = Browser.touchMoveEvent;
var stopEvent = Browser.touchEndEvent;
var cancelEvent = Browser.isPointer ? 'pointerleave' : 'mouseleave';
/** UnBind the Event handler */
EventHandler.remove(this.element, startEvent, this.chartOnMouseDown);
EventHandler.remove(this.element, moveEvent, this.mouseMove);
EventHandler.remove(this.element, stopEvent, this.mouseEnd);
EventHandler.remove(this.element, 'click', this.chartOnMouseClick);
EventHandler.remove(this.element, cancelEvent, this.mouseLeave);
EventHandler.remove(this.element, 'keydown', this.chartKeyDown);
EventHandler.remove(document.body, 'keydown', this.documentKeyHandler);
EventHandler.remove(this.element, 'keyup', this.chartKeyUp);
window.removeEventListener((Browser.isTouch && ('orientation' in window && 'onorientationchange' in window)) ? 'orientationchange' : 'resize', this.resizeBound);
/**
* To fix memory issue
*/
if (this.touchObject) {
this.touchObject.destroy();
this.touchObject = null;
}
};
/**
* Binding events to the element while component creation.
*
* @hidden
* @returns {void}
*/
Chart3D.prototype.wireEvents = function () {
/**
* To fix react timeout destroy issue.
*/
if (!this.element) {
return;
}
/** Find the Events type */
var cancelEvent = Browser.isPointer ? 'pointerleave' : 'mouseleave';
/** Bind the Event handler */
EventHandler.add(this.element, Browser.touchStartEvent, this.chartOnMouseDown, this);
EventHandler.add(this.element, Browser.touchMoveEvent, this.mouseMove, this);
EventHandler.add(this.element, Browser.touchEndEvent, this.mouseEnd, this);
EventHandler.add(this.element, 'click', this.chartOnMouseClick, this);
EventHandler.add(this.element, cancelEvent, this.mouseLeave, this);
EventHandler.add(this.element, 'keydown', this.chartKeyDown, this);
EventHandler.add(do