PageSourceSearch

https://www.limouxin-tourisme.com/app/dist/limouxin/addons/woody-l…/code/es-modules/Core/Axis/Axis.js

js limouxin-tourisme.com collected 2026-10-02 21:59:23 UTC 131,935 bytes, 3,255 lines download raw bytes

1/* *
2 *
3 *  (c) 2010-2024 Torstein Honsi
4 *
5 *  License: www.highcharts.com/license
6 *
7 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
8 *
9 * */
10'use strict';
11import A from '../Animation/AnimationUtilities.js';
12const { animObject } = A;
13import AxisDefaults from './AxisDefaults.js';
14const { xAxis, yAxis } = AxisDefaults;
15import Color from '../Color/Color.js';
16import D from '../Defaults.js';
17const { defaultOptions } = D;
18import F from '../Foundation.js';
19const { registerEventOptions } = F;
20import H from '../Globals.js';
21const { deg2rad } = H;
22import Tick from './Tick.js';
23import U from '../Utilities.js';
24const { arrayMax, arrayMin, clamp, correctFloat, defined, destroyObjectProperties, erase, error, extend, fireEvent, getClosestDistance, insertItem, isArray, isNumber, isString, merge, normalizeTickInterval, objectEach, pick, relativeLength, removeEvent, splat, syncTimeout } = U;
25const getNormalizedTickInterval = (axis, tickInterval) => normalizeTickInterval(tickInterval, void 0, void 0, pick(axis.options.allowDecimals, 
26// If the tick interval is greater than 0.5, avoid decimals, as
27// linear axes are often used to render discrete values (#3363). If
28// a tick amount is set, allow decimals by default, as it increases
29// the chances for a good fit.
30tickInterval < 0.5 || axis.tickAmount !== void 0), !!axis.tickAmount);
31extend(defaultOptions, { xAxis, yAxis: merge(xAxis, yAxis) });
32/* *
33 *
34 *  Class
35 *
36 * */
37/**
38 * Create a new axis object. Called internally when instantiating a new chart or
39 * adding axes by {@link Highcharts.Chart#addAxis}.
40 *
41 * A chart can have from 0 axes (pie chart) to multiples. In a normal, single
42 * series cartesian chart, there is one X axis and one Y axis.
43 *
44 * The X axis or axes are referenced by {@link Highcharts.Chart.xAxis}, which is
45 * an array of Axis objects. If there is only one axis, it can be referenced
46 * through `chart.xAxis[0]`, and multiple axes have increasing indices. The same
47 * pattern goes for Y axes.
48 *
49 * If you need to get the axes from a series object, use the `series.xAxis` and
50 * `series.yAxis` properties. These are not arrays, as one series can only be
51 * associated to one X and one Y axis.
52 *
53 * A third way to reference the axis programmatically is by `id`. Add an `id` in
54 * the axis configuration options, and get the axis by
55 * {@link Highcharts.Chart#get}.
56 *
57 * Configuration options for the axes are given in options.xAxis and
58 * options.yAxis.
59 *
60 * @class
61 * @name Highcharts.Axis
62 *
63 * @param {Highcharts.Chart} chart
64 * The Chart instance to apply the axis on.
65 *
66 * @param {Highcharts.AxisOptions} userOptions
67 * Axis options
68 */
69class Axis {
70    /* *
71     *
72     *  Constructors
73     *
74     * */
75    constructor(chart, userOptions, coll) {
76        this.init(chart, userOptions, coll);
77    }
78    /* *
79     *
80     *  Functions
81     *
82     * */
83    /**
84     * Overrideable function to initialize the axis.
85     *
86     * @see {@link Axis}
87     *
88     * @function Highcharts.Axis#init
89     *
90     * @param {Highcharts.Chart} chart
91     * The Chart instance to apply the axis on.
92     *
93     * @param {AxisOptions} userOptions
94     * Axis options.
95     *
96     * @emits Highcharts.Axis#event:afterInit
97     * @emits Highcharts.Axis#event:init
98     */
99    init(chart, userOptions, coll = this.coll) {
100        const isXAxis = coll === 'xAxis', axis = this, horiz = axis.isZAxis || (chart.inverted ? !isXAxis : isXAxis);
101        /**
102         * The Chart that the axis belongs to.
103         *
104         * @name Highcharts.Axis#chart
105         * @type {Highcharts.Chart}
106         */
107        axis.chart = chart;
108        /**
109         * Whether the axis is horizontal.
110         *
111         * @name Highcharts.Axis#horiz
112         * @type {boolean|undefined}
113         */
114        axis.horiz = horiz;
115        /**
116         * Whether the axis is the x-axis.
117         *
118         * @name Highcharts.Axis#isXAxis
119         * @type {boolean|undefined}
120         */
121        axis.isXAxis = isXAxis;
122        /**
123         * The collection where the axis belongs, for example `xAxis`, `yAxis`
124         * or `colorAxis`. Corresponds to properties on Chart, for example
125         * {@link Chart.xAxis}.
126         *
127         * @name Highcharts.Axis#coll
128         * @type {string}
129         */
130        axis.coll = coll;
131        fireEvent(this, 'init', { userOptions: userOptions });
132        // Needed in setOptions
133        axis.opposite = pick(userOptions.opposite, axis.opposite);
134        /**
135         * The side on which the axis is rendered. 0 is top, 1 is right, 2
136         * is bottom and 3 is left.
137         *
138         * @name Highcharts.Axis#side
139         * @type {number}
140         */
141        axis.side = pick(userOptions.side, axis.side, (horiz ?
142            (axis.opposite ? 0 : 2) : // Top : bottom
143            (axis.opposite ? 1 : 3)) // Right : left
144        );
145        /**
146         * Current options for the axis after merge of defaults and user's
147         * options.
148         *
149         * @name Highcharts.Axis#options
150         * @type {Highcharts.AxisOptions}
151         */
152        axis.setOptions(userOptions);
153        const options = axis.options, labelsOptions = options.labels;
154        // Set the type and fire an event
155        axis.type ?? (axis.type = options.type || 'linear');
156        axis.uniqueNames ?? (axis.uniqueNames = options.uniqueNames ?? true);
157        fireEvent(axis, 'afterSetType');
158        /**
159         * User's options for this axis without defaults.
160         *
161         * @name Highcharts.Axis#userOptions
162         * @type {Highcharts.AxisOptions}
163         */
164        axis.userOptions = userOptions;
165        axis.minPixelPadding = 0;
166        /**
167         * Whether the axis is reversed. Based on the `axis.reversed`,
168         * option, but inverted charts have reversed xAxis by default.
169         *
170         * @name Highcharts.Axis#reversed
171         * @type {boolean}
172         */
173        axis.reversed = pick(options.reversed, axis.reversed);
174        axis.visible = options.visible;
175        axis.zoomEnabled = options.zoomEnabled;
176        // Initial categories
177        axis.hasNames = this.type === 'category' || options.categories === true;
178        /**
179         * If categories are present for the axis, names are used instead of
180         * numbers for that axis.
181         *
182         * Since Highcharts 3.0, categories can also be extracted by giving each
183         * point a name and setting axis type to `category`. However, if you
184         * have multiple series, best practice remains defining the `categories`
185         * array.
186         *
187         * @see [xAxis.categories](/highcharts/xAxis.categories)
188         *
189         * @name Highcharts.Axis#categories
190         * @type {Array<string>}
191         * @readonly
192         */
193        axis.categories = (isArray(options.categories) && options.categories) ||
194            (axis.hasNames ? [] : void 0);
195        if (!axis.names) { // Preserve on update (#3830)
196            axis.names = [];
197            axis.names.keys = {};
198        }
199        // Placeholder for plotlines and plotbands groups
200        axis.plotLinesAndBandsGroups = {};
201        // Shorthand types
202        axis.positiveValuesOnly = !!axis.logarithmic;
203        // Flag, if axis is linked to another axis
204        axis.isLinked = defined(options.linkedTo);
205        /**
206         * List of major ticks mapped by position on axis.
207         *
208         * @see {@link Highcharts.Tick}
209         *
210         * @name Highcharts.Axis#ticks
211         * @type {Highcharts.Dictionary<Highcharts.Tick>}
212         */
213        axis.ticks = {};
214        axis.labelEdge = [];
215        /**
216         * List of minor ticks mapped by position on the axis.
217         *
218         * @see {@link Highcharts.Tick}
219         *
220         * @name Highcharts.Axis#minorTicks
221         * @type {Highcharts.Dictionary<Highcharts.Tick>}
222         */
223        axis.minorTicks = {};
224        // List of plotLines/Bands
225        axis.plotLinesAndBands = [];
226        // Alternate bands
227        axis.alternateBands = {};
228        /**
229         * The length of the axis in terms of pixels.
230         *
231         * @name Highcharts.Axis#len
232         * @type {number}
233         */
234        axis.len ?? (axis.len = 0);
235        axis.minRange = axis.userMinRange = options.minRange || options.maxZoom;
236        axis.range = options.range;
237        axis.offset = options.offset || 0;
238        /**
239         * The maximum value of the axis. In a logarithmic axis, this is the
240         * logarithm of the real value, and the real value can be obtained from
241         * {@link Axis#getExtremes}.
242         *
243         * @name Highcharts.Axis#max
244         * @type {number|undefined}
245         */
246        axis.max = void 0;
247        /**
248         * The minimum value of the axis. In a logarithmic axis, this is the
249         * logarithm of the real value, and the real value can be obtained from
250         * {@link Axis#getExtremes}.
251         *
252         * @name Highcharts.Axis#min
253         * @type {number|undefined}
254         */
255        axis.min = void 0;
256        /**
257         * The processed crosshair options.
258         *
259         * @name Highcharts.Axis#crosshair
260         * @type {boolean|Highcharts.AxisCrosshairOptions}
261         */
262        const crosshair = pick(options.crosshair, splat(chart.options.tooltip.crosshairs)[isXAxis ? 0 : 1]);
263        axis.crosshair = crosshair === true ? {} : crosshair;
264        // Register. Don't add it again on Axis.update().
265        if (chart.axes.indexOf(axis) === -1) { //
266            if (isXAxis) { // #2713
267                chart.axes.splice(chart.xAxis.length, 0, axis);
268            }
269            else {
270                chart.axes.push(axis);
271            }
272            insertItem(this, chart[this.coll]);
273        }
274        chart.orderItems(axis.coll);
275        /**
276         * All series associated to the axis.
277         *
278         * @name Highcharts.Axis#series
279         * @type {Array<Highcharts.Series>}
280         */
281        axis.series = axis.series || []; // Populated by Series
282        // Reversed axis
283        if (chart.inverted &&
284            !axis.isZAxis &&
285            isXAxis &&
286            !defined(axis.reversed)) {
287            axis.reversed = true;
288        }
289        axis.labelRotation = isNumber(labelsOptions.rotation) ?
290            labelsOptions.rotation :
291            void 0;
292        // Register event listeners
293        registerEventOptions(axis, options);
294        fireEvent(this, 'afterInit');
295    }
296    /**
297     * Merge and set options.
298     *
299     * @private
300     * @function Highcharts.Axis#setOptions
301     *
302     * @param {Highcharts.AxisOptions} userOptions
303     * Axis options.
304     *
305     * @emits Highcharts.Axis#event:afterSetOptions
306     */
307    setOptions(userOptions) {
308        const sideSpecific = this.horiz ?
309            // Top and bottom axis defaults
310            {
311                labels: {
312                    autoRotation: [-45],
313                    padding: 3
314                },
315                margin: 15
316            } :
317            // Left and right axis, title rotated 90 or 270 degrees
318            // respectively
319            {
320                labels: {
321                    padding: 1
322                },
323                title: {
324                    rotation: 90 * this.side
325                }
326            };
327        this.options = merge(sideSpecific, defaultOptions[this.coll], userOptions);
328        fireEvent(this, 'afterSetOptions', { userOptions });
329    }
330    /**
331     * The default label formatter. The context is a special config object for
332     * the label. In apps, use the
333     * [labels.formatter](https://api.highcharts.com/highcharts/xAxis.labels.formatter)
334     * instead, except when a modification is needed.
335     *
336     * @function Highcharts.Axis#defaultLabelFormatter
337     *
338     * @param {Highcharts.AxisLabelsFormatterContextObject} this
339     * Formatter context of axis label.
340     *
341     * @param {Highcharts.AxisLabelsFormatterContextObject} [ctx]
342     * Formatter context of axis label.
343     *
344     * @return {string}
345     * The formatted label content.
346     */
347    defaultLabelFormatter() {
348        const axis = this.axis, chart = this.chart, { numberFormatter } = chart, value = isNumber(this.value) ? this.value : NaN, time = axis.chart.time, categories = axis.categories, dateTimeLabelFormat = this.dateTimeLabelFormat, lang = defaultOptions.lang, numericSymbol
348s = lang.numericSymbols, numSymMagnitude = lang.numericSymbolMagnitude || 1000, 
349        // Make sure the same symbol is added for all labels on a linear
350        // axis
351        numericSymbolDetector = axis.logarithmic ?
352            Math.abs(value) :
353            axis.tickInterval;
354        let i = numericSymbols && numericSymbols.length, multi, ret;
355        if (categories) {
356            ret = `${this.value}`;
357        }
358        else if (dateTimeLabelFormat) { // Datetime axis
359            ret = time.dateFormat(dateTimeLabelFormat, value, true);
360        }
361        else if (i &&
362            numericSymbols &&
363            numericSymbolDetector >= 1000) {
364            // Decide whether we should add a numeric symbol like k (thousands)
365            // or M (millions). If we are to enable this in tooltip or other
366            // places as well, we can move this logic to the numberFormatter and
367            // enable it by a parameter.
368            while (i-- && typeof ret === 'undefined') {
369                multi = Math.pow(numSymMagnitude, i + 1);
370                if (
371                // Only accept a numeric symbol when the distance is more
372                // than a full unit. So for example if the symbol is k, we
373                // don't accept numbers like 0.5k.
374                numericSymbolDetector >= multi &&
375                    // Accept one decimal before the symbol. Accepts 0.5k but
376                    // not 0.25k. How does this work with the previous?
377                    (value * 10) % multi === 0 &&
378                    numericSymbols[i] !== null &&
379                    value !== 0) { // #5480
380                    ret = numberFormatter(value / multi, -1) + numericSymbols[i];
381                }
382            }
383        }
384        if (typeof ret === 'undefined') {
385            if (Math.abs(value) >= 10000) { // Add thousands separators
386                ret = numberFormatter(value, -1);
387            }
388            else { // Small numbers
389                ret = numberFormatter(value, -1, void 0, ''); // #2466
390            }
391        }
392        return ret;
393    }
394    /**
395     * Get the minimum and maximum for the series of each axis. The function
396     * analyzes the axis series and updates `this.dataMin` and `this.dataMax`.
397     *
398     * @private
399     * @function Highcharts.Axis#getSeriesExtremes
400     *
401     * @emits Highcharts.Axis#event:afterGetSeriesExtremes
402     * @emits Highcharts.Axis#event:getSeriesExtremes
403     */
404    getSeriesExtremes() {
405        const axis = this;
406        let xExtremes;
407        fireEvent(this, 'getSeriesExtremes', null, function () {
408            axis.hasVisibleSeries = false;
409            // Reset properties in case we're redrawing (#3353)
410            axis.dataMin = axis.dataMax = axis.threshold = void 0;
411            axis.softThreshold = !axis.isXAxis;
412            // Loop through this axis' series
413            axis.series.forEach((series) => {
414                if (series.reserveSpace()) {
415                    const seriesOptions = series.options;
416                    let xData, threshold = seriesOptions.threshold, seriesDataMin, seriesDataMax;
417                    axis.hasVisibleSeries = true;
418                    // Validate threshold in logarithmic axes
419                    if (axis.positiveValuesOnly && (threshold || 0) <= 0) {
420                        threshold = void 0;
421                    }
422                    // Get dataMin and dataMax for X axes
423                    if (axis.isXAxis) {
424                        xData = series.getColumn('x');
425                        if (xData.length) {
426                            xData = axis.logarithmic ?
427                                xData.filter((x) => x > 0) :
428                                xData;
429                            xExtremes = series.getXExtremes(xData);
430                            // If xData contains values which is not numbers,
431                            // then filter them out. To prevent performance hit,
432                            // we only do this after we have already found
433                            // seriesDataMin because in most cases all data is
434                            // valid. #5234.
435                            seriesDataMin = xExtremes.min;
436                            seriesDataMax = xExtremes.max;
437                            if (!isNumber(seriesDataMin) &&
438                                // #5010:
vendor: 6,362 bytes, lines 439-588
439                                !(seriesDataMin instanceof Date)) {
440                                xData = xData.filter(isNumber);
441                                xExtremes = series.getXExtremes(xData);
442                                // Do it again with valid data
443                                seriesDataMin = xExtremes.min;
444                                seriesDataMax = xExtremes.max;
445                            }
446                            if (xData.length) {
447                                axis.dataMin = Math.min(pick(axis.dataMin, seriesDataMin), seriesDataMin);
448                                axis.dataMax = Math.max(pick(axis.dataMax, seriesDataMax), seriesDataMax);
449                            }
450                        }
451                        // Get dataMin and dataMax for Y axes, as well as handle
452                        // stacking and processed data
453                    }
454                    else {
455                        // Get this particular series extremes
456                        const dataExtremes = series.applyExtremes();
457                        // Get the dataMin and dataMax so far. If percentage is
458                        // used, the min and max are always 0 and 100. If
459                        // seriesDataMin and seriesDataMax is null, then series
460                        // doesn't have active y data, we continue with nulls
461                        if (isNumber(dataExtremes.dataMin)) {
462                            seriesDataMin = dataExtremes.dataMin;
463                            axis.dataMin = Math.min(pick(axis.dataMin, seriesDataMin), seriesDataMin);
464                        }
465                        if (isNumber(dataExtremes.dataMax)) {
466                            seriesDataMax = dataExtremes.dataMax;
467                            axis.dataMax = Math.max(pick(axis.dataMax, seriesDataMax), seriesDataMax);
468                        }
469                        // Adjust to threshold
470                        if (defined(threshold)) {
471                            axis.threshold = threshold;
472                        }
473                        // If any series has a hard threshold, it takes
474                        // precedence
475                        if (!seriesOptions.softThreshold ||
476                            axis.positiveValuesOnly) {
477                            axis.softThreshold = false;
478                        }
479                    }
480                }
481            });
482        });
483        fireEvent(this, 'afterGetSeriesExtremes');
484    }
485    /**
486     * Translate from axis value to pixel position on the chart, or back. Use
487     * the `toPixels` and `toValue` functions in applications.
488     *
489     * @private
490     * @function Highcharts.Axis#translate
491     */
492    translate(val, backwards, cvsCoord, old, handleLog, pointPlacement) {
493        const axis = (this.linkedParent || this), // #1417
494        localMin = (old && axis.old ? axis.old.min : axis.min);
495        if (!isNumber(localMin)) {
496            return NaN;
497        }
498        const minPixelPadding = axis.minPixelPadding, doPostTranslate = (axis.isOrdinal ||
499            axis.brokenAxis?.hasBreaks ||
500            (axis.logarithmic && handleLog)) && axis.lin2val;
501        let sign = 1, cvsOffset = 0, localA = old && axis.old ? axis.old.transA : axis.transA, returnValue = 0;
502        if (!localA) {
503            localA = axis.transA;
504        }
505        // In vertical axes, the canvas coordinates start from 0 at the top like
506        // in SVG.
507        if (cvsCoord) {
508            sign *= -1; // Canvas coordinates inverts the value
509            cvsOffset = axis.len;
510        }
511        // Handle reversed axis
512        if (axis.reversed) {
513            sign *= -1;
514            cvsOffset -= sign * (axis.sector || axis.len);
515        }
516        // From pixels to value
517        if (backwards) { // Reverse translation
518            val = val * sign + cvsOffset;
519            val -= minPixelPadding;
520            // From chart pixel to value:
521            returnValue = val / localA + localMin;
522            if (doPostTranslate) { // Log, ordinal and broken axis
523                returnValue = axis.lin2val(returnValue);
524            }
525            // From value to pixels
526        }
527        else {
528            if (doPostTranslate) { // Log, ordinal and broken axis
529                val = axis.val2lin(val);
530            }
531            const value = sign * (val - localMin) * localA;
532            returnValue = value +
533                cvsOffset +
534                (sign * minPixelPadding) +
535                (isNumber(pointPlacement) ? localA * pointPlacement : 0);
536            if (!axis.isRadial) {
537                returnValue = correctFloat(returnValue);
538            }
539        }
540        return returnValue;
541    }
542    /**
543     * Translate a value in terms of axis units into pixels within the chart.
544     *
545     * @function Highcharts.Axis#toPixels
546     *
547     * @param {number|string} value
548     * A value in terms of axis units. For datetime axes, a timestamp or
549     * date/time string is accepted.
550     *
551     * @param {boolean} [paneCoordinates=false]
552     * Whether to return the pixel coordinate relative to the chart or just the
553     * axis/pane itself.
554     *
555     * @return {number}
556     * Pixel position of the value on the chart or axis.
557     */
558    toPixels(value, paneCoordinates) {
559        return this.translate(this.chart?.time.parse(value) ?? NaN, false, !this.horiz, void 0, true) + (paneCoordinates ? 0 : this.pos);
560    }
561    /**
562     * Translate a pixel position along the axis to a value in terms of axis
563     * units.
564     *
565     * @function Highcharts.Axis#toValue
566     *
567     * @param {number} pixel
568     * The pixel value coordinate.
569     *
570     * @param {boolean} [paneCoordinates=false]
571     * Whether the input pixel is relative to the chart or just the axis/pane
572     * itself.
573     *
574     * @return {number}
575     * The axis value.
576     */
577    toValue(pixel, paneCoordinates) {
578        return this.translate(pixel - (paneCoordinates ? 0 : this.pos), true, !this.horiz, void 0, true);
579    }
580    /**
581     * Create the path for a plot line that goes from the given value on
582     * this axis, across the plot to the opposite side. Also used internally for
583     * grid lines and crosshairs.
584     *
585     * @function Highcharts.Axis#getPlotLinePath
586     *
587     * @param {Highcharts.AxisPlotLinePathOptionsObject} options
588     * Options for the path.
vendor: 4,445 bytes, lines 589-694
589     *
590     * @return {Highcharts.SVGPathArray|null}
591     * The SVG path definition for the plot line.
592     */
593    getPlotLinePath(options) {
594        const axis = this, chart = axis.chart, axisLeft = axis.left, axisTop = axis.top, old = options.old, value = options.value, lineWidth = options.lineWidth, cHeight = (old && chart.oldChartHeight) || chart.chartHeight, cWidth = (old && chart.oldChartWidth) || chart.chartWidth, transB = axis.transB;
595        let translatedValue = options.translatedValue, force = options.force, x1, y1, x2, y2, skip;
596        // eslint-disable-next-line valid-jsdoc
597        /**
598         * Check if x is between a and b. If not, either move to a/b
599         * or skip, depending on the force parameter.
600         * @private
601         */
602        function between(x, a, b) {
603            if (force !== 'pass' && (x < a || x > b)) {
604                if (force) {
605                    x = clamp(x, a, b);
606                }
607                else {
608                    skip = true;
609                }
610            }
611            return x;
612        }
613        const evt = {
614            value,
615            lineWidth,
616            old,
617            force,
618            acrossPanes: options.acrossPanes,
619            translatedValue
620        };
621        fireEvent(this, 'getPlotLinePath', evt, function (e) {
622            translatedValue = pick(translatedValue, axis.translate(value, void 0, void 0, old));
623            // Keep the translated value within sane bounds, and avoid Infinity
624            // to fail the isNumber test (#7709).
625            translatedValue = clamp(translatedValue, -1e9, 1e9);
626            x1 = x2 = translatedValue + transB;
627            y1 = y2 = cHeight - translatedValue - transB;
628            if (!isNumber(translatedValue)) { // No min or max
629                skip = true;
630                force = false; // #7175, don't force it when path is invalid
631            }
632            else if (axis.horiz) {
633                y1 = axisTop;
634                y2 = cHeight - axis.bottom + (axis.options.isInternal ?
635                    0 :
636                    (chart.scrollablePixelsY || 0)); // #20354, scrollablePixelsY shouldn't be used for navigator
637                x1 = x2 = between(x1, axisLeft, axisLeft + axis.width);
638            }
639            else {
640                x1 = axisLeft;
641                x2 = cWidth - axis.right + (chart.scrollablePixelsX || 0);
642                y1 = y2 = between(y1, axisTop, axisTop + axis.height);
643            }
644            e.path = skip && !force ?
645                void 0 :
646                chart.renderer.crispLine([['M', x1, y1], ['L', x2, y2]], lineWidth || 1);
647        });
648        return evt.path;
649    }
650    /**
651     * Internal function to get the tick positions of a linear axis to round
652     * values like whole tens or every five.
653     *
654     * @function Highcharts.Axis#getLinearTickPositions
655     *
656     * @param {number} tickInterval
657     * The normalized tick interval.
658     *
659     * @param {number} min
660     * Axis minimum.
661     *
662     * @param {number} max
663     * Axis maximum.
664     *
665     * @return {Array<number>}
666     * An array of axis values where ticks should be placed.
667     */
668    getLinearTickPositions(tickInterval, min, max) {
669        const roundedMin = correctFloat(Math.floor(min / tickInterval) * tickInterval), roundedMax = correctFloat(Math.ceil(max / tickInterval) * tickInterval), tickPositions = [];
670        let pos, lastPos, precision;
671        // When the precision is higher than what we filter out in
672        // correctFloat, skip it (#6183).
673        if (correctFloat(roundedMin + tickInterval) === roundedMin) {
674            precision = 20;
675        }
676        // For single points, add a tick regardless of the relative position
677        // (#2662, #6274)
678        if (this.single) {
679            return [min];
680        }
681        // Populate the intermediate values
682        pos = roundedMin;
683        while (pos <= roundedMax) {
684            // Place the tick on the rounded value
685            tickPositions.push(pos);
686            // Always add the raw tickInterval, not the corrected one.
687            pos = correctFloat(pos + tickInterval, precision);
688            // If the interval is not big enough in the current min - max range
689            // to actually increase the loop variable, we need to break out to
690            // prevent endless loop. Issue #619
691            if (pos === lastPos) {
692                break;
693            }
694            // Record the last value
vendor: 4,902 bytes, lines 695-802
695            lastPos = pos;
696        }
697        return tickPositions;
698    }
699    /**
700     * Resolve the new minorTicks/minorTickInterval options into the legacy
701     * loosely typed minorTickInterval option.
702     *
703     * @function Highcharts.Axis#getMinorTickInterval
704     *
705     * @return {number|"auto"|null}
706     * Legacy option
707     */
708    getMinorTickInterval() {
709        const { minorTicks, minorTickInterval } = this.options;
710        if (minorTicks === true) {
711            return pick(minorTickInterval, 'auto');
712        }
713        if (minorTicks === false) {
714            return;
715        }
716        return minorTickInterval;
717    }
718    /**
719     * Internal function to return the minor tick positions. For logarithmic
720     * axes, the same logic as for major ticks is reused.
721     *
722     * @function Highcharts.Axis#getMinorTickPositions
723     *
724     * @return {Array<number>}
725     * An array of axis values where ticks should be placed.
726     */
727    getMinorTickPositions() {
728        const axis = this, options = axis.options, tickPositions = axis.tickPositions, minorTickInterval = axis.minorTickInterval, pointRangePadding = axis.pointRangePadding || 0, min = (axis.min || 0) - pointRangePadding, // #1498
729        max = (axis.max || 0) + pointRangePadding, // #1498
730        range = axis.brokenAxis?.hasBreaks ?
731            axis.brokenAxis.unitLength : max - min;
732        let minorTickPositions = [], pos;
733        // If minor ticks get too dense, they are hard to read, and may cause
734        // long running script. So we don't draw them.
735        if (range && range / minorTickInterval < axis.len / 3) { // #3875
736            const logarithmic = axis.logarithmic;
737            if (logarithmic) {
738                // For each interval in the major ticks, compute the minor ticks
739                // separately.
740                this.paddedTicks.forEach(function (_pos, i, paddedTicks) {
741                    if (i) {
742                        minorTickPositions.push.apply(minorTickPositions, logarithmic.getLogTickPositions(minorTickInterval, paddedTicks[i - 1], paddedTicks[i], true));
743                    }
744                });
745            }
746            else if (axis.dateTime &&
747                this.getMinorTickInterval() === 'auto') { // #1314
748                minorTickPositions = minorTickPositions.concat(axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(minorTickInterval), min, max, options.startOfWeek));
749            }
750            else {
751                for (pos = min + (tickPositions[0] - min) % minorTickInterval; pos <= max; pos += minorTickInterval) {
752                    // Very, very, tight grid lines (#5771)
753                    if (pos === minorTickPositions[0]) {
754                        break;
755                    }
756                    minorTickPositions.push(pos);
757                }
758            }
759        }
760        if (minorTickPositions.length !== 0) {
761            axis.trimTicks(minorTickPositions); // #3652 #3743 #1498 #6330
762        }
763        return minorTickPositions;
764    }
765    /**
766     * Adjust the min and max for the minimum range. Keep in mind that the
767     * series data is not yet processed, so we don't have information on data
768     * cropping and grouping, or updated `axis.pointRange` or
769     * `series.pointRange`. The data can't be processed until we have finally
770     * established min and max.
771     *
772     * @private
773     * @function Highcharts.Axis#adjustForMinRange
774     */
775    adjustForMinRange() {
776        const axis = this, options = axis.options, logarithmic = axis.logarithmic, time = axis.chart.time;
777        let { max, min, minRange } = axis, zoomOffset, spaceAvailable, closestDataRange, minArgs, maxArgs;
778        // Set the automatic minimum range based on the closest point distance
779        if (axis.isXAxis &&
780            typeof minRange === 'undefined' &&
781            !logarithmic) {
782            if (defined(options.min) ||
783                defined(options.max) ||
784                defined(options.floor) ||
785                defined(options.ceiling)) {
786                // Setting it to null, as opposed to undefined, signals we don't
787                // run this block again as per the condition above.
788                minRange = null;
789            }
790            else {
791                // Find the closest distance between raw data points, as opposed
792                // to closestPointRange that applies to processed points
793                // (cropped and grouped)
794                closestDataRange = getClosestDistance(axis.series.map((s) => {
795                    const xData = s.getColumn('x');
796                    // If xIncrement, we only need to measure the two first
797                    // points to get the distance. Saves processing time.
798                    return s.xIncrement ? xData.slice(0, 2) : xData;
799                })) || 0;
800                minRange = Math.min(closestDataRange * 5, axis.dataMax - axis.dataMin);
801            }
802        }
803        // If minRange is exceeded, adjust
804        if (isNumber(max) &&
805            isNumber(min) &&
806            isNumber(minRange) &&
807            max - min < minRange) {
808            spaceAvailable =
809                axis.dataMax - axis.dataMin >=
810                    minRange;
811            zoomOffset = (minRange - max + min) / 2;
812            // If min and max options have been set, don't go beyond it
813            minArgs = [
814                min - zoomOffset,
815                time.parse(options.min) ?? (min - zoomOffset)
816            ];
817            // If space is available, stay within the data range
818            if (spaceAvailable) {
819                minArgs[2] = logarithmic ?
820                    logarithmic.log2lin(axis.dataMin) :
821                    axis.dataMin;
822            }
823            min = arrayMax(minArgs);
824            maxArgs = [
825                min + minRange,
826                time.parse(options.max) ?? (min + minRange)
827            ];
828            // If space is available, stay within the data range
829            if (spaceAvailable) {
830                maxArgs[2] = logarithmic ?
831                    logarithmic.log2lin(axis.dataMax) :
832                    axis.dataMax;
833            }
834            max = arrayMin(maxArgs);
835            // Now if the max is adjusted, adjust the min back
836            if (max - min < minRange) {
837                minArgs[0] = max - minRange;
838                minArgs[1] = time.parse(options.min) ?? (max - minRange);
839                min = arrayMax(minArgs);
840            }
841        }
842        // Record modified extremes
843        axis.minRange = minRange;
844        axis.min = min;
845        axis.max = max;
846    }
847    /**
848     * Find the closestPointRange across all series, including the single data
849     * series.
850     *
851     * @private
852     * @function Highcharts.Axis#getClosest
853     */
854    getClosest() {
855        let closestSingleDistance, closestDistance;
856        if (this.categories) {
857            closestDistance = 1;
858        }
859        else {
860            const singleXs = [];
861            this.series.forEach(function (series) {
862                const seriesClosest = series.closestPointRange, xData = series.getColumn('x');
863                if (xData.length === 1) {
864                    singleXs.push(xData[0]);
865                }
866                else if (series.sorted &&
867                    defined(seriesClosest) &&
868                    series.reserveSpace()) {
869                    closestDistance = defined(closestDistance) ?
870                        Math.min(closestDistance, seriesClosest) :
871                        seriesClosest;
872                }
873            });
874            if (singleXs.length) {
875                singleXs.sort((a, b) => a - b);
876                closestSingleDistance = getClosestDistance([singleXs]);
877            }
878        }
879        if (closestSingleDistance && closestDistance) {
880            return Math.min(closestSingleDistance, closestDistance);
881        }
882        return closestSingleDistance || closestDistance;
883    }
884    /**
885     * When a point name is given and no x, search for the name in the existing
886     * categories, or if categories aren't provided, search names or create a
887     * new category (#2522).
888     *
889     * @private
890     * @function Highcharts.Axis#nameToX
891     *
892     * @param {Highcharts.Point} point
893     * The point to inspect.
894     *
895     * @return {number}
896     * The X value that the point is given.
897     */
898    nameToX(point) {
899        const explicitCategories = isArray(this.options.categories), names = explicitCategories ? this.categories : this.names;
900        let nameX = point.options.x, x;
901        point.series.requireSorting = false;
902        if (!defined(nameX)) {
903            nameX = this.uniqueNames && names ?
904                (explicitCategories ?
905                    names.indexOf(point.name) :
906                    pick(names.keys[point.name], -1)) :
907                point.series.autoIncrement();
908        }
909        if (nameX === -1) { // Not found in current categories
910            if (!explicitCategories && names) {
911                x = names.length;
912            }
913        }
914        else if (isNumber(nameX)) {
915            x = nameX;
916        }
917        // Write the last point's name to the names array
918        if (typeof x !== 'undefined') {
919            this.names[x] = point.name;
920            // Backwards mapping is much faster than array searching (#7725)
921            this.names.keys[point.name] = x;
922        }
923        else if (point.x) {
924            x = point.x; // #17438
925        }
926        return x;
927    }
928    /**
929     * When changes have been done to series data, update the axis.names.
930     *
931     * @private
932     * @function Highcharts.Axis#updateNames
933     */
934    updateNames() {
935        const axis = this, names = this.names, i = names.length;
936        if (i > 0) {
937            Object.keys(names.keys).forEach(function (key) {
938                delete (names.keys)[key];
939            });
940            names.length = 0;
941            this.minRange = this.userMinRange; // Reset
942            (this.series || []).forEach((series) => {
943                // Reset incrementer (#5928)
944                series.xIncrement = null;
945                // When adding a series, points are not yet generated
946                if (!series.points || series.isDirtyData) {
947                    // When we're updating the series with data that is longer
948                    // than it was, and cropThreshold is passed, we need to make
949                    // sure that the axis.max is increased _before_ running the
950                    // premature processData. Otherwise this early iteration of
951                    // processData will crop the points to axis.max, and the
952                    // names array will be too short (#5857).
953                    axis.max = Math.max(axis.max || 0, series.dataTable.rowCount - 1);
954                    series.processData();
955                    series.generatePoints();
956                }
957                const xData = series.getColumn('x').slice();
958                series.data.forEach((point, i) => {
959                    let x = xData[i];
960                    if (point?.options &&
961                        typeof point.name !== 'undefined' // #9562
962                    ) {
963                        x = axis.nameToX(point);
964                        if (typeof x !== 'undefined' && x !== point.x) {
965                            xData[i] = point.x = x;
966                        }
967                    }
968                });
969                series.dataTable.setColumn('x', xData);
970            });
971        }
972    }
973    /**
974     * Update translation information.
975     *
976     * @private
977     * @function Highcharts.Axis#setAxisTranslation
978     *
979     * @emits Highcharts.Axis#event:afterSetAxisTranslation
980     */
981    setAxisTranslation() {
982        const axis = this, range = axis.max - axis.min, linkedParent = axis.linkedParent, hasCategories = !!axis.categories, isXAxis = axis.isXAxis;
983        let pointRange = axis.axisPointRange || 0, closestPointRange, minPointOffset = 0, pointRangePadding = 0, ordinalCorrection, transA = axis.transA;
984        // Adjust translation for padding. Y axis with categories need to go
985        // through the same (#1784).
986        if (isXAxis || hasCategories || pointRange) {
987            // Get the closest points
988            closestPointRange = axis.getClosest();
989            if (linkedParent) {
990                minPointOffset = linkedParent.minPointOffset;
991                pointRangePadding = linkedParent.pointRangePadding;
992            }
993            else {
994                axis.series.forEach(function (series) {
995                    const seriesPointRange = hasCategories ?
996                        1 :
997                        (isXAxis ?
998                            pick(series.options.pointRange, closestPointRange, 0) :
999                            (axis.axisPointRange || 0)), // #2806
1000                    pointPlacement = series.options.pointPlacement;
1001                    pointRange = Math.max(pointRange, seriesPointRange);
1002                    if (!axis.single || hasCategories) {
1003                        // TODO: series should internally set x- and y-
1004                        // pointPlacement to simplify this logic.
1005                        const isPointPlacementAxis = series.is('xrange') ?
1006                            !isXAxis :
1007                            isXAxis;
1008                        // The `minPointOffset` is the value padding to the left
1009                        // of the axis in order to make room for points with a
1010                        // pointRange, typically columns, or line/scatter points
1011                        // on a category axis. When the `pointPlacement` option
1012                        // is 'between' or 'on', this padding does not apply.
1013                        minPointOffset = Math.max(minPointOffset, isPointPlacementAxis && isString(pointPlacement) ?
1014                            0 :
1015                            seriesPointRange / 2);
1016                        // Determine the total padding needed to the length of
1017                        // the axis to make room for the pointRange. If the
1018                        // series' pointPlacement is 'on', no padding is added.
1019                        pointRangePadding = Math.max(pointRangePadding, isPointPlacementAxis && pointPlacement === 'on' ?
1020                            0 :
1021                            seriesPointRange);
1022                    }
1023                });
1024            }
1025            // Record minPointOffset and pointRangePadding
1026            ordinalCorrection = (axis.ordinal && axis.ordinal.slope && closestPointRange) ?
1027                axis.ordinal.slope / closestPointRange :
1028                1; // #988, #1853
1029            axis.minPointOffset = minPointOffset =
1030                minPointOffset * ordinalCorrection;
1031            axis.pointRangePadding =
1032                pointRangePadding = pointRangePadding * ordinalCorrection;
1033            // The `pointRange` is the width reserved for each point, like in a
1034            // column chart
1035            axis.pointRange = Math.min(pointRange, axis.single && hasCategories ? 1 : range);
1036            // The `closestPointRange` is the closest distance between points.
1037            // In columns it is mostly equal to pointRange, but in lines
1038            // pointRange is 0 while closestPointRange is some other value
1039            if (isXAxis && closestPointRange) {
1040                axis.closestPointRange = closestPointRange;
1041            }
1042        }
1043        // Secondary values
1044        axis.translationSlope = axis.transA = transA =
1045            axis.staticScale ||
1046                axis.len / ((range + pointRangePadding) || 1);
1047        // Translation addend
1048        axis.transB = axis.horiz ? axis.left : axis.bottom;
1049        axis.minPixelPadding = transA * minPointOffset;
1050        fireEvent(this, 'afterSetAxisTranslation');
1051    }
1052    /**
1053     * @private
1054     * @function Highcharts.Axis#minFromRange
1055     */
1056    minFromRange() {
1057        const { max, min } = this;
1058        return isNumber(max) && isNumber(min) && max - min || void 0;
1059    }
1060    /**
1061     * Set the tick positions to round values and optionally extend the extremes
1062     * to the nearest tick.
1063     *
1064     * @private
1065     * @function Highcharts.Axis#setTickInterval
1066     *
1067     * @param {boolean} secondPass
1068     * TO-DO: parameter description
1069     *
1070     * @emits Highcharts.Axis#event:foundExtremes
1071     */
1072    setTickInterval(secondPass) {
1073        const axis = this, { categories, chart, dataMax, dataMin, dateTime, isXAxis, logarithmic, options, softThreshold } = axis, time = chart.time, threshold = isNumber(axis.threshold) ? axis.threshold : void 0, minRange = axis.minRange || 0, { ceiling, floor, linkedTo, softMax, softMin } = options, linkedParent = isNumber(linkedTo) && chart[axis.coll]?.[linkedTo], tickPixelIntervalOption = options.tickPixelInterval;
1074        let maxPadding = options.maxPadding, minPadding = options.minPadding, range = 0, linkedParentExtremes, 
1075        // Only non-negative tickInterval is valid, #12961
1076        tickIntervalOption = isNumber(options.tickInterval) && options.tickInterval >= 0 ?
1077            options.tickInterval : void 0, thresholdMin, thresholdMax, hardMin, hardMax;
1078        if (!dateTime && !categories && !linkedParent) {
1079            this.getTickAmount();
1080        }
1081        // Min or max set either by zooming/setExtremes or initial options
1082        hardMin = pick(axis.userMin, time.parse(options.min));
1083        hardMax = pick(axis.userMax, time.parse(options.max));
1084        // Linked axis gets the extremes from the parent axis
1085        if (linkedParent) {
1086            axis.linkedParent = linkedParent;
1087            linkedParentExtremes = linkedParent.getExtremes();
1088            axis.min = pick(linkedParentExtremes.min, linkedParentExtremes.dataMin);
1089            axis.max = pick(linkedParentExtremes.max, linkedParentExtremes.dataMax);
vendor: 6,691 bytes, lines 1090-1241
1090            if (this.type !== linkedParent.type) {
1091                // Can't link axes of different type
1092                error(11, true, chart);
1093            }
1094            // Initial min and max from the extreme data values
1095        }
1096        else {
1097            // Adjust to hard threshold
1098            if (softThreshold &&
1099                defined(threshold) &&
1100                isNumber(dataMax) &&
1101                isNumber(dataMin)) {
1102                if (dataMin >= threshold) {
1103                    thresholdMin = threshold;
1104                    minPadding = 0;
1105                }
1106                else if (dataMax <= threshold) {
1107                    thresholdMax = threshold;
1108                    maxPadding = 0;
1109                }
1110            }
1111            axis.min = pick(hardMin, thresholdMin, dataMin);
1112            axis.max = pick(hardMax, thresholdMax, dataMax);
1113        }
1114        if (isNumber(axis.max) && isNumber(axis.min)) {
1115            if (logarithmic) {
1116                if (axis.positiveValuesOnly &&
1117                    !secondPass &&
1118                    Math.min(axis.min, pick(dataMin, axis.min)) <= 0) { // #978
1119                    // Can't plot negative values on log axis
1120                    error(10, true, chart);
1121                }
1122                // The correctFloat cures #934, float errors on full tens. But
1123                // it was too aggressive for #4360 because of conversion back to
1124                // lin, therefore use precision 15.
1125                axis.min = correctFloat(logarithmic.log2lin(axis.min), 16);
1126                axis.max = correctFloat(logarithmic.log2lin(axis.max), 16);
1127            }
1128            // Handle zoomed range
1129            if (axis.range && isNumber(dataMin)) {
1130                // #618, #6773:
1131                axis.userMin = axis.min = hardMin = Math.max(dataMin, axis.minFromRange() || 0);
1132                axis.userMax = hardMax = axis.max;
1133                axis.range = void 0; // Don't use it when running setExtremes
1134            }
1135        }
1136        // Hook for Highcharts Stock Scroller and bubble axis padding
1137        fireEvent(axis, 'foundExtremes');
1138        // Adjust min and max for the minimum range
1139        axis.adjustForMinRange();
1140        if (isNumber(axis.min) && isNumber(axis.max)) {
1141            // Handle options for floor, ceiling, softMin and softMax (#6359)
1142            if (!isNumber(axis.userMin) &&
1143                isNumber(softMin) &&
1144                softMin < axis.min) {
1145                axis.min = hardMin = softMin; // #6894
1146            }
1147            if (!isNumber(axis.userMax) &&
1148                isNumber(softMax) &&
1149                softMax > axis.max) {
1150                axis.max = hardMax = softMax; // #6894
1151            }
1152            // Pad the values to get clear of the chart's edges. To avoid
1153            // tickInterval taking the padding into account, we do this after
1154            // computing tick interval (#1337).
1155            if (!categories &&
1156                !axis.axisPointRange &&
1157                !axis.stacking?.usePercentage &&
1158                !linkedParent) {
1159                range = axis.max - axis.min;
1160                if (range) {
1161                    if (!defined(hardMin) && minPadding) {
1162                        axis.min -= range * minPadding;
1163                    }
1164                    if (!defined(hardMax) && maxPadding) {
1165                        axis.max += range * maxPadding;
1166                    }
1167                }
1168            }
1169            if (!isNumber(axis.userMin) && isNumber(floor)) {
1170                axis.min = Math.max(axis.min, floor);
1171            }
1172            if (!isNumber(axis.userMax) && isNumber(ceiling)) {
1173                axis.max = Math.min(axis.max, ceiling);
1174            }
1175            // When the threshold is soft, adjust the extreme value only if the
1176            // data extreme and the padded extreme land on either side of the
1177            // threshold. For example, a series of [0, 1, 2, 3] would make the
1178            // yAxis add a tick for -1 because of the default `minPadding` and
1179            // `startOnTick` options. This is prevented by the `softThreshold`
1180            // option.
1181            if (softThreshold &&
1182                isNumber(dataMin) &&
1183                isNumber(dataMax)) {
1184                const numThreshold = threshold || 0;
1185                if (!defined(hardMin) &&
1186                    axis.min < numThreshold &&
1187                    dataMin >= numThreshold) {
1188                    axis.min = options.minRange ?
1189                        Math.min(numThreshold, axis.max - minRange) :
1190                        numThreshold;
1191                }
1192                else if (!defined(hardMax) &&
1193                    axis.max > numThreshold &&
1194                    dataMax <= numThreshold) {
1195                    axis.max = options.minRange ?
1196                        Math.max(numThreshold, axis.min + minRange) :
1197                        numThreshold;
1198                }
1199            }
1200            // If min is bigger than highest, or if max less than lowest value,
1201            // the chart should not render points. (#14417)
1202            if (!chart.polar && axis.min > axis.max) {
1203                if (defined(options.min)) {
1204                    axis.max = axis.min;
1205                }
1206                else if (defined(options.max)) {
1207                    axis.min = axis.max;
1208                }
1209            }
1210            range = axis.max - axis.min;
1211        }
1212        // Get tickInterval
1213        if (axis.min === axis.max ||
1214            !isNumber(axis.min) ||
1215            !isNumber(axis.max)) {
1216            axis.tickInterval = 1;
1217        }
1218        else if (linkedParent &&
1219            !tickIntervalOption &&
1220            tickPixelIntervalOption === linkedParent.options.tickPixelInterval) {
1221            axis.tickInterval = tickIntervalOption = linkedParent.tickInterval;
1222        }
1223        else {
1224            axis.tickInterval = pick(tickIntervalOption, this.tickAmount ?
1225                range / Math.max(this.tickAmount - 1, 1) :
1226                void 0, 
1227            // For categorized axis, 1 is default, for linear axis use
1228            // tickPix
1229            categories ?
1230                1 :
1231                // Don't let it be more than the data range
1232                range * tickPixelIntervalOption /
1233                    Math.max(axis.len, tickPixelIntervalOption));
1234        }
1235        // Now we're finished detecting min and max, crop and group series data.
1236        // This is in turn needed in order to find tick positions in ordinal
1237        // axes.
1238        if (isXAxis && !secondPass) {
1239            const hasExtremesChanged = axis.min !== axis.old?.min ||
1240                axis.max !== axis.old?.max;
1241            // First process all series assigned to that axis.
vendor: 5,927 bytes, lines 1242-1354
1242            axis.series.forEach(function (series) {
1243                // Allows filtering out points outside the plot area.
1244                series.forceCrop = series.forceCropping?.();
1245                series.processData(hasExtremesChanged);
1246            });
1247            // Then apply grouping if needed. The hasExtremesChanged helps to
1248            // decide if the data grouping should be skipped in the further
1249            // calculations #16319.
1250            fireEvent(this, 'postProcessData', { hasExtremesChanged });
1251        }
1252        // Set the translation factor used in translate function
1253        axis.setAxisTranslation();
1254        // Hook for ordinal axes and radial axes
1255        fireEvent(this, 'initialAxisTranslation');
1256        // In column-like charts, don't cramp in more ticks than there are
1257        // points (#1943, #4184)
1258        if (axis.pointRange && !tickIntervalOption) {
1259            axis.tickInterval = Math.max(axis.pointRange, axis.tickInterval);
1260        }
1261        // Before normalizing the tick interval, handle minimum tick interval.
1262        // This applies only if tickInterval is not defined.
1263        const minTickInterval = pick(options.minTickInterval, 
1264        // In datetime axes, don't go below the data interval, except when
1265        // there are scatter-like series involved (#13369).
1266        dateTime &&
1267            !axis.series.some((s) => !s.sorted) ?
1268            axis.closestPointRange : 0);
1269        if (!tickIntervalOption && axis.tickInterval < minTickInterval) {
1270            axis.tickInterval = minTickInterval;
1271        }
1272        // For linear axes, normalize the interval
1273        if (!dateTime && !logarithmic && !tickIntervalOption) {
1274            axis.tickInterval = getNormalizedTickInterval(axis, axis.tickInterval);
1275        }
1276        // Prevent ticks from getting so close that we can't draw the labels
1277        if (!this.tickAmount) {
1278            axis.tickInterval = axis.unsquish();
1279        }
1280        this.setTickPositions();
1281    }
1282    /**
1283     * Now we have computed the normalized tickInterval, get the tick positions.
1284     *
1285     * @private
1286     * @function Highcharts.Axis#setTickPositions
1287     *
1288     * @emits Highcharts.Axis#event:afterSetTickPositions
1289     */
1290    setTickPositions() {
1291        const axis = this, options = this.options, tickPositionsOption = options.tickPositions, tickPositioner = options.tickPositioner, minorTickIntervalOption = this.getMinorTickInterval(), allowEndOnTick = !this.isPanning, startOnTick = allowEndOnTick && options.startOnTick, endOnTick = allowEndOnTick && options.endOnTick;
1292        let tickPositions = [], tickPositionerResult;
1293        // Set the tickmarkOffset
1294        this.tickmarkOffset = (this.categories &&
1295            options.tickmarkPlacement === 'between' &&
1296            this.tickInterval === 1) ? 0.5 : 0; // #3202
1297        // When there is only one point, or all points have the same value on
1298        // this axis, then min and max are equal and tickPositions.length is 0
1299        // or 1. In this case, add some padding in order to center the point,
1300        // but leave it with one tick. #1337.
1301        this.single =
1302            this.min === this.max &&
1303                defined(this.min) &&
1304                !this.tickAmount &&
1305                (
1306                // Data is on integer (#6563)
1307                this.min % 1 === 0 ||
1308                    // Between integers and decimals are not allowed (#6274)
1309                    options.allowDecimals !== false);
1310        /**
1311         * Contains the current positions that are laid out on the axis. The
1312         * positions are numbers in terms of axis values. In a category axis
1313         * they are integers, in a datetime axis they are also integers, but
1314         * designating milliseconds.
1315         *
1316         * This property is read only - for modifying the tick positions, use
1317         * the `tickPositioner` callback or [axis.tickPositions(
1318         * https://api.highcharts.com/highcharts/xAxis.tickPositions) option
1319         * instead.
1320         *
1321         * @name Highcharts.Axis#tickPositions
1322         * @type {Highcharts.AxisTickPositionsArray|undefined}
1323         */
1324        if (tickPositionsOption) {
1325            // Find the tick positions. Work on a copy (#1565)
1326            tickPositions = tickPositionsOption.slice();
1327        }
1328        else if (isNumber(this.min) && isNumber(this.max)) {
1329            // Too many ticks (#6405). Create a friendly warning and provide two
1330            // ticks so at least we can show the data series.
1331            if (!axis.ordinal?.positions &&
1332                ((this.max - this.min) /
1333                    this.tickInterval >
1334                    Math.max(2 * this.len, 200))) {
1335                tickPositions = [this.min, this.max];
1336                error(19, false, this.chart);
1337            }
1338            else if (axis.dateTime) {
1339                tickPositions = axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(this.tickInterval, options.units), this.min, this.max, options.startOfWeek, axis.ordinal?.positions, this.closestPointRange, true);
1340            }
1341            else if (axis.logarithmic) {
1342                tickPositions = axis.logarithmic.getLogTickPositions(this.tickInterval, this.min, this.max);
1343            }
1344            else {
1345                const startingTickInterval = this.tickInterval;
1346                let adjustedTickInterval = startingTickInterval;
1347                while (adjustedTickInterval <= startingTickInterval * 2) {
1348                    tickPositions = this.getLinearTickPositions(this.tickInterval, this.min, this.max);
1349                    // If there are more tick positions than the set tickAmount,
1350                    // increase the tickInterval and continue until it fits.
1351                    // (#17100)
1352                    if (this.tickAmount &&
1353                        tickPositions.length > this.tickAmount) {
1354                        this.tickInterval = getNormalizedTickInterval(this, adju
vendor: 7,230 bytes, lines 1354-1532
1354stedTickInterval *= 1.1);
1355                    }
1356                    else {
1357                        break;
1358                    }
1359                }
1360            }
1361            // Too dense ticks, keep only the first and last (#4477)
1362            if (tickPositions.length > this.len) {
1363                tickPositions = [
1364                    tickPositions[0],
1365                    tickPositions[tickPositions.length - 1]
1366                ];
1367                // Reduce doubled value (#7339)
1368                if (tickPositions[0] === tickPositions[1]) {
1369                    tickPositions.length = 1;
1370                }
1371            }
1372            // Run the tick positioner callback, that allows modifying auto tick
1373            // positions.
1374            if (tickPositioner) {
1375                // Make it available to the positioner
1376                this.tickPositions = tickPositions;
1377                tickPositionerResult = tickPositioner.apply(axis, [this.min, this.max]);
1378                if (tickPositionerResult) {
1379                    tickPositions = tickPositionerResult;
1380                }
1381            }
1382        }
1383        this.tickPositions = tickPositions;
1384        // Get minorTickInterval
1385        this.minorTickInterval =
1386            minorTickIntervalOption === 'auto' && this.tickInterval ?
1387                this.tickInterval / options.minorTicksPerMajor :
1388                minorTickIntervalOption;
1389        // Reset min/max or remove extremes based on start/end on tick
1390        this.paddedTicks = tickPositions.slice(0); // Used for logarithmic minor
1391        this.trimTicks(tickPositions, startOnTick, endOnTick);
1392        if (!this.isLinked && isNumber(this.min) && isNumber(this.max)) {
1393            // Substract half a unit (#2619, #2846, #2515, #3390), but not in
1394            // case of multiple ticks (#6897)
1395            if (this.single &&
1396                tickPositions.length < 2 &&
1397                !this.categories &&
1398                !this.series.some((s) => (s.is('heatmap') && s.options.pointPlacement === 'between'))) {
1399                this.min -= 0.5;
1400                this.max += 0.5;
1401            }
1402            if (!tickPositionsOption && !tickPositionerResult) {
1403                this.adjustTickAmount();
1404            }
1405        }
1406        fireEvent(this, 'afterSetTickPositions');
1407    }
1408    /**
1409     * Handle startOnTick and endOnTick by either adapting to padding min/max or
1410     * rounded min/max. Also handle single data points.
1411     *
1412     * @private
1413     * @function Highcharts.Axis#trimTicks
1414     *
1415     * @param {Array<number>} tickPositions
1416     * TO-DO: parameter description
1417     *
1418     * @param {boolean} [startOnTick]
1419     * TO-DO: parameter description
1420     *
1421     * @param {boolean} [endOnTick]
1422     * TO-DO: parameter description
1423     */
1424    trimTicks(tickPositions, startOnTick, endOnTick) {
1425        const roundedMin = tickPositions[0], roundedMax = tickPositions[tickPositions.length - 1], minPointOffset = (!this.isOrdinal && this.minPointOffset) || 0; // (#12716)
1426        fireEvent(this, 'trimTicks');
1427        if (!this.isLinked) {
1428            if (startOnTick && roundedMin !== -Infinity) { // #6502
1429                this.min = roundedMin;
1430            }
1431            else {
1432                while (this.min - minPointOffset > tickPositions[0]) {
1433                    tickPositions.shift();
1434                }
1435            }
1436            if (endOnTick) {
1437                this.max = roundedMax;
1438            }
1439            else {
1440                while (this.max + minPointOffset <
1441                    tickPositions[tickPositions.length - 1]) {
1442                    tickPositions.pop();
1443                }
1444            }
1445            // If no tick are left, set one tick in the middle (#3195)
1446            if (tickPositions.length === 0 &&
1447                defined(roundedMin) &&
1448                !this.options.tickPositions) {
1449                tickPositions.push((roundedMax + roundedMin) / 2);
1450            }
1451        }
1452    }
1453    /**
1454     * Check if there are multiple axes in the same pane.
1455     *
1456     * @private
1457     * @function Highcharts.Axis#alignToOthers
1458     *
1459     * @return {boolean|undefined}
1460     * True if there are other axes.
1461     */
1462    alignToOthers() {
1463        const axis = this, chart = axis.chart, alignedAxes = [this], options = axis.options, chartOptions = chart.options.chart, alignThresholds = (this.coll === 'yAxis' &&
1464            chartOptions.alignThresholds), thresholdAlignments = [];
1465        let hasOther;
1466        axis.thresholdAlignment = void 0;
1467        if ((
1468        // Only if alignTicks or alignThresholds is true
1469        (chartOptions.alignTicks !== false && options.alignTicks) ||
1470            alignThresholds) &&
1471            // Disabled when startOnTick or endOnTick are false (#7604)
1472            options.startOnTick !== false &&
1473            options.endOnTick !== false &&
1474            // Don't try to align ticks on a log axis, they are not evenly
1475            // spaced (#6021)
1476            !axis.logarithmic) {
1477            // Get a key identifying which pane the axis belongs to
1478            const getKey = (axis) => {
1479                const { horiz, options } = axis;
1480                return [
1481                    horiz ? options.left : options.top,
1482                    options.width,
1483                    options.height,
1484                    options.pane
1485                ].join(',');
1486            };
1487            const thisKey = getKey(this);
1488            chart[this.coll].forEach(function (otherAxis) {
1489                const { series } = otherAxis;
1490                if (
1491                // #4442
1492                series.length &&
1493                    series.some((s) => s.visible) &&
1494                    otherAxis !== axis &&
1495                    getKey(otherAxis) === thisKey) {
1496                    hasOther = true; // #4201
1497                    alignedAxes.push(otherAxis);
1498                }
1499            });
1500        }
1501        if (hasOther && alignThresholds) {
1502            // Handle alignThresholds. The `thresholdAlignments` array keeps
1503            // records of where each axis in the group wants its threshold, from
1504            // 0 which is on `axis.min`, to 1 which is on `axis.max`.
1505            alignedAxes.forEach((otherAxis) => {
1506                const threshAlign = otherAxis.getThresholdAlignment(axis);
1507                if (isNumber(threshAlign)) {
1508                    thresholdAlignments.push(threshAlign);
1509                }
1510            });
1511            // For each of the axes in the group, record the average
1512            // `thresholdAlignment`.
1513            const thresholdAlignment = thresholdAlignments.length > 1 ?
1514                thresholdAlignments.reduce((sum, n) => (sum += n), 0) / thresholdAlignments.length :
1515                void 0;
1516            alignedAxes.forEach((axis) => {
1517                axis.thresholdAlignment = thresholdAlignment;
1518            });
1519        }
1520        return hasOther;
1521    }
1522    /**
1523     * Where the axis wants its threshold, from 0 which is on `axis.min`, to 1 which
1524     * is on `axis.max`.
1525     *
1526     * @private
1527     * @function Highcharts.Axis#getThresholdAlignment
1528     */
1529    getThresholdAlignment(callerAxis) {
1530        if (!isNumber(this.dataMin) ||
1531            (this !== callerAxis &&
1532                this.series.some((s) => (s.isDirty || s.isDirtyData)))) {
vendor: 7,425 bytes, lines 1533-1695
1533            this.getSeriesExtremes();
1534        }
1535        if (isNumber(this.threshold)) {
1536            let thresholdAlignment = clamp(((this.threshold - (this.dataMin || 0)) /
1537                ((this.dataMax || 0) - (this.dataMin || 0))), 0, 1);
1538            if (this.options.reversed) {
1539                thresholdAlignment = 1 - thresholdAlignment;
1540            }
1541            return thresholdAlignment;
1542        }
1543    }
1544    /**
1545     * Find the max ticks of either the x and y axis collection, and record it
1546     * in `this.tickAmount`.
1547     *
1548     * @private
1549     * @function Highcharts.Axis#getTickAmount
1550     */
1551    getTickAmount() {
1552        const axis = this, options = this.options, tickPixelInterval = options.tickPixelInterval;
1553        let tickAmount = options.tickAmount;
1554        if (!defined(options.tickInterval) &&
1555            !tickAmount &&
1556            this.len < tickPixelInterval &&
1557            !this.isRadial &&
1558            !axis.logarithmic &&
1559            options.startOnTick &&
1560            options.endOnTick) {
1561            tickAmount = 2;
1562        }
1563        if (!tickAmount && this.alignToOthers()) {
1564            // Add 1 because 4 tick intervals require 5 ticks (including first
1565            // and last)
1566            tickAmount = Math.ceil(this.len / tickPixelInterval) + 1;
1567        }
1568        // For tick amounts of 2 and 3, compute five ticks and remove the
1569        // intermediate ones. This prevents the axis from adding ticks that are
1570        // too far away from the data extremes.
1571        if (tickAmount < 4) {
1572            this.finalTickAmt = tickAmount;
1573            tickAmount = 5;
1574        }
1575        this.tickAmount = tickAmount;
1576    }
1577    /**
1578     * When using multiple axes, adjust the number of ticks to match the highest
1579     * number of ticks in that group.
1580     *
1581     * @private
1582     * @function Highcharts.Axis#adjustTickAmount
1583     */
1584    adjustTickAmount() {
1585        const axis = this, { finalTickAmt, max, min, options, tickPositions, tickAmount, thresholdAlignment } = axis, currentTickAmount = tickPositions?.length, threshold = pick(axis.threshold, axis.softThreshold ? 0 : null);
1586        let len, i, tickInterval = axis.tickInterval, thresholdTickIndex;
1587        const 
1588        // Extend the tickPositions by appending a position
1589        append = () => tickPositions.push(correctFloat(tickPositions[tickPositions.length - 1] +
1590            tickInterval)), 
1591        // Extend the tickPositions by prepending a position
1592        prepend = () => tickPositions.unshift(correctFloat(tickPositions[0] - tickInterval));
1593        // If `thresholdAlignment` is a number, it means the `alignThresholds`
1594        // option is true. The `thresholdAlignment` is a scalar value between 0
1595        // and 1 for where the threshold should be relative to `axis.min` and
1596        // `axis.max`. Now that we know the tick amount, convert this to the
1597        // tick index. Unless `thresholdAlignment` is exactly 0 or 1, avoid the
1598        // first or last tick because that would lead to series being clipped.
1599        if (isNumber(thresholdAlignment)) {
1600            thresholdTickIndex = thresholdAlignment < 0.5 ?
1601                Math.ceil(thresholdAlignment * (tickAmount - 1)) :
1602                Math.floor(thresholdAlignment * (tickAmount - 1));
1603            if (options.reversed) {
1604                thresholdTickIndex = tickAmount - 1 - thresholdTickIndex;
1605            }
1606        }
1607        if (axis.hasData() && isNumber(min) && isNumber(max)) { // #14769
1608            // Adjust extremes and translation to the modified tick positions
1609            const adjustExtremes = () => {
1610                axis.transA *= (currentTickAmount - 1) / (tickAmount - 1);
1611                // Do not crop when ticks are not extremes (#9841)
1612                axis.min = options.startOnTick ?
1613                    tickPositions[0] :
1614                    Math.min(min, tickPositions[0]);
1615                axis.max = options.endOnTick ?
1616                    tickPositions[tickPositions.length - 1] :
1617                    Math.max(max, tickPositions[tickPositions.length - 1]);
1618            };
1619            // When the axis is subject to the alignThresholds option. Use
1620            // axis.threshold because the local threshold includes the
1621            // `softThreshold`.
1622            if (isNumber(thresholdTickIndex) && isNumber(axis.threshold)) {
1623                // Throw away the previously computed tickPositions and start
1624                // from scratch with only the threshold itself, then add ticks
1625                // below the threshold first, then fill up above the threshold.
1626                // If we are not able to fill up to axis.max, double the
1627                // tickInterval and run again.
1628                while (tickPositions[thresholdTickIndex] !== threshold ||
1629                    tickPositions.length !== tickAmount ||
1630                    tickPositions[0] > min ||
1631                    tickPositions[tickPositions.length - 1] < max) {
1632                    tickPositions.length = 0;
1633                    tickPositions.push(axis.threshold);
1634                    while (tickPositions.length < tickAmount) {
1635                        if (
1636                        // Start by prepending positions until the threshold
1637                        // is at the required index...
1638                        tickPositions[thresholdTickIndex] === void 0 ||
1639                            tickPositions[thresholdTickIndex] > axis.threshold) {
1640                            prepend();
1641                        }
1642                        else {
1643                            // ... then append positions until we have the
1644                            // required length
1645                            append();
1646                        }
1647                    }
1648                    // Safety vent
1649                    if (tickInterval > axis.tickInterval * 8) {
1650                        break;
1651                    }
1652                    tickInterval *= 2;
1653                }
1654                adjustExtremes();
1655            }
1656            else if (currentTickAmount < tickAmount) {
1657                while (tickPositions.length < tickAmount) {
1658                    // Extend evenly for both sides unless we're on the
1659                    // threshold (#3965)
1660                    if (tickPositions.length % 2 || min === threshold) {
1661                        append();
1662                    }
1663                    else {
1664                        prepend();
1665                    }
1666                }
1667                adjustExtremes();
1668            }
1669            // The finalTickAmt property is set in getTickAmount
1670            if (defined(finalTickAmt)) {
1671                i = len = tickPositions.length;
1672                while (i--) {
1673                    if (
1674                    // Remove every other tick
1675                    (finalTickAmt === 3 && i % 2 === 1) ||
1676                        // Remove all but first and last
1677                        (finalTickAmt <= 2 && i > 0 && i < len - 1)) {
1678                        tickPositions.splice(i, 1);
1679                    }
1680                }
1681                axis.finalTickAmt = void 0;
1682            }
1683        }
1684    }
1685    /**
1686     * Set the scale based on data min and max, user set min and max or options.
1687     *
1688     * @private
1689     * @function Highcharts.Axis#setScale
1690     *
1691     * @emits Highcharts.Axis#event:afterSetScale
1692     */
1693    setScale() {
1694        const axis = this, { coll, stacking } = axis;
1695        let isDirtyData = false, isXAxisDirty = false;
1696        axis.series.forEach((series) => {
1697            isDirtyData = isDirtyData || series.isDirtyData || series.isDirty;
1698            // When x axis is dirty, we need new data extremes for y as
1699            // well:
1700            isXAxisDirty = (isXAxisDirty ||
1701                (series.xAxis && series.xAxis.isDirty) ||
1702                false);
1703        });
1704        // Set the new axisLength
1705        axis.setAxisSize();
1706        const isDirtyAxisLength = axis.len !== (axis.old && axis.old.len);
1707        // Do we really need to go through all this?
1708        if (isDirtyAxisLength ||
1709            isDirtyData ||
1710            isXAxisDirty ||
1711            axis.isLinked ||
1712            axis.forceRedraw ||
1713            axis.userMin !== (axis.old && axis.old.userMin) ||
1714            axis.userMax !== (axis.old && axis.old.userMax) ||
1715            axis.alignToOthers()) {
1716            if (stacking && coll === 'yAxis') {
1717                stacking.buildStacks();
1718            }
1719            axis.forceRedraw = false;
1720            // #18066 delete minRange property to ensure that it will be
1721            // calculated again after dirty data in series
1722            if (!axis.userMinRange) {
1723                axis.minRange = void 0;
1724            }
1725            // Get data extremes if needed
1726            axis.getSeriesExtremes();
1727            // Get fixed positions based on tickInterval
1728            axis.setTickInterval();
1729            if (stacking && coll === 'xAxis') {
1730                stacking.buildStacks();
1731            }
1732            // Mark as dirty if it is not already set to dirty and extremes have
1733            // changed. #595.
1734            if (!axis.isDirty) {
1735                axis.isDirty =
1736                    isDirtyAxisLength ||
1737                        axis.min !== axis.old?.min ||
1738                        axis.max !== axis.old?.max;
1739            }
1740        }
1741        else if (stacking) {
1742            stacking.cleanStacks();
1743        }
1744        // Recalculate all extremes object when the data has changed. It is
1745        // required when vertical panning is enabled.
1746        if (isDirtyData) {
1747            delete axis.allExtremes;
1748        }
1749        fireEvent(this, 'afterSetScale');
1750    }
1751    /**
1752     * Set the minimum and maximum of the axes after render time. If the
1753     * `startOnTick` and `endOnTick` options are true, the minimum and maximum
1754     * values are rounded off to the nearest tick. To prevent this, these
1755     * options can be set to false before calling setExtremes. Also, setExtremes
1756     * will not allow a range lower than the `minRange` option, which by default
1757     * is the range of five points.
1758     *
1759     * @sample highcharts/members/axis-setextremes/
1760     *         Set extremes from a button
1761     * @sample highcharts/members/axis-setextremes-datetime/
1762     *         Set extremes on a datetime axis
1763     * @sample highcharts/members/axis-setextremes-off-ticks/
1764     *         Set extremes off ticks
1765     * @sample stock/members/axis-setextremes/
1766     *         Set extremes in Highcharts Stock
1767     *
1768     * @function Highcharts.Axis#setExtremes
1769     *
1770     * @param {number|string} [newMin]
1771     * The new minimum value. For datetime axes, date strings are accepted.
1772     *
1773     * @param {number|string} [newMax]
1774     * The new maximum value. For datetime axes, date strings are accepted.
1775     *
1776     * @param {boolean} [redraw=true]
1777     * Whether to redraw the chart or wait for an explicit call to
1778     * {@link Highcharts.Chart#redraw}
1779     *
1780     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation=true]
1781     * Enable or modify animations.
1782     *
1783     * @param {*} [eventArguments]
1784     * Arguments to be accessed in event handler.
1785     *
1786     * @emits Highcharts.Axis#event:setExtremes
1787     */
1788    setExtremes(min, max, redraw = true, animation, eventArguments) {
1789        const chart = this.chart;
1790        this.series.forEach((serie) => {
1791            delete serie.kdTree;
1792        });
1793        min = chart.time.parse(min);
1794        max = chart.time.parse(max);
1795        // Extend the arguments with min and max
1796        eventArguments = extend(eventArguments, { min, max });
1797        // Fire the event
1798        fireEvent(this, 'setExtremes', eventArguments, (e) => {
1799            this.userMin = e.min;
1800            this.userMax = e.max;
1801            this.eventArgs = e;
1802            if (redraw) {
1803                chart.redraw(animation);
1804            }
1805        });
1806    }
1807    /**
1808     * Update the axis metrics.
1809     *
1810     * @private
1811     * @function Highcharts.Axis#setAxisSize
1812     */
1813    setAxisSize() {
1814        const chart = this.chart, options = this.options, 
1815        // [top, right, bottom, left]
1816        offsets = options.offsets || [0, 0, 0, 0], horiz = this.horiz, 
1817        // Check for percentage based input values. Rounding fixes problems
1818        // with column overflow and plot line filtering (#4898, #4899)
1819        width = this.width = Math.round(relativeLength(pick(options.width, chart.plotWidth - offsets[3] + offsets[1]), chart.plotWidth)), height = this.height = Math.round(relativeLength(pick(options.height, chart.plotHeight - offsets[0] + offsets[2]), chart.plotHeight)), top = this.top = Math.round(relativeLength(pick(options.top, chart.plotTop + offsets[0]), chart.plotHeight, chart.plotTop)), left = this.left = Math.round(relativeLength(pick(options.left, chart.plotLeft + offsets[3]), chart.plotWidth, chart.plotLeft));
1820        // Expose basic values to use in Series object and navigator
1821        this.bottom = chart.chartHeight - height - top;
1822        this.right = chart.chartWidth - width - left;
1823        // Direction agnostic properties
1824        this.len = Math.max(horiz ? width : height, 0); // Math.max fixes #905
1825        /**
1826         * The position of the axis in terms of pixels, compared to the chart
1827         * edge. In a horizontal axis it is the same as `chart.plotLeft` unless
1828         * the axis is explicitly positioned, and in a default vertical axis it
1829         * is the same as `chart.plotTop`.
1830         *
1831         * @name Highcharts.Axis#pos
1832         * @type {number}
1833         */
1834        this.pos = horiz ? left : top; // Distance from SVG origin
1835    }
1836    /**
1837     * Get the current extremes for the axis.
1838     *
1839     * @sample highcharts/members/axis-getextremes/
1840     *         Report extremes by click on a button
1841     *
1842     * @function Highcharts.Axis#getExtremes
1843     *
1844     * @return {Highcharts.ExtremesObject}
vendor: 7,649 bytes, lines 1845-2040
1845     * An object containing extremes information.
1846     */
1847    getExtremes() {
1848        const axis = this, log = axis.logarithmic;
1849        return {
1850            min: log ?
1851                correctFloat(log.lin2log(axis.min)) :
1852                axis.min,
1853            max: log ?
1854                correctFloat(log.lin2log(axis.max)) :
1855                axis.max,
1856            dataMin: axis.dataMin,
1857            dataMax: axis.dataMax,
1858            userMin: axis.userMin,
1859            userMax: axis.userMax
1860        };
1861    }
1862    /**
1863     * Get the zero plane either based on zero or on the min or max value.
1864     * Used in bar and area plots.
1865     *
1866     * @function Highcharts.Axis#getThreshold
1867     *
1868     * @param {number} threshold
1869     * The threshold in axis values.
1870     *
1871     * @return {number}
1872     * The translated threshold position in terms of pixels, and corrected to
1873     * stay within the axis bounds.
1874     */
1875    getThreshold(threshold) {
1876        const axis = this, log = axis.logarithmic, realMin = log ? log.lin2log(axis.min) : axis.min, realMax = log ? log.lin2log(axis.max) : axis.max;
1877        if (threshold === null || threshold === -Infinity) {
1878            threshold = realMin;
1879        }
1880        else if (threshold === Infinity) {
1881            threshold = realMax;
1882        }
1883        else if (realMin > threshold) {
1884            threshold = realMin;
1885        }
1886        else if (realMax < threshold) {
1887            threshold = realMax;
1888        }
1889        return axis.translate(threshold, 0, 1, 0, 1);
1890    }
1891    /**
1892     * Compute auto alignment for the axis label based on which side the axis is
1893     * on and the given rotation for the label.
1894     *
1895     * @private
1896     * @function Highcharts.Axis#autoLabelAlign
1897     *
1898     * @param {number} rotation
1899     * The rotation in degrees as set by either the `rotation` or `autoRotation`
1900     * options.
1901     *
1902     * @return {Highcharts.AlignValue}
1903     * Can be `"center"`, `"left"` or `"right"`.
1904     */
1905    autoLabelAlign(rotation) {
1906        const angle = (pick(rotation, 0) - (this.side * 90) + 720) % 360, evt = { align: 'center' };
1907        fireEvent(this, 'autoLabelAlign', evt, function (e) {
1908            if (angle > 15 && angle < 165) {
1909                e.align = 'right';
1910            }
1911            else if (angle > 195 && angle < 345) {
1912                e.align = 'left';
1913            }
1914        });
1915        return evt.align;
1916    }
1917    /**
1918     * Get the tick length and width for the axis based on axis options.
1919     *
1920     * @private
1921     * @function Highcharts.Axis#tickSize
1922     *
1923     * @param {string} [prefix]
1924     * 'tick' or 'minorTick'
1925     *
1926     * @return {Array<number,number>|undefined}
1927     * An array of tickLength and tickWidth
1928     */
1929    tickSize(prefix) {
1930        const options = this.options, tickWidth = pick(options[prefix === 'tick' ? 'tickWidth' : 'minorTickWidth'], 
1931        // Default to 1 on linear and datetime X axes
1932        prefix === 'tick' && this.isXAxis && !this.categories ? 1 : 0);
1933        let tickLength = options[prefix === 'tick' ? 'tickLength' : 'minorTickLength'], tickSize;
1934        if (tickWidth && tickLength) {
1935            // Negate the length
1936            if (options[prefix + 'Position'] === 'inside') {
1937                tickLength = -tickLength;
1938            }
1939            tickSize = [tickLength, tickWidth];
1940        }
1941        const e = { tickSize };
1942        fireEvent(this, 'afterTickSize', e);
1943        return e.tickSize;
1944    }
1945    /**
1946     * Return the size of the labels.
1947     *
1948     * @private
1949     * @function Highcharts.Axis#labelMetrics
1950     */
1951    labelMetrics() {
1952        const renderer = this.chart.renderer, ticks = this.ticks, tick = ticks[Object.keys(ticks)[0]] || {};
1953        return this.chart.renderer.fontMetrics(tick.label ||
1954            tick.movedLabel ||
1955            renderer.box);
1956    }
1957    /**
1958     * Prevent the ticks from getting so close we can't draw the labels. On a
1959     * horizontal axis, this is handled by rotating the labels, removing ticks
1960     * and adding ellipsis. On a vertical axis remove ticks and add ellipsis.
1961     *
1962     * @private
1963     * @function Highcharts.Axis#unsquish
1964     */
1965    unsquish() {
1966        const labelOptions = this.options.labels, padding = labelOptions.padding || 0, horiz = this.horiz, tickInterval = this.tickInterval, slotSize = this.len / (((this.categories ? 1 : 0) +
1967            this.max -
1968            this.min) /
1969            tickInterval), rotationOption = labelOptions.rotation, 
1970        // We don't know the actual rendered line height at this point, but
1971        // it defaults to 0.8em
1972        lineHeight = correctFloat(this.labelMetrics().h * 0.8), range = Math.max(this.max - this.min, 0), 
1973        // Return the multiple of tickInterval that is needed to avoid
1974        // collision
1975        getStep = function (spaceNeeded) {
1976            let step = (spaceNeeded + 2 * padding) / (slotSize || 1);
1977            step = step > 1 ? Math.ceil(step) : 1;
1978            // Guard for very small or negative angles (#9835)
1979            if (step * tickInterval > range &&
1980                spaceNeeded !== Infinity &&
1981                slotSize !== Infinity &&
1982                range) {
1983                step = Math.ceil(range / tickInterval);
1984            }
1985            return correctFloat(step * tickInterval);
1986        };
1987        let newTickInterval = tickInterval, rotation, bestScore = Number.MAX_VALUE, autoRotation;
1988        if (horiz) {
1989            if (!labelOptions.staggerLines) {
1990                if (isNumber(rotationOption)) {
1991                    autoRotation = [rotationOption];
1992                }
1993                else if (slotSize < labelOptions.autoRotationLimit) {
1994                    autoRotation = labelOptions.autoRotation;
1995                }
1996            }
1997            if (autoRotation) {
1998                let step, score;
1999                // Loop over the given autoRotation options, and determine which
2000                // gives the best score. The best score is that with the lowest
2001                // number of steps and a rotation closest to horizontal.
2002                for (const rot of autoRotation) {
2003                    if (rot === rotationOption ||
2004                        (rot && rot >= -90 && rot <= 90)) { // #3891
2005                        step = getStep(Math.abs(lineHeight / Math.sin(deg2rad * rot)));
2006                        score = step + Math.abs(rot / 360);
2007                        if (score < bestScore) {
2008                            bestScore = score;
2009                            rotation = rot;
2010                            newTickInterval = step;
2011                        }
2012                    }
2013                }
2014            }
2015        }
2016        else { // #4411
2017            newTickInterval = getStep(lineHeight * 0.75);
2018        }
2019        this.autoRotation = autoRotation;
2020        this.labelRotation = pick(rotation, isNumber(rotationOption) ? rotationOption : 0);
2021        return labelOptions.step ? tickInterval : newTickInterval;
2022    }
2023    /**
2024     * Get the general slot width for labels/categories on this axis. This may
2025     * change between the pre-render (from Axis.getOffset) and the final tick
2026     * rendering and placement.
2027     *
2028     * @private
2029     * @function Highcharts.Axis#getSlotWidth
2030     *
2031     * @param {Highcharts.Tick} [tick] Optionally, calculate the slot width
2032     * basing on tick label. It is used in highcharts-3d module, where the slots
2033     * has different widths depending on perspective angles.
2034     *
2035     * @return {number}
2036     * The pixel width allocated to each axis label.
2037     */
2038    getSlotWidth(tick) {
2039        // #5086, #1580, #1931
2040        const chart = this.chart, horiz = this.horiz, labelOptions = this.options.labels, slot
2040Count = Math.max(this.tickPositions.length - (this.categories ? 0 : 1), 1), marginLeft = chart.margin[3];
2041        // Used by grid axis
2042        if (tick && isNumber(tick.slotWidth)) { // #13221, can be 0
2043            return tick.slotWidth;
2044        }
2045        if (horiz && labelOptions.step < 2 && !this.isRadial) {
2046            if (labelOptions.rotation) { // #4415
2047                return 0;
2048            }
2049            return ((this.staggerLines || 1) * this.len) / slotCount;
2050        }
2051        if (!horiz) {
2052            // #7028
2053            const cssWidth = labelOptions.style.width;
2054            if (cssWidth !== void 0) {
2055                return parseInt(String(cssWidth), 10);
2056            }
2057            if (marginLeft) {
2058                return marginLeft - chart.spacing[3];
2059            }
2060        }
2061        // Last resort, a fraction of the available size
2062        return chart.chartWidth * 0.33;
2063    }
2064    /**
2065     * Render the axis labels and determine whether ellipsis or rotation need to
2066     * be applied.
2067     *
2068     * @private
2069     * @function Highcharts.Axis#renderUnsquish
2070     */
2071    renderUnsquish() {
2072        const chart = this.chart, renderer = chart.renderer, tickPositions = this.tickPositions, ticks = this.ticks, labelOptions = this.options.labels, labelStyleOptions = labelOptions.style, horiz = this.horiz, slotWidth = this.getSlotWidth(), innerWidth = Math.max(1, Math.round(slotWidth - (horiz ?
2073            2 * (labelOptions.padding || 0) :
2074            labelOptions.distance || 0 // #21172
2075        ))), attr = {}, labelMetrics = this.labelMetrics(), lineClampOption = labelStyleOptions.lineClamp;
2076        let commonWidth, lineClamp = lineClampOption ?? (Math.floor(this.len / (tickPositions.length * labelMetrics.h)) || 1), maxLabelLength = 0;
2077        // Set rotation option unless it is "auto", like in gauges
2078        if (!isString(labelOptions.rotation)) {
2079            // #4443
2080            attr.rotation = labelOptions.rotation || 0;
2081        }
2082        // Get the longest label length
2083        tickPositions.forEach(function (tickPosition) {
2084            const tick = ticks[tickPosition];
2085            // Replace label - sorting animation
2086            if (tick.movedLabel) {
2087                tick.replaceMovedLabel();
2088            }
2089            const textPxLength = tick.label?.textPxLength || 0;
2090            if (textPxLength > maxLabelLength) {
2091                maxLabelLength = textPxLength;
2092            }
2093        });
2094        this.maxLabelLength = maxLabelLength;
2095        // Handle auto rotation on horizontal axis
2096        if (this.autoRotation) {
2097            // Apply rotation only if the label is too wide for the slot, and
2098            // the label is wider than its height.
2099            if (maxLabelLength > innerWidth &&
2100                maxLabelLength > labelMetrics.h) {
2101                attr.rotation = this.labelRotation;
2102            }
2103            else {
2104                this.labelRotation = 0;
2105            }
2106            // Handle word-wrap or ellipsis on vertical axis
2107        }
2108        else if (slotWidth) {
2109            // For word-wrap or ellipsis
2110            commonWidth = innerWidth;
2111        }
2112        // Add ellipsis if the label length is significantly longer than ideal
2113        if (attr.rotation) {
2114            commonWidth = (maxLabelLength > chart.chartHeight * 0.5 ?
2115                chart.chartHeight * 0.33 :
2116                maxLabelLength);
2117            if (!lineClampOption) {
2118                lineClamp = 1;
2119            }
2120        }
2121        // Set the explicit or automatic label alignment
2122        this.labelAlign = labelOptions.align ||
2123            this.autoLabelAlign(this.labelRotation);
2124        if (this.labelAlign) {
2125            attr.align = this.labelAlign;
2126        }
2127        // Apply general and specific CSS
2128        tickPositions.forEach(function (pos) {
2129            const tick = ticks[pos], label = tick && tick.label, widthOption = labelStyleOptions.width, css = {};
2130            if (label) {
2131                // This needs to go before the CSS in old IE (#4502)
2132                label.attr(attr);
2133                if (tick.shortenLabel) {
2134                    tick.shortenLabel();
2135                }
2136                else if (commonWidth &&
2137                    !widthOption &&
2138                    // Setting width in this case messes with the bounding box
2139                    // (#7975)
2140                    labelStyleOptions.whiteSpace !== 'nowrap' &&
2141                    (
2142                    // Speed optimizing, #7656
2143                    commonWidth < (label.textPxLength || 0) ||
2144                        // Resetting CSS, #4928
2145                        label.element.tagName === 'SPAN')) {
2146                    label.css(extend(css, {
2147                        width: `${commonWidth}px`,
2148                        lineClamp
2149                    }));
2150                    // Reset previously shortened label (#8210)
2151                }
2152                else if (label.styles.width && !css.width && !widthOption) {
2153                    label.css({ width: 'auto' });
2154                }
2155                tick.rotation = attr.rotation;
2156            }
2157        }, this);
2158        // Note: Why is this not part of getLabelPosition?
2159        this.tickRotCorr = renderer.rotCorr(labelMetrics.b, this.labelRotation || 0, this.side !== 0);
2160    }
2161    /**
2162     * Return true if the axis has associated data.
2163     *
2164     * @function Highcharts.Axis#hasData
2165     *
2166     * @return {boolean}
2167     * True if the axis has associated visible series and those series have
2168     * either valid data points or explicit `min` and `max` settings.
2169     */
2170    hasData() {
2171        return this.series.some(function (s) {
2172            return s.hasData();
2173        }) ||
2174            (this.options.showEmpty &&
2175                defined(this.min) &&
2176                defined(this.max));
2177    }
2178    /**
2179     * Adds the title defined in axis.options.title.
2180     *
2181     * @function Highcharts.Axis#addTitle
2182     *
2183     * @param {boolean} [display]
2184     * Whether or not to display the title.
2185     */
2186    addTitle(display) {
2187        const axis = this, renderer = axis.chart.renderer, horiz = axis.horiz, opposite = axis.opposite, options = axis.options, axisTitleOptions = options.title, styledMode = axis.chart.styledMode;
2188        let textAlign;
2189        if (!axis.axisTitle) {
2190            textAlign = axisTitleOptions.textAlign;
2191            if (!textAlign) {
2192                textAlign = (horiz ? {
2193                    low: 'left',
2194                    middle: 'center',
2195                    high: 'right'
2196                } : {
2197                    low: opposite ? 'right' : 'left',
2198                    middle: 'center',
2199                    high: opposite ? 'left' : 'right'
2200                })[axisTitleOptions.align];
2201            }
2202            axis.axisTitle = renderer
2203                .text(axisTitleOptions.text || '', 0, 0, axisTitleOptions.useHTML)
2204                .attr({
2205                zIndex: 7,
2206                rotation: axisTitleOptions.rotation || 0,
2207                align: textAlign
2208            })
2209                .addClass('highcharts-axis-title');
2210            // #7814, don't mutate style option
2211            if (!styledMode) {
2212                axis.axisTitle.css(merge(axisTitleOptions.style));
2213            }
2214            axis.axisTitle.add(axis.axisGroup);
2215            axis.axisTitle.isNew = true;
2216        }
2217        // Max width defaults to the length of the axis
2218        if (!styledMode &&
2219            !axisTitleOptions.style.width &&
2220            !axis.isRadial) {
2221            axis.axisTitle.css({
2222                width: axis.len + 'px'
2223            });
2224        }
2225        // Hide or show the title depending on whether showEmpty is set
2226        axis.axisTitle[display ? 'show' : 'hide'](display);
2227    }
2228    /**
2229     * Generates a tick for initial positioning.
2230     *
2231     * @private
2232     * @function Highcharts.Axis#generateTick
2233     *
2234     * @param {number} pos
2235     * The tick position in axis values.
2236     *
2237     * @param {number} [i]
2238     * The index of the tick in {@link Axis.tickPositions}.
2239     */
2240    generateTick(pos) {
2241        const axis = this, ticks = axis.ticks;
2242        if (!ticks[pos]) {
2243            ticks[pos] = new Tick(axis, pos);
2244        }
2245        else {
2246            ticks[pos].addLabel(); // Update labels depending on tick interval
2247        }
2248    }
2249    /**
2250     * Create the axisGroup and gridGroup elements on first iteration.
2251     *
2252     * @private
2253     * @function Highcharts.Axis#getOffset
2254     *
2255     * @emits Highcharts.Axis#event:afterGetOffset
2256     */
2257    createGroups() {
2258        const { axisParent, // Used in color axis
2259        chart, coll, options } = this, renderer = chart.renderer;
2260        const createGroup = (name, suffix, zIndex) => renderer.g(name)
2261            .attr({ zIndex })
2262            .addClass(`highcharts-${coll.toLowerCase()}${suffix} ` +
2263            (this.isRadial ? `highcharts-radial-axis${suffix} ` : '') +
2264            (options.className || ''))
2265            .add(axisParent);
2266        if (!this.axisGroup) {
2267            this.gridGroup = createGroup('grid', '-grid', options.gridZIndex);
2268            this.axisGroup = createGroup('axis', '', options.zIndex);
2269            this.labelGroup = createGroup('axis-labels', '-labels', options.labels.zIndex);
2270        }
2271    }
2272    /**
2273     * Render the tick labels to a preliminary position to get their sizes
2274     *
2275     * @private
2276     * @function Highcharts.Axis#getOffset
2277     *
2278     * @emits Highcharts.Axis#event:afterGetOffset
2279     */
2280    getOffset() {
2281        const axis = this, { chart, horiz, options, side, ticks, tickPositions, coll } = axis, invertedSide = (chart.inverted && !axis.isZAxis ?
2282            [1, 0, 3, 2][side] :
2283            side), hasData = axis.hasData(), axisTitleOptions = options.title, labelOptions = options.labels, hasCrossing = isNumber(options.crossing), axisOffset = chart.axisOffset, clipOffset = chart.clipOffset, directionFactor = [-1, 1, 1, -1][side];
2284        let showAxis, titleOffset = 0, titleOffsetOption, titleMargin = 0, labelOffset = 0, // Reset
2285        labelOffsetPadded, lineHeightCorrection;
2286        // For reuse in Axis.render
2287        axis.showAxis = showAxis = hasData || options.showEmpty;
2288        // Set/reset staggerLines
2289        axis.staggerLines = (axis.horiz && labelOptions.staggerLines) || void 0;
2290        axis.createGroups();
2291        if (hasData || axis.isLinked) {
2292            // Generate ticks
2293            tickPositions.forEach(function (pos) {
2294                axis.generateTick(pos);
2295            });
2296            axis.renderUnsquish();
2297            // Left side must be align: right and right side must
2298            // have align: left for labels
2299            axis.reserveSpaceDefault = (side === 0 ||
2300                side === 2 ||
2301                { 1: 'left', 3: 'right' }[side] === axis.labelAlign);
2302            if (pick(labelOptions.reserveSpace, hasCrossing ? false : null, axis.labelAlign === 'center' ? true : null, axis.reserveSpaceDefault)) {
2303                tickPositions.forEach(function (pos) {
2304                    // Get the highest offset
2305                    labelOffset = Math.max(ticks[pos].getLabelSize(), labelOffset);
2306                });
2307            }
2308            if (axis.staggerLines) {
2309                labelOffset *= axis.staggerLines;
2310            }
2311            axis.labelOffset = labelOffset * (axis.opposite ? -1 : 1);
2312        }
2313        else { // Doesn't have data
2314            objectEach(ticks, function (tick, n) {
2315                tick.destroy();
2316                delete ticks[n];
2317            });
2318        }
2319        if (axisTitleOptions?.text &&
2320            axisTitleOptions.enabled !== false) {
2321            axis.addTitle(showAxis);
2322            if (showAxis &&
2323                !hasCrossing &&
2324                axisTitleOptions.reserveSpace !== false) {
2325                axis.titleOffset = titleOffset =
2326                    axis.axisTitle.getBBox()[horiz ? 'height' : 'width'];
2327                titleOffsetOption = axisTitleOptions.offset;
2328                titleMargin = defined(titleOffsetOption) ?
2329                    0 :
2330                    pick(axisTitleOptions.margin, horiz ? 5 : 10);
2331            }
2332        }
2333        // Render the axis line
2334        axis.renderLine();
2335        // Handle automatic or user set offset
2336        axis.offset = directionFactor * pick(options.offset, axisOffset[side] ? axisOffset[side] + (options.margin || 0) : 0);
2337        axis.tickRotCorr = axis.tickRotCorr || { x: 0, y: 0 }; // Polar
2338        if (side === 0) {
2339            lineHeightCorrection = -axis.labelMetrics().h;
2340        }
2341        else if (side === 2) {
2342            lineHeightCorrection = axis.tickRotCorr.y;
2343        }
2344        else {
2345            lineHeightCorrection = 0;
2346        }
2347        // Find the padded label offset
2348        labelOffsetPadded = Math.abs(labelOffset) + titleMargin;
2349        if (labelOffset) {
2350            labelOffsetPadded -= lineHeightCorrection;
2351            labelOffsetPadded += directionFactor * (horiz ?
2352                pick(labelOptions.y, axis.tickRotCorr.y +
2353                    directionFactor * labelOptions.distance) :
2354                pick(labelOptions.x, directionFactor * labelOptions.distance));
2355        }
2356        axis.axisTitleMargin = pick(titleOffsetOption, labelOffsetPadded);
2357        if (axis.getMaxLabelDimensions) {
2358            axis.maxLabelDimensions = axis.getMaxLabelDimensions(ticks, tickPositions);
2359        }
2360        // Due to GridAxis.tickSize, tickSize should be calculated after ticks
2361        // has rendered.
2362        if (coll !== 'colorAxis' && clipOffset) {
2363            const tickSize = this.tickSize('tick');
2364            axisOffset[side] = Math.max(axisOffset[side], (axis.axisTitleMargin || 0) + titleOffset +
2365                directionFactor * axis.offset, labelOffsetPadded, // #3
vendor: 4,701 bytes, lines 2365-2483
2365027
2366            tickPositions && tickPositions.length && tickSize ?
2367                tickSize[0] + directionFactor * axis.offset :
2368                0 // #4866
2369            );
2370            // Decide the clipping needed to keep the graph inside
2371            // the plot area and axis lines
2372            const clip = !axis.axisLine || options.offset ?
2373                0 :
2374                // #4308, #4371
2375                axis.axisLine.strokeWidth() / 2;
2376            clipOffset[invertedSide] = Math.max(clipOffset[invertedSide], clip);
2377        }
2378        fireEvent(this, 'afterGetOffset');
2379    }
2380    /**
2381     * Internal function to get the path for the axis line. Extended for polar
2382     * charts.
2383     *
2384     * @function Highcharts.Axis#getLinePath
2385     *
2386     * @param {number} lineWidth
2387     * The line width in pixels.
2388     *
2389     * @return {Highcharts.SVGPathArray}
2390     * The SVG path definition in array form.
2391     */
2392    getLinePath(lineWidth) {
2393        const chart = this.chart, opposite = this.opposite, offset = this.offset, horiz = this.horiz, lineLeft = this.left + (opposite ? this.width : 0) + offset, lineTop = chart.chartHeight - this.bottom -
2394            (opposite ? this.height : 0) + offset;
2395        if (opposite) {
2396            lineWidth *= -1; // Crispify the other way - #1480, #1687
2397        }
2398        return chart.renderer
2399            .crispLine([
2400            [
2401                'M',
2402                horiz ?
2403                    this.left :
2404                    lineLeft,
2405                horiz ?
2406                    lineTop :
2407                    this.top
2408            ],
2409            [
2410                'L',
2411                horiz ?
2412                    chart.chartWidth - this.right :
2413                    lineLeft,
2414                horiz ?
2415                    lineTop :
2416                    chart.chartHeight - this.bottom
2417            ]
2418        ], lineWidth);
2419    }
2420    /**
2421     * Render the axis line. Called internally when rendering and redrawing the
2422     * axis.
2423     *
2424     * @function Highcharts.Axis#renderLine
2425     */
2426    renderLine() {
2427        if (!this.axisLine) {
2428            this.axisLine = this.chart.renderer.path()
2429                .addClass('highcharts-axis-line')
2430                .add(this.axisGroup);
2431            if (!this.chart.styledMode) {
2432                this.axisLine.attr({
2433                    stroke: this.options.lineColor,
2434                    'stroke-width': this.options.lineWidth,
2435                    zIndex: 7
2436                });
2437            }
2438        }
2439    }
2440    /**
2441     * Position the axis title.
2442     *
2443     * @private
2444     * @function Highcharts.Axis#getTitlePosition
2445     *
2446     * @return {Highcharts.PositionObject}
2447     * X and Y positions for the title.
2448     */
2449    getTitlePosition(axisTitle) {
2450        // Compute anchor points for each of the title align options
2451        const horiz = this.horiz, axisLeft = this.left, axisTop = this.top, axisLength = this.len, axisTitleOptions = this.options.title, margin = horiz ? axisLeft : axisTop, opposite = this.opposite, offset = this.offset, xOption = axisTitleOptions.x, yOption = axisTitleOptions.y, fontMetrics = this.chart.renderer.fontMetrics(axisTitle), 
2452        // The part of a multiline text that is below the baseline of the
2453        // first line. Subtract 1 to preserve pixel-perfectness from the
2454        // old behaviour (v5.0.12), where only one line was allowed.
2455        textHeightOvershoot = axisTitle ? Math.max(axisTitle.getBBox(false, 0).height - fontMetrics.h - 1, 0) : 0, 
2456        // The position in the length direction of the axis
2457        alongAxis = ({
2458            low: margin + (horiz ? 0 : axisLength),
2459            middle: margin + axisLength / 2,
2460            high: margin + (horiz ? axisLength : 0)
2461        })[axisTitleOptions.align], 
2462        // The position in the perpendicular direction of the axis
2463        offAxis = (horiz ? axisTop + this.height : axisLeft) +
2464            (horiz ? 1 : -1) * // Horizontal axis reverses the margin
2465                (opposite ? -1 : 1) * // So does opposite axes
2466                (this.axisTitleMargin || 0) +
2467            [
2468                -textHeightOvershoot, // Top
2469                textHeightOvershoot, // Right
2470                fontMetrics.f, // Bottom
2471                -textHeightOvershoot // Left
2472            ][this.side], titlePosition = {
2473            x: horiz ?
2474                alongAxis + xOption :
2475                offAxis + (opposite ? this.width : 0) + offset + xOption,
2476            y: horiz ?
2477                offAxis + yOption - (opposite ? this.height : 0) + offset :
2478                alongAxis + yOption
2479        };
2480        fireEvent(this, 'afterGetTitlePosition', { titlePosition: titlePosition });
2481        return titlePosition;
2482    }
2483    /**
2484     * Render a minor tick into the given position. If a minor tick already
2485     * exists in this position, move it.
2486     *
2487     * @function Highcharts.Axis#renderMinorTick
2488     *
2489     * @param {number} pos
2490     * The position in axis values.
2491     *
2492     * @param {boolean} slideIn
2493     * Whether the tick should animate in from last computed position
2494     */
2495    renderMinorTick(pos, slideIn) {
2496        const axis = this;
2497        const minorTicks = axis.minorTicks;
2498        if (!minorTicks[pos]) {
2499            minorTicks[pos] = new Tick(axis, pos, 'minor');
2500        }
2501        // Render new ticks in old position
2502        if (slideIn && minorTicks[pos].isNew) {
2503            minorTicks[pos].render(null, true);
2504        }
2505        minorTicks[pos].render(null, false, 1);
2506    }
2507    /**
2508     * Render a major tick into the given position. If a tick already exists
2509     * in this position, move it.
2510     *
2511     * @function Highcharts.Axis#renderTick
2512     *
2513     * @param {number} pos
2514     * The position in axis values.
2515     *
2516     * @param {number} i
2517     * The tick index.
2518     *
2519     * @param {boolean} slideIn
2520     * Whether the tick should animate in from last computed position
2521     */
2522    renderTick(pos, i, slideIn) {
2523        const axis = this, isLinked = axis.isLinked, ticks = axis.ticks;
2524        // Linked axes need an extra check to find out if
2525        if (!isLinked ||
2526            (pos >= axis.min && pos <= axis.max) ||
2527            (axis.grid && axis.grid.isColumn)) {
2528            if (!ticks[pos]) {
2529                ticks[pos] = new Tick(axis, pos);
2530            }
2531            // NOTE this seems like overkill. Could be handled in tick.render by
2532            // setting old position in attr, then set new position in animate.
2533            // render new ticks in old position
2534            if (slideIn && ticks[pos].isNew) {
2535                // Start with negative opacity so that it is visible from
2536                // halfway into the animation
2537                ticks[pos].render(i, true, -1);
2538            }
2539            ticks[pos].render(i);
2540        }
2541    }
2542    /**
2543     * Render the axis.
2544     *
2545     * @private
2546     * @function Highcharts.Axis#render
2547     *
2548     * @emits Highcharts.Axis#event:afterRender
2549     */
2550    render() {
2551        const axis = this, chart = axis.chart, log = axis.logarithmic, renderer = chart.renderer, options = axis.options, isLinked = axis.isLinked, tickPositions = axis.tickPositions, axisTitle = axis.axisTitle, ticks = axis.ticks, minorTicks = axis.minorTicks, alternateBands = axis.alternateBands, stackLabelOptions = options.stackLabels, alternateGridColor = options.alternateGridColor, crossing = options.crossing, tickmarkOffset = axis.tickmarkOffset, axisLine = axis.axisLine, showAxis = axis.showAxis, animation = animObject(renderer.globalAnimation);
2552        let from, to;
2553        // Reset
2554        axis.labelEdge.length = 0;
2555        axis.overlap = false;
2556        // Mark all elements inActive before we go over and mark the active ones
2557        [ticks, minorTicks, alternateBands].forEach(function (coll) {
2558            objectEach(coll, function (tick) {
2559                tick.isActive = false;
2560            });
2561        });
2562        // Crossing
2563        if (isNumber(crossing)) {
2564            const otherAxis = this.isXAxis ? chart.yAxis[0] : chart.xAxis[0], directionFactor = [1, -1, -1, 1][this.side];
2565            if (otherAxis) {
2566                let px = otherAxis.toPixels(crossing, true);
2567                if (axis.horiz) {
2568                    px = otherAxis.len - px;
2569                }
2570                axis.offset = directionFactor * px;
2571            }
2572        }
2573        // If the series has data draw the ticks. Else only the line and title
2574        if (axis.hasData() || isLinked) {
2575            const slideInTicks = axis.chart.hasRendered &&
2576                axis.old && isNumber(axis.old.min);
2577            // Minor ticks
2578            if (axis.minorTickInterval && !axis.categories) {
2579                axis.getMinorTickPositions().forEach(function (pos) {
2580                    axis.renderMinorTick(pos, slideInTicks);
2581                });
2582            }
2583            // Major ticks. Pull out the first item and render it last so that
2584            // we can get the position of the neighbour label. #808.
2585            if (tickPositions.length) { // #1300
2586                tickPositions.forEach(function (pos, i) {
2587                    axis.renderTick(pos, i, slideInTicks);
2588                });
2589                // In a categorized axis, the tick marks are displayed
2590                // between labels. So we need to add a tick mark and
2591                // grid line at the left edge of the X axis.
2592                if (tickmarkOffset && (axis.min === 0 || axis.single)) {
2593                    if (!ticks[-1]) {
2594                        ticks[-1] = new Tick(axis, -1, null, true);
2595                    }
2596                    ticks[-1].render(-1);
2597                }
2598            }
2599            // Alternate grid color
2600            if (alternateGridColor) {
2601                tickPositions.forEach(function (pos, i) {
2602                    to = typeof tickPositions[i + 1] !== 'undefined' ?
2603                        tickPositions[i + 1] + tickmarkOffset :
2604                        axis.max - tickmarkOffset;
2605                    if (i % 2 === 0 &&
2606                        pos < axis.max &&
2607                        to <= axis.max + (chart.polar ?
2608                            -tickmarkOffset :
2609                            tickmarkOffset)) { // #2248, #4660
2610                        if (!alternateBands[pos]) {
2611                            // Should be imported from PlotLineOrBand.js, but
2612                            // the dependency cycle with axis is a problem
2613                            alternateBands[pos] = new H.PlotLineOrBand(axis, {});
2614                        }
2615                        from = pos + tickmarkOffset; // #949
2616                        alternateBands[pos].options = {
2617                            from: log ? log.lin2log(from) : from,
2618                            to: log ? log.lin2log(to) : to,
2619                            color: alternateGridColor,
2620                            className: 'highcharts-alternate-grid'
2621                        };
2622                        alternateBands[pos].render();
2623                        alternateBands[pos].isActive = true;
2624                    }
2625                });
2626            }
2627            // Custom plot lines and bands
2628            if (!axis._addedPlotLB) { // Only first time
2629                axis._addedPlotLB = true;
2630                (options.plotLines || [])
2631                    .concat(options.plotBands || [])
2632                    .forEach(function (plotLineOptions) {
2633                    axis
2634                        .addPlotBandOrLine(plotLineOptions);
2635                });
2636            }
2637        } // End if hasData
2638        // Remove inactive ticks
2639        [ticks, minorTicks, alternateBands].forEach(function (coll) {
2640            const forDestruction = [], delay = animation.duration, destroyInactiveItems = function () {
2641                let i = forDestruction.length;
2642                while (i--) {
2643                    // When resizing rapidly, the same items
2644                    // may be destroyed in different timeouts,
2645                    // or the may be reactivated
2646                    if (coll[forDestruction[i]] &&
2647                        !coll[forDestruction[i]].isActive) {
2648                        coll[forDestruction[i]].destroy();
2649                        delete coll[forDestruction[i]];
2650                    }
2651                }
2652            };
2653            objectEach(coll, function (tick, pos) {
2654                if (!tick.isActive) {
2655                    // Render to zero opacity
2656                    tick.render(pos, false, 0);
2657                    tick.isActive = false;
2658                    forDestruction.push(pos);
2659                }
2660            });
2661            // When the objects are finished fading out, destroy them
2662            syncTimeout(destroyInactiveItems, coll === alternateBands ||
2663                !chart.hasRendered ||
2664                !delay ?
2665                0 :
2666                delay);
2667        });
2668        // Set the axis line path
2669        if (axisLine) {
2670            axisLine[axisLine.isPlaced ? 'animate' : 'attr']({
2671                d: this.getLinePath(axisLine.strokeWidth())
2672            });
2673            axisLine.isPlaced = true;
2674            // Show or hide the line depending on options.showEmpty
2675            axisLine[showAxis ? 'show' : 'hide'](showAxis);
2676        }
2677        if (axisTitle && showAxis) {
2678            axisTitle[axisTitle.isNew ? 'attr' : 'animate'](axis.getTitlePosition(axisTitle));
2679            axisTitle.isNew = false;
2680        }
2681        // Stacked totals:
2682        if (stackLabelOptions && stackLabelOptions.enabled && axis.stacking) {
2683            axis.stacking.renderStackTotals();
2684        }
2685        // End stacked totals
2686        // Record old scaling for updating/animation. Pinch base must be
2687        // preserved until the pinch ends.
2688        axis.old = {
2689            len: axis.len,
2690            max: axis.max,
2691            min: axis.min,
2692            transA: axis.transA,
2693            userMax: axis.userMax,
2694            userMin: axis.userMin
2695        };
2696        axis.isDirty = false;
2697        fireEvent(this, 'afterRender');
2698    }
2699    /**
2700     * Redraw the axis to reflect changes in the data or axis extremes. Called
2701     * internally from Highcharts.Chart#redraw.
2702     *
2703     * @private
2704     * @function Highcharts.Axis#redraw
2705     */
2706    redraw() {
2707        if (this.visible) {
2708            // Render the axis
2709            this.render();
2710            // Move plot lines and bands
2711            this.plotLinesAndBands.forEach(function (plotLine) {
2712                plotLine.render();
2713            });
2714        }
2715        // Mark associated series as dirty and ready for redraw
2716        this.series.forEach(function (series) {
2717            series.isDirty = true;
2718        });
2719    }
2720    /**
2721     * Returns an array of axis properties, that should be untouched during
2722     * reinitialization.
2723     *
2724     * @private
2725     * @function Highcharts.Axis#getKeepProps
2726     */
2727    getKeepProps() {
2728        return (this.keepProps || Axis.keepProps);
2729    }
2730    /**
2731     * Destroys an Axis instance. See {@link Axis#remove} for the API endpoint
2732     * to fully remove the axis.
2733     *
2734     * @private
2735     * @function Highcharts.Axis#destroy
2736     *
2737     * @param {boolean} [keepEvents]
2738     * Whether to preserve events, used internally in Axis.update.
2739     */
2740    destroy(keepEvents) {
2741        const axis = this, plotLinesAndBands = axis.plotLinesAndBands, eventOptions = this.eventOptions;
2742        fireEvent(this, 'destroy', { keepEvents: keepEvents });
2743        // Remove the events
2744        if (!keepEvents) {
2745            removeEvent(axis);
2746        }
2747        // Destroy collections
2748        [axis.ticks, axis.minorTicks, axis.alternateBands].forEach(function (coll) {
2749            destroyObjectProperties(coll);
2750        });
2751        if (plotLinesAndBands) {
2752            let i = plotLinesAndBands.length;
2753            while (i--) { // #1975
2754                plotLinesAndBands[i].destroy();
2755            }
2756        }
2757        // Destroy elements
2758        [
2759            'axisLine', 'axisTitle', 'axisGroup',
2760            'gridGroup', 'labelGroup', 'cross', 'scrollbar'
2761        ].forEach(function (prop) {
2762            if (axis[prop]) {
2763                axis[prop] = axis[prop].destroy();
2764            }
2765        });
2766        // Destroy each generated group for plotlines and plotbands
2767        for (const plotGroup in axis.plotLinesAndBandsGroups) { // eslint-disable-line guard-for-in
2768            axis.plotLinesAndBandsGroups[plotGroup] =
2769                axis.plotLinesAndBandsGroups[plotGroup].destroy();
2770        }
2771        // Delete all properties and fall back to the prototype.
2772        objectEach(axis, function (val, key) {
2773            if (axis.getKeepProps().indexOf(key) === -1) {
2774                delete axis[key];
2775            }
2776        });
2777        this.eventOptions = eventOptions;
2778    }
2779    /**
2780     * Internal function to draw a crosshair.
2781     *
2782     * @function Highcharts.Axis#drawCrosshair
2783     *
2784     * @param {Highcharts.PointerEventObject} [e]
2785     * The event arguments from the modified pointer event, extended with
2786     * `chartX` and `chartY`
2787     *
2788     * @param {Highcharts.Point} [point]
2789     * The Point object if the crosshair snaps to points.
2790     *
2791     * @emits Highcharts.Axis#event:afterDrawCrosshair
2792     * @emits Highcharts.Axis#event:drawCrosshair
2793     */
2794    drawCrosshair(e, point) {
2795        const options = this.crosshair, snap = pick(options && options.snap, true), chart = this.chart;
2796        let path, pos, categorized, graphic = this.cross, crossOptions;
2797        fireEvent(this, 'drawCrosshair', { e: e, point: point });
2798        // Use last available event when updating non-snapped crosshairs without
2799        // mouse interaction (#5287)
2800        if (!e) {
2801            e = this.cross && this.cross.e;
2802        }
2803        if (
2804        // Disabled in options
2805        !options ||
2806            // Snap
2807            ((defined(point) || !snap) === false)) {
2808            this.hideCrosshair();
2809        }
2810        else {
2811            // Get the path
2812            if (!snap) {
2813                pos = e &&
2814                    (this.horiz ?
2815                        e.chartX - this.pos :
2816                        this.len - e.chartY + this.pos);
2817            }
2818            else if (defined(point)) {
2819                // #3834
2820                pos = pick(this.coll !== 'colorAxis' ?
2821                    point.crosshairPos : // 3D axis extension
2822                    null, this.isXAxis ?
2823                    point.plotX :
2824                    this.len - point.plotY);
2825            }
2826            if (defined(pos)) {
2827                crossOptions = {
2828                    // Value, only used on radial
2829                    value: point && (this.isXAxis ?
2830                        point.x :
2831                        pick(point.stackY, point.y)),
2832                    translatedValue: pos
2833                };
2834                if (chart.polar) {
2835                    // Additional information required for crosshairs in
2836                    // polar chart
2837                    extend(crossOptions, {
2838                        isCrosshair: true,
2839                        chartX: e && e.chartX,
2840                        chartY: e && e.chartY,
2841                        point: point
2842                    });
2843                }
2844                path = this.getPlotLinePath(crossOptions) ||
2845                    null; // #3189
2846            }
2847            if (!defined(path)) {
2848                this.hideCrosshair();
2849                return;
2850            }
2851            categorized = this.categories && !this.isRadial;
2852            // Draw the cross
2853            if (!graphic) {
2854                this.cross = graphic = chart.renderer
2855                    .path()
2856                    .addClass('highcharts-crosshair highcharts-crosshair-' +
2857                    (categorized ? 'category ' : 'thin ') +
2858                    (options.className || ''))
2859                    .attr({
2860                    zIndex: pick(options.zIndex, 2)
2861                })
2862                    .add();
2863                // Presentational attributes
2864                if (!chart.styledMode) {
2865                    graphic.attr({
2866                        stroke: options.color ||
2867                            (categorized ?
2868                                Color
2869                                    .parse("#ccd3ff" /* Palette.highlightColor20 */)
2870                                    .setOpacity(0.25)
2871                                    .get() :
2872                                "#cccccc" /* Palette.neutralColor20 */),
2873                        'stroke-width': pick(options.width, 1)
2874                    }).css({
2875                        'pointer-events': 'none'
2876                    });
2877                    if (options.dashStyle) {
2878                        graphic.attr({
2879                            dashstyle: options.dashStyle
2880                        });
2881                    }
2882                }
2883            }
2884            graphic.show().attr({
2885                d: path
2886            });
2887            if (categorized && !options.width) {
2888                graphic.attr({
2889                    'stroke-width': this.transA
2890                });
2891            }
2892            this.cross.e = e;
2893        }
2894        fireEvent(this, 'afterDrawCrosshair', { e: e, point: point });
2895    }
2896    /**
2897     * Hide the crosshair if visible.
2898     *
2899     * @function Highcharts.Axis#hideCrosshair
2900     */
2901    hideCrosshair() {
2902        if (this.cross) {
2903            this.cross.hide();
2904        }
2905        fireEvent(this, 'afterHideCrosshair');
2906    }
2907    /**
2908     * Update an axis object with a new set of options. The options are merged
2909     * with the existing options, so only new or altered options need to be
2910     * specified.
2911     *
2912     * @sample highcharts/members/axis-update/
2913     *         Axis update demo
2914     *
2915     * @function Highcharts.Axis#update
2916     *
2917     * @param {Highcharts.AxisOptions} options
2918     * The new options that will be merged in with existing options on the axis.
2919     *
2920     * @param {boolean} [redraw=true]
2921     * Whether to redraw the chart after the axis is altered. If doing more
2922     * operations on the chart, it is a good idea to set redraw to false and
2923     * call {@link Chart#redraw} after.
2924     */
2925    update(options, redraw) {
2926        const chart = this.chart;
2927        options = merge(this.userOptions, options);
2928        this.destroy(true);
2929        this.init(chart, options);
2930        chart.isDirtyBox = true;
2931        if (pick(redraw, true)) {
2932            chart.redraw();
2933        }
2934    }
2935    /**
2936     * Remove the axis from the chart.
2937     *
2938     * @sample highcharts/members/chart-addaxis/
2939     *         Add and remove axes
2940     *
2941     * @function Highcharts.Axis#remove
2942     *
2943     * @param {boolean} [redraw=true]
2944     * Whether to redraw the chart following the remove.
2945     */
2946    remove(redraw) {
2947        const chart = this.chart, coll = this.coll, axisSeries = this.series;
2948        let i = axisSeries.length;
2949        // Remove associated series (#2687)
2950        while (i--) {
2951            if (axisSeries[i]) {
2952                axisSeries[i].remove(false);
2953            }
2954        }
2955        // Remove the axis
2956        erase(chart.axes, this);
2957        erase(chart[coll] || [], this);
2958        chart.orderItems(coll);
2959        this.destroy();
2960        chart.isDirtyBox = true;
2961        if (pick(redraw, true)) {
2962            chart.redraw();
2963        }
2964    }
2965    /**
2966     * Update the axis title by options after render time.
2967     *
2968     * @sample highcharts/members/axis-settitle/
2969     *         Set a new Y axis title
2970     *
2971     * @function Highcharts.Axis#setTitle
2972     *
2973     * @param {Highcharts.AxisTitleOptions} titleOptions
2974     * The additional title options.
2975     *
2976     * @param {boolean} [redraw=true]
2977     * Whether to redraw the chart after setting the title.
2978     */
2979    setTitle(titleOptions, redraw) {
2980        this.update({ title: titleOptions }, redraw);
2981    }
2982    /**
2983     * Set new axis categories and optionally redraw.
2984     *
2985     * @sample highcharts/members/axis-setcategories/
2986     *         Set categories by click on a button
2987     *
2988     * @function Highcharts.Axis#setCategories
2989     *
2990     * @param {Array<string>} categories
2991     * The new categories.
2992     *
2993     * @param {boolean} [redraw=true]
2994     * Whether to redraw the chart.
2995     */
2996    setCategories(categories, redraw) {
2997        this.update({ categories: categories }, redraw);
2998    }
2999}
3000/* *
3001 *
3002 *  Static Properties
3003 *
3004 * */
3005// Properties to survive after destroy, needed for Axis.update (#4317,
3006// #5773, #5881).
3007Axis.keepProps = [
3008    'coll',
3009    'extKey',
3010    'hcEvents',
3011    'len',
3012    'names',
3013    'series',
3014    'userMax',
3015    'userMin'
3016];
3017/* *
3018 *
3019 *  Default Export
3020 *
3021 * */
3022export default Axis;
3023/* *
3024 *
3025 *  API Declarations
3026 *
3027 * */
3028/**
3029 * Options for the path on the Axis to be calculated.
3030 * @interface Highcharts.AxisPlotLinePathOptionsObject
3031 */ /**
3032* Axis value.
3033* @name Highcharts.AxisPlotLinePathOptionsObject#value
3034* @type {number|undefined}
3035*/ /**
3036* Line width used for calculation crisp line coordinates. Defaults to 1.
3037* @name Highcharts.AxisPlotLinePathOptionsObject#lineWidth
3038* @type {number|undefined}
3039*/ /**
3040* If `false`, the function will return null when it falls outside the axis
3041* bounds. If `true`, the function will return a path aligned to the plot area
3042* sides if it falls outside. If `pass`, it will return a path outside.
3043* @name Highcharts.AxisPlotLinePathOptionsObject#force
3044* @type {string|boolean|undefined}
3045*/ /**
3046* Used in Highcharts Stock. When `true`, plot paths
3047* (crosshair, plotLines, gridLines)
3048* will be rendered on all axes when defined on the first axis.
3049* @name Highcharts.AxisPlotLinePathOptionsObject#acrossPanes
3050* @type {boolean|undefined}
3051*/ /**
3052* Use old coordinates (for resizing and rescaling).
3053* If not set, defaults to `false`.
3054* @name Highcharts.AxisPlotLinePathOptionsObject#old
3055* @type {boolean|undefined}
3056*/ /**
3057* If given, return the plot line path of a pixel position on the axis.
3058* @name Highcharts.AxisPlotLinePathOptionsObject#translatedValue
3059* @type {number|undefined}
3060*/ /**
3061* Used in Polar axes. Reverse the positions for concatenation of polygonal
3062* plot bands
3063* @name Highcharts.AxisPlotLinePathOptionsObject#reverse
3064* @type {boolean|undefined}
3065*/
3066/**
3067 * Options for crosshairs on axes.
3068 *
3069 * @product highstock
3070 *
3071 * @typedef {Highcharts.XAxisCrosshairOptions|Highcharts.YAxisCrosshairOptions} Highcharts.AxisCrosshairOptions
3072 */
3073/**
3074 * @typedef {"navigator"|"pan"|"rangeSelectorButton"|"rangeSelectorInput"|"scrollbar"|"traverseUpButton"|"zoom"} Highcharts.AxisExtremesTriggerValue
3075 */
3076/**
3077 * @callback Highcharts.AxisEventCallbackFunction
3078 *
3079 * @param {Highcharts.Axis} this
3080 */
3081/**
3082 * @callback Highcharts.AxisLabelsFormatterCallbackFunction
3083 *
3084 * @param {Highcharts.AxisLabelsFormatterContextObject} this
3085 *
3086 * @param {Highcharts.AxisLabelsFormatterContextObject} ctx
3087 *
3088 * @return {string}
3089 */
3090/**
3091 * @interface Highcharts.AxisLabelsFormatterContextObject
3092 */ /**
3093* The axis item of the label
3094* @name Highcharts.AxisLabelsFormatterContextObject#axis
3095* @type {Highcharts.Axis}
3096*/ /**
3097* The chart instance.
3098* @name Highcharts.AxisLabelsFormatterContextObject#chart
3099* @type {Highcharts.Chart}
3100*/ /**
3101* Default formatting of date/time labels.
3102* @name Highcharts.AxisLabelsFormatterContextObject#dateTimeLabelFormat
3103* @type {string|undefined}
3104*/ /**
3105* Whether the label belongs to the first tick on the axis.
3106* @name Highcharts.AxisLabelsFormatterContextObject#isFirst
3107* @type {boolean}
3108*/ /**
3109* Whether the label belongs to the last tick on the axis.
3110* @name Highcharts.AxisLabelsFormatterContextObject#isLast
3111* @type {boolean}
3112*/ /**
3113* The position on the axis in terms of axis values. For category axes, a
3114* zero-based index. For datetime axes, the JavaScript time in milliseconds
3115* since 1970.
3116* @name Highcharts.AxisLabelsFormatterContextObject#pos
3117* @type {number}
3118*/ /**
3119* The preformatted text as the result of the default formatting. For example
3120* dates will be formatted as strings, and numbers with language-specific comma
3121* separators, thousands separators and numeric symbols like `k` or `M`.
3122* @name Highcharts.AxisLabelsFormatterContextObject#text
3123* @type {string|undefined}
3124*/ /**
3125* The Tick instance.
3126* @name Highcharts.AxisLabelsFormatterContextObject#tick
3127* @type {Highcharts.Tick}
3128*/ /**
3129* This can be either a numeric value or a category string.
3130* @name Highcharts.AxisLabelsFormatterContextObject#value
3131* @type {number|string}
3132*/
3133/**
3134 * Options for axes.
3135 *
3136 * @typedef {Highcharts.XAxisOptions|Highcharts.YAxisOptions|Highcharts.ZAxisOptions} Highcharts.AxisOptions
3137 */
3138/**
3139 * @callback Highcharts.AxisPointBreakEventCallbackFunction
3140 *
3141 * @param {Highcharts.Axis} this
3142 *
3143 * @param {Highcharts.AxisPointBreakEventObject} evt
3144 */
3145/**
3146 * @interface Highcharts.AxisPointBreakEventObject
3147 */ /**
3148* @name Highcharts.AxisPointBreakEventObject#brk
3149* @type {Highcharts.Dictionary<number>}
3150*/ /**
3151* @name Highcharts.AxisPointBreakEventObject#point
3152* @type {Highcharts.Point}
3153*/ /**
3154* @name Highcharts.AxisPointBreakEventObject#preventDefault
3155* @type {Function}
3156*/ /**
3157* @name Highcharts.AxisPointBreakEventObject#target
3158* @type {Highcharts.SVGElement}
3159*/ /**
3160* @name Highcharts.AxisPointBreakEventObject#type
3161* @type {"pointBreak"|"pointInBreak"}
3162*/
3163/**
3164 * @callback Highcharts.AxisSetExtremesEventCallbackFunction
3165 *
3166 * @param {Highcharts.Axis} this
3167 *
3168 * @param {Highcharts.AxisSetExtremesEventObject} evt
3169 */
3170/**
3171 * @interface Highcharts.AxisSetExtremesEventObject
3172 * @extends Highcharts.ExtremesObject
3173 */ /**
3174* @name Highcharts.AxisSetExtremesEventObject#preventDefault
3175* @type {Function}
3176*/ /**
3177* @name Highcharts.AxisSetExtremesEventObject#target
3178* @type {Highcharts.SVGElement}
3179*/ /**
3180* @name Highcharts.AxisSetExtremesEventObject#trigger
3181* @type {Highcharts.AxisExtremesTriggerValue|string}
3182*/ /**
3183* @name Highcharts.AxisSetExtremesEventObject#type
3184* @type {"setExtremes"}
3185*/
3186/**
3187 * @callback Highcharts.AxisTickPositionerCallbackFunction
3188 *
3189 * @param {Highcharts.Axis} this
3190 *
3191 * @return {Highcharts.AxisTickPositionsArray}
3192 */
3193/**
3194 * @interface Highcharts.AxisTickPositionsArray
3195 * @augments Array<number>
3196 */
3197/**
3198 * @typedef {"high"|"low"|"middle"} Highcharts.AxisTitleAlignValue
3199 */
3200/**
3201 * @typedef {Highcharts.XAxisTitleOptions|Highcharts.YAxisTitleOptions|Highcharts.ZAxisTitleOptions} Highcharts.AxisTitleOptions
3202 */
3203/**
3204 * @typedef {"linear"|"logarithmic"|"datetime"|"category"|"treegrid"} Highcharts.AxisTypeValue
3205 */
3206/**
3207 * The returned object literal from the {@link Highcharts.Axis#getExtremes}
3208 * function.
3209 *
3210 * @interface Highcharts.ExtremesObject
3211 */ /**
3212* The maximum value of the axis' associated series.
3213* @name Highcharts.ExtremesObject#dataMax
3214* @type {number}
3215*/ /**
3216* The minimum value of the axis' associated series.
3217* @name Highcharts.ExtremesObject#dataMin
3218* @type {number}
3219*/ /**
3220* The maximum axis value, either automatic or set manually. If the `max` option
3221* is not set, `maxPadding` is 0 and `endOnTick` is false, this value will be
3222* the same as `dataMax`.
3223* @name Highcharts.ExtremesObject#max
3224* @type {number}
3225*/ /**
3226* The minimum axis value, either automatic or set manually. If the `min` option
3227* is not set, `minPadding` is 0 and `startOnTick` is false, this value will be
3228* the same as `dataMin`.
3229* @name Highcharts.ExtremesObject#min
3230* @type {number}
3231*/ /**
3232* The user defined maximum, either from the `max` option or from a zoom or
3233* `setExtremes` action.
3234* @name Highcharts.ExtremesObject#userMax
3235* @type {number|undefined}
3236*/ /**
3237* The user defined minimum, either from the `min` option or from a zoom or
3238* `setExtremes` action.
3239* @name Highcharts.ExtremesObject#userMin
3240* @type {number|undefined}
3241*/
3242/**
3243 * Formatter function for the text of a crosshair label.
3244 *
3245 * @callback Highcharts.XAxisCrosshairLabelFormatterCallbackFunction
3246 *
3247 * @param {Highcharts.Axis} this
3248 * Axis context
3249 *
3250 * @param {number} value
3251 * Y value of the data point
3252 *
3253 * @return {string}
3254 */
3255''; // Keeps doclets above in JS file

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.