@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,066 lines • 85.3 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;
};
/**
* Circular 3D chart file.
*/
import { Animation, Browser, Collection, Complex, Component, Event, EventHandler, Internationalization, NotifyPropertyChanges, Property, animationMode, isNullOrUndefined, remove, extend } from '@syncfusion/ej2-base';
import { Border, Font, Indexes, Margin } from '../common/model/base';
import { getCircular3DThemeColor } from './model/theme';
import { CircularChart3DSeries } from './renderer/series';
import { Data } from '../common/model/data';
import { ImageOption, RectOption, appendChildElement, calculateSize, createSvg, degreeToLocation, getAnimationFunction, getElement, getTitle, redrawElement, removeElement, showTooltip, subtractRect, textElement, titlePositionX, withInBounds } from '../common/utils/helper';
import { PathOption, Rect, Size, TextOption, measureText } from '@syncfusion/ej2-svg-base';
import { CircularChart3DBinaryTreeBuilder, CircularChart3DTransform, CircularChart3DGraphics, CircularChart3DMatrix, CircularChart3DPolygonModule, CircularChart3DSvgRenderer, CircularChart3DVectorModule } from './renderer/3d-renderer';
import { animationComplete, beforeResize, load, pointClick, pointMove, resized } from '../common/model/constants';
import { PrintUtils } from '../common/utils/print';
import { CircularChart3DLegendSettings } from './legend/legend';
import { CircularChart3DPointData, CircularChart3DTooltipSettings } from './user-interaction/tooltip';
/**
* Represents the circular 3D chart control.
* ```html
* <div id="container"/>
* <script>
* let pie: CircularChart3D = new CircularChart3D({ });
* pie.appendTo("#container");
*
* </script>
* ```
*
* @public
*/
var CircularChart3D = /** @class */ (function (_super) {
__extends(CircularChart3D, _super);
/**
* Constructor for creating the circular 3D chart widget.
*
* @private
* @param {CircularChart3DModel} options - Specifies the instance of the circular 3D chart model.
* @param {string | HTMLElement} element - Specifies the element for which the circular 3D chart will be rendered
* @returns {void}
*/
function CircularChart3D(options, element) {
var _this = _super.call(this, options, element) || this;
_this.chartId = 57724;
/** @private */
_this.explodeDistance = 0;
/** @private */
_this.rotateActivate = false;
/** @private */
_this.previousTargetId = '';
/** @private */
_this.currentPointIndex = 0;
/** @private */
_this.currentLegendIndex = 0;
/** @private */
_this.isLegendClicked = false;
/** @private */
_this.delayRedraw = false;
return _this;
}
Object.defineProperty(CircularChart3D.prototype, "type", {
get: function () {
return 'Pie';
},
enumerable: true,
configurable: true
});
/**
* To create SVG object, renderer, and bind events for the container.
*
* @private
* @returns {void}
*/
CircularChart3D.prototype.preRender = function () {
this.allowServerDataBinding = false;
this.unWireEvents();
this.titleLocation = { x: 0, y: 0, size: new Size(0, 0) };
this.subTitleLocation = { x: 0, y: 0, size: new Size(0, 0) };
this.circularRadius = [];
this.innerRadius = [];
this.matrixObj = new CircularChart3DMatrix();
this.bspTreeObj = new CircularChart3DBinaryTreeBuilder();
this.polygon = new CircularChart3DPolygonModule();
this.vector = new CircularChart3DVectorModule(null, null, null);
this.graphics = new CircularChart3DGraphics();
this.transform3D = new CircularChart3DTransform();
this.svg3DRenderer = new CircularChart3DSvgRenderer();
this.circular3DPolygon = [];
this.explodeDistance = 0;
this.setCulture();
this.animateSeries = true;
if (this.element.id === '') {
var collection = document.getElementsByClassName('e-circular3dchart').length;
this.element.id = 'acc_chart_' + this.chartId + '_' + collection;
}
this.wireEvents();
this.element.setAttribute('dir', this.enableRtl ? 'rtl' : '');
this.element.style.outline = 'none';
};
/**
* Method to unbind events for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.unWireEvents = function () {
/** Find the Events type */
var isIE11Pointer = Browser.isPointer;
var start = Browser.touchStartEvent;
var move = Browser.touchMoveEvent;
var stop = Browser.touchEndEvent;
var cancel = isIE11Pointer ? 'pointerleave' : 'mouseleave';
/** UnBind the Event handler */
EventHandler.remove(this.element, move, this.chartOnMouseMove);
EventHandler.remove(this.element, stop, this.chartMouseUp);
EventHandler.remove(this.element, start, this.chartMouseDown);
EventHandler.remove(this.element, 'click', this.chartOnMouseClick);
EventHandler.remove(this.element, cancel, this.chartMouseLeave);
EventHandler.remove(this.element, 'keydown', this.circular3DChartKeyDown);
EventHandler.remove(this.element, 'keyup', this.circular3DChartKeyUp);
window.removeEventListener((Browser.isTouch && ('orientation' in window && 'onorientationchange' in window)) ? 'orientationchange' : 'resize', this.chartResizeBound);
};
/**
* Handles the mouse click on the circular 3D chart.
*
* @param {PointerEvent} e - Mouse event arguments.
* @returns {boolean} - Indicates whether the mouse click event was handled by the circular 3D chart.
* @private
*/
CircularChart3D.prototype.chartOnMouseClick = function (e) {
this.setMouseXY(e);
if (this.circularChartLegend3DModule && this.legendSettings.visible) {
this.circularChartLegend3DModule.click(e);
}
if (this.selectionMode !== 'None' && this.circularChartSelection3DModule) {
this.circularChartSelection3DModule.calculateSelectedElements(this, e.target, e.type);
}
if (this.visibleSeries[0].explode) {
var id = e.target.id;
var indexes = void 0;
var pointIndex = void 0;
if (id.indexOf('-point-') > -1) {
indexes = id.split('-series-')[1].split('-point-');
pointIndex = parseInt(indexes[1], 10);
var currentPointIndex = this.visibleSeries[0].explodeIndex;
if (currentPointIndex === pointIndex || this.visibleSeries[0].points[pointIndex].isExplode) {
this.visibleSeries[0].explodeIndex = null;
this.visibleSeries[0].isExploded = true;
this.visibleSeries[0].points.forEach(function (point) {
point.isExplode = false;
});
}
else {
this.visibleSeries[0].explodeIndex = pointIndex;
}
this.removeSeriesElements(this);
this.visibleSeries[0].segments = [];
this.circular3DPolygon = [];
this.renderSeries();
this.processSelection();
this.delayRedraw = true;
}
}
this.trigger('circularChart3DMouseClick', { target: e.target.id, x: this.mouseX, y: this.mouseY });
if (this.pointClick) {
this.triggerPointEvent(pointClick, e.target, e);
}
this.removeNavigationStyle();
return false;
};
/**
* Triggers a point event for a circular 3D chart element.
*
* @param {string} event - The type of event to trigger.
* @param {Element} element - The DOM element associated with the event.
* @param {PointerEvent | TouchEvent | undefined} e - The pointer or touch event.
* @returns {void}
*/
CircularChart3D.prototype.triggerPointEvent = function (event, element, e) {
var evt = e;
var point;
var series = this.visibleSeries[0];
if (element.id.indexOf('point') > -1 && element.id.indexOf('series') > -1) {
var pointIndex = parseInt(element.id.split('point-')[1], 10);
point = series.points[pointIndex];
}
if (point) {
this.trigger(event, {
series: series,
point: point,
seriesIndex: series.index, pointIndex: point.index,
x: this.mouseX, y: this.mouseY, pageX: evt.pageX, pageY: evt.pageY
});
}
};
/**
* Handles the mouse move on the circular 3D chart.
*
* @param {PointerEvent} e - Mouse event arguments.
* @returns {boolean} - Indicates whether the mouse move event was handled by the circular 3D chart.
* @private
*/
CircularChart3D.prototype.chartOnMouseMove = function (e) {
if (!getElement(this.element.id + '_svg')) {
return false;
}
this.setMouseXY(e);
this.trigger('circularChart3DMouseMove', { target: e.target.id, x: this.mouseX, y: this.mouseY });
if (this.rotateActivate) {
var deltaX = this.previousCoords.x - this.mouseX;
var deltaY = this.previousCoords.y - this.mouseY;
if (deltaX || deltaY) {
this.tilt -= deltaY;
this.rotation += deltaX;
if (!this.isTouch) {
var grpElement = document.getElementById(this.groupElement.id);
grpElement.innerHTML = '';
grpElement.remove();
}
var size = { width: this.availableSize.width, height: this.availableSize.height };
this.graphics.view(this.svgObject, this, this.rotation, this.tilt, size, 0, this.depth);
appendChildElement(false, this.svgObject, this.groupElement, this.redraw);
this.setSeriesTabIndex();
this.previousCoords.y = this.mouseY;
this.previousCoords.x = this.mouseX;
if (this.circularChartHighlight3DModule && this.highlightMode !== 'None') {
this.circularChartHighlight3DModule.calculateSelectedElements(this, document.getElementById(this.element.id + '-border'), 'mousemove');
this.circularChartHighlight3DModule.previousSelectedElement = [];
}
this.processSelection();
}
}
if (this.pointMove) {
this.triggerPointEvent(pointMove, e.target, e);
}
if (this.tooltip.enable && this.circularChartTooltip3DModule) {
this.circularChartTooltip3DModule.mouseMoveHandler(e, this);
}
if (!this.isTouch) {
this.titleTooltip(e, this.mouseX, this.mouseY);
}
this.notify(Browser.touchMoveEvent, e);
return false;
};
/**
* Displays a tooltip for the given event at the specified coordinates.
*
* @param {Event} event - The event triggering the tooltip display.
* @param {number} x - The x-coordinate for the tooltip position.
* @param {number} y - The y-coordinate for the tooltip position.
* @param {boolean} isTouch - Optional parameter indicating whether the event is a touch event. Defaults to false if not provided.
* @returns {void}
*/
CircularChart3D.prototype.titleTooltip = function (event, x, y, isTouch) {
var targetId = event.target.id;
var id = (targetId === (this.element.id + '-title') || targetId === (this.element.id + '-sub-title') ||
targetId === (this.element.id + '_chart_legend_title'));
if ((event.target.textContent.indexOf('...') > -1) && id) {
var title = (targetId === (this.element.id + '-title')) ?
this.title : (targetId === (this.element.id + '-sub-title')) ? this.subTitle : this.legendSettings.title;
showTooltip(title, x, y, this.element.offsetWidth, this.element.id + '_EJ2_Title_Tooltip', getElement(this.element.id + '_Secondary_Element'), isTouch);
}
else {
removeElement(this.element.id + '_EJ2_Title_Tooltip');
}
};
/**
* Sets the mouse x and y coordinates based on the specified pointer event.
*
* @param {PointerEvent} e - Specifies the pointer event.
* @returns {void}
*/
CircularChart3D.prototype.setMouseXY = function (e) {
var pageX;
var pageY;
var svgRectElement = getElement(this.element.id + '_svg');
if (svgRectElement && this.element) {
var svgRect = svgRectElement.getBoundingClientRect();
var rect = this.element.getBoundingClientRect();
if (e.type.indexOf('touch') > -1) {
this.isTouch = true;
var touchArg = e;
pageY = touchArg.changedTouches[0].clientY;
pageX = touchArg.changedTouches[0].clientX;
}
else {
this.isTouch = e.pointerType === 'touch' || e.pointerType === '2';
pageX = e.clientX;
pageY = e.clientY;
}
this.mouseY = (pageY - rect.top) - Math.max(svgRect.top - rect.top, 0);
this.mouseX = (pageX - rect.left) - Math.max(svgRect.left - rect.left, 0);
}
};
/**
* Method to bind events for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.wireEvents = function () {
if (!this.element) {
return;
}
/** Find the Events type */
var isIE11Pointer = Browser.isPointer;
var start = Browser.touchStartEvent;
var stop = Browser.touchEndEvent;
var move = Browser.touchMoveEvent;
var cancel = isIE11Pointer ? 'pointerleave' : 'mouseleave';
/** Bind the Event handler */
EventHandler.add(this.element, move, this.chartOnMouseMove, this);
EventHandler.add(this.element, stop, this.chartMouseUp, this);
EventHandler.add(this.element, start, this.chartMouseDown, this);
EventHandler.add(this.element, 'click', this.chartOnMouseClick, this);
EventHandler.add(this.element, cancel, this.chartMouseLeave, this);
EventHandler.add(this.element, 'keydown', this.circular3DChartKeyDown, this);
EventHandler.add(this.element, 'keyup', this.circular3DChartKeyUp, this);
this.chartResizeBound = this.chartResize.bind(this);
window.addEventListener((Browser.isTouch && ('orientation' in window && 'onorientationchange' in window)) ? 'orientationchange' : 'resize', this.chartResizeBound);
//new Touch(this.element); // To avoid geasture blocking for browser
/** Apply the style for chart */
this.setStyle(this.element);
};
/**
* Handles the mouse leave on circular 3D chart.
*
* @param {PointerEvent} e - Mouse event arguments.
* @returns {boolean} - Indicates the mouse leave event for the circular 3D chart.
* @private
*/
CircularChart3D.prototype.chartMouseLeave = function (e) {
this.setMouseXY(e);
this.trigger('circularChart3DMouseLeave', { target: e.target.id, x: this.mouseX, y: this.mouseY });
if (this.tooltip.enable && this.circularChartTooltip3DModule) {
this.circularChartTooltip3DModule.mouseLeaveHandler();
}
this.notify(Browser.isPointer ? 'pointerleave' : 'mouseleave', e);
this.rotateActivate = false;
return false;
};
/**
* Handles the mouse end event for the circular 3D chart.
*
* @param {PointerEvent} e - Mouse event arguments.
* @returns {boolean} - Indicates the mouse end event for the circular 3D chart.
* @private
*/
CircularChart3D.prototype.chartMouseUp = function (e) {
this.setMouseXY(e);
this.trigger('circularChart3DMouseUp', { target: e.target.id, x: this.mouseX, y: this.mouseY });
if (this.isTouch) {
this.titleTooltip(e, this.mouseX, this.mouseY, this.isTouch);
}
this.rotateActivate = false;
if (this.tooltip.enable && this.circularChartTooltip3DModule) {
this.circularChartTooltip3DModule.mouseUpHandler(e, this);
}
this.notify(Browser.touchEndEvent, e);
return false;
};
/**
* Handles the mouse start event on the circular 3D chart.
*
* @param {PointerEvent} e - Mouse event arguments.
* @returns {boolean} - Indicates whether the mouse start event was handled by the circular 3D chart.
* @private
*/
CircularChart3D.prototype.chartMouseDown = function (e) {
this.setMouseXY(e);
this.trigger('circularChart3DMouseDown', { target: e.target.id, x: this.mouseX, y: this.mouseY });
this.cachedX = this.mouseX;
this.cachedY = this.mouseY;
var svgRect = getElement(this.element.id + '_svg').getBoundingClientRect();
var bounds = document.getElementById(this.element.id + '-svg-chart-3d').getBoundingClientRect();
var rect = { x: bounds.left - svgRect.left, y: bounds.top - svgRect.top, width: bounds.width, height: bounds.height };
if (this.enableRotation && withInBounds(this.mouseX, this.mouseY, rect)) {
this.rotateActivate = true;
this.previousCoords = { x: this.mouseX, y: this.mouseY };
}
return false;
};
/**
* Applies styles for the circular 3D chart element.
*
* @param {HTMLElement} element - Specifies the circular 3D chart element.
* @returns {void}
*/
CircularChart3D.prototype.setStyle = function (element) {
element.style.touchAction = this.enableRotation ? 'none' : 'element';
element.style.msTouchAction = 'element';
element.style.msContentZooming = 'none';
element.style.msUserSelect = 'none';
element.style.webkitUserSelect = 'none';
element.style.position = 'relative';
element.style.display = 'block';
element.style.height = (element.style.height || (this.height && this.height.indexOf('%') === -1)) ? element.style.height : 'inherit';
};
/**
* Method to set the culture for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.setCulture = function () {
this.intl = new Internationalization();
};
/**
* Renders the circular 3D chart elements.
*
* @returns {void}
* @private
*/
CircularChart3D.prototype.render = function () {
var _this = this;
if (this.element.className.indexOf('e-circular3dchart') === -1) {
this.element.classList.add('e-circular3dchart');
}
this.element.setAttribute('role', 'region');
this.element.setAttribute('tabindex', '0');
this.element.setAttribute('aria-label', this.title + '. Syncfusion interactive chart.');
this.element.setAttribute('class', this.element.getAttribute('class') + ' e-circular3dchart-focused');
var loadEventData = {
chart: this,
theme: this.theme, name: load, cancel: false
};
this.trigger(load, loadEventData, function () {
if (!loadEventData.cancel) {
_this.setTheme();
_this.calculateVisibleSeries();
_this.processData();
_this.renderComplete();
_this.allowServerDataBinding = true;
}
});
};
/**
* Sets the theme for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.setTheme = function () {
/** Set theme for circular 3D chart */
this.themeStyle = getCircular3DThemeColor(this.theme);
};
/**
* Processes data from the data source to find points for rendering.
*
* @param {boolean} render - A boolean value indicating whether to trigger rendering after processing the data. Default is true.
* @returns {void}
*/
CircularChart3D.prototype.processData = function (render) {
if (render === void 0) { render = true; }
this.seriesCounts = 0;
for (var _i = 0, _a = this.visibleSeries; _i < _a.length; _i++) {
var series = _a[_i];
series.dataModule = new Data(series.dataSource || this.dataSource, series.query);
series.refreshDataManager(this, render);
}
};
/**
* Refreshes the circular 3D chart.
*
* @private
* @returns {void}
*/
CircularChart3D.prototype.refreshChart = function () {
this.createPieSvg();
this.calculateBounds();
this.circular3DPolygon = [];
this.visibleSeries[0].segments = [];
this.groupElement = this.renderer.createGroup({ 'id': this.element.id + '-svg-chart-3d' });
this.groupElement.setAttribute('role', 'region');
this.groupElement.setAttribute('aria-hidden', 'false');
this.renderElements();
removeElement('chartmeasuretext');
};
/**
* Renders elements for the circular 3D chart.
*
* @private
* @returns {void}
*/
CircularChart3D.prototype.renderElements = function () {
this.renderBorder();
this.createSecondaryElement();
this.renderTitle();
this.renderSeries();
this.renderLegend();
appendChildElement(false, this.element, this.svgObject, this.redraw);
this.processSelection();
this.setSecondaryElementPosition();
this.trigger('loaded', { chart: this });
this.setSeriesTabIndex();
this.doAnimation();
this.animateSeries = false;
};
/**
* Sets the tabindex attribute to '0' for the last element matching the selector pattern "[id*='region-series-0-point-0']".
*
* @returns {void}
*/
CircularChart3D.prototype.setSeriesTabIndex = function () {
var elements;
for (var i = 0; i < this.visibleSeries[0].points.length; i++) {
if (this.visibleSeries[0].points[i].visible) {
elements = document.querySelectorAll('[id*="region-series-0-point-' + this.visibleSeries[0].points[i].index + '"]');
break;
}
}
if (elements && elements.length > 0) {
var element = elements[elements.length - 1];
element.setAttribute('tabindex', '0');
}
};
/**
* Processes the selection in the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.processSelection = function () {
var selectedDataIndexes = [];
if (this.circularChartSelection3DModule && this.selectionMode !== 'None') {
selectedDataIndexes = extend([], this.circularChartSelection3DModule.selectedDataIndexes, null, true);
this.circularChartSelection3DModule.invokeSelection(this);
}
if (this.circularChartHighlight3DModule) {
this.circularChartHighlight3DModule.invokeHighlight(this);
}
if (selectedDataIndexes.length > 0) {
this.circularChartSelection3DModule.selectedDataIndexes = selectedDataIndexes;
this.circularChartSelection3DModule.redrawSelection(this);
}
};
/**
* Performs a highlight animation on the specified HTML element with the given duration and starting opacity.
*
* @param {HTMLElement} element - The HTML element to animate.
* @param {number} duration - The duration of the animation in milliseconds.
* @param {number} startOpacity - The starting opacity value for the animation.
* @returns {void}
* @private
*/
CircularChart3D.prototype.highlightAnimation = function (element, duration, startOpacity) {
var endOpacity = parseFloat(this.visibleSeries[0].opacity.toString());
if (endOpacity) {
new Animation({}).animate(element, {
duration: duration,
progress: function (args) {
element.style.animation = '';
var progress = args.timeStamp / args.duration;
var currentOpacity = startOpacity + (endOpacity - startOpacity) * progress;
element.setAttribute('opacity', currentOpacity.toString());
},
end: function () {
element.setAttribute('opacity', endOpacity.toString());
}
});
}
};
/**
* Stops the animation for the specified HTML element in the circular 3D chart.
*
* @param {HTMLElement} element - The HTML element for which the animation should be stopped.
* @returns {void}
* @private
*/
CircularChart3D.prototype.stopElementAnimation = function (element) {
var endOpacity = parseFloat(this.visibleSeries[0].opacity.toString());
var animation = element.getAttribute('e-animate');
if (animation) {
Animation.stop(element);
}
element.setAttribute('opacity', endOpacity.toString());
};
/**
* Initiates and executes the animation for the circular 3D chart.
* This method assumes the existence of visible series and focuses on the first series for animation.
*
* @returns {void}
*/
CircularChart3D.prototype.doAnimation = function () {
var series = this.visibleSeries[0];
if (series.animation.enable && this.animateSeries) {
var clippath_1 = this.renderer.createClipPath({ id: this.element.id + 'SeriesGroup0' + '_clipPath' });
var path = new PathOption(this.element.id + 'SeriesGroup0' + '_slice', 'transparent', 1, 'transparent', 1, '', '');
var clipslice = this.renderer.drawPath(path);
clippath_1.appendChild(clipslice);
this.svgObject.appendChild(clippath_1);
var id_1 = this.element.id;
var groupElementID_1 = this.groupElement.id;
document.querySelectorAll('[id*="region-series-"]').forEach(function (slice) {
if (slice.parentElement.id === groupElementID_1) {
slice.style.cssText = 'clip-path:url(#' + clippath_1.id + '); -webkit-clip-path:url(#' + clippath_1.id + ');';
slice.setAttribute('clip-path', 'url(#' + id_1 + 'SeriesGroup0' + '_clipPath' + ')');
}
});
if (series.segments[0]) {
this.animationRect(clipslice, series);
}
}
};
/**
* Renders the legend for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.renderLegend = function () {
if (!this.circularChartLegend3DModule || !this.legendSettings.visible) {
return null;
}
if (this.circularChartLegend3DModule.legendCollections.length && this.visibleSeries[0].labelBound) {
this.circularChartLegend3DModule.getSmartLegendLocation(this.visibleSeries[0].labelBound, this.circularChartLegend3DModule.legendBounds, this.margin);
}
this.circularChartLegend3DModule.renderLegend(this, this.legendSettings, this.circularChartLegend3DModule.legendBounds, this.redraw);
};
/**
* Initiates animation for the circular 3D series.
*
* @param {Element} slice - Specifies the slice element to animate.
* @param {CircularChart3DSeries} series - Specifies the circular 3D chart series.
* @returns {void}
*/
CircularChart3D.prototype.animationRect = function (slice, series) {
var _this = this;
var startAngle = -90;
var duration = series.animation.duration; //this.duration ? this.duration : series.animation.duration;
var value;
var radius = Math.max(this.availableSize.height, this.availableSize.width) * 0.75;
radius += radius * (0.414); // formula r + r / 2 * (1.414 -1)
var effect = getAnimationFunction('Linear'); // need to check animation type
var center = {
x: series.segments[0].center.x - this.rotation / 2,
y: series.segments[0].center.y + this.tilt / 2
};
for (var i = 0; i < series.points.length; i++) {
var dataLabelElement = getElement(this.element.id + '-svg-data-label-text-' + i);
if (dataLabelElement) {
dataLabelElement.style.visibility = 'hidden';
}
var shapeElement = getElement(this.element.id + '-svg-data-label-series-0-shape-' + i);
if (shapeElement) {
shapeElement.style.visibility = 'hidden';
}
var templateElement = getElement(this.element.id + '-series-' + series.index + '-data-label-' + i);
if (templateElement) {
templateElement.style.visibility = 'hidden';
}
var connectorElement = getElement(this.element.id + '-datalabel-series-0-connector-' + i);
if (connectorElement) {
connectorElement.style.visibility = 'hidden';
}
}
if (!isNullOrUndefined(slice)) {
new Animation({}).animate(slice, {
duration: (duration === 0 && animationMode === 'Enable') ? 1000 : duration,
delay: series.animation.delay,
progress: function (args) {
value = effect(args.timeStamp, startAngle, 359.99999, args.duration);
slice.setAttribute('d', _this.getPathArc(center, startAngle, value, radius));
},
end: function () {
slice.setAttribute('d', _this.getPathArc(center, 0, 359.99999, radius));
_this.trigger(animationComplete, { series: series, chart: _this });
for (var i = 0; i < series.points.length; i++) {
var dataLabelElement = getElement(_this.element.id + '-svg-data-label-text-' + i);
if (dataLabelElement) {
dataLabelElement.style.visibility = 'visible';
}
var shapeElement = getElement(_this.element.id + '-svg-data-label-series-0-shape-' + i);
if (shapeElement) {
shapeElement.style.visibility = 'visible';
}
var templateElement = getElement(_this.element.id + '-series-' + series.index + '-data-label-' + i);
if (templateElement) {
templateElement.style.visibility = 'visible';
}
var connectorElement = getElement(_this.element.id + '-datalabel-series-0-connector-' + i);
if (connectorElement) {
connectorElement.style.visibility = 'visible';
}
}
}
});
}
};
/**
* Gets the path arc direction for the circular 3D chart.
*
* @param {ChartLocation} center - Specifies the center of the series segment.
* @param {number} start - Specifies the start angle in degrees.
* @param {number} end - Specifies the end angle in degrees.
* @param {number} radius - Specifies the radius of the series.
* @returns {string} - Path arc direction as an SVG path string.
*/
CircularChart3D.prototype.getPathArc = function (center, start, end, radius) {
var degree = end - start;
degree = degree < 0 ? (degree + 360) : degree;
var flag = (degree < 180) ? 0 : 1;
return this.getPiePath(center, degreeToLocation(start, radius, center), degreeToLocation(end, radius, center), radius, flag);
};
/**
* Gets the SVG path string for a pie in the circular 3D chart.
*
* @param {ChartLocation} center - Specifies the center of the series segment.
* @param {ChartLocation} start - Specifies the start angle in degrees.
* @param {ChartLocation} end - Specifies the end angle in degrees.
* @param {number} radius - Specifies the radius of the series.
* @param {number} clockWise - Specifies the clockwise direction (0 for anti-clockwise, 1 for clockwise).
* @returns {string} - SVG path string for the pie.
*/
CircularChart3D.prototype.getPiePath = function (center, start, end, radius, clockWise) {
return 'M ' + center.x + ' ' + center.y + ' L ' + start.x + ' ' + start.y + ' A ' + radius + ' ' +
radius + ' 0 ' + clockWise + ' 1 ' + end.x + ' ' + end.y + ' Z';
};
/**
* Renders the border for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.renderBorder = function () {
var padding = this.border.width;
var rect = new RectOption(this.element.id + '-border', this.background || this.themeStyle.background, this.border, 1, new Rect(padding / 2, padding / 2, this.availableSize.width - padding, this.availableSize.height - padding));
var htmlObject = this.renderer.drawRectangle(rect);
htmlObject.setAttribute('aria-hidden', 'true');
appendChildElement(false, this.svgObject, htmlObject, this.redraw);
var backGroundImage = this.backgroundImage;
if (backGroundImage) {
var image = new ImageOption(this.availableSize.height - padding, this.availableSize.width - padding, backGroundImage, 0, 0, this.element.id + '-background', 'visible', 'none');
appendChildElement(false, this.svgObject, this.renderer.drawImage(image), this.redraw);
}
};
/**
* Creates the secondary element for tooltips and data labels.
*
* @returns {void}
*/
CircularChart3D.prototype.createSecondaryElement = function () {
var element = redrawElement(this.redraw, this.element.id + '_Secondary_Element') ||
this.createElement('div', {
id: this.element.id + '_Secondary_Element',
styles: 'position: relative'
});
appendChildElement(false, this.element, element, this.redraw);
};
/**
* Renders the series for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.renderSeries = function () {
if (!this.redraw) {
this.svgObject.appendChild(this.renderer.createGroup({ id: this.element.id + '_SeriesCollection' }));
}
for (var _i = 0, _a = this.visibleSeries; _i < _a.length; _i++) {
var series = _a[_i];
if (series.visible && this[('pie' + 'Series3DModule')]) {
series.draw(series, this);
this.defaultLabelBound(series);
}
}
};
/**
* Sets the default label bounds for the specified circular 3D chart series based on its circular bounds.
*
* @param {CircularChart3DSeries} series - The CircularChart3DSeries for which to set the default label bounds.
* @returns {void}
*/
CircularChart3D.prototype.defaultLabelBound = function (series) {
if (series.segments.length > 0 && series.dataLabel.visible) {
var circularBound = this.getSeriesBound(series);
if (series.dataLabel.visible && series.dataLabel.position === 'Inside') {
series.labelBound = new Rect(circularBound.x, circularBound.y, circularBound.width + circularBound.x, circularBound.height + circularBound.y);
}
series.findMaxBounds(series.labelBound, circularBound);
if (this.circularChartLegend3DModule) {
series.labelBound.x -= this.explodeDistance;
series.labelBound.y -= this.explodeDistance;
series.labelBound.height += (this.explodeDistance - series.labelBound.y);
series.labelBound.width += (this.explodeDistance - series.labelBound.x);
}
}
};
/**
* Calculates and returns the bounding rectangle (Rect) for the specified circular 3D chart series.
*
* @param {CircularChart3DSeries} series - The CircularChart3DSeries for which to calculate the bounding rectangle.
* @returns {Rect} - The calculated bounding rectangle for the series.
*/
CircularChart3D.prototype.getSeriesBound = function (series) {
var rect = new Rect(Infinity, Infinity, -Infinity, -Infinity);
var start = 0;
var total = 360;
var end = (0 + total) % 360;
end = (end === 0) ? 360 : end;
series.findMaxBounds(rect, this.getRectFromAngle(start));
series.findMaxBounds(rect, this.getRectFromAngle(end));
series.findMaxBounds(rect, new Rect(series.segments[0].center.x, series.segments[0].center.y, 0, 0));
var nextQuandrant = (Math.floor(start / 90) * 90 + 90) % 360;
var lastQuadrant = (Math.floor(end / 90) * 90) % 360;
lastQuadrant = (lastQuadrant === 0) ? 360 : lastQuadrant;
if (total >= 90 || lastQuadrant === nextQuandrant) {
series.findMaxBounds(rect, this.getRectFromAngle(nextQuandrant));
series.findMaxBounds(rect, this.getRectFromAngle(lastQuadrant));
}
if (start === 0 || (start + total >= 360)) {
series.findMaxBounds(rect, this.getRectFromAngle(0));
}
var length = nextQuandrant === lastQuadrant ? 0 : Math.floor(total / 90);
for (var i = 1; i < length; i++) {
nextQuandrant = nextQuandrant + 90;
if ((nextQuandrant < lastQuadrant || end < start) || total === 360) {
series.findMaxBounds(rect, this.getRectFromAngle(nextQuandrant));
}
}
rect.width -= rect.x;
rect.height -= rect.y;
return rect;
};
/**
* Computes and returns a rectangle (Rect) based on the specified angle.
*
* @param {number} angle - The angle used to calculate the rectangle position.
* @returns {Rect} - The calculated rectangle representing the position.
*/
CircularChart3D.prototype.getRectFromAngle = function (angle) {
var location = degreeToLocation(angle, this.circularRadius[0], this.visibleSeries[0].segments[0].center);
return new Rect(location.x, location.y, 0, 0);
};
/**
* Renders the title for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.renderTitle = function () {
var margin = this.margin;
if (!this.title) {
return null;
}
var getAnchor = this.getTextAnchor(this.titleStyle.textAlignment, this.enableRtl);
var titleSize = measureText(this.title, this.titleStyle, this.themeStyle.chartTitleFont);
var titleHeight = this.margin.top + (titleSize.height * 3 / 4);
var rect = new Rect(margin.left, 0, this.availableSize.width - margin.left - margin.right, 0);
var options = new TextOption(this.element.id + '-title', titlePositionX(rect, this.titleStyle), titleHeight, getAnchor, this.titleCollection, '', 'auto');
this.titleLocation = { x: options.x, y: options.y, size: titleSize };
var element = textElement(this.renderer, options, this.titleStyle, this.titleStyle.color || this.themeStyle.chartTitleFont.color, this.svgObject, false, this.redraw, null, null, null, null, null, null, null, null, this.themeStyle.chartTitleFont);
if (element) {
element.setAttribute('tabindex', '0');
element.style.outline = 'none';
element.parentNode.insertBefore(element, this.svgObject.children && this.svgObject.children[1]);
}
if (this.subTitle) {
this.renderSubTitle(options);
}
};
/**
* Gets the text anchor based on the specified alignment and RTL setting.
*
* @param {Alignment} alignment - The alignment of the text.
* @param {boolean} enableRTL - A boolean indicating whether right-to-left (RTL) text is enabled.
* @returns {string} - The text anchor value.
*/
CircularChart3D.prototype.getTextAnchor = function (alignment, enableRTL) {
switch (alignment) {
case 'Near':
return enableRTL ? 'end' : 'start';
case 'Far':
return enableRTL ? 'start' : 'end';
default:
return 'middle';
}
};
/**
* Renders the subtitle for the circular 3D chart.
*
* @param {TextOption} options - The text options for rendering the subtitle.
* @returns {void}
*/
CircularChart3D.prototype.renderSubTitle = function (options) {
var maxWidth = 0;
var titleWidth = 0;
var padding = 10;
var alignment = this.titleStyle.textAlignment;
var subTitleElementSize = measureText(this.subTitle, this.subTitleStyle, this.themeStyle.chartSubTitleFont);
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 rect = new Rect(alignment === 'Center' ? (options.x - maxWidth / 2) : alignment === 'Far' ? options.x - maxWidth : options.x, 0, maxWidth, 0);
var subTitleOption = new TextOption(this.element.id + '-sub-title', titlePositionX(rect, this.subTitleStyle), options.y * options.text.length + ((subTitleElementSize.height) * 3 / 4) + padding, this.getTextAnchor(this.subTitleStyle.textAlignment, this.enableRtl), this.subTitleCollection, '', 'auto');
this.subTitleLocation = { x: subTitleOption.x, y: subTitleOption.y, size: subTitleElementSize };
textElement(this.renderer, subTitleOption, this.subTitleStyle, this.subTitleStyle.color || this.themeStyle.chartSubTitleFont.color, this.svgObject, false, this.redraw, null, null, null, null, null, null, null, null, this.themeStyle.chartSubTitleFont);
};
/**
* Sets the left and top position for the data label and tooltip template for center-aligned chart.
*
* @private
* @returns {void}
*/
CircularChart3D.prototype.setSecondaryElementPosition = function () {
var tooltipParent = getElement(this.element.id + '_Secondary_Element');
if (!tooltipParent) {
return;
}
var rect = this.element.getBoundingClientRect();
var svgRect = getElement(this.element.id + '_svg').getBoundingClientRect();
tooltipParent.style.left = Math.max(svgRect.left - rect.left, 0) + 'px';
tooltipParent.style.top = Math.max(svgRect.top - rect.top, 0) + 'px';
};
/**
* Creates an SVG element for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.createPieSvg = function () {
this.removeSvg();
createSvg(this);
};
/**
* Removes the SVG from the circular 3D chart.
*
* @returns {void}
* @private
*/
CircularChart3D.prototype.removeSvg = function () {
if (this.redraw) {
return null;
}
removeElement(this.element.id + '_Secondary_Element');
if (this.svgObject) {
while (this.svgObject.childNodes.length > 0) {
this.svgObject.removeChild(this.svgObject.firstChild);
}
if (!this.svgObject.hasChildNodes() && this.svgObject.parentNode) {
remove(this.svgObject);
}
}
removeElement('EJ2_legend_tooltip');
removeElement('EJ2_datalabel_tooltip');
removeElement(this.element.id + 'PointHover_Border');
};
/**
* Calculates and sets the visible series for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.calculateVisibleSeries = function () {
this.visibleSeries = [];
this.series[0].index = 0;
this.visibleSeries.push(this.series[0]);
};
/**
* Method to calculate bounds for the circular 3D chart.
*
* @returns {void}
* @private
*/
CircularChart3D.prototype.calculateBounds = function () {
this.initialClipRect = new Rect(this.margin.left, this.margin.top, this.availableSize.width, this.availableSize.height);
this.titleCollection = [];
this.subTitleCollection = [];
var titleHeight = 0;
var subTitleHeight = 0;
var maxWidth = 0;
var titleWidth = 0;
if (this.title) {
this.titleCollection = getTitle(this.title, this.titleStyle, this.initialClipRect.width, this.enableRtl, this.themeStyle.chartTitleFont);
}
titleHeight = this.title ? measureText(this.title, this.titleStyle, this.themeStyle.chartTitleFont).height * this.titleCollection.length : titleHeight;
if (this.subTitle) {
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;
}
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);
}
subtractRect(this.initialClipRect, new Rect(0, (subTitleHeight + titleHeight), this.margin.right + this.margin.left, this.margin.bottom + this.margin.top));
this.calculateLegendBounds();
};
/*
* Method to calculate legend bounds for the circular 3D chart.
*
* @returns {void}
*/
CircularChart3D.prototype.calculateLegendBounds = function () {
if (!this.circularChartLegend3DModule || !this.legendSettings.visible) {
return null;
}
this.circularChartLegend3DModule.getLegendOptions(this, this.visibleSeries);
this.circularChartLegend3DModule.calculateLegendBounds(this.initialClipRect, this.availableSize, null);
};
/**
* Handles the print method for the circular 3D chart control.
*
* @param {string[] | string | Element} id - Specifies the element to print.
* @returns {void}
*/
CircularChart3D.prototype.print = function (id) {
var exportChart = new PrintUtils(this);
exportChart.print(id);
};
/**
* Export method for the circular 3D chart.
*
* @param {ExportType} type - Specifies the type of the image file (PNG, JPEG, SVG).
* @param {string} fileName - Specifies the name of the exported image file.
* @returns {void}
*/
CircularChart3D.prototype.export = function (type, fileName) {
if (this.circularChartExport3DModule) {
this.circularChartExport3DModule.export(type, fileName);
if (this.afterExport) {
this.circularChartExport3DModule.getDataUrl(this);
}
}
};
/**
* Export the chart on the page to a PDF document.
*
* @param {string} fileName - The name of the exported file.
* @param {PdfPageOrientation} orientation - Page orientation (portrait or landscape).
* @param {CircularChart3D[]} controls - Array of controls to be exported.
* @param {number} width - The width of the exported chart.
* @param {number} height - The height of the exported chart.
* @param {boolean} isVertical - Export the chart vertically or horizontally.
* @param {string} header - Text to appear at the top of the exported PDF document.
* @param {string} footer - Text to appear at the bottom of the exported PDF document.
* @param {boolean} exportToMultiplePage - Export the chart to multiple PDF pages.
* @returns {void}
*/
CircularChart3D.prototype.pdfExport = function (fileName, orientation, controls, width, height, isVertical, header, footer, exportToMultiplePage) {
if (this.circularChartExport3DModule) {
this.circularChartExport3DModule.pdfExport(fileName, orientation, controls, width, height, isVertical, header, footer, exportToMultiplePage);
}
};
/**
* Provides an array of modules needed for control rendering in the circular 3D chart.
*
* @returns {ModuleDeclaration[]} - An array of required modules.
* @private
*/
CircularChart3D.prototype.requiredModules = function () {
var modules = [];
modules.push({
member: this.type + 'Series3D',
args: [this]
});
if (this.legendSettings.visible) {
modules.push({
member: 'Circ