PageSourceSearch

https://tourisme-hautvaldesevre.fr/app/dist/hautvaldesevre-tourism…/Extensions/OverlappingDataLabels.js

js tourisme-hautvaldesevre.fr collected 2026-10-02 19:24:04 UTC 9,118 bytes, 253 lines download raw bytes

1/* *
2 *
3 *  Highcharts module to hide overlapping data labels.
4 *  This module is included in Highcharts.
5 *
6 *  (c) 2009-2024 Torstein Honsi
7 *
8 *  License: www.highcharts.com/license
9 *
10 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
11 *
12 * */
13'use strict';
14import GeometryUtilities from '../Core/Geometry/GeometryUtilities.js';
15const { pointInPolygon } = GeometryUtilities;
16import U from '../Core/Utilities.js';
17const { addEvent, fireEvent, objectEach, pick } = U;
18/* *
19 *
20 *  Functions
21 *
22 * */
23/**
24 * Hide overlapping labels. Labels are moved and faded in and out on zoom to
25 * provide a smooth visual impression.
26 *
27 * @requires modules/overlapping-datalabels
28 *
29 * @private
30 * @function Highcharts.Chart#hideOverlappingLabels
31 * @param {Array<Highcharts.SVGElement>} labels
32 *        Rendered data labels
33 */
34function chartHideOverlappingLabels(labels) {
35    const chart = this, len = labels.length, isIntersectRect = (box1, box2) => !(box2.x >= box1.x + box1.width ||
36        box2.x + box2.width <= box1.x ||
37        box2.y >= box1.y + box1.height ||
38        box2.y + box2.height <= box1.y), isPolygonOverlap = (box1Poly, box2Poly) => {
39        for (const p of box1Poly) {
40            if (pointInPolygon({ x: p[0], y: p[1] }, box2Poly)) {
41                return true;
42            }
43        }
44        return false;
45    };
46    /**
47     * Get the box with its position inside the chart, as opposed to getBBox
48     * that only reports the position relative to the parent.
49     */
50    function getAbsoluteBox(label) {
51        if (label && (!label.alignAttr || label.placed)) {
52            const padding = label.box ? 0 : (label.padding || 0), pos = label.alignAttr || {
53                x: label.attr('x'),
54                y: label.attr('y')
55            }, bBox = label.getBBox();
56            label.width = bBox.width;
57            label.height = bBox.height;
58            return {
59                x: pos.x + (label.parentGroup?.translateX || 0) + padding,
60                y: pos.y + (label.parentGroup?.translateY || 0) + padding,
61                width: (label.width || 0) - 2 * padding,
62                height: (label.height || 0) - 2 * padding,
63                polygon: bBox?.polygon
64            };
65        }
66    }
67    let label, label1, label2, box1, box2, isLabelAffected = false;
68    for (let i = 0; i < len; i++) {
69        label = labels[i];
70        if (label) {
71            // Mark with initial opacity
72            label.oldOpacity = label.opacity;
73            label.newOpacity = 1;
74            label.absoluteBox = getAbsoluteBox(label);
75        }
76    }
77    // Prevent a situation in a gradually rising slope, that each label will
78    // hide the previous one because the previous one always has lower rank.
79    labels.sort((a, b) => (b.labelrank || 0) - (a.labelrank || 0));
80    // Detect overlapping labels
81    for (let i = 0; i < len; ++i) {
82        label1 = labels[i];
83        box1 = label1 && label1.absoluteBox;
84        const box1Poly = box1?.polygon;
85        for (let j = i + 1; j < len; ++j) {
86            label2 = labels[j];
87            box2 = label2 && label2.absoluteBox;
88            let toHide = false;
89            if (box1 &&
90                box2 &&
91                label1 !== label2 && // #6465, polar chart with connectEnds
92                label1.newOpacity !== 0 &&
93                label2.newOpacity !== 0 &&
94                // #15863 dataLabels are no longer hidden by translation
95                label1.visibility !== 'hidden' &&
96                label2.visibility !== 'hidden') {
97                const box2Poly = box2.polygon;
98                // If labels have polygons, only evaluate
99                // based on polygons
100                if (box1Poly &&
101                    box2Poly &&
102                    box1Poly !== box2Poly) {
103                    if (isPolygonOverlap(box1Poly, box2Poly)) {
104                        toHide = true;
105                    }
106                    // If there are no polygons, evaluate rectangles coliding
107                }
108                else if (isIntersectRect(box1, box2)) {
109                    toHide = true;
110                }
111                if (toHide) {
112                    const overlappingLabel = (label1.labelrank < label2.labelrank ?
113                        label1 :
114                        label2), labelText = overlappingLabel.text;
115                    overlappingLabel.newOpacity = 0;
116                    if (labelText?.element.querySelector('textPath')) {
117                        labelText.hide();
118                    }
119                }
120            }
121        }
122    }
123    // Hide or show
124    for (const label of labels) {
125        if (hideOrShow(label, chart)) {
126            isLabelAffected = true;
127        }
128    }
129    if (isLabelAffected) {
130        fireEvent(chart, 'afterHideAllOverlappingLabels');
131    }
132}
133/** @private */
134function compose(ChartClass) {
135    const chartProto = ChartClass.prototype;
136    if (!chartProto.hideOverlappingLabels) {
137        chartProto.hideOverlappingLabels = chartHideOverlappingLabels;
138        addEvent(ChartClass, 'render', onChartRender);
139    }
140}
141/**
142 * Hide or show labels based on opacity.
143 *
144 * @private
145 * @function hideOrShow
146 * @param {Highcharts.SVGElement} label
147 * The label.
148 * @param {Highcharts.Chart} chart
149 * The chart that contains the label.
150 * @return {boolean}
151 * Whether label is affected
152 */
153function hideOrShow(label, chart) {
154    let complete, newOpacity, isLabelAffected = false;
155    if (label) {
156        newOpacity = label.newOpacity;
157        if (label.oldOpacity !== newOpacity) {
158            // Toggle data labels
159            if (label.hasClass('highcharts-data-label')) {
160                // Make sure the label is completely hidden to avoid catching
161                // clicks (#4362)
162                label[newOpacity ? 'removeClass' : 'addClass']('highcharts-data-label-hidden');
163                complete = function () {
164                    if (!chart.styledMode) {
165                        label.css({
166                            pointerEvents: newOpacity ? 'auto' : 'none'
167                        });
168                    }
169                };
170                isLabelAffected = true;
171                // Animate or set the opacity
172                label[label.isOld ? 'animate' : 'attr']({ opacity: newOpacity }, void 0, complete);
173                fireEvent(chart, 'afterHideOverlappingLabel');
174                // Toggle other labels, tick labels
175            }
176            else {
177                label.attr({
178                    opacity: newOpacity
179                });
180            }
181        }
182        label.isOld = true;
183    }
184    return isLabelAffected;
185}
186/**
187 * Collect potential overlapping data labels. Stack labels probably don't need
188 * to be considered because they are usually accompanied by data labels that lie
189 * inside the columns.
190 * @private
191 */
192function onChartRender() {
193    const chart = this;
194    let labels = [];
195    // Consider external label collectors
196    for (const collector of (chart.labelCollectors || [])) {
197        labels = labels.concat(collector());
198    }
199    for (const yAxis of (chart.yAxis || [])) {
200        if (yAxis.stacking &&
201            yAxis.options.stackLabels &&
202            !yAxis.options.stackLabels.allowOverlap) {
203            objectEach(yAxis.stacking.stacks, (stack) => {
204                objectEach(stack, (stackItem) => {
205                    if (stackItem.label) {
206                        labels.push(stackItem.label);
207                    }
208                });
209            });
210        }
211    }
212    for (const series of (chart.series || [])) {
213        if (series.visible && series.hasDataLabels?.()) { // #3866
214            const push = (points) => {
215                for (const point of points) {
216                    if (point.visible) {
217                        (point.dataLabels || []).forEach((label) => {
218                            const options = label.options || {};
219                            label.labelrank = pick(options.labelrank, point.labelrank, point.shapeArgs?.height); // #4118
220                            // Allow overlap if the option is explicitly true
221                            if (
222                            // #13449
223                            options.allowOverlap ??
224                                // Pie labels outside have a separate placement
225                                // logic, skip the overlap logic
226                                Number(options.distance) > 0) {
227                                label.oldOpacity = label.opacity;
228                                label.newOpacity = 1;
229                                hideOrShow(label, chart);
230                                // Do not allow overlap
231                            }
232                            else {
233                                labels.push(label);
234                            }
235                        });
236                    }
237                }
238            };
239            push(series.nodes || []);
240            push(series.points);
241        }
242    }
243    this.hideOverlappingLabels(labels);
244}
245/* *
246 *
247 *  Default Export
248 *
249 * */
250const OverlappingDataLabels = {
251    compose
252};
253export default OverlappingDataLabels;

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.