PageSourceSearch

https://www.paysaurillactourisme.com/app/dist/aurillac/addons/wood…/Core/Renderer/HTML/HTMLElement.js

js paysaurillactourisme.com collected 2026-10-09 17:51:47 UTC 14,126 bytes, 407 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 AST from './AST.js';
12import H from '../../Globals.js';
13const { composed } = H;
14import SVGElement from '../SVG/SVGElement.js';
15import U from '../../Utilities.js';
16const { attr, css, createElement, defined, extend, getAlignFactor, isNumber, pInt, pushUnique } = U;
17/**
18 * The opacity and visibility properties are set as attributes on the main
19 * element and SVG groups, and as identical CSS properties on the HTML element
20 * and the ancestry divs. (#3542)
21 *
22 * @private
23 */
24function commonSetter(value, key, elem) {
25    const style = this.div?.style || elem.style;
26    SVGElement.prototype[`${key}Setter`].call(this, value, key, elem);
27    if (style) {
28        style[key] = value;
29    }
30}
31/**
32 * Decorate each SVG group in the ancestry line. Each SVG `g` element that
33 * contains children with useHTML, will receive a `div` element counterpart to
34 * contain the HTML span. These div elements are translated and styled like
35 * original `g` counterparts.
36 *
37 * @private
38 */
39const decorateSVGGroup = (g, container) => {
40    if (!g.div) {
41        const className = attr(g.element, 'class'), cssProto = g.css;
42        // Create the parallel HTML group
43        const div = createElement('div', className ? { className } : void 0, {
44            // Add HTML specific styles
45            position: 'absolute',
46            left: `${g.translateX || 0}px`,
47            top: `${g.translateY || 0}px`,
48            // Add pre-existing styles
49            ...g.styles,
50            // Add g attributes that correspond to CSS
51            display: g.display,
52            opacity: g.opacity, // #5075
53            visibility: g.visibility
54        }, 
55        // The top group is appended to container
56        g.parentGroup?.div || container);
57        g.classSetter = (value, key, element) => {
58            element.setAttribute('class', value);
59            div.className = value;
60        };
61        /**
62         * Common translate setter for X and Y on the HTML group.
63         *
64         * Reverted the fix for #6957 due to positioning problems and offline
65         * export (#7254, #7280, #7529)
66         * @private
67         */
68        g.translateXSetter = g.translateYSetter = (value, key) => {
69            g[key] = value;
70            div.style[key === 'translateX' ? 'left' : 'top'] = `${value}px`;
71            g.doTransform = true;
72        };
73        g.opacitySetter = g.visibilitySetter = commonSetter;
74        // Extend the parent group's css function by updating the parallel div
75        // counterpart with the same style.
76        g.css = (styles) => {
77            // Call the base css method. The `parentGroup` can be either an
78            // SVGElement or an SVGLabel, in which the css method is extended
79            // (#19200).
80            cssProto.call(g, styles);
81            // #6794
82            if (styles.cursor) {
83                div.style.cursor = styles.cursor;
84            }
85            // #18821
86            if (styles.pointerEvents) {
87                div.style.pointerEvents = styles.pointerEvents;
88            }
89            return g;
90        };
91        // Event handling
92        g.on = function () {
93            SVGElement.prototype.on.apply({
94                element: div,
95                onEvents: g.onEvents
96            }, arguments);
97            return g;
98        };
99        g.div = div;
100    }
101    return g.div;
102};
103/* *
104 *
105 *  Class
106 *
107 * */
108class HTMLElement extends SVGElement {
109    /* *
110     *
111     *  Static Functions
112     *
113     * */
114    /**
115     * Compose
116     * @private
117     */
118    static compose(SVGRendererClass) {
119        if (pushUnique(composed, this.compose)) {
120            /**
121             * Create a HTML text node. This is used by the SVG renderer `text`
122             * and `label` functions through the `useHTML` parameter.
123             *
124             * @private
125             */
126            SVGRendererClass.prototype.html = function (str, x, y) {
127                return new HTMLElement(this, 'span')
128                    // Set the default attributes
129                    .attr({
130                    text: str,
131                    x: Math.round(x),
132                    y: Math.round(y)
133                });
134            };
135        }
136    }
137    /* *
138     *
139     *  Functions
140     *
141     * */
142    constructor(renderer, nodeName) {
143        super(renderer, nodeName);
144        this.css({
145            position: 'absolute',
146            ...(renderer.styledMode ? {} : {
147                fontFamily: renderer.style.fontFamily,
148                fontSize: renderer.style.fontSize
149            })
150        });
151    }
152    /**
153     * Get the correction in X and Y positioning as the element is rotated.
154     * @private
155     */
156    getSpanCorrection(width, baseline, alignCorrection) {
157        this.xCorr = -width * alignCorrection;
158        this.yCorr = -baseline;
159    }
160    /**
161     * Apply CSS to HTML elements. This is used in text within SVG rendering.
162     * @private
163     */
164    css(styles) {
165        const { element } = this, 
166        // When setting or unsetting the width style, we need to update
167        // transform (#8809)
168        isSettingWidth = (element.tagName === 'SPAN' &&
169            styles &&
170            'width' in styles), textWidth = isSettingWidth && styles.width;
171        let doTransform;
172        if (isSettingWidth) {
173            delete styles.width;
174            this.textWidth = pInt(textWidth) || void 0;
175            doTransform = true;
176        }
177        // Some properties require other properties to be set
178        if (styles?.textOverflow === 'ellipsis') {
179            styles.overflow = 'hidden';
180        }
181        if (styles?.lineClamp) {
182            styles.display = '-webkit-box';
183            styles.WebkitLineClamp = styles.lineClamp;
184            styles.WebkitBoxOrient = 'vertical';
185            styles.overflow = 'hidden';
186        }
187        // SVG natively supports setting font size as numbers. With HTML, the
188        // font size should behave in the same way (#21624).
189        if (isNumber(Number(styles?.fontSize))) {
190            styles.fontSize = styles.fontSize + 'px';
191        }
192        extend(this.styles, styles);
193        css(element, styles);
194        // Now that all styles are applied, to the transform
195        if (doTransform) {
196            this.updateTransform();
197        }
198        return this;
199    }
200    /**
201     * The useHTML method for calculating the bounding box based on offsets.
202     * Called internally from the `SVGElement.getBBox` function and subsequently
203     * rotated.
204     *
205     * @private
206     */
207    htmlGetBBox() {
208        const { element } = this;
209        return {
210            x: element.offsetLeft,
211            y: element.offsetTop,
212            width: element.offsetWidth,
213            height: element.offsetHeight
214        };
215    }
216    /**
217     * Batch update styles and attributes related to transform
218     *
219     * @private
220     */
221    updateTransform() {
222        // Aligning non added elements is expensive
223        if (!this.added) {
224            this.alignOnAdd = true;
225            return;
226        }
227        const { element, renderer, rotation, rotationOriginX, rotationOriginY, scaleX, scaleY, styles, textAlign = 'left', textWidth, translateX = 0, translateY = 0, x = 0, y = 0 } = this, { display = 'block', whiteSpace } = styles;
228        // Get the pixel length of the text
229        const getTextPxLength = () => {
230            if (this.textPxLength) {
231                return this.textPxLength;
232            }
233            // Reset multiline/ellipsis in order to read width (#4928,
234            // #5417)
235            css(element, {
236                width: '',
237                whiteSpace: whiteSpace || 'nowrap'
238            });
239            return element.offsetWidth;
240        };
241        // Apply translate
242        css(element, {
243            marginLeft: `${translateX}px`,
244            marginTop: `${translateY}px`
245        });
246        if (element.tagName === 'SPAN') {
247            const currentTextTransform = [
248                rotation,
249                textAlign,
250                element.innerHTML,
251                textWidth,
252                this.textAlign
253            ].join(','), parentPadding = (this.parentGroup?.padding * -1) || 0;
254            let baseline;
255            // Update textWidth. Use the memoized textPxLength if possible, to
256            // avoid the getTextPxLength function using elem.offsetWidth.
257            // Calling offsetWidth affects rendering time as it forces layout
258            // (#7656).
259            if (textWidth !== this.oldTextWidth) { // #983, #1254
260                const textPxLength = getTextPxLength(), textWidthNum = textWidth || 0;
261                if (((textWidthNum > this.oldTextWidth) ||
262                    textPxLength > textWidthNum) && (
263                // Only set the width if the text is able to word-wrap,
264                // or text-overflow is ellipsis (#9537)
265                /[ \-]/.test(element.textContent || element.innerText) ||
266                    element.style.textOverflow === 'ellipsis')) {
267                    css(element, {
268                        width: ((textPxLength > textWidthNum) ||
269                            rotation ||
270                            scaleX) ?
271                            textWidth + 'px' :
272                            'auto', // #16261
273                        display,
274                        whiteSpace: whiteSpace || 'normal' // #3331
275                    });
276                    this.oldTextWidth = textWidth;
277                }
278            }
279            // Do the calculations and DOM access only if properties changed
280            if (currentTextTransform !== this.cTT) {
281                baseline = renderer.fontMetrics(element).b;
282                // Renderer specific handling of span rotation, but only if we
283                // have something to update.
284                if (defined(rotation) &&
285                    ((rotation !== (this.oldRotation || 0)) ||
286                        (textAlign !== this.oldAlign))) {
287                    this.setSpanRotation(rotation, parentPadding, parentPadding);
288                }
289                this.getSpanCorrection(
290                // Avoid elem.offsetWidth if we can, it affects rendering
291                // time heavily (#7656)
292                ((!defined(rotation) &&
293                    !this.textWidth &&
294                    this.textPxLength) || // #7920
295                    element.offsetWidth), baseline, getAlignFactor(textAlign));
296            }
297            // Apply position with correction and rotation origin
298            const { xCorr = 0, yCorr = 0 } = this, rotOriginX = (rotationOriginX ?? x) - xCorr - x - parentPadding, rotOriginY = (rotationOriginY ?? y) - yCorr - y - parentPadding, styles = {
299                left: `${x + xCorr}px`,
300                top: `${y + yCorr}px`,
301                textAlign,
302                transformOrigin: `${rotOriginX}px ${rotOriginY}px`
303            };
304            if (scaleX || scaleY) {
305                styles.transform = `scale(${scaleX ?? 1},${scaleY ?? 1})`;
306            }
307            css(element, styles);
308            // Record current text transform
309            this.cTT = currentTextTransform;
310            this.oldRotation = rotation;
311            this.oldAlign = textAlign;
312        }
313    }
314    /**
315     * Set the rotation of an individual HTML span.
316     * @private
317     */
318    setSpanRotation(rotation, originX, originY) {
319        // CSS transform and transform-origin both supported without prefix
320        // since Firefox 16 (2012), IE 10 (2012), Chrome 36 (2014), Safari 9
321        // (2015).;
322        css(this.element, {
323            transform: `rotate(${rotation}deg)`,
324            transformOrigin: `${originX}% ${originY}px`
325        });
326    }
327    /**
328     * Add the element to a group wrapper. For HTML elements, a parallel div
329     * will be created for each ancenstor SVG `g` element.
330     *
331     * @private
332     */
333    add(parentGroup) {
334        const container = this.renderer.box
335            .parentNode, parents = [];
336        let div;
337        this.parentGroup = parentGroup;
338        // Create a parallel divs to hold the HTML elements
339        if (parentGroup) {
340            div = parentGroup.div;
341            if (!div) {
342                // Read the parent chain into an array and read from top
343                // down
344                let svgGroup = parentGroup;
345                while (svgGroup) {
346                    parents.push(svgGroup);
347                    // Move up to the next parent group
348                    svgGroup = svgGroup.parentGroup;
349                }
350                // Decorate each of the ancestor group elements with a parallel
351                // div that reflects translation and styling
352                for (const parentGroup of parents.reverse()) {
353                    div = decorateSVGGroup(parentGroup, container);
354                }
355            }
356        }
357        (div || container).appendChild(this.element);
358        this.added = true;
359        if (this.alignOnAdd) {
360            this.updateTransform();
361        }
362        return this;
363    }
364    /**
365     * Text setter
366     * @private
367     */
368    textSetter(value) {
369        if (value !== this.textStr) {
370            delete this.bBox;
371            delete this.oldTextWidth;
372            AST.setElementHTML(this.element, value ?? '');
373            this.textStr = value;
374            this.doTransform = true;
375        }
376    }
377    /**
378     * Align setter
379     *
380     * @private
381     */
382    alignSetter(value) {
383        this.alignValue = this.textAlign = value;
384        this.doTransform = true;
385    }
386    /**
387     * Various setters which rely on update transform
388     * @private
389     */
390    xSetter(value, key) {
391        this[key] = value;
392        this.doTransform = true;
393    }
394}
395// Some shared setters
396const proto = HTMLElement.prototype;
397proto.visibilitySetter = proto.opacitySetter = commonSetter;
398proto.ySetter =
399    proto.rotationSetter =
400        proto.rotationOriginXSetter =
401            proto.rotationOriginYSetter = proto.xSetter;
402/* *
403 *
404 *  Default Export
405 *
406 * */
407export default HTMLElement;

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.