PageSourceSearch

https://provence-alpes-cotedazur.com/app/dist/crt-paca/addons/wood…/code/es-modules/Core/Chart/Chart.js

js provence-alpes-cotedazur.com collected 2026-10-02 03:27:49 UTC 117,717 bytes, 2,974 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 { animate, animObject, setAnimation } = A;
13import Axis from '../Axis/Axis.js';
14import D from '../Defaults.js';
15const { defaultOptions } = D;
16import Templating from '../Templating.js';
17const { numberFormat } = Templating;
18import Foundation from '../Foundation.js';
19const { registerEventOptions } = Foundation;
20import H from '../Globals.js';
21const { charts, doc, marginNames, svg, win } = H;
22import RendererRegistry from '../Renderer/RendererRegistry.js';
23import Series from '../Series/Series.js';
24import SeriesRegistry from '../Series/SeriesRegistry.js';
25const { seriesTypes } = SeriesRegistry;
26import SVGRenderer from '../Renderer/SVG/SVGRenderer.js';
27import Time from '../Time.js';
28import U from '../Utilities.js';
29import AST from '../Renderer/HTML/AST.js';
30import Tick from '../Axis/Tick.js';
31const { addEvent, attr, createElement, css, defined, diffObjects, discardElement, erase, error, extend, find, fireEvent, getAlignFactor, getStyle, isArray, isNumber, isObject, isString, merge, objectEach, pick, pInt, relativeLength, removeEvent, splat, syncTimeout, uniqueKey } = U;
32/* *
33 *
34 *  Class
35 *
36 * */
37/* eslint-disable no-invalid-this, valid-jsdoc */
38/**
39 * The Chart class. The recommended constructor is {@link Highcharts#chart}.
40 *
41 * @example
42 * let chart = Highcharts.chart('container', {
43 *        title: {
44 *               text: 'My chart'
45 *        },
46 *        series: [{
47 *            data: [1, 3, 2, 4]
48 *        }]
49 * })
50 *
51 * @class
52 * @name Highcharts.Chart
53 *
54 * @param {string|Highcharts.HTMLDOMElement} [renderTo]
55 *        The DOM element to render to, or its id.
56 *
57 * @param {Highcharts.Options} options
58 *        The chart options structure.
59 *
60 * @param {Highcharts.ChartCallbackFunction} [callback]
61 *        Function to run when the chart has loaded and all external images
62 *        are loaded. Defining a
63 *        [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
64 *        handler is equivalent.
65 */
66class Chart {
67    /**
68     * Factory function for basic charts.
69     *
70     * @example
71     * // Render a chart in to div#container
72     * let chart = Highcharts.chart('container', {
73     *     title: {
74     *         text: 'My chart'
75     *     },
76     *     series: [{
77     *         data: [1, 3, 2, 4]
78     *     }]
79     * });
80     *
81     * @function Highcharts.chart
82     *
83     * @param {string|Highcharts.HTMLDOMElement} [renderTo]
84     * The DOM element to render to, or its id.
85     *
86     * @param {Highcharts.Options} options
87     * The chart options structure.
88     *
89     * @param {Highcharts.ChartCallbackFunction} [callback]
90     * Function to run when the chart has loaded and all external images are
91     * loaded. Defining a
92     * [chart.events.load](https://api.highcharts.com/highcharts/chart.events.load)
93     * handler is equivalent.
94     *
95     * @return {Highcharts.Chart}
96     * Returns the Chart object.
97     */
98    static chart(a, b, c) {
99        return new Chart(a, b, c);
100    }
101    // Implementation
102    constructor(a, 
103    /* eslint-disable @typescript-eslint/no-unused-vars */
104    b, c
105    /* eslint-enable @typescript-eslint/no-unused-vars */
106    ) {
107        this.sharedClips = {};
108        const args = [
109            // ES5 builds fail unless we cast it to an Array
110            ...arguments
111        ];
112        // Remove the optional first argument, renderTo, and set it on this.
113        if (isString(a) || a.nodeName) {
114            this.renderTo = args.shift();
115        }
116        this.init(args[0], args[1]);
117    }
118    /* *
119     *
120     *  Functions
121     *
122     * */
123    /**
124     * Function setting zoom options after chart init and after chart update.
125     * Offers support for deprecated options.
126     *
127     * @private
128     * @function Highcharts.Chart#setZoomOptions
129     */
130    setZoomOptions() {
131        const chart = this, options = chart.options.chart, zooming = options.zooming;
132        chart.zooming = {
133            ...zooming,
134            type: pick(options.zoomType, zooming.type),
135            key: pick(options.zoomKey, zooming.key),
136            pinchType: pick(options.pinchType, zooming.pinchType),
137            singleTouch: pick(options.zoomBySingleTouch, zooming.singleTouch, false),
138            resetButton: merge(zooming.resetButton, options.resetZoomButton)
139        };
140    }
141    /**
142     * Overridable function that initializes the chart. The constructor's
143     * arguments are passed on directly.
144     *
145     * @function Highcharts.Chart#init
146     *
147     * @param {Highcharts.Options} userOptions
148     *        Custom options.
149     *
150     * @param {Function} [callback]
151     *        Function to run when the chart has loaded and all external
152     *        images are loaded.
153     *
154     *
155     * @emits Highcharts.Chart#event:init
156     * @emits Highcharts.Chart#event:afterInit
157     */
158    init(userOptions, callback) {
159        // Fire the event with a default function
160        fireEvent(this, 'init', { args: arguments }, function () {
161            const options = merge(defaultOptions, userOptions), // Do the merge
162            optionsChart = options.chart, renderTo = this.renderTo || optionsChart.renderTo;
163            /**
164             * The original options given to the constructor or a chart factory
165             * like {@link Highcharts.chart} and {@link Highcharts.stockChart}.
166             * The original options are shallow copied to avoid mutation. The
167             * copy, `chart.userOptions`, may later be mutated to reflect
168             * updated options throughout the lifetime of the chart.
169             *
170             * For collections, like `series`, `xAxis` and `yAxis`, the chart
171             * user options should always be reflected by the item user option,
172             * so for example the following should always be true:
173             *
174             * `chart.xAxis[0].userOptions === chart.userOptions.xAxis[0]`
175             *
176             * @name Highcharts.Chart#userOptions
177             * @type {Highcharts.Options}
178             */
179            this.userOptions = extend({}, userOptions);
180            if (!(this.renderTo = (isString(renderTo) ?
181                doc.getElementById(renderTo) :
182                renderTo))) {
183                // Display an error if the renderTo is wrong
184                error(13, true, this);
185            }
186            this.margin = [];
187            this.spacing = [];
188            // An array of functions that returns labels that should be
189            // considered for anti-collision
190            this.labelCollectors = [];
191            this.callback = callback;
192            this.isResizing = 0;
193            /**
194             * The options structure for the chart after merging
195             * {@link #defaultOptions} and {@link #userOptions}. It contains
196             * members for the sub elements like series, legend, tooltip etc.
197             *
198             * @name Highcharts.Chart#options
199             * @type {Highcharts.Options}
200             */
201            this.options = options;
202            /**
203             * All the axes in the chart.
204             *
205             * @see  Highcharts.Chart.xAxis
206             * @see  Highcharts.Chart.yAxis
207             *
208             * @name Highcharts.Chart#axes
209             * @type {Array<Highcharts.Axis>}
210             */
211            this.axes = [];
212            /**
213             * All the current series in the chart.
214             *
215             * @name Highcharts.Chart#series
216             * @type {Array<Highcharts.Series>}
217             */
218            this.series = [];
219            this.locale = options.lang.locale ??
220                this.renderTo.closest('[lang]')?.lang;
221            /**
222             * The `Time` object associated with the chart. Since v6.0.5,
223             * time settings can be applied individually for each chart. If
224             * no individual settings apply, the `Time` object is shared by
225             * all instances.
226             *
227             * @name Highcharts.Chart#time
228             * @type {Highcharts.Time}
229             */
230            this.time = new Time(extend(options.time || {}, {
231                locale: this.locale
232            }));
233            options.time = this.time.options;
234            /**
235             * Callback function to override the default function that formats
236             * all the numbers in the chart. Returns a string with the formatted
237             * number.
238             *
239             * @name Highcharts.Chart#numberFormatter
240             * @type {Highcharts.NumberFormatterCallbackFunction}
241             */
242            this.numberFormatter = (optionsChart.numberFormatter || numberFormat).bind(this);
243            /**
244             * Whether the chart is in styled mode, meaning all presentational
245             * attributes are avoided.
246             *
247             * @name Highcharts.Chart#styledMode
248             * @type {boolean}
249             */
250            this.styledMode = optionsChart.styledMode;
251            this.hasCartesianSeries = optionsChart.showAxes;
252            const chart = this;
253            /**
254             * Index position of the chart in the {@link Highcharts#charts}
255             * property.
256             *
257             * @name Highcharts.Chart#index
258             * @type {number}
259             * @readonly
260             */
261            chart.index = charts.length; // Add the chart to the global lookup
262            charts.push(chart);
263            H.chartCount++;
264            // Chart event handlers
265            registerEventOptions(this, optionsChart);
266            /**
267             * A collection of the X axes in the chart.
268             *
269             * @name Highcharts.Chart#xAxis
270             * @type {Array<Highcharts.Axis>}
271             */
272            chart.xAxis = [];
273            /**
274             * A collection of the Y axes in the chart.
275             *
276             * @name Highcharts.Chart#yAxis
277             * @type {Array<Highcharts.Axis>}
278             *
279             * @todo
280             * Make events official: Fire the event `afterInit`.
281             */
282            chart.yAxis = [];
283            chart.pointCount = chart.colorCounter = chart.symbolCounter = 0;
284            this.setZoomOptions();
285            // Fire after init but before first render, before axes and series
286            // have been initialized.
287            fireEvent(chart, 'afterInit');
vendor: 14,146 bytes, lines 288-656
288            chart.firstRender();
289        });
290    }
291    /**
292     * Internal function to unitialize an individual series.
293     *
294     * @private
295     * @function Highcharts.Chart#initSeries
296     */
297    initSeries(options) {
298        const chart = this, optionsChart = chart.options.chart, type = (options.type ||
299            optionsChart.type), SeriesClass = seriesTypes[type];
300        // No such series type
301        if (!SeriesClass) {
302            error(17, true, chart, { missingModuleFor: type });
303        }
304        const series = new SeriesClass();
305        if (typeof series.init === 'function') {
306            series.init(chart, options);
307        }
308        return series;
309    }
310    /**
311     * Internal function to set data for all series with enabled sorting.
312     *
313     * @private
314     * @function Highcharts.Chart#setSortedData
315     */
316    setSortedData() {
317        this.getSeriesOrderByLinks().forEach(function (series) {
318            // We need to set data for series with sorting after series init
319            if (!series.points && !series.data && series.enabledDataSorting) {
320                series.setData(series.options.data, false);
321            }
322        });
323    }
324    /**
325     * Sort and return chart series in order depending on the number of linked
326     * series.
327     *
328     * @private
329     * @function Highcharts.Series#getSeriesOrderByLinks
330     */
331    getSeriesOrderByLinks() {
332        return this.series.concat().sort(function (a, b) {
333            if (a.linkedSeries.length || b.linkedSeries.length) {
334                return b.linkedSeries.length - a.linkedSeries.length;
335            }
336            return 0;
337        });
338    }
339    /**
340     * Order all series or axes above a given index. When series or axes are
341     * added and ordered by configuration, only the last series is handled
342     * (#248, #1123, #2456, #6112). This function is called on series and axis
343     * initialization and destroy.
344     *
345     * @private
346     * @function Highcharts.Chart#orderItems
347     * @param {string} coll The collection name
348     * @param {number} [fromIndex=0]
349     * If this is given, only the series above this index are handled.
350     */
351    orderItems(coll, fromIndex = 0) {
352        const collection = this[coll], 
353        // Item options should be reflected in chart.options.series,
354        // chart.options.yAxis etc
355        optionsArray = this.options[coll] = splat(this.options[coll])
356            .slice(), userOptionsArray = this.userOptions[coll] = this.userOptions[coll] ?
357            splat(this.userOptions[coll]).slice() :
358            [];
359        if (this.hasRendered) {
360            // Remove all above index
361            optionsArray.splice(fromIndex);
362            userOptionsArray.splice(fromIndex);
363        }
364        if (collection) {
365            for (let i = fromIndex, iEnd = collection.length; i < iEnd; ++i) {
366                const item = collection[i];
367                if (item) {
368                    /**
369                     * Contains the series' index in the `Chart.series` array.
370                     *
371                     * @name Highcharts.Series#index
372                     * @type {number}
373                     * @readonly
374                     */
375                    item.index = i;
376                    if (item instanceof Series) {
377                        item.name = item.getName();
378                    }
379                    if (!item.options.isInternal) {
380                        optionsArray[i] = item.options;
381                        userOptionsArray[i] = item.userOptions;
382                    }
383                }
384            }
385        }
386    }
387    /**
388     * Check whether a given point is within the plot area.
389     *
390     * @function Highcharts.Chart#isInsidePlot
391     *
392     * @param {number} plotX
393     * Pixel x relative to the plot area.
394     *
395     * @param {number} plotY
396     * Pixel y relative to the plot area.
397     *
398     * @param {Highcharts.ChartIsInsideOptionsObject} [options]
399     * Options object.
400     *
401     * @return {boolean}
402     * Returns true if the given point is inside the plot area.
403     */
404    isInsidePlot(plotX, plotY, options = {}) {
405        const { inverted, plotBox, plotLeft, plotTop, scrollablePlotBox } = this, { scrollLeft = 0, scrollTop = 0 } = (options.visiblePlotOnly &&
406            this.scrollablePlotArea?.scrollingContainer) || {}, series = options.series, box = (options.visiblePlotOnly && scrollablePlotBox) || plotBox, x = options.inverted ? plotY : plotX, y = options.inverted ? plotX : plotY, e = {
407            x,
408            y,
409            isInsidePlot: true,
410            options
411        };
412        if (!options.ignoreX) {
413            const xAxis = (series &&
414                (inverted && !this.polar ? series.yAxis : series.xAxis)) || {
415                pos: plotLeft,
416                len: Infinity
417            };
418            const chartX = options.paneCoordinates ?
419                xAxis.pos + x : plotLeft + x;
420            if (!(chartX >= Math.max(scrollLeft + plotLeft, xAxis.pos) &&
421                chartX <= Math.min(scrollLeft + plotLeft + box.width, xAxis.pos + xAxis.len))) {
422                e.isInsidePlot = false;
423            }
424        }
425        if (!options.ignoreY && e.isInsidePlot) {
426            const yAxis = (!inverted && options.axis &&
427                !options.axis.isXAxis && options.axis) || (series && (inverted ? series.xAxis : series.yAxis)) || {
428                pos: plotTop,
429                len: Infinity
430            };
431            const chartY = options.paneCoordinates ?
432                yAxis.pos + y : plotTop + y;
433            if (!(chartY >= Math.max(scrollTop + plotTop, yAxis.pos) &&
434                chartY <= Math.min(scrollTop + plotTop + box.height, yAxis.pos + yAxis.len))) {
435                e.isInsidePlot = false;
436            }
437        }
438        fireEvent(this, 'afterIsInsidePlot', e);
439        return e.isInsidePlot;
440    }
441    /**
442     * Redraw the chart after changes have been done to the data, axis extremes
443     * chart size or chart elements. All methods for updating axes, series or
444     * points have a parameter for redrawing the chart. This is `true` by
445     * default. But in many cases you want to do more than one operation on the
446     * chart before redrawing, for example add a number of points. In those
447     * cases it is a waste of resources to redraw the chart for each new point
448     * added. So you add the points and call `chart.redraw()` after.
449     *
450     * @function Highcharts.Chart#redraw
451     *
452     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
453     * If or how to apply animation to the redraw. When `undefined`, it applies
454     * the animation that is set in the `chart.animation` option.
455     *
456     * @emits Highcharts.Chart#event:afterSetExtremes
457     * @emits Highcharts.Chart#event:beforeRedraw
458     * @emits Highcharts.Chart#event:predraw
459     * @emits Highcharts.Chart#event:redraw
460     * @emits Highcharts.Chart#event:render
461     * @emits Highcharts.Chart#event:updatedData
462     */
463    redraw(animation) {
464        fireEvent(this, 'beforeRedraw');
465        const chart = this, axes = chart.hasCartesianSeries ? chart.axes : chart.colorAxis || [], series = chart.series, pointer = chart.pointer, legend = chart.legend, legendUserOptions = chart.userOptions.legend, renderer = chart.renderer, isHiddenChart = renderer.isHidden(), afterRedraw = [];
466        let hasDirtyStacks, hasStackedSeries, i, isDirtyBox = chart.isDirtyBox, redrawLegend = chart.isDirtyLegend, serie;
467        renderer.rootFontSize = renderer.boxWrapper.getStyle('font-size');
468        // Handle responsive rules, not only on resize (#6130)
469        if (chart.setResponsive) {
470            chart.setResponsive(false);
471        }
472        // Set the global animation. When chart.hasRendered is not true, the
473        // redraw call comes from a responsive rule and animation should not
474        // occur.
475        setAnimation(chart.hasRendered ? animation : false, chart);
476        if (isHiddenChart) {
477            chart.temporaryDisplay();
478        }
479        // Adjust title layout (reflow multiline text)
480        chart.layOutTitles(false);
481        // Link stacked series
482        i = series.length;
483        while (i--) {
484            serie = series[i];
485            if (serie.options.stacking || serie.options.centerInCategory) {
486                hasStackedSeries = true;
487                if (serie.isDirty) {
488                    hasDirtyStacks = true;
489                    break;
490                }
491            }
492        }
493        if (hasDirtyStacks) { // Mark others as dirty
494            i = series.length;
495            while (i--) {
496                serie = series[i];
497                if (serie.options.stacking) {
498                    serie.isDirty = true;
499                }
500            }
501        }
502        // Handle updated data in the series
503        series.forEach(function (serie) {
504            if (serie.isDirty) {
505                if (serie.options.legendType === 'point') {
506                    if (typeof serie.updateTotals === 'function') {
507                        serie.updateTotals();
508                    }
509                    redrawLegend = true;
510                }
511                else if (legendUserOptions &&
512                    (!!legendUserOptions.labelFormatter ||
513                        legendUserOptions.labelFormat)) {
514                    redrawLegend = true; // #2165
515                }
516            }
517            if (serie.isDirtyData) {
518                fireEvent(serie, 'updatedData');
519            }
520        });
521        // Handle added or removed series
522        if (redrawLegend && legend && legend.options.enabled) {
523            // Draw legend graphics
524            legend.render();
525            chart.isDirtyLegend = false;
526        }
527        // Reset stacks
528        if (hasStackedSeries) {
529            chart.getStacks();
530        }
531        // Set axes scales
532        axes.forEach(function (axis) {
533            axis.updateNames();
534            axis.setScale();
535        });
536        chart.getMargins(); // #3098
537        // If one axis is dirty, all axes must be redrawn (#792, #2169)
538        axes.forEach(function (axis) {
539            if (axis.isDirty) {
540                isDirtyBox = true;
541            }
542        });
543        // Redraw axes
544        axes.forEach(function (axis) {
545            // Fire 'afterSetExtremes' only if extremes are set
546            const key = axis.min + ',' + axis.max;
547            if (axis.extKey !== key) { // #821, #4452
548                axis.extKey = key;
549                // Prevent a recursive call to chart.redraw() (#1119)
550                afterRedraw.push(function () {
551                    fireEvent(axis, 'afterSetExtremes', extend(axis.eventArgs, axis.getExtremes())); // #747, #751
552                    delete axis.eventArgs;
553                });
554            }
555            if (isDirtyBox || hasStackedSeries) {
556                axis.redraw();
557            }
558        });
559        // The plot areas size has changed
560        if (isDirtyBox) {
561            chart.drawChartBox();
562        }
563        // Fire an event before redrawing series, used by the boost module to
564        // clear previous series renderings.
565        fireEvent(chart, 'predraw');
566        // Redraw affected series
567        series.forEach(function (serie) {
568            if ((isDirtyBox || serie.isDirty) && serie.visible) {
569                serie.redraw();
570            }
571            // Set it here, otherwise we will have unlimited 'updatedData' calls
572            // for a hidden series after setData(). Fixes #6012
573            serie.isDirtyData = false;
574        });
575        // Move tooltip or reset
576        if (pointer) {
577            pointer.reset(true);
578        }
579        // Redraw if canvas
580        renderer.draw();
581        // Fire the events
582        fireEvent(chart, 'redraw');
583        fireEvent(chart, 'render');
584        if (isHiddenChart) {
585            chart.temporaryDisplay(true);
586        }
587        // Fire callbacks that are put on hold until after the redraw
588        afterRedraw.forEach(function (callback) {
589            callback.call();
590        });
591    }
592    /**
593     * Get an axis, series or point object by `id` as given in the configuration
594     * options. Returns `undefined` if no item is found.
595     *
596     * @sample highcharts/plotoptions/series-id/
597     *         Get series by id
598     *
599     * @function Highcharts.Chart#get
600     *
601     * @param {string} id
602     * The id as given in the configuration options.
603     *
604     * @return {Highcharts.Axis|Highcharts.Series|Highcharts.Point|undefined}
605     * The retrieved item.
606     */
607    get(id) {
608        const series = this.series;
609        /**
610         * @private
611         */
612        function itemById(item) {
613            return (item.id === id ||
614                (item.options && item.options.id === id));
615        }
616        let ret = 
617        // Search axes
618        find(this.axes, itemById) ||
619            // Search series
620            find(this.series, itemById);
621        // Search points
622        for (let i = 0; !ret && i < series.length; i++) {
623            ret = find(series[i].points || [], itemById);
624        }
625        return ret;
626    }
627    /**
628     * Create the Axis instances based on the config options.
629     *
630     * @private
631     * @function Highcharts.Chart#createAxes
632     * @emits Highcharts.Chart#event:afterCreateAxes
633     * @emits Highcharts.Chart#event:createAxes
634     */
635    createAxes() {
636        const options = this.userOptions;
637        fireEvent(this, 'createAxes');
638        for (const coll of ['xAxis', 'yAxis']) {
639            const arr = options[coll] = splat(options[coll] || {});
640            for (const axisOptions of arr) {
641                // eslint-disable-next-line no-new
642                new Axis(this, axisOptions, coll);
643            }
644        }
645        fireEvent(this, 'afterCreateAxes');
646    }
647    /**
648     * Returns an array of all currently selected points in the chart. Points
649     * can be selected by clicking or programmatically by the
650     * {@link Highcharts.Point#select}
651     * function.
652     *
653     * @sample highcharts/plotoptions/series-allowpointselect-line/
654     *         Get selected points
655     * @sample highcharts/members/point-select-lasso/
656     *         Lasso selection
657     * @sample highcharts/chart/events-selection-points/
658     *         Rectangle selection
659     *
660     * @function Highcharts.Chart#getSelectedPoints
661     *
662     * @return {Array<Highcharts.Point>}
663     *         The currently selected points.
664     */
665    getSelectedPoints() {
666        return this.series.reduce((acc, series) => {
667            // For one-to-one points inspect series.data in order to retrieve
668            // points outside the visible range (#6445). For grouped data,
669            // inspect the generated series.points.
670            series.getPointsCollection()
671                .forEach((point) => {
672                if (pick(point.selectedStaging, point.selected)) {
673                    acc.push(point);
674                }
675            });
676            return acc;
677        }, []);
678    }
679    /**
680     * Returns an array of all currently selected series in the chart. Series
681     * can be selected either programmatically by the
682     * {@link Highcharts.Series#select}
683     * function or by checking the checkbox next to the legend item if
684     * [series.showCheckBox](https://api.highcharts.com/highcharts/plotOptions.series.showCheckbox)
685     * is true.
686     *
687     * @sample highcharts/members/chart-getselectedseries/
688     *         Get selected series
689     *
690     * @function Highcharts.Chart#getSelectedSeries
691     *
692     * @return {Array<Highcharts.Series>}
693     *         The currently selected series.
694     */
695    getSelectedSeries() {
696        return this.series.filter((s) => s.selected);
697    }
698    /**
699     * Set a new title or subtitle for the chart.
700     *
701     * @sample highcharts/members/chart-settitle/
702     *         Set title text and styles
703     *
704     * @function Highcharts.Chart#setTitle
705     *
706     * @param {Highcharts.TitleOptions} [titleOptions]
707     *        New title options. The title text itself is set by the
708     *        `titleOptions.text` property.
709     *
710     * @param {Highcharts.SubtitleOptions} [subtitleOptions]
711     *        New subtitle options. The subtitle text itself is set by the
712     *        `subtitleOptions.text` property.
713     *
714     * @param {boolean} [redraw]
715     *        Whether to redraw the chart or wait for a later call to
716     *        `chart.redraw()`.
717     */
718    setTitle(titleOptions, subtitleOptions, redraw) {
719        this.applyDescription('title', titleOptions);
720        this.applyDescription('subtitle', subtitleOptions);
721        // The initial call also adds the caption. On update, chart.update will
722        // relay to Chart.setCaption.
723        this.applyDescription('caption', void 0);
724        this.layOutTitles(redraw);
725    }
726    /**
727     * Apply a title, subtitle or caption for the chart
728     *
729     * @private
730     * @function Highcharts.Chart#applyDescription
731     * @param key {string}
732     * Either title, subtitle or caption
733     * @param {Highcharts.TitleOptions|Highcharts.SubtitleOptions|Highcharts.CaptionOptions|undefined} explicitOptions
734     * The options to set, will be merged with default options.
735     */
736    applyDescription(key, explicitOptions) {
737        const chart = this;
738        // Merge default options with explicit options
739        const options = this.options[key] = merge(this.options[key], explicitOptions);
740        let elem = this[key];
741        if (elem && explicitOptions) {
742            this[key] = elem = elem.destroy(); // Remove old
743        }
744        if (options && !elem) {
745            elem = this.renderer.text(options.text, 0, 0, options.useHTML)
746                .attr({
747                align: options.align,
748                'class': 'highcharts-' + key,
749                zIndex: options.zIndex || 4
750            })
751                .css({
752                textOverflow: 'ellipsis',
753                whiteSpace: 'nowrap'
754            })
755                .add();
756            // Update methods, relay to `applyDescription`
757            elem.update = function (updateOptions, redraw) {
758                chart.applyDescription(key, updateOptions);
759                chart.layOutTitles(redraw);
760            };
761            // Presentational
762            if (!this.styledMode) {
763                elem.css(extend(key === 'title' ? {
764                    // #2944
765                    fontSize: this.options.isStock ? '1em' : '1.2em'
766                } : {}, options.style));
767            }
768            // Get unwrapped text length and reset
769            elem.textPxLength = elem.getBBox().width;
770            elem.css({ whiteSpace: options.style?.whiteSpace });
771            /**
772             * The chart title. The title has an `update` method that allows
773             * modifying the options directly or indirectly via
774             * `chart.update`.
775             *
776             * @sample highcharts/members/title-update/
777             *         Updating titles
778             *
779             * @name Highcharts.Chart#title
vendor: 4,865 bytes, lines 780-876
780             * @type {Highcharts.TitleObject}
781             */
782            /**
783             * The chart subtitle. The subtitle has an `update` method that
784             * allows modifying the options directly or indirectly via
785             * `chart.update`.
786             *
787             * @name Highcharts.Chart#subtitle
788             * @type {Highcharts.SubtitleObject}
789             */
790            this[key] = elem;
791        }
792    }
793    /**
794     * Internal function to lay out the chart title, subtitle and caption, and
795     * cache the full offset height for use in `getMargins`. The result is
796     * stored in `this.titleOffset`.
797     *
798     * @private
799     * @function Highcharts.Chart#layOutTitles
800     *
801     * @param {boolean} [redraw=true]
802     * @emits Highcharts.Chart#event:afterLayOutTitles
803     */
804    layOutTitles(redraw = true) {
805        const titleOffset = [0, 0, 0], { options, renderer, spacingBox } = this;
806        // Lay out the title, subtitle and caption respectively
807        ['title', 'subtitle', 'caption'].forEach((key) => {
808            const desc = this[key], descOptions = this.options[key], alignTo = merge(spacingBox), textPxLength = desc?.textPxLength || 0;
809            if (desc && descOptions) {
810                // Provide a hook for the exporting button to shift the title
811                fireEvent(this, 'layOutTitle', { alignTo, key, textPxLength });
812                const fontMetrics = renderer.fontMetrics(desc), baseline = fontMetrics.b, lineHeight = fontMetrics.h, verticalAlign = descOptions.verticalAlign || 'top', topAligned = verticalAlign === 'top', 
813                // Use minScale only for top-aligned titles. It is not
814                // likely that we will need scaling for other positions, but
815                // if it is requested, we need to adjust the vertical
816                // position to the scale.
817                minScale = topAligned && descOptions.minScale || 1, offset = key === 'title' ?
818                    topAligned ? -3 : 0 :
819                    // Floating subtitle (#6574)
820                    topAligned ? titleOffset[0] + 2 : 0, uncappedScale = Math.min(alignTo.width / textPxLength, 1), scale = Math.max(minScale, uncappedScale), alignAttr = merge({
821                    y: verticalAlign === 'bottom' ?
822                        baseline :
823                        offset + baseline
824                }, {
825                    align: key === 'title' ?
826                        // Title defaults to center for short titles,
827                        // left for word-wrapped titles
828                        (uncappedScale < minScale ? 'left' : 'center') :
829                        // Subtitle defaults to the title.align
830                        this.title?.alignValue
831                }, descOptions), width = descOptions.width || ((uncappedScale > minScale ?
832                    // One line
833                    this.chartWidth :
834                    // Allow word wrap
835                    alignTo.width) / scale);
836                // No animation when switching alignment
837                if (desc.alignValue !== alignAttr.align) {
838                    desc.placed = false;
839                }
840                // Set the width and read the height
841                const height = Math.round(desc
842                    .css({ width: `${width}px` })
843                    // Skip the cache for HTML (#3481, #11666)
844                    .getBBox(descOptions.useHTML).height);
845                alignAttr.height = height;
846                // Perform scaling and alignment
847                desc
848                    .align(alignAttr, false, alignTo)
849                    .attr({
850                    align: alignAttr.align,
851                    scaleX: scale,
852                    scaleY: scale,
853                    'transform-origin': `${alignTo.x +
854                        textPxLength *
855                            scale *
856                            getAlignFactor(alignAttr.align)} ${lineHeight}`
857                });
858                // Adjust the rendered title offset
859                if (!descOptions.floating) {
860                    const offset = height * (
861                    // When scaling down the title, preserve the offset as
862                    // long as it's only one line, but scale down the offset
863                    // if the title wraps to multiple lines.
864                    height < lineHeight * 1.2 ? 1 : scale);
865                    if (verticalAlign === 'top') {
866                        titleOffset[0] = Math.ceil(titleOffset[0] + offset);
867                    }
868                    else if (verticalAlign === 'bottom') {
869                        titleOffset[2] = Math.ceil(titleOffset[2] + offset);
870                    }
871                }
872            }
873        }, this);
874        // Handle title.margin and caption.margin
875        if (titleOffset[0] &&
876            (options.title?.verticalAlign || 'top') === 'top') {
vendor: 7,946 bytes, lines 877-1068
877            titleOffset[0] += options.title?.margin || 0;
878        }
879        if (titleOffset[2] &&
880            options.caption?.verticalAlign === 'bottom') {
881            titleOffset[2] += options.caption?.margin || 0;
882        }
883        const requiresDirtyBox = (!this.titleOffset ||
884            this.titleOffset.join(',') !== titleOffset.join(','));
885        // Used in getMargins
886        this.titleOffset = titleOffset;
887        fireEvent(this, 'afterLayOutTitles');
888        if (!this.isDirtyBox && requiresDirtyBox) {
889            this.isDirtyBox = this.isDirtyLegend = requiresDirtyBox;
890            // Redraw if necessary (#2719, #2744)
891            if (this.hasRendered && redraw && this.isDirtyBox) {
892                this.redraw();
893            }
894        }
895    }
896    /**
897     * Internal function to get the available size of the container element
898     *
899     * @private
900     * @function Highcharts.Chart#getContainerBox
901     */
902    getContainerBox() {
903        // Temporarily hide support divs from a11y and others, #21888
904        const nonContainers = [].map.call(this.renderTo.children, (child) => {
905            if (child !== this.container) {
906                const display = child.style.display;
907                child.style.display = 'none';
908                return [child, display];
909            }
910        }), box = {
911            width: getStyle(this.renderTo, 'width', true) || 0,
912            height: (getStyle(this.renderTo, 'height', true) || 0)
913        };
914        // Restore the non-containers
915        nonContainers.filter(Boolean).forEach(([div, display]) => {
916            div.style.display = display;
917        });
918        return box;
919    }
920    /**
921     * Internal function to get the chart width and height according to options
922     * and container size. Sets {@link Chart.chartWidth} and
923     * {@link Chart.chartHeight}.
924     *
925     * @private
926     * @function Highcharts.Chart#getChartSize
927     */
928    getChartSize() {
929        const chart = this, optionsChart = chart.options.chart, widthOption = optionsChart.width, heightOption = optionsChart.height, containerBox = chart.getContainerBox(), enableDefaultHeight = containerBox.height <= 1 ||
930            ( // #21510, prevent infinite reflow
931            !chart.renderTo.parentElement?.style.height &&
932                chart.renderTo.style.height === '100%');
933        /**
934         * The current pixel width of the chart.
935         *
936         * @name Highcharts.Chart#chartWidth
937         * @type {number}
938         */
939        chart.chartWidth = Math.max(// #1393
940        0, widthOption || containerBox.width || 600 // #1460
941        );
942        /**
943         * The current pixel height of the chart.
944         *
945         * @name Highcharts.Chart#chartHeight
946         * @type {number}
947         */
948        chart.chartHeight = Math.max(0, relativeLength(heightOption, chart.chartWidth) ||
949            (enableDefaultHeight ? 400 : containerBox.height));
950        chart.containerBox = containerBox;
951    }
952    /**
953     * If the renderTo element has no offsetWidth, most likely one or more of
954     * its parents are hidden. Loop up the DOM tree to temporarily display the
955     * parents, then save the original display properties, and when the true
956     * size is retrieved, reset them. Used on first render and on redraws.
957     *
958     * @private
959     * @function Highcharts.Chart#temporaryDisplay
960     *
961     * @param {boolean} [revert]
962     * Revert to the saved original styles.
963     */
964    temporaryDisplay(revert) {
965        let node = this.renderTo, tempStyle;
966        if (!revert) {
967            while (node && node.style) {
968                // When rendering to a detached node, it needs to be temporarily
969                // attached in order to read styling and bounding boxes (#5783,
970                // #7024).
971                if (!doc.body.contains(node) && !node.parentNode) {
972                    node.hcOrigDetached = true;
973                    doc.body.appendChild(node);
974                }
975                if (getStyle(node, 'display', false) === 'none' ||
976                    node.hcOricDetached) {
977                    node.hcOrigStyle = {
978                        display: node.style.display,
979                        height: node.style.height,
980                        overflow: node.style.overflow
981                    };
982                    tempStyle = {
983                        display: 'block',
984                        overflow: 'hidden'
985                    };
986                    if (node !== this.renderTo) {
987                        tempStyle.height = 0;
988                    }
989                    css(node, tempStyle);
990                    // If it still doesn't have an offset width after setting
991                    // display to block, it probably has an !important priority
992                    // #2631, 6803
993                    if (!node.offsetWidth) {
994                        node.style.setProperty('display', 'block', 'important');
995                    }
996                }
997                node = node.parentNode;
998                if (node === doc.body) {
999                    break;
1000                }
1001            }
1002        }
1003        else {
1004            while (node && node.style) {
1005                if (node.hcOrigStyle) {
1006                    css(node, node.hcOrigStyle);
1007                    delete node.hcOrigStyle;
1008                }
1009                if (node.hcOrigDetached) {
1010                    doc.body.removeChild(node);
1011                    node.hcOrigDetached = false;
1012                }
1013                node = node.parentNode;
1014            }
1015        }
1016    }
1017    /**
1018     * Set the {@link Chart.container|chart container's} class name, in
1019     * addition to `highcharts-container`.
1020     *
1021     * @function Highcharts.Chart#setClassName
1022     *
1023     * @param {string} [className]
1024     * The additional class name.
1025     */
1026    setClassName(className) {
1027        this.container.className = 'highcharts-container ' + (className || '');
1028    }
1029    /**
1030     * Get the containing element, determine the size and create the inner
1031     * container div to hold the chart.
1032     *
1033     * @private
1034     * @function Highcharts.Chart#afterGetContainer
1035     * @emits Highcharts.Chart#event:afterGetContainer
1036     */
1037    getContainer() {
1038        const chart = this, options = chart.options, optionsChart = options.chart, indexAttrName = 'data-highcharts-chart', containerId = uniqueKey(), renderTo = chart.renderTo;
1039        let containerStyle;
1040        // If the container already holds a chart, destroy it. The check for
1041        // hasRendered is there because web pages that are saved to disk from
1042        // the browser, will preserve the data-highcharts-chart attribute and
1043        // the SVG contents, but not an interactive chart. So in this case,
1044        // charts[oldChartIndex] will point to the wrong chart if any (#2609).
1045        const oldChartIndex = pInt(attr(renderTo, indexAttrName));
1046        if (isNumber(oldChartIndex) &&
1047            charts[oldChartIndex] &&
1048            charts[oldChartIndex].hasRendered) {
1049            charts[oldChartIndex].destroy();
1050        }
1051        // Make a reference to the chart from the div
1052        attr(renderTo, indexAttrName, chart.index);
1053        // Remove previous chart
1054        renderTo.innerHTML = AST.emptyHTML;
1055        // If the container doesn't have an offsetWidth, it has or is a child of
1056        // a node that has display:none. We need to temporarily move it out to a
1057        // visible state to determine the size, else the legend and tooltips
1058        // won't render properly. The skipClone option is used in sparklines as
1059        // a micro optimization, saving about 1-2 ms each chart.
1060        if (!optionsChart.skipClone && !renderTo.offsetWidth) {
1061            chart.temporaryDisplay();
1062        }
1063        // Get the width and height
1064        chart.getChartSize();
1065        const chartHeight = chart.chartHeight;
1066        let chartWidth = chart.chartWidth;
1067        // Allow table cells and flex-boxes to shrink without the chart blocking
1068        //
vendor: 1,597 bytes, lines 1068-1107
1068 them out (#6427)
1069        css(renderTo, { overflow: 'hidden' });
1070        // Create the inner container
1071        if (!chart.styledMode) {
1072            containerStyle = extend({
1073                position: 'relative',
1074                // Needed for context menu (avoidscrollbars) and content
1075                // overflow in IE
1076                overflow: 'hidden',
1077                width: chartWidth + 'px',
1078                height: chartHeight + 'px',
1079                textAlign: 'left',
1080                lineHeight: 'normal', // #427
1081                zIndex: 0, // #1072
1082                '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',
1083                userSelect: 'none', // #13503
1084                'touch-action': 'manipulation',
1085                outline: 'none',
1086                padding: '0px'
1087            }, optionsChart.style || {});
1088        }
1089        /**
1090         * The containing HTML element of the chart. The container is
1091         * dynamically inserted into the element given as the `renderTo`
1092         * parameter in the {@link Highcharts#chart} constructor.
1093         *
1094         * @name Highcharts.Chart#container
1095         * @type {Highcharts.HTMLDOMElement}
1096         */
1097        const container = createElement('div', {
1098            id: containerId
1099        }, containerStyle, renderTo);
1100        chart.container = container;
1101        // Adjust width if setting height affected it (#20334)
1102        chart.getChartSize();
1103        if (chartWidth !== chart.chartWidth) {
1104            chartWidth = chart.chartWidth;
1105            if (!chart.styledMode) {
1106                css(container, {
1107                    width: 
1107pick(optionsChart.style?.width, chartWidth + 'px')
1108                });
1109            }
1110        }
1111        chart.containerBox = chart.getContainerBox();
1112        // Cache the cursor (#1650)
1113        chart._cursor = container.style.cursor;
1114        // Initialize the renderer
1115        const Renderer = optionsChart.renderer || !svg ?
1116            RendererRegistry.getRendererType(optionsChart.renderer) :
1117            SVGRenderer;
1118        /**
1119         * The renderer instance of the chart. Each chart instance has only one
1120         * associated renderer.
1121         *
1122         * @name Highcharts.Chart#renderer
1123         * @type {Highcharts.SVGRenderer}
1124         */
1125        chart.renderer = new Renderer(container, chartWidth, chartHeight, void 0, optionsChart.forExport, options.exporting && options.exporting.allowHTML, chart.styledMode);
1126        // Set the initial animation from the options
1127        setAnimation(void 0, chart);
1128        chart.setClassName(optionsChart.className);
1129        if (!chart.styledMode) {
1130            chart.renderer.setStyle(optionsChart.style);
1131        }
1132        else {
1133            // Initialize definitions
1134            for (const key in options.defs) { // eslint-disable-line guard-for-in
1135                this.renderer.definition(options.defs[key]);
1136            }
1137        }
1138        // Add a reference to the charts index
1139        chart.renderer.chartIndex = chart.index;
1140        fireEvent(this, 'afterGetContainer');
1141    }
1142    /**
1143     * Calculate margins by rendering axis labels in a preliminary position.
1144     * Title, subtitle and legend have already been rendered at this stage, but
1145     * will be moved into their final positions.
1146     *
1147     * @private
1148     * @function Highcharts.Chart#getMargins
1149     * @emits Highcharts.Chart#event:getMargins
1150     */
1151    getMargins(skipAxes) {
1152        const { spacing, margin, titleOffset } = this;
1153        this.resetMargins();
1154        // Adjust for title and subtitle
1155        if (titleOffset[0] && !defined(margin[0])) {
1156            this.plotTop = Math.max(this.plotTop, titleOffset[0] + spacing[0]);
1157        }
1158        if (titleOffset[2] && !defined(margin[2])) {
1159            this.marginBottom = Math.max(this.marginBottom, titleOffset[2] + spacing[2]);
1160        }
1161        // Adjust for legend
1162        if (this.legend && this.legend.display) {
1163            this.legend.adjustMargins(margin, spacing);
1164        }
1165        fireEvent(this, 'getMargins');
1166        if (!skipAxes) {
1167            this.getAxisMargins();
1168        }
1169    }
1170    /**
1171     * @private
1172     * @function Highcharts.Chart#getAxisMargins
1173     */
1174    getAxisMargins() {
1175        const chart = this, 
1176        // [top, right, bottom, left]
1177        axisOffset = chart.axisOffset = [0, 0, 0, 0], colorAxis = chart.colorAxis, margin = chart.margin, getOffset = function (axes) {
1178            axes.forEach(function (axis) {
1179                if (axis.visible) {
1180                    axis.getOffset();
1181                }
1182            });
1183        };
1184        // Pre-render axes to get labels offset width
1185        if (chart.hasCartesianSeries) {
1186            getOffset(chart.axes);
1187        }
1188        else if (colorAxis && colorAxis.length) {
1189            getOffset(colorAxis);
1190        }
1191        // Add the axis offsets
1192        marginNames.forEach(function (m, side) {
1193            if (!defined(margin[side])) {
1194                chart[m] += axisOffset[side];
1195            }
1196        });
1197        chart.setChartSize();
1198    }
1199    /**
1200     * Return the current options of the chart, but only those that differ from
1201     * default options. Items that can be either an object or an array of
1202     * objects, like `series`, `xAxis` and `yAxis`, are always returned as
1203     * array.
1204     *
1205     * @sample highcharts/members/chart-getoptions
1206     *
1207     * @function Highcharts.Chart#getOptions
1208     *
1209     * @since 11.1.0
1210     */
1211    getOptions() {
1212        return diffObjects(this.userOptions, defaultOptions);
1213    }
1214    /**
1215     * Reflows the chart to its container. By default, the Resize Observer is
1216     * attached to the chart's div which allows to reflows the chart
1217     * automatically to its container, as per the
1218     * [chart.reflow](https://api.highcharts.com/highcharts/chart.reflow)
1219     * option.
1220     *
1221     * @sample highcharts/chart/events-container/
1222     *         Pop up and reflow
1223     *
1224     * @function Highcharts.Chart#reflow
1225     *
1226     * @param {global.Event} [e]
1227     *        Event arguments. Used primarily when the function is called
1228     *        internally as a response to window resize.
1229     */
1230    reflow(e) {
1231        const chart = this, oldBox = chart.containerBox, containerBox = chart.getContainerBox();
1232        delete chart.pointer?.chartPosition;
1233        // Width and height checks for display:none. Target is doc in Opera
1234        // and win in Firefox, Chrome and IE9.
1235        if (!chart.isPrinting &&
1236            !chart.isResizing &&
1237            oldBox &&
1238            // When fired by resize observer inside hidden container
1239            containerBox.width) {
1240            if (containerBox.width !== oldBox.width ||
1241                containerBox.height !== oldBox.height) {
1242                U.clearTimeout(chart.reflowTimeout);
1243                // When called from window.resize, e is set, else it's called
1244                // directly (#2224)
1245                chart.reflowTimeout = syncTimeout(function () {
1246                    // Set size, it may have been destroyed in the meantime
1247                    // (#1257)
1248                    if (chart.container) {
1249                        chart.setSize(void 0, void 0, false);
1250                    }
1251                }, e ? 100 : 0);
1252            }
1253            chart.containerBox = containerBox;
1254        }
1255    }
1256    /**
1257     * Toggle the event handlers necessary for auto resizing, depending on the
1258     * `chart.reflow` option.
1259     *
1260     * @private
1261     * @function Highcharts.Chart#setReflow
1262     */
1263    setReflow() {
1264        const chart = this;
1265        const runReflow = (e) => {
1266            if (chart.options?.chart.reflow && chart.hasLoaded) {
1267                chart.reflow(e);
1268            }
1269        };
1270        if (typeof ResizeObserver === 'function') {
1271            (new ResizeObserver(runReflow)).observe(chart.renderTo);
1272            // Fallback for more legacy browser versions.
1273        }
1274        else {
1275            const unbind = addEvent(win, 'resize', runReflow);
1276            addEvent(this, 'destroy', unbind);
1277        }
1278    }
1279    /**
1280     * Resize the chart to a given width and height. In order to set the width
1281     * only, the height argument may be skipped. To set the height only, pass
1282     * `undefined` for the width.
1283     *
1284     * @sample highcharts/members/chart-setsize-button/
1285     *         Test resizing from buttons
1286     * @sample highcharts/members/chart-setsize-jquery-resizable/
1287     *         Add a jQuery UI resizable
1288     * @sample stock/members/chart-setsize/
1289     *         Highcharts Stock with UI resizable
1290     *
1291     * @function Highcharts.Chart#setSize
1292     *
1293     * @param {number|null} [width]
1294     *        The new pixel width of the chart. Since v4.2.6, the argument can
1295     *        be `undefined` in order to preserve the current value (when
1296     *        setting height only), or `null` to adapt to the width of the
1297     *        containing element.
1298     *
1299     * @param {number|null} [height]
1300     *        The new pixel height of the chart. Since v4.2.6, the argument can
1301     *        be `undefined` in order to preserve the current value, or `null`
1302     *        in order to adapt to the height of the containing element.
1303     *
1304     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
1305     *        Whether and how to apply animation. When `undefined`, it applies
1306     *        the animation that is set in the `chart.animation` option.
1307     *
1308     *
1309     * @emits Highcharts.Chart#event:endResize
1310     * @emits Highcharts.Chart#event:resize
1311     */
1312    setSize(width, height, animation) {
1313        const chart = this, renderer = chart.renderer;
1314        // Handle the isResizing counter
1315        chart.isResizing += 1;
1316        // Set the animation for the current process
1317        setAnimation(animation, chart);
1318        const globalAnimation = renderer.globalAnimation;
1319        chart.oldChartHeight = chart.chartHeight;
1320        chart.oldChartWidth = chart.chartWidth;
1321        if (typeof width !== 'undefined') {
1322            chart.options.chart.width = width;
1323        }
1324        if (typeof height !== 'undefined') {
1325            chart.options.chart.height = height;
1326        }
1327        chart.getChartSize();
vendor: 4,315 bytes, lines 1328-1430
1328        const { chartWidth, chartHeight, scrollablePixelsX = 0, scrollablePixelsY = 0 } = chart;
1329        // Avoid expensive redrawing if the computed size didn't change
1330        if (chart.isDirtyBox ||
1331            chartWidth !== chart.oldChartWidth ||
1332            chartHeight !== chart.oldChartHeight) {
1333            // Resize the container with the global animation applied if enabled
1334            // (#2503)
1335            if (!chart.styledMode) {
1336                (globalAnimation ? animate : css)(chart.container, {
1337                    width: `${chartWidth + scrollablePixelsX}px`,
1338                    height: `${chartHeight + scrollablePixelsY}px`
1339                }, globalAnimation);
1340            }
1341            chart.setChartSize(true);
1342            renderer.setSize(chartWidth, chartHeight, globalAnimation);
1343            // Handle axes
1344            chart.axes.forEach(function (axis) {
1345                axis.isDirty = true;
1346                axis.setScale();
1347            });
1348            chart.isDirtyLegend = true; // Force legend redraw
1349            chart.isDirtyBox = true; // Force redraw of plot and chart border
1350            chart.layOutTitles(); // #2857
1351            chart.getMargins();
1352            chart.redraw(globalAnimation);
1353            chart.oldChartHeight = void 0;
1354            fireEvent(chart, 'resize');
1355            // Fire endResize and set isResizing back. If animation is disabled,
1356            // fire without delay, but in a new thread to avoid triggering the
1357            // resize observer (#19027).
1358            setTimeout(() => {
1359                if (chart) {
1360                    fireEvent(chart, 'endResize');
1361                }
1362            }, animObject(globalAnimation).duration);
1363        }
1364        // Handle resizing counter even if we've re-rendered or not (#20548).
1365        chart.isResizing -= 1;
1366    }
1367    /**
1368     * Set the public chart properties. This is done before and after the
1369     * pre-render to determine margin sizes.
1370     *
1371     * @private
1372     * @function Highcharts.Chart#setChartSize
1373     * @emits Highcharts.Chart#event:afterSetChartSize
1374     */
1375    setChartSize(skipAxes) {
1376        const chart = this, { chartHeight, chartWidth, inverted, spacing, renderer } = chart, clipOffset = chart.clipOffset, clipRoundFunc = Math[inverted ? 'floor' : 'round'];
1377        let plotLeft, plotTop, plotWidth, plotHeight;
1378        /**
1379         * The current left position of the plot area in pixels.
1380         *
1381         * @name Highcharts.Chart#plotLeft
1382         * @type {number}
1383         */
1384        chart.plotLeft = plotLeft = Math.round(chart.plotLeft);
1385        /**
1386         * The current top position of the plot area in pixels.
1387         *
1388         * @name Highcharts.Chart#plotTop
1389         * @type {number}
1390         */
1391        chart.plotTop = plotTop = Math.round(chart.plotTop);
1392        /**
1393         * The current width of the plot area in pixels.
1394         *
1395         * @name Highcharts.Chart#plotWidth
1396         * @type {number}
1397         */
1398        chart.plotWidth = plotWidth = Math.max(0, Math.round(chartWidth - plotLeft - chart.marginRight));
1399        /**
1400         * The current height of the plot area in pixels.
1401         *
1402         * @name Highcharts.Chart#plotHeight
1403         * @type {number}
1404         */
1405        chart.plotHeight = plotHeight = Math.max(0, Math.round(chartHeight - plotTop - chart.marginBottom));
1406        chart.plotSizeX = inverted ? plotHeight : plotWidth;
1407        chart.plotSizeY = inverted ? plotWidth : plotHeight;
1408        // Set boxes used for alignment
1409        chart.spacingBox = renderer.spacingBox = {
1410            x: spacing[3],
1411            y: spacing[0],
1412            width: chartWidth - spacing[3] - spacing[1],
1413            height: chartHeight - spacing[0] - spacing[2]
1414        };
1415        chart.plotBox = renderer.plotBox = {
1416            x: plotLeft,
1417            y: plotTop,
1418            width: plotWidth,
1419            height: plotHeight
1420        };
1421        // Compute the clipping box
1422        if (clipOffset) {
1423            chart.clipBox = {
1424                x: clipRoundFunc(clipOffset[3]),
1425                y: clipRoundFunc(clipOffset[0]),
1426                width: clipRoundFunc(chart.plotSizeX - clipOffset[1] - clipOffset[3]),
1427                height: clipRoundFunc(chart.plotSizeY - clipOffset[0] - clipOffset[2])
1428            };
1429        }
1430        if (!skipAxes) {
1431            chart.axes.forEach(function (axis) {
1432                axis.setAxisSize();
1433                axis.setAxisTranslation();
1434            });
1435            renderer.alignElements();
1436        }
1437        fireEvent(chart, 'afterSetChartSize', { skipAxes: skipAxes });
1438    }
1439    /**
1440     * Initial margins before auto size margins are applied.
1441     *
1442     * @private
1443     * @function Highcharts.Chart#resetMargins
1444     */
1445    resetMargins() {
1446        fireEvent(this, 'resetMargins');
1447        const chart = this, chartOptions = chart.options.chart, plotBorderWidth = chartOptions.plotBorderWidth || 0, halfWidth = plotBorderWidth / 2;
1448        // Create margin and spacing array
1449        ['margin', 'spacing'].forEach(function splashArrays(target) {
1450            const value = chartOptions[target], values = isObject(value) ? value : [value, value, value, value];
1451            [
1452                'Top',
1453                'Right',
1454                'Bottom',
1455                'Left'
1456            ].forEach(function (sideName, side) {
1457                chart[target][side] = pick(chartOptions[target + sideName], values[side]);
1458            });
1459        });
1460        // Set margin names like chart.plotTop, chart.plotLeft,
1461        // chart.marginRight, chart.marginBottom.
1462        marginNames.forEach(function (m, side) {
1463            chart[m] = pick(chart.margin[side], chart.spacing[side]);
1464        });
1465        chart.axisOffset = [0, 0, 0, 0]; // Top, right, bottom, left
1466        chart.clipOffset = [
1467            halfWidth,
1468            halfWidth,
1469            halfWidth,
1470            halfWidth
1471        ];
1472        chart.plotBorderWidth = plotBorderWidth;
1473    }
1474    /**
1475     * Internal function to draw or redraw the borders and backgrounds for chart
1476     * and plot area.
1477     *
1478     * @private
1479     * @function Highcharts.Chart#drawChartBox
1480     * @emits Highcharts.Chart#event:afterDrawChartBox
1481     */
1482    drawChartBox() {
1483        const chart = this, optionsChart = chart.options.chart, renderer = chart.renderer, chartWidth = chart.chartWidth, chartHeight = chart.chartHeight, styledMode = chart.styledMode, plotBGImage = chart.plotBGImage, chartBackgroundColor = optionsChart.backgroundColor, plotBackgroun
vendor: 5,936 bytes, lines 1483-1635
1483dColor = optionsChart.plotBackgroundColor, plotBackgroundImage = optionsChart.plotBackgroundImage, plotLeft = chart.plotLeft, plotTop = chart.plotTop, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, plotBox = chart.plotBox, clipRect = chart.clipRect, clipBox = chart.clipBox;
1484        let chartBackground = chart.chartBackground, plotBackground = chart.plotBackground, plotBorder = chart.plotBorder, chartBorderWidth, mgn, bgAttr, verb = 'animate';
1485        // Chart area
1486        if (!chartBackground) {
1487            chart.chartBackground = chartBackground = renderer.rect()
1488                .addClass('highcharts-background')
1489                .add();
1490            verb = 'attr';
1491        }
1492        if (!styledMode) {
1493            // Presentational
1494            chartBorderWidth = optionsChart.borderWidth || 0;
1495            mgn = chartBorderWidth + (optionsChart.shadow ? 8 : 0);
1496            bgAttr = {
1497                fill: chartBackgroundColor || 'none'
1498            };
1499            if (chartBorderWidth || chartBackground['stroke-width']) { // #980
1500                bgAttr.stroke = optionsChart.borderColor;
1501                bgAttr['stroke-width'] = chartBorderWidth;
1502            }
1503            chartBackground
1504                .attr(bgAttr)
1505                .shadow(optionsChart.shadow);
1506        }
1507        else {
1508            chartBorderWidth = mgn = chartBackground.strokeWidth();
1509        }
1510        chartBackground[verb]({
1511            x: mgn / 2,
1512            y: mgn / 2,
1513            width: chartWidth - mgn - chartBorderWidth % 2,
1514            height: chartHeight - mgn - chartBorderWidth % 2,
1515            r: optionsChart.borderRadius
1516        });
1517        // Plot background
1518        verb = 'animate';
1519        if (!plotBackground) {
1520            verb = 'attr';
1521            chart.plotBackground = plotBackground = renderer.rect()
1522                .addClass('highcharts-plot-background')
1523                .add();
1524        }
1525        plotBackground[verb](plotBox);
1526        if (!styledMode) {
1527            // Presentational attributes for the background
1528            plotBackground
1529                .attr({
1530                fill: plotBackgroundColor || 'none'
1531            })
1532                .shadow(optionsChart.plotShadow);
1533            // Create the background image
1534            if (plotBackgroundImage) {
1535                if (!plotBGImage) {
1536                    chart.plotBGImage = renderer.image(plotBackgroundImage, plotLeft, plotTop, plotWidth, plotHeight).add();
1537                }
1538                else {
1539                    if (plotBackgroundImage !== plotBGImage.attr('href')) {
1540                        plotBGImage.attr('href', plotBackgroundImage);
1541                    }
1542                    plotBGImage.animate(plotBox);
1543                }
1544            }
1545        }
1546        // Plot clip
1547        if (!clipRect) {
1548            chart.clipRect = renderer.clipRect(clipBox);
1549        }
1550        else {
1551            clipRect.animate({
1552                width: clipBox.width,
1553                height: clipBox.height
1554            });
1555        }
1556        // Plot area border
1557        verb = 'animate';
1558        if (!plotBorder) {
1559            verb = 'attr';
1560            chart.plotBorder = plotBorder = renderer.rect()
1561                .addClass('highcharts-plot-border')
1562                .attr({
1563                zIndex: 1 // Above the grid
1564            })
1565                .add();
1566        }
1567        if (!styledMode) {
1568            // Presentational
1569            plotBorder.attr({
1570                stroke: optionsChart.plotBorderColor,
1571                'stroke-width': optionsChart.plotBorderWidth || 0,
1572                fill: 'none'
1573            });
1574        }
1575        plotBorder[verb](plotBorder.crisp({
1576            x: plotLeft,
1577            y: plotTop,
1578            width: plotWidth,
1579            height: plotHeight
1580        }, -plotBorder.strokeWidth())); // #3282 plotBorder should be negative;
1581        // reset
1582        chart.isDirtyBox = false;
1583        fireEvent(this, 'afterDrawChartBox');
1584    }
1585    /**
1586     * Detect whether a certain chart property is needed based on inspecting its
1587     * options and series. This mainly applies to the chart.inverted property,
1588     * and in extensions to the chart.angular and chart.polar properties.
1589     *
1590     * @private
1591     * @function Highcharts.Chart#propFromSeries
1592     */
1593    propFromSeries() {
1594        const chart = this, optionsChart = chart.options.chart, seriesOptions = chart.options.series;
1595        let i, klass, value;
1596        /**
1597         * The flag is set to `true` if a series of the chart is inverted.
1598         *
1599         * @name Highcharts.Chart#inverted
1600         * @type {boolean|undefined}
1601         */
1602        ['inverted', 'angular', 'polar'].forEach(function (key) {
1603            // The default series type's class
1604            klass = seriesTypes[optionsChart.type];
1605            // Get the value from available chart-wide properties
1606            value =
1607                // It is set in the options:
1608                optionsChart[key] ||
1609                    // The default series class:
1610                    (klass && klass.prototype[key]);
1611            // Requires it
1612            // 4. Check if any the chart's series require it
1613            i = seriesOptions && seriesOptions.length;
1614            while (!value && i--) {
1615                klass = seriesTypes[seriesOptions[i].type];
1616                if (klass && klass.prototype[key]) {
1617                    value = true;
1618                }
1619            }
1620            // Set the chart property
1621            chart[key] = value;
1622        });
1623    }
1624    /**
1625     * Internal function to link two or more series together, based on the
1626     * `linkedTo` option. This is done from `Chart.render`, and after
1627     * `Chart.addSeries` and `Series.remove`.
1628     *
1629     * @private
1630     * @function Highcharts.Chart#linkSeries
1631     * @emits Highcharts.Chart#event:afterLinkSeries
1632     */
1633    linkSeries(isUpdating) {
1634        const chart = this, chartSeries = chart.series;
1635        // Reset links
1636        chartSeries.forEach(function (series) {
1637            series.linkedSeries.length = 0;
1638        });
1639        // Apply new links
1640        chartSeries.forEach(function (series) {
1641            const { linkedTo } = series.options;
1642            if (isString(linkedTo)) {
1643                let linkedParent;
1644                if (linkedTo === ':previous') {
1645                    linkedParent = chart.series[series.index - 1];
1646                }
1647                else {
1648                    linkedParent = chart.get(linkedTo);
1649                }
1650                // #3341 avoid mutual linking
1651                if (linkedParent &&
1652                    linkedParent.linkedParent !== series) {
1653                    linkedParent.linkedSeries.push(series);
1654                    /**
1655                     * The parent series of the current series, if the current
1656                     * series has a [linkedTo](https://api.highcharts.com/highcharts/series.line.linkedTo)
1657                     * setting.
1658                     *
1659                     * @name Highcharts.Series#linkedParent
1660                     * @type {Highcharts.Series}
1661                     * @readonly
1662                     */
1663                    series.linkedParent = linkedParent;
1664                    if (linkedParent.enabledDataSorting) {
1665                        series.setDataSortingOptions();
1666                    }
1667                    series.visible = pick(series.options.visible, linkedParent.options.visible, series.visible); // #3879
1668                }
1669            }
1670        });
1671        fireEvent(this, 'afterLinkSeries', { isUpdating });
1672    }
1673    /**
1674     * Render series for the chart.
1675     *
1676     * @private
1677     * @function Highcharts.Chart#renderSeries
1678     */
1679    renderSeries() {
1680        this.series.forEach(function (serie) {
1681            serie.translate();
1682            serie.render();
1683        });
1684    }
1685    /**
1686     * Render all graphics for the chart. Runs internally on initialization.
1687     *
1688     * @private
1689     * @function Highcharts.Chart#render
1690     */
1691    render() {
1692        const chart = this, axes = chart.axes, colorAxis = chart.colorAxis, renderer = chart.renderer, axisLayoutRuns = chart.options.chart.axisLayoutRuns || 2, renderAxes = (axes) => {
1693            axes.forEach((axis) => {
1694                if (axis.visible) {
1695                    axis.render();
1696                }
1697            });
1698        };
1699        let expectedSpace = 0, // Correction for X axis labels
1700        // If the plot area size has changed significantly, calculate tick
1701        // positions again
1702        redoHorizontal = true, redoVertical, run = 0;
1703        // Title
1704        chart.setTitle();
1705        // Fire an event before the margins are computed. This is where the
1706        // legend is assigned.
1707        fireEvent(chart, 'beforeMargins');
1708        // Get stacks
1709        chart.getStacks?.();
1710        // Get chart margins
1711        chart.getMargins(true);
1712        chart.setChartSize();
1713        for (const axis of axes) {
1714            const { options } = axis, { labels } = options;
1715            if (chart.hasCartesianSeries && // #20948
1716                axis.horiz &&
1717                axis.visible &&
1718                labels.enabled &&
1719                axis.series.length &&
1720                axis.coll !== 'colorAxis' &&
1721                !chart.polar) {
1722                expectedSpace = options.tickLength;
1723                axis.createGroups();
1724                // Calculate expected space based on dummy tick
1725                const mockTick = new Tick(axis, 0, '', true), label = mockTick.createLabel('x', labels);
1726                mockTick.destroy();
1727                if (label &&
1728                    pick(labels.reserveSpace, !isNumber(options.crossing))) {
1729                    expectedSpace = label.getBBox().height +
1730                        labels.distance +
1731                        Math.max(options.offset || 0, 0);
1732                }
1733                if (expectedSpace) {
1734                    label?.destroy();
1735                    break;
1736                }
1737            }
1738        }
1739        // Use Math.max to prevent negative plotHeight
1740        chart.plotHeight = Math.max(chart.plotHeight - expectedSpace, 0);
1741        while ((redoHorizontal || redoVertical || axisLayoutRuns > 1) &&
1742            run < axisLayoutRuns // #19794
1743        ) {
1744            const tempWidth = chart.plotWidth, tempHeight = chart.plotHeight;
1745            for (const axis of axes) {
1746                if (run === 0) {
1747                    // Get margins by pre-rendering axes
1748                    axis.setScale();
1749                }
1750                else if ((axis.horiz && redoHorizontal) ||
1751                    (!axis.horiz && redoVertical)) {
1752                    // Update to reflect the new margins
1753                    axis.setTickInterval(true);
1754                }
1755            }
1756            if (run === 0) {
1757                chart.getAxisMargins();
1758            }
1759            else {
1760                // Check again for new, rotated or moved labels
1761                chart.getMargins();
1762            }
1763            redoHorizontal = (tempWidth / chart.plotWidth) > (run ? 1 : 1.1);
1764            redoVertical = (tempHeight / chart.plotHeight) > (run ? 1 : 1.05);
1765            run++;
1766        }
1767        // Draw the borders and backgrounds
1768        chart.drawChartBox();
1769        // Axes
1770        if (chart.hasCartesianSeries) {
1771            renderAxes(axes);
1772        }
1773        else if (colorAxis && colorAxis.length) {
1774            renderAxes(colorAxis);
1775        }
1776        // The series
1777        if (!chart.seriesGroup) {
1778            chart.seriesGroup = renderer.g('series-group')
1779                .attr({ zIndex: 3 })
1780                .shadow(chart.options.chart.seriesGroupShadow)
1781                .add();
1782        }
1783        chart.renderSeries();
1784        // Credits
1785        chart.addCredits();
1786        // Handle responsiveness
1787        if (chart.setResponsive) {
1788            chart.setResponsive();
1789        }
1790        // Set flag
1791        chart.hasRendered = true;
1792    }
1793    /**
1794     * Set a new credits label for the chart.
1795     *
1796     * @sample highcharts/credits/credits-update/
1797     *         Add and update credits
1798     *
1799     * @function Highcharts.Chart#addCredits
1800     *
1801     * @param {Highcharts.CreditsOptions} [credits]
1802     * A configuration object for the new credits.
1803     */
1804    addCredits(credits) {
1805        const chart = this, creds = merge(true, this.options.credits, credits);
1806        if (creds.enabled && !this.credits) {
1807            /**
1808             * The chart's credits label. The label has an `update` method that
1809             * allows setting new options as per the
1810             * [credits options set](https://api.highcharts.com/highcharts/credits).
1811             *
1812             * @name Highcharts.Chart#credits
1813             * @type {Highcharts.SVGElement}
1814             */
1815            this.credits = this.renderer.text(creds.text + (this.mapCredits || ''), 0, 0)
1816                .addClass('highcharts-credits')
1817                .on('click', function () {
1818                if (creds.href) {
1819                    win.location.href = creds.href;
1820                }
1821            })
1822                .attr({
1823                align: creds.position.align,
1824                zIndex: 8
1825            });
1826            if (!chart.styledMode) {
1827                this.credits.css(creds.style);
1828            }
1829            this.credits
1830                .add()
1831                .align(creds.position);
1832            // Dynamically update
1833            this.credits.update = function (options) {
1834                chart.credits = chart.credits.destroy();
1835                chart.addCredits(options);
1836            };
1837        }
1838    }
1839    /**
1840     * Remove the chart and purge memory. This method is called internally
1841     * before adding a second chart into the same container, as well as on
1842     * window unload to prevent leaks.
1843     *
1844     * @sample highcharts/members/chart-destroy/
1845     *         Destroy the chart from a button
1846     * @sample stock/members/chart-destroy/
1847     *         Destroy with Highcharts Stock
1848     *
1849     * @function Highcharts.Chart#destroy
1850     *
1851     * @emits Highcharts.Chart#event:destroy
1852     */
1853    destroy() {
1854        const chart = this, axes = chart.axes, series = chart.series, container = chart.container, parentNode = container && container.parentNode;
1855        let i;
1856        // Fire the chart.destroy event
1857        fireEvent(chart, 'destroy');
1858        // Delete the chart from charts lookup array
1859        if (chart.renderer.forExport) {
1860            erase(charts, chart); // #6569
1861        }
1862        else {
1863            charts[chart.index] = void 0;
1864        }
1865        H.chartCount--;
1866        chart.renderTo.removeAttribute('data-highcharts-chart');
1867        // Remove events
1868        removeEvent(chart);
1869        // ==== Destroy collections:
1870        // Destroy axes
1871        i = axes.length;
1872        while (i--) {
1873            axes[i] = axes[i].destroy();
1874        }
1875        // Destroy scroller & scroller series before destroying base series
1876        if (this.scroller && this.scroller.destroy) {
1877            this.scroller.destroy();
1878        }
1879        // Destroy each series
1880        i = series.length;
1881        while (i--) {
1882            series[i] = series[i].destroy();
1883        }
1884        // ==== Destroy chart properties:
1885        [
1886            'title', 'subtitle', 'chartBackground', 'plotBackgroun
vendor: 4,274 bytes, lines 1886-1997
1886d',
1887            'plotBGImage', 'plotBorder', 'seriesGroup', 'clipRect', 'credits',
1888            'pointer', 'rangeSelector', 'legend', 'resetZoomButton', 'tooltip',
1889            'renderer'
1890        ].forEach(function (name) {
1891            const prop = chart[name];
1892            if (prop && prop.destroy) {
1893                chart[name] = prop.destroy();
1894            }
1895        });
1896        // Remove container and all SVG, check container as it can break in IE
1897        // when destroyed before finished loading
1898        if (container) {
1899            container.innerHTML = AST.emptyHTML;
1900            removeEvent(container);
1901            if (parentNode) {
1902                discardElement(container);
1903            }
1904        }
1905        // Clean it all up
1906        objectEach(chart, function (val, key) {
1907            delete chart[key];
1908        });
1909    }
1910    /**
1911     * Prepare for first rendering after all data are loaded.
1912     *
1913     * @private
1914     * @function Highcharts.Chart#firstRender
1915     * @emits Highcharts.Chart#event:beforeRender
1916     */
1917    firstRender() {
1918        const chart = this, options = chart.options;
1919        // Create the container
1920        chart.getContainer();
1921        chart.resetMargins();
1922        chart.setChartSize();
1923        // Set the common chart properties (mainly invert) from the given series
1924        chart.propFromSeries();
1925        // Get axes
1926        chart.createAxes();
1927        // Initialize the series
1928        const series = isArray(options.series) ? options.series : [];
1929        options.series = []; // Avoid mutation
1930        series.forEach(
1931        // #9680
1932        function (serieOptions) {
1933            chart.initSeries(serieOptions);
1934        });
1935        chart.linkSeries();
1936        chart.setSortedData();
1937        // Run an event after axes and series are initialized, but before
1938        // render. At this stage, the series data is indexed and cached in the
1939        // xData and yData arrays, so we can access those before rendering. Used
1940        // in Highcharts Stock.
1941        fireEvent(chart, 'beforeRender');
1942        chart.render();
1943        chart.pointer?.getChartPosition(); // #14973
1944        // Fire the load event if there are no external images
1945        if (!chart.renderer.imgCount && !chart.hasLoaded) {
1946            chart.onload();
1947        }
1948        // If the chart was rendered outside the top container, put it back in
1949        // (#3679)
1950        chart.temporaryDisplay(true);
1951    }
1952    /**
1953     * Internal function that runs on chart load, async if any images are loaded
1954     * in the chart. Runs the callbacks and triggers the `load` and `render`
1955     * events.
1956     *
1957     * @private
1958     * @function Highcharts.Chart#onload
1959     * @emits Highcharts.Chart#event:load
1960     * @emits Highcharts.Chart#event:render
1961     */
1962    onload() {
1963        // Run callbacks, first the ones registered by modules, then user's one
1964        this.callbacks.concat([this.callback]).forEach(function (fn) {
1965            // Chart destroyed in its own callback (#3600)
1966            if (fn && typeof this.index !== 'undefined') {
1967                fn.apply(this, [this]);
1968            }
1969        }, this);
1970        fireEvent(this, 'load');
1971        fireEvent(this, 'render');
1972        // Set up auto resize, check for not destroyed (#6068)
1973        if (defined(this.index)) {
1974            this.setReflow();
1975        }
1976        this.warnIfA11yModuleNotLoaded();
1977        // Don't run again
1978        this.hasLoaded = true;
1979    }
1980    /**
1981     * Emit console warning if the a11y module is not loaded.
1982     * @private
1983     */
1984    warnIfA11yModuleNotLoaded() {
1985        const { options, title } = this;
1986        if (options && !this.accessibility) {
1987            // Make chart behave as an image with the title as alt text
1988            this.renderer.boxWrapper.attr({
1989                role: 'img',
1990                'aria-label': ((title && title.element.textContent) || ''
1991                // #17753, < is not allowed in SVG attributes
1992                ).replace(/</g, '&lt;')
1993            });
1994            if (!(options.accessibility && options.accessibility.enabled === false)) {
1995                error('Highcharts warning: Consider including the ' +
1996                    '"accessibility.js" module to make your chart more ' +
1997                    'usable for people with disabilities. Set the ' +
1998                    '"accessibility.enabled" option to false to remove this ' +
1999                    'warning. See https://www.highcharts.com/docs/accessibility/accessibility-module.', false, this);
2000            }
2001        }
2002    }
2003    /**
2004     * Add a series to the chart after render time. Note that this method should
2005     * never be used when adding data synchronously at chart render time, as it
2006     * adds expense to the calculations and rendering. When adding data at the
2007     * same time as the chart is initialized, add the series as a configuration
2008     * option instead. With multiple axes, the `offset` is dynamically adjusted.
2009     *
2010     * @sample highcharts/members/chart-addseries/
2011     *         Add a series from a button
2012     * @sample stock/members/chart-addseries/
2013     *         Add a series in Highcharts Stock
2014     *
2015     * @function Highcharts.Chart#addSeries
2016     *
2017     * @param {Highcharts.SeriesOptionsType} options
2018     *        The config options for the series.
2019     *
2020     * @param {boolean} [redraw=true]
2021     *        Whether to redraw the chart after adding.
2022     *
2023     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
2024     *        Whether to apply animation, and optionally animation
2025     *        configuration. When `undefined`, it applies the animation that is
2026     *        set in the `chart.animation` option.
2027     *
2028     * @return {Highcharts.Series}
2029     *         The newly created series object.
2030     *
2031     * @emits Highcharts.Chart#event:addSeries
2032     * @emits Highcharts.Chart#event:afterAddSeries
2033     */
2034    addSeries(options, redraw, animation) {
2035        const chart = this;
2036        let series;
2037        if (options) { // <- not necessary
2038            redraw = pick(redraw, true); // Defaults to true
2039            fireEvent(chart, 'addSeries', { options: options }, function () {
2040                series = chart.initSeries(options);
2041                chart.isDirtyLegend = true;
2042                chart.linkSeries();
2043                if (series.enabledDataSorting) {
2044                    // We need to call `setData` after `linkSeries`
2045                    series.setData(options.data, false);
2046                }
2047                fireEvent(chart, 'afterAddSeries', { series: series });
2048                if (redraw) {
2049                    chart.redraw(animation);
2050                }
2051            });
2052        }
2053        return series;
2054    }
2055    /**
2056     * Add an axis to the chart after render time. Note that this method should
2057     * never be used when adding data synchronously at chart render time, as it
2058     * adds expense to the calculations and rendering. When adding data at the
2059     * same time as the chart is initialized, add the axis as a configuration
2060     * option instead.
2061     *
2062     * @sample highcharts/members/chart-addaxis/
2063     *         Add and remove axes
2064     *
2065     * @function Highcharts.Chart#addAxis
2066     *
2067     * @param {Highcharts.AxisOptions} options
2068     *        The axis options.
2069     *
2070     * @param {boolean} [isX=false]
2071     *        Whether it is an X axis or a value axis.
2072     *
2073     * @param {boolean} [redraw=true]
2074     *        Whether to redraw the chart after adding.
2075     *
2076     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
2077     *        Whether and how to apply animation in the redraw. When
2078     *        `undefined`, it applies the animation that is set in the
2079     *        `chart.animation` option.
2080     *
2081     * @return {Highcharts.Axis}
2082     *         The newly generated Axis object.
2083     */
2084    addAxis(options, isX, redraw, animation) {
2085        return this.createAxis(isX ? 'xAxis' : 'yAxis', { axis: options, redraw: redraw, animation: animation });
2086    }
2087    /**
2088     * Add a color axis to the chart after render time. Note that this method
2089     * should never be used when adding data synchronously at chart render time,
2090     * as it adds expense to the calculations and rendering. When adding data at
2091     * the same time as the chart is initialized, add the axis as a
2092     * configuration option instead.
2093     *
2094     * @sample highcharts/members/chart-addaxis/
2095     *         Add and remove axes
2096     *
2097     * @function Highcharts.Chart#addColorAxis
2098     *
2099     * @param {Highcharts.ColorAxisOptions} options
2100     *        The axis options.
2101     *
2102     * @param {boolean} [redraw=true]
2103     *        Whether to redraw the chart after adding.
2104     *
2105     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
2106     *        Whether and how to apply animation in the redraw. When
2107     *        `undefined`, it applies the animation that is set in the
2108     *        `chart.animation` option.
2109     *
2110     * @return {Highcharts.Axis}
2111     *         The newly generated Axis object.
2112     */
2113    addColorAxis(options, redraw, animation) {
2114        return this.createAxis('colorAxis', { axis: options, redraw: redraw, animation: animation });
2115    }
2116    /**
2117     * Factory for creating different axis types.
2118     *
2119     * @private
2120     * @function Highcharts.Chart#createAxis
2121     *
2122     * @param {string} coll
2123     *        An axis type.
2124     *
2125     * @param {...Array<*>} arguments
2126     *        All arguments for the constructor.
2127     *
2128     * @return {Highcharts.Axis}
2129     *         The newly generated Axis object.
2130     */
2131    createAxis(coll, options) {
2132        const axis = new Axis(this, options.axis, coll);
2133        if (pick(options.redraw, true)) {
2134            this.redraw(options.animation);
2135        }
2136        return axis;
2137    }
2138    /**
2139     * Dim the chart and show a loading text or symbol. Options for the loading
2140     * screen are defined in {@link
2141     * https://api.highcharts.com/highcharts/loading|the loading options}.
2142     *
2143     * @sample highcharts/members/chart-hideloading/
2144     *         Show and hide loading from a button
2145     * @sample highcharts/members/chart-showloading/
2146     *         Apply different text labels
2147     * @sample stock/members/chart-show-hide-loading/
2148     *         Toggle loading in Highcharts Stock
2149     *
2150     * @function Highcharts.Chart#showLoading
2151     *
2152     * @param {string} [str]
2153     *        An optional text to show in the loading label instead of the
2154     *        default one. The default text is set in
2155     *        [lang.loading](https://api.highcharts.com/highcharts/lang.loading).
2156     */
2157    showLoading(str) {
2158        const chart = this, options = chart.options, loadingOptions = options.loading, setLoadingSize = function () {
2159            if (loadingDiv) {
2160                css(loadingDiv, {
2161                    left: chart.plotLeft + 'px',
2162                    top: chart.plotTop + 'px',
2163                    width: chart.plotWidth + 'px',
2164                    height: chart.plotHeight + 'px'
2165                });
2166            }
2167        };
2168        let loadingDiv = chart.loadingDiv, loadingSpan = chart.loadingSpan;
2169        // Create the layer at the first call
2170        if (!loadingDiv) {
2171            chart.loadingDiv = loadingDiv = createElement('div', {
2172                className: 'highcharts-loading highcharts-loading-hidden'
2173            }, null, chart.container);
2174        }
2175        if (!loadingSpan) {
2176            chart.loadingSpan = loadingSpan = createElement('span', { className: 'highcharts-loading-inner' }, null, loadingDiv);
2177            addEvent(chart, 'redraw', setLoadingSize); // #1080
2178        }
2179        loadingDiv.className = 'highcharts-loading';
2180        // Update text
2181        AST.setElementHTML(loadingSpan, pick(str, options.lang.loading, ''));
2182        if (!chart.styledMode) {
2183            // Update visuals
2184            css(loadingDiv, extend(loadingOptions.style, {
2185                zIndex: 10
2186            }));
2187            css(loadingSpan, loadingOptions.labelStyle);
2188            // Show it
2189            if (!chart.loadingShown) {
2190                css(loadingDiv, {
2191                    opacity: 0,
2192                    display: ''
2193                });
2194                animate(loadingDiv, {
2195                    opacity: loadingOptions.style.opacity || 0.5
2196                }, {
2197                    duration: loadingOptions.showDuration || 0
2198                });
2199            }
2200        }
2201        chart.loadingShown = true;
2202        setLoadingSize();
2203    }
2204    /**
2205     * Hide the loading layer.
2206     *
2207     * @see Highcharts.Chart#showLoading
2208     *
2209     * @sample highcharts/members/chart-hideloading/
2210     *         Show and hide loading from a button
2211     * @sample stock/members/chart-show-hide-loading/
2212     *         Toggle loading in Highcharts Stock
2213     *
2214     * @function Highcharts.Chart#hideLoading
2215     */
2216    hideLoading() {
2217        const options = this.options, loadingDiv = this.loadingDiv;
2218        if (loadingDiv) {
2219            loadingDiv.className =
2220                'highcharts-loading highcharts-loading-hidden';
2221            if (!this.styledMode) {
2222                animate(loadingDiv, {
2223                    opacity: 0
2224                }, {
2225                    duration: options.loading.hideDuration || 100,
2226                    complete: function () {
2227                        css(loadingDiv, { display: 'none' });
2228                    }
2229                });
2230            }
2231        }
2232        this.loadingShown = false;
2233    }
2234    /**
2235     * A generic function to update any element of the chart. Elements can be
2236     * enabled and disabled, moved, re-styled, re-formatted etc.
2237     *
2238     * A special case is configuration objects that take arrays, for example
2239     * [xAxis](https://api.highcharts.com/highcharts/xAxis),
2240     * [yAxis](https://api.highcharts.com/highcharts/yAxis) or
2241     * [series](https://api.highcharts.com/highcharts/series). For these
2242     * collections, an `id` option is used to map the new option set to an
2243     * existing object. If an existing object of the same id is not found, the
2244     * corresponding item is updated. So for example, running `chart.update`
2245     * with a series item without an id, will cause the existing chart's series
2246     * with the same index in the series array to be updated. When the
2247     * `oneToOne` parameter is true, `chart.update` will also take care of
2248     * adding and removing items from the collection. Read more under the
2249     * parameter description below.
2250     *
2251     * Note that when changing series data, `chart.update` may mutate the passed
2252     * data options.
2253     *
2254     * See also the
2255     * [responsive option set](https://api.highcharts.com/highcharts/responsive).
2256     * Switching between `responsive.rules` basically runs `chart.update` under
2257     * the hood.
2258     *
2259     * @sample highcharts/members/chart-update/
2260     *         Update chart geometry
2261     *
2262     * @function Highcharts.Chart#update
2263     *
2264     * @param {Highcharts.Options} options
2265     *        A configuration object for the new chart options.
2266     *
2267     * @param {boolean} [redraw=true]
2268     *        Whether to redraw the chart.
2269     *
2270     * @param {boolean} [oneToOne=false]
2271     *        When `true`, the `series`, `xAxis`, `yAxis` and `annotations`
2272     *        collections will be updated one to one, and items will be either
2273     *        added or removed to match the new updated options. For example,
2274     *        if the chart has two series and we call `chart.update` with a
2275     *        configuration containing three series, one will be added. If we
2276     *        call `chart.update` with one series, one will be removed. Setting
2277     *        an empty `series` array will remove all series, but leaving out
2278     *        the`series` property will leave all series untouched. If the
2279     *        series have id's, the new series options will be matched by id,
2280     *        and the remaining ones removed.
2281     *
2282     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animation]
2283     *        Whether to apply animation, and optionally animation
2284     *        configuration. When `undefined`, it applies the animation that is
2285     *        set in the `chart.animation` option.
2286     *
2287     * @emits Highcharts.Chart#event:update
2288     * @emits Highcharts.Chart#event:afterUpdate
2289     */
2290    update(options, redraw, oneToOne, animation) {
2291        const chart = this, adders = {
2292            credits: 'addCredits',
2293            title: 'setTitle',
2294            subtitle: 'setSubtitle',
2295            caption: 'setCaption'
2296        }, isResponsiveOptions = options.isResponsiveOptions, itemsForRemoval = [];
2297        let updateAllAxes, updateAllSeries, runSetSize;
2298        fireEvent(chart, 'update', { options: options });
2299        // If there are responsive rules in action, undo the responsive rules
2300        // before we apply the updated options and replay the responsive rules
2301        // on top from the chart.redraw function (#9617).
2302        if (!isResponsiveOptions) {
2303            chart.setResponsive(false, true);
2304        }
2305        options = diffObjects(options, chart.options);
2306        chart.userOptions = merge(chart.userOptions, options);
2307        // If the top-level chart option is present, some special updates are
2308        // required
2309        const optionsChart = options.chart;
2310        if (optionsChart) {
2311            merge(true, chart.options.chart, optionsChart);
2312            // Add support for deprecated zooming options like zoomType, #17861
2313            this.setZoomOptions();
2314            // Setter function
vendor: 11,697 bytes, lines 2315-2601
2315            if ('className' in optionsChart) {
2316                chart.setClassName(optionsChart.className);
2317            }
2318            if ('inverted' in optionsChart ||
2319                'polar' in optionsChart ||
2320                'type' in optionsChart) {
2321                // Parse options.chart.inverted and options.chart.polar together
2322                // with the available series.
2323                chart.propFromSeries();
2324                updateAllAxes = true;
2325            }
2326            if ('alignTicks' in optionsChart) { // #6452
2327                updateAllAxes = true;
2328            }
2329            if ('events' in optionsChart) {
2330                // Chart event handlers
2331                registerEventOptions(this, optionsChart);
2332            }
2333            objectEach(optionsChart, function (val, key) {
2334                if (chart.propsRequireUpdateSeries.indexOf('chart.' + key) !==
2335                    -1) {
2336                    updateAllSeries = true;
2337                }
2338                // Only dirty box
2339                if (chart.propsRequireDirtyBox.indexOf(key) !== -1) {
2340                    chart.isDirtyBox = true;
2341                }
2342                // Chart setSize
2343                if (chart.propsRequireReflow.indexOf(key) !== -1) {
2344                    chart.isDirtyBox = true;
2345                    if (!isResponsiveOptions) {
2346                        runSetSize = true;
2347                    }
2348                }
2349            });
2350            if (!chart.styledMode && optionsChart.style) {
2351                chart.renderer.setStyle(chart.options.chart.style || {});
2352            }
2353        }
2354        // Moved up, because tooltip needs updated plotOptions (#6218)
2355        if (!chart.styledMode && options.colors) {
2356            this.options.colors = options.colors;
2357        }
2358        // Some option structures correspond one-to-one to chart objects that
2359        // have update methods, for example
2360        // options.credits => chart.credits
2361        // options.legend => chart.legend
2362        // options.title => chart.title
2363        // options.tooltip => chart.tooltip
2364        // options.subtitle => chart.subtitle
2365        // options.mapNavigation => chart.mapNavigation
2366        // options.navigator => chart.navigator
2367        // options.scrollbar => chart.scrollbar
2368        objectEach(options, function (val, key) {
2369            if (chart[key] &&
2370                typeof chart[key].update === 'function') {
2371                chart[key].update(val, false);
2372                // If a one-to-one object does not exist, look for an adder function
2373            }
2374            else if (typeof chart[adders[key]] === 'function') {
2375                chart[adders[key]](val);
2376                // Else, just merge the options. For nodes like loading, noData,
2377                // plotOptions
2378            }
2379            else if (key !== 'colors' &&
2380                chart.collectionsWithUpdate.indexOf(key) === -1) {
2381                merge(true, chart.options[key], options[key]);
2382            }
2383            if (key !== 'chart' &&
2384                chart.propsRequireUpdateSeries.indexOf(key) !== -1) {
2385                updateAllSeries = true;
2386            }
2387        });
2388        // Setters for collections. For axes and series, each item is referred
2389        // by an id. If the id is not found, it defaults to the corresponding
2390        // item in the collection, so setting one series without an id, will
2391        // update the first series in the chart. Setting two series without
2392        // an id will update the first and the second respectively (#6019)
2393        // chart.update and responsive.
2394        this.collectionsWithUpdate.forEach(function (coll) {
2395            if (options[coll]) {
2396                splat(options[coll]).forEach(function (newOptions, i) {
2397                    const hasId = defined(newOptions.id);
2398                    let item;
2399                    // Match by id
2400                    if (hasId) {
2401                        item = chart.get(newOptions.id);
2402                    }
2403                    // No match by id found, match by index instead
2404                    if (!item && chart[coll]) {
2405                        item = chart[coll][pick(newOptions.index, i)];
2406                        // Check if we grabbed an item with an existing but
2407                        // different id (#13541). Check that the item in this
2408                        // position is not internal (navigator).
2409                        if (item && ((hasId && defined(item.options.id)) ||
2410                            item.options.isInternal)) {
2411                            item = void 0;
2412                        }
2413                    }
2414                    if (item && item.coll === coll) {
2415                        item.update(newOptions, false);
2416                        if (oneToOne) {
2417                            item.touched = true;
2418                        }
2419                    }
2420                    // If oneToOne and no matching item is found, add one
2421                    if (!item && oneToOne && chart.collectionsWithInit[coll]) {
2422                        chart.collectionsWithInit[coll][0].apply(chart, 
2423                        // [newOptions, ...extraArguments, redraw=false]
2424                        [
2425                            newOptions
2426                        ].concat(
2427                        // Not all initializers require extra args
2428                        chart.collectionsWithInit[coll][1] || []).concat([
2429                            false
2430                        ])).touched = true;
2431                    }
2432                });
2433                // Add items for removal
2434                if (oneToOne) {
2435                    chart[coll].forEach(function (item) {
2436                        if (!item.touched && !item.options.isInternal) {
2437                            itemsForRemoval.push(item);
2438                        }
2439                        else {
2440                            delete item.touched;
2441                        }
2442                    });
2443                }
2444            }
2445        });
2446        itemsForRemoval.forEach(function (item) {
2447            if (item.chart && item.remove) { // #9097, avoid removing twice
2448                item.remove(false);
2449            }
2450        });
2451        if (updateAllAxes) {
2452            chart.axes.forEach(function (axis) {
2453                axis.update({}, false);
2454            });
2455        }
2456        // Certain options require the whole series structure to be thrown away
2457        // and rebuilt
2458        if (updateAllSeries) {
2459            chart.getSeriesOrderByLinks().forEach(function (series) {
2460                // Avoid removed navigator series
2461                if (series.chart) {
2462                    series.update({}, false);
2463                }
2464            }, this);
2465        }
2466        // Update size. Redraw is forced.
2467        const newWidth = optionsChart && optionsChart.width;
2468        const newHeight = optionsChart && (isString(optionsChart.height) ?
2469            relativeLength(optionsChart.height, newWidth || chart.chartWidth) :
2470            optionsChart.height);
2471        if (
2472        // In this case, run chart.setSize with newWidth and newHeight which
2473        // are undefined, only for reflowing chart elements because margin
2474        // or spacing has been set (#8190)
2475        runSetSize ||
2476            // In this case, the size is actually set
2477            (isNumber(newWidth) && newWidth !== chart.chartWidth) ||
2478            (isNumber(newHeight) && newHeight !== chart.chartHeight)) {
2479            chart.setSize(newWidth, newHeight, animation);
2480        }
2481        else if (pick(redraw, true)) {
2482            chart.redraw(animation);
2483        }
2484        fireEvent(chart, 'afterUpdate', {
2485            options: options,
2486            redraw: redraw,
2487            animation: animation
2488        });
2489    }
2490    /**
2491     * Shortcut to set the subtitle options. This can also be done from {@link
2492     * Chart#update} or {@link Chart#setTitle}.
2493     *
2494     * @function Highcharts.Chart#setSubtitle
2495     *
2496     * @param {Highcharts.SubtitleOptions} options
2497     *        New subtitle options. The subtitle text itself is set by the
2498     *        `options.text` property.
2499     */
2500    setSubtitle(options, redraw) {
2501        this.applyDescription('subtitle', options);
2502        this.layOutTitles(redraw);
2503    }
2504    /**
2505     * Set the caption options. This can also be done from {@link
2506     * Chart#update}.
2507     *
2508     * @function Highcharts.Chart#setCaption
2509     *
2510     * @param {Highcharts.CaptionOptions} options
2511     *        New caption options. The caption text itself is set by the
2512     *        `options.text` property.
2513     */
2514    setCaption(options, redraw) {
2515        this.applyDescription('caption', options);
2516        this.layOutTitles(redraw);
2517    }
2518    /**
2519     * Display the zoom button, so users can reset zoom to the default view
2520     * settings.
2521     *
2522     * @function Highcharts.Chart#showResetZoom
2523     *
2524     * @emits Highcharts.Chart#event:afterShowResetZoom
2525     * @emits Highcharts.Chart#event:beforeShowResetZoom
2526     */
2527    showResetZoom() {
2528        const chart = this, lang = defaultOptions.lang, btnOptions = chart.zooming.resetButton, theme = btnOptions.theme, alignTo = (btnOptions.relativeTo === 'chart' ||
2529            btnOptions.relativeTo === 'spacingBox' ?
2530            null :
2531            'plotBox');
2532        /**
2533         * @private
2534         */
2535        function zoomOut() {
2536            chart.zoomOut();
2537        }
2538        fireEvent(this, 'beforeShowResetZoom', null, function () {
2539            chart.resetZoomButton = chart.renderer
2540                .button(lang.resetZoom, null, null, zoomOut, theme)
2541                .attr({
2542                align: btnOptions.position.align,
2543                title: lang.resetZoomTitle
2544            })
2545                .addClass('highcharts-reset-zoom')
2546                .add()
2547                .align(btnOptions.position, false, alignTo);
2548        });
2549        fireEvent(this, 'afterShowResetZoom');
2550    }
2551    /**
2552     * Zoom the chart out after a user has zoomed in. See also
2553     * [Axis.setExtremes](/class-reference/Highcharts.Axis#setExtremes).
2554     *
2555     * @function Highcharts.Chart#zoomOut
2556     *
2557     * @emits Highcharts.Chart#event:selection
2558     */
2559    zoomOut() {
2560        fireEvent(this, 'selection', { resetSelection: true }, () => this.transform({ reset: true, trigger: 'zoom' }));
2561    }
2562    /**
2563     * Pan the chart by dragging the mouse across the pane. This function is
2564     * called on mouse move, and the distance to pan is computed from chartX
2565     * compared to the first chartX position in the dragging operation.
2566     *
2567     * @private
2568     * @function Highcharts.Chart#pan
2569     * @param {Highcharts.PointerEventObject} event
2570     * @param {string} panning
2571     */
2572    pan(event, panning) {
2573        const chart = this, panningOptions = (typeof panning === 'object' ?
2574            panning :
2575            {
2576                enabled: panning,
2577                type: 'x'
2578            }), type = panningOptions.type, axes = type && chart[{
2579            x: 'xAxis',
2580            xy: 'axes',
2581            y: 'yAxis'
2582        }[type]]
2583            .filter((axis) => axis.options.panningEnabled && !axis.options.isInternal), chartOptions = chart.options.chart;
2584        if (chartOptions?.panning) {
2585            chartOptions.panning = panningOptions;
2586        }
2587        fireEvent(this, 'pan', { originalEvent: event }, () => {
2588            chart.transform({
2589                axes,
2590                event,
2591                to: {
2592                    x: event.chartX - (chart.mouseDownX || 0),
2593                    y: event.chartY - (chart.mouseDownY || 0)
2594                },
2595                trigger: 'pan'
2596            });
2597            css(chart.container, { cursor: 'move' });
2598        });
2599    }
2600    /**
2601     * Pan and scale the chart. Used internally by mouse-pan, touch-p
2601an,
2602     * touch-zoom, and mousewheel zoom.
2603     *
2604     * The main positioning logic is created around two imaginary boxes. What is
2605     * currently within the `from` rectangle, should be transformed to fill up
2606     * the `to` rectangle.
2607     * - In a mouse zoom, the `from` rectangle is the selection, while the `to`
2608     *   rectangle is the full plot area.
2609     * - In a touch zoom, the `from` rectangle is made up of the last two-finger
2610     *   touch, while the `to`` rectangle is the current touch.
2611     * - In a mousewheel zoom, the `to` rectangle is a 10x10 px square,
2612     *   while the `to` rectangle reflects the scale around that.
2613     *
2614     * @private
2615     * @function Highcharts.Chart#transform
2616     */
2617    transform(params) {
2618        const { axes = this.axes, event, from = {}, reset, selection, to = {}, trigger } = params, { inverted, time } = this;
2619        let hasZoomed = false, displayButton, isAnyAxisPanning;
2620        // Remove active points for shared tooltip
2621        this.hoverPoints?.forEach((point) => point.setState());
2622        for (const axis of axes) {
2623            const { horiz, len, minPointOffset = 0, options, reversed } = axis, wh = horiz ? 'width' : 'height', xy = horiz ? 'x' : 'y', toLength = pick(to[wh], axis.len), fromLength = pick(from[wh], axis.len), 
2624            // If fingers pinched very close on this axis, treat as pan
2625            scale = Math.abs(toLength) < 10 ?
2626                1 :
2627                toLength / fromLength, fromCenter = (from[xy] || 0) + fromLength / 2 - axis.pos, toCenter = (to[xy] ?? axis.pos) +
2628                toLength / 2 - axis.pos, move = fromCenter - toCenter / scale, pointRangeDirection = (reversed && !inverted) ||
2629                (!reversed && inverted) ?
2630                -1 :
2631                1, minPx = move;
2632            // Zooming in multiple panes, zoom only in the pane that receives
2633            // the input
2634            if (!reset && (fromCenter < 0 || fromCenter > axis.len)) {
2635                continue;
2636            }
2637            let newMin = axis.toValue(minPx, true) +
2638                // Don't apply offset for selection (#20784)
2639                (selection || axis.isOrdinal ?
2640                    0 : minPointOffset * pointRangeDirection), newMax = axis.toValue(minPx + len / scale, true) -
2641                (
2642                // Don't apply offset for selection (#20784)
2643                selection || axis.isOrdinal ?
2644                    0 :
2645                    ((minPointOffset * pointRangeDirection) ||
2646                        // Polar zoom tests failed when this was not
2647                        // commented:
2648                        // (axis.isXAxis && axis.pointRangePadding) ||
2649                        0)), allExtremes = axis.allExtremes;
2650            if (newMin > newMax) {
2651                [newMin, newMax] = [newMax, newMin];
2652            }
2653            // General calculations of the full data extremes. It is calculated
2654            // on the first call to transform, then reused for subsequent
2655            // touch/pan calls. (#11315).
2656            if (scale === 1 &&
2657                !reset &&
2658                axis.coll === 'yAxis' &&
2659                !allExtremes) {
2660                for (const series of axis.series) {
2661                    const seriesExtremes = series.getExtremes(series.getProcessedData(true).modified
2662                        .getColumn('y') || [], true);
2663                    allExtremes ?? (allExtremes = {
2664                        dataMin: Number.MAX_VALUE,
2665                        dataMax: -Number.MAX_VALUE
2666                    });
2667                    if (isNumber(seriesExtremes.dataMin) &&
2668                        isNumber(seriesExtremes.dataMax)) {
2669                        allExtremes.dataMin = Math.min(seriesExtremes.dataMin, allExtremes.dataMin);
2670                        allExtremes.dataMax = Math.max(seriesExtremes.dataMax, allExtremes.dataMax);
2671                    }
2672                }
2673                axis.allExtremes = allExtremes;
2674            }
2675            const { dataMin, dataMax, min, max } = extend(axis.getExtremes(), allExtremes || {}), optionsMin = time.parse(options.min), optionsMax = time.parse(options.max), 
2676            // For boosted chart where data extremes are skipped
2677            safeDataMin = dataMin ?? optionsMin, safeDataMax = dataMax ?? optionsMax, range = newMax - newMin, padRange = axis.categories ? 0 : Math.min(range, safeDataMax - safeDataMin), paddedMin = safeDataMin - padRange * (defined(optionsMin) ? 0 : options.minPadding), paddedMax = safeDataMax + padRange * (defined(optionsMax) ? 0 : options.maxPadding), 
2678            // We're allowed to zoom outside the data extremes if we're
2679            // dealing with a bubble chart, if we're panning, or if we're
2680            // pinching or mousewheeling in.
2681            allowZoomOutside = axis.allowZoomOutside ||
2682                scale === 1 ||
2683                (trigger !== 'zoom' && scale > 1), 
2684            // Calculate the floor and the ceiling
2685            floor = Math.min(optionsMin ?? paddedMin, paddedMin, allowZoomOutside ? min : paddedMin), ceiling = Math.max(optionsMax ?? paddedMax, paddedMax, allowZoomOutside ? max : paddedMax);
2686            // It is not necessary to calculate extremes on ordinal axis,
2687            // because they are already calculated, so we don't want to override
2688            // them.
2689            if (!axis.isOrdinal ||
2690                axis.options.overscroll || // #21316
2691                scale !== 1 ||
2692                reset) {
2693                // If the new range spills over, either to the min or max,
2694                // adjust it.
2695                if (newMin < floor) {
2696                    newMin = floor;
2697                    if (scale >= 1) {
2698                        newMax = newMin + range;
2699                    }
2700                }
2701                if (newMax > ceiling) {
2702                    newMax = ceiling;
2703                    if (scale >= 1) {
2704                        newMin = newMax - range;
2705                    }
2706                }
2707                // Set new extremes if they are actually new
2708                if (reset || (axis.series.length &&
2709                    (newMin !== min || newMax !== max) &&
2710                    newMin >= floor &&
2711                    newMax <= ceiling)) {
2712                    if (selection) {
2713                        selection[axis.coll].push({
2714                            axis,
2715                            min: newMin,
2716                            max: newMax
2717                        });
2718                    }
2719                    else {
2720                        // Temporarily flag the axis as `isPanning` in order to
2721                        // disallow certain axis padding options that would make
2722                        // panning/zooming hard. Reset and redraw after the
2723                        // operation has finished.
2724                        axis.isPanning = trigger !== 'zoom';
2725                        if (axis.isPanning) {
2726                            isAnyAxisPanning = true; // #21319
2727                        }
2728                        axis.setExtremes(reset ? void 0 : newMin, reset ? void 0 : newMax, false, false, { move, trigger, scale });
2729                        if (!reset &&
2730                            (newMin > floor || newMax < ceiling) &&
2731                            trigger !== 'mousewheel') {
2732                            displayButton = true;
2733                        }
2734                    }
2735                    hasZoomed = true;
2736                }
2737                if (event) {
2738                    this[horiz ? 'mouseDownX' : 'mouseDownY'] =
2739                        event[horiz ? 'chartX' : 'chartY'];
2740                }
2741            }
2742        }
2743        if (hasZoomed) {
2744            if (selection) {
2745                fireEvent(this, 'selection', selection, 
2746                // Run transform again, this time without the selection data
2747                // so that the transform is applied.
2748                () => {
2749                    delete params.selection;
2750                    params.trigger = 'zoom';
2751                    this.transform(params);
2752                });
2753            }
2754            else {
2755                // Show or hide the Reset zoom button, but not while panning
2756                if (displayButton &&
2757                    !isAnyAxisPanning &&
2758                    !this.resetZoomButton) {
2759                    this.showResetZoom();
2760                }
2761                else if (!displayButton && this.resetZoomButton) {
2762                    this.resetZoomButton = this.resetZoomButton.destroy();
2763                }
2764                this.redraw(trigger === 'zoom' &&
2765                    (this.options.chart.animation ?? this.pointCount < 100));
2766            }
2767        }
2768        return hasZoomed;
2769    }
2770}
2771extend(Chart.prototype, {
2772    // Hook for adding callbacks in modules
2773    callbacks: [],
2774    /**
2775     * These collections (arrays) implement `Chart.addSomething` method used in
2776     * chart.update() to create new object in the collection. Equivalent for
2777     * deleting is resolved by simple `Something.remove()`.
2778     *
2779     * Note: We need to define these references after initializers are bound to
2780     * chart's prototype.
2781     *
2782     * @private
2783     */
2784    collectionsWithInit: {
2785        // CollectionName: [ initializingMethod, [extraArguments] ]
2786        xAxis: [Chart.prototype.addAxis, [true]],
2787        yAxis: [Chart.prototype.addAxis, [false]],
2788        series: [Chart.prototype.addSeries]
2789    },
2790    /**
2791     * These collections (arrays) implement update() methods with support for
2792     * one-to-one option.
2793     * @private
2794     */
2795    collectionsWithUpdate: [
2796        'xAxis',
2797        'yAxis',
2798        'series'
2799    ],
2800    /**
2801     * These properties cause isDirtyBox to be set to true when updating. Can be
2802     * extended from plugins.
2803     * @private
2804     */
2805    propsRequireDirtyBox: [
2806        'backgroundColor',
2807        'borderColor',
2808        'borderWidth',
2809        'borderRadius',
2810        'plotBackgroun
2810dColor',
2811        'plotBackgroundImage',
2812        'plotBorderColor',
2813        'plotBorderWidth',
2814        'plotShadow',
2815        'shadow'
2816    ],
2817    /**
2818     * These properties require a full reflow of chart elements, best
2819     * implemented through running `Chart.setSize` internally (#8190).
2820     * @private
2821     */
2822    propsRequireReflow: [
2823        'margin',
2824        'marginTop',
2825        'marginRight',
2826        'marginBottom',
2827        'marginLeft',
2828        'spacing',
2829        'spacingTop',
2830        'spacingRight',
2831        'spacingBottom',
2832        'spacingLeft'
2833    ],
2834    /**
2835     * These properties cause all series to be updated when updating. Can be
2836     * extended from plugins.
2837     * @private
2838     */
2839    propsRequireUpdateSeries: [
2840        'chart.inverted',
2841        'chart.polar',
2842        'chart.ignoreHiddenSeries',
2843        'chart.type',
2844        'colors',
2845        'plotOptions',
2846        'time',
2847        'tooltip'
2848    ]
2849});
2850/* *
2851 *
2852 *  Default Export
2853 *
2854 * */
2855export default Chart;
2856/* *
2857 *
2858 *  API Declarations
2859 *
2860 * */
2861/**
2862 * Callback for chart constructors.
2863 *
2864 * @callback Highcharts.ChartCallbackFunction
2865 *
2866 * @param {Highcharts.Chart} chart
2867 *        Created chart.
2868 */
2869/**
2870 * Format a number and return a string based on input settings.
2871 *
2872 * @callback Highcharts.NumberFormatterCallbackFunction
2873 *
2874 * @param {number} number
2875 *        The input number to format.
2876 *
2877 * @param {number} decimals
2878 *        The amount of decimals. A value of -1 preserves the amount in the
2879 *        input number.
2880 *
2881 * @param {string} [decimalPoint]
2882 *        The decimal point, defaults to the one given in the lang options, or
2883 *        a dot.
2884 *
2885 * @param {string} [thousandsSep]
2886 *        The thousands separator, defaults to the one given in the lang
2887 *        options, or a space character.
2888 *
2889 * @return {string} The formatted number.
2890 */
2891/**
2892 * The chart title. The title has an `update` method that allows modifying the
2893 * options directly or indirectly via `chart.update`.
2894 *
2895 * @interface Highcharts.TitleObject
2896 * @extends Highcharts.SVGElement
2897 */ /**
2898* Modify options for the title.
2899*
2900* @function Highcharts.TitleObject#update
2901*
2902* @param {Highcharts.TitleOptions} titleOptions
2903*        Options to modify.
2904*
2905* @param {boolean} [redraw=true]
2906*        Whether to redraw the chart after the title is altered. If doing more
2907*        operations on the chart, it is a good idea to set redraw to false and
2908*        call {@link Chart#redraw} after.
2909*/
2910/**
2911 * The chart subtitle. The subtitle has an `update` method that
2912 * allows modifying the options directly or indirectly via
2913 * `chart.update`.
2914 *
2915 * @interface Highcharts.SubtitleObject
2916 * @extends Highcharts.SVGElement
2917 */ /**
2918* Modify options for the subtitle.
2919*
2920* @function Highcharts.SubtitleObject#update
2921*
2922* @param {Highcharts.SubtitleOptions} subtitleOptions
2923*        Options to modify.
2924*
2925* @param {boolean} [redraw=true]
2926*        Whether to redraw the chart after the subtitle is altered. If doing
2927*        more operations on the chart, it is a good idea to set redraw to false
2928*        and call {@link Chart#redraw} after.
2929*/
2930/**
2931 * The chart caption. The caption has an `update` method that
2932 * allows modifying the options directly or indirectly via
2933 * `chart.update`.
2934 *
2935 * @interface Highcharts.CaptionObject
2936 * @extends Highcharts.SVGElement
2937 */ /**
2938* Modify options for the caption.
2939*
2940* @function Highcharts.CaptionObject#update
2941*
2942* @param {Highcharts.CaptionOptions} captionOptions
2943*        Options to modify.
2944*
2945* @param {boolean} [redraw=true]
2946*        Whether to redraw the chart after the caption is altered. If doing
2947*        more operations on the chart, it is a good idea to set redraw to false
2948*        and call {@link Chart#redraw} after.
2949*/
2950/**
2951 * @interface Highcharts.ChartIsInsideOptionsObject
2952 */ /**
2953* @name Highcharts.ChartIsInsideOptionsObject#axis
2954* @type {Highcharts.Axis|undefined}
2955*/ /**
2956* @name Highcharts.ChartIsInsideOptionsObject#ignoreX
2957* @type {boolean|undefined}
2958*/ /**
2959* @name Highcharts.ChartIsInsideOptionsObject#ignoreY
2960* @type {boolean|undefined}
2961*/ /**
2962* @name Highcharts.ChartIsInsideOptionsObject#inverted
2963* @type {boolean|undefined}
2964*/ /**
2965* @name Highcharts.ChartIsInsideOptionsObject#paneCoordinates
2966* @type {boolean|undefined}
2967*/ /**
2968* @name Highcharts.ChartIsInsideOptionsObject#series
2969* @type {Highcharts.Series|undefined}
2970*/ /**
2971* @name Highcharts.ChartIsInsideOptionsObject#visiblePlotOnly
2972* @type {boolean|undefined}
2973*/
2974''; // 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.