PageSourceSearch

https://provence-alpes-cotedazur.com/app/dist/crt-paca/addons/wood…/Core/Renderer/SVG/SVGRenderer.js

js provence-alpes-cotedazur.com collected 2026-10-02 03:27:31 UTC 66,429 bytes, 1,883 lines download raw bytes

vendor: 26,164 bytes, lines 1-726
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 AST from '../HTML/AST.js';
12import D from '../../Defaults.js';
13const { defaultOptions } = D;
14import Color from '../../Color/Color.js';
15import H from '../../Globals.js';
16const { charts, deg2rad, doc, isFirefox, isMS, isWebKit, noop, SVG_NS, symbolSizes, win } = H;
17import RendererRegistry from '../RendererRegistry.js';
18import SVGElement from './SVGElement.js';
19import SVGLabel from './SVGLabel.js';
20import Symbols from './Symbols.js';
21import TextBuilder from './TextBuilder.js';
22import U from '../../Utilities.js';
23const { addEvent, attr, createElement, crisp, css, defined, destroyObjectProperties, extend, isArray, isNumber, isObject, isString, merge, pick, pInt, replaceNested, uniqueKey } = U;
24/* *
25 *
26 *  Variables
27 *
28 * */
29let hasInternalReferenceBug;
30/* *
31 *
32 *  Class
33 *
34 * */
35/* eslint-disable no-invalid-this, valid-jsdoc */
36/**
37 * Allows direct access to the Highcharts rendering layer in order to draw
38 * primitive shapes like circles, rectangles, paths or text directly on a chart,
39 * or independent from any chart. The SVGRenderer represents a wrapper object
40 * for SVG in modern browsers.
41 *
42 * An existing chart's renderer can be accessed through {@link Chart.renderer}.
43 * The renderer can also be used completely decoupled from a chart.
44 *
45 * See [How to use the SVG Renderer](
46 * https://www.highcharts.com/docs/advanced-chart-features/renderer) for a
47 * comprehensive tutorial.
48 *
49 * @sample highcharts/members/renderer-on-chart
50 *         Annotating a chart programmatically.
51 * @sample highcharts/members/renderer-basic
52 *         Independent SVG drawing.
53 *
54 * @example
55 * // Use directly without a chart object.
56 * let renderer = new Highcharts.Renderer(parentNode, 600, 400);
57 *
58 * @class
59 * @name Highcharts.SVGRenderer
60 *
61 * @param {Highcharts.HTMLDOMElement} container
62 *        Where to put the SVG in the web page.
63 *
64 * @param {number} width
65 *        The width of the SVG.
66 *
67 * @param {number} height
68 *        The height of the SVG.
69 *
70 * @param {Highcharts.CSSObject} [style]
71 *        The box style, if not in styleMode
72 *
73 * @param {boolean} [forExport=false]
74 *        Whether the rendered content is intended for export.
75 *
76 * @param {boolean} [allowHTML=true]
77 *        Whether the renderer is allowed to include HTML text, which will be
78 *        projected on top of the SVG.
79 *
80 * @param {boolean} [styledMode=false]
81 *        Whether the renderer belongs to a chart that is in styled mode.
82 *        If it does, it will avoid setting presentational attributes in
83 *        some cases, but not when set explicitly through `.attr` and `.css`
84 *        etc.
85 */
86class SVGRenderer {
87    /**
88     * The root `svg` node of the renderer.
89     *
90     * @name Highcharts.SVGRenderer#box
91     * @type {Highcharts.SVGDOMElement}
92     */
93    /**
94     * The wrapper for the root `svg` node of the renderer.
95     *
96     * @name Highcharts.SVGRenderer#boxWrapper
97     * @type {Highcharts.SVGElement}
98     */
99    /**
100     * A pointer to the `defs` node of the root SVG.
101     *
102     * @name Highcharts.SVGRenderer#defs
103     * @type {Highcharts.SVGElement}
104     */
105    /**
106     * Whether the rendered content is intended for export.
107     *
108     * @name Highcharts.SVGRenderer#forExport
109     * @type {boolean | undefined}
110     */
111    /**
112     * Page url used for internal references.
113     *
114     * @private
115     * @name Highcharts.SVGRenderer#url
116     * @type {string}
117     */
118    /**
119     * Initialize the SVGRenderer. Overridable initializer function that takes
120     * the same parameters as the constructor.
121     *
122     * @function Highcharts.SVGRenderer#init
123     *
124     * @param {Highcharts.HTMLDOMElement} container
125     * Where to put the SVG in the web page.
126     *
127     * @param {number} width
128     * The width of the SVG.
129     *
130     * @param {number} height
131     * The height of the SVG.
132     *
133     * @param {Highcharts.CSSObject} [style]
134     * The box style, if not in styleMode
135     *
136     * @param {boolean} [forExport=false]
137     * Whether the rendered content is intended for export.
138     *
139     * @param {boolean} [allowHTML=true]
140     * Whether the renderer is allowed to include HTML text, which will be
141     * projected on top of the SVG.
142     *
143     * @param {boolean} [styledMode=false]
144     * Whether the renderer belongs to a chart that is in styled mode. If it
145     * does, it will avoid setting presentational attributes in some cases, but
146     * not when set explicitly through `.attr` and `.css` etc.
147     */
148    constructor(container, width, height, style, forExport, allowHTML, styledMode) {
149        const renderer = this, boxWrapper = renderer
150            .createElement('svg')
151            .attr({
152            version: '1.1',
153            'class': 'highcharts-root'
154        }), element = boxWrapper.element;
155        if (!styledMode) {
156            boxWrapper.css(this.getStyle(style || {}));
157        }
158        container.appendChild(element);
159        // Always use ltr on the container, otherwise text-anchor will be
160        // flipped and text appear outside labels, buttons, tooltip etc (#3482)
161        attr(container, 'dir', 'ltr');
162        // For browsers other than IE, add the namespace attribute (#1978)
163        if (container.innerHTML.indexOf('xmlns') === -1) {
164            attr(element, 'xmlns', this.SVG_NS);
165        }
166        this.box = element;
167        this.boxWrapper = boxWrapper;
168        this.alignedObjects = [];
169        this.url = this.getReferenceURL();
170        // Add description
171        const desc = this.createElement('desc').add();
172        desc.element.appendChild(doc.createTextNode('Created with @product.name@ @product.version@'));
173        this.defs = this.createElement('defs').add();
174        this.allowHTML = allowHTML;
175        this.forExport = forExport;
176        this.styledMode = styledMode;
177        this.gradients = {}; // Object where gradient SvgElements are stored
178        this.cache = {}; // Cache for numerical bounding boxes
179        this.cacheKeys = [];
180        this.imgCount = 0;
181        this.rootFontSize = boxWrapper.getStyle('font-size');
182        renderer.setSize(width, height, false);
183        // Issue 110 workaround:
184        // In Firefox, if a div is positioned by percentage, its pixel position
185        // may land between pixels. The container itself doesn't display this,
186        // but an SVG element inside this container will be drawn at subpixel
187        // precision. In order to draw sharp lines, this must be compensated
188        // for. This doesn't seem to work inside iframes though (like in
189        // jsFiddle).
190        let subPixelFix, rect;
191        if (isFirefox && container.getBoundingClientRect) {
192            subPixelFix = function () {
193                css(container, { left: 0, top: 0 });
194                rect = container.getBoundingClientRect();
195                css(container, {
196                    left: (Math.ceil(rect.left) - rect.left) + 'px',
197                    top: (Math.ceil(rect.top) - rect.top) + 'px'
198                });
199            };
200            // Run the fix now
201            subPixelFix();
202            // Run it on resize
203            renderer.unSubPixelFix = addEvent(win, 'resize', subPixelFix);
204        }
205    }
206    /* *
207     *
208     *  Functions
209     *
210     * */
211    /**
212     * General method for adding a definition to the SVG `defs` tag. Can be used
213     * for gradients, fills, filters etc. Styled mode only. A hook for adding
214     * general definitions to the SVG's defs tag. Definitions can be referenced
215     * from the CSS by its `id`. Read more in
216     * [gradients, shadows and patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns).
217     * Styled mode only.
218     *
219     * @function Highcharts.SVGRenderer#definition
220     *
221     * @param {Highcharts.ASTNode} def
222     * A serialized form of an SVG definition, including children.
223     *
224     * @return {Highcharts.SVGElement}
225     * The inserted node.
226     */
227    definition(def) {
228        const ast = new AST([def]);
229        return ast.addToDOM(this.defs.element);
230    }
231    /**
232     * Get the prefix needed for internal URL references to work in certain
233     * cases. Some older browser versions had a bug where internal url
234     * references in SVG attributes, on the form `url(#some-id)`, would fail if
235     * a base tag was present in the page. There were also issues with
236     * `history.pushState` related to this prefix.
237     *
238     * Related issues: #24, #672, #1070, #5244.
239     *
240     * The affected browsers are:
241     * - Chrome <= 53 (May 2018)
242     * - Firefox <= 51 (January 2017)
243     * - Safari/Mac <= 12.1 (2018 or 2019)
244     * - Safari/iOS <= 13
245     *
246     * @todo Remove this hack when time has passed. All the affected browsers
247     * are evergreens, so it is increasingly unlikely that users are affected by
248     * the bug.
249     *
250     * @return {string}
251     * The prefix to use. An empty string for modern browsers.
252     */
253    getReferenceURL() {
254        if ((isFirefox || isWebKit) &&
255            doc.getElementsByTagName('base').length) {
256            // Detect if a clip path is taking effect by performing a hit test
257            // outside the clipped area. If the hit element is the rectangle
258            // that was supposed to be clipped, the bug is present. This only
259            // has to be performed once per page load, so we store the result
260            // locally in the module.
261            if (!defined(hasInternalReferenceBug)) {
262                const id = uniqueKey();
263                const ast = new AST([{
264                        tagName: 'svg',
265                        attributes: {
266                            width: 8,
267                            height: 8
268                        },
269                        children: [{
270                                tagName: 'defs',
271                                children: [{
272                                        tagName: 'clipPath',
273                                        attributes: {
274                                            id
275                                        },
276                                        children: [{
277                                                tagName: 'rect',
278                                                attributes: {
279                                                    width: 4,
280                                                    height: 4
281                                                }
282                                            }]
283                                    }]
284                            }, {
285                                tagName: 'rect',
286                                attributes: {
287                                    id: 'hitme',
288                                    width: 8,
289                                    height: 8,
290                                    'clip-path': `url(#${id})`,
291                                    fill: 'rgba(0,0,0,0.001)'
292                                }
293                            }]
294                    }]);
295                const svg = ast.addToDOM(doc.body);
296                css(svg, {
297                    position: 'fixed',
298                    top: 0,
299                    left: 0,
300                    zIndex: 9e5
301                });
302                const hitElement = doc.elementFromPoint(6, 6);
303                hasInternalReferenceBug = (hitElement && hitElement.id) === 'hitme';
304                doc.body.removeChild(svg);
305            }
306            if (hasInternalReferenceBug) {
307                // Scan alert #[72]: Loop for nested patterns
308                return replaceNested(win.location.href.split('#')[0], // Remove hash
309                [/<[^>]*>/g, ''], // Wing cut HTML
310                [/([\('\)])/g, '\\$1'], // Escape parantheses and quotes
311                [/ /g, '%20'] // Replace spaces (needed for Safari only)
312                );
313            }
314        }
315        return '';
316    }
317    /**
318     * Get the global style setting for the renderer.
319     *
320     * @private
321     * @function Highcharts.SVGRenderer#getStyle
322     *
323     * @param {Highcharts.CSSObject} style
324     * Style settings.
325     *
326     * @return {Highcharts.CSSObject}
327     * The style settings mixed with defaults.
328     */
329    getStyle(style) {
330        this.style = extend({
331            fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", ' +
332                'Roboto, Helvetica, Arial, "Apple Color Emoji", ' +
333                '"Segoe UI Emoji", "Segoe UI Symbol", sans-serif',
334            fontSize: '1rem'
335        }, style);
336        return this.style;
337    }
338    /**
339     * Apply the global style on the renderer, mixed with the default styles.
340     *
341     * @function Highcharts.SVGRenderer#setStyle
342     *
343     * @param {Highcharts.CSSObject} style
344     * CSS to apply.
345     */
346    setStyle(style) {
347        this.boxWrapper.css(this.getStyle(style));
348    }
349    /**
350     * Detect whether the renderer is hidden. This happens when one of the
351     * parent elements has `display: none`. Used internally to detect when we
352     * need to render preliminarily in another div to get the text bounding
353     * boxes right.
354     *
355     * @function Highcharts.SVGRenderer#isHidden
356     *
357     * @return {boolean}
358     * True if it is hidden.
359     */
360    isHidden() {
361        return !this.boxWrapper.getBBox().width;
362    }
363    /**
364     * Destroys the renderer and its allocated members.
365     *
366     * @function Highcharts.SVGRenderer#destroy
367     *
368     * @return {null}
369     * Pass through value.
370     */
371    destroy() {
372        const renderer = this, rendererDefs = renderer.defs;
373        renderer.box = null;
374        renderer.boxWrapper = renderer.boxWrapper.destroy();
375        // Call destroy on all gradient elements
376        destroyObjectProperties(renderer.gradients || {});
377        renderer.gradients = null;
378        renderer.defs = rendererDefs.destroy();
379        // Remove sub pixel fix handler (#982)
380        if (renderer.unSubPixelFix) {
381            renderer.unSubPixelFix();
382        }
383        renderer.alignedObjects = null;
384        return null;
385    }
386    /**
387     * Create a wrapper for an SVG element. Serves as a factory for
388     * {@link SVGElement}, but this function is itself mostly called from
389     * primitive factories like {@link SVGRenderer#path}, {@link
390     * SVGRenderer#rect} or {@link SVGRenderer#text}.
391     *
392     * @function Highcharts.SVGRenderer#createElement
393     *
394     * @param {string} nodeName
395     * The node name, for example `rect`, `g` etc.
396     *
397     * @return {Highcharts.SVGElement}
398     * The generated SVGElement.
399     */
400    createElement(nodeName) {
401        return new this.Element(this, nodeName);
402    }
403    /**
404     * Get converted radial gradient attributes according to the radial
405     * reference. Used internally from the {@link SVGElement#colorGradient}
406     * function.
407     *
408     * @private
409     * @function Highcharts.SVGRenderer#getRadialAttr
410     */
411    getRadialAttr(radialReference, gradAttr) {
412        return {
413            cx: (radialReference[0] - radialReference[2] / 2) +
414                (gradAttr.cx || 0) * radialReference[2],
415            cy: (radialReference[1] - radialReference[2] / 2) +
416                (gradAttr.cy || 0) * radialReference[2],
417            r: (gradAttr.r || 0) * radialReference[2]
418        };
419    }
420    /**
421     * Create a drop shadow definition and return its id
422     *
423     * @private
424     * @function Highcharts.SVGRenderer#shadowDefinition
425     *
426     * @param {boolean|Highcharts.ShadowOptionsObject} [shadowOptions] The
427     *        shadow options. If `true`, the default options are applied
428     */
429    shadowDefinition(shadowOptions) {
430        const id = [
431            `highcharts-drop-shadow-${this.chartIndex}`,
432            ...Object.keys(shadowOptions)
433                .map((key) => `${key}-${shadowOptions[key]}`)
434        ].join('-').toLowerCase().replace(/[^a-z\d\-]/g, ''), options = merge({
435            color: '#000000',
436            offsetX: 1,
437            offsetY: 1,
438            opacity: 0.15,
439            width: 5
440        }, shadowOptions);
441        if (!this.defs.element.querySelector(`#${id}`)) {
442            this.definition({
443                tagName: 'filter',
444                attributes: {
445                    id,
446                    filterUnits: options.filterUnits
447                },
448                children: this.getShadowFilterContent(options)
449            });
450        }
451        return id;
452    }
453    /**
454     * Get shadow filter content.
455     * NOTE! Overridden in es5 module for IE11 compatibility.
456     *
457     * @private
458     * @function Highcharts.SVGRenderer#getShadowFilterContent
459     *
460     * @param {ShadowOptionsObject} options
461     * The shadow options.
462     * @return {Array<AST.Node>}
463     * The shadow filter content.
464     */
465    getShadowFilterContent(options) {
466        return [{
467                tagName: 'feDropShadow',
468                attributes: {
469                    dx: options.offsetX,
470                    dy: options.offsetY,
471                    'flood-color': options.color,
472                    // Tuned and modified to keep a preserve compatibility
473                    // with the old settings
474                    'flood-opacity': Math.min(options.opacity * 5, 1),
475                    stdDeviation: options.width / 2
476                }
477            }];
478    }
479    /**
480     * Parse a simple HTML string into SVG tspans. Called internally when text
481     * is set on an SVGElement. The function supports a subset of HTML tags, CSS
482     * text features like `width`, `text-overflow`, `white-space`, and also
483     * attributes like `href` and `style`.
484     *
485     * @private
486     * @function Highcharts.SVGRenderer#buildText
487     *
488     * @param {Highcharts.SVGElement} wrapper
489     * The parent SVGElement.
490     */
491    buildText(wrapper) {
492        new TextBuilder(wrapper).buildSVG();
493    }
494    /**
495     * Returns white for dark colors and black for bright colors, based on W3C's
496     * definition of [Relative luminance](
497     * https://www.w3.org/WAI/GL/wiki/Relative_luminance).
498     *
499     * @function Highcharts.SVGRenderer#getContrast
500     *
501     * @param {Highcharts.ColorString} color
502     * The color to get the contrast for.
503     *
504     * @return {Highcharts.ColorString}
505     * The contrast color, either `#000000` or `#FFFFFF`.
506     */
507    getContrast(color) {
508        // #6216, #17273
509        const rgba = Color.parse(color).rgba
510            .map((b8) => {
511            const c = b8 / 255;
512            return c <= 0.03928 ?
513                c / 12.92 :
514                Math.pow((c + 0.055) / 1.055, 2.4);
515        });
516        // Relative luminance
517        const l = 0.2126 * rgba[0] + 0.7152 * rgba[1] + 0.0722 * rgba[2];
518        // Use white or black based on which provides more contrast
519        return 1.05 / (l + 0.05) > (l + 0.05) / 0.05 ? '#FFFFFF' : '#000000';
520    }
521    /**
522     * Create a button with preset states. Styles for the button can either be
523     * set as arguments, or a general theme for all buttons can be set by the
524     * `global.buttonTheme` option.
525     *
526     * @function Highcharts.SVGRenderer#button
527     *
528     * @param {string} text
529     * The text or HTML to draw.
530     *
531     * @param {number} x
532     * The x position of the button's left side.
533     *
534     * @param {number} y
535     * The y position of the button's top side.
536     *
537     * @param {Highcharts.EventCallbackFunction<Highcharts.SVGElement>} callback
538     * The function to execute on button click or touch.
539     *
540     * @param {Highcharts.SVGAttributes} [theme]
541     * SVG attributes for the normal state.
542     *
543     * @param {Highcharts.SVGAttributes} [hoverState]
544     * SVG attributes for the hover state.
545     *
546     * @param {Highcharts.SVGAttributes} [selectState]
547     * SVG attributes for the pressed state.
548     *
549     * @param {Highcharts.SVGAttributes} [disabledState]
550     * SVG attributes for the disabled state.
551     *
552     * @param {Highcharts.SymbolKeyValue} [shape=rect]
553     * The shape type.
554     *
555     * @param {boolean} [useHTML=false]
556     * Whether to use HTML to render the label.
557     *
558     * @return {Highcharts.SVGElement}
559     * The button element.
560     */
561    button(text, x, y, callback, theme = {}, hoverState, selectState, disabledState, shape, useHTML) {
562        const label = this.label(text, x, y, shape, void 0, void 0, useHTML, void 0, 'button'), styledMode = this.styledMode, args = arguments;
563        let curState = 0;
564        theme = merge(defaultOptions.global.buttonTheme, theme);
565        // @todo Consider moving this to a lower level, like .attr
566        if (styledMode) {
567            delete theme.fill;
568            delete theme.stroke;
569            delete theme['stroke-width'];
570        }
571        const states = theme.states || {}, normalStyle = theme.style || {};
572        delete theme.states;
573        delete theme.style;
574        // Presentational
575        const stateAttribs = [
576            AST.filterUserAttributes(theme)
577        ], 
578        // The string type is a mistake, it is just for compliance with
579        // SVGAttribute and is not used in button theme.
580        stateStyles = [normalStyle];
581        if (!styledMode) {
582            ['hover', 'select', 'disabled'].forEach((stateName, i) => {
583                stateAttribs.push(merge(stateAttribs[0], AST.filterUserAttributes(args[i + 5] || states[stateName] || {})));
584                stateStyles.push(stateAttribs[i + 1].style);
585                delete stateAttribs[i + 1].style;
586            });
587        }
588        // Add the events. IE9 and IE10 need mouseover and mouseout to function
589        // (#667).
590        addEvent(label.element, isMS ? 'mouseover' : 'mouseenter', function () {
591            if (curState !== 3) {
592                label.setState(1);
593            }
594        });
595        addEvent(label.element, isMS ? 'mouseout' : 'mouseleave', function () {
596            if (curState !== 3) {
597                label.setState(curState);
598            }
599        });
600        label.setState = (state = 0) => {
601            // Hover state is temporary, don't record it
602            if (state !== 1) {
603                label.state = curState = state;
604            }
605            // Update visuals
606            label
607                .removeClass(/highcharts-button-(normal|hover|pressed|disabled)/)
608                .addClass('highcharts-button-' +
609                ['normal', 'hover', 'pressed', 'disabled'][state]);
610            if (!styledMode) {
611                label.attr(stateAttribs[state]);
612                const css = stateStyles[state];
613                if (isObject(css)) {
614                    label.css(css);
615                }
616            }
617        };
618        label.attr(stateAttribs[0]);
619        // Presentational attributes
620        if (!styledMode) {
621            label.css(extend({ cursor: 'default' }, normalStyle));
622            // HTML labels don't need to handle pointer events because click and
623            // mouseenter/mouseleave is bound to the underlying <g> element.
624            // Should this be reconsidered, we need more complex logic to share
625            // events between the <g> and its <div> counterpart, and avoid
626            // triggering mouseenter/mouseleave when hovering from one to the
627            // other (#17440).
628            if (useHTML) {
629                label.text.css({ pointerEvents: 'none' });
630            }
631        }
632        return label
633            .on('touchstart', (e) => e.stopPropagation())
634            .on('click', function (e) {
635            if (curState !== 3) {
636                callback.call(label, e);
637            }
638        });
639    }
640    /**
641     * Make a straight line crisper by not spilling out to neighbour pixels.
642     *
643     * @function Highcharts.SVGRenderer#crispLine
644     *
645     * @param {Highcharts.SVGPathArray} points
646     *        The original points on the format `[['M', 0, 0], ['L', 100, 0]]`.
647     *
648     * @param {number} width
649     *        The width of the line.
650     *
651     * @return {Highcharts.SVGPathArray}
652     *         The original points array, but modified to render crisply.
653     */
654    crispLine(points, width) {
655        const [start, end] = points;
656        // Normalize to a crisp line
657        if (defined(start[1]) && start[1] === end[1]) {
658            start[1] = end[1] = crisp(start[1], width);
659        }
660        if (defined(start[2]) && start[2] === end[2]) {
661            start[2] = end[2] = crisp(start[2], width);
662        }
663        return points;
664    }
665    /**
666     * Draw a path, wraps the SVG `path` element.
667     *
668     * @sample highcharts/members/renderer-path-on-chart/
669     *         Draw a path in a chart
670     * @sample highcharts/members/renderer-path/
671     *         Draw a path independent from a chart
672     *
673     * @example
674     * let path = renderer.path(['M', 10, 10, 'L', 30, 30, 'z'])
675     *     .attr({ stroke: '#ff00ff' })
676     *     .add();
677     *
678     * @function Highcharts.SVGRenderer#path
679     *
680     * @param {Highcharts.SVGPathArray} [path]
681     * An SVG path definition in array form.
682     *
683     * @return {Highcharts.SVGElement}
684     * The generated wrapper element.
685     *
686     */ /**
687    * Draw a path, wraps the SVG `path` element.
688    *
689    * @function Highcharts.SVGRenderer#path
690    *
691    * @param {Highcharts.SVGAttributes} [attribs]
692    * The initial attributes.
693    *
694    * @return {Highcharts.SVGElement}
695    * The generated wrapper element.
696    */
697    path(path) {
698        const attribs = (this.styledMode ? {} : {
699            fill: 'none'
700        });
701        if (isArray(path)) {
702            attribs.d = path;
703        }
704        else if (isObject(path)) { // Attributes
705            extend(attribs, path);
706        }
707        return this.createElement('path').attr(attribs);
708    }
709    /**
710     * Draw a circle, wraps the SVG `circle` element.
711     *
712     * @sample highcharts/members/renderer-circle/
713     *         Drawing a circle
714     *
715     * @function Highcharts.SVGRenderer#circle
716     *
717     * @param {number} [x]
718     * The center x position.
719     *
720     * @param {number} [y]
721     * The center y position.
722     *
723     * @param {number} [r]
724     * The radius.
725     *
726     * @return {Highcharts.SVGElement}
727     * The generated wrapper element.
728     */ /**
729    * Draw a circle, wraps the SVG `circle` element.
730    *
731    * @function Highcharts.SVGRenderer#circle
732    *
733    * @param {Highcharts.SVGAttributes} [attribs]
734    * The initial attributes.
735    *
736    * @return {Highcharts.SVGElement}
737    * The generated wrapper element.
738    */
739    circle(x, y, r) {
740        const attribs = (isObject(x) ?
741            x :
742            typeof x === 'undefined' ? {} : { x: x, y: y, r: r }), wrapper = this.createElement('circle');
743        // Setting x or y translates to cx and cy
744        wrapper.xSetter = wrapper.ySetter = function (value, key, element) {
745            element.setAttribute('c' + key, value);
746        };
747        return wrapper.attr(attribs);
748    }
749    /**
750     * Draw and return an arc.
751     *
752     * @sample highcharts/members/renderer-arc/
753     *         Drawing an arc
754     *
755     * @function Highcharts.SVGRenderer#arc
756     *
757     * @param {number} [x=0]
758     * Center X position.
759     *
760     * @param {number} [y=0]
761     * Center Y position.
762     *
763     * @param {number} [r=0]
764     * The outer radius' of the arc.
765     *
766     * @param {number} [innerR=0]
767     * Inner radius like used in donut charts.
768     *
769     * @param {number} [start=0]
770     * The starting angle of the arc in radians, where 0 is to the right and
771     * `-Math.PI/2` is up.
772     *
773     * @param {number} [end=0]
774     * The ending angle of the arc in radians, where 0 is to the right and
775     * `-Math.PI/2` is up.
776     *
777     * @return {Highcharts.SVGElement}
778     * The generated wrapper element.
779     */ /**
780    * Draw and return an arc. Overloaded function that takes arguments object.
781    *
782    * @function Highcharts.SVGRenderer#arc
783    *
784    * @param {Highcharts.SVGAttributes} attribs
785    * Initial SVG attributes.
786    *
787    * @return {Highcharts.SVGElement}
788    * The generated wrapper element.
789    */
790    arc(x, y, r, innerR, start, end) {
791        let options;
792        if (isObject(x)) {
793            options = x;
794            y = options.y;
795            r = options.r;
796            innerR = options.innerR;
797            start = options.start;
798            end = options.end;
799            x = options.x;
800        }
801        else {
802            options = { innerR, start, end };
803        }
804        // Arcs are defined as symbols for the ability to set
805        // attributes in attr and animate
806        const arc = this.symbol('arc', x, y, r, r, options);
807        arc.r = r; // #959
808        return arc;
809    }
810    /**
811     * Draw and return a rectangle.
812     *
813     * @function Highcharts.SVGRenderer#rect
814     *
815     * @param {number} [x]
816     * Left position.
817     *
818     * @param {number} [y]
819     * Top position.
820     *
821     * @param {number} [width]
822     * Width of the rectangle.
823     *
824     * @param {number} [height]
825     * Height of the rectangle.
826     *
827     * @param {number} [r]
828     * Border corner radius.
829     *
830     * @param {number} [strokeWidth]
831     * A stroke width can be supplied to allow crisp drawing.
832     *
833     * @return {Highcharts.SVGElement}
834     * The generated wrapper element.
835     */ /**
836    * Draw and return a rectangle.
837    *
838    * @sample highcharts/members/renderer-rect-on-chart/
839    *         Draw a rectangle in a chart
840    * @sample highcharts/members/renderer-rect/
841    *         Draw a rectangle independent from a chart
842    *
843    * @function Highcharts.SVGRenderer#rect
844    *
845    * @param {Highcharts.SVGAttributes} [attributes]
846    * General SVG attributes for the rectangle.
847    *
848    * @return {Highcharts.SVGElement}
849    * The generated wrapper element.
850    */
851    rect(x, y, width, height, r, strokeWidth) {
852        const attribs = (isObject(x) ?
853            x :
854            typeof x === 'undefined' ?
855                {} :
856                {
857                    x,
858                    y,
859                    r,
860                    width: Math.max(width || 0, 0),
861                    height: Math.max(height || 0, 0)
862                }), wrapper = this.createElement('rect');
863        if (!this.styledMode) {
864            if (typeof strokeWidth !== 'undefined') {
865                attribs['stroke-width'] = strokeWidth;
866                extend(attribs, wrapper.crisp(attribs));
867            }
868            attribs.fill = 'none';
869        }
870        wrapper.rSetter = function (value, _key, element) {
871            wrapper.r = value;
872            attr(element, {
873                rx: value,
874                ry: value
875            });
876        };
877        wrapper.rGetter = function () {
878            return wrapper.r || 0;
879        };
880        return wrapper.attr(attribs);
881    }
882    /**
883     * Draw and return a rectangle with advanced corner rounding options.
884     *
885     * @function Highcharts.SVGRenderer#roundedRect
886     *
887     * @param {Highcharts.SVGAttributes} attribs
888     *      Attributes
889     * @return {Highcharts.SVGElement}
vendor: 16,413 bytes, lines 890-1334
890     * The generated wrapper element.
891     */
892    roundedRect(attribs) {
893        return this.symbol('roundedRect').attr(attribs);
894    }
895    /**
896     * Resize the {@link SVGRenderer#box} and re-align all aligned child
897     * elements.
898     *
899     * @sample highcharts/members/renderer-g/
900     *         Show and hide grouped objects
901     *
902     * @function Highcharts.SVGRenderer#setSize
903     *
904     * @param {number} width
905     * The new pixel width.
906     *
907     * @param {number} height
908     * The new pixel height.
909     *
910     * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animate=true]
911     * Whether and how to animate.
912     */
913    setSize(width, height, animate) {
914        const renderer = this;
915        renderer.width = width;
916        renderer.height = height;
917        renderer.boxWrapper.animate({
918            width: width,
919            height: height
920        }, {
921            step: function () {
922                this.attr({
923                    viewBox: '0 0 ' + this.attr('width') + ' ' +
924                        this.attr('height')
925                });
926            },
927            duration: pick(animate, true) ? void 0 : 0
928        });
929        renderer.alignElements();
930    }
931    /**
932     * Create and return an svg group element. Child
933     * {@link Highcharts.SVGElement} objects are added to the group by using the
934     * group as the first parameter in {@link Highcharts.SVGElement#add|add()}.
935     *
936     * @function Highcharts.SVGRenderer#g
937     *
938     * @param {string} [name]
939     *        The group will be given a class name of `highcharts-{name}`. This
940     *        can be used for styling and scripting.
941     *
942     * @return {Highcharts.SVGElement}
943     *         The generated wrapper element.
944     */
945    g(name) {
946        const elem = this.createElement('g');
947        return name ?
948            elem.attr({ 'class': 'highcharts-' + name }) :
949            elem;
950    }
951    /**
952     * Display an image.
953     *
954     * @sample highcharts/members/renderer-image-on-chart/
955     *         Add an image in a chart
956     * @sample highcharts/members/renderer-image/
957     *         Add an image independent of a chart
958     *
959     * @function Highcharts.SVGRenderer#image
960     *
961     * @param {string} href
962     *        The image source.
963     *
964     * @param {number} [x]
965     *        The X position.
966     *
967     * @param {number} [y]
968     *        The Y position.
969     *
970     * @param {number} [width]
971     *        The image width. If omitted, it defaults to the image file width.
972     *
973     * @param {number} [height]
974     *        The image height. If omitted it defaults to the image file
975     *        height.
976     *
977     * @param {Function} [onload]
978     *        Event handler for image load.
979     *
980     * @return {Highcharts.SVGElement}
981     *         The generated wrapper element.
982     */
983    image(href, x, y, width, height, onload) {
984        const attribs = { preserveAspectRatio: 'none' };
985        // Optional properties (#11756)
986        if (isNumber(x)) {
987            attribs.x = x;
988        }
989        if (isNumber(y)) {
990            attribs.y = y;
991        }
992        if (isNumber(width)) {
993            attribs.width = width;
994        }
995        if (isNumber(height)) {
996            attribs.height = height;
997        }
998        const elemWrapper = this.createElement('image').attr(attribs), onDummyLoad = function (e) {
999            elemWrapper.attr({ href });
1000            onload.call(elemWrapper, e);
1001        };
1002        // Add load event if supplied
1003        if (onload) {
1004            // We have to use a dummy HTML image since IE support for SVG image
1005            // load events is very buggy. First set a transparent src, wait for
1006            // dummy to load, and then add the real src to the SVG image.
1007            elemWrapper.attr({
1008                /* eslint-disable-next-line max-len */
1009                href: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
1010            });
1011            const dummy = new win.Image();
1012            addEvent(dummy, 'load', onDummyLoad);
1013            dummy.src = href;
1014            if (dummy.complete) {
1015                onDummyLoad({});
1016            }
1017        }
1018        else {
1019            elemWrapper.attr({ href });
1020        }
1021        return elemWrapper;
1022    }
1023    /**
1024     * Draw a symbol out of pre-defined shape paths from
1025     * {@link SVGRenderer#symbols}.
1026     * It is used in Highcharts for point makers, which cake a `symbol` option,
1027     * and label and button backgrounds like in the tooltip and stock flags.
1028     *
1029     * @function Highcharts.SVGRenderer#symbol
1030     *
1031     * @param {string} symbol
1032     * The symbol name.
1033     *
1034     * @param {number} [x]
1035     * The X coordinate for the top left position.
1036     *
1037     * @param {number} [y]
1038     * The Y coordinate for the top left position.
1039     *
1040     * @param {number} [width]
1041     * The pixel width.
1042     *
1043     * @param {number} [height]
1044     * The pixel height.
1045     *
1046     * @param {Highcharts.SymbolOptionsObject} [options]
1047     * Additional options, depending on the actual symbol drawn.
1048     *
1049     * @return {Highcharts.SVGElement}
1050     * SVG symbol.
1051     */
1052    symbol(symbol, x, y, width, height, options) {
1053        const ren = this, imageRegex = /^url\((.*?)\)$/, isImage = imageRegex.test(symbol), sym = (!isImage && (this.symbols[symbol] ? symbol : 'circle')), 
1054        // Get the symbol definition function
1055        symbolFn = (sym && this.symbols[sym]);
1056        let obj, path, imageSrc, centerImage;
1057        if (symbolFn) {
1058            // Check if there's a path defined for this symbol
1059            if (typeof x === 'number') {
1060                path = symbolFn.call(this.symbols, x || 0, y || 0, width || 0, height || 0, options);
1061            }
1062            obj = this.path(path);
1063            if (!ren.styledMode) {
1064                obj.attr('fill', 'none');
1065            }
1066            // Expando properties for use in animate and attr
1067            extend(obj, {
1068                symbolName: (sym || void 0),
1069                x: x,
1070                y: y,
1071                width: width,
1072                height: height
1073            });
1074            if (options) {
1075                extend(obj, options);
1076            }
1077            // Image symbols
1078        }
1079        else if (isImage) {
1080            imageSrc = symbol.match(imageRegex)[1];
1081            // Create the image synchronously, add attribs async
1082            const img = obj = this.image(imageSrc);
1083            // The image width is not always the same as the symbol width. The
1084            // image may be centered within the symbol, as is the case when
1085            // image shapes are used as label backgrounds, for example in flags.
1086            img.imgwidth = pick(options && options.width, symbolSizes[imageSrc] && symbolSizes[imageSrc].width);
1087            img.imgheight = pick(options && options.height, symbolSizes[imageSrc] && symbolSizes[imageSrc].height);
1088            /**
1089             * Set the size and position
1090             */
1091            centerImage = (obj) => obj.attr({
1092                width: obj.width,
1093                height: obj.height
1094            });
1095            /**
1096             * Width and height setters that take both the image's physical size
1097             * and the label size into consideration, and translates the image
1098             * to center within the label.
1099             */
1100            ['width', 'height'].forEach((key) => {
1101                img[`${key}Setter`] = function (value, key) {
1102                    this[key] = value;
1103                    const { alignByTranslate, element, width, height, imgwidth, imgheight } = this, imgSize = key === 'width' ? imgwidth : imgheight;
1104                    let scale = 1;
1105                    // Scale and center the image within its container. The name
1106                    // `backgroundSize` is taken from the CSS spec, but the
1107                    // value `within` is made up. Other possible values in the
1108                    // spec, `cover` and `contain`, can be implemented if
1109                    // needed.
1110                    if (options &&
1111                        options.backgroundSize === 'within' &&
1112                        width &&
1113                        height &&
1114                        imgwidth &&
1115                        imgheight) {
1116                        scale = Math.min(width / imgwidth, height / imgheight);
1117                        // Update both width and height to keep the ratio
1118                        // correct (#17315)
1119                        attr(element, {
1120                            width: Math.round(imgwidth * scale),
1121                            height: Math.round(imgheight * scale)
1122                        });
1123                    }
1124                    else if (element && imgSize) {
1125                        element.setAttribute(key, imgSize);
1126                    }
1127                    if (!alignByTranslate && imgwidth && imgheight) {
1128                        this.translate(((width || 0) - (imgwidth * scale)) / 2, ((height || 0) - (imgheight * scale)) / 2);
1129                    }
1130                };
1131            });
1132            if (defined(x)) {
1133                img.attr({
1134                    x: x,
1135                    y: y
1136                });
1137            }
1138            img.isImg = true;
1139            img.symbolUrl = symbol;
1140            if (defined(img.imgwidth) && defined(img.imgheight)) {
1141                centerImage(img);
1142            }
1143            else {
1144                // Initialize image to be 0 size so export will still function
1145                // if there's no cached sizes.
1146                img.attr({ width: 0, height: 0 });
1147                // Create a dummy JavaScript image to get the width and height.
1148                createElement('img', {
1149                    onload: function () {
1150                        const chart = charts[ren.chartIndex];
1151                        // Special case for SVGs on IE11, the width is not
1152                        // accessible until the image is part of the DOM
1153                        // (#2854).
1154                        if (this.width === 0) {
1155                            css(this, {
1156                                position: 'absolute',
1157                                top: '-999em'
1158                            });
1159                            doc.body.appendChild(this);
1160                        }
1161                        // Center the image
1162                        symbolSizes[imageSrc] = {
1163                            width: this.width,
1164                            height: this.height
1165                        };
1166                        img.imgwidth = this.width;
1167                        img.imgheight = this.height;
1168                        if (img.element) {
1169                            centerImage(img);
1170                        }
1171                        // Clean up after #2854 workaround.
1172                        if (this.parentNode) {
1173                            this.parentNode.removeChild(this);
1174                        }
1175                        // Fire the load event when all external images are
1176                        // loaded
1177                        ren.imgCount--;
1178                        if (!ren.imgCount && chart && !chart.hasLoaded) {
1179                            chart.onload();
1180                        }
1181                    },
1182                    src: imageSrc
1183                });
1184                this.imgCount++;
1185            }
1186        }
1187        return obj;
1188    }
1189    /**
1190     * Define a clipping rectangle. The clipping rectangle is later applied
1191     * to {@link SVGElement} objects through the {@link SVGElement#clip}
1192     * function.
1193     *
1194     * This function is deprecated as of v11.2. Instead, use a regular shape
1195     * (`rect`, `path` etc), and the `SVGElement.clipTo` function.
1196     *
1197     * @example
1198     * let circle = renderer.circle(100, 100, 100)
1199     *     .attr({ fill: 'red' })
1200     *     .add();
1201     * let clipRect = renderer.clipRect(100, 100, 100, 100);
1202     *
1203     * // Leave only the lower right quarter visible
1204     * circle.clip(clipRect);
1205     *
1206     * @deprecated
1207     *
1208     * @function Highcharts.SVGRenderer#clipRect
1209     *
1210     * @param {number} [x]
1211     *
1212     * @param {number} [y]
1213     *
1214     * @param {number} [width]
1215     *
1216     * @param {number} [height]
1217     *
1218     * @return {Highcharts.ClipRectElement}
1219     *         A clipping rectangle.
1220     */
1221    clipRect(x, y, width, height) {
1222        return this.rect(x, y, width, height, 0);
1223    }
1224    /**
1225     * Draw text. The text can contain a subset of HTML, like spans and anchors
1226     * and some basic text styling of these. For more advanced features like
1227     * border and background, use {@link Highcharts.SVGRenderer#label} instead.
1228     * To update the text after render, run `text.attr({ text: 'New text' })`.
1229     *
1230     * @sample highcharts/members/renderer-text-on-chart/
1231     *         Annotate the chart freely
1232     * @sample highcharts/members/renderer-on-chart/
1233     *         Annotate with a border and in response to the data
1234     * @sample highcharts/members/renderer-text/
1235     *         Formatted text
1236     *
1237     * @function Highcharts.SVGRenderer#text
1238     *
1239     * @param {string} [str]
1240     * The text of (subset) HTML to draw.
1241     *
1242     * @param {number} [x]
1243     * The x position of the text's lower left corner.
1244     *
1245     * @param {number} [y]
1246     * The y position of the text's lower left corner.
1247     *
1248     * @param {boolean} [useHTML=false]
1249     * Use HTML to render the text.
1250     *
1251     * @return {Highcharts.SVGElement}
1252     * The text object.
1253     */
1254    text(str, x, y, useHTML) {
1255        const renderer = this, attribs = {};
1256        if (useHTML && (renderer.allowHTML || !renderer.forExport)) {
1257            return renderer.html(str, x, y);
1258        }
1259        attribs.x = Math.round(x || 0); // X always needed for line-wrap logic
1260        if (y) {
1261            attribs.y = Math.round(y);
1262        }
1263        if (defined(str)) {
1264            attribs.text = str;
1265        }
1266        const wrapper = renderer.createElement('text').attr(attribs);
1267        if (!useHTML || (renderer.forExport && !renderer.allowHTML)) {
1268            wrapper.xSetter = function (value, key, element) {
1269                const tspans = element.getElementsByTagName('tspan'), parentVal = element.getAttribute(key);
1270                for (let i = 0, tspan; i < tspans.length; i++) {
1271                    tspan = tspans[i];
1272                    // If the x values are equal, the tspan represents a line
1273                    // break
1274                    if (tspan.getAttribute(key) === parentVal) {
1275                        tspan.setAttribute(key, value);
1276                    }
1277                }
1278                element.setAttribute(key, value);
1279            };
1280        }
1281        return wrapper;
1282    }
1283    /**
1284     * Utility to return the baseline offset and total line height from the font
1285     * size.
1286     *
1287     * @function Highcharts.SVGRenderer#fontMetrics
1288     *
1289     * @param {Highcharts.SVGElement|Highcharts.SVGDOMElement|number} [element]
1290     *        The element to inspect for a current font size. If a number is
1291     *        given, it's used as a fall back for direct font size in pixels.
1292     *
1293     * @return {Highcharts.FontMetricsObject}
1294     *         The font metrics.
1295     */
1296    fontMetrics(element) {
1297        const f = pInt(SVGElement.prototype.getStyle.call(element, 'font-size') || 0);
1298        // Empirical values found by comparing font size and bounding box
1299        // height. Applies to the default font family.
1300        // https://jsfiddle.net/highcharts/7xvn7/
1301        const h = f < 24 ? f + 3 : Math.round(f * 1.2), b = Math.round(h * 0.8);
1302        return {
1303            // Line height
1304            h,
1305            // Baseline
1306            b,
1307            // Font size
1308            f
1309        };
1310    }
1311    /**
1312     * Correct X and Y positioning of a label for rotation (#1764).
1313     *
1314     * @private
1315     * @function Highcharts.SVGRenderer#rotCorr
1316     */
1317    rotCorr(baseline, rotation, alterY) {
1318        let y = baseline;
1319        if (rotation && alterY) {
1320            y = Math.max(y * Math.cos(rotation * deg2rad), 4);
1321        }
1322        return {
1323            x: (-baseline / 3) * Math.sin(rotation * deg2rad),
1324            y: y
1325        };
1326    }
1327    /**
1328     * Compatibility function to convert the legacy one-dimensional path array
1329     * into an array of segments.
1330     *
1331     * It is used in maps to parse the `path` option, and in SVGRenderer.dSetter
1332     * to support legacy paths from demos.
1333     *
1334     * @private
vendor: 9,993 bytes, lines 1334-1575
1334
1335     * @function Highcharts.SVGRenderer#pathToSegments
1336     */
1337    pathToSegments(path) {
1338        const ret = [];
1339        const segment = [];
1340        const commandLength = {
1341            A: 8,
1342            C: 7,
1343            H: 2,
1344            L: 3,
1345            M: 3,
1346            Q: 5,
1347            S: 5,
1348            T: 3,
1349            V: 2
1350        };
1351        // Short, non-typesafe parsing of the one-dimensional array. It splits
1352        // the path on any string. This is not type checked against the tuple
1353        // types, but is shorter, and doesn't require specific checks for any
1354        // command type in SVG.
1355        for (let i = 0; i < path.length; i++) {
1356            // Command skipped, repeat previous or insert L/l for M/m
1357            if (isString(segment[0]) &&
1358                isNumber(path[i]) &&
1359                segment.length === commandLength[(segment[0].toUpperCase())]) {
1360                path.splice(i, 0, segment[0].replace('M', 'L').replace('m', 'l'));
1361            }
1362            // Split on string
1363            if (typeof path[i] === 'string') {
1364                if (segment.length) {
1365                    ret.push(segment.slice(0));
1366                }
1367                segment.length = 0;
1368            }
1369            segment.push(path[i]);
1370        }
1371        ret.push(segment.slice(0));
1372        return ret;
1373        /*
1374        // Fully type-safe version where each tuple type is checked. The
1375        // downside is filesize and a lack of flexibility for unsupported
1376        // commands
1377        const ret: SVGPath = [],
1378            commands = {
1379                A: 7,
1380                C: 6,
1381                H: 1,
1382                L: 2,
1383                M: 2,
1384                Q: 4,
1385                S: 4,
1386                T: 2,
1387                V: 1,
1388                Z: 0
1389            };
1390
1391        let i = 0,
1392            lastI = 0,
1393            lastCommand;
1394
1395        while (i < path.length) {
1396            const item = path[i];
1397
1398            let command;
1399
1400            if (typeof item === 'string') {
1401                command = item;
1402                i += 1;
1403            } else {
1404                command = lastCommand || 'M';
1405            }
1406
1407            // Upper case
1408            const commandUC = command.toUpperCase();
1409
1410            if (commandUC in commands) {
1411
1412                // No numeric parameters
1413                if (command === 'Z' || command === 'z') {
1414                    ret.push([command]);
1415
1416                // One numeric parameter
1417                } else {
1418                    const val0 = path[i];
1419                    if (typeof val0 === 'number') {
1420
1421                        // Horizontal line to
1422                        if (command === 'H' || command === 'h') {
1423                            ret.push([command, val0]);
1424                            i += 1;
1425
1426                        // Vertical line to
1427                        } else if (command === 'V' || command === 'v') {
1428                            ret.push([command, val0]);
1429                            i += 1;
1430
1431                        // Two numeric parameters
1432                        } else {
1433                            const val1 = path[i + 1];
1434                            if (typeof val1 === 'number') {
1435                                // lineTo
1436                                if (command === 'L' || command === 'l') {
1437                                    ret.push([command, val0, val1]);
1438                                    i += 2;
1439
1440                                // moveTo
1441                                } else if (command === 'M' || command === 'm') {
1442                                    ret.push([command, val0, val1]);
1443                                    i += 2;
1444
1445                                // Smooth quadratic bezier
1446                                } else if (command === 'T' || command === 't') {
1447                                    ret.push([command, val0, val1]);
1448                                    i += 2;
1449
1450                                // Four numeric parameters
1451                                } else {
1452                                    const val2 = path[i + 2],
1453                                        val3 = path[i + 3];
1454                                    if (
1455                                        typeof val2 === 'number' &&
1456                                        typeof val3 === 'number'
1457                                    ) {
1458                                        // Quadratic bezier to
1459                                        if (
1460                                            command === 'Q' ||
1461                                            command === 'q'
1462                                        ) {
1463                                            ret.push([
1464                                                command,
1465                                                val0,
1466                                                val1,
1467                                                val2,
1468                                                val3
1469                                            ]);
1470                                            i += 4;
1471
1472                                        // Smooth cubic bezier to
1473                                        } else if (
1474                                            command === 'S' ||
1475                                            command === 's'
1476                                        ) {
1477                                            ret.push([
1478                                                command,
1479                                                val0,
1480                                                val1,
1481                                                val2,
1482                                                val3
1483                                            ]);
1484                                            i += 4;
1485
1486                                        // Six numeric parameters
1487                                        } else {
1488                                            const val4 = path[i + 4],
1489                                                val5 = path[i + 5];
1490
1491                                            if (
1492                                                typeof val4 === 'number' &&
1493                                                typeof val5 === 'number'
1494                                            ) {
1495                                                // Curve to
1496                                                if (
1497                                                    command === 'C' ||
1498                                                    command === 'c'
1499                                                ) {
1500                                                    ret.push([
1501                                                        command,
1502                                                        val0,
1503                                                        val1,
1504                                                        val2,
1505                                                        val3,
1506                                                        val4,
1507                                                        val5
1508                                                    ]);
1509                                                    i += 6;
1510
1511                                                // Seven numeric parameters
1512                                                } else {
1513                                                    const val6 = path[i + 6];
1514
1515                                                    // Arc to
1516                                                    if (
1517                                                        typeof val6 ===
1518                                                        'number' &&
1519                                                        (
1520                                                            command === 'A' ||
1521                                                            command === 'a'
1522                                                        )
1523                                                    ) {
1524                                                        ret.push([
1525                                                            command,
1526                                                            val0,
1527                                                            val1,
1528                                                            val2,
1529                                                            val3,
1530                                                            val4,
1531                                                            val5,
1532                                                            val6
1533                                                        ]);
1534                                                        i += 7;
1535
1536                                                    }
1537
1538                                                }
1539                                            }
1540                                        }
1541                                    }
1542                                }
1543                            }
1544
1545                        }
1546                    }
1547                }
1548            }
1549
1550            // An unmarked command following a moveTo is a lineTo
1551            lastCommand = command === 'M' ? 'L' : command;
1552
1553            if (i === lastI) {
1554                break;
1555            }
1556            lastI = i;
1557        }
1558        return ret;
1559        */
1560    }
1561    /**
1562     * Draw a label, which is an extended text element with support for border
1563     * and background. Highcharts creates a `g` element with a text and a `path`
1564     * or `rect` inside, to make it behave somewhat like a HTML div. Border and
1565     * background are set through `stroke`, `stroke-width` and `fill` attributes
1566     * using the {@link Highcharts.SVGElement#attr|attr} method. To update the
1567     * text after render, run `label.attr({ text: 'New text' })`.
1568     *
1569     * @sample highcharts/members/renderer-label-on-chart/
1570     *         A label on the chart
1571     *
1572     * @function Highcharts.SVGRenderer#label
1573     *
1574     * @param {string} str
1575     * 
1575       The initial text string or (subset) HTML to render.
1576     *
1577     * @param {number} x
1578     *        The x position of the label's left side.
1579     *
1580     * @param {number} [y]
1581     *        The y position of the label's top side or baseline, depending on
1582     *        the `baseline` parameter.
1583     *
1584     * @param {string} [shape='rect']
1585     *        The shape of the label's border/background, if any. Defaults to
1586     *        `rect`. Other possible values are `callout` or other shapes
1587     *        defined in {@link Highcharts.SVGRenderer#symbols}.
1588     *
1589     * @param {number} [anchorX]
1590     *        In case the `shape` has a pointer, like a flag, this is the
1591     *        coordinates it should be pinned to.
1592     *
1593     * @param {number} [anchorY]
1594     *        In case the `shape` has a pointer, like a flag, this is the
1595     *        coordinates it should be pinned to.
1596     *
1597     * @param {boolean} [useHTML=false]
1598     *        Whether to use HTML to render the label.
1599     *
1600     * @param {boolean} [baseline=false]
1601     *        Whether to position the label relative to the text baseline,
1602     *        like {@link Highcharts.SVGRenderer#text|renderer.text}, or to the
1603     *        upper border of the rectangle.
1604     *
1605     * @param {string} [className]
1606     *        Class name for the group.
1607     *
1608     * @return {Highcharts.SVGElement}
1609     *         The generated label.
1610     */
1611    label(str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
1612        return new SVGLabel(this, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className);
1613    }
1614    /**
1615     * Re-align all aligned elements.
1616     *
1617     * @private
1618     * @function Highcharts.SVGRenderer#alignElements
1619     */
1620    alignElements() {
1621        this.alignedObjects.forEach((el) => el.align());
1622    }
1623}
1624extend(SVGRenderer.prototype, {
1625    /**
1626     * A pointer to the renderer's associated Element class.
1627     *
1628     * @name Highcharts.SVGRenderer#Element
1629     * @type {Highcharts.SVGElement}
1630     */
1631    Element: SVGElement,
1632    SVG_NS,
1633    /**
1634     * A collection of characters mapped to HTML entities. When `useHTML` on an
1635     * element is true, these entities will be rendered correctly by HTML. In
1636     * the SVG pseudo-HTML, they need to be unescaped back to simple characters,
1637     * so for example `&lt;` will render as `<`.
1638     *
1639     * @example
1640     * // Add support for unescaping quotes
1641     * Highcharts.SVGRenderer.prototype.escapes['"'] = '&quot;';
1642     *
1643     * @name Highcharts.SVGRenderer#escapes
1644     * @type {Highcharts.Dictionary<string>}
1645     */
1646    escapes: {
1647        '&': '&amp;',
1648        '<': '&lt;',
1649        '>': '&gt;',
1650        "'": '&#39;', // eslint-disable-line quotes
1651        '"': '&quot;'
1652    },
1653    /**
1654     * An extendable collection of functions for defining symbol paths.
1655     *
1656     * @name Highcharts.SVGRenderer#symbols
1657     * @type {Highcharts.SymbolDictionary}
1658     */
1659    symbols: Symbols,
1660    /**
1661     * Dummy function for plugins, called every time the renderer is updated.
1662     * Prior to Highcharts 5, this was used for the canvg renderer.
1663     *
1664     * @deprecated
1665     * @function Highcharts.SVGRenderer#draw
1666     */
1667    draw: noop
1668});
1669/* *
1670 *
1671 *  Registry
1672 *
1673 * */
1674RendererRegistry.registerRendererType('svg', SVGRenderer, true);
1675/* *
1676 *
1677 *  Export Default
1678 *
1679 * */
1680export default SVGRenderer;
1681/* *
1682 *
1683 *  API Declarations
1684 *
1685 * */
1686/**
1687 * A clipping rectangle that can be applied to one or more {@link SVGElement}
1688 * instances. It is instantiated with the {@link SVGRenderer#clipRect} function
1689 * and applied with the {@link SVGElement#clip} function.
1690 *
1691 * @example
1692 * let circle = renderer.circle(100, 100, 100)
1693 *     .attr({ fill: 'red' })
1694 *     .add();
1695 * let clipRect = renderer.clipRect(100, 100, 100, 100);
1696 *
1697 * // Leave only the lower right quarter visible
1698 * circle.clip(clipRect);
1699 *
1700 * @typedef {Highcharts.SVGElement} Highcharts.ClipRectElement
1701 */
1702/**
1703 * The font metrics.
1704 *
1705 * @interface Highcharts.FontMetricsObject
1706 */ /**
1707* The baseline relative to the top of the box.
1708*
1709* @name Highcharts.FontMetricsObject#b
1710* @type {number}
1711*/ /**
1712* The font size.
1713*
1714* @name Highcharts.FontMetricsObject#f
1715* @type {number}
1716*/ /**
1717* The line height.
1718*
1719* @name Highcharts.FontMetricsObject#h
1720* @type {number}
1721*/
1722/**
1723 * An object containing `x` and `y` properties for the position of an element.
1724 *
1725 * @interface Highcharts.PositionObject
1726 */ /**
1727* X position of the element.
1728* @name Highcharts.PositionObject#x
1729* @type {number}
1730*/ /**
1731* Y position of the element.
1732* @name Highcharts.PositionObject#y
1733* @type {number}
1734*/
1735/**
1736 * A rectangle.
1737 *
1738 * @interface Highcharts.RectangleObject
1739 */ /**
1740* Height of the rectangle.
1741* @name Highcharts.RectangleObject#height
1742* @type {number}
1743*/ /**
1744* Width of the rectangle.
1745* @name Highcharts.RectangleObject#width
1746* @type {number}
1747*/ /**
1748* Horizontal position of the rectangle.
1749* @name Highcharts.RectangleObject#x
1750* @type {number}
1751*/ /**
1752* Vertical position of the rectangle.
1753* @name Highcharts.RectangleObject#y
1754* @type {number}
1755*/
1756/**
1757 * The shadow options.
1758 *
1759 * @interface Highcharts.ShadowOptionsObject
1760 */ /**
1761* The shadow color.
1762* @name    Highcharts.ShadowOptionsObject#color
1763* @type    {Highcharts.ColorString|undefined}
1764* @default ${palette.neutralColor100}
1765*/ /**
1766* The horizontal offset from the element.
1767*
1768* @name    Highcharts.ShadowOptionsObject#offsetX
1769* @type    {number|undefined}
1770* @default 1
1771*/ /**
1772* The vertical offset from the element.
1773* @name    Highcharts.ShadowOptionsObject#offsetY
1774* @type    {number|undefined}
1775* @default 1
1776*/ /**
1777* The shadow opacity.
1778*
1779* @name    Highcharts.ShadowOptionsObject#opacity
1780* @type    {number|undefined}
1781* @default 0.15
1782*/ /**
1783* The shadow width or distance from the element.
1784* @name    Highcharts.ShadowOptionsObject#width
1785* @type    {number|undefined}
1786* @default 3
1787*/
1788/**
1789 * @interface Highcharts.SizeObject
1790 */ /**
1791* @name Highcharts.SizeObject#height
1792* @type {number}
1793*/ /**
1794* @name Highcharts.SizeObject#width
1795* @type {number}
1796*/
1797/**
1798 * Array of path commands, that will go into the `d` attribute of an SVG
1799 * element.
1800 *
1801 * @typedef {Array<(Array<Highcharts.SVGPathCommand>|Array<Highcharts.SVGPathCommand,number>|Array<Highcharts.SVGPathCommand,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number,number>)>} Highcharts.SVGPathArray
1802 */
1803/**
1804 * Possible path commands in an SVG path array. Valid values are `A`, `C`, `H`,
1805 * `L`, `M`, `Q`, `S`, `T`, `V`, `Z`.
1806 *
1807 * @typedef {string} Highcharts.SVGPathCommand
1808 * @validvalue ["a","c","h","l","m","q","s","t","v","z","A","C","H","L","M","Q","S","T","V","Z"]
1809 */
1810/**
1811 * An extendable collection of functions for defining symbol paths. Symbols are
1812 * used internally for point markers, button and label borders and backgrounds,
1813 * or custom shapes. Extendable by adding to {@link SVGRenderer#symbols}.
1814 *
1815 * @interface Highcharts.SymbolDictionary
1816 */ /**
1817* @name Highcharts.SymbolDictionary#[key:string]
1818* @type {Function|undefined}
1819*/ /**
1820* @name Highcharts.SymbolDictionary#arc
1821* @type {Function|undefined}
1822*/ /**
1823* @name Highcharts.SymbolDictionary#callout
1824* @type {Function|undefined}
1825*/ /**
1826* @name Highcharts.SymbolDictionary#circle
1827* @type {Function|undefined}
1828*/ /**
1829* @name Highcharts.SymbolDictionary#diamond
1830* @type {Function|undefined}
1831*/ /**
1832* @name Highcharts.SymbolDictionary#square
1833* @type {Function|undefined}
1834*/ /**
1835* @name Highcharts.SymbolDictionary#triangle
1836* @type {Function|undefined}
1837*/
1838/**
1839 * Can be one of `arc`, `callout`, `circle`, `diamond`, `square`, `triangle`,
1840 * and `triangle-down`. Symbols are used internally for point markers, button
1841 * and label borders and backgrounds, or custom shapes. Extendable by adding to
1842 * {@link SVGRenderer#symbols}.
1843 *
1844 * @typedef {"arc"|"callout"|"circle"|"diamond"|"square"|"triangle"|"triangle-down"} Highcharts.SymbolKeyValue
1845 */
1846/**
1847 * Additional options, depending on the actual symbol drawn.
1848 *
1849 * @interface Highcharts.SymbolOptionsObject
1850 */ /**
1851* The anchor X position for the `callout` symbol. This is where the chevron
1852* points to.
1853*
1854* @name Highcharts.SymbolOptionsObject#anchorX
1855* @type {number|undefined}
1856*/ /**
1857* The anchor Y position for the `callout` symbol. This is where the chevron
1858* points to.
1859*
1860* @name Highcharts.SymbolOptionsObject#anchorY
1861* @type {number|undefined}
1862*/ /**
1863* The end angle of an `arc` symbol.
1864*
1865* @name Highcharts.SymbolOptionsObject#end
1866* @type {number|undefined}
1867*/ /**
1868* Whether to draw `arc` symbol open or closed.
1869*
1870* @name Highcharts.SymbolOptionsObject#open
1871* @type {boolean|undefined}
1872*/ /**
1873* The radius of an `arc` symbol, or the border radius for the `callout` symbol.
1874*
1875* @name Highcharts.SymbolOptionsObject#r
1876* @type {number|undefined}
1877*/ /**
1878* The start angle of an `arc` symbol.
1879*
1880* @name Highcharts.SymbolOptionsObject#start
1881* @type {number|undefined}
1882*/
1883(''); // Keeps doclets above in transpiled 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.