/**
* @license Highcharts Gantt JS v10.2.1 (2022-08-29)
*
* Gantt series
*
* (c) 2016-2021 Lars A. V. Cabrera
*
* License: www.highcharts.com/license
*/
(function (factory) {
if (typeof module === 'object' && module.exports) {
factory['default'] = factory;
module.exports = factory;
} else if (typeof define === 'function' && define.amd) {
define('highcharts/modules/gantt', ['highcharts'], function (Highcharts) {
factory(Highcharts);
factory.Highcharts = Highcharts;
return factory;
});
} else {
factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
}
}(function (Highcharts) {
'use strict';
var _modules = Highcharts ? Highcharts._modules : {};
function _registerModule(obj, path, args, fn) {
if (!obj.hasOwnProperty(path)) {
obj[path] = fn.apply(null, args);
if (typeof CustomEvent === 'function') {
window.dispatchEvent(
new CustomEvent(
'HighchartsModuleLoaded',
{ detail: { path: path, module: obj[path] }
})
);
}
}
}
_registerModule(_modules, 'Series/XRange/XRangeSeriesDefaults.js', [_modules['Core/Utilities.js']], function (U) {
/* *
*
* X-range series module
*
* (c) 2010-2021 Torstein Honsi, Lars A. V. Cabrera
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var correctFloat = U.correctFloat,
isNumber = U.isNumber,
isObject = U.isObject;
/* *
*
* Constants
*
* */
/**
* The X-range series displays ranges on the X axis, typically time
* intervals with a start and end date.
*
* @sample {highcharts} highcharts/demo/x-range/
* X-range
* @sample {highcharts} highcharts/css/x-range/
* Styled mode X-range
* @sample {highcharts} highcharts/chart/inverted-xrange/
* Inverted X-range
*
* @extends plotOptions.column
* @since 6.0.0
* @product highcharts highstock gantt
* @excluding boostThreshold, crisp, cropThreshold, depth, edgeColor,
* edgeWidth, findNearestPointBy, getExtremesFromAll,
* negativeColor, pointInterval, pointIntervalUnit,
* pointPlacement, pointRange, pointStart, softThreshold,
* stacking, threshold, data, dataSorting, boostBlending
* @requires modules/xrange
* @optionparent plotOptions.xrange
*/
var XRangeSeriesDefaults = {
/**
* A partial fill for each point,
typically used to visualize how much
* of a task is performed. The partial fill object can be set either on
* series or point level.
*
* @sample {highcharts} highcharts/demo/x-range
* X-range with partial fill
*
* @product highcharts highstock gantt
* @apioption plotOptions.xrange.partialFill
*/
/**
* The fill color to be used for partial fills. Defaults to a darker
* shade of the point color.
*
* @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
* @product highcharts highstock gantt
* @apioption plotOptions.xrange.partialFill.fill
*/
/**
* A partial fill for each point,
typically used to visualize how much
* of a task is performed. See [completed](series.gantt.data.completed).
*
* @sample gantt/demo/progress-indicator
* Gantt with progress indicator
*
* @product gantt
* @apioption plotOptions.gantt.partialFill
*/
/**
* In an X-range series,
this option makes all points of the same Y-axis
* category the same color.
*/
colorByPoint: true,
dataLabels: {
formatter: function () {
var point = this.point,
amount = point.partialFill;
if (isObject(amount)) {
amount = amount.amount;
}
if (isNumber(amount) && amount > 0) {
return correctFloat(amount * 100) + '%';
}
},
inside: true,
verticalAlign: 'middle'
},
tooltip: {
headerFormat: '{point.x} - {point.x2}
',
pointFormat: '\u25CF {series.name}: {point.yCategory}
'
},
borderRadius: 3,
pointRange: 0
};
/* *
*
* Export Default
*
* */
/* *
*
* API Options
*
* */
/**
* An `xrange` series. If the [type](#series.xrange.type) option is not
* specified, it is inherited from [chart.type](#chart.type).
*
* @extends series,plotOptions.xrange
* @excluding boostThreshold, crisp, cropThreshold, depth, edgeColor, edgeWidth,
* findNearestPointBy, getExtremesFromAll, negativeColor,
* pointInterval, pointIntervalUnit, pointPlacement, pointRange,
* pointStart, softThreshold, stacking, threshold, dataSorting,
* boostBlending
* @product highcharts highstock gantt
* @requires modules/xrange
* @apioption series.xrange
*/
/**
* An array of data points for the series. For the `xrange` series type,
* points can be given in the following ways:
*
* 1. An array of objects with named values. The objects are point configuration
* objects as seen below.
* ```js
* data: [{
* x: Date.UTC(2017, 0, 1),
* x2: Date.UTC(2017, 0, 3),
* name: "Test",
* y: 0,
* color: "#00FF00"
* }, {
* x: Date.UTC(2017, 0, 4),
* x2: Date.UTC(2017, 0, 5),
* name: "Deploy",
* y: 1,
* color: "#FF0000"
* }]
* ```
*
* @sample {highcharts} highcharts/series/data-array-of-objects/
* Config objects
*
* @declare Highcharts.XrangePointOptionsObject
* @type {Array<*>}
* @extends series.line.data
* @product highcharts highstock gantt
* @apioption series.xrange.data
*/
/**
* The starting X value of the range point.
*
* @sample {highcharts} highcharts/demo/x-range
* X-range
*
* @type {number}
* @product highcharts highstock gantt
* @apioption series.xrange.data.x
*/
/**
* The ending X value of the range point.
*
* @sample {highcharts} highcharts/demo/x-range
* X-range
*
* @type {number}
* @product highcharts highstock gantt
* @apioption series.xrange.data.x2
*/
/**
* The Y value of the range point.
*
* @sample {highcharts} highcharts/demo/x-range
* X-range
*
* @type {number}
* @product highcharts highstock gantt
* @apioption series.xrange.data.y
*/
/**
* A partial fill for each point, typically used to visualize how much of
* a task is performed. The partial fill object can be set either on series
* or point level.
*
* @sample {highcharts} highcharts/demo/x-range
* X-range with partial fill
*
* @declare Highcharts.XrangePointPartialFillOptionsObject
* @product highcharts highstock gantt
* @apioption series.xrange.data.partialFill
*/
/**
* The amount of the X-range point to be filled. Values can be 0-1 and are
* converted to percentages in the default data label formatter.
*
* @type {number}
* @product highcharts highstock gantt
* @apioption series.xrange.data.partialFill.amount
*/
/**
* The fill color to be used for partial fills. Defaults to a darker shade
* of the point color.
*
* @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
* @product highcharts highstock gantt
* @apioption series.xrange.data.partialFill.fill
*/
(''); // adds doclets above to transpiled file
return XRangeSeriesDefaults;
});
_registerModule(_modules, 'Series/XRange/XRangePoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
/* *
*
* X-range series module
*
* (c) 2010-2021 Torstein Honsi, Lars A. V. Cabrera
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d,
b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d,
b) { d.__proto__ = b; }) ||
function (d,
b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var pointProto = SeriesRegistry.series.prototype.pointClass.prototype,
ColumnPoint = SeriesRegistry.seriesTypes.column.prototype.pointClass;
var extend = U.extend;
/* *
*
* Class
*
* */
var XRangePoint = /** @class */ (function (_super) {
__extends(XRangePoint, _super);
function XRangePoint() {
/* *
*
* Static Functions
*
* */
var _this = _super !== null && _super.apply(this,
arguments) || this;
/* *
*
* Properties
*
* */
_this.options = void 0;
_this.series = void 0;
return _this;
}
/**
* Return color of a point based on its category.
*
* @private
* @function getColorByCategory
*
* @param {object} series
* The series which the point belongs to.
*
* @param {object} point
* The point to calculate its color for.
*
* @return {object}
* Returns an object containing the properties color and colorIndex.
*/
XRangePoint.getColorByCategory = function (series, point) {
var colors = series.options.colors || series.chart.options.colors,
colorCount = colors ?
colors.length :
series.chart.options.chart.colorCount,
colorIndex = point.y % colorCount,
color = colors && colors[colorIndex];
return {
colorIndex: colorIndex,
color: color
};
};
/* *
*
* Functions
*
* */
/**
* @private
*/
XRangePoint.prototype.resolveColor = function () {
var series = this.series;
if (series.options.colorByPoint && !this.options.color) {
var colorByPoint = XRangePoint.getColorByCategory(series,
this);
if (!series.chart.styledMode) {
this.color = colorByPoint.color;
}
if (!this.options.colorIndex) {
this.colorIndex = colorByPoint.colorIndex;
}
}
else if (!this.color) {
this.color = series.color;
}
};
/**
* Extend init to have y default to 0.
*
* @private
*/
XRangePoint.prototype.init = function () {
pointProto.init.apply(this, arguments);
if (!this.y) {
this.y = 0;
}
return this;
};
/**
* @private
*/
XRangePoint.prototype.setState = function () {
pointProto.setState.apply(this, arguments);
this.series.drawPoint(this, this.series.getAnimationVerb());
};
/**
* Add x2 and yCategory to the available properties for tooltip formats.
*
* @private
*/
XRangePoint.prototype.getLabelConfig = function () {
var cfg = pointProto.getLabelConfig.call(this),
yCats = this.series.yAxis.categories;
cfg.x2 = this.x2;
cfg.yCategory = this.yCategory = yCats && yCats[this.y];
return cfg;
};
/**
* @private
*/
XRangePoint.prototype.isValid = function () {
return typeof this.x === 'number' &&
typeof this.x2 === 'number';
};
return XRangePoint;
}(ColumnPoint));
extend(XRangePoint.prototype, {
ttBelow: false,
tooltipDateKeys: ['x', 'x2']
});
/* *
*
* Default Export
*
* */
/* *
*
* API Declarations
*
* */
/**
* The ending X value of the range point.
* @name Highcharts.Point#x2
* @type {number|undefined}
* @requires modules/xrange
*/
/**
* Extend applyOptions so that `colorByPoint` for x-range means that one
* color is applied per Y axis category.
*
* @private
* @function Highcharts.Point#applyOptions
*
* @return {Highcharts.Series}
*/
/**
* @interface Highcharts.PointOptionsObject in parts/Point.ts
*/ /**
* The ending X value of the range point.
* @name Highcharts.PointOptionsObject#x2
* @type {number|undefined}
* @requires modules/xrange
*/
(''); // keeps doclets above in JS file
return XRangePoint;
});
_registerModule(_modules, 'Series/XRange/XRangeSeries.js', [_modules['Core/Globals.js'], _modules['Core/Color/Color.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js'], _modules['Series/XRange/XRangeSeriesDefaults.js'], _modules['Series/XRange/XRangePoint.js']], function (H, Color, SeriesRegistry, U, XRangeSeriesDefaults, XRangePoint) {
/* *
*
* X-range series module
*
* (c) 2010-2021 Torstein Honsi, Lars A. V. Cabrera
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d,
b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d,
b) { d.__proto__ = b; }) ||
function (d,
b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var noop = H.noop;
var color = Color.parse;
var seriesProto = SeriesRegistry.series.prototype,
ColumnSeries = SeriesRegistry.seriesTypes.column;
var addEvent = U.addEvent,
clamp = U.clamp,
defined = U.defined,
extend = U.extend,
find = U.find,
isNumber = U.isNumber,
isObject = U.isObject,
merge = U.merge,
pick = U.pick;
/* *
*
* Constants
*
* */
var composedClasses = [];
/* *
*
* Functions
*
* */
/**
* Max x2 should be considered in xAxis extremes
* @private
*/
function onAxisAfterGetSeriesExtremes() {
var dataMax,
modMax;
if (this.isXAxis) {
dataMax = pick(this.dataMax, -Number.MAX_VALUE);
for (var _i = 0, _a = this.series; _i < _a.length; _i++) {
var series = _a[_i];
if (series.x2Data) {
for (var _b = 0, _c = series.x2Data; _b < _c.length; _b++) {
var val = _c[_b];
if (val && val > dataMax) {
dataMax = val;
modMax = true;
}
}
}
}
if (modMax) {
this.dataMax = dataMax;
}
}
}
/* *
*
* Class
*
* */
/**
* @private
* @class
* @name Highcharts.seriesTypes.xrange
*
* @augments Highcharts.Series
*/
var XRangeSeries = /** @class */ (function (_super) {
__extends(XRangeSeries, _super);
function XRangeSeries() {
/* *
*
* Static Properties
*
* */
var _this = _super !== null && _super.apply(this,
arguments) || this;
/* *
*
* Properties
*
* */
_this.data = void 0;
_this.options = void 0;
_this.points = void 0;
return _this;
/*
// Override to remove stroke from points. For partial fill.
pointAttribs: function () {
let series = this,
retVal = columnType.prototype.pointAttribs
.apply(series, arguments);
//retVal['stroke-width'] = 0;
return retVal;
}
//*/
/* eslint-enable valid-jsdoc */
}
/* *
*
* Static Functions
*
* */
XRangeSeries.compose = function (AxisClass) {
if (composedClasses.indexOf(AxisClass) === -1) {
composedClasses.push(AxisClass);
addEvent(AxisClass, 'afterGetSeriesExtremes', onAxisAfterGetSeriesExtremes);
}
};
/* *
*
* Functions
*
* */
/**
* @private
*/
XRangeSeries.prototype.init = function () {
_super.prototype.init.apply(this, arguments);
this.options.stacking = void 0; // #13161
};
/**
* Borrow the column series metrics, but with swapped axes. This gives
* free access to features like groupPadding, grouping, pointWidth etc.
* @private
*/
XRangeSeries.prototype.getColumnMetrics = function () {
var _this = this;
var swapAxes = function () {
for (var _i = 0,
_a = _this.chart.series; _i < _a.length; _i++) {
var series = _a[_i];
var xAxis = series.xAxis;
series.xAxis = series.yAxis;
series.yAxis = xAxis;
}
};
swapAxes();
var metrics = _super.prototype.getColumnMetrics.call(this);
swapAxes();
return metrics;
};
/**
* Override cropData to show a point where x or x2 is outside visible range,
* but one of them is inside.
* @private
*/
XRangeSeries.prototype.cropData = function (xData, yData, min, max) {
// Replace xData with x2Data to find the appropriate cropStart
var crop = seriesProto.cropData.call(this,
this.x2Data,
yData,
min,
max);
// Re-insert the cropped xData
crop.xData = xData.slice(crop.start, crop.end);
return crop;
};
/**
* Finds the index of an existing point that matches the given point
* options.
*
* @private
*
* @param {Highcharts.XRangePointOptions} options
* The options of the point.
*
* @return {number|undefined}
* Returns index of a matching point, or undefined if no match is
* found.
*/
XRangeSeries.prototype.findPointIndex = function (options) {
var _a = this,
cropStart = _a.cropStart,
points = _a.points;
var id = options.id;
var pointIndex;
if (id) {
var point = find(points,
function (point) { return point.id === id; });
pointIndex = point ? point.index : void 0;
}
if (typeof pointIndex === 'undefined') {
var point = find(points,
function (point) { return (point.x === options.x &&
point.x2 === options.x2 &&
!point.touched); });
pointIndex = point ? point.index : void 0;
}
// Reduce pointIndex if data is cropped
if (this.cropped &&
isNumber(pointIndex) &&
isNumber(cropStart) &&
pointIndex >= cropStart) {
pointIndex -= cropStart;
}
return pointIndex;
};
/**
* @private
*/
XRangeSeries.prototype.translatePoint = function (point) {
var xAxis = this.xAxis,
yAxis = this.yAxis,
metrics = this.columnMetrics,
options = this.options,
minPointLength = options.minPointLength || 0,
oldColWidth = (point.shapeArgs && point.shapeArgs.width || 0) / 2,
seriesXOffset = this.pointXOffset = metrics.offset,
posX = pick(point.x2,
point.x + (point.len || 0));
var plotX = point.plotX,
plotX2 = xAxis.translate(posX, 0, 0, 0, 1);
var length = Math.abs(plotX2 - plotX),
inverted = this.chart.inverted,
borderWidth = pick(options.borderWidth, 1),
crisper = borderWidth % 2 / 2;
var widthDifference,
partialFill,
yOffset = metrics.offset,
pointHeight = Math.round(metrics.width),
dlLeft,
dlRight,
dlWidth,
clipRectWidth;
if (minPointLength) {
widthDifference = minPointLength - length;
if (widthDifference < 0) {
widthDifference = 0;
}
plotX -= widthDifference / 2;
plotX2 += widthDifference / 2;
}
plotX = Math.max(plotX, -10);
plotX2 = clamp(plotX2, -10, xAxis.len + 10);
// Handle individual pointWidth
if (defined(point.options.pointWidth)) {
yOffset -= ((Math.ceil(point.options.pointWidth) - pointHeight) / 2);
pointHeight = Math.ceil(point.options.pointWidth);
}
// Apply pointPlacement to the Y axis
if (options.pointPlacement &&
isNumber(point.plotY) &&
yAxis.categories) {
point.plotY = yAxis.translate(point.y, 0, 1, 0, 1, options.pointPlacement);
}
var x = Math.floor(Math.min(plotX,
plotX2)) + crisper;
var x2 = Math.floor(Math.max(plotX,
plotX2)) + crisper;
var shapeArgs = {
x: x,
y: Math.floor(point.plotY + yOffset) + crisper,
width: x2 - x,
height: pointHeight,
r: this.options.borderRadius
};
point.shapeArgs = shapeArgs;
// Move tooltip to default position
if (!inverted) {
point.tooltipPos[0] -= oldColWidth +
seriesXOffset -
shapeArgs.width / 2;
}
else {
point.tooltipPos[1] += seriesXOffset +
oldColWidth;
}
// Align data labels inside the shape and inside the plot area
dlLeft = shapeArgs.x;
dlRight = dlLeft + shapeArgs.width;
if (dlLeft < 0 || dlRight > xAxis.len) {
dlLeft = clamp(dlLeft, 0, xAxis.len);
dlRight = clamp(dlRight, 0, xAxis.len);
dlWidth = dlRight - dlLeft;
point.dlBox = merge(shapeArgs, {
x: dlLeft,
width: dlRight - dlLeft,
centerX: dlWidth ? dlWidth / 2 : null
});
}
else {
point.dlBox = null;
}
// Tooltip position
var tooltipPos = point.tooltipPos;
var xIndex = !inverted ? 0 : 1;
var yIndex = !inverted ? 1 : 0;
var tooltipYOffset = (this.columnMetrics ?
this.columnMetrics.offset :
-metrics.width / 2);
// Centering tooltip position (#14147)
if (!inverted) {
tooltipPos[xIndex] += (xAxis.reversed ? -1 : 0) * shapeArgs.width;
}
else {
tooltipPos[xIndex] += shapeArgs.width / 2;
}
tooltipPos[yIndex] = clamp(tooltipPos[yIndex] + ((inverted ? -1 : 1) * tooltipYOffset), 0, yAxis.len - 1);
// Add a partShapeArgs to the point, based on the shapeArgs property
partialFill = point.partialFill;
if (partialFill) {
// Get the partial fill amount
if (isObject(partialFill)) {
partialFill = partialFill.amount;
}
// If it was not a number, assume 0
if (!isNumber(partialFill)) {
partialFill = 0;
}
point.partShapeArgs = merge(shapeArgs, {
r: this.options.borderRadius
});
clipRectWidth = Math.max(Math.round(length * partialFill + point.plotX -
plotX), 0);
point.clipRectArgs = {
x: xAxis.reversed ? // #10717
shapeArgs.x + length - clipRectWidth :
shapeArgs.x,
y: shapeArgs.y,
width: clipRectWidth,
height: shapeArgs.height
};
}
};
/**
* @private
*/
XRangeSeries.prototype.translate = function () {
_super.prototype.translate.apply(this, arguments);
for (var _i = 0, _a = this.points; _i < _a.length; _i++) {
var point = _a[_i];
this.translatePoint(point);
}
};
/**
* Draws a single point in the series. Needed for partial fill.
*
* This override turns point.graphic into a group containing the
* original graphic and an overlay displaying the partial fill.
*
* @private
*
* @param {Highcharts.Point} point
* An instance of Point in the series.
*
* @param {"animate"|"attr"} verb
* 'animate' (animates changes) or 'attr' (sets options)
*/
XRangeSeries.prototype.drawPoint = function (point, verb) {
var seriesOpts = this.options,
renderer = this.chart.renderer,
type = point.shapeType,
shapeArgs = point.shapeArgs,
partShapeArgs = point.partShapeArgs,
clipRectArgs = point.clipRectArgs,
cutOff = seriesOpts.stacking && !seriesOpts.borderRadius,
pointState = point.state,
stateOpts = (seriesOpts.states[pointState || 'normal'] ||
{}),
pointStateVerb = typeof pointState === 'undefined' ?
'attr' : verb,
pointAttr = this.pointAttribs(point,
pointState),
animation = pick(this.chart.options.chart.animation,
stateOpts.animation);
var graphic = point.graphic,
pfOptions = point.partialFill;
if (!point.isNull && point.visible !== false) {
// Original graphic
if (graphic) { // update
graphic.rect[verb](shapeArgs);
}
else {
point.graphic = graphic = renderer.g('point')
.addClass(point.getClassName())
.add(point.group || this.group);
graphic.rect = renderer[type](merge(shapeArgs))
.addClass(point.getClassName())
.addClass('highcharts-partfill-original')
.add(graphic);
}
// Partial fill graphic
if (partShapeArgs) {
if (graphic.partRect) {
graphic.partRect[verb](merge(partShapeArgs));
graphic.partialClipRect[verb](merge(clipRectArgs));
}
else {
graphic.partialClipRect = renderer.clipRect(clipRectArgs.x, clipRectArgs.y, clipRectArgs.width, clipRectArgs.height);
graphic.partRect =
renderer[type](partShapeArgs)
.addClass('highcharts-partfill-overlay')
.add(graphic)
.clip(graphic.partialClipRect);
}
}
// Presentational
if (!this.chart.styledMode) {
graphic
.rect[verb](pointAttr, animation)
.shadow(seriesOpts.shadow, null, cutOff);
if (partShapeArgs) {
// Ensure pfOptions is an object
if (!isObject(pfOptions)) {
pfOptions = {};
}
if (isObject(seriesOpts.partialFill)) {
pfOptions = merge(seriesOpts.partialFill, pfOptions);
}
var fill = (pfOptions.fill ||
color(pointAttr.fill).brighten(-0.3).get() ||
color(point.color || this.color)
.brighten(-0.3).get());
pointAttr.fill = fill;
graphic
.partRect[pointStateVerb](pointAttr, animation)
.shadow(seriesOpts.shadow, null, cutOff);
}
}
}
else if (graphic) {
point.graphic = graphic.destroy(); // #1269
}
};
/**
* @private
*/
XRangeSeries.prototype.drawPoints = function () {
var verb = this.getAnimationVerb();
// Draw the columns
for (var _i = 0, _a = this.points; _i < _a.length; _i++) {
var point = _a[_i];
this.drawPoint(point, verb);
}
};
/**
* Returns "animate", or "attr" if the number of points is above the
* animation limit.
*
* @private
*/
XRangeSeries.prototype.getAnimationVerb = function () {
return (this.chart.pointCount < (this.options.animationLimit || 250) ?
'animate' :
'attr');
};
/**
* @private
*/
XRangeSeries.prototype.isPointInside = function (point) {
var shapeArgs = point.shapeArgs,
plotX = point.plotX,
plotY = point.plotY;
if (!shapeArgs) {
return _super.prototype.isPointInside.apply(this, arguments);
}
var isInside = typeof plotX !== 'undefined' &&
typeof plotY !== 'undefined' &&
plotY >= 0 &&
plotY <= this.yAxis.len &&
(shapeArgs.x || 0) + (shapeArgs.width || 0) >= 0 &&
plotX <= this.xAxis.len;
return isInside;
};
XRangeSeries.defaultOptions = merge(ColumnSeries.defaultOptions, XRangeSeriesDefaults);
return XRangeSeries;
}(ColumnSeries));
extend(XRangeSeries.prototype, {
pointClass: XRangePoint,
cropShoulder: 1,
getExtremesFromAll: true,
parallelArrays: ['x', 'x2', 'y'],
requireSorting: false,
type: 'xrange',
animate: seriesProto.animate,
autoIncrement: noop,
buildKDTree: noop
});
SeriesRegistry.registerSeriesType('xrange', XRangeSeries);
/* *
*
* Default Export
*
* */
return XRangeSeries;
});
_registerModule(_modules, 'Series/Gantt/GanttPoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
/* *
*
* (c) 2016-2021 Highsoft AS
*
* Author: Lars A. V. Cabrera
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d,
b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d,
b) { d.__proto__ = b; }) ||
function (d,
b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var XRangePoint = SeriesRegistry.seriesTypes.xrange.prototype.pointClass;
var pick = U.pick;
/* *
*
* Class
*
* */
var GanttPoint = /** @class */ (function (_super) {
__extends(GanttPoint, _super);
function GanttPoint() {
/* *
*
* Static Functions
*
* */
var _this = _super !== null && _super.apply(this,
arguments) || this;
_this.options = void 0;
_this.series = void 0;
return _this;
/* eslint-enable valid-jsdoc */
}
/* eslint-disable valid-jsdoc */
/**
* @private
*/
GanttPoint.setGanttPointAliases = function (options) {
/**
* Add a value to options if the value exists.
* @private
*/
function addIfExists(prop, val) {
if (typeof val !== 'undefined') {
options[prop] = val;
}
}
addIfExists('x', pick(options.start, options.x));
addIfExists('x2', pick(options.end, options.x2));
addIfExists('partialFill', pick(options.completed, options.partialFill));
};
/* *
*
* Functions
*
* */
/* eslint-disable valid-jsdoc */
/**
* Applies the options containing the x and y data and possible some
* extra properties. This is called on point init or from point.update.
*
* @private
* @function Highcharts.Point#applyOptions
*
* @param {Object} options
* The point options
*
* @param {number} x
* The x value
*
* @return {Highcharts.Point}
* The Point instance
*/
GanttPoint.prototype.applyOptions = function (options, x) {
var point = this,
ganttPoint;
ganttPoint = _super.prototype.applyOptions.call(point, options, x);
GanttPoint.setGanttPointAliases(ganttPoint);
return ganttPoint;
};
GanttPoint.prototype.isValid = function () {
return ((typeof this.start === 'number' ||
typeof this.x === 'number') &&
(typeof this.end === 'number' ||
typeof this.x2 === 'number' ||
this.milestone));
};
return GanttPoint;
}(XRangePoint));
/* *
*
* Default Export
*
* */
return GanttPoint;
});
_registerModule(_modules, 'Core/Axis/BrokenAxis.js', [_modules['Core/Axis/Stacking/StackItem.js'], _modules['Core/Utilities.js']], function (StackItem, U) {
/* *
*
* (c) 2009-2021 Torstein Honsi
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var addEvent = U.addEvent,
find = U.find,
fireEvent = U.fireEvent,
isArray = U.isArray,
isNumber = U.isNumber,
pick = U.pick;
/* *
*
* Composition
*
* */
/**
* Axis with support of broken data rows.
* @private
*/
var BrokenAxis;
(function (BrokenAxis) {
/* *
*
* Declarations
*
* */
/* *
*
* Constants
*
* */
var composedClasses = [];
/* *
*
* Functions
*
* */
/* eslint-disable valid-jsdoc */
/**
* Adds support for broken axes.
* @private
*/
function compose(AxisClass, SeriesClass) {
if (composedClasses.indexOf(AxisClass) === -1) {
composedClasses.push(AxisClass);
AxisClass.keepProps.push('brokenAxis');
addEvent(AxisClass, 'init', onAxisInit);
addEvent(AxisClass, 'afterInit', onAxisAfterInit);
addEvent(AxisClass, 'afterSetTickPositions', onAxisAfterSetTickPositions);
addEvent(AxisClass, 'afterSetOptions', onAxisAfterSetOptions);
}
if (composedClasses.indexOf(SeriesClass) === -1) {
composedClasses.push(SeriesClass);
var seriesProto = SeriesClass.prototype;
seriesProto.drawBreaks = seriesDrawBreaks;
seriesProto.gappedPath = seriesGappedPath;
addEvent(SeriesClass, 'afterGeneratePoints', onSeriesAfterGeneratePoints);
addEvent(SeriesClass, 'afterRender', onSeriesAfterRender);
}
return AxisClass;
}
BrokenAxis.compose = compose;
/**
* @private
*/
function onAxisAfterInit() {
if (typeof this.brokenAxis !== 'undefined') {
this.brokenAxis.setBreaks(this.options.breaks, false);
}
}
/**
* Force Axis to be not-ordinal when breaks are defined.
* @private
*/
function onAxisAfterSetOptions() {
var axis = this;
if (axis.brokenAxis && axis.brokenAxis.hasBreaks) {
axis.options.ordinal = false;
}
}
/**
* @private
*/
function onAxisAfterSetTickPositions() {
var axis = this,
brokenAxis = axis.brokenAxis;
if (brokenAxis &&
brokenAxis.hasBreaks) {
var tickPositions = axis.tickPositions,
info = axis.tickPositions.info,
newPositions = [];
for (var i = 0; i < tickPositions.length; i++) {
if (!brokenAxis.isInAnyBreak(tickPositions[i])) {
newPositions.push(tickPositions[i]);
}
}
axis.tickPositions = newPositions;
axis.tickPositions.info = info;
}
}
/**
* @private
*/
function onAxisInit() {
var axis = this;
if (!axis.brokenAxis) {
axis.brokenAxis = new Additions(axis);
}
}
/**
* @private
*/
function onSeriesAfterGeneratePoints() {
var _a = this,
isDirty = _a.isDirty,
connectNulls = _a.options.connectNulls,
points = _a.points,
xAxis = _a.xAxis,
yAxis = _a.yAxis;
// Set, or reset visibility of the points. Axis.setBreaks marks
// the series as isDirty
if (isDirty) {
var i = points.length;
while (i--) {
var point = points[i];
// Respect nulls inside the break (#4275)
var nullGap = point.y === null && connectNulls === false;
var isPointInBreak = (!nullGap && ((xAxis &&
xAxis.brokenAxis &&
xAxis.brokenAxis.isInAnyBreak(point.x,
true)) || (yAxis &&
yAxis.brokenAxis &&
yAxis.brokenAxis.isInAnyBreak(point.y,
true))));
// Set point.visible if in any break.
// If not in break, reset visible to original value.
point.visible = isPointInBreak ?
false :
point.options.visible !== false;
}
}
}
/**
* @private
*/
function onSeriesAfterRender() {
this.drawBreaks(this.xAxis, ['x']);
this.drawBreaks(this.yAxis, pick(this.pointArrayMap, ['y']));
}
/**
* @private
*/
function seriesDrawBreaks(axis, keys) {
var series = this,
points = series.points;
var breaks,
threshold,
eventName,
y;
if (axis && // #5950
axis.brokenAxis &&
axis.brokenAxis.hasBreaks) {
var brokenAxis_1 = axis.brokenAxis;
keys.forEach(function (key) {
breaks = brokenAxis_1 && brokenAxis_1.breakArray || [];
threshold = axis.isXAxis ?
axis.min :
pick(series.options.threshold, axis.min);
points.forEach(function (point) {
y = pick(point['stack' + key.toUpperCase()], point[key]);
breaks.forEach(function (brk) {
if (isNumber(threshold) && isNumber(y)) {
eventName = false;
if ((threshold < brk.from && y > brk.to) ||
(threshold > brk.from && y < brk.from)) {
eventName = 'pointBreak';
}
else if ((threshold < brk.from &&
y > brk.from &&
y < brk.to) || (threshold > brk.from &&
y > brk.to &&
y < brk.from)) {
eventName = 'pointInBreak';
}
if (eventName) {
fireEvent(axis, eventName, { point: point, brk: brk });
}
}
});
});
});
}
}
/**
* Extend getGraphPath by identifying gaps in the data so that we
* can draw a gap in the line or area. This was moved from ordinal
* axis module to broken axis module as of #5045.
*
* @private
* @function Highcharts.Series#gappedPath
*
* @return {Highcharts.SVGPathArray}
* Gapped path
*/
function seriesGappedPath() {
var currentDataGrouping = this.currentDataGrouping,
groupingSize = currentDataGrouping && currentDataGrouping.gapSize,
points = this.points.slice(),
yAxis = this.yAxis;
var gapSize = this.options.gapSize,
i = points.length - 1,
stack;
/**
* Defines when to display a gap in the graph, together with the
* [gapUnit](plotOptions.series.gapUnit) option.
*
* In case when `dataGrouping` is enabled, points can be grouped
* into a larger time span. This can make the grouped points to
* have a greater distance than the absolute value of `gapSize`
* property, which will result in disappearing graph completely.
* To prevent this situation the mentioned distance between
* grouped points is used instead of previously defined
* `gapSize`.
*
* In practice, this option is most often used to visualize gaps
* in time series. In a stock chart, intraday data is available
* for daytime hours, while gaps will appear in nights and
* weekends.
*
* @see [gapUnit](plotOptions.series.gapUnit)
* @see [xAxis.breaks](#xAxis.breaks)
*
* @sample {highstock} stock/plotoptions/series-gapsize/
* Setting the gap size to 2 introduces gaps for weekends in
* daily datasets.
*
* @type {number}
* @default 0
* @product highstock
* @requires modules/broken-axis
* @apioption plotOptions.series.gapSize
*/
/**
* Together with [gapSize](plotOptions.series.gapSize), this
* option defines where to draw gaps in the graph.
*
* When the `gapUnit` is `"relative"` (default), a gap size of 5
* means that if the distance between two points is greater than
* 5 times that of the two closest points, the graph will be
* broken.
*
* When the `gapUnit` is `"value"`, the gap is based on absolute
* axis values, which on a datetime axis is milliseconds. This
* also applies to the navigator series that inherits gap
* options from the base series.
*
* @see [gapSize](plotOptions.series.gapSize)
*
* @type {string}
* @default relative
* @since 5.0.13
* @product highstock
* @validvalue ["relative", "value"]
* @requires modules/broken-axis
* @apioption plotOptions.series.gapUnit
*/
if (gapSize && i > 0) { // #5008
// Gap unit is relative
if (this.options.gapUnit !== 'value') {
gapSize *= this.basePointRange;
}
// Setting a new gapSize in case dataGrouping is enabled
// (#7686)
if (groupingSize &&
groupingSize > gapSize &&
// Except when DG is forced (e.g. from other series)
// and has lower granularity than actual points (#11351)
groupingSize >= this.basePointRange) {
gapSize = groupingSize;
}
// extension for ordinal breaks
var current = void 0,
next = void 0;
while (i--) {
// Reassign next if it is not visible
if (!(next && next.visible !== false)) {
next = points[i + 1];
}
current = points[i];
// Skip iteration if one of the points is not visible
if (next.visible === false || current.visible === false) {
continue;
}
if (next.x - current.x > gapSize) {
var xRange = (current.x + next.x) / 2;
points.splice(// insert after this one
i + 1, 0, {
isNull: true,
x: xRange
});
// For stacked chart generate empty stack items, #6546
if (yAxis.stacking && this.options.stacking) {
stack = yAxis.stacking.stacks[this.stackKey][xRange] = new StackItem(yAxis, yAxis.options.stackLabels, false, xRange, this.stack);
stack.total = 0;
}
}
// Assign current to next for the upcoming iteration
next = current;
}
}
// Call base method
return this.getGraphPath(points);
}
/* *
*
* Class
*
* */
/**
* Provides support for broken axes.
* @private
* @class
*/
var Additions = /** @class */ (function () {
/* *
*
* Constructors
*
* */
function Additions(axis) {
this.hasBreaks = false;
this.axis = axis;
}
/* *
*
* Static Functions
*
* */
/**
* @private
*/
Additions.isInBreak = function (brk, val) {
var repeat = brk.repeat || Infinity,
from = brk.from,
length = brk.to - brk.from,
test = (val >= from ?
(val - from) % repeat :
repeat - ((from - val) % repeat));
var ret;
if (!brk.inclusive) {
ret = test < length && test !== 0;
}
else {
ret = test <= length;
}
return ret;
};
/**
* @private
*/
Additions.lin2Val = function (val) {
var axis = this;
var brokenAxis = axis.brokenAxis;
var breakArray = brokenAxis && brokenAxis.breakArray;
if (!breakArray || !isNumber(val)) {
return val;
}
var nval = val,
brk,
i;
for (i = 0; i < breakArray.length; i++) {
brk = breakArray[i];
if (brk.from >= nval) {
break;
}
else if (brk.to < nval) {
nval += brk.len;
}
else if (Additions.isInBreak(brk, nval)) {
nval += brk.len;
}
}
return nval;
};
/**
* @private
*/
Additions.val2Lin = function (val) {
var axis = this;
var brokenAxis = axis.brokenAxis;
var breakArray = brokenAxis && brokenAxis.breakArray;
if (!breakArray || !isNumber(val)) {
return val;
}
var nval = val,
brk,
i;
for (i = 0; i < breakArray.length; i++) {
brk = breakArray[i];
if (brk.to <= val) {
nval -= brk.len;
}
else if (brk.from >= val) {
break;
}
else if (Additions.isInBreak(brk, val)) {
nval -= (val - brk.from);
break;
}
}
return nval;
};
/* *
*
* Functions
*
* */
/**
* Returns the first break found where the x is larger then break.from
* and smaller then break.to.
*
* @param {number} x
* The number which should be within a break.
*
* @param {Array} breaks
* The array of breaks to search within.
*
* @return {Highcharts.XAxisBreaksOptions|undefined}
* Returns the first break found that matches, returns false if no break
* is found.
*/
Additions.prototype.findBreakAt = function (x, breaks) {
return find(breaks, function (b) {
return b.from < x && x < b.to;
});
};
/**
* @private
*/
Additions.prototype.isInAnyBreak = function (val, testKeep) {
var brokenAxis = this,
axis = brokenAxis.axis,
breaks = axis.options.breaks || [];
var i = breaks.length,
inbrk,
keep,
ret;
if (i && isNumber(val)) {
while (i--) {
if (Additions.isInBreak(breaks[i], val)) {
inbrk = true;
if (!keep) {
keep = pick(breaks[i].showPoints, !axis.isXAxis);
}
}
}
if (inbrk && testKeep) {
ret = inbrk && !keep;
}
else {
ret = inbrk;
}
}
return ret;
};
/**
* Dynamically set or unset breaks in an axis. This function in lighter
* than usin Axis.update, and it also preserves animation.
*
* @private
* @function Highcharts.Axis#setBreaks
*
* @param {Array} [breaks]
* The breaks to add. When `undefined` it removes existing breaks.
*
* @param {boolean} [redraw=true]
* Whether to redraw the chart immediately.
*/
Additions.prototype.setBreaks = function (breaks, redraw) {
var brokenAxis = this;
var axis = brokenAxis.axis;
var hasBreaks = (isArray(breaks) && !!breaks.length);
axis.isDirty = brokenAxis.hasBreaks !== hasBreaks;
brokenAxis.hasBreaks = hasBreaks;
axis.options.breaks = axis.userOptions.breaks = breaks;
axis.forceRedraw = true; // Force recalculation in setScale
// Recalculate series related to the axis.
axis.series.forEach(function (series) {
series.isDirty = true;
});
if (!hasBreaks && axis.val2lin === Additions.val2Lin) {
// Revert to prototype functions
delete axis.val2lin;
delete axis.lin2val;
}
if (hasBreaks) {
axis.userOptions.ordinal = false;
axis.lin2val = Additions.lin2Val;
axis.val2lin = Additions.val2Lin;
axis.setExtremes = function (newMin, newMax, redraw, animation, eventArguments) {
// If trying to set extremes inside a break, extend min to
// after, and max to before the break ( #3857 )
if (brokenAxis.hasBreaks) {
var breaks_1 = (this.options.breaks || []);
var axisBreak = void 0;
while ((axisBreak = brokenAxis.findBreakAt(newMin, breaks_1))) {
newMin = axisBreak.to;
}
while ((axisBreak = brokenAxis.findBreakAt(newMax, breaks_1))) {
newMax = axisBreak.from;
}
// If both min and max is within the same break.
if (newMax < newMin) {
newMax = newMin;
}
}
axis.constructor.prototype.setExtremes.call(this, newMin, newMax, redraw, animation, eventArguments);
};
axis.setAxisTranslation = function () {
axis.constructor.prototype.setAxisTranslation.call(this);
brokenAxis.unitLength = void 0;
if (brokenAxis.hasBreaks) {
var breaks_2 = axis.options.breaks || [],
// Temporary one:
breakArrayT_1 = [],
breakArray_1 = [],
pointRangePadding = pick(axis.pointRangePadding, 0);
var length_1 = 0,
inBrk_1,
repeat_1,
min_1 = axis.userMin || axis.min,
max_1 = axis.userMax || axis.max,
start_1,
i_1;
// Min & max check (#4247)
breaks_2.forEach(function (brk) {
repeat_1 = brk.repeat || Infinity;
if (isNumber(min_1) && isNumber(max_1)) {
if (Additions.isInBreak(brk, min_1)) {
min_1 += ((brk.to % repeat_1) -
(min_1 % repeat_1));
}
if (Additions.isInBreak(brk, max_1)) {
max_1 -= ((max_1 % repeat_1) -
(brk.from % repeat_1));
}
}
});
// Construct an array holding all breaks in the axis
breaks_2.forEach(function (brk) {
start_1 = brk.from;
repeat_1 = brk.repeat || Infinity;
if (isNumber(min_1) && isNumber(max_1)) {
while (start_1 - repeat_1 > min_1) {
start_1 -= repeat_1;
}
while (start_1 < min_1) {
start_1 += repeat_1;
}
for (i_1 = start_1; i_1 < max_1; i_1 += repeat_1) {
breakArrayT_1.push({
value: i_1,
move: 'in'
});
breakArrayT_1.push({
value: i_1 + brk.to - brk.from,
move: 'out',
size: brk.breakSize
});
}
}
});
breakArrayT_1.sort(function (a, b) {
return ((a.value === b.value) ?
((a.move === 'in' ? 0 : 1) -
(b.move === 'in' ? 0 : 1)) :
a.value - b.value);
});
// Simplify the breaks
inBrk_1 = 0;
start_1 = min_1;
breakArrayT_1.forEach(function (brk) {
inBrk_1 += (brk.move === 'in' ? 1 : -1);
if (inBrk_1 === 1 && brk.move === 'in') {
start_1 = brk.value;
}
if (inBrk_1 === 0 && isNumber(start_1)) {
breakArray_1.push({
from: start_1,
to: brk.value,
len: brk.value - start_1 - (brk.size || 0)
});
length_1 += (brk.value -
start_1 -
(brk.size || 0));
}
});
brokenAxis.breakArray = breakArray_1;
// Used with staticScale, and below the actual axis
// length, when breaks are substracted.
if (isNumber(min_1) &&
isNumber(max_1) &&
isNumber(axis.min)) {
brokenAxis.unitLength = max_1 - min_1 - length_1 +
pointRangePadding;
fireEvent(axis, 'afterBreaks');
if (axis.staticScale) {
axis.transA = axis.staticScale;
}
else if (brokenAxis.unitLength) {
axis.transA *=
(max_1 - axis.min + pointRangePadding) /
brokenAxis.unitLength;
}
if (pointRangePadding) {
axis.minPixelPadding =
axis.transA * (axis.minPointOffset || 0);
}
axis.min = min_1;
axis.max = max_1;
}
}
};
}
if (pick(redraw, true)) {
axis.chart.redraw();
}
};
return Additions;
}());
BrokenAxis.Additions = Additions;
})(BrokenAxis || (BrokenAxis = {}));
/* *
*
* Default Export
*
* */
return BrokenAxis;
});
_registerModule(_modules, 'Core/Axis/GridAxis.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Axis/AxisDefaults.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (Axis, AxisDefaults, H, U) {
/* *
*
* (c) 2016 Highsoft AS
* Authors: Lars A. V. Cabrera
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var dateFormats = H.dateFormats;
var addEvent = U.addEvent,
defined = U.defined,
erase = U.erase,
find = U.find,
isArray = U.isArray,
isNumber = U.isNumber,
merge = U.merge,
pick = U.pick,
timeUnits = U.timeUnits,
wrap = U.wrap;
/* *
*
* Enums
*
* */
/**
* Enum for which side the axis is on. Maps to axis.side.
* @private
*/
var GridAxisSide;
(function (GridAxisSide) {
GridAxisSide[GridAxisSide["top"] = 0] = "top";
GridAxisSide[GridAxisSide["right"] = 1] = "right";
GridAxisSide[GridAxisSide["bottom"] = 2] = "bottom";
GridAxisSide[GridAxisSide["left"] = 3] = "left";
})(GridAxisSide || (GridAxisSide = {}));
/* *
*
* Constants
*
* */
var composedClasses = [];
/* *
*
* Functions
*
* */
/**
* @private
*/
function argsToArray(args) {
return Array.prototype.slice.call(args, 1);
}
/**
* @private
*/
function isObject(x) {
// Always use strict mode
return U.isObject(x, true);
}
/**
* @private
*/
function applyGridOptions(axis) {
var options = axis.options;
// Center-align by default
/*
if (!options.labels) {
options.labels = {};
}
*/
options.labels.align = pick(options.labels.align, 'center');
// @todo: Check against tickLabelPlacement between/on etc
/* Prevents adding the last tick label if the axis is not a category
axis.
Since numeric labels are normally placed at starts and ends of a
range of value, and this module makes the label point at the value,
an "extra" label would appear. */
if (!axis.categories) {
options.showLastLabel = false;
}
// Prevents rotation of labels when squished, as rotating them would not
// help.
axis.labelRotation = 0;
options.labels.rotation = 0;
}
/**
* Extends axis class with grid support.
* @private
*/
function compose(AxisClass, ChartClass, TickClass) {
if (composedClasses.indexOf(AxisClass) === -1) {
composedClasses.push(AxisClass);
AxisClass.keepProps.push('grid');
AxisClass.prototype.getMaxLabelDimensions = getMaxLabelDimensions;
wrap(AxisClass.prototype, 'unsquish', wrapUnsquish);
// Add event handlers
addEvent(AxisClass, 'init', onInit);
addEvent(AxisClass, 'afterGetOffset', onAfterGetOffset);
addEvent(AxisClass, 'afterGetTitlePosition', onAfterGetTitlePosition);
addEvent(AxisClass, 'afterInit', onAfterInit);
addEvent(AxisClass, 'afterRender', onAfterRender);
addEvent(AxisClass, 'afterSetAxisTranslation', onAfterSetAxisTranslation);
addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions);
addEvent(AxisClass, 'afterSetOptions', onAfterSetOptions2);
addEvent(AxisClass, 'afterSetScale', onAfterSetScale);
addEvent(AxisClass, 'afterTickSize', onAfterTickSize);
addEvent(AxisClass, 'trimTicks', onTrimTicks);
addEvent(AxisClass, 'destroy', onDestroy);
}
if (composedClasses.indexOf(ChartClass) === -1) {
addEvent(ChartClass, 'afterSetChartSize', onChartAfterSetChartSize);
}
if (composedClasses.indexOf(TickClass) === -1) {
addEvent(TickClass, 'afterGetLabelPosition', onTickAfterGetLabelPosition);
addEvent(TickClass, 'labelFormat', onTickLabelFormat);
}
return AxisClass;
}
/**
* Get the largest label width and height.
*
* @private
* @function Highcharts.Axis#getMaxLabelDimensions
*
* @param {Highcharts.Dictionary} ticks
* All the ticks on one axis.
*
* @param {Array} tickPositions
* All the tick positions on one axis.
*
* @return {Highcharts.SizeObject}
* Object containing the properties height and width.
*
* @todo Move this to the generic axis implementation, as it is used there.
*/
function getMaxLabelDimensions(ticks, tickPositions) {
var dimensions = {
width: 0,
height: 0
};
tickPositions.forEach(function (pos) {
var tick = ticks[pos];
var labelHeight = 0,
labelWidth = 0,
label;
if (isObject(tick)) {
label = isObject(tick.label) ? tick.label : {};
// Find width and height of label
labelHeight = label.getBBox ? label.getBBox().height : 0;
if (label.textStr && !isNumber(label.textPxLength)) {
label.textPxLength = label.getBBox().width;
}
labelWidth = isNumber(label.textPxLength) ?
// Math.round ensures crisp lines
Math.round(label.textPxLength) :
0;
if (label.textStr) {
// Set the tickWidth same as the label width after ellipsis
// applied #10281
labelWidth = Math.round(label.getBBox().width);
}
// Update the result if width and/or height are larger
dimensions.height = Math.max(labelHeight, dimensions.height);
dimensions.width = Math.max(labelWidth, dimensions.width);
}
});
// For tree grid, add indentation
if (this.options.type === 'treegrid' &&
this.treeGrid &&
this.treeGrid.mapOfPosToGridNode) {
var treeDepth = this.treeGrid.mapOfPosToGridNode[-1].height || 0;
dimensions.width += (this.options.labels.indentation *
(treeDepth - 1));
}
return dimensions;
}
/**
* Handle columns and getOffset.
* @private
*/
function onAfterGetOffset() {
var grid = this.grid;
(grid && grid.columns || []).forEach(function (column) {
column.getOffset();
});
}
/**
* @private
*/
function onAfterGetTitlePosition(e) {
var axis = this;
var options = axis.options;
var gridOptions = options.grid || {};
if (gridOptions.enabled === true) {
// compute anchor points for each of the title align options
var axisTitle = axis.axisTitle,
axisHeight = axis.height,
horiz = axis.horiz,
axisLeft = axis.left,
offset = axis.offset,
opposite = axis.opposite,
options_1 = axis.options,
axisTop = axis.top,
axisWidth = axis.width;
var tickSize = axis.tickSize();
var titleWidth = axisTitle && axisTitle.getBBox().width;
var xOption = options_1.title.x;
var yOption = options_1.title.y;
var titleMargin = pick(options_1.title.margin,
horiz ? 5 : 10);
var titleFontSize = axis.chart.renderer.fontMetrics(options_1.title.style.fontSize,
axisTitle).f;
var crispCorr = tickSize ? tickSize[0] / 2 : 0;
// TODO account for alignment
// the position in the perpendicular direction of the axis
var offAxis = ((horiz ? axisTop + axisHeight : axisLeft) +
(horiz ? 1 : -1) * // horizontal axis reverses the margin
(opposite ? -1 : 1) * // so does opposite axes
crispCorr +
(axis.side === GridAxisSide.bottom ? titleFontSize : 0));
e.titlePosition.x = horiz ?
axisLeft - (titleWidth || 0) / 2 - titleMargin + xOption :
offAxis + (opposite ? axisWidth : 0) + offset + xOption;
e.titlePosition.y = horiz ?
(offAxis -
(opposite ? axisHeight : 0) +
(opposite ? titleFontSize : -titleFontSize) / 2 +
offset +
yOption) :
axisTop - titleMargin + yOption;
}
}
/**
* @private
*/
function onAfterInit() {
var axis = this;
var chart = axis.chart,
_a = axis.options.grid,
gridOptions = _a === void 0 ? {} : _a,
userOptions = axis.userOptions;
if (gridOptions.enabled) {
applyGridOptions(axis);
}
if (gridOptions.columns) {
var columns = axis.grid.columns = [];
var columnIndex = axis.grid.columnIndex = 0;
// Handle columns, each column is a grid axis
while (++columnIndex < gridOptions.columns.length) {
var columnOptions = merge(userOptions,
gridOptions.columns[gridOptions.columns.length - columnIndex - 1], {
linkedTo: 0,
// Force to behave like category axis
type: 'category',
// Disable by default the scrollbar on the grid axis
scrollbar: {
enabled: false
}
});
delete columnOptions.grid.columns; // Prevent recursion
var column = new Axis(axis.chart,
columnOptions);
column.grid.isColumn = true;
column.grid.columnIndex = columnIndex;
// Remove column axis from chart axes array, and place it
// in the columns array.
erase(chart.axes, column);
erase(chart[axis.coll], column);
columns.push(column);
}
}
}
/**
* Draw an extra line on the far side of the outermost axis,
* creating floor/roof/wall of a grid. And some padding.
* ```
* Make this:
* (axis.min) __________________________ (axis.max)
* | | | | |
* Into this:
* (axis.min) __________________________ (axis.max)
* ___|____|____|____|____|__
* ```
* @private
*/
function onAfterRender() {
var axis = this,
grid = axis.grid,
options = axis.options,
gridOptions = options.grid || {};
if (gridOptions.enabled === true) {
var min = axis.min || 0,
max = axis.max || 0;
// @todo acutual label padding (top, bottom, left, right)
axis.maxLabelDimensions = axis.getMaxLabelDimensions(axis.ticks, axis.tickPositions);
// Remove right wall before rendering if updating
if (axis.rightWall) {
axis.rightWall.destroy();
}
/*
Draw an extra axis line on outer axes
>
Make this: |______|______|______|___
> _________________________
Into this: |______|______|______|__|
*/
if (axis.grid && axis.grid.isOuterAxis() && axis.axisLine) {
var lineWidth = options.lineWidth;
if (lineWidth) {
var linePath = axis.getLinePath(lineWidth),
startPoint = linePath[0],
endPoint = linePath[1],
// Negate distance if top or left axis
// Subtract 1px to draw the line at the end of the tick
tickLength = (axis.tickSize('tick') || [1])[0],
distance = (tickLength - 1) * ((axis.side === GridAxisSide.top ||
axis.side === GridAxisSide.left) ? -1 : 1);
// If axis is horizontal, reposition line path vertically
if (startPoint[0] === 'M' && endPoint[0] === 'L') {
if (axis.horiz) {
startPoint[2] += distance;
endPoint[2] += distance;
}
else {
startPoint[1] += distance;
endPoint[1] += distance;
}
}
// If it doesn't exist, add an upper and lower border
// for the vertical grid axis.
if (!axis.horiz && axis.chart.marginRight) {
var upperBorderStartPoint = startPoint,
upperBorderEndPoint = [
'L',
axis.left,
startPoint[2] || 0
],
upperBorderPath = [
upperBorderStartPoint,
upperBorderEndPoint
],
lowerBorderEndPoint = [
'L',
axis.chart.chartWidth - axis.chart.marginRight,
axis.toPixels(max + axis.tickmarkOffset)
],
lowerBorderStartPoint = [
'M',
endPoint[1] || 0,
axis.toPixels(max + axis.tickmarkOffset)
],
lowerBorderPath = [
lowerBorderStartPoint,
lowerBorderEndPoint
];
if (!axis.grid.upperBorder && min % 1 !== 0) {
axis.grid.upperBorder = axis.grid.renderBorder(upperBorderPath);
}
if (axis.grid.upperBorder) {
axis.grid.upperBorder.attr({
stroke: options.lineColor,
'stroke-width': options.lineWidth
});
axis.grid.upperBorder.animate({
d: upperBorderPath
});
}
if (!axis.grid.lowerBorder && max % 1 !== 0) {
axis.grid.lowerBorder = axis.grid.renderBorder(lowerBorderPath);
}
if (axis.grid.lowerBorder) {
axis.grid.lowerBorder.attr({
stroke: options.lineColor,
'stroke-width': options.lineWidth
});
axis.grid.lowerBorder.animate({
d: lowerBorderPath
});
}
}
// Render an extra line parallel to the existing axes, to
// close the grid.
if (!axis.grid.axisLineExtra) {
axis.grid.axisLineExtra = axis.grid.renderBorder(linePath);
}
else {
axis.grid.axisLineExtra.attr({
stroke: options.lineColor,
'stroke-width': options.lineWidth
});
axis.grid.axisLineExtra.animate({
d: linePath
});
}
// show or hide the line depending on options.showEmpty
axis.axisLine[axis.showAxis ? 'show' : 'hide']();
}
}
(grid && grid.columns || []).forEach(function (column) { return column.render(); });
// Manipulate the tick mark visibility
// based on the axis.max- allows smooth scrolling.
if (!axis.horiz &&
axis.chart.hasRendered &&
(axis.scrollbar ||
(axis.linkedParent && axis.linkedParent.scrollbar))) {
var tickmarkOffset = axis.tickmarkOffset,
lastTick = axis.tickPositions[axis.tickPositions.length - 1],
firstTick = axis.tickPositions[0];
var label = void 0,
tickMark = void 0;
while ((label = axis.hiddenLabels.pop()) && label.element) {
label.show(); // #15453
}
while ((tickMark = axis.hiddenMarks.pop()) &&
tickMark.element) {
tickMark.show(); // #16439
}
// Hide/show firts tick label.
label = axis.ticks[firstTick].label;
if (label) {
if (min - firstTick > tickmarkOffset) {
axis.hiddenLabels.push(label.hide());
}
else {
label.show();
}
}
// Hide/show last tick mark/label.
label = axis.ticks[lastTick].label;
if (label) {
if (lastTick - max > tickmarkOffset) {
axis.hiddenLabels.push(label.hide());
}
else {
label.show();
}
}
var mark = axis.ticks[lastTick].mark;
if (mark &&
lastTick - max < tickmarkOffset &&
lastTick - max > 0 && axis.ticks[lastTick].isLast) {
axis.hiddenMarks.push(mark.hide());
}
}
}
}
/**
* @private
*/
function onAfterSetAxisTranslation() {
var axis = this;
var tickInfo = axis.tickPositions && axis.tickPositions.info;
var options = axis.options;
var gridOptions = options.grid || {};
var userLabels = axis.userOptions.labels || {};
// Fire this only for the Gantt type chart, #14868.
if (gridOptions.enabled) {
if (axis.horiz) {
axis.series.forEach(function (series) {
series.options.pointRange = 0;
});
// Lower level time ticks, like hours or minutes, represent
// points in time and not ranges. These should be aligned
// left in the grid cell by default. The same applies to
// years of higher order.
if (tickInfo &&
options.dateTimeLabelFormats &&
options.labels &&
!defined(userLabels.align) &&
(options.dateTimeLabelFormats[tickInfo.unitName]
.range === false ||
tickInfo.count > 1 // years
)) {
options.labels.align = 'left';
if (!defined(userLabels.x)) {
options.labels.x = 3;
}
}
}
else {
// Don't trim ticks which not in min/max range but
// they are still in the min/max plus tickInterval.
if (this.options.type !== 'treegrid' &&
axis.grid &&
axis.grid.columns) {
this.minPointOffset = this.tickInterval;
}
}
}
}
/**
* Creates a left and right wall on horizontal axes:
* - Places leftmost tick at the start of the axis, to create a left
* wall
* - Ensures that the rightmost tick is at the end of the axis, to
* create a right wall.
* @private
*/
function onAfterSetOptions(e) {
var options = this.options,
userOptions = e.userOptions,
gridOptions = ((options && isObject(options.grid)) ? options.grid : {});
var gridAxisOptions;
if (gridOptions.enabled === true) {
// Merge the user options into default grid axis options so
// that when a user option is set, it takes presedence.
gridAxisOptions = merge(true, {
className: ('highcharts-grid-axis ' + (userOptions.className || '')),
dateTimeLabelFormats: {
hour: {
list: ['%H:%M', '%H']
},
day: {
list: ['%A, %e. %B', '%a, %e. %b', '%E']
},
week: {
list: ['Week %W', 'W%W']
},
month: {
list: ['%B', '%b', '%o']
}
},
grid: {
borderWidth: 1
},
labels: {
padding: 2,
style: {
fontSize: '13px'
}
},
margin: 0,
title: {
text: null,
reserveSpace: false,
rotation: 0
},
// In a grid axis, only allow one unit of certain types,
// for example we shouln't have one grid cell spanning
// two days.
units: [[
'millisecond',
[1, 10, 100]
], [
'second',
[1, 10]
], [
'minute',
[1, 5, 15]
], [
'hour',
[1, 6]
], [
'day',
[1]
], [
'week',
[1]
], [
'month',
[1]
], [
'year',
null
]]
}, userOptions);
// X-axis specific options
if (this.coll === 'xAxis') {
// For linked axes, tickPixelInterval is used only if
// the tickPositioner below doesn't run or returns
// undefined (like multiple years)
if (defined(userOptions.linkedTo) &&
!defined(userOptions.tickPixelInterval)) {
gridAxisOptions.tickPixelInterval = 350;
}
// For the secondary grid axis, use the primary axis'
// tick intervals and return ticks one level higher.
if (
// Check for tick pixel interval in options
!defined(userOptions.tickPixelInterval) &&
// Only for linked axes
defined(userOptions.linkedTo) &&
!defined(userOptions.tickPositioner) &&
!defined(userOptions.tickInterval)) {
gridAxisOptions.tickPositioner = function (min, max) {
var parentInfo = (this.linkedParent &&
this.linkedParent.tickPositions &&
this.linkedParent.tickPositions.info);
if (parentInfo) {
var units = (gridAxisOptions.units || []);
var unitIdx = void 0,
count = 1,
unitName = 'year';
for (var i = 0; i < units.length; i++) {
var unit_1 = units[i];
if (unit_1 && unit_1[0] === parentInfo.unitName) {
unitIdx = i;
break;
}
}
// Get the first allowed count on the next unit.
var unit = (isNumber(unitIdx) && units[unitIdx + 1]);
if (unit) {
unitName = unit[0] || 'year';
var counts = unit[1];
count = counts && counts[0] || 1;
// In case the base X axis shows years, make the
// secondary axis show ten times the years (#11427)
}
else if (parentInfo.unitName === 'year') {
// unitName is 'year'
count = parentInfo.count * 10;
}
var unitRange = timeUnits[unitName];
this.tickInterval = unitRange * count;
return this.chart.time.getTimeTicks({ unitRange: unitRange, count: count, unitName: unitName }, min, max, this.options.startOfWeek);
}
};
}
}
// Now merge the combined options into the axis options
merge(true, this.options, gridAxisOptions);
if (this.horiz) {
/* _________________________
Make this: ___|_____|_____|_____|__|
^ ^
_________________________
Into this: |_____|_____|_____|_____|
^ ^ */
options.minPadding = pick(userOptions.minPadding, 0);
options.maxPadding = pick(userOptions.maxPadding, 0);
}
// If borderWidth is set, then use its value for tick and
// line width.
if (isNumber(options.grid.borderWidth)) {
options.tickWidth = options.lineWidth =
gridOptions.borderWidth;
}
}
}
/**
* @private
*/
function onAfterSetOptions2(e) {
var axis = this;
var userOptions = e.userOptions;
var gridOptions = userOptions && userOptions.grid || {};
var columns = gridOptions.columns;
// Add column options to the parent axis. Children has their column
// options set on init in onGridAxisAfterInit.
if (gridOptions.enabled && columns) {
merge(true, axis.options, columns[columns.length - 1]);
}
}
/**
* Handle columns and setScale.
* @private
*/
function onAfterSetScale() {
var axis = this;
(axis.grid.columns || []).forEach(function (column) { return column.setScale(); });
}
/**
* Draw vertical axis ticks extra long to create cell floors and roofs.
* Overrides the tickLength for vertical axes.
* @private
*/
function onAfterTickSize(e) {
var defaultLeftAxisOptions = AxisDefaults.defaultLeftAxisOptions;
var _a = this,
horiz = _a.horiz,
maxLabelDimensions = _a.maxLabelDimensions,
_b = _a.options.grid,
gridOptions = _b === void 0 ? {} : _b;
if (gridOptions.enabled && maxLabelDimensions) {
var labelPadding = (Math.abs(defaultLeftAxisOptions.labels.x) * 2);
var distance = horiz ?
(gridOptions.cellHeight ||
labelPadding + maxLabelDimensions.height) :
labelPadding + maxLabelDimensions.width;
if (isArray(e.tickSize)) {
e.tickSize[0] = distance;
}
else {
e.tickSize = [distance, 0];
}
}
}
/**
* @private
*/
function onChartAfterSetChartSize() {
this.axes.forEach(function (axis) {
(axis.grid && axis.grid.columns || []).forEach(function (column) {
column.setAxisSize();
column.setAxisTranslation();
});
});
}
/**
* @private
*/
function onDestroy(e) {
var grid = this.grid;
(grid.columns || []).forEach(function (column) { return column.destroy(e.keepEvents); });
grid.columns = void 0;
}
/**
* Wraps axis init to draw cell walls on vertical axes.
* @private
*/
function onInit(e) {
var axis = this;
var userOptions = e.userOptions || {};
var gridOptions = userOptions.grid || {};
if (gridOptions.enabled && defined(gridOptions.borderColor)) {
userOptions.tickColor = userOptions.lineColor = (gridOptions.borderColor);
}
if (!axis.grid) {
axis.grid = new GridAxisAdditions(axis);
}
axis.hiddenLabels = [];
axis.hiddenMarks = [];
}
/**
* Center tick labels in cells.
* @private
*/
function onTickAfterGetLabelPosition(e) {
var tick = this,
label = tick.label,
axis = tick.axis,
reversed = axis.reversed,
chart = axis.chart,
options = axis.options,
gridOptions = options.grid || {},
labelOpts = axis.options.labels,
align = labelOpts.align,
// verticalAlign is currently not supported for axis.labels.
verticalAlign = 'middle', // labelOpts.verticalAlign,
side = GridAxisSide[axis.side],
tickmarkOffset = e.tickmarkOffset,
tickPositions = axis.tickPositions,
tickPos = tick.pos - tickmarkOffset,
nextTickPos = (isNumber(tickPositions[e.index + 1]) ?
tickPositions[e.index + 1] - tickmarkOffset :
(axis.max || 0) + tickmarkOffset),
tickSize = axis.tickSize('tick'),
tickWidth = tickSize ? tickSize[0] : 0,
crispCorr = tickSize ? tickSize[1] / 2 : 0;
var labelHeight,
lblMetrics,
lines,
bottom,
top,
left,
right;
// Only center tick labels in grid axes
if (gridOptions.enabled === true) {
// Calculate top and bottom positions of the cell.
if (side === 'top') {
bottom = axis.top + axis.offset;
top = bottom - tickWidth;
}
else if (side === 'bottom') {
top = chart.chartHeight - axis.bottom + axis.offset;
bottom = top + tickWidth;
}
else {
bottom = axis.top + axis.len - (axis.translate(reversed ? nextTickPos : tickPos) || 0);
top = axis.top + axis.len - (axis.translate(reversed ? tickPos : nextTickPos) || 0);
}
// Calculate left and right positions of the cell.
if (side === 'right') {
left = chart.chartWidth - axis.right + axis.offset;
right = left + tickWidth;
}
else if (side === 'left') {
right = axis.left + axis.offset;
left = right - tickWidth;
}
else {
left = Math.round(axis.left + (axis.translate(reversed ? nextTickPos : tickPos) || 0)) - crispCorr;
right = Math.min(// #15742
Math.round(axis.left + (axis.translate(reversed ? tickPos : nextTickPos) || 0)) - crispCorr, axis.left + axis.len);
}
tick.slotWidth = right - left;
// Calculate the positioning of the label based on
// alignment.
e.pos.x = (align === 'left' ?
left :
align === 'right' ?
right :
left + ((right - left) / 2) // default to center
);
e.pos.y = (verticalAlign === 'top' ?
top :
verticalAlign === 'bottom' ?
bottom :
top + ((bottom - top) / 2) // default to middle
);
lblMetrics = chart.renderer.fontMetrics(labelOpts.style.fontSize, label && label.element);
labelHeight = label ? label.getBBox().height : 0;
// Adjustment to y position to align the label correctly.
// Would be better to have a setter or similar for this.
if (!labelOpts.useHTML) {
lines = Math.round(labelHeight / lblMetrics.h);
e.pos.y += (
// Center the label
// TODO: why does this actually center the label?
((lblMetrics.b - (lblMetrics.h - lblMetrics.f)) / 2) +
// Adjust for height of additional lines.
-(((lines - 1) * lblMetrics.h) / 2));
}
else {
e.pos.y += (
// Readjust yCorr in htmlUpdateTransform
lblMetrics.b +
// Adjust for height of html label
-(labelHeight / 2));
}
e.pos.x += (axis.horiz && labelOpts.x) || 0;
}
}
/**
* @private
*/
function onTickLabelFormat(ctx) {
var axis = ctx.axis,
value = ctx.value;
if (axis.options.grid &&
axis.options.grid.enabled) {
var tickPos = axis.tickPositions;
var series = (axis.linkedParent || axis).series[0];
var isFirst = value === tickPos[0];
var isLast = value === tickPos[tickPos.length - 1];
var point = series && find(series.options.data,
function (p) {
return p[axis.isXAxis ? 'x' : 'y'] === value;
});
var pointCopy = void 0;
if (point && series.is('gantt')) {
// For the Gantt set point aliases to the pointCopy
// to do not change the original point
pointCopy = merge(point);
H.seriesTypes.gantt.prototype.pointClass
.setGanttPointAliases(pointCopy);
}
// Make additional properties available for the
// formatter
ctx.isFirst = isFirst;
ctx.isLast = isLast;
ctx.point = pointCopy;
}
}
/**
* Makes tick labels which are usually ignored in a linked axis
* displayed if they are within range of linkedParent.min.
* ```
* _____________________________
* | | | | |
* Make this: | | 2 | 3 | 4 |
* |___|_______|_______|_______|
* ^
* _____________________________
* | | | | |
* Into this: | 1 | 2 | 3 | 4 |
* |___|_______|_______|_______|
* ^
* ```
* @private
* @todo Does this function do what the drawing says? Seems to affect
* ticks and not the labels directly?
*/
function onTrimTicks() {
var axis = this;
var options = axis.options;
var gridOptions = options.grid || {};
var categoryAxis = axis.categories;
var tickPositions = axis.tickPositions;
var firstPos = tickPositions[0];
var lastPos = tickPositions[tickPositions.length - 1];
var linkedMin = axis.linkedParent && axis.linkedParent.min;
var linkedMax = axis.linkedParent && axis.linkedParent.max;
var min = linkedMin || axis.min;
var max = linkedMax || axis.max;
var tickInterval = axis.tickInterval;
var endMoreThanMin = (firstPos < min &&
firstPos + tickInterval > min);
var startLessThanMax = (lastPos > max &&
lastPos - tickInterval < max);
if (gridOptions.enabled === true &&
!categoryAxis &&
(axis.horiz || axis.isLinked)) {
if (endMoreThanMin && !options.startOnTick) {
tickPositions[0] = min;
}
if (startLessThanMax && !options.endOnTick) {
tickPositions[tickPositions.length - 1] = max;
}
}
}
/**
* Avoid altering tickInterval when reserving space.
* @private
*/
function wrapUnsquish(proceed) {
var axis = this;
var _a = axis.options.grid,
gridOptions = _a === void 0 ? {} : _a;
if (gridOptions.enabled === true && axis.categories) {
return axis.tickInterval;
}
return proceed.apply(axis, argsToArray(arguments));
}
/* *
*
* Class
*
* */
/**
* Additions for grid axes.
* @private
* @class
*/
var GridAxisAdditions = /** @class */ (function () {
/* *
*
* Constructors
*
* */
function GridAxisAdditions(axis) {
this.axis = axis;
}
/* *
*
* Functions
*
* */
/**
* Checks if an axis is the outer axis in its dimension. Since
* axes are placed outwards in order, the axis with the highest
* index is the outermost axis.
*
* Example: If there are multiple x-axes at the top of the chart,
* this function returns true if the axis supplied is the last
* of the x-axes.
*
* @private
*
* @return {boolean}
* True if the axis is the outermost axis in its dimension; false if
* not.
*/
GridAxisAdditions.prototype.isOuterAxis = function () {
var axis = this.axis;
var chart = axis.chart;
var columnIndex = axis.grid.columnIndex;
var columns = (axis.linkedParent && axis.linkedParent.grid.columns ||
axis.grid.columns);
var parentAxis = columnIndex ? axis.linkedParent : axis;
var thisIndex = -1,
lastIndex = 0;
(chart[axis.coll] || []).forEach(function (otherAxis, index) {
if (otherAxis.side === axis.side &&
!otherAxis.options.isInternal) {
lastIndex = index;
if (otherAxis === parentAxis) {
// Get the index of the axis in question
thisIndex = index;
}
}
});
return (lastIndex === thisIndex &&
(isNumber(columnIndex) ?
columns.length === columnIndex :
true));
};
/**
* Add extra border based on the provided path.
* @private
* @param {SVGPath} path
* The path of the border.
* @return {Highcharts.SVGElement}
* Border
*/
GridAxisAdditions.prototype.renderBorder = function (path) {
var axis = this.axis,
renderer = axis.chart.renderer,
options = axis.options,
extraBorderLine = renderer.path(path)
.addClass('highcharts-axis-line')
.add(axis.axisBorder);
if (!renderer.styledMode) {
extraBorderLine.attr({
stroke: options.lineColor,
'stroke-width': options.lineWidth,
zIndex: 7
});
}
return extraBorderLine;
};
return GridAxisAdditions;
}());
/* *
*
* Registry
*
* */
// First letter of the day of the week, e.g. 'M' for 'Monday'.
dateFormats.E = function (timestamp) {
return this.dateFormat('%a', timestamp, true).charAt(0);
};
// Adds week date format
dateFormats.W = function (timestamp) {
var time = this, d = new this.Date(timestamp), unitsToOmit = ['Hours', 'Milliseconds', 'Minutes', 'Seconds'];
unitsToOmit.forEach(function (format) {
time.set(format, d, 0);
});
var firstDay = (this.get('Day',
d) + 6) % 7;
var thursday = new this.Date(d.valueOf());
this.set('Date', thursday, this.get('Date', d) - firstDay + 3);
var firstThursday = new this.Date(this.get('FullYear',
thursday), 0, 1);
if (this.get('Day', firstThursday) !== 4) {
this.set('Month', d, 0);
this.set('Date', d, 1 + (11 - this.get('Day', firstThursday)) % 7);
}
return (1 +
Math.floor((thursday.valueOf() - firstThursday.valueOf()) / 604800000)).toString();
};
/* *
*
* Default Export
*
* */
var GridAxis = {
compose: compose
};
/* *
*
* API Options
*
* */
/**
* @productdesc {gantt}
* For grid axes (like in Gantt charts),
* it is possible to declare as a list to provide different
* formats depending on available space.
*
* Defaults to:
* ```js
* {
* hour: { list: ['%H:%M', '%H'] },
* day: { list: ['%A, %e. %B', '%a, %e. %b', '%E'] },
* week: { list: ['Week %W', 'W%W'] },
* month: { list: ['%B', '%b', '%o'] }
* }
* ```
*
* @sample {gantt} gantt/grid-axis/date-time-label-formats
* Gantt chart with custom axis date format.
*
* @apioption xAxis.dateTimeLabelFormats
*/
/**
* Set grid options for the axis labels. Requires Highcharts Gantt.
*
* @since 6.2.0
* @product gantt
* @apioption xAxis.grid
*/
/**
* Enable grid on the axis labels. Defaults to true for Gantt charts.
*
* @type {boolean}
* @default true
* @since 6.2.0
* @product gantt
* @apioption xAxis.grid.enabled
*/
/**
* Set specific options for each column (or row for horizontal axes) in the
* grid. Each extra column/row is its own axis, and the axis options can be set
* here.
*
* @sample gantt/demo/left-axis-table
* Left axis as a table
*
* @type {Array}
* @apioption xAxis.grid.columns
*/
/**
* Set border color for the label grid lines.
*
* @type {Highcharts.ColorString}
* @apioption xAxis.grid.borderColor
*/
/**
* Set border width of the label grid lines.
*
* @type {number}
* @default 1
* @apioption xAxis.grid.borderWidth
*/
/**
* Set cell height for grid axis labels. By default this is calculated from font
* size. This option only applies to horizontal axes.
*
* @sample gantt/grid-axis/cellheight
* Gant chart with custom cell height
* @type {number}
* @apioption xAxis.grid.cellHeight
*/
''; // keeps doclets above in JS file
return GridAxis;
});
_registerModule(_modules, 'Gantt/Tree.js', [_modules['Core/Utilities.js']], function (U) {
/* *
*
* (c) 2016-2021 Highsoft AS
*
* Authors: Jon Arild Nygard
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
/* eslint no-console: 0 */
var extend = U.extend,
isNumber = U.isNumber,
pick = U.pick;
/**
* Creates an object map from parent id to childrens index.
*
* @private
* @function Highcharts.Tree#getListOfParents
*
* @param {Array<*>} data
* List of points set in options. `Array.parent` is parent id of point.
*
* @param {Array} ids
* List of all point ids.
*
* @return {Highcharts.Dictionary>}
* Map from parent id to children index in data
*/
var getListOfParents = function (data,
ids) {
var listOfParents = data.reduce(function (prev,
curr) {
var parent = pick(curr.parent, '');
if (typeof prev[parent] === 'undefined') {
prev[parent] = [];
}
prev[parent].push(curr);
return prev;
}, {}), parents = Object.keys(listOfParents);
// If parent does not exist, hoist parent to root of tree.
parents.forEach(function (parent, list) {
var children = listOfParents[parent];
if ((parent !== '') && (ids.indexOf(parent) === -1)) {
children.forEach(function (child) {
list[''].push(child);
});
delete list[parent];
}
});
return listOfParents;
};
var getNode = function (id,
parent,
level,
data,
mapOfIdToChildren,
options) {
var descendants = 0,
height = 0,
after = options && options.after,
before = options && options.before,
node = {
data: data,
depth: level - 1,
id: id,
level: level,
parent: parent
},
start,
end,
children;
// Allow custom logic before the children has been created.
if (typeof before === 'function') {
before(node, options);
}
// Call getNode recursively on the children. Calulate the height of the
// node, and the number of descendants.
children = ((mapOfIdToChildren[id] || [])).map(function (child) {
var node = getNode(child.id,
id, (level + 1),
child,
mapOfIdToChildren,
options),
childStart = child.start,
childEnd = (child.milestone === true ?
childStart :
child.end);
// Start should be the lowest child.start.
start = ((!isNumber(start) || childStart < start) ?
childStart :
start);
// End should be the largest child.end.
// If child is milestone, then use start as end.
end = ((!isNumber(end) || childEnd > end) ?
childEnd :
end);
descendants = descendants + 1 + node.descendants;
height = Math.max(node.height + 1, height);
return node;
});
// Calculate start and end for point if it is not already explicitly set.
if (data) {
data.start = pick(data.start, start);
data.end = pick(data.end, end);
}
extend(node, {
children: children,
descendants: descendants,
height: height
});
// Allow custom logic after the children has been created.
if (typeof after === 'function') {
after(node, options);
}
return node;
};
var getTree = function (data,
options) {
var ids = data.map(function (d) {
return d.id;
}), mapOfIdToChildren = getListOfParents(data, ids);
return getNode('', null, 1, null, mapOfIdToChildren, options);
};
var Tree = {
getListOfParents: getListOfParents,
getNode: getNode,
getTree: getTree
};
return Tree;
});
_registerModule(_modules, 'Core/Axis/TreeGrid/TreeGridTick.js', [_modules['Core/Utilities.js']], function (U) {
/* *
*
* (c) 2016 Highsoft AS
* Authors: Jon Arild Nygard
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var addEvent = U.addEvent,
isObject = U.isObject,
isNumber = U.isNumber,
pick = U.pick,
wrap = U.wrap;
/* *
*
* Constants
*
* */
var composedClasses = [];
/* *
*
* Functions
*
* */
/**
* @private
*/
function onTickInit() {
var tick = this;
if (!tick.treeGrid) {
tick.treeGrid = new TreeGridTickAdditions(tick);
}
}
/**
* @private
*/
function onTickHover(label) {
label.addClass('highcharts-treegrid-node-active');
if (!label.renderer.styledMode) {
label.css({
textDecoration: 'underline'
});
}
}
/**
* @private
*/
function onTickHoverExit(label, options) {
var css = isObject(options.style) ? options.style : {};
label.removeClass('highcharts-treegrid-node-active');
if (!label.renderer.styledMode) {
label.css({ textDecoration: css.textDecoration });
}
}
/**
* @private
*/
function renderLabelIcon(tick, params) {
var treeGrid = tick.treeGrid,
isNew = !treeGrid.labelIcon,
renderer = params.renderer,
labelBox = params.xy,
options = params.options,
width = options.width || 0,
height = options.height || 0,
iconCenter = {
x: labelBox.x - (width / 2) - (options.padding || 0),
y: labelBox.y - (height / 2)
},
rotation = params.collapsed ? 90 : 180,
shouldRender = params.show && isNumber(iconCenter.y);
var icon = treeGrid.labelIcon;
if (!icon) {
treeGrid.labelIcon = icon = renderer
.path(renderer.symbols[options.type](options.x || 0, options.y || 0, width, height))
.addClass('highcharts-label-icon')
.add(params.group);
}
// Set the new position, and show or hide
icon[shouldRender ? 'show' : 'hide'](); // #14904, #1338
// Presentational attributes
if (!renderer.styledMode) {
icon
.attr({
cursor: 'pointer',
'fill': pick(params.color, "#666666" /* Palette.neutralColor60 */),
'stroke-width': 1,
stroke: options.lineColor,
strokeWidth: options.lineWidth || 0
});
}
// Update the icon positions
icon[isNew ? 'attr' : 'animate']({
translateX: iconCenter.x,
translateY: iconCenter.y,
rotation: rotation
});
}
/**
* @private
*/
function wrapGetLabelPosition(proceed, x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
var tick = this,
lbOptions = pick(tick.options && tick.options.labels,
labelOptions),
pos = tick.pos,
axis = tick.axis,
options = axis.options,
isTreeGrid = options.type === 'treegrid',
result = proceed.apply(tick,
[x,
y,
label,
horiz,
lbOptions,
tickmarkOffset,
index,
step]);
var symbolOptions,
indentation,
mapOfPosToGridNode,
node,
level;
if (isTreeGrid) {
symbolOptions = (lbOptions && isObject(lbOptions.symbol, true) ?
lbOptions.symbol :
{});
indentation = (lbOptions && isNumber(lbOptions.indentation) ?
lbOptions.indentation :
0);
mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode;
node = mapOfPosToGridNode && mapOfPosToGridNode[pos];
level = (node && node.depth) || 1;
result.x += (
// Add space for symbols
((symbolOptions.width || 0) +
((symbolOptions.padding || 0) * 2)) +
// Apply indentation
((level - 1) * indentation));
}
return result;
}
/**
* @private
*/
function wrapRenderLabel(proceed) {
var tick = this, pos = tick.pos, axis = tick.axis, label = tick.label, mapOfPosToGridNode = axis.treeGrid.mapOfPosToGridNode, options = axis.options, labelOptions = pick(tick.options && tick.options.labels, options && options.labels), symbolOptions = (labelOptions && isObject(labelOptions.symbol, true) ?
labelOptions.symbol :
{}), node = mapOfPosToGridNode && mapOfPosToGridNode[pos], level = node && node.depth, isTreeGrid = options.type === 'treegrid', shouldRender = axis.tickPositions.indexOf(pos) > -1, prefixClassName = 'highcharts-treegrid-node-', styledMode = axis.chart.styledMode;
var collapsed,
addClassName,
removeClassName;
if (isTreeGrid && node) {
// Add class name for hierarchical styling.
if (label &&
label.element) {
label.addClass(prefixClassName + 'level-' + level);
}
}
proceed.apply(tick, Array.prototype.slice.call(arguments, 1));
if (isTreeGrid &&
label &&
label.element &&
node &&
node.descendants &&
node.descendants > 0) {
collapsed = axis.treeGrid.isCollapsed(node);
renderLabelIcon(tick, {
color: (!styledMode &&
label.styles &&
label.styles.color ||
''),
collapsed: collapsed,
group: label.parentGroup,
options: symbolOptions,
renderer: label.renderer,
show: shouldRender,
xy: label.xy
});
// Add class name for the node.
addClassName = prefixClassName +
(collapsed ? 'collapsed' : 'expanded');
removeClassName = prefixClassName +
(collapsed ? 'expanded' : 'collapsed');
label
.addClass(addClassName)
.removeClass(removeClassName);
if (!styledMode) {
label.css({
cursor: 'pointer'
});
}
// Add events to both label text and icon
[label, tick.treeGrid.labelIcon].forEach(function (object) {
if (object && !object.attachedTreeGridEvents) {
// On hover
addEvent(object.element, 'mouseover', function () {
onTickHover(label);
});
// On hover out
addEvent(object.element, 'mouseout', function () {
onTickHoverExit(label, labelOptions);
});
addEvent(object.element, 'click', function () {
tick.treeGrid.toggleCollapse();
});
object.attachedTreeGridEvents = true;
}
});
}
}
/* *
*
* Classes
*
* */
/**
* @private
* @class
*/
var TreeGridTickAdditions = /** @class */ (function () {
/* *
*
* Constructors
*
* */
/**
* @private
*/
function TreeGridTickAdditions(tick) {
this.tick = tick;
}
/* *
*
* Static Functions
*
* */
/**
* @private
*/
TreeGridTickAdditions.compose = function (TickClass) {
if (composedClasses.indexOf(TickClass) === -1) {
composedClasses.push(TickClass);
addEvent(TickClass, 'init', onTickInit);
wrap(TickClass.prototype, 'getLabelPosition', wrapGetLabelPosition);
wrap(TickClass.prototype, 'renderLabel', wrapRenderLabel);
// backwards compatibility
TickClass.prototype.collapse = function (redraw) {
this.treeGrid.collapse(redraw);
};
TickClass.prototype.expand = function (redraw) {
this.treeGrid.expand(redraw);
};
TickClass.prototype.toggleCollapse = function (redraw) {
this.treeGrid.toggleCollapse(redraw);
};
}
};
/* *
*
* Functions
*
* */
/**
* Collapse the grid cell. Used when axis is of type treegrid.
*
* @see gantt/treegrid-axis/collapsed-dynamically/demo.js
*
* @private
* @function Highcharts.Tick#collapse
*
* @param {boolean} [redraw=true]
* Whether to redraw the chart or wait for an explicit call to
* {@link Highcharts.Chart#redraw}
*/
TreeGridTickAdditions.prototype.collapse = function (redraw) {
var tick = this.tick,
axis = tick.axis,
brokenAxis = axis.brokenAxis;
if (brokenAxis &&
axis.treeGrid.mapOfPosToGridNode) {
var pos = tick.pos,
node = axis.treeGrid.mapOfPosToGridNode[pos],
breaks = axis.treeGrid.collapse(node);
brokenAxis.setBreaks(breaks, pick(redraw, true));
}
};
/**
* Destroy remaining labelIcon if exist.
*
* @private
* @function Highcharts.Tick#destroy
*/
TreeGridTickAdditions.prototype.destroy = function () {
if (this.labelIcon) {
this.labelIcon.destroy();
}
};
/**
* Expand the grid cell. Used when axis is of type treegrid.
*
* @see gantt/treegrid-axis/collapsed-dynamically/demo.js
*
* @private
* @function Highcharts.Tick#expand
*
* @param {boolean} [redraw=true]
* Whether to redraw the chart or wait for an explicit call to
* {@link Highcharts.Chart#redraw}
*/
TreeGridTickAdditions.prototype.expand = function (redraw) {
var tick = this.tick,
axis = tick.axis,
brokenAxis = axis.brokenAxis;
if (brokenAxis &&
axis.treeGrid.mapOfPosToGridNode) {
var pos = tick.pos,
node = axis.treeGrid.mapOfPosToGridNode[pos],
breaks = axis.treeGrid.expand(node);
brokenAxis.setBreaks(breaks, pick(redraw, true));
}
};
/**
* Toggle the collapse/expand state of the grid cell. Used when axis is
* of type treegrid.
*
* @see gantt/treegrid-axis/collapsed-dynamically/demo.js
*
* @private
* @function Highcharts.Tick#toggleCollapse
*
* @param {boolean} [redraw=true]
* Whether to redraw the chart or wait for an explicit call to
* {@link Highcharts.Chart#redraw}
*/
TreeGridTickAdditions.prototype.toggleCollapse = function (redraw) {
var tick = this.tick,
axis = tick.axis,
brokenAxis = axis.brokenAxis;
if (brokenAxis &&
axis.treeGrid.mapOfPosToGridNode) {
var pos = tick.pos,
node = axis.treeGrid.mapOfPosToGridNode[pos],
breaks = axis.treeGrid.toggleCollapse(node);
brokenAxis.setBreaks(breaks, pick(redraw, true));
}
};
return TreeGridTickAdditions;
}());
/* *
*
* Default Export
*
* */
return TreeGridTickAdditions;
});
_registerModule(_modules, 'Series/TreeUtilities.js', [_modules['Core/Color/Color.js'], _modules['Core/Utilities.js']], function (Color, U) {
/* *
*
* (c) 2014-2021 Highsoft AS
*
* Authors: Jon Arild Nygard / Oystein Moseng
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
var extend = U.extend,
isArray = U.isArray,
isNumber = U.isNumber,
isObject = U.isObject,
merge = U.merge,
pick = U.pick;
/* *
*
* Functions
*
* */
/* eslint-disable valid-jsdoc */
/**
* @private
*/
function getColor(node, options) {
var index = options.index,
mapOptionsToLevel = options.mapOptionsToLevel,
parentColor = options.parentColor,
parentColorIndex = options.parentColorIndex,
series = options.series,
colors = options.colors,
siblings = options.siblings,
points = series.points,
chartOptionsChart = series.chart.options.chart;
var getColorByPoint,
point,
level,
colorByPoint,
colorIndexByPoint,
color,
colorIndex;
/**
* @private
*/
var variateColor = function (color) {
var colorVariation = level && level.colorVariation;
if (colorVariation &&
colorVariation.key === 'brightness' &&
index &&
siblings) {
return Color.parse(color).brighten(colorVariation.to * (index / siblings)).get();
}
return color;
};
if (node) {
point = points[node.i];
level = mapOptionsToLevel[node.level] || {};
getColorByPoint = point && level.colorByPoint;
if (getColorByPoint) {
colorIndexByPoint = point.index % (colors ?
colors.length :
chartOptionsChart.colorCount);
colorByPoint = colors && colors[colorIndexByPoint];
}
// Select either point color, level color or inherited color.
if (!series.chart.styledMode) {
color = pick(point && point.options.color, level && level.color, colorByPoint, parentColor && variateColor(parentColor), series.color);
}
colorIndex = pick(point && point.options.colorIndex, level && level.colorIndex, colorIndexByPoint, parentColorIndex, options.colorIndex);
}
return {
color: color,
colorIndex: colorIndex
};
}
/**
* Creates a map from level number to its given options.
*
* @private
*
* @param {Object} params
* Object containing parameters.
* - `defaults` Object containing default options. The default options are
* merged with the userOptions to get the final options for a specific
* level.
* - `from` The lowest level number.
* - `levels` User options from series.levels.
* - `to` The highest level number.
*
* @return {Highcharts.Dictionary