devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,098 lines (1,072 loc) • 64.1 kB
JavaScript
/**
* DevExtreme (cjs/__internal/viz/m_chart.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _component_registrator = _interopRequireDefault(require("../../core/component_registrator"));
var _common = require("../../core/utils/common");
var _extend2 = require("../../core/utils/extend");
var _iterator = require("../../core/utils/iterator");
var _math = require("../../core/utils/math");
var _size = require("../../core/utils/size");
var _type = require("../../core/utils/type");
var _window = require("../../core/utils/window");
var _crosshair = require("../../viz/chart_components/crosshair");
var _layout_manager = require("../../viz/chart_components/layout_manager");
var _multi_axes_synchronizer = _interopRequireDefault(require("../../viz/chart_components/multi_axes_synchronizer"));
var _scroll_bar = require("../../viz/chart_components/scroll_bar");
var _shutter_zoom = _interopRequireDefault(require("../../viz/chart_components/shutter_zoom"));
var _zoom_and_pan = _interopRequireDefault(require("../../viz/chart_components/zoom_and_pan"));
var _annotations = require("../../viz/core/annotations");
var _utils = require("../../viz/core/utils");
var _range_data_calculator = _interopRequireDefault(require("../../viz/series/helpers/range_data_calculator"));
var _range = require("../../viz/translators/range");
var _utils2 = require("../../viz/utils");
var _m_advanced_chart = require("./chart_components/m_advanced_chart");
var _m_base_chart = require("./chart_components/m_base_chart");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const DEFAULT_PANE_NAME = "default";
const VISUAL_RANGE = "VISUAL_RANGE";
const DEFAULT_PANES = [{
name: "default",
border: {}
}];
const DISCRETE = "discrete";
const {
isArray: isArray
} = Array;
function getFirstAxisNameForPane(axes, paneName, defaultPane) {
let result;
for (let i = 0; i < axes.length; i += 1) {
if (axes[i].pane === paneName || void 0 === axes[i].pane && paneName === defaultPane) {
result = axes[i].name;
break
}
}
if (!result) {
result = axes[0].name
}
return result
}
function changeVisibilityAxisGrids(axis, gridVisibility, minorGridVisibility) {
const gridOpt = axis.getOptions().grid;
const minorGridOpt = axis.getOptions().minorGrid;
gridOpt.visible = gridVisibility;
minorGridOpt && (minorGridOpt.visible = minorGridVisibility)
}
function hideGridsOnNonFirstValueAxisForPane(axesForPane) {
let axisShown = false;
const hiddenStubAxis = [];
const minorGridVisibility = axesForPane.some((axis => {
const minorGridOptions = axis.getOptions().minorGrid;
return null === minorGridOptions || void 0 === minorGridOptions ? void 0 : minorGridOptions.visible
}));
const gridVisibility = axesForPane.some((axis => {
const gridOptions = axis.getOptions().grid;
return null === gridOptions || void 0 === gridOptions ? void 0 : gridOptions.visible
}));
if (axesForPane.length > 1) {
axesForPane.forEach((axis => {
const gridOpt = axis.getOptions().grid;
if (axisShown) {
changeVisibilityAxisGrids(axis, false, false)
} else if (null !== gridOpt && void 0 !== gridOpt && gridOpt.visible) {
if (axis.getTranslator().getBusinessRange().isEmpty()) {
changeVisibilityAxisGrids(axis, false, false);
hiddenStubAxis.push(axis)
} else {
axisShown = true;
changeVisibilityAxisGrids(axis, gridVisibility, minorGridVisibility)
}
}
}));
if (!axisShown && hiddenStubAxis.length) {
changeVisibilityAxisGrids(hiddenStubAxis[0], gridVisibility, minorGridVisibility)
}
}
}
function findAxisOptions(valueAxes, valueAxesOptions, axisName) {
let result;
let axInd;
for (axInd = 0; axInd < valueAxesOptions.length; axInd += 1) {
if (valueAxesOptions[axInd].name === axisName) {
result = valueAxesOptions[axInd];
result.priority = axInd;
break
}
}
if (!result) {
for (axInd = 0; axInd < valueAxes.length; axInd += 1) {
if (valueAxes[axInd].name === axisName) {
result = valueAxes[axInd].getOptions();
result.priority = valueAxes[axInd].priority;
break
}
}
}
return result
}
function findAxis(paneName, axisName, axes) {
const axisByName = axes.find((axis => axis.name === axisName && axis.pane === paneName));
if (axisByName) {
return axisByName
}
if (paneName) {
return findAxis(void 0, axisName, axes)
}
}
function compareAxes(a, b) {
return a.priority - b.priority
}
function doesPaneExist(panes, paneName) {
let found = false;
(0, _iterator.each)(panes, ((_, pane) => {
if (pane.name === paneName) {
found = true;
return false
}
return
}));
return found
}
function accumulate(field, src1, src2, auxSpacing) {
const val1 = src1[field] || 0;
const val2 = src2[field] || 0;
return val1 + val2 + (val1 && val2 ? auxSpacing : 0)
}
function pickMax(field, src1, src2) {
return pickMaxValue(src1[field], src2[field])
}
function pickMaxValue(val1, val2) {
return Math.max(val1 || 0, val2 || 0)
}
function getAxisMargins(axis) {
return axis.getMargins()
}
function getHorizontalAxesMargins(axes, getMarginsFunc) {
return axes.reduce(((margins, axis) => {
var _axis$getOrthogonalAx;
const axisMargins = getMarginsFunc(axis);
const paneMargins = margins.panes[axis.pane] = margins.panes[axis.pane] || {};
const spacing = axis.getMultipleAxesSpacing();
paneMargins.top = accumulate("top", paneMargins, axisMargins, spacing);
paneMargins.bottom = accumulate("bottom", paneMargins, axisMargins, spacing);
paneMargins.left = pickMax("left", paneMargins, axisMargins);
paneMargins.right = pickMax("right", paneMargins, axisMargins);
margins.top = pickMax("top", paneMargins, margins);
margins.bottom = pickMax("bottom", paneMargins, margins);
margins.left = pickMax("left", paneMargins, margins);
margins.right = pickMax("right", paneMargins, margins);
const orthogonalAxis = null === (_axis$getOrthogonalAx = axis.getOrthogonalAxis) || void 0 === _axis$getOrthogonalAx ? void 0 : _axis$getOrthogonalAx.call(axis);
const shouldResetPositionMargin = (null === orthogonalAxis || void 0 === orthogonalAxis ? void 0 : orthogonalAxis.customPositionIsAvailable()) && (!axis.customPositionIsBoundaryOrthogonalAxis() || !orthogonalAxis.customPositionEqualsToPredefined());
if (shouldResetPositionMargin) {
margins[orthogonalAxis.getResolvedBoundaryPosition()] = 0
}
return margins
}), {
panes: {}
})
}
function getVerticalAxesMargins(axes) {
return axes.reduce(((margins, axis) => {
const axisMargins = axis.getMargins();
const paneMargins = margins.panes[axis.pane] = margins.panes[axis.pane] || {};
const spacing = axis.getMultipleAxesSpacing();
paneMargins.top = pickMax("top", paneMargins, axisMargins);
paneMargins.bottom = pickMax("bottom", paneMargins, axisMargins);
paneMargins.left = accumulate("left", paneMargins, axisMargins, spacing);
paneMargins.right = accumulate("right", paneMargins, axisMargins, spacing);
margins.top = pickMax("top", paneMargins, margins);
margins.bottom = pickMax("bottom", paneMargins, margins);
margins.left = pickMax("left", paneMargins, margins);
margins.right = pickMax("right", paneMargins, margins);
return margins
}), {
panes: {}
})
}
function performActionOnAxes(axes, action, actionArgument1, actionArgument2, actionArgument3) {
axes.forEach((axis => {
axis[action](null === actionArgument1 || void 0 === actionArgument1 ? void 0 : actionArgument1[axis.pane], (null === actionArgument2 || void 0 === actionArgument2 ? void 0 : actionArgument2[axis.pane]) || actionArgument2, actionArgument3)
}))
}
function shrinkCanvases(isRotated, canvases, sizes, verticalMargins, horizontalMargins) {
function getMargin(side, margins, pane) {
const m = !(isRotated ? ["left", "right"] : ["top", "bottom"]).includes(side) ? margins : margins.panes[pane] || {};
return m[side]
}
function getMaxMargin(side, margins1, margins2, pane) {
return pickMaxValue(getMargin(side, margins1, pane), getMargin(side, margins2, pane))
}
const getOriginalField = field => `original${field[0].toUpperCase()}${field.slice(1)}`;
function shrink(canvases, paneNames, sizeField, startMargin, endMargin, oppositeMargins) {
paneNames = paneNames.sort(((p1, p2) => canvases[p2][startMargin] - canvases[p1][startMargin]));
paneNames.forEach((pane => {
const canvas = canvases[pane];
oppositeMargins.forEach((margin => {
canvas[margin] = canvas[getOriginalField(margin)] + getMaxMargin(margin, verticalMargins, horizontalMargins, pane)
}))
}));
const firstPane = canvases[paneNames[0]];
const initialEmptySpace = firstPane[sizeField] - firstPane[getOriginalField(endMargin)] - canvases[paneNames.at(-1)][getOriginalField(startMargin)];
let emptySpace = paneNames.reduce(((space, paneName) => {
const maxStartMargin = getMaxMargin(startMargin, verticalMargins, horizontalMargins, paneName);
const maxEndMargin = getMaxMargin(endMargin, verticalMargins, horizontalMargins, paneName);
return space - maxStartMargin - maxEndMargin
}), initialEmptySpace) - _utils.PANE_PADDING * (paneNames.length - 1);
emptySpace -= Object.keys(sizes).reduce(((prev, key) => {
const currentHeight = !(0, _utils.isRelativeHeightPane)(sizes[key]) ? sizes[key].height : 0;
return prev + currentHeight
}), 0);
const initialOffset = firstPane[sizeField] - firstPane[getOriginalField(endMargin)] - (emptySpace < 0 ? emptySpace : 0);
paneNames.reduce(((offset, pane) => {
const canvas = canvases[pane];
const paneSize = sizes[pane];
offset -= getMaxMargin(endMargin, verticalMargins, horizontalMargins, pane);
canvas[endMargin] = firstPane[sizeField] - offset;
offset -= !(0, _utils.isRelativeHeightPane)(paneSize) ? paneSize.height : Math.floor(emptySpace * paneSize.height);
canvas[startMargin] = offset;
offset -= getMaxMargin(startMargin, verticalMargins, horizontalMargins, pane) + _utils.PANE_PADDING;
return offset
}), initialOffset)
}
const paneNames = Object.keys(canvases);
if (!isRotated) {
shrink(canvases, paneNames, "height", "top", "bottom", ["left", "right"])
} else {
shrink(canvases, paneNames, "width", "left", "right", ["top", "bottom"])
}
return canvases
}
function drawAxesWithTicks(axes, condition, canvases, panesBorderOptions) {
if (condition) {
performActionOnAxes(axes, "createTicks", canvases);
_multi_axes_synchronizer.default.synchronize(axes)
}
performActionOnAxes(axes, "draw", !condition && canvases, panesBorderOptions)
}
function shiftAxis(side1, side2) {
const shifts = {};
return function(axis) {
if (!axis.customPositionIsAvailable() || axis.customPositionEqualsToPredefined()) {
const shift = shifts[axis.pane] = shifts[axis.pane] || {
top: 0,
left: 0,
bottom: 0,
right: 0
};
const spacing = axis.getMultipleAxesSpacing();
const margins = axis.getMargins();
axis.shift(shift);
shift[side1] = accumulate(side1, shift, margins, spacing);
shift[side2] = accumulate(side2, shift, margins, spacing)
} else {
axis.shift({
top: 0,
left: 0,
bottom: 0,
right: 0
})
}
}
}
function getCommonSize(side, margins) {
let size = 0;
let paneMargins;
Object.keys(margins.panes).forEach((pane => {
paneMargins = margins.panes[pane];
size += "height" === side ? paneMargins.top + paneMargins.bottom : paneMargins.left + paneMargins.right
}));
return size
}
function checkUsedSpace(sizeShortage, side, axes, getMarginFunc) {
let size = 0;
if (sizeShortage[side] > 0) {
size = getCommonSize(side, getMarginFunc(axes, getAxisMargins));
performActionOnAxes(axes, "hideTitle");
sizeShortage[side] -= size - getCommonSize(side, getMarginFunc(axes, getAxisMargins))
}
if (sizeShortage[side] > 0) {
performActionOnAxes(axes, "hideOuterElements")
}
}
function axisAnimationEnabled(drawOptions, pointsToAnimation) {
const pointsCount = pointsToAnimation.reduce(((sum, count) => sum + count), 0) / pointsToAnimation.length;
return drawOptions.animate && pointsCount <= drawOptions.animationPointsLimit
}
function collectMarkersInfoBySeries(allSeries, filteredSeries, argAxis) {
const series = [];
const overloadedSeries = {};
const argVisualRange = argAxis.visualRange();
const argTranslator = argAxis.getTranslator();
const argViewPortFilter = _range_data_calculator.default.getViewPortFilter(argVisualRange || {});
filteredSeries.forEach((s => {
const valAxis = s.getValueAxis();
const valVisualRange = valAxis.getCanvasRange();
const valTranslator = valAxis.getTranslator();
const seriesIndex = allSeries.indexOf(s);
const valViewPortFilter = _range_data_calculator.default.getViewPortFilter(valVisualRange || {});
overloadedSeries[seriesIndex] = {};
filteredSeries.forEach((sr => {
overloadedSeries[seriesIndex][allSeries.indexOf(sr)] = 0
}));
const seriesPoints = [];
const pointsInViewport = s.getPoints().filter((p => p.getOptions().visible && argViewPortFilter(p.argument) && (valViewPortFilter(p.getMinValue(true)) || valViewPortFilter(p.getMaxValue(true)))));
pointsInViewport.forEach((p => {
const tp = {
seriesIndex: seriesIndex,
argument: p.argument,
value: p.getMaxValue(true),
size: p.bubbleSize || p.getOptions().size,
x: void 0,
y: void 0
};
if (p.getMinValue(true) !== p.getMaxValue(true)) {
const mp = (0, _extend2.extend)({}, tp);
mp.value = p.getMinValue(true);
mp.x = argTranslator.to(mp.argument, 1);
mp.y = valTranslator.to(mp.value, 1);
seriesPoints.push(mp)
}
tp.x = argTranslator.to(tp.argument, 1);
tp.y = valTranslator.to(tp.value, 1);
seriesPoints.push(tp)
}));
overloadedSeries[seriesIndex].pointsCount = seriesPoints.length;
overloadedSeries[seriesIndex].total = 0;
overloadedSeries[seriesIndex].continuousSeries = 0;
series.push({
name: s.name,
index: seriesIndex,
points: seriesPoints
})
}));
return {
series: series,
overloadedSeries: overloadedSeries
}
}
const isOverlay = (currentPoint, overlayPoint, pointRadius) => {
const pointHitsLeftBorder = overlayPoint.x - pointRadius <= currentPoint.x;
const pointHitsRightBorder = overlayPoint.x + pointRadius >= currentPoint.x;
const pointHitsTopBorder = overlayPoint.y - pointRadius <= currentPoint.y;
const pointHitsBottomBorder = overlayPoint.y + pointRadius >= currentPoint.y;
const isPointOverlappedHorizontally = pointHitsLeftBorder && pointHitsRightBorder;
const isPointOverlappedVertically = pointHitsTopBorder && pointHitsBottomBorder;
return isPointOverlappedHorizontally && isPointOverlappedVertically
};
const isPointOverlapped = (currentPoint, points, skipSamePointsComparing) => {
const radiusPoint = currentPoint.getOptions().size / 2;
for (let i = 0; i < points.length; i += 1) {
if (!skipSamePointsComparing) {
const isXCoordinateSame = points[i].x === currentPoint.x;
const isYCoordinateSame = points[i].y === currentPoint.y;
if (isXCoordinateSame && isYCoordinateSame) {
continue
}
}
if (isOverlay(currentPoint, points[i], radiusPoint)) {
return true
}
}
return false
};
function fastHidingPointMarkersByArea(canvas, markersInfo, series) {
const area = canvas.width * canvas.height;
const seriesPoints = markersInfo.series;
for (let i = seriesPoints.length - 1; i >= 0; i -= 1) {
const currentSeries = series.filter((s => s.name === seriesPoints[i].name))[0];
const {
points: points
} = seriesPoints[i];
const pointSize = points.length ? points[0].size : 0;
const pointsArea = pointSize * pointSize * points.length;
if (currentSeries.autoHidePointMarkersEnabled() && pointsArea >= area / seriesPoints.length) {
const {
index: index
} = seriesPoints[i];
currentSeries.autoHidePointMarkers = true;
seriesPoints.splice(i, 1);
series.splice(series.indexOf(currentSeries), 1);
markersInfo.overloadedSeries[index] = null
}
}
}
function updateMarkersInfo(points, overloadedSeries) {
let isContinuousSeries = false;
for (let i = 0; i < points.length - 1; i += 1) {
const curPoint = points[i];
const {
size: size
} = curPoint;
if ((0, _type.isDefined)(curPoint.x) && (0, _type.isDefined)(curPoint.y)) {
for (let j = i + 1; j < points.length; j += 1) {
const nextPoint = points[j];
const nextX = null === nextPoint || void 0 === nextPoint ? void 0 : nextPoint.x;
const nextY = null === nextPoint || void 0 === nextPoint ? void 0 : nextPoint.y;
if (!(0, _type.isDefined)(nextX) || Math.abs(curPoint.x - nextX) >= size) {
isContinuousSeries = isContinuousSeries && j !== i + 1;
break
} else {
const distance = (0, _type.isDefined)(nextX) && (0, _type.isDefined)(nextY) && Math.sqrt((curPoint.x - nextX) ** 2 + (curPoint.y - nextY) ** 2);
if (distance && distance < size) {
overloadedSeries[curPoint.seriesIndex][nextPoint.seriesIndex] += 1;
overloadedSeries[curPoint.seriesIndex].total += 1;
if (!isContinuousSeries) {
overloadedSeries[curPoint.seriesIndex].continuousSeries += 1;
isContinuousSeries = true
}
}
}
}
}
}
}
const dxChart = _m_advanced_chart.AdvancedChart.inherit({
_themeSection: "chart",
_fontFields: ["crosshair.label.font"],
_initCore() {
this.paneAxis = {};
this.callBase()
},
_init() {
this._containerInitialHeight = (0, _window.hasWindow)() ? (0, _size.getHeight)(this._$element) : 0;
this.callBase()
},
_correctAxes() {
this._correctValueAxes(true)
},
_setDeprecatedOptions() {
this.callBase();
(0, _extend2.extend)(this._deprecatedOptions, {
"argumentAxis.aggregateByCategory": {
since: "23.1",
message: "Use the aggregation.enabled property"
}
})
},
_getExtraOptions: _common.noop,
_createPanes() {
let panes = this.option("panes");
let panesNameCounter = 0;
let defaultPane;
if (!panes || isArray(panes) && !panes.length) {
panes = DEFAULT_PANES
}
this.callBase();
defaultPane = this.option("defaultPane");
panes = (0, _extend2.extend)(true, [], isArray(panes) ? panes : [panes]);
(0, _iterator.each)(panes, ((_, pane) => {
pane.name = !(0, _type.isDefined)(pane.name) ? "default" + panesNameCounter++ : pane.name
}));
if ((0, _type.isDefined)(defaultPane)) {
if (!doesPaneExist(panes, defaultPane)) {
this._incidentOccurred("W2101", [defaultPane]);
defaultPane = panes[panes.length - 1].name
}
} else {
defaultPane = panes[panes.length - 1].name
}
this.defaultPane = defaultPane;
panes = this._isRotated() ? panes.reverse() : panes;
return panes
},
_getAxisRenderingOptions: () => ({
axisType: "xyAxes",
drawingType: "linear"
}),
_prepareAxisOptions(typeSelector, userOptions, rotated) {
return {
isHorizontal: "argumentAxis" === typeSelector !== rotated,
containerColor: this._themeManager.getOptions("containerBackgroundColor")
}
},
_checkPaneName(seriesTheme) {
const paneList = (0, _utils.map)(this.panes, (pane => pane.name));
seriesTheme.pane = seriesTheme.pane || this.defaultPane;
return paneList.includes(seriesTheme.pane)
},
_initCustomPositioningAxes() {
const argumentAxis = this.getArgumentAxis();
const valueAxisName = argumentAxis.getOptions().customPositionAxis;
const valueAxis = this._valueAxes.find((v => v.pane === argumentAxis.pane && (!valueAxisName || valueAxisName === v.name)));
this._valueAxes.forEach((v => {
if (argumentAxis !== v.getOrthogonalAxis()) {
v.getOrthogonalAxis = () => argumentAxis;
v.customPositionIsBoundaryOrthogonalAxis = () => argumentAxis.customPositionIsBoundary()
}
}));
if ((0, _type.isDefined)(valueAxis) && valueAxis !== argumentAxis.getOrthogonalAxis()) {
argumentAxis.getOrthogonalAxis = () => valueAxis;
argumentAxis.customPositionIsBoundaryOrthogonalAxis = () => this._valueAxes.some((v => v.customPositionIsBoundary()))
} else if ((0, _type.isDefined)(argumentAxis.getOrthogonalAxis()) && !(0, _type.isDefined)(valueAxis)) {
argumentAxis.getOrthogonalAxis = _common.noop
}
},
_getAllAxes() {
return this._argumentAxes.concat(this._valueAxes)
},
_resetAxesAnimation(isFirstDrawing, isHorizontal) {
let axes;
if ((0, _type.isDefined)(isHorizontal)) {
axes = isHorizontal ^ this._isRotated() ? this._argumentAxes : this._valueAxes
} else {
axes = this._getAllAxes()
}
axes.forEach((a => {
a.resetApplyingAnimation(isFirstDrawing)
}))
},
_axesBoundaryPositioning() {
const allAxes = this._getAllAxes();
let boundaryStateChanged = false;
allAxes.forEach((a => {
if (!a.customPositionIsAvailable()) {
return
}
const prevBoundaryState = a.customPositionIsBoundary();
a._customBoundaryPosition = a.getCustomBoundaryPosition();
boundaryStateChanged = boundaryStateChanged || prevBoundaryState !== a.customPositionIsBoundary()
}));
return boundaryStateChanged
},
_getCrosshairMargins() {
const crosshairOptions = this._getCrosshairOptions() || {};
const crosshairEnabled = crosshairOptions.enabled;
const margins = (0, _crosshair.getMargins)();
const horizontalLabel = (0, _extend2.extend)(true, {}, crosshairOptions.label, crosshairOptions.horizontalLine.label);
const verticalLabel = (0, _extend2.extend)(true, {}, crosshairOptions.label, crosshairOptions.verticalLine.label);
return {
x: crosshairEnabled && crosshairOptions.horizontalLine.visible && horizontalLabel.visible ? margins.x : 0,
y: crosshairEnabled && crosshairOptions.verticalLine.visible && verticalLabel.visible ? margins.y : 0
}
},
_getValueAxis(paneName, axisName) {
const valueAxes = this._valueAxes;
const valueAxisOptions = this.option("valueAxis") || {};
const valueAxesOptions = isArray(valueAxisOptions) ? valueAxisOptions : [valueAxisOptions];
const rotated = this._isRotated();
const crosshairMargins = this._getCrosshairMargins();
let axisOptions;
let axis;
axisName = axisName || getFirstAxisNameForPane(valueAxes, paneName, this.defaultPane);
axis = findAxis(paneName, axisName, valueAxes);
if (!axis) {
axisOptions = findAxisOptions(valueAxes, valueAxesOptions, axisName);
if (!axisOptions) {
this._incidentOccurred("W2102", [axisName]);
axisOptions = {
name: axisName,
priority: valueAxes.length
}
}
axis = this._createAxis(false, this._populateAxesOptions("valueAxis", axisOptions, {
pane: paneName,
name: axisName,
optionPath: isArray(valueAxisOptions) ? `valueAxis[${axisOptions.priority}]` : "valueAxis",
crosshairMargin: rotated ? crosshairMargins.y : crosshairMargins.x
}, rotated));
axis.applyVisualRangeSetter(this._getVisualRangeSetter());
valueAxes.push(axis)
}
axis.setPane(paneName);
return axis
},
_correctValueAxes(needHideGrids) {
const synchronizeMultiAxes = this._themeManager.getOptions("synchronizeMultiAxes");
const valueAxes = this._valueAxes;
const paneWithAxis = {};
this.series.forEach((series => {
const axis = series.getValueAxis();
paneWithAxis[axis.pane] = true
}));
this.panes.forEach((pane => {
const paneName = pane.name;
if (!paneWithAxis[paneName]) {
this._getValueAxis(paneName)
}
if (needHideGrids && synchronizeMultiAxes) {
hideGridsOnNonFirstValueAxisForPane(valueAxes.filter((axis => axis.pane === paneName)))
}
}));
this._valueAxes = valueAxes.filter((axis => {
if (!axis.pane) {
axis.setPane(this.defaultPane)
}
const paneExists = doesPaneExist(this.panes, axis.pane);
if (!paneExists) {
axis.dispose();
axis = null
}
return paneExists
})).sort(compareAxes);
const defaultAxis = this.getValueAxis();
this._valueAxes.forEach((axis => {
const {
optionPath: optionPath
} = axis.getOptions();
if (optionPath) {
const axesWithSamePath = this._valueAxes.filter((a => a.getOptions().optionPath === optionPath));
if (axesWithSamePath.length > 1) {
if (axesWithSamePath.some((a => a === defaultAxis))) {
axesWithSamePath.forEach((a => {
if (a !== defaultAxis) {
a.getOptions().optionPath = null
}
}))
} else {
axesWithSamePath.forEach(((a, i) => {
if (0 !== i) {
a.getOptions().optionPath = null
}
}))
}
}
}
}))
},
_getSeriesForPane(paneName) {
const paneSeries = [];
(0, _iterator.each)(this.series, ((_, oneSeries) => {
if (oneSeries.pane === paneName) {
paneSeries.push(oneSeries)
}
}));
return paneSeries
},
_createPanesBorderOptions() {
const commonBorderOptions = this._themeManager.getOptions("commonPaneSettings").border;
const panesBorderOptions = {};
this.panes.forEach((pane => {
panesBorderOptions[pane.name] = (0, _extend2.extend)(true, {}, commonBorderOptions, pane.border)
}));
return panesBorderOptions
},
_createScrollBar() {
const scrollBarOptions = this._themeManager.getOptions("scrollBar") || {};
const scrollBarGroup = this._scrollBarGroup;
if (scrollBarOptions.visible) {
scrollBarOptions.rotated = this._isRotated();
this._scrollBar = (this._scrollBar || new _scroll_bar.ScrollBar(this._renderer, scrollBarGroup)).update(scrollBarOptions)
} else {
var _this$_scrollBar;
scrollBarGroup.linkRemove();
null === (_this$_scrollBar = this._scrollBar) || void 0 === _this$_scrollBar || _this$_scrollBar.dispose();
this._scrollBar = null
}
},
_executeAppendAfterSeries(append) {
append()
},
_prepareToRender() {
const panesBorderOptions = this._createPanesBorderOptions();
this._createPanesBackground();
this._appendAxesGroups();
this._adjustViewport();
return panesBorderOptions
},
_adjustViewport() {
const adjustOnZoom = this._themeManager.getOptions("adjustOnZoom");
if (!adjustOnZoom) {
return
}
this._valueAxes.forEach((axis => axis.adjust()))
},
_recreateSizeDependentObjects(isCanvasChanged) {
const series = this._getVisibleSeries();
const useAggregation = series.some((s => s.useAggregation()));
const zoomChanged = this._isZooming();
if (!useAggregation) {
return
}
this._argumentAxes.forEach((axis => {
axis.updateCanvas(this._canvas, true)
}));
series.forEach((series => {
if (series.useAggregation() && (isCanvasChanged || zoomChanged || !series._useAllAggregatedPoints)) {
series.createPoints()
}
}));
this._processSeriesFamilies()
},
_isZooming() {
const argumentAxis = this.getArgumentAxis();
if (!(null !== argumentAxis && void 0 !== argumentAxis && argumentAxis.getTranslator())) {
return false
}
const businessRange = argumentAxis.getTranslator().getBusinessRange();
const zoomRange = argumentAxis.getViewport();
let min = zoomRange ? zoomRange.min : 0;
let max = zoomRange ? zoomRange.max : 0;
if ("logarithmic" === businessRange.axisType) {
min = (0, _utils.getLog)(min, businessRange.base);
max = (0, _utils.getLog)(max, businessRange.base)
}
const viewportDistance = businessRange.axisType === DISCRETE ? (0, _utils.getCategoriesInfo)(businessRange.categories, min, max).categories.length : Math.abs(max - min);
let precision = (0, _math.getPrecision)(viewportDistance);
precision = precision > 1 ? 10 ** (precision - 2) : 1;
const zoomChanged = Math.round((this._zoomLength - viewportDistance) * precision) / precision !== 0;
this._zoomLength = viewportDistance;
return zoomChanged
},
_handleSeriesDataUpdated() {
const viewport = new _range.Range;
this.series.forEach((s => {
viewport.addRange(s.getArgumentRange())
}));
this._argumentAxes.forEach((axis => {
axis.updateCanvas(this._canvas, true);
axis.setBusinessRange(viewport, this._axesReinitialized)
}));
this.callBase()
},
_isLegendInside() {
return this._legend && "inside" === this._legend.getPosition()
},
_isRotated() {
return this._themeManager.getOptions("rotated")
},
_getLayoutTargets() {
return this.panes
},
_applyClipRects(panesBorderOptions) {
this._drawPanesBorders(panesBorderOptions);
this._createClipRectsForPanes();
this._applyClipRectsForAxes();
this._fillPanesBackground()
},
_updateLegendPosition(drawOptions, legendHasInsidePosition) {
if (drawOptions.drawLegend && this._legend && legendHasInsidePosition) {
const {
panes: panes
} = this;
const newCanvas = (0, _extend2.extend)({}, panes[0].canvas);
const layoutManager = new _layout_manager.LayoutManager;
newCanvas.right = panes[panes.length - 1].canvas.right;
newCanvas.bottom = panes[panes.length - 1].canvas.bottom;
layoutManager.layoutInsideLegend(this._legend, newCanvas)
}
},
_allowLegendInsidePosition: () => true,
_applyExtraSettings(series) {
const paneIndex = this._getPaneIndex(series.pane);
const panesClipRects = this._panesClipRects;
const wideClipRect = panesClipRects.wide[paneIndex];
series.setClippingParams(panesClipRects.base[paneIndex].id, null === wideClipRect || void 0 === wideClipRect ? void 0 : wideClipRect.id, this._getPaneBorderVisibility(paneIndex))
},
_updatePanesCanvases(drawOptions) {
if (!drawOptions.recreateCanvas) {
return
}(0, _utils.updatePanesCanvases)(this.panes, this._canvas, this._isRotated())
},
_normalizePanesHeight() {
(0, _utils.normalizePanesHeight)(this.panes)
},
_renderScaleBreaks() {
this._valueAxes.concat(this._argumentAxes).forEach((axis => {
axis.drawScaleBreaks()
}))
},
_getArgFilter() {
return _range_data_calculator.default.getViewPortFilter(this.getArgumentAxis().visualRange() || {})
},
_hidePointsForSingleSeriesIfNeeded(series) {
const seriesPoints = series.getPoints();
let overlappedPointsCount = 0;
for (let i = 0; i < seriesPoints.length; i += 1) {
const currentPoint = seriesPoints[i];
const overlappingPoints = seriesPoints.slice(i + 1);
overlappedPointsCount += Number(isPointOverlapped(currentPoint, overlappingPoints));
if (overlappedPointsCount > seriesPoints.length / 2) {
series.autoHidePointMarkers = true;
break
}
}
},
_applyAutoHidePointMarkers(filteredSeries) {
let overlappingPoints = [];
const overlappedPointsCalculator = (pointsCount, currentPoint) => pointsCount + isPointOverlapped(currentPoint, overlappingPoints, true);
for (let i = filteredSeries.length - 1; i >= 0; i -= 1) {
const currentSeries = filteredSeries[i];
if (!currentSeries.autoHidePointMarkersEnabled()) {
continue
}
currentSeries.autoHidePointMarkers = false;
this._hidePointsForSingleSeriesIfNeeded(currentSeries);
if (!currentSeries.autoHidePointMarkers) {
const seriesPoints = currentSeries.getPoints();
const overlappingPointsCount = seriesPoints.reduce(overlappedPointsCalculator, 0);
if (overlappingPointsCount < seriesPoints.length) {
overlappingPoints = overlappingPoints.concat(seriesPoints)
} else {
currentSeries.autoHidePointMarkers = true
}
}
}
},
_applyPointMarkersAutoHiding() {
const allSeries = this.series;
if (!this._themeManager.getOptions("autoHidePointMarkers")) {
allSeries.forEach((s => {
s.autoHidePointMarkers = false
}));
return
}
this.panes.forEach((_ref => {
let {
borderCoords: borderCoords,
name: name
} = _ref;
const series = allSeries.filter((s => s.pane === name && s.usePointsToDefineAutoHiding()));
series.forEach((singleSeries => {
singleSeries.prepareCoordinatesForPoints()
}));
const argAxis = this.getArgumentAxis();
const markersInfo = collectMarkersInfoBySeries(allSeries, series, argAxis);
fastHidingPointMarkersByArea(borderCoords, markersInfo, series);
if (markersInfo.series.length) {
const argVisualRange = argAxis.visualRange();
const argAxisIsDiscrete = argAxis.getOptions().type === DISCRETE;
const sortingCallback = argAxisIsDiscrete ? (p1, p2) => argVisualRange.categories.indexOf(p1.argument) - argVisualRange.categories.indexOf(p2.argument) : (p1, p2) => p1.argument - p2.argument;
let points = [];
markersInfo.series.forEach((s => {
points = points.concat(s.points)
}));
points.sort(sortingCallback);
updateMarkersInfo(points, markersInfo.overloadedSeries);
this._applyAutoHidePointMarkers(series)
}
}))
},
_renderAxes(drawOptions, panesBorderOptions) {
function calculateTitlesWidth(axes) {
return axes.map((axis => {
if (!axis.getTitle) {
return 0
}
const title = axis.getTitle();
return title ? title.bBox.width : 0
}))
}
const rotated = this._isRotated();
const synchronizeMultiAxes = this._themeManager.getOptions("synchronizeMultiAxes");
const scrollBar = this._scrollBar ? [this._scrollBar] : [];
const extendedArgAxes = this._isArgumentAxisBeforeScrollBar() ? this._argumentAxes.concat(scrollBar) : scrollBar.concat(this._argumentAxes);
const verticalAxes = rotated ? this._argumentAxes : this._valueAxes;
const verticalElements = rotated ? extendedArgAxes : this._valueAxes;
const horizontalAxes = rotated ? this._valueAxes : this._argumentAxes;
const horizontalElements = rotated ? this._valueAxes : extendedArgAxes;
const allAxes = verticalAxes.concat(horizontalAxes);
const allElements = allAxes.concat(scrollBar);
const verticalAxesFirstDrawing = verticalAxes.some((v => v.isFirstDrawing()));
this._normalizePanesHeight();
this._updatePanesCanvases(drawOptions);
let panesCanvases = this.panes.reduce(((canvases, pane) => {
canvases[pane.name] = (0, _extend2.extend)({}, pane.canvas);
return canvases
}), {});
const paneSizes = this.panes.reduce(((sizes, pane) => {
sizes[pane.name] = {
height: pane.height,
unit: pane.unit
};
return sizes
}), {});
const cleanPanesCanvases = (0, _extend2.extend)(true, {}, panesCanvases);
this._initCustomPositioningAxes();
const needCustomAdjustAxes = this._axesBoundaryPositioning();
if (!drawOptions.adjustAxes && !needCustomAdjustAxes) {
drawAxesWithTicks(verticalAxes, !rotated && synchronizeMultiAxes, panesCanvases, panesBorderOptions);
drawAxesWithTicks(horizontalAxes, rotated && synchronizeMultiAxes, panesCanvases, panesBorderOptions);
performActionOnAxes(allAxes, "prepareAnimation");
this._renderScaleBreaks();
horizontalAxes.forEach((a => a.resolveOverlappingForCustomPositioning(verticalAxes)));
verticalAxes.forEach((a => a.resolveOverlappingForCustomPositioning(horizontalAxes)));
return false
}
if (needCustomAdjustAxes) {
allAxes.forEach((a => a.customPositionIsAvailable() && a.shift({
top: 0,
left: 0,
bottom: 0,
right: 0
})))
}
if (this._scrollBar) {
this._scrollBar.setPane(this.panes)
}
let vAxesMargins = {
panes: {},
left: 0,
right: 0
};
let hAxesMargins = getHorizontalAxesMargins(horizontalElements, (axis => axis.estimateMargins(panesCanvases[axis.pane])));
panesCanvases = shrinkCanvases(rotated, panesCanvases, paneSizes, vAxesMargins, hAxesMargins);
const drawAxesAndSetCanvases = isHorizontal => {
const axes = isHorizontal ? horizontalAxes : verticalAxes;
const condition = (isHorizontal ? rotated : !rotated) && synchronizeMultiAxes;
drawAxesWithTicks(axes, condition, panesCanvases, panesBorderOptions);
if (isHorizontal) {
hAxesMargins = getHorizontalAxesMargins(horizontalElements, getAxisMargins)
} else {
vAxesMargins = getVerticalAxesMargins(verticalElements)
}
panesCanvases = shrinkCanvases(rotated, panesCanvases, paneSizes, vAxesMargins, hAxesMargins)
};
drawAxesAndSetCanvases(false);
drawAxesAndSetCanvases(true);
if (!this._changesApplying && this._estimateTickIntervals(verticalAxes, panesCanvases)) {
drawAxesAndSetCanvases(false)
}
let oldTitlesWidth = calculateTitlesWidth(verticalAxes);
const visibleSeries = this._getVisibleSeries();
const pointsToAnimation = this._getPointsToAnimation(visibleSeries);
const axesIsAnimated = axisAnimationEnabled(drawOptions, pointsToAnimation);
performActionOnAxes(allElements, "updateSize", panesCanvases, axesIsAnimated);
horizontalElements.forEach(shiftAxis("top", "bottom"));
verticalElements.forEach(shiftAxis("left", "right"));
this._renderScaleBreaks();
this.panes.forEach((pane => {
(0, _extend2.extend)(pane.canvas, panesCanvases[pane.name])
}));
this._valueAxes.forEach((axis => {
axis.setInitRange()
}));
verticalAxes.forEach(((axis, i) => {
var _axis$hasWrap;
if (null !== (_axis$hasWrap = axis.hasWrap) && void 0 !== _axis$hasWrap && _axis$hasWrap.call(axis)) {
const title = axis.getTitle();
const newTitleWidth = title ? title.bBox.width : 0;
const offset = newTitleWidth - oldTitlesWidth[i];
if ("right" === axis.getOptions().position) {
vAxesMargins.right += offset
} else {
vAxesMargins.left += offset;
this.panes.forEach((_ref2 => {
let {
name: name
} = _ref2;
vAxesMargins.panes[name].left += offset
}))
}
panesCanvases = shrinkCanvases(rotated, panesCanvases, paneSizes, vAxesMargins, hAxesMargins);
performActionOnAxes(allElements, "updateSize", panesCanvases, false, false);
oldTitlesWidth = calculateTitlesWidth(verticalAxes)
}
}));
if (verticalAxes.some((v => v.customPositionIsAvailable() && v.getCustomPosition() !== v._axisPosition))) {
axesIsAnimated && this._resetAxesAnimation(verticalAxesFirstDrawing, false);
performActionOnAxes(verticalAxes, "updateSize", panesCanvases, axesIsAnimated)
}
horizontalAxes.forEach((a => a.resolveOverlappingForCustomPositioning(verticalAxes)));
verticalAxes.forEach((a => a.resolveOverlappingForCustomPositioning(horizontalAxes)));
return cleanPanesCanvases
},
_getExtraTemplatesItems() {
const allAxes = (this._argumentAxes || []).concat(this._valueAxes || []);
const elements = this._collectTemplatesFromItems(allAxes);
return {
items: elements.items,
groups: elements.groups,
launchRequest() {
allAxes.forEach((a => {
a.setRenderedState(true)
}))
},
doneRequest() {
allAxes.forEach((a => {
a.setRenderedState(false)
}))
}
}
},
_estimateTickIntervals: (axes, canvases) => axes.some((axis => axis.estimateTickInterval(canvases[axis.pane]))),
checkForMoreSpaceForPanesCanvas() {
const rotated = this._isRotated();
const panesAreCustomSized = this.panes.filter((p => p.unit)).length === this.panes.length;
let needSpace = false;
if (panesAreCustomSized) {
let needHorizontalSpace = 0;
let needVerticalSpace = 0;
if (rotated) {
const argAxisRightMargin = this.getArgumentAxis().getMargins().right;
const rightPanesIndent = Math.min(...this.panes.map((p => p.canvas.right)));
needHorizontalSpace = this._canvas.right + argAxisRightMargin - rightPanesIndent
} else {
const argAxisBottomMargin = this.getArgumentAxis().getMargins().bottom;
const bottomPanesIndent = Math.min(...this.panes.map((p => p.canvas.bottom)));
needVerticalSpace = this._canvas.bottom + argAxisBottomMargin - bottomPanesIndent
}
needSpace = needHorizontalSpace > 0 || needVerticalSpace > 0 ? {
width: needHorizontalSpace,
height: needVerticalSpace
} : false;
if (0 !== needVerticalSpace) {
const realSize = this.getSize();
const customSize = this.option("size");
const container = this._$element[0];
const containerHasStyledHeight = !!parseInt(container.style.height, 10) || 0 !== this._containerInitialHeight;
if (!rotated && !(null !== customSize && void 0 !== customSize && customSize.height) && !containerHasStyledHeight) {
this._forceResize(realSize.width, realSize.height + needVerticalSpace);
needSpace = false
}
}
} else {
needSpace = this.layoutManager.needMoreSpaceForPanesCanvas(this._getLayoutTargets(), rotated, (pane => ({
width: rotated && !!pane.unit,
height: !rotated && !!pane.unit
})))
}
return needSpace
},
_forceResize(width, height) {
this._renderer.resize(width, height);
this._updateSize(true);
this._setContentSize();
this._preserveOriginalCanvas();
this._updateCanvasClipRect(this._canvas)
},
_shrinkAxes(sizeShortage, panesCanvases) {
if (!sizeShortage || !panesCanvases) {
return
}
this._renderer.stopAllAnimations(true);
const rotated = this._isRotated();
const scrollBar = this._scrollBar ? [this._scrollBar] : [];
const extendedArgAxes = this._isArgumentAxisBeforeScrollBar() ? this._argumentAxes.concat(scrollBar) : scrollBar.concat(this._argumentAxes);
const verticalAxes = rotated ? extendedArgAxes : this._valueAxes;
const horizontalAxes = rotated ? this._valueAxes : extendedArgAxes;
const allAxes = verticalAxes.concat(horizontalAxes);
if (sizeShortage.width || sizeShortage.height) {
checkUsedSpace(sizeShortage, "height", horizontalAxes, getHorizontalAxesMargins);
checkUsedSpace(sizeShortage, "width", verticalAxes, getVerticalAxesMargins);
performActionOnAxes(allAxes, "updateSize", panesCanvases);
const paneSizes = this.panes.reduce(((sizes, pane) => {
sizes[pane.name] = {
height: pane.height,
unit: pane.unit
};
return sizes
}), {});
panesCanvases = shrinkCanvases(rotated, panesCanvases, paneSizes, getVerticalAxesMargins(verticalAxes), getHorizontalAxesMargins(horizontalAxes, getAxisMargins));
performActionOnAxes(allAxes, "updateSize", panesCanvases);
horizontalAxes.forEach(shiftAxis("top", "bottom"));
verticalAxes.forEach(shiftAxis("left", "right"));
this.panes.forEach((pane => (0, _extend2.extend)(pane.canvas, panesCanvases[pane.name])))
}
},
_isArgumentAxisBeforeScrollBar() {
const argumentAxis = this.getArgumentAxis();
if