devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,105 lines (1,088 loc) • 64.4 kB
JavaScript
/**
* DevExtreme (cjs/viz/axes/xy_axes.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";
exports.default = void 0;
var _range = require("../translators/range");
var _format_helper = _interopRequireDefault(require("../../format_helper"));
var _date = _interopRequireDefault(require("../../core/utils/date"));
var _extend = require("../../core/utils/extend");
var _datetime_breaks = require("./datetime_breaks");
var _common = require("../../core/utils/common");
var _utils = require("../core/utils");
var _type = require("../../core/utils/type");
var _axes_constants = _interopRequireDefault(require("./axes_constants"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const getNextDateUnit = _date.default.getNextDateUnit;
const correctDateWithUnitBeginning = _date.default.correctDateWithUnitBeginning;
const _math = Math;
const _max = _math.max;
const TOP = _axes_constants.default.top;
const BOTTOM = _axes_constants.default.bottom;
const LEFT = _axes_constants.default.left;
const RIGHT = _axes_constants.default.right;
const CENTER = _axes_constants.default.center;
const SCALE_BREAK_OFFSET = 3;
const RANGE_RATIO = .3;
const WAVED_LINE_CENTER = 2;
const WAVED_LINE_TOP = 0;
const WAVED_LINE_BOTTOM = 4;
const WAVED_LINE_LENGTH = 24;
const TICKS_CORRECTIONS = {
left: -1,
top: -1,
right: 0,
bottom: 0,
center: -.5
};
function prepareDatesDifferences(datesDifferences, tickInterval) {
let dateUnitInterval;
let i;
if ("week" === tickInterval) {
tickInterval = "day"
}
if ("quarter" === tickInterval) {
tickInterval = "month"
}
if (datesDifferences[tickInterval]) {
for (i = 0; i < _date.default.dateUnitIntervals.length; i++) {
dateUnitInterval = _date.default.dateUnitIntervals[i];
if (datesDifferences[dateUnitInterval]) {
datesDifferences[dateUnitInterval] = false;
datesDifferences.count--
}
if (dateUnitInterval === tickInterval) {
break
}
}
}
}
function sortingBreaks(breaks) {
return breaks.sort((function(a, b) {
return a.from - b.from
}))
}
function getMarkerDates(min, max, markerInterval) {
const origMin = min;
let dates;
min = correctDateWithUnitBeginning(min, markerInterval);
max = correctDateWithUnitBeginning(max, markerInterval);
dates = _date.default.getSequenceByInterval(min, max, markerInterval);
if (dates.length && origMin > dates[0]) {
dates = dates.slice(1)
}
return dates
}
function getStripHorizontalAlignmentPosition(alignment) {
let position = "start";
if ("center" === alignment) {
position = "center"
}
if ("right" === alignment) {
position = "end"
}
return position
}
function getStripVerticalAlignmentPosition(alignment) {
let position = "start";
if ("center" === alignment) {
position = "center"
}
if ("bottom" === alignment) {
position = "end"
}
return position
}
function getMarkerInterval(tickInterval) {
let markerInterval = getNextDateUnit(tickInterval);
if ("quarter" === markerInterval) {
markerInterval = getNextDateUnit(markerInterval)
}
return markerInterval
}
function getMarkerFormat(curDate, prevDate, tickInterval, markerInterval) {
let format = markerInterval;
const datesDifferences = prevDate && _date.default.getDatesDifferences(prevDate, curDate);
if (prevDate && "year" !== tickInterval) {
prepareDatesDifferences(datesDifferences, tickInterval);
format = _format_helper.default.getDateFormatByDifferences(datesDifferences)
}
return format
}
function getMaxSide(act, boxes) {
return boxes.reduce((function(prevValue, box) {
return _max(prevValue, act(box))
}), 0)
}
function getDistanceByAngle(bBox, rotationAngle) {
rotationAngle = _math.abs(rotationAngle);
rotationAngle = rotationAngle % 180 >= 90 ? 90 - rotationAngle % 90 : rotationAngle % 90;
const a = rotationAngle * (_math.PI / 180);
if (a >= _math.atan(bBox.height / bBox.width)) {
return bBox.height / _math.abs(_math.sin(a))
} else {
return bBox.width
}
}
function getMaxConstantLinePadding(constantLines) {
return constantLines.reduce((function(padding, options) {
return _max(padding, options.paddingTopBottom)
}), 0)
}
function getConstantLineLabelMarginForVerticalAlignment(constantLines, alignment, labelHeight) {
return constantLines.some((function(options) {
return options.label.verticalAlignment === alignment
})) && labelHeight || 0
}
function getLeftMargin(bBox) {
return _math.abs(bBox.x) || 0
}
function getRightMargin(bBox) {
return _math.abs(bBox.width - _math.abs(bBox.x)) || 0
}
function generateRangesOnPoints(points, edgePoints, getRange) {
let i;
let length;
let maxRange = null;
const ranges = [];
let curValue;
let prevValue;
let curRange;
for (i = 1, length = points.length; i < length; i++) {
curValue = points[i];
prevValue = points[i - 1];
curRange = getRange(curValue, prevValue);
if (edgePoints.indexOf(curValue) >= 0) {
if (!maxRange || curRange > maxRange.length) {
maxRange = {
start: curValue,
end: prevValue,
length: curRange
}
}
} else {
if (maxRange && curRange < maxRange.length) {
ranges.push(maxRange)
} else {
ranges.push({
start: curValue,
end: prevValue,
length: curRange
})
}
maxRange = null
}
}
if (maxRange) {
ranges.push(maxRange)
}
return ranges
}
function generateAutoBreaks(_ref, series, _ref2) {
let {
logarithmBase: logarithmBase,
type: type,
maxAutoBreakCount: maxAutoBreakCount
} = _ref;
let {
minVisible: minVisible,
maxVisible: maxVisible
} = _ref2;
const breaks = [];
const getRange = "logarithmic" === type ? (min, max) => (0, _utils.getLog)(max / min, logarithmBase) : (min, max) => max - min;
let visibleRange = getRange(minVisible, maxVisible);
const points = series.reduce(((result, s) => {
const points = s.getPointsInViewPort();
result[0] = result[0].concat(points[0]);
result[1] = result[1].concat(points[1]);
return result
}), [
[],
[]
]);
const sortedAllPoints = points[0].concat(points[1]).sort(((a, b) => b - a));
const edgePoints = points[1].filter((p => points[0].indexOf(p) < 0));
let minDiff = .3 * visibleRange;
const ranges = generateRangesOnPoints(sortedAllPoints, edgePoints, getRange).filter((_ref3 => {
let {
length: length
} = _ref3;
return !!length
})).sort(((a, b) => b.length - a.length));
const epsilon = _math.min.apply(null, ranges.map((r => r.length))) / 1e3;
const _maxAutoBreakCount = (0, _type.isDefined)(maxAutoBreakCount) ? _math.min(maxAutoBreakCount, ranges.length) : ranges.length;
for (let i = 0; i < _maxAutoBreakCount; i++) {
if (ranges[i].length >= minDiff) {
if (visibleRange <= ranges[i].length) {
break
}
visibleRange -= ranges[i].length;
if (visibleRange > epsilon || visibleRange < -epsilon) {
breaks.push({
from: ranges[i].start,
to: ranges[i].end
});
minDiff = .3 * visibleRange
}
} else {
break
}
}
sortingBreaks(breaks);
return breaks
}
var _default = exports.default = {
linear: {
_getStep: function(boxes, rotationAngle) {
const spacing = this._options.label.minSpacing;
const func = this._isHorizontal ? function(box) {
return box.width + spacing
} : function(box) {
return box.height
};
let maxLabelLength = getMaxSide(func, boxes);
if (rotationAngle) {
maxLabelLength = getDistanceByAngle({
width: maxLabelLength,
height: this._getMaxLabelHeight(boxes, 0)
}, rotationAngle)
}
return _axes_constants.default.getTicksCountInRange(this._majorTicks, this._isHorizontal ? "x" : "y", maxLabelLength)
},
_getMaxLabelHeight: function(boxes, spacing) {
return getMaxSide((function(box) {
return box.height
}), boxes) + spacing
},
_validateOverlappingMode: function(mode, displayMode) {
if (this._isHorizontal && ("rotate" === displayMode || "stagger" === displayMode) || !this._isHorizontal) {
return _axes_constants.default.validateOverlappingMode(mode)
}
return mode
},
_validateDisplayMode: function(mode) {
return this._isHorizontal ? mode : "standard"
},
getMarkerTrackers: function() {
return this._markerTrackers
},
_getSharpParam: function(opposite) {
return this._isHorizontal ^ opposite ? "h" : "v"
},
_createAxisElement: function() {
return this._renderer.path([], "line")
},
_updateAxisElementPosition: function() {
const axisCoord = this._axisPosition;
const canvas = this._getCanvasStartEnd();
this._axisElement.attr({
points: this._isHorizontal ? [canvas.start, axisCoord, canvas.end, axisCoord] : [axisCoord, canvas.start, axisCoord, canvas.end]
})
},
_getTranslatedCoord: function(value, offset) {
return this._translator.translate(value, offset)
},
_initAxisPositions() {
const that = this;
if (that.customPositionIsAvailable()) {
that._customBoundaryPosition = that.getCustomBoundaryPosition()
}
if (!that.customPositionIsAvailable() || that.customPositionIsBoundary()) {
that._axisPosition = that.getPredefinedPosition(that.getResolvedBoundaryPosition())
} else {
that._axisPosition = that.getCustomPosition()
}
},
_getTickMarkPoints(coords, length, tickOptions) {
const isHorizontal = this._isHorizontal;
const tickOrientation = this._options.tickOrientation;
const labelPosition = this._options.label.position;
let tickStartCoord;
if ((0, _type.isDefined)(tickOrientation)) {
tickStartCoord = TICKS_CORRECTIONS[tickOrientation] * length
} else {
let shift = tickOptions.shift || 0;
if (!isHorizontal && labelPosition === LEFT || isHorizontal && labelPosition !== BOTTOM) {
shift = -shift
}
tickStartCoord = shift + this.getTickStartPositionShift(length)
}
return [coords.x + (isHorizontal ? 0 : tickStartCoord), coords.y + (isHorizontal ? tickStartCoord : 0), coords.x + (isHorizontal ? 0 : tickStartCoord + length), coords.y + (isHorizontal ? tickStartCoord + length : 0)]
},
getTickStartPositionShift(length) {
const width = this._options.width;
const position = this.getResolvedBoundaryPosition();
return length % 2 === 1 ? width % 2 === 0 && (position === LEFT || position === TOP) || width % 2 === 1 && (position === RIGHT || position === BOTTOM) && !this.hasNonBoundaryPosition() ? Math.floor(-length / 2) : -Math.floor(length / 2) : -length / 2 + (width % 2 === 0 ? 0 : position === BOTTOM || position === RIGHT ? -1 : 1)
},
_getTitleCoords: function() {
const horizontal = this._isHorizontal;
let x = this._axisPosition;
let y = this._axisPosition;
const align = this._options.title.alignment;
const canvas = this._getCanvasStartEnd();
const fromStartToEnd = horizontal || this._options.position === LEFT;
const canvasStart = fromStartToEnd ? canvas.start : canvas.end;
const canvasEnd = fromStartToEnd ? canvas.end : canvas.start;
const coord = align === LEFT ? canvasStart : align === RIGHT ? canvasEnd : canvas.start + (canvas.end - canvas.start) / 2;
if (horizontal) {
x = coord
} else {
y = coord
}
return {
x: x,
y: y
}
},
_drawTitleText: function(group, coords) {
const options = this._options;
const titleOptions = options.title;
const attrs = {
opacity: titleOptions.opacity,
align: titleOptions.alignment,
class: titleOptions.cssClass
};
if (!titleOptions.text || !group) {
return
}
coords = coords || this._getTitleCoords();
if (!this._isHorizontal) {
attrs.rotate = options.position === LEFT ? 270 : 90
}
const text = this._renderer.text(titleOptions.text, coords.x, coords.y).css((0, _utils.patchFontOptions)(titleOptions.font)).attr(attrs).append(group);
this._checkTitleOverflow(text);
return text
},
_updateTitleCoords: function() {
this._title && this._title.element.attr(this._getTitleCoords())
},
_drawTitle: function() {
const title = this._drawTitleText(this._axisTitleGroup);
if (title) {
this._title = {
element: title
}
}
},
_measureTitle: function() {
if (this._title) {
if (this._title.bBox && !this._title.originalSize) {
this._title.originalSize = this._title.bBox
}
this._title.bBox = this._title.element.getBBox()
}
},
_drawDateMarker: function(date, options, range) {
const that = this;
const markerOptions = that._options.marker;
const invert = that._translator.getBusinessRange().invert;
const textIndent = markerOptions.width + markerOptions.textLeftIndent;
let pathElement;
if (null === options.x) {
return
}
if (!options.withoutStick) {
pathElement = that._renderer.path([options.x, options.y, options.x, options.y + markerOptions.separatorHeight], "line").attr({
"stroke-width": markerOptions.width,
stroke: markerOptions.color,
"stroke-opacity": markerOptions.opacity,
sharp: "h"
}).append(that._axisElementsGroup)
}
const text = String(that.formatLabel(date, options.labelOptions, range));
return {
date: date,
x: options.x,
y: options.y,
cropped: options.withoutStick,
label: that._renderer.text(text, options.x, options.y).css((0, _utils.patchFontOptions)(markerOptions.label.font)).append(that._axisElementsGroup),
line: pathElement,
getContentContainer() {
return this.label
},
getEnd: function() {
return this.x + (invert ? -1 : 1) * (textIndent + this.labelBBox.width)
},
setTitle: function() {
this.title = text
},
hideLabel: function() {
this.label.dispose();
this.label = null;
this.title = text
},
hide: function() {
if (pathElement) {
pathElement.dispose();
pathElement = null
}
this.label.dispose();
this.label = null;
this.hidden = true
}
}
},
_drawDateMarkers: function() {
const that = this;
const options = that._options;
const translator = that._translator;
const viewport = that._getViewportRange();
const minBound = viewport.minVisible;
let dateMarkers = [];
let dateMarker;
function draw(markerDate, format, withoutStick) {
return that._drawDateMarker(markerDate, {
x: translator.translate(markerDate),
y: markersAreaTop,
labelOptions: that._getLabelFormatOptions(format),
withoutStick: withoutStick
}, viewport)
}
if (viewport.isEmpty() || !options.marker.visible || "datetime" !== options.argumentType || "discrete" === options.type || that._majorTicks.length <= 1) {
return []
}
const markersAreaTop = that._axisPosition + options.marker.topIndent;
const tickInterval = _date.default.getDateUnitInterval(this._tickInterval);
const markerInterval = getMarkerInterval(tickInterval);
const markerDates = getMarkerDates(minBound, viewport.maxVisible, markerInterval);
if (markerDates.length > 1 || 1 === markerDates.length && minBound < markerDates[0]) {
dateMarkers = markerDates.reduce((function(markers, curDate, i, dates) {
const marker = draw(curDate, getMarkerFormat(curDate, dates[i - 1] || minBound < curDate && minBound, tickInterval, markerInterval));
marker && markers.push(marker);
return markers
}), []);
if (minBound < markerDates[0]) {
dateMarker = draw(minBound, getMarkerFormat(minBound, markerDates[0], tickInterval, markerInterval), true);
dateMarker && dateMarkers.unshift(dateMarker)
}
}
return dateMarkers
},
_adjustDateMarkers: function(offset) {
offset = offset || 0;
const that = this;
const markerOptions = this._options.marker;
const textIndent = markerOptions.width + markerOptions.textLeftIndent;
const invert = this._translator.getBusinessRange().invert;
const canvas = that._getCanvasStartEnd();
const dateMarkers = this._dateMarkers;
if (!dateMarkers.length) {
return offset
}
if (dateMarkers[0].cropped) {
if (!this._checkMarkersPosition(invert, dateMarkers[1], dateMarkers[0])) {
dateMarkers[0].hideLabel()
}
}
let prevDateMarker;
dateMarkers.forEach((function(marker, i, markers) {
if (marker.cropped) {
return
}
if (invert ? marker.getEnd() < canvas.end : marker.getEnd() > canvas.end) {
marker.hideLabel()
} else if (that._checkMarkersPosition(invert, marker, prevDateMarker)) {
prevDateMarker = marker
} else {
marker.hide()
}
}));
this._dateMarkers.forEach((function(marker) {
if (marker.label) {
const labelBBox = marker.labelBBox;
const dy = marker.y + markerOptions.textTopIndent - labelBBox.y;
marker.label.attr({
translateX: invert ? marker.x - textIndent - labelBBox.x - labelBBox.width : marker.x + textIndent - labelBBox.x,
translateY: dy + offset
})
}
if (marker.line) {
marker.line.attr({
translateY: offset
})
}
}));
that._initializeMarkersTrackers(offset);
return offset + markerOptions.topIndent + markerOptions.separatorHeight
},
_checkMarkersPosition: function(invert, dateMarker, prevDateMarker) {
if (void 0 === prevDateMarker) {
return true
}
return invert ? dateMarker.x < prevDateMarker.getEnd() : dateMarker.x > prevDateMarker.getEnd()
},
_initializeMarkersTrackers: function(offset) {
const separatorHeight = this._options.marker.separatorHeight;
const renderer = this._renderer;
const businessRange = this._translator.getBusinessRange();
const canvas = this._getCanvasStartEnd();
const group = this._axisElementsGroup;
this._markerTrackers = this._dateMarkers.filter((function(marker) {
return !marker.hidden
})).map((function(marker, i, markers) {
const nextMarker = markers[i + 1] || {
x: canvas.end,
date: businessRange.max
};
const x = marker.x;
const y = marker.y + offset;
const markerTracker = renderer.path([x, y, x, y + separatorHeight, nextMarker.x, y + separatorHeight, nextMarker.x, y, x, y], "area").attr({
"stroke-width": 1,
stroke: "grey",
fill: "grey",
opacity: 1e-4
}).append(group);
markerTracker.data("range", {
startValue: marker.date,
endValue: nextMarker.date
});
if (marker.title) {
markerTracker.setTitle(marker.title)
}
return markerTracker
}))
},
_getLabelFormatOptions: function(formatString) {
const that = this;
let markerLabelOptions = that._markerLabelOptions;
if (!markerLabelOptions) {
that._markerLabelOptions = markerLabelOptions = (0, _extend.extend)(true, {}, that._options.marker.label)
}
if (!(0, _type.isDefined)(that._options.marker.label.format)) {
markerLabelOptions.format = formatString
}
return markerLabelOptions
},
_adjustConstantLineLabels: function(constantLines) {
const that = this;
const axisPosition = that._options.position;
const canvas = that.getCanvas();
const canvasLeft = canvas.left;
const canvasRight = canvas.width - canvas.right;
const canvasTop = canvas.top;
const canvasBottom = canvas.height - canvas.bottom;
const verticalCenter = canvasTop + (canvasBottom - canvasTop) / 2;
const horizontalCenter = canvasLeft + (canvasRight - canvasLeft) / 2;
let maxLabel = 0;
constantLines.forEach((function(item) {
const isHorizontal = that._isHorizontal;
const linesOptions = item.options;
const paddingTopBottom = linesOptions.paddingTopBottom;
const paddingLeftRight = linesOptions.paddingLeftRight;
const labelOptions = linesOptions.label;
const labelVerticalAlignment = labelOptions.verticalAlignment;
const labelHorizontalAlignment = labelOptions.horizontalAlignment;
const labelIsInside = "inside" === labelOptions.position;
const label = item.label;
const box = item.labelBBox;
let translateX;
let translateY;
if (null === label || box.isEmpty) {
return
}
if (isHorizontal) {
if (labelIsInside) {
if (labelHorizontalAlignment === LEFT) {
translateX = item.coord - paddingLeftRight - box.x - box.width
} else {
translateX = item.coord + paddingLeftRight - box.x
}
switch (labelVerticalAlignment) {
case CENTER:
translateY = verticalCenter - box.y - box.height / 2;
break;
case BOTTOM:
translateY = canvasBottom - paddingTopBottom - box.y - box.height;
break;
default:
translateY = canvasTop + paddingTopBottom - box.y
}
} else {
if (axisPosition === labelVerticalAlignment) {
maxLabel = _max(maxLabel, box.height + paddingTopBottom)
}
translateX = item.coord - box.x - box.width / 2;
if (labelVerticalAlignment === BOTTOM) {
translateY = canvasBottom + paddingTopBottom - box.y
} else {
translateY = canvasTop - paddingTopBottom - box.y - box.height
}
}
} else if (labelIsInside) {
if (labelVerticalAlignment === BOTTOM) {
translateY = item.coord + paddingTopBottom - box.y
} else {
translateY = item.coord - paddingTopBottom - box.y - box.height
}
switch (labelHorizontalAlignment) {
case CENTER:
translateX = horizontalCenter - box.x - box.width / 2;
break;
case RIGHT:
translateX = canvasRight - paddingLeftRight - box.x - box.width;
break;
default:
translateX = canvasLeft + paddingLeftRight - box.x
}
} else {
if (axisPosition === labelHorizontalAlignment) {
maxLabel = _max(maxLabel, box.width + paddingLeftRight)
}
translateY = item.coord - box.y - box.height / 2;
if (labelHorizontalAlignment === RIGHT) {
translateX = canvasRight + paddingLeftRight - box.x
} else {
translateX = canvasLeft - paddingLeftRight - box.x - box.width
}
}
label.attr({
translateX: translateX,
translateY: translateY
})
}));
return maxLabel
},
_drawConstantLinesForEstimating: function(constantLines) {
const that = this;
const renderer = this._renderer;
const group = renderer.g();
constantLines.forEach((function(options) {
that._drawConstantLineLabelText(options.label.text, 0, 0, options.label, group).attr({
align: "center"
})
}));
return group.append(renderer.root)
},
_estimateLabelHeight: function(bBox, labelOptions) {
let height = bBox.height;
const drawingType = labelOptions.drawingType;
if ("stagger" === this._validateDisplayMode(drawingType) || "stagger" === this._validateOverlappingMode(labelOptions.overlappingBehavior, drawingType)) {
height = 2 * height + labelOptions.staggeringSpacing
}
if ("rotate" === this._validateDisplayMode(drawingType) || "rotate" === this._validateOverlappingMode(labelOptions.overlappingBehavior, drawingType)) {
const sinCos = (0, _utils.getCosAndSin)(labelOptions.rotationAngle);
height = height * sinCos.cos + bBox.width * sinCos.sin
}
return height && (height + labelOptions.indentFromAxis || 0) || 0
},
estimateMargins: function(canvas) {
this.updateCanvas(canvas);
const {
position: position,
placeholderSize: placeholderSize
} = this._options;
const range = this._getViewportRange();
const ticksData = this._createTicksAndLabelFormat(range);
const ticks = ticksData.ticks;
const tickInterval = ticksData.tickInterval;
const options = this._options;
const constantLineOptions = this._outsideConstantLines.filter((l => l.labelOptions.visible)).map((l => l.options));
const rootElement = this._renderer.root;
const labelIsVisible = options.label.visible && !range.isEmpty() && ticks.length;
const labelValue = labelIsVisible && this.formatLabel(ticks[ticks.length - 1], options.label, void 0, void 0, tickInterval, ticks);
const labelElement = labelIsVisible && this._renderer.text(labelValue, 0, 0).css(this._textFontStyles).attr(this._textOptions).append(rootElement);
const titleElement = this._drawTitleText(rootElement, {
x: 0,
y: 0
});
const constantLinesLabelsElement = this._drawConstantLinesForEstimating(constantLineOptions);
const labelBox = !options.label.template && labelElement && labelElement.getBBox() || {
x: 0,
y: 0,
width: 0,
height: 0
};
const titleBox = titleElement && titleElement.getBBox() || {
x: 0,
y: 0,
width: 0,
height: 0
};
const constantLinesBox = constantLinesLabelsElement.getBBox();
const titleHeight = titleBox.height ? titleBox.height + options.title.margin : 0;
const labelHeight = this._estimateLabelHeight(labelBox, options.label);
const constantLinesHeight = constantLinesBox.height ? constantLinesBox.height + getMaxConstantLinePadding(constantLineOptions) : 0;
const height = labelHeight + titleHeight;
const margins = {
left: _max(getLeftMargin(labelBox), getLeftMargin(constantLinesBox)),
right: _max(getRightMargin(labelBox), getRightMargin(constantLinesBox)),
top: ("top" === options.position ? height : 0) + getConstantLineLabelMarginForVerticalAlignment(constantLineOptions, "top", constantLinesHeight),
bottom: ("top" !== options.position ? height : 0) + getConstantLineLabelMarginForVerticalAlignment(constantLineOptions, "bottom", constantLinesHeight)
};
if (placeholderSize) {
margins[position] = placeholderSize
}
labelElement && labelElement.remove();
titleElement && titleElement.remove();
constantLinesLabelsElement && constantLinesLabelsElement.remove();
return margins
},
_checkAlignmentConstantLineLabels: function(labelOptions) {
const position = labelOptions.position;
let verticalAlignment = (labelOptions.verticalAlignment || "").toLowerCase();
let horizontalAlignment = (labelOptions.horizontalAlignment || "").toLowerCase();
if (this._isHorizontal) {
if ("outside" === position) {
verticalAlignment = verticalAlignment === BOTTOM ? BOTTOM : TOP;
horizontalAlignment = CENTER
} else {
verticalAlignment = verticalAlignment === CENTER ? CENTER : verticalAlignment === BOTTOM ? BOTTOM : TOP;
horizontalAlignment = horizontalAlignment === LEFT ? LEFT : RIGHT
}
} else if ("outside" === position) {
verticalAlignment = CENTER;
horizontalAlignment = horizontalAlignment === LEFT ? LEFT : RIGHT
} else {
verticalAlignment = verticalAlignment === BOTTOM ? BOTTOM : TOP;
horizontalAlignment = horizontalAlignment === RIGHT ? RIGHT : horizontalAlignment === CENTER ? CENTER : LEFT
}
labelOptions.verticalAlignment = verticalAlignment;
labelOptions.horizontalAlignment = horizontalAlignment
},
_getConstantLineLabelsCoords: function(value, lineLabelOptions) {
const that = this;
let x = value;
let y = value;
if (that._isHorizontal) {
y = that._orthogonalPositions["top" === lineLabelOptions.verticalAlignment ? "start" : "end"]
} else {
x = that._orthogonalPositions["right" === lineLabelOptions.horizontalAlignment ? "end" : "start"]
}
return {
x: x,
y: y
}
},
_getAdjustedStripLabelCoords: function(strip) {
const stripOptions = strip.options;
const paddingTopBottom = stripOptions.paddingTopBottom;
const paddingLeftRight = stripOptions.paddingLeftRight;
const horizontalAlignment = stripOptions.label.horizontalAlignment;
const verticalAlignment = stripOptions.label.verticalAlignment;
const box = strip.labelBBox;
const labelHeight = box.height;
const labelWidth = box.width;
const labelCoords = strip.labelCoords;
let y = labelCoords.y - box.y;
let x = labelCoords.x - box.x;
if (verticalAlignment === TOP) {
y += paddingTopBottom
} else if (verticalAlignment === CENTER) {
y -= labelHeight / 2
} else if (verticalAlignment === BOTTOM) {
y -= paddingTopBottom + labelHeight
}
if (horizontalAlignment === LEFT) {
x += paddingLeftRight
} else if (horizontalAlignment === CENTER) {
x -= labelWidth / 2
} else if (horizontalAlignment === RIGHT) {
x -= paddingLeftRight + labelWidth
}
return {
translateX: x,
translateY: y
}
},
_adjustTitle: function(offset) {
offset = offset || 0;
if (!this._title) {
return
}
const options = this._options;
const position = options.position;
const margin = options.title.margin;
const title = this._title;
const boxTitle = title.bBox;
const x = boxTitle.x;
const y = boxTitle.y;
const width = boxTitle.width;
const height = boxTitle.height;
const axisPosition = this._axisPosition;
const loCoord = axisPosition - margin - offset;
const hiCoord = axisPosition + margin + offset;
const params = {};
if (this._isHorizontal) {
if (position === TOP) {
params.translateY = loCoord - (y + height)
} else {
params.translateY = hiCoord - y
}
} else if (position === LEFT) {
params.translateX = loCoord - (x + width)
} else {
params.translateX = hiCoord - x
}
title.element.attr(params)
},
_checkTitleOverflow: function(titleElement) {
if (!this._title && !titleElement) {
return
}
const canvasLength = this._getScreenDelta();
const title = titleElement ? {
bBox: titleElement.getBBox(),
element: titleElement
} : this._title;
const titleOptions = this._options.title;
const boxTitle = title.bBox;
if ((this._isHorizontal ? boxTitle.width : boxTitle.height) > canvasLength) {
title.element.setMaxSize(canvasLength, void 0, {
wordWrap: titleOptions.wordWrap || "none",
textOverflow: titleOptions.textOverflow || "ellipsis"
});
this._wrapped = titleOptions.wordWrap && "none" !== titleOptions.wordWrap
} else {
const moreThanOriginalSize = title.originalSize && canvasLength > (this._isHorizontal ? title.originalSize.width : title.originalSize.height);
!this._wrapped && moreThanOriginalSize && title.element.restoreText()
}
},
coordsIn: function(x, y) {
const canvas = this.getCanvas();
const isHorizontal = this._options.isHorizontal;
const position = this._options.position;
const coord = isHorizontal ? y : x;
if (isHorizontal && (x < canvas.left || x > canvas.width - canvas.right) || !isHorizontal && (y < canvas.top || y > canvas.height - canvas.bottom)) {
return false
}
if (isHorizontal && position === _axes_constants.default.top || !isHorizontal && position === _axes_constants.default.left) {
return coord < canvas[position]
}
return coord > canvas[isHorizontal ? "height" : "width"] - canvas[position]
},
_boundaryTicksVisibility: {
min: true,
max: true
},
adjust() {
const seriesData = this._seriesData;
const viewport = this._series.filter((s => s.isVisible())).reduce(((range, s) => {
const seriesRange = s.getViewport();
range.min = (0, _type.isDefined)(seriesRange.min) ? range.min < seriesRange.min ? range.min : seriesRange.min : range.min;
range.max = (0, _type.isDefined)(seriesRange.max) ? range.max > seriesRange.max ? range.max : seriesRange.max : range.max;
if (s.showZero) {
range = new _range.Range(range);
range.correctValueZeroLevel()
}
return range
}), {});
if ((0, _type.isDefined)(viewport.min) && (0, _type.isDefined)(viewport.max)) {
seriesData.minVisible = viewport.min;
seriesData.maxVisible = viewport.max
}
seriesData.userBreaks = this._getScaleBreaks(this._options, {
minVisible: seriesData.minVisible,
maxVisible: seriesData.maxVisible
}, this._series, this.isArgumentAxis);
this._translator.updateBusinessRange(this._getViewportRange())
},
hasWrap() {
return this._wrapped
},
getAxisPosition() {
return this._axisPosition
},
_getStick: function() {
return !this._options.valueMarginsEnabled
},
_getStripLabelCoords: function(from, to, stripLabelOptions) {
const orthogonalPositions = this._orthogonalPositions;
const isHorizontal = this._isHorizontal;
const horizontalAlignment = stripLabelOptions.horizontalAlignment;
const verticalAlignment = stripLabelOptions.verticalAlignment;
let x;
let y;
if (isHorizontal) {
if (horizontalAlignment === CENTER) {
x = from + (to - from) / 2
} else if (horizontalAlignment === LEFT) {
x = from
} else if (horizontalAlignment === RIGHT) {
x = to
}
y = orthogonalPositions[getStripVerticalAlignmentPosition(verticalAlignment)]
} else {
x = orthogonalPositions[getStripHorizontalAlignmentPosition(horizontalAlignment)];
if (verticalAlignment === TOP) {
y = from
} else if (verticalAlignment === CENTER) {
y = to + (from - to) / 2
} else if (verticalAlignment === BOTTOM) {
y = to
}
}
return {
x: x,
y: y
}
},
_getTranslatedValue: function(value, offset) {
let interval;
if ("semidiscrete" === this._options.type) {
interval = this._options.tickInterval
}
const pos1 = this._translator.translate(value, offset, false, interval);
const pos2 = this._axisPosition;
const isHorizontal = this._isHorizontal;
return {
x: isHorizontal ? pos1 : pos2,
y: isHorizontal ? pos2 : pos1
}
},
areCoordsOutsideAxis: function(coords) {
const coord = this._isHorizontal ? coords.x : coords.y;
const visibleArea = this.getVisibleArea();
if (coord < visibleArea[0] || coord > visibleArea[1]) {
return true
}
return false
},
_getSkippedCategory: function(ticks) {
let skippedCategory;
if (this._options.type === _axes_constants.default.discrete && this._tickOffset && 0 !== ticks.length) {
skippedCategory = ticks[ticks.length - 1]
}
return skippedCategory
},
_filterBreaks: function(breaks, viewport, breakStyle) {
const minVisible = viewport.minVisible;
const maxVisible = viewport.maxVisible;
const breakSize = breakStyle ? breakStyle.width : 0;
return breaks.reduce((function(result, currentBreak) {
let from = currentBreak.from;
let to = currentBreak.to;
const lastResult = result[result.length - 1];
let newBreak;
if (!(0, _type.isDefined)(from) || !(0, _type.isDefined)(to)) {
return result
}
if (from > to) {
to = [from, from = to][0]
}
if (result.length && from < lastResult.to) {
if (to > lastResult.to) {
lastResult.to = to > maxVisible ? maxVisible : to;
if (lastResult.gapSize) {
lastResult.gapSize = void 0;
lastResult.cumulativeWidth += breakSize
}
}
} else if (from >= minVisible && from < maxVisible || to <= maxVisible && to > minVisible) {
from = from >= minVisible ? from : minVisible;
to = to <= maxVisible ? to : maxVisible;
if (to - from < maxVisible - minVisible) {
newBreak = {
from: from,
to: to,
cumulativeWidth: ((null === lastResult || void 0 === lastResult ? void 0 : lastResult.cumulativeWidth) ?? 0) + breakSize
};
if (currentBreak.gapSize) {
newBreak.gapSize = _date.default.convertMillisecondsToDateUnits(to - from);
newBreak.cumulativeWidth = (null === lastResult || void 0 === lastResult ? void 0 : lastResult.cumulativeWidth) ?? 0
}
result.push(newBreak)
}
}
return result
}), [])
},
_getScaleBreaks: function(axisOptions, viewport, series, isArgumentAxis) {
const that = this;
let breaks = (axisOptions.breaks || []).map((function(b) {
return {
from: that.parser(b.startValue),
to: that.parser(b.endValue)
}
}));
if ("discrete" !== axisOptions.type && "datetime" === axisOptions.dataType && axisOptions.workdaysOnly) {
breaks = breaks.concat((0, _datetime_breaks.generateDateBreaks)(viewport.minVisible, viewport.maxVisible, axisOptions.workWeek, axisOptions.singleWorkdays, axisOptions.holidays))
}
if (!isArgumentAxis && "discrete" !== axisOptions.type && "datetime" !== axisOptions.dataType && axisOptions.autoBreaksEnabled && 0 !== axisOptions.maxAutoBreakCount) {
breaks = breaks.concat(generateAutoBreaks(axisOptions, series, viewport))
}
return sortingBreaks(breaks)
},
_drawBreak: function(translatedEnd, positionFrom, positionTo, width, options, group) {
const breakStart = translatedEnd - (!this._translator.isInverted() ? width + 1 : 0);
const attr = {
"stroke-width": 1,
stroke: options.borderColor,
sharp: !options.isWaved ? options.isHorizontal ? "h" : "v" : void 0
};
const spaceAttr = {
stroke: options.color,
"stroke-width": width
};
const getPoints = this._isHorizontal ? rotateLine : function(p) {
return p
};
const drawer = getLineDrawer(this._renderer, group, getPoints, positionFrom, breakStart, positionTo, options.isWaved);
drawer(width / 2, spaceAttr);
drawer(0, attr);
drawer(width, attr)
},
_createBreakClipRect: function(from, to) {
const that = this;
const canvas = that._canvas;
const clipWidth = to - from;
let clipRect;
if (that._isHorizontal) {
clipRect = that._renderer.clipRect(canvas.left, from, canvas.width, clipWidth)
} else {
clipRect = that._renderer.clipRect(from, canvas.top, clipWidth, canvas.height)
}
that._breaksElements = that._breaksElements || [];
that._breaksElements.push(clipRect);
return clipRect.id
},
_createBreaksGroup: function(clipFrom, clipTo) {
const group = this._renderer.g().attr({
class: this._axisCssPrefix + "breaks",
"clip-path": this._createBreakClipRect(clipFrom, clipTo)
}).append(this._scaleBreaksGroup);
this._breaksElements = this._breaksElements || [];
this._breaksElements.push(group);
return group
},
_disposeBreaksGroup: function() {
(this._breaksElements || []).forEach((function(clipRect) {
clipRect.dispose()
}));
this._breaksElements = null
},
drawScaleBreaks: function(customCanvas) {
const that = this;
const options = that._options;
const breakStyle = options.breakStyle;
const position = options.position;
let positionFrom;
let positionTo;
const breaks = that._translator.getBusinessRange().breaks || [];
let additionGroup;
let additionBreakFrom;
let additionBreakTo;
that._disposeBreaksGroup();
if (!(breaks && breaks.length)) {
return
}
const breakOptions = {
color: that._options.containerColor,
borderColor: breakStyle.color,
isHorizontal: that._isHorizontal,
isWaved: "straight" !== breakStyle.line.toLowerCase()
};
if (customCanvas) {
positionFrom = customCanvas.start;
positionTo = customCanvas.end
} else {
positionFrom = that._orthogonalPositions.start - (options.visible && !that._axisShift && (position === LEFT || position === TOP) ? 3 : 0);
positionTo = that._orthogonalPositions.end + (options.visible && (position === RIGHT || position === BOTTOM)