PageSourceSearch

https://www.montpellier-francia.es/app/dist/montpelliertourisme/ad…/Core/Renderer/RendererUtilities.js

js montpellier-francia.es collected 2026-09-26 10:10:39 UTC 6,587 bytes, 172 lines download raw bytes

vendor: 6,256 bytes, lines 1-158
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';
11/* *
12 *
13 *  Imports
14 *
15 * */
16import U from '../Utilities.js';
17const { clamp, pick, pushUnique, stableSort } = U;
18/* *
19 *
20 *  Namespace
21 *
22 * */
23var RendererUtilities;
24(function (RendererUtilities) {
25    /* *
26     *
27     *  Declarations
28     *
29     * */
30    /* *
31     *
32     *  Functions
33     *
34     * */
35    /* eslint-disable valid-jsdoc */
36    /**
37     * General distribution algorithm for distributing labels of differing size
38     * along a confined length in two dimensions. The algorithm takes an array
39     * of objects containing a size, a target and a rank. It will place the
40     * labels as close as possible to their targets, skipping the lowest ranked
41     * labels if necessary.
42     * @private
43     */
44    function distribute(boxes, len, maxDistance) {
45        // Original array will be altered with added .pos
46        const origBoxes = boxes, reducedLen = origBoxes.reducedLen || len, sortByRank = (a, b) => (b.rank || 0) - (a.rank || 0), sortByTarget = (a, b) => a.target - b.target, restBoxes = [], // The outranked overshoot
47        boxesLength = boxes.length, forDeletion = [], push = restBoxes.push;
48        let i, cursor, step, overlapping = true, box, target, total = 0, equalRank;
49        // If the total size exceeds the len, remove those boxes with the lowest
50        // rank
51        i = boxesLength;
52        while (i--) {
53            total += boxes[i].size;
54        }
55        // Sort by rank, then slice away overshoot
56        if (total > reducedLen) {
57            stableSort(boxes, sortByRank);
58            equalRank = boxes[0].rank === boxes[boxes.length - 1].rank;
59            step = equalRank ? boxesLength / 2 : -1;
60            cursor = equalRank ? step : boxesLength - 1;
61            // When the boxes have equal rank (pie data labels, flags - #10073),
62            // decimate the boxes by starting in the middle and gradually remove
63            // more items inside the array. When they are sorted by rank, just
64            // remove the ones with the lowest rank from the end.
65            while (step && total > reducedLen) {
66                i = Math.floor(cursor);
67                box = boxes[i];
68                if (pushUnique(forDeletion, i)) {
69                    total -= box.size;
70                }
71                cursor += step;
72                // Start over the decimation with smaller steps
73                if (equalRank && cursor >= boxes.length) {
74                    step /= 2;
75                    cursor = step;
76                }
77            }
78            // Clean out the boxes marked for deletion
79            forDeletion
80                .sort((a, b) => b - a)
81                .forEach((i) => push.apply(restBoxes, boxes.splice(i, 1)));
82        }
83        // Order by target
84        stableSort(boxes, sortByTarget);
85        // So far we have been mutating the original array. Now
86        // create a copy with target arrays
87        boxes = boxes.map((box) => ({
88            size: box.size,
89            targets: [box.target],
90            align: pick(box.align, 0.5)
91        }));
92        while (overlapping) {
93            // Initial positions: target centered in box
94            i = boxes.length;
95            while (i--) {
96                box = boxes[i];
97                // Composite box, average of targets
98                target = (Math.min.apply(0, box.targets) +
99                    Math.max.apply(0, box.targets)) / 2;
100                box.pos = clamp(target - box.size * box.align, 0, len - box.size);
101            }
102            // Detect overlap and join boxes
103            i = boxes.length;
104            overlapping = false;
105            while (i--) {
106                // Overlap
107                if (i > 0 &&
108                    boxes[i - 1].pos + boxes[i - 1].size >
109                        boxes[i].pos) {
110                    // Add this size to the previous box
111                    boxes[i - 1].size += boxes[i].size;
112                    boxes[i - 1].targets = boxes[i - 1]
113                        .targets
114                        .concat(boxes[i].targets);
115                    boxes[i - 1].align = 0.5;
116                    // Overlapping right, push left
117                    if (boxes[i - 1].pos + boxes[i - 1].size > len) {
118                        boxes[i - 1].pos = len - boxes[i - 1].size;
119                    }
120                    boxes.splice(i, 1); // Remove this item
121                    overlapping = true;
122                }
123            }
124        }
125        // Add the rest (hidden boxes)
126        push.apply(origBoxes, restBoxes);
127        // Now the composite boxes are placed, we need to put the original boxes
128        // within them
129        i = 0;
130        boxes.some((box) => {
131            let posInCompositeBox = 0;
132            // Exceeded maxDistance => abort
133            return (box.targets || []).some(() => {
134                origBoxes[i].pos = box.pos + posInCompositeBox;
135                // If the distance between the position and the target exceeds
136                // maxDistance, abort the loop and decrease the length in
137                // increments of 10% to recursively reduce the number of
138                // visible boxes by rank. Once all boxes are within the
139                // maxDistance, we're good.
140                if (typeof maxDistance !== 'undefined' &&
141                    Math.abs(origBoxes[i].pos - origBoxes[i].target) > maxDistance) {
142                    // Reset the positions that are already set
143                    origBoxes
144                        .slice(0, i + 1)
145                        .forEach((box) => delete box.pos);
146                    // Try with a smaller length
147                    origBoxes.reducedLen =
148                        (origBoxes.reducedLen || len) - (len * 0.1);
149                    // Recurse
150                    if (origBoxes.reducedLen > len * 0.1) {
151                        distribute(origBoxes, len, maxDistance);
152                    }
153                    // Exceeded maxDistance => abort
154                    return true;
155                }
156                posInCompositeBox += origBoxes[i].size;
157                i++;
158                return false;
159            });
160        });
161        // Add the rest (hidden) boxes and sort by target
162        stableSort(origBoxes, sortByTarget);
163        return origBoxes;
164    }
165    RendererUtilities.distribute = distribute;
166})(RendererUtilities || (RendererUtilities = {}));
167/* *
168 *
169 *  Default Export
170 *
171 * */
172export default RendererUtilities;

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.