@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.
988 lines • 125 kB
JavaScript
import { createElement, isNullOrUndefined, Animation } from '@syncfusion/ej2-base';
import { DataUtil } from '@syncfusion/ej2-data';
import { subtractThickness, valueToCoefficient, sum, redrawElement, isBreakLabel, ChartLocation, withInBounds, rotateTextSize, removeElement, calculateScrollbarOffset } from '../../common/utils/helper';
import { subArray, inside, appendChildElement, stringToNumber } from '../../common/utils/helper';
import { Thickness, logBase, createZoomingLabels, getElement } from '../../common/utils/helper';
import { Size, Rect, measureText, TextOption, PathOption } from '@syncfusion/ej2-svg-base';
import { textElement, textTrim, getRotatedRectangleCoordinates, isRotatedRectIntersect, isZoomSet } from '../../common/utils/helper';
/**
* Specifies the Cartesian Axis Layout.
*/
var axisPadding = 10;
var CartesianAxisLayoutPanel = /** @class */ (function () {
/** @private */
/**
* Constructor for creating the chart.
*
* @param {Chart} chartModule - Specifies the Chart model.
* @private */
function CartesianAxisLayoutPanel(chartModule) {
this.chart = chartModule;
this.padding = 5;
}
/**
* Measure the axis size.
*
* @returns {void}
* @private
*/
CartesianAxisLayoutPanel.prototype.measureAxis = function (rect) {
var chart = this.chart;
var chartAreaWidth = chart.chartArea.width ? stringToNumber(chart.chartArea.width, chart.availableSize.width) : null;
this.crossAt(chart);
this.seriesClipRect = new Rect(rect.x, rect.y, rect.width, rect.height);
this.initialClipRect = rect;
this.leftSize = 0;
this.rightSize = 0;
this.topSize = 0;
this.bottomSize = 0;
//Measure Axis size with initial Rect
this.measureRowAxis(chart, this.initialClipRect);
this.initialClipRect = subtractThickness(this.initialClipRect, new Thickness(this.leftSize, this.rightSize, 0, 0));
this.measureColumnAxis(chart, this.initialClipRect);
this.initialClipRect = subtractThickness(this.initialClipRect, new Thickness(0, 0, this.topSize, this.bottomSize));
if (!this.chart.delayRedraw) {
this.calculateAxisSize(this.initialClipRect);
}
this.leftSize = 0;
this.rightSize = 0;
this.topSize = 0;
this.bottomSize = 0;
//Measure Axis size with series Rect
this.measureRowAxis(chart, this.initialClipRect);
this.seriesClipRect = subtractThickness(this.seriesClipRect, new Thickness(this.leftSize, this.rightSize, 0, 0));
this.measureColumnAxis(chart, this.initialClipRect);
this.seriesClipRect = subtractThickness(this.seriesClipRect, new Thickness(0, 0, this.topSize, this.bottomSize));
if (chartAreaWidth) {
this.calculateFixedChartArea(chart, chartAreaWidth);
}
if (!this.chart.delayRedraw) {
chart.refreshAxis();
this.calculateAxisSize(this.seriesClipRect);
}
};
CartesianAxisLayoutPanel.prototype.calculateFixedChartArea = function (chart, chartAreaWidth) {
this.seriesClipRect.width = chartAreaWidth;
this.seriesClipRect.x = chart.availableSize.width - chart.margin.right - chartAreaWidth -
(chart.legendSettings.position === 'Right' ? chart.legendModule.legendBounds.width : 0);
for (var _i = 0, _a = chart.rows; _i < _a.length; _i++) {
var item = _a[_i];
this.seriesClipRect.x -= sum(item.farSizes);
}
};
CartesianAxisLayoutPanel.prototype.measureRowAxis = function (chart, rect) {
var row;
this.calculateRowSize(rect);
for (var _i = 0, _a = chart.rows; _i < _a.length; _i++) {
var item = _a[_i];
row = item;
row.nearSizes = [];
row.farSizes = [];
row.insideNearSizes = [];
row.insideFarSizes = [];
this.arrangeAxis(row);
this.measureDefinition(row, chart, new Size(chart.availableSize.width, row.computedHeight));
if (this.leftSize < sum(row.nearSizes)) {
this.leftSize = sum(row.nearSizes);
}
if (this.rightSize < sum(row.farSizes)) {
this.rightSize = sum(row.farSizes);
}
}
};
CartesianAxisLayoutPanel.prototype.measureColumnAxis = function (chart, rect) {
var column;
this.calculateColumnSize(rect);
for (var _i = 0, _a = chart.columns; _i < _a.length; _i++) {
var item = _a[_i];
column = item;
column.farSizes = [];
column.nearSizes = [];
column.insideNearSizes = [];
column.insideFarSizes = [];
this.arrangeAxis(column);
this.measureDefinition(column, chart, new Size(column.computedWidth, chart.availableSize.height));
if (this.bottomSize < sum(column.nearSizes)) {
this.bottomSize = sum(column.nearSizes);
}
if (this.topSize < sum(column.farSizes)) {
this.topSize = sum(column.farSizes);
}
}
};
/**
* Measure the column and row in chart.
*
* @returns {void}
* @private
*/
CartesianAxisLayoutPanel.prototype.measureDefinition = function (definition, chart, size) {
var ele;
for (var _i = 0, _a = definition.axes; _i < _a.length; _i++) {
var axis = _a[_i];
ele = axis.scrollbarSettings.height;
axis.scrollBarHeight = chart.scrollBarModule && chart.zoomModule && chart.zoomSettings.enableScrollbar &&
axis.enableScrollbarOnZooming && chart.zoomModule.isZoomed && (axis.zoomFactor < 1 || axis.zoomPosition > 0) ? ele : 0;
axis.scrollBarHeight = chart.scrollBarModule && (chart.zoomModule && chart.zoomSettings.enableScrollbar &&
axis.enableScrollbarOnZooming && chart.zoomModule.isZoomed && (axis.zoomFactor < 1 || axis.zoomPosition > 0)
|| axis.scrollbarSettings.enable) ? ele : 0;
axis.getModule(chart);
axis.baseModule.calculateRangeAndInterval(size, axis);
definition.computeSize(axis, axis.scrollBarHeight, definition, chart);
}
if (definition.farSizes.length > 0) {
definition.farSizes[definition.farSizes.length - 1] -= axisPadding;
}
if (definition.nearSizes.length > 0) {
definition.nearSizes[definition.nearSizes.length - 1] -= axisPadding;
}
};
/**
* Measure the axis.
*
* @param {Rect} rect - The rect for measuring the axis.
* @returns {void}
* @private
*/
CartesianAxisLayoutPanel.prototype.calculateAxisSize = function (rect) {
var chart = this.chart;
var row;
var column;
var definition;
var axis;
var nearCount = 0;
var farCount = 0;
var size = 0;
var x;
var y;
var axisOffset;
this.calculateRowSize(rect);
var isPrimaryYaxisOutside = false;
for (var i = 0, len = chart.rows.length; i < len; i++) {
row = chart.rows[i];
nearCount = 0;
farCount = 0;
for (var j = 0, len_1 = row.axes.length; j < len_1; j++) {
axis = row.axes[j];
axisOffset = axis.plotOffset;
if (axis.rect.height === 0) {
axis.rect.height = row.computedHeight;
size = 0;
for (var k = i + 1, len_2 = i + axis.span; k < len_2; k++) {
definition = chart.rows[k];
size += definition.computedHeight;
}
axis.rect.y = (row.computedTop - size) + (axis.plotOffsetTop ? axis.plotOffsetTop : axisOffset);
axis.rect.height = (axis.rect.height + size) -
(this.getAxisOffsetValue(axis.plotOffsetTop, axis.plotOffsetBottom, axis.plotOffset));
axis.rect.width = 0;
}
if (axis.name === 'primaryYAxis' && axis.labelPosition === 'Outside') {
isPrimaryYaxisOutside = true;
}
if (axis.isAxisOpposedPosition) {
if (axis.labelPosition === 'Inside' && axis.orientation === 'Vertical') {
if (farCount > 0) {
x = rect.x + rect.width + sum(subArray(row.farSizes, farCount))
+ axis.maxLabelSize.width + axis.multiLevelLabelHeight + (axis.tickPosition === 'Inside' ? axis.majorTickLines.height : 0) + axis.labelPadding;
}
else {
x = rect.x + rect.width - sum(subArray(row.insideFarSizes, farCount));
}
}
else {
x = rect.x + rect.width + sum(subArray(row.farSizes, farCount));
}
axis.rect.x = axis.rect.x >= x ? axis.rect.x : x;
farCount++;
}
else {
if (axis.labelPosition === 'Inside' && axis.orientation === 'Vertical') {
x = rect.x + sum(subArray(row.insideNearSizes, isPrimaryYaxisOutside ? nearCount - 1 : nearCount));
}
else {
x = rect.x - sum(subArray(row.nearSizes, nearCount));
}
axis.rect.x = axis.rect.x <= x ? axis.rect.x : x;
nearCount++;
}
}
}
this.calculateColumnSize(rect);
for (var i = 0, len = chart.columns.length; i < len; i++) {
column = chart.columns[i];
nearCount = 0;
farCount = 0;
for (var j = 0, len_3 = column.axes.length; j < len_3; j++) {
axis = column.axes[j];
axisOffset = axis.plotOffset;
if (axis.rect.width === 0) {
for (var k = i, len_4 = (i + axis.span); k < len_4; k++) {
definition = chart.columns[k];
axis.rect.width += definition.computedWidth;
}
axis.rect.x = column.computedLeft + (axis.plotOffsetLeft ? axis.plotOffsetLeft : axisOffset);
axis.rect.width -= (this.getAxisOffsetValue(axis.plotOffsetLeft, axis.plotOffsetRight, axis.plotOffset));
axis.rect.height = 0;
}
if (axis.isAxisOpposedPosition) {
if (axis.labelPosition === 'Inside' && axis.orientation === 'Horizontal') {
if (farCount > 0) {
y = rect.y - sum(subArray(column.farSizes, farCount)) - axis.maxLabelSize.height
- axis.multiLevelLabelHeight - (axis.tickPosition === 'Inside' ? axis.majorTickLines.height : 0) - axis.labelPadding;
}
else {
y = rect.y + sum(subArray(column.insideFarSizes, farCount));
}
}
else {
y = rect.y - sum(subArray(column.farSizes, farCount));
}
axis.rect.y = axis.rect.y <= y ? axis.rect.y : y;
farCount++;
}
else {
if (axis.labelPosition === 'Inside' && axis.orientation === 'Horizontal') {
if (nearCount > 0) {
y = rect.y + rect.height + sum(subArray(column.nearSizes, nearCount)) + axis.maxLabelSize.height
+ axis.multiLevelLabelHeight + (axis.tickPosition === 'Inside' ? axis.majorTickLines.height : 0) + axis.labelPadding;
}
else {
y = rect.y + rect.height - sum(subArray(column.insideNearSizes, nearCount));
}
}
else {
y = rect.y + rect.height + sum(subArray(column.nearSizes, nearCount));
}
axis.rect.y = axis.rect.y >= y ? axis.rect.y : y;
nearCount++;
}
}
}
};
/**
* Measure the axis.
*
* @returns {void}
* @private
*/
CartesianAxisLayoutPanel.prototype.measure = function () {
var chart = this.chart;
var row;
var column;
var definition;
var actualIndex;
var span;
for (var _i = 0, _a = chart.axisCollections; _i < _a.length; _i++) {
var axis = _a[_i];
//definition.Axes = axis;
if (axis.orientation === 'Vertical') {
chart.verticalAxes.push(axis);
actualIndex = this.getActualRow(axis);
row = chart.rows[actualIndex];
this.pushAxis(row, axis);
span = ((actualIndex + axis.span) > chart.rows.length ? chart.rows.length : (actualIndex + axis.span));
for (var j = actualIndex + 1; j < span; j++) {
definition = chart.rows[j];
definition.axes[row.axes.length - 1] = axis;
chart.rows[j] = definition;
}
chart.rows[actualIndex] = row;
}
else {
chart.horizontalAxes.push(axis);
actualIndex = this.getActualColumn(axis);
column = chart.columns[actualIndex];
this.pushAxis(column, axis);
span = ((actualIndex + axis.span) > chart.columns.length ? chart.columns.length : (actualIndex + axis.span));
for (var j = actualIndex + 1; j < span; j++) {
definition = chart.columns[j];
definition.axes[column.axes.length - 1] = axis;
chart.columns[j] = definition;
}
chart.columns[actualIndex] = column;
}
axis.isRTLEnabled = chart.enableRtl;
axis.setIsInversedAndOpposedPosition();
}
};
CartesianAxisLayoutPanel.prototype.getAxisOffsetValue = function (position1, position2, plotOffset) {
var rangeOffset = position1 ? (position1 + (position2 ? position2 :
plotOffset)) : (position2 ? position2 + plotOffset : 2 * plotOffset);
return rangeOffset;
};
CartesianAxisLayoutPanel.prototype.crossAt = function (chart) {
for (var _i = 0, _a = chart.axisCollections; _i < _a.length; _i++) {
var axis = _a[_i];
if (axis.crossesAt === null) {
continue;
}
if (!axis.crossesInAxis) {
if (chart.requireInvertedAxis) {
axis.crossInAxis = ((axis.orientation === 'Horizontal')) ? chart.primaryXAxis : chart.primaryYAxis;
}
else {
axis.crossInAxis = ((axis.orientation === 'Horizontal')) ? chart.primaryYAxis : chart.primaryXAxis;
}
axis.crossAt = this.updateCrossAt(axis.crossInAxis, axis.crossesAt);
continue;
}
else {
for (var i = 2, len = chart.axisCollections.length; i < len; i++) {
if (axis.crossesInAxis === chart.axisCollections[i].name) {
axis.crossInAxis = chart.axisCollections[i];
axis.crossAt = this.updateCrossAt(axis.crossInAxis, axis.crossesAt);
continue;
}
}
}
}
};
CartesianAxisLayoutPanel.prototype.updateCrossAt = function (axis, crossAt) {
switch (axis.valueType) {
case 'DateTime': {
var option = {
skeleton: 'full',
type: 'dateTime'
};
var dateParser = this.chart.intl.getDateParser(option);
var dateFormatter = this.chart.intl.getDateFormat(option);
return Date.parse(dateParser(dateFormatter(new Date(DataUtil.parse.parseJson({ val: crossAt }).val))));
}
case 'Category':
return parseFloat(crossAt) ? parseFloat(crossAt) : axis.labels.indexOf(crossAt);
case 'Logarithmic':
return logBase(crossAt, axis.logBase);
default:
return crossAt;
}
};
CartesianAxisLayoutPanel.prototype.pushAxis = function (definition, axis) {
for (var i = 0, len = definition.axes.length; i <= len; i++) {
if (!definition.axes[i]) {
definition.axes[i] = axis;
break;
}
}
};
CartesianAxisLayoutPanel.prototype.arrangeAxis = function (definition) {
var axisCollection = [];
for (var i = 0, len = definition.axes.length; i <= len; i++) {
if (definition.axes[i]) {
axisCollection.push(definition.axes[i]);
}
}
definition.axes = axisCollection;
};
CartesianAxisLayoutPanel.prototype.getActualColumn = function (axis) {
var actualLength = this.chart.columns.length;
var pos = axis.columnIndex;
var result = pos >= actualLength ? actualLength - 1 : (pos < 0 ? 0 : pos);
return result;
};
CartesianAxisLayoutPanel.prototype.getActualRow = function (axis) {
var actualLength = this.chart.rows.length;
var pos = axis.rowIndex;
var result = pos >= actualLength ? actualLength - 1 : (pos < 0 ? 0 : pos);
return result;
};
/**
* Measure the row size.
*
* @returns {void}
*/
CartesianAxisLayoutPanel.prototype.calculateRowSize = function (rect) {
/** Calculate row size */
var chart = this.chart;
var row;
var rowTop = rect.y + rect.height;
var height = 0;
var remainingHeight = Math.max(0, rect.height);
for (var i = 0, len = chart.rows.length; i < len; i++) {
row = chart.rows[i];
if (row.height.indexOf('%') !== -1) {
height = Math.min(remainingHeight, (rect.height * parseInt(row.height, 10) / 100));
}
else {
height = Math.min(remainingHeight, parseInt(row.height, 10));
}
height = (i !== (len - 1)) ? height : remainingHeight;
row.computedHeight = height;
rowTop -= height;
row.computedTop = rowTop;
remainingHeight -= height;
}
};
/**
* Measure the row size.
*
* @param {Rect} rect rect
* @returns {void}
*/
CartesianAxisLayoutPanel.prototype.calculateColumnSize = function (rect) {
/** Calculate column size */
var chart = this.chart;
var column;
var columnLeft = rect.x;
var width = 0;
var remainingWidth = Math.max(0, rect.width);
for (var i = 0, len = chart.columns.length; i < len; i++) {
column = chart.columns[i];
if (column.width.indexOf('%') !== -1) {
width = Math.min(remainingWidth, (rect.width * parseInt(column.width, 10) / 100));
}
else {
width = Math.min(remainingWidth, parseInt(column.width, 10));
}
width = (i !== (len - 1)) ? width : remainingWidth;
column.computedWidth = width;
column.computedLeft = columnLeft;
columnLeft += width;
remainingWidth -= width;
}
};
/**
* To render the axis element.
*
* @returns {void}
* @private
*/
CartesianAxisLayoutPanel.prototype.renderAxes = function () {
var chart = this.chart;
var axis;
var axisElement = chart.renderer.createGroup({ id: chart.element.id + 'AxisInsideCollection' });
var axisLineElement = chart.renderer.createGroup({ id: chart.element.id + 'AxisOutsideCollection' });
if (axisLineElement) {
axisLineElement.setAttribute('aria-hidden', 'true');
}
var outsideElement;
var isInside;
if (chart.scrollBarModule) {
chart.scrollBarModule.topScrollBarCount = 0;
chart.scrollBarModule.bottomScrollBarCount = 0;
chart.scrollBarModule.leftScrollBarCount = 0;
chart.scrollBarModule.rightScrollBarCount = 0;
}
for (var i = 0, len = chart.axisCollections.length; i < len; i++) {
var axisVisibility = true;
axis = chart.axisCollections[i];
axis.index = i;
this.element = chart.renderer.createGroup({ id: chart.element.id + 'AxisGroup' + i + 'Inside' });
if (this.element) {
this.element.setAttribute('aria-hidden', 'true');
}
outsideElement = chart.renderer.createGroup({ id: chart.element.id + 'AxisGroup' + i + 'Outside' });
if (outsideElement) {
outsideElement.setAttribute('aria-hidden', 'true');
}
for (var _i = 0, _a = axis.series; _i < _a.length; _i++) {
var series = _a[_i];
if (axis.name === series.yAxisName || axis.name === series.xAxisName) {
axisVisibility = series.visible;
if (series.category === 'Pareto' && !series.paretoOptions.showAxis && series.type === 'Line') {
axisVisibility = false;
}
if (!axisVisibility) {
continue;
}
else {
break;
}
}
}
if (!axisVisibility) {
if (axis.zoomingScrollBar) {
axis.zoomingScrollBar.removeScrollSvg();
}
continue;
}
isInside = this.findAxisPosition(axis);
this.drawAxis(axis, i, isInside, outsideElement, axisElement, axisLineElement);
}
this.drawPaneLines(chart, axisElement);
appendChildElement(chart.enableCanvas, chart.svgObject, axisElement, chart.redraw);
return axisLineElement;
};
/**
* To render the axis scrollbar
*
* @param {Chart} chart chart
* @param {Axis} axis axis
* @returns {void}
*/
CartesianAxisLayoutPanel.prototype.renderScrollbar = function (chart, axis) {
var isZoomed = isNullOrUndefined(chart.zoomModule) ? false : chart.zoomModule.isZoomed;
if (!axis.zoomingScrollBar) {
chart.scrollBarModule.injectTo(axis, chart);
}
if (((isZoomed && (axis.zoomFactor < 1 || axis.zoomPosition > 0)) || (axis.scrollbarSettings.enable &&
(axis.zoomFactor <= 1 || axis.zoomPosition >= 0))) &&
(!axis.zoomingScrollBar.isScrollUI)) {
if (!chart.scrollElement) {
chart.scrollElement = redrawElement(chart.redraw, chart.element.id + '_scrollElement') || createElement('div', { id: chart.element.id + '_scrollElement' });
}
appendChildElement(false, chart.scrollElement, axis.zoomingScrollBar.render(true), true);
}
else if (axis.zoomFactor === 1 && axis.zoomPosition === 0 && axis.zoomingScrollBar.svgObject && !axis.scrollbarSettings.enable) {
axis.zoomingScrollBar.destroy();
}
else if (axis.zoomingScrollBar.svgObject) {
var topOffset = (axis.isAxisOpposedPosition && axis.orientation === 'Horizontal' ? -16 : 0)
+ axis.rect.y + Math.max(0.5, axis.lineStyle.width / 2);
var leftOffset = (axis.isAxisOpposedPosition && axis.orientation !== 'Horizontal' ? 16 : 0)
+ (axis.rect.x - (axis.orientation === 'Horizontal' && axis.scrollbarSettings.enableZoom ? axis.zoomingScrollBar.svgExtraWidth / 2 : 0))
- (axis.orientation === 'Vertical' ? axis.scrollbarSettings.height : 0);
if (axis.orientation !== 'Horizontal' && (axis.scrollbarSettings.position === 'Left' || axis.scrollbarSettings.position === 'Right')) {
leftOffset = calculateScrollbarOffset(axis.zoomingScrollBar, false);
}
else if (axis.orientation === 'Horizontal' && (axis.scrollbarSettings.position === 'Top' || axis.scrollbarSettings.position === 'Bottom')) {
topOffset = calculateScrollbarOffset(axis.zoomingScrollBar, true);
}
axis.zoomingScrollBar.svgObject.style.top = topOffset + 'px';
axis.zoomingScrollBar.svgObject.style.left = leftOffset + 'px';
}
if (axis.zoomingScrollBar.isScrollUI) {
axis.zoomingScrollBar.isScrollUI = false;
}
};
/**
* Draws pane lines for the specified chart.
*
* @param {Chart} chart -The chart for which pane lines are to be drawn.
* @param {Element} [axisElement] -Optional. The axis element to which the pane lines are associated.
* @returns {void}
* @private
*/
CartesianAxisLayoutPanel.prototype.drawPaneLines = function (chart, axisElement) {
this.element = chart.renderer.createGroup({ id: chart.element.id + 'DefinitionLine' });
for (var j = 0, len = chart.rows.length; j < len; j++) {
var row = chart.rows[j];
if (row.border.color) {
this.drawBottomLine(row, j, true);
}
}
for (var j = 0, len = chart.columns.length; j < len; j++) {
var column = chart.columns[j];
if (column.border.color) {
this.drawBottomLine(column, j, false);
}
}
axisElement = axisElement ? axisElement : getElement(chart.element.id + 'AxisInsideCollection');
if (!this.chart.enableCanvas) {
axisElement.appendChild(this.element);
}
};
/**
* Draws an axis for the specified axis configuration.
*
* @private
* @param {Axis} axis -The axis configuration to be drawn.
* @param {number} index -The index of the axis.
* @param {boolean} isInside -Indicates whether the axis is inside or outside the plot area.
* @param {Element} outsideElement -The element where the axis should be drawn if it's outside the plot area.
* @param {Element} axisElement -The element representing the axis.
* @param {Element} axisLineElement -The element representing the axis line.
* @returns {void}
*/
CartesianAxisLayoutPanel.prototype.drawAxis = function (axis, index, isInside, outsideElement, axisElement, axisLineElement) {
axis.updateCrossValue();
var axisName = '';
if (axis.orientation === 'Horizontal') {
if (axis.visible && axis.internalVisibility && axis.lineStyle.width > 0) {
this.drawAxisLine(axis, index, axis.plotOffset, 0, 0, 0, axis.plotOffsetLeft, axis.plotOffsetRight, isInside ? outsideElement : this.element, axis.updatedRect);
}
axisName = 'X';
}
else {
if (axis.visible && axis.internalVisibility && axis.lineStyle.width > 0) {
this.drawAxisLine(axis, index, 0, axis.plotOffset, axis.plotOffsetBottom, axis.plotOffsetTop, 0, 0, isInside ? outsideElement : this.element, axis.updatedRect);
}
axisName = 'Y';
}
if (axis.majorGridLines.width > 0 || axis.majorTickLines.width > 0 || axis.minorTickLines.width > 0 ||
axis.minorGridLines.width > 0) {
this['draw' + axisName + 'AxisGridLine'](axis, index, (isInside || axis.tickPosition === 'Inside') ? outsideElement : this.element, axis.updatedRect);
}
if (axis.visible && axis.internalVisibility) {
this['draw' + axisName + 'AxisLabels'](axis, index, (isInside || axis.labelPosition === 'Inside') ? outsideElement : this.element, (axis.placeNextToAxisLine ? axis.updatedRect : axis.rect));
this['draw' + axisName + 'AxisBorder'](axis, index, (isInside || axis.labelPosition === 'Inside') ? outsideElement : this.element, (axis.placeNextToAxisLine ? axis.updatedRect : axis.rect));
this['draw' + axisName + 'AxisTitle'](axis, index, isInside ? outsideElement : this.element, (axis.placeNextToAxisLine ? axis.updatedRect : axis.rect));
}
if (!this.chart.enableCanvas) {
axisElement.appendChild(this.element);
if (outsideElement && outsideElement.childNodes.length > 0) {
axisLineElement.appendChild(outsideElement);
}
}
if (this.chart.scrollBarModule && ((this.chart.zoomSettings.enableScrollbar && axis.enableScrollbarOnZooming) ||
axis.scrollbarSettings.enable)) {
this.renderScrollbar(this.chart, axis);
}
else {
if (axis.zoomingScrollBar) {
axis.zoomingScrollBar.destroy();
}
}
};
/**
* To find the axis position
*
* @param {Axis} axis axis
* @returns {boolean} axis position
* @private
*/
CartesianAxisLayoutPanel.prototype.findAxisPosition = function (axis) {
return axis.crossAt !== null && axis.isInside(axis.crossInAxis.visibleRange);
};
/**
* To render the bootom line of the columns and rows
*
* @param {Row | Column} definition definition
* @param {number} index index
* @param {boolean} isRow isRow
* @returns {void}
*/
CartesianAxisLayoutPanel.prototype.drawBottomLine = function (definition, index, isRow) {
var chart = this.chart;
var optionsLine = {};
var x1;
var x2;
var y1;
var y2;
var definitionName;
if (isRow) {
definition = definition;
y1 = y2 = definition.computedTop + definition.computedHeight;
x1 = this.seriesClipRect.x;
x2 = x1 + this.seriesClipRect.width;
definitionName = 'Row';
}
else {
definition = definition;
x1 = x2 = definition.computedLeft;
y1 = this.seriesClipRect.y;
y2 = y1 + this.seriesClipRect.height;
definitionName = 'Column';
}
optionsLine = {
'id': chart.element.id + '_AxisBottom_' + definitionName + index,
x1: x1,
y1: y1,
x2: x2,
y2: y2,
'stroke-width': definition.border.width,
'stroke': definition.border.color
};
this.htmlObject = chart.renderer.drawLine(optionsLine);
appendChildElement(chart.enableCanvas, this.element, this.htmlObject);
};
/**
* To render the axis line
*
* @param {Axis} axis axis
* @param {number} index index
* @param {number} plotX plotX
* @param {number} plotY plotY
* @param {number} plotBottom plotBottom
* @param {number} plotTop plotTop
* @param {number} plotLeft plotLeft
* @param {number} plotRight plotRight
* @param {Element} parent parent
* @param {Rect} rect rect
* @returns {void}
*/
CartesianAxisLayoutPanel.prototype.drawAxisLine = function (axis, index, plotX, plotY, plotBottom, plotTop, plotLeft, plotRight, parent, rect) {
var chart = this.chart;
var optionsLine = {};
var element = getElement(chart.element.id + 'AxisLine_' + index);
var direction = element ? element.getAttribute('d') : '';
element = null;
optionsLine = {
'id': chart.element.id + 'AxisLine_' + index,
'd': 'M ' + (rect.x - plotX - plotLeft) + ' ' + (rect.y - plotY - plotTop) +
' L ' + (rect.x + rect.width + plotX + plotRight) + ' ' + (rect.y + rect.height + plotY + plotBottom),
'stroke-dasharray': axis.lineStyle.dashArray,
'stroke-width': axis.lineStyle.width,
'stroke': axis.lineStyle.color || chart.themeStyle.axisLine
};
this.htmlObject = chart.renderer.drawPath(optionsLine);
appendChildElement(chart.enableCanvas, parent, this.htmlObject, chart.redraw, true, 'x', 'y', null, direction, null, null, null, chart.duration);
};
/**
* To render the yAxis grid line
*
* @param {Axis} axis axis
* @param {number} index index
* @param {Element} parent parent
* @param {Rect} rect rect
* @returns {void}
*/
CartesianAxisLayoutPanel.prototype.drawYAxisGridLine = function (axis, index, parent, rect) {
var isLogAxis = axis.valueType === 'Logarithmic';
var isCategoryAxis = axis.valueType.indexOf('Category') > -1;
var tempInterval;
var pointY = 0;
var majorGrid = '';
var majorTick = '';
var minorGridDirection;
var isOpposed = axis.isAxisOpposedPosition;
var tickSize = isOpposed ? axis.majorTickLines.height : -axis.majorTickLines.height;
var axisLineSize = (isOpposed) ? axis.lineStyle.width * 0.5 : -axis.lineStyle.width * 0.5;
var ticksbwtLabel = (axis.valueType === 'Category' && axis.labelPlacement === 'BetweenTicks') ?
0.5 : 0;
var scrollBarHeight = (isNullOrUndefined(axis.crossesAt) && axis.scrollbarSettings.position !== 'Right' && axis.scrollbarSettings.position !== 'Left') ? isOpposed ? axis.scrollBarHeight :
-axis.scrollBarHeight : 0;
var isTickInside = axis.tickPosition === 'Inside';
var ticks = isTickInside ? (rect.x - tickSize - axisLineSize) : (rect.x + tickSize + axisLineSize + scrollBarHeight);
var length = axis.visibleLabels.length;
var chartThemeStyle = this.chart.themeStyle;
var count = 1;
if (axis.valueType.indexOf('Category') > -1 && axis.labelPlacement === 'BetweenTicks' && length > 0 && !this.chart.stockChart) {
length += 1;
}
var minorGridLines = axis.minorGridLines;
var minorTickLines = axis.minorTickLines;
//Gridlines
for (var i = 0; i < length; i++) {
tempInterval = !axis.visibleLabels[i] ? (axis.visibleLabels[i - 1].value + axis.visibleRange.interval) - ticksbwtLabel
: axis.visibleLabels[i].value - ticksbwtLabel;
pointY = valueToCoefficient(tempInterval, axis) * rect.height;
pointY = (pointY * -1) + (rect.y + rect.height);
if (pointY >= rect.y && (rect.y + rect.height) >= pointY) {
if (this.chart.redraw && !this.chart.enableCanvas && this.chart.zoomRedraw && axis.visible && axis.majorGridLines.width && i !== 0 && !getElement(this.chart.element.id + '_MajorGridLine_' + index + '_' + i)) {
majorGrid = 'M ' + this.seriesClipRect.x + ' ' + (this.seriesClipRect.y + (axis.isInversed ? this.seriesClipRect.height + ((this.seriesClipRect.height / (i ? i : 1)) * count) : -((this.seriesClipRect.height / (i ? i : 1)) * count))) +
' L ' + (this.seriesClipRect.x + this.seriesClipRect.width) + ' ' + (this.seriesClipRect.y + (axis.isInversed ? this.seriesClipRect.height + ((this.seriesClipRect.height / (i ? i : 1)) * count) : -((this.seriesClipRect.height / (i ? i : 1)) * count)));
this.updateAxisElement(axis, index, majorGrid, i, '_MajorGridLine_', this.element, false);
getElement(parent.id).appendChild(this.element.childNodes[this.element.childNodes.length - 1]);
}
if ((inside(tempInterval, axis.visibleRange)) || this.isBorder(axis, i, pointY)) {
majorGrid = 'M ' + this.seriesClipRect.x + ' ' + (pointY) +
' L ' + (this.seriesClipRect.x + this.seriesClipRect.width) + ' ' + pointY;
this.renderGridLine(axis, index, majorGrid, axis.majorGridLines, '_MajorGridLine_', i, this.element, chartThemeStyle.majorGridLine, axis.majorGridLines.dashArray);
}
if (this.chart.redraw && this.chart.zoomRedraw && axis.majorTickLines.width && i !== 0 && !getElement(this.chart.element.id + '_MajorTickLine_' + index + '_' + i) && !this.chart.enableCanvas && axis.visible) {
majorTick = 'M ' + this.seriesClipRect.x + ' ' + (this.seriesClipRect.y + (axis.isInversed ? this.seriesClipRect.height + ((this.seriesClipRect.height / (i ? i : 1)) * count) : -((this.seriesClipRect.height / (i ? i : 1)) * count))) +
' L ' + ticks + ' ' + (this.seriesClipRect.y + (axis.isInversed ? this.seriesClipRect.height + ((this.seriesClipRect.height / (i ? i : 1)) * count) : -((this.seriesClipRect.height / (i ? i : 1)) * count)));
this.updateAxisElement(axis, index, majorTick, i, '_MajorTickLine_', parent, false);
getElement(parent.id).appendChild(this.element.childNodes[this.element.childNodes.length - 1]);
count += 1;
}
majorTick = 'M ' + (rect.x + axisLineSize + (isTickInside ? scrollBarHeight : 0)) + ' ' + pointY +
' L ' + (ticks) + ' ' + pointY;
this.renderGridLine(axis, index, majorTick, axis.majorTickLines, '_MajorTickLine_', i, parent, chartThemeStyle.majorTickLine);
if ((minorGridLines.width > 0 || minorTickLines.width > 0) && axis.minorTicksPerInterval > 0) {
if (i === 0 && isZoomSet(axis) && !isLogAxis && !isCategoryAxis) {
this.renderMinorGridOnZooming(axis, tempInterval, rect, i, index, chartThemeStyle, parent);
}
minorGridDirection = this.drawAxisMinorLine(axis, tempInterval, rect, i);
this.renderGridLine(axis, index, minorGridDirection[0], minorGridLines, '_MinorGridLine_', i, this.element, chartThemeStyle.minorGridLine, minorGridLines.dashArray);
this.renderGridLine(axis, index, minorGridDirection[1], minorTickLines, '_MinorTickLine_', i, parent, chartThemeStyle.minorTickLine);
if (i === length - 1 && isZoomSet(axis) && isLogAxis && !isCategoryAxis) {
this.renderMinorGridOnZooming(axis, (tempInterval + axis.visibleRange.interval), rect, i, index, chartThemeStyle, parent);
}
}
}
}
if (length && this.previousYLabel > length && !this.chart.enableCanvas && axis.visible &&
this.chart.zoomRedraw && this.chart.redraw) {
for (var i = length; i < this.previousYLabel; i++) {
var pointYValue = this.seriesClipRect.y + (axis.isInversed ? ((this.seriesClipRect.height / length) *
((i - length) + 1)) + this.seriesClipRect.height : -((this.seriesClipRect.height / length) * ((i - length) + 1)));
if (axis.majorGridLines.width) {
majorGrid = 'M ' + this.seriesClipRect.x + ' ' + +pointYValue +
' L ' + (this.seriesClipRect.x + this.seriesClipRect.width) + ' ' + pointYValue;
this.updateAxisElement(axis, index, majorGrid, i, '_MajorGridLine_', this.element, true);
}
if (axis.majorTickLines.width) {
majorTick = 'M ' + this.seriesClipRect.x + ' ' + pointYValue +
' L ' + ticks + ' ' + pointYValue;
this.updateAxisElement(axis, index, majorTick, i, '_MajorTickLine_', parent, true);
}
}
}
};
/**
* To check the border of the axis
*
* @param {Axis} axis axis
* @param {number} index index
* @param {number} value value
* @returns {boolean} check the border of the axis
*/
CartesianAxisLayoutPanel.prototype.isBorder = function (axis, index, value) {
var border = this.chart.chartArea.border;
var rect = this.seriesClipRect;
var orientation = axis.orientation;
var start = (orientation === 'Horizontal') ? rect.x : rect.y;
var size = (orientation === 'Horizontal') ? rect.width : rect.height;
var startIndex = (orientation === 'Horizontal') ? 0 : axis.visibleLabels.length - 1;
var endIndex = (orientation === 'Horizontal') ? axis.visibleLabels.length - 1 : 0;
if (axis.plotOffset > 0) {
return true;
}
else if ((value === start || value === (start + size)) && (border.width <= 0 || border.color === 'transparent')) {
return true;
}
else if ((value !== start && index === startIndex) || (value !== (start + size) && index === endIndex)) {
return true;
}
return false;
};
/**
* To render the yAxis label
*
* @param {Axis} axis axis
* @param {number} index index
* @param {Element} parent parent
* @param {Rect} rect rect
* @returns {void}
* @private
*/
CartesianAxisLayoutPanel.prototype.drawYAxisLabels = function (axis, index, parent, rect) {
var chart = this.chart;
var label;
var pointX = 0;
var pointY = 0;
var elementSize;
var labelSpace = axis.labelPadding;
var options;
var isAxisBreakLabel;
var isLabelInside = axis.labelPosition === 'Inside';
var isOpposed = axis.isAxisOpposedPosition;
var RotatedWidth;
var tickSpace = axis.labelPosition === axis.tickPosition ? axis.majorTickLines.height : 0;
var padding = tickSpace + labelSpace + axis.lineStyle.width * 0.5;
var angle = axis.angle % 360;
var isVerticalAngle = (angle === -90 || angle === 90 || angle === 270 || angle === -270);
padding += (isVerticalAngle) ? (isLabelInside ? 5 : -5) : 0;
padding = (isOpposed) ? padding : -padding;
var labelElement = chart.renderer.createGroup({ id: chart.element.id + 'AxisLabels' + index });
var scrollBarHeight = (isNullOrUndefined(axis.crossesAt) && axis.scrollbarSettings.position !== 'Left' && axis.scrollbarSettings.position !== 'Right') ? axis.scrollBarHeight * (isOpposed ? 1 : -1) : 0;
var textHeight;
var textPadding;
var maxLineWidth;
var pixel = 10;
var isInverse = axis.isAxisInverse;
var count = 1;
var previousEnd = isInverse ? rect.y : (rect.y + rect.height);
var labelPadding;
var intervalLength;
var labelHeight;
var yAxisLabelX;
var isLabelOnAxisLineLeft = ((!isOpposed && !isLabelInside) || (isOpposed && isLabelInside));
if (isLabelInside) {
labelPadding = !isLabelOnAxisLineLeft ? -padding : padding;
}
else {
labelPadding = !isLabelOnAxisLineLeft ? -padding + (chart.enableRtl ? -scrollBarHeight : scrollBarHeight) :
padding + (chart.enableRtl ? -scrollBarHeight : scrollBarHeight);
}
var sizeWidth = [];
var breakLabelSizeWidth = [];
axis.visibleLabels.map(function (item) {
sizeWidth.push(item.size['width']);
breakLabelSizeWidth.push(item.breakLabelSize['width']);
});
var LabelMaxWidth = Math.max.apply(Math, sizeWidth);
var breakLabelMaxWidth = Math.max.apply(Math, breakLabelSizeWidth);
RotatedWidth = LabelMaxWidth;
if (angle >= -45 && angle <= 45 && angle !== 0) {
RotatedWidth = LabelMaxWidth * Math.cos(angle * Math.PI / 180);
if (RotatedWidth < 0) {
RotatedWidth = -RotatedWidth;
}
}
for (var i = 0, len = axis.visibleLabels.length; i < len; i++) {
label = axis.visibleLabels[i];
isAxisBreakLabel = isBreakLabel(axis.visibleLabels[i].originalText);
elementSize = isAxisBreakLabel ? axis.visibleLabels[i].breakLabelSize : axis.visibleLabels[i].size;
pointY = (valueToCoefficient(axis.visibleLabels[i].value, axis) * rect.height) + (chart.stockChart && axis.labelPosition !== 'Outside' ? 7 : 0);
pointY = Math.floor((pointY * -1) + (rect.y + rect.height));
textHeight = ((elementSize.height / 8) * axis.visibleLabels[i].text.length / 2);
textPadding = (chart.requireInvertedAxis && axis.labelPosition === 'Inside') ? 0 : ((elementSize.height / 4) * 3) + 3;
intervalLength = rect.height / axis.visibleLabels.length;
labelHeight = ((axis.labelIntersectAction === 'Trim' || axis.labelIntersectAction === 'Wrap') && angle !== 0 &&
elementSize.width > intervalLength) ? intervalLength : elementSize.width;
pointY = (isAxisBreakLabel ? (axis.labelPosition === 'Inside' ? (pointY - (elementSize.height / 2) - textHeight + textPadding)
: (pointY - textHeight)) : (axis.labelPosition === 'Inside' ? pointY + textPadding : pointY));
if (axis.labelPosition === 'Inside' && ((i === 0 && !axis.isInversed) || (i === len - 1 && axis.isInversed))) {
if (chart.stockChart) {
pointY -= (textPadding);
}
else {
pointY -= (textPadding - ((chart.requireInvertedAxis && axis.labelPosition === 'Inside') ? 0 : (axis.opposedPosition ? -padding : padding)));
}
}
if (axis.majorGridLines.width > axis.majorTickLines.width) {
maxLineWidth = axis.majorGridLines.width;
}
else {
maxLineWidth = axis.majorTickLines.width;
}
if (axis.labelStyle.textAlignment === 'Far') {
pointY = pointY - maxLineWidth - pixel;
}
else if (axis.labelStyle.textAlignment === 'Near') {
pointY = pointY + maxLineWidth + pixel;
}
// label X value adjustment (Start)
if (isLabelInside) {
yAxisLabelX = labelPadding + ((angle === 0 ? elementSize.width :
(isAxisBreakLabel ? breakLabelMaxWidth : LabelMaxWidth)) / 2);
}
else {
yAxisLabelX = labelPadding - ((angle === 0 ? elementSize.width :
(isAxisBreakLabel ? breakLabelMaxWidth : RotatedWidth)) / 2);
}
if (axis.enableWrap && chart.requireInvertedAxis && angle && ((!axis.opposedPosition && axis.labelPosition === 'Inside') || (axis.opposedPosition && axis.labelPosition === 'Outside'))) {
yAxisLabelX = axis.opposedPosition ? yAxisLabelX - LabelMaxWidth / 2 : yAxisLabelX + LabelMaxWidth / 2;
}
pointX = isOpposed ? (axis.scrollBarHeight !== 0 && axis.scrollbarSettings.position !== 'Right' && axis.scrollbarSettings.position !== 'Left') ? ((rect.x + axis.scrollBarHeight + padding) - yAxisLabelX) :
(rect.x - yAxisLabelX) : (rect.x + yAxisLabelX);
if (isVerticalAngle) {
pointX += (isOpposed) ? 5 : -5;
}
yAxisLabelX = labelPadding;
options = new TextOption(chart.element.id + index + '_AxisLabel_' + i, pointX, pointY, 'middle', label.text, '', 'middle', angle);
switch (axis.edgeLabelPlacement) {
case 'None':
break;
case 'Hide':
if (((i === 0 || (isInverse && i === len - 1)) && options.y > rect.y) ||
(((i === len - 1) || (isInverse && i === 0)) && options.y - elementSize.height * 0.5 < rect.y)) {
options.text = '';
}
break;
case 'Shift':
if ((i === 0 || (isInverse && i === len - 1)) && options.y > rect.y + rect.height) {
options.y = pointY = rect.y + rect.height;
}
else if (((i === len - 1) || (isInverse && i === 0)) &&
(options.y <= 0)) {
options.y = pointY = rect.y + elementSize.height * 0.5;
}
break;
}
// ------- Hide Calculation (Start) -------------
var previousYValue = options.y;
var currentYValue = options.y - labelHeight;
if (isAxisBreakLabel) {
previousYValue = (options.y - (labelHeight / 2));
currentYValue = options.y + (labelHeight / 2);
}
if ((angle === 90 || angle === 270) && axis.labelIntersectAction === 'Hide' && i !== 0 &&
(!isInverse ? previousYValue >= previousEnd : currentYValue <= previousEnd)) {
continue;
}
previousEnd = isInverse ? previousYValue : currentYValue;
// ------- Hide Calculation (End) -------------
options.transform = 'rotate(' + angle + ',' + pointX + ',' + pointY + ')';
if (this.chart.redraw && this.chart.zoomRedraw && !getElement(options.id) && !this.chart.enableCanvas && axis.visible) {
var optionsY = options.y;
options.y = this.seriesClipRect.y + (axis.isInversed ? this.seriesClipRect.height + ((this.seriesClipRect.height /
(i ? i : 1)) * count) : -((this.seriesClipRect.height / (i ? i : 1)) * count));
this.updateAxisElement(axis, index, '', i, '_AxisLabel_', labelElement, false, options, label);
options.y = optionsY;
count += 1;
}
textElement(chart.renderer, options, label.labelStyle, label.labelStyle.color || chart.themeStyle.axisLabelFont.color, labelElement, false, chart.redraw, true, true, chart.du