PageSourceSearch

https://tahititourisme.org/app/dist/tahiti-corporate/addons/woody-…/es-modules/Core/Renderer/SVG/SVGLabel.js

js tahititourisme.org collected 2026-10-04 01:52:10 UTC 13,387 bytes, 400 lines download raw bytes

vendor: 4,713 bytes, lines 1-157
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 * */
10import SVGElement from './SVGElement.js';
11import U from '../../Utilities.js';
12const { defined, extend, getAlignFactor, isNumber, merge, pick, removeEvent } = U;
13/* *
14 *
15 *  Class
16 *
17 * */
18/**
19 * SVG label to render text.
20 * @private
21 * @class
22 * @name Highcharts.SVGLabel
23 * @augments Highcharts.SVGElement
24 */
25class SVGLabel extends SVGElement {
26    /* *
27     *
28     *  Constructor
29     *
30     * */
31    constructor(renderer, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
32        super(renderer, 'g');
33        this.paddingLeftSetter = this.paddingSetter;
34        this.paddingRightSetter = this.paddingSetter;
35        this.doUpdate = false;
36        this.textStr = str;
37        this.x = x;
38        this.y = y;
39        this.anchorX = anchorX;
40        this.anchorY = anchorY;
41        this.baseline = baseline;
42        this.className = className;
43        this.addClass(className === 'button' ?
44            'highcharts-no-tooltip' :
45            'highcharts-label');
46        if (className) {
47            this.addClass('highcharts-' + className);
48        }
49        // Create the text element. An undefined text content prevents redundant
50        // box calculation (#16121)
51        this.text = renderer.text(void 0, 0, 0, useHTML).attr({ zIndex: 1 });
52        // Validate the shape argument
53        let hasBGImage;
54        if (typeof shape === 'string') {
55            hasBGImage = /^url\((.*?)\)$/.test(shape);
56            if (hasBGImage || this.renderer.symbols[shape]) {
57                this.symbolKey = shape;
58            }
59        }
60        this.bBox = SVGLabel.emptyBBox;
61        this.padding = 3;
62        this.baselineOffset = 0;
63        this.needsBox = renderer.styledMode || hasBGImage;
64        this.deferredAttr = {};
65        this.alignFactor = 0;
66    }
67    /* *
68     *
69     *  Functions
70     *
71     * */
72    alignSetter(value) {
73        const alignFactor = getAlignFactor(value);
74        this.textAlign = value;
75        if (alignFactor !== this.alignFactor) {
76            this.alignFactor = alignFactor;
77            // Bounding box exists, means we're dynamically changing
78            if (this.bBox && isNumber(this.xSetting)) {
79                this.attr({ x: this.xSetting }); // #5134
80            }
81        }
82    }
83    anchorXSetter(value, key) {
84        this.anchorX = value;
85        this.boxAttr(key, Math.round(value) - this.getCrispAdjust() - this.xSetting);
86    }
87    anchorYSetter(value, key) {
88        this.anchorY = value;
89        this.boxAttr(key, value - this.ySetting);
90    }
91    /*
92     * Set a box attribute, or defer it if the box is not yet created
93     */
94    boxAttr(key, value) {
95        if (this.box) {
96            this.box.attr(key, value);
97        }
98        else {
99            this.deferredAttr[key] = value;
100        }
101    }
102    /*
103     * Pick up some properties and apply them to the text instead of the
104     * wrapper.
105     */
106    css(styles) {
107        if (styles) {
108            const textStyles = {};
109            // Create a copy to avoid altering the original object
110            // (#537)
111            styles = merge(styles);
112            SVGLabel.textProps.forEach((prop) => {
113                if (typeof styles[prop] !== 'undefined') {
114                    textStyles[prop] = styles[prop];
115                    delete styles[prop];
116                }
117            });
118            this.text.css(textStyles);
119            // Update existing text, box (#9400, #12163, #18212)
120            if ('fontSize' in textStyles || 'fontWeight' in textStyles) {
121                this.updateTextPadding();
122            }
123            else if ('width' in textStyles || 'textOverflow' in textStyles) {
124                this.updateBoxSize();
125            }
126        }
127        return SVGElement.prototype.css.call(this, styles);
128    }
129    /*
130     * Destroy and release memory.
131     */
132    destroy() {
133        // Added by button implementation
134        removeEvent(this.element, 'mouseenter');
135        removeEvent(this.element, 'mouseleave');
136        if (this.text) {
137            this.text.destroy();
138        }
139        if (this.box) {
140            this.box = this.box.destroy();
141        }
142        // Call base implementation to destroy the rest
143        SVGElement.prototype.destroy.call(this);
144        return void 0;
145    }
146    fillSetter(value, key) {
147        if (value) {
148            this.needsBox = true;
149        }
150        // For animation getter (#6776)
151        this.fill = value;
152        this.boxAttr(key, value);
153    }
154    /*
155     * Return the bounding box of the box, not the group.
156     */
157    getBBox(reload, rot) {
vendor: 4,296 bytes, lines 158-278
158        // If we have a text string and the DOM bBox was 0, it typically means
159        // that the label was first rendered hidden, so we need to update the
160        // bBox (#15246)
161        if (this.textStr && this.bBox.width === 0 && this.bBox.height === 0) {
162            this.updateBoxSize();
163        }
164        const { padding, height = 0, translateX = 0, translateY = 0, width = 0 } = this, paddingLeft = pick(this.paddingLeft, padding), rotation = rot ?? (this.rotation || 0);
165        let bBox = {
166            width,
167            height,
168            x: translateX + this.bBox.x - paddingLeft,
169            y: translateY + this.bBox.y - padding + this.baselineOffset
170        };
171        if (rotation) {
172            bBox = this.getRotatedBox(bBox, rotation);
173        }
174        return bBox;
175    }
176    getCrispAdjust() {
177        return (this.renderer.styledMode && this.box ?
178            this.box.strokeWidth() :
179            (this['stroke-width'] ?
180                parseInt(this['stroke-width'], 10) :
181                0)) % 2 / 2;
182    }
183    heightSetter(value) {
184        this.heightSetting = value;
185        this.doUpdate = true;
186    }
187    /**
188     * This method is executed in the end of `attr()`, after setting all
189     * attributes in the hash. In can be used to efficiently consolidate
190     * multiple attributes in one SVG property -- e.g., translate, rotate and
191     * scale are merged in one "transform" attribute in the SVG node.
192     * Also updating height or width should trigger update of the box size.
193     *
194     * @private
195     * @function Highcharts.SVGLabel#afterSetters
196     */
197    afterSetters() {
198        super.afterSetters();
199        if (this.doUpdate) {
200            this.updateBoxSize();
201            this.doUpdate = false;
202        }
203    }
204    /*
205     * After the text element is added, get the desired size of the border
206     * box and add it before the text in the DOM.
207     */
208    onAdd() {
209        this.text.add(this);
210        this.attr({
211            // Alignment is available now  (#3295, 0 not rendered if given
212            // as a value)
213            text: pick(this.textStr, ''),
214            x: this.x || 0,
215            y: this.y || 0
216        });
217        if (this.box && defined(this.anchorX)) {
218            this.attr({
219                anchorX: this.anchorX,
220                anchorY: this.anchorY
221            });
222        }
223    }
224    paddingSetter(value, key) {
225        if (!isNumber(value)) {
226            this[key] = void 0;
227        }
228        else if (value !== this[key]) {
229            this[key] = value;
230            this.updateTextPadding();
231        }
232    }
233    rSetter(value, key) {
234        this.boxAttr(key, value);
235    }
236    strokeSetter(value, key) {
237        // For animation getter (#6776)
238        this.stroke = value;
239        this.boxAttr(key, value);
240    }
241    'stroke-widthSetter'(value, key) {
242        if (value) {
243            this.needsBox = true;
244        }
245        this['stroke-width'] = value;
246        this.boxAttr(key, value);
247    }
248    'text-alignSetter'(value) {
249        // The text-align variety is for the pre-animation getter. The code
250        // should be unified to either textAlign or text-align.
251        this.textAlign = this['text-align'] = value;
252        this.updateTextPadding();
253    }
254    textSetter(text) {
255        if (typeof text !== 'undefined') {
256            // Must use .attr to ensure transforms are done (#10009)
257            this.text.attr({ text });
258        }
259        this.updateTextPadding();
260        this.reAlign();
261    }
262    /*
263     * This function runs after the label is added to the DOM (when the bounding
264     * box is available), and after the text of the label is updated to detect
265     * the new bounding box and reflect it in the border box.
266     */
267    updateBoxSize() {
268        const text = this.text, attribs = {}, padding = this.padding, 
269        // #12165 error when width is null (auto)
270        // #12163 when fontweight: bold, recalculate bBox without cache
271        // #3295 && 3514 box failure when string equals 0
272        bBox = this.bBox = (((!isNumber(this.widthSetting) ||
273            !isNumber(this.heightSetting) ||
274            this.textAlign) && defined(text.textStr)) ?
275            text.getBBox(void 0, 0) :
276            SVGLabel.emptyBBox);
277        let crispAdjust;
278        this.width = this.getPaddedWidth();
vendor: 4,378 bytes, lines 279-400
279        this.height = (this.heightSetting || bBox.height || 0) + 2 * padding;
280        const metrics = this.renderer.fontMetrics(text);
281        // Update the label-scoped y offset. Math.min because of inline
282        // style (#9400)
283        this.baselineOffset = padding + Math.min(
284        // When applicable, use the font size of the first line (#15707)
285        (this.text.firstLineMetrics || metrics).b, 
286        // When the height is 0, there is no bBox, so go with the font
287        // metrics. Highmaps CSS demos.
288        bBox.height || Infinity);
289        // #15491: Vertical centering
290        if (this.heightSetting) {
291            this.baselineOffset += (this.heightSetting - metrics.h) / 2;
292        }
293        if (this.needsBox && !text.textPath) {
294            // Create the border box if it is not already present
295            if (!this.box) {
296                // Symbol definition exists (#5324)
297                const box = this.box = this.symbolKey ?
298                    this.renderer.symbol(this.symbolKey) :
299                    this.renderer.rect();
300                box.addClass(// Don't use label className for buttons
301                (this.className === 'button' ?
302                    '' : 'highcharts-label-box') +
303                    (this.className ?
304                        ' highcharts-' + this.className + '-box' : ''));
305                box.add(this);
306            }
307            crispAdjust = this.getCrispAdjust();
308            attribs.x = crispAdjust;
309            attribs.y = ((this.baseline ? -this.baselineOffset : 0) + crispAdjust);
310            // Apply the box attributes
311            attribs.width = Math.round(this.width);
312            attribs.height = Math.round(this.height);
313            this.box.attr(extend(attribs, this.deferredAttr));
314            this.deferredAttr = {};
315        }
316    }
317    /*
318     * This function runs after setting text or padding, but only if padding
319     * is changed.
320     */
321    updateTextPadding() {
322        const text = this.text, textAlign = text.styles.textAlign || this.textAlign;
323        if (!text.textPath) {
324            this.updateBoxSize();
325            // Determine y based on the baseline
326            const textY = this.baseline ? 0 : this.baselineOffset, textX = (this.paddingLeft ?? this.padding) +
327                // Compensate for alignment
328                getAlignFactor(textAlign) * (this.widthSetting ?? this.bBox.width);
329            // Update if anything changed
330            if (textX !== text.x || textY !== text.y) {
331                text.attr({
332                    align: textAlign,
333                    x: textX
334                });
335                if (typeof textY !== 'undefined') {
336                    text.attr('y', textY);
337                }
338            }
339            // Record current values
340            text.x = textX;
341            text.y = textY;
342        }
343    }
344    widthSetter(value) {
345        // `width:auto` => null
346        this.widthSetting = isNumber(value) ? value : void 0;
347        this.doUpdate = true;
348    }
349    getPaddedWidth() {
350        const padding = this.padding;
351        const paddingLeft = pick(this.paddingLeft, padding);
352        const paddingRight = pick(this.paddingRight, padding);
353        return ((this.widthSetting || this.bBox.width || 0) +
354            paddingLeft +
355            paddingRight);
356    }
357    xSetter(value) {
358        this.x = value; // For animation getter
359        if (this.alignFactor) {
360            value -= this.alignFactor * this.getPaddedWidth();
361            // Force animation even when setting to the same value (#7898)
362            this['forceAnimate:x'] = true;
363        }
364        this.xSetting = Math.round(value);
365        this.attr('translateX', this.xSetting);
366    }
367    ySetter(value) {
368        this.ySetting = this.y = Math.round(value);
369        this.attr('translateY', this.ySetting);
370    }
371}
372/* *
373 *
374 *  Static Properties
375 *
376 * */
377SVGLabel.emptyBBox = {
378    width: 0,
379    height: 0,
380    x: 0,
381    y: 0
382};
383/**
384 * For labels, these CSS properties are applied to the `text` node directly.
385 *
386 * @private
387 * @name Highcharts.SVGLabel#textProps
388 * @type {Array<string>}
389 */
390SVGLabel.textProps = [
391    'color', 'direction', 'fontFamily', 'fontSize', 'fontStyle',
392    'fontWeight', 'lineClamp', 'lineHeight', 'textAlign', 'textDecoration',
393    'textOutline', 'textOverflow', 'whiteSpace', 'width'
394];
395/* *
396 *
397 *  Default Export
398 *
399 * */
400export default SVGLabel;

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.