@chartbuddy.io/embed 1.7.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +56 -0
- package/README.md +391 -0
- package/chart-schema.d.ts +91 -0
- package/chart-schema.json +1144 -0
- package/chartbuddy-embed.api.mjs +64 -0
- package/chartbuddy-embed.d.ts +488 -0
- package/chartbuddy-embed.global.js +135 -0
- package/chartbuddy-embed.mjs +135 -0
- package/chartbuddy-embed.single.global.js +4201 -0
- package/chartbuddy-embed.single.mjs +4201 -0
- package/element.d.ts +78 -0
- package/element.mjs +233 -0
- package/js/core/chart/labelPlacementWorker.js +2 -0
- package/labelPlacementAccel-QHVANOZO.wasm +0 -0
- package/llms.txt +341 -0
- package/package.json +101 -0
- package/react.d.ts +97 -0
- package/react.mjs +219 -0
- package/ts/shared/libraries/DOMPurify.min.js +2 -0
- package/ts/shared/libraries/d3.min.js +2 -0
- package/vue.d.ts +108 -0
- package/vue.mjs +253 -0
- package/webapp-entry.css +2 -0
- package/webapp-entry.js +4063 -0
package/element.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for `@chartbuddy.io/embed/element`.
|
|
3
|
+
*
|
|
4
|
+
* No peer dependencies — this is a plain custom element and works in any host.
|
|
5
|
+
* Primarily documented for Angular; see the Angular guide in the docs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ChartData, ChartDataInput, EmbedMode, Insight } from './chartbuddy-embed';
|
|
9
|
+
|
|
10
|
+
/** The registered tag name, `'chartbuddy-insight'`. */
|
|
11
|
+
export const TAG_NAME: 'chartbuddy-insight';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `<chartbuddy-insight>` — a custom element wrapping the Insight API.
|
|
15
|
+
*
|
|
16
|
+
* Set `chartData` as a **property**, not an attribute (it is an object). The
|
|
17
|
+
* remaining options work as either property or attribute.
|
|
18
|
+
*
|
|
19
|
+
* Events are `CustomEvent`s: `ready` (detail: `Insight`), `change` (detail:
|
|
20
|
+
* `ChartData | null`), `mode` (detail: `EmbedMode`), `error` (detail: `Error`).
|
|
21
|
+
*/
|
|
22
|
+
export class ChartBuddyInsightElement extends HTMLElement {
|
|
23
|
+
/**
|
|
24
|
+
* Chart config. Assign a new object to patch the live chart — the element
|
|
25
|
+
* calls `update()` rather than remounting. Compared by identity, so mutating
|
|
26
|
+
* a nested property in place is not detected.
|
|
27
|
+
*/
|
|
28
|
+
chartData?: ChartDataInput;
|
|
29
|
+
/** Stable id for the registry. Duplicate ids on one page throw. */
|
|
30
|
+
instanceId?: string;
|
|
31
|
+
/** Open the full editor instead of view-only. Changing this remounts. */
|
|
32
|
+
editable?: boolean;
|
|
33
|
+
/** Show the Reset / Import / Export strip (edit mode only). */
|
|
34
|
+
toolbar?: boolean;
|
|
35
|
+
/** Persist config to localStorage. Needs a stable `instanceId`. */
|
|
36
|
+
persist?: boolean;
|
|
37
|
+
/** Engine asset base for the multi-file build. Must end with `/`. */
|
|
38
|
+
assetBase?: string;
|
|
39
|
+
|
|
40
|
+
/** The live instance, or null before connect / after disconnect. */
|
|
41
|
+
readonly insight: Insight | null;
|
|
42
|
+
/** True once the chart has finished booting. */
|
|
43
|
+
readonly ready: boolean;
|
|
44
|
+
/** Last validation or boot failure, or null. */
|
|
45
|
+
readonly error: Error | null;
|
|
46
|
+
|
|
47
|
+
addEventListener<K extends keyof ChartBuddyInsightEventMap>(
|
|
48
|
+
type: K,
|
|
49
|
+
listener: (event: ChartBuddyInsightEventMap[K]) => void,
|
|
50
|
+
options?: boolean | AddEventListenerOptions,
|
|
51
|
+
): void;
|
|
52
|
+
addEventListener(
|
|
53
|
+
type: string,
|
|
54
|
+
listener: EventListenerOrEventListenerObject,
|
|
55
|
+
options?: boolean | AddEventListenerOptions,
|
|
56
|
+
): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ChartBuddyInsightEventMap {
|
|
60
|
+
ready: CustomEvent<Insight>;
|
|
61
|
+
change: CustomEvent<ChartData | null>;
|
|
62
|
+
mode: CustomEvent<EmbedMode>;
|
|
63
|
+
error: CustomEvent<Error>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Register the element. Runs automatically on import; call it directly only to
|
|
68
|
+
* use a different tag name. Calling twice with the same tag is a no-op.
|
|
69
|
+
*/
|
|
70
|
+
export function defineInsightElement(tagName?: string): void;
|
|
71
|
+
|
|
72
|
+
declare global {
|
|
73
|
+
interface HTMLElementTagNameMap {
|
|
74
|
+
'chartbuddy-insight': ChartBuddyInsightElement;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default ChartBuddyInsightElement;
|
package/element.mjs
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @chartbuddy.io/embed/element — `<chartbuddy-insight>` custom element.
|
|
3
|
+
*
|
|
4
|
+
* A framework-agnostic wrapper around the imperative Insight API, for hosts
|
|
5
|
+
* where a framework-specific package is the wrong shape:
|
|
6
|
+
*
|
|
7
|
+
* - **Angular** — the primary consumer. Angular binds properties and listens to
|
|
8
|
+
* events on custom elements natively, so this gives Angular users the same
|
|
9
|
+
* lifecycle guarantees as the React/Vue bindings without ChartBuddy shipping a
|
|
10
|
+
* compiled Angular library (which would pin the package to an Angular major).
|
|
11
|
+
* - Svelte, Solid, Lit, Astro, htmx, and plain HTML.
|
|
12
|
+
*
|
|
13
|
+
* Same lifecycle contract as the other bindings: mounts once, patches on
|
|
14
|
+
* `chartData` changes instead of remounting, remounts only on construction
|
|
15
|
+
* options, destroys on disconnect.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* import '@chartbuddy.io/embed/element';
|
|
19
|
+
*
|
|
20
|
+
* const el = document.createElement('chartbuddy-insight');
|
|
21
|
+
* el.style.height = '400px';
|
|
22
|
+
* el.chartData = { chartType: 'clusteredBar', seriesData: grid };
|
|
23
|
+
* el.addEventListener('change', (e) => console.log(e.detail));
|
|
24
|
+
* document.body.append(el);
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { Insight } from './chartbuddy-embed.api.mjs';
|
|
28
|
+
|
|
29
|
+
/** Element tag. Also the registry key, so double-registration is detectable. */
|
|
30
|
+
export const TAG_NAME = 'chartbuddy-insight';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Construction options, and the attribute each is mirrored from. Changing one of
|
|
34
|
+
* these remounts the chart; `chartData` does not.
|
|
35
|
+
*/
|
|
36
|
+
const CONSTRUCTION_ATTRS = {
|
|
37
|
+
'instance-id': 'instanceId',
|
|
38
|
+
editable: 'editable',
|
|
39
|
+
toolbar: 'toolbar',
|
|
40
|
+
persist: 'persist',
|
|
41
|
+
'asset-base': 'assetBase',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const BOOLEAN_PROPS = new Set(['editable', 'toolbar', 'persist']);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Read an attribute as the type its property expects. Boolean attributes follow
|
|
48
|
+
* HTML convention — present means true, `="false"` is respected so frameworks
|
|
49
|
+
* that stringify bindings still work.
|
|
50
|
+
*/
|
|
51
|
+
function readAttribute(el, attr, prop) {
|
|
52
|
+
if (!el.hasAttribute(attr)) return undefined;
|
|
53
|
+
const raw = el.getAttribute(attr);
|
|
54
|
+
if (!BOOLEAN_PROPS.has(prop)) return raw ?? undefined;
|
|
55
|
+
return raw !== 'false';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class ChartBuddyInsightElement extends HTMLElement {
|
|
59
|
+
static get observedAttributes() {
|
|
60
|
+
return Object.keys(CONSTRUCTION_ATTRS);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#insight = null;
|
|
64
|
+
#chartData;
|
|
65
|
+
#openedWith;
|
|
66
|
+
#props = {};
|
|
67
|
+
#stops = [];
|
|
68
|
+
#connected = false;
|
|
69
|
+
#ready = false;
|
|
70
|
+
#error = null;
|
|
71
|
+
/** Guards against an attribute burst remounting once per attribute. */
|
|
72
|
+
#remountQueued = false;
|
|
73
|
+
|
|
74
|
+
/* --- properties --------------------------------------------------------- */
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Chart config. Assign a new object to patch the live chart; the element calls
|
|
78
|
+
* `update()` rather than remounting. Compared by identity.
|
|
79
|
+
*/
|
|
80
|
+
get chartData() {
|
|
81
|
+
return this.#chartData;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
set chartData(value) {
|
|
85
|
+
this.#chartData = value;
|
|
86
|
+
if (!this.#insight || value === undefined || value === this.#openedWith) return;
|
|
87
|
+
this.#openedWith = value;
|
|
88
|
+
try {
|
|
89
|
+
this.#insight.update(value);
|
|
90
|
+
this.#setError(null);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
this.#setError(err);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The live Insight, or null before connect / after disconnect. */
|
|
97
|
+
get insight() {
|
|
98
|
+
return this.#insight;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** True once the chart has finished booting. */
|
|
102
|
+
get ready() {
|
|
103
|
+
return this.#ready;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Last validation or boot failure, or null. */
|
|
107
|
+
get error() {
|
|
108
|
+
return this.#error;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* --- lifecycle ---------------------------------------------------------- */
|
|
112
|
+
|
|
113
|
+
connectedCallback() {
|
|
114
|
+
this.#connected = true;
|
|
115
|
+
// The chart fills its container, so an unsized element renders nothing.
|
|
116
|
+
// `block` is set here rather than in CSS so a bare tag is never invisible.
|
|
117
|
+
if (!this.style.display) this.style.display = 'block';
|
|
118
|
+
this.#mount();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
disconnectedCallback() {
|
|
122
|
+
this.#connected = false;
|
|
123
|
+
this.#teardown();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
attributeChangedCallback(attr, previous, next) {
|
|
127
|
+
if (previous === next) return;
|
|
128
|
+
const prop = CONSTRUCTION_ATTRS[attr];
|
|
129
|
+
if (!prop) return;
|
|
130
|
+
const value = readAttribute(this, attr, prop);
|
|
131
|
+
if (value === undefined) delete this.#props[prop];
|
|
132
|
+
else this.#props[prop] = value;
|
|
133
|
+
if (this.#connected) this.#queueRemount();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* --- internals ---------------------------------------------------------- */
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Coalesce a burst of attribute writes into one remount. Frameworks commonly
|
|
140
|
+
* set several attributes in the same task, and each would otherwise destroy
|
|
141
|
+
* and rebuild the chart.
|
|
142
|
+
*/
|
|
143
|
+
#queueRemount() {
|
|
144
|
+
if (this.#remountQueued) return;
|
|
145
|
+
this.#remountQueued = true;
|
|
146
|
+
Promise.resolve().then(() => {
|
|
147
|
+
this.#remountQueued = false;
|
|
148
|
+
if (this.#connected) this.#mount();
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#mount() {
|
|
153
|
+
this.#teardown();
|
|
154
|
+
|
|
155
|
+
// Attributes set before upgrade are not replayed, so read them all here.
|
|
156
|
+
for (const [attr, prop] of Object.entries(CONSTRUCTION_ATTRS)) {
|
|
157
|
+
const value = readAttribute(this, attr, prop);
|
|
158
|
+
if (value !== undefined) this.#props[prop] = value;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let instance;
|
|
162
|
+
try {
|
|
163
|
+
instance = new Insight(this, {
|
|
164
|
+
...this.#props,
|
|
165
|
+
chartData: this.#chartData,
|
|
166
|
+
});
|
|
167
|
+
} catch (err) {
|
|
168
|
+
this.#setError(err);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.#insight = instance;
|
|
173
|
+
this.#openedWith = this.#chartData;
|
|
174
|
+
this.#setError(null);
|
|
175
|
+
|
|
176
|
+
this.#stops.push(
|
|
177
|
+
instance.on('change', (cd) => this.#emit('change', cd)),
|
|
178
|
+
instance.on('mode', (mode) => this.#emit('mode', mode)),
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
instance.ready.then(
|
|
182
|
+
() => {
|
|
183
|
+
if (this.#insight !== instance) return;
|
|
184
|
+
this.#ready = true;
|
|
185
|
+
this.#emit('ready', instance);
|
|
186
|
+
},
|
|
187
|
+
(err) => {
|
|
188
|
+
if (this.#insight !== instance) return;
|
|
189
|
+
this.#setError(err);
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#teardown() {
|
|
195
|
+
this.#stops.splice(0).forEach((stop) => stop());
|
|
196
|
+
this.#ready = false;
|
|
197
|
+
if (this.#insight) {
|
|
198
|
+
this.#insight.destroy();
|
|
199
|
+
this.#insight = null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#setError(err) {
|
|
204
|
+
if (err === null) {
|
|
205
|
+
this.#error = null;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
this.#error = err instanceof Error ? err : new Error(String(err));
|
|
209
|
+
// Not `composed`, so the error does not escape a shadow root unexpectedly.
|
|
210
|
+
this.#emit('error', this.#error);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
#emit(type, detail) {
|
|
214
|
+
this.dispatchEvent(new CustomEvent(type, { detail }));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Register the element. Called automatically on import; exported so hosts that
|
|
220
|
+
* need a different tag name (or a deferred registration) can control it.
|
|
221
|
+
*
|
|
222
|
+
* Safe to call twice — a second call with the same tag is a no-op rather than a
|
|
223
|
+
* throw, because bundle duplication is common and should not break a page.
|
|
224
|
+
*/
|
|
225
|
+
export function defineInsightElement(tagName = TAG_NAME) {
|
|
226
|
+
if (typeof customElements === 'undefined') return;
|
|
227
|
+
if (customElements.get(tagName)) return;
|
|
228
|
+
customElements.define(tagName, ChartBuddyInsightElement);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
defineInsightElement();
|
|
232
|
+
|
|
233
|
+
export default ChartBuddyInsightElement;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var ChartBuddyWebApp=(()=>{var A=class N{static layoutLabels(t,e,r,o=lt.STACKED_BAR){return new N(t,e,r,o).layoutLabels()}constructor(t,e,r,o){this.labels=t||[],this.obstacles=e||[],this.bounds=H(r),this.preset=nt(o||{}),this.obstacleById=new Map(this.obstacles.map(_=>[_.id,_])),this.measured=this.buildMeasuredLabels(),this.measuredById=new Map(this.measured.map(_=>[_.input.id,_])),this.debugMetrics={candidateGenerationMs:0,scoringMs:0,scoreCalls:0,generatedCandidates:0,prunedCandidates:0,wasmUsage:{pruningCalls:0,overlapCalls:0,overlapStatsCalls:0,labelOverlapCalls:0}}}layoutLabels(){let t=performance.now(),e=this.getSolveAttempts(),r=Number.POSITIVE_INFINITY,o=new Map;for(let c=0;c<e;c++){let l=this.buildInitialLayout(c);this.refineLayout(l,c);let n=this.scoreLayout(l);n<r&&(r=n,o=this.cloneLayout(l))}this.lastLayout=this.cloneLayout(o);let _=performance.now()-t,s={labelCount:this.labels.length,obstacleCount:this.obstacles.length,attempts:e,refinePasses:this.getRefinePassCount(),durationMs:Number(_.toFixed(2)),candidateGenerationMs:Number(this.debugMetrics.candidateGenerationMs.toFixed(2)),scoringMs:Number(this.debugMetrics.scoringMs.toFixed(2)),scoreCalls:this.debugMetrics.scoreCalls,generatedCandidates:this.debugMetrics.generatedCandidates,prunedCandidates:this.debugMetrics.prunedCandidates,avgNearbyObstacles:Number((this.measured.reduce((c,l)=>c+l.nearbyObstacleIds.length,0)/Math.max(1,this.measured.length)).toFixed(2)),avgNearbyLabels:Number((this.measured.reduce((c,l)=>c+l.nearbyLabelIds.length,0)/Math.max(1,this.measured.length)).toFixed(2))};return console.log("[ChartLabelPlacementEngine] Layout timing",s),{states:o}}buildMeasuredLabels(){let t=this.labels.map(r=>({input:r,config:R(this.getRolePreset(r.role),r.override||{}),density:0,preferredAngles:[],nearbyLabelIds:[],nearbyObstacleIds:[]})),e=t.map(()=>({x:0,y:0}));for(let r=0;r<t.length;r++)for(let o=r+1;o<t.length;o++){let _=t[r],s=t[o],c=_.input.target.x-s.input.target.x,l=_.input.target.y-s.input.target.y,n=c*c+l*l,d=Math.sqrt(n);if(d>0&&d<this.preset.neighborhood.densityRadius){let i=1-d/this.preset.neighborhood.densityRadius;_.density+=i,s.density+=i}if(n>0&&n<this.preset.neighborhood.preferredAngleRadius*this.preset.neighborhood.preferredAngleRadius){let i=1/n;e[r].x+=c*i,e[r].y+=l*i,e[o].x-=c*i,e[o].y-=l*i}let p=(_.input.size.width+s.input.size.width)/2+(this.getCandidateConfig(_).maxLabelTravel+this.getCandidateConfig(s).maxLabelTravel)+this.preset.neighborhood.nearbyPadding,a=(_.input.size.height+s.input.size.height)/2+(this.getCandidateConfig(_).maxLabelTravel+this.getCandidateConfig(s).maxLabelTravel)+this.preset.neighborhood.nearbyPadding;Math.abs(c)<=p&&Math.abs(l)<=a&&(_.nearbyLabelIds.push(s.input.id),s.nearbyLabelIds.push(_.input.id))}for(let r of t){let o=this.getCandidateConfig(r),_=r.input.size.width/2+o.maxLabelTravel+this.preset.neighborhood.nearbyPadding,s=r.input.size.height/2+o.maxLabelTravel+this.preset.neighborhood.nearbyPadding;for(let c of this.obstacles)this.shouldIncludeNearbyObstacle(r,c,_,s)&&r.nearbyObstacleIds.push(c.id);r.nearbyObstacleIds=this.pruneNearbyObstacleIds(r)}return t.forEach((r,o)=>{r.preferredAngles=this.derivePreferredAngles(r.input,e[o])}),t}buildInitialLayout(t){let e=new Map;for(let r of this.getPlacementOrder(t))e.set(r.input.id,this.pickBestCandidate(r,e,t));return e}refineLayout(t,e){let r=this.getRefinePassCount();for(let o=0;o<r;o++){let _=this.measured.map(s=>{let c=t.get(s.input.id)||this.buildPositionedState(s.input,s.input.initialState),l=this.evaluateCandidate(s,c,t);return{info:s,overlap:l.overlap,score:l.score}}).sort((s,c)=>c.overlap.blockingCount!==s.overlap.blockingCount?c.overlap.blockingCount-s.overlap.blockingCount:c.overlap.blockingArea!==s.overlap.blockingArea?c.overlap.blockingArea-s.overlap.blockingArea:c.overlap.count!==s.overlap.count?c.overlap.count-s.overlap.count:c.overlap.area!==s.overlap.area?c.overlap.area-s.overlap.area:c.score-s.score).map(s=>s.info).filter(s=>!s.config.fixedAfterPlacement);for(let s of _)t.set(s.input.id,this.pickBestCandidate(s,t,e+o+1,t.get(s.input.id)))}}getPlacementOrder(t){let e=[...this.measured].sort((_,s)=>{let c=(s.config.priority||0)-(_.config.priority||0);if(c!==0)return c;let l=s.input.size.width*s.input.size.height-_.input.size.width*_.input.size.height,n=s.density-_.density;return Math.abs(n)>.01?n:l}),r=[];for(let _ of e){let s=_.config.priority||0,c=r[r.length-1];!c||c.priority!==s?r.push({priority:s,items:[_]}):c.items.push(_)}return r.flatMap(_=>{let s=[..._.items];if(t%2===1)s.reverse();else if(t>1&&s.length>0){let c=t%s.length;return[...s.slice(c),...s.slice(0,c)]}return s})}pickBestCandidate(t,e,r,o){let _=this.generateCandidates(t,r,o),s=_[0],c=Number.POSITIVE_INFINITY,l=Number.POSITIVE_INFINITY,n=Number.POSITIVE_INFINITY,d=!1,p=b(t);for(let a of _){let i=this.evaluateCandidate(t,a,e),B=i.overlap;if(d&&B.blockingCount>0)continue;!d&&B.blockingCount===0&&(d=!0,c=Number.POSITIVE_INFINITY,l=0,n=0);let f=i.score;(B.count<l||B.count===l&&B.area<n||B.count===l&&B.area===n&&f<c)&&(s=a,c=f,l=B.count,n=B.area)}return s}generateCandidates(t,e,r){let o=performance.now(),_=this.getCandidateConfig(t),s=_.strategy||"radial",c=this.ensureAnchorCandidateIncluded(this.generateCandidatesForStrategy(s,t,e,r,_),t.input),l=this.applyCandidateConstraints(c,t,_);this.debugMetrics.generatedCandidates+=l.length;let n=this.pruneCandidates(l,t,_.pruningLimit);return this.debugMetrics.prunedCandidates+=n.length,this.debugMetrics.candidateGenerationMs+=performance.now()-o,n}ensureAnchorCandidateIncluded(t,e){let r=this.buildPositionedState(e,{placement:"placed",angle:0,distance:0,dx:0,dy:0});return t.some(_=>_.placement==="placed"&&Math.abs(_.x-e.target.x)<=.5&&Math.abs(_.y-e.target.y)<=.5)?t:[r,...t]}generateCandidatesForStrategy(t,e,r,o,_){switch(t){case"stackedBarDataLabel":return this.generateStackedBarDataLabelCandidates(e,r,o,_);case"clusteredBarDataLabel":return this.generateClusteredBarDataLabelCandidates(e,r,o,_);case"clusteredBarTotalLabel":return this.generateClusteredBarTotalLabelCandidates(e,r,o,_);default:return this.generateRadialCandidates(e,r,o,_)}}generateRadialCandidates(t,e,r,o){let _=[],s=ot(t.preferredAngles,e%3*7.5),c=(o.baseAngles||[]).map(n=>n+e%2*10),l=M(s,c);_.push(this.buildPositionedState(t.input,t.input.initialState)),_.push(this.buildPositionedState(t.input,z)),_.push(this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:0,dy:0}));for(let n of o.distances||[])for(let d of l){let p=d*Math.PI/180;_.push(this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:Math.cos(p)*n,dy:-Math.sin(p)*n}))}if(r&&r.placement==="placed"){_.push(r);let n=M([L(r.x-t.input.target.x,t.input.target.y-r.y)],o.localAngles||[]);for(let d of o.localDistances||[])for(let p of n){let a=p*Math.PI/180;_.push(this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:r.x+Math.cos(a)*d-t.input.target.x,dy:r.y-Math.sin(a)*d-t.input.target.y}))}}return _}generateStackedBarDataLabelCandidates(t,e,r,o){let _=[],s=ot(t.preferredAngles,e%3*7.5),c=(o.baseAngles||[]).map(d=>d+e%2*8),l=M(s,c);_.push(this.buildPositionedState(t.input,t.input.initialState)),_.push(this.buildPositionedState(t.input,z)),_.push(this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:0,dy:0}));for(let d of o.distances||[])for(let p of l){let a=p*Math.PI/180;_.push(this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:Math.cos(a)*d,dy:-Math.sin(a)*d}))}if(this.shouldExpandStackedBarCandidateSearch(t,_,o)){let d=M(l,o.tierTwoAngles||[]);for(let p of o.tierTwoDistances||[])for(let a of d){let i=a*Math.PI/180;_.push(this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:Math.cos(i)*p,dy:-Math.sin(i)*p}))}}if(r&&r.placement==="placed"){_.push(r);let d=M([L(r.x-t.input.target.x,t.input.target.y-r.y)],o.localAngles||[]),p=this.shouldExpandRefinementSearch(t,r,o),a=p?o.localDistances||[]:(o.localDistances||[]).slice(0,Math.max(2,Math.ceil((o.localDistances||[]).length/2))),i=p?d:d.slice(0,Math.max(3,Math.ceil(d.length/2)));for(let B of a)for(let f of i){let u=f*Math.PI/180;_.push(this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:r.x+Math.cos(u)*B-t.input.target.x,dy:r.y-Math.sin(u)*B-t.input.target.y}))}}return _}generateClusteredBarDataLabelCandidates(t,e,r,o){let _=this.generateRadialCandidates(t,e,r,o);return[...this.buildOwnMarkCandidates(t.input),..._]}generateClusteredBarTotalLabelCandidates(t,e,r,o){let _=[this.buildPositionedState(t.input,t.input.initialState),this.buildPositionedState(t.input,z),this.buildPositionedState(t.input,{placement:"placed",angle:0,distance:0,dx:0,dy:0}),...this.buildVerticalAnchorCandidates(t.input,o.distances||[])];return r&&r.placement==="placed"&&(_.push(r),_.push(...this.buildVerticalSeedCandidates(t.input,r,o.localDistances||[]))),_}buildOwnMarkCandidates(t){let e=t?.geometry?.bounds;if(!e)return[];let r=H(e);if(r.width<=0||r.height<=0)return[];let o=(t?.size?.width||0)/2,_=(t?.size?.height||0)/2,s=r.left+o,c=r.right-o,l=r.top+_,n=r.bottom-_,d=s<=c&&l<=n,p=d?O(t.target.x,s,c):O(t.target.x,r.left,r.right),a=d?O(t.target.y,l,n):O(t.target.y,r.top,r.bottom),i=d?O(r.left+r.width/2,s,c):O(r.left+r.width/2,r.left,r.right),B=d?O(r.top+r.height/2,l,n):O(r.top+r.height/2,r.top,r.bottom),f=Math.min(Math.max(2,r.width*.18),Math.max(0,(c-s)/2)),u=Math.min(Math.max(2,r.height*.18),Math.max(0,(n-l)/2));return[{x:p,y:a},{x:i,y:B},{x:i,y:B-u},{x:i,y:B+u},{x:i-f,y:B},{x:i+f,y:B},{x:p,y:B-u},{x:p,y:B+u}].map(X=>this.buildCandidateAtPoint(t,X))}buildVerticalAnchorCandidates(t,e){return[...new Set((e||[]).filter(o=>Number.isFinite(o)&&o>=0))].map(o=>this.buildPositionedState(t,{placement:"placed",angle:0,distance:0,dx:0,dy:-o}))}buildVerticalSeedCandidates(t,e,r){return[...new Set((r||[]).filter(_=>Number.isFinite(_)&&_>=0))].map(_=>this.buildCandidateAtPoint(t,{x:e.x,y:Math.min(e.y,t.target.y)-_}))}shouldExpandStackedBarCandidateSearch(t,e,r){let o={blocking:r.refinementExpansionBlockingThreshold??1,area:r.refinementExpansionAreaThreshold??12},_=this.findBestCandidateOverlapProfile(t,e);return _?_.blockingCount>o.blocking||_.area>o.area||_.blockingArea>o.area:!0}shouldExpandRefinementSearch(t,e,r){let o=e||this.buildPositionedState(t.input,t.input.initialState),_=this.getCombinedBlockingStats(t.input.id,b(t),o,new Map);return _.blockingCount>(r.refinementExpansionBlockingThreshold??1)||_.area>(r.refinementExpansionAreaThreshold??12)||_.blockingArea>(r.refinementExpansionAreaThreshold??12)}findBestCandidateOverlapProfile(t,e){let r=null;for(let o of e){let _=this.getCombinedBlockingStats(t.input.id,b(t),o,new Map);if(!r){r=_;continue}(_.blockingCount<r.blockingCount||_.blockingCount===r.blockingCount&&_.blockingArea<r.blockingArea||_.blockingCount===r.blockingCount&&_.blockingArea===r.blockingArea&&_.area<r.area)&&(r=_)}return r}applyCandidateConstraints(t,e,r){let o=t;if(r.strategy==="clusteredBarTotalLabel"){let _=o.filter(s=>s.placement!=="placed"||s.y-e.input.target.y<=.5);_.length>0&&(o=_)}return o}pruneCandidates(t,e,r){let o=new Map;for(let a of t){let i=a.placement==="hidden"?"hidden":`${a.placement}:${Math.round(a.x*2)}:${Math.round(a.y*2)}`;o.has(i)||o.set(i,a)}let _=[...o.values()],s=this.computePruningBatchMetrics(e,_),c=_.map((a,i)=>({candidate:a,score:this.computePruningScore(e,a,s?.[i]),anchorDistance:Math.hypot(a.x-e.input.target.x,a.y-e.input.target.y)})).sort((a,i)=>a.score-i.score),l=c.filter(a=>a.candidate.placement==="over"||a.anchorDistance<=.5),n=new Set(l.map(a=>a.candidate)),d=c.filter(a=>!n.has(a.candidate)),p=Math.max(0,r-l.length);return[...l,...d.slice(0,p)].map(a=>a.candidate)}computePruningScore(t,e,r=null){let o=performance.now(),_=this.computeCandidateScoreFast(t,e,new Map,r||this.computePruningFallbackMetrics(t,e));return this.debugMetrics.scoringMs+=performance.now()-o,this.debugMetrics.scoreCalls+=1,_}computePruningFallbackMetrics(t,e){let r=b(t);return{labelOverlap:{count:0,area:0,blockingCount:0,blockingArea:0,penalty:0},roleObstacleOverlap:{count:0,area:0,blockingCount:0,blockingArea:0,penalty:0},segmentOverlapArea:this.computeSegmentOverlapArea(t,e),roleObstaclePenalty:this.computeRoleObstaclePenalty(t,r,e)}}computePruningBatchMetrics(t,e){let r=w();if(!r||!e?.length)return null;let o=b(t),_=[];for(let B of t.nearbyObstacleIds){let f=this.obstacleById.get(B);if(!f||f.id===t.input.targetObstacleId)continue;if(!f.role||f.role==="segment"){_.push({bounds:f.bounds,penaltyMultiplier:0,isSegment:1});continue}let u=this.getInteractionPolicy(o,f.role);(u.allowOverlap===!1||u.blocksPlacement!==!1)&&_.push({bounds:f.bounds,penaltyMultiplier:(u.overlapPenaltyMultiplier||1)*t.config.scoring.labelOverlapPenalty,isSegment:0})}if(_.length===0)return e.map(()=>({labelOverlap:{count:0,area:0,blockingCount:0,blockingArea:0,penalty:0},roleObstacleOverlap:{count:0,area:0,blockingCount:0,blockingArea:0,penalty:0},segmentOverlapArea:0,roleObstaclePenalty:0}));Z||(console.log("[ChartLabelPlacementEngine] Using WASM pruning accelerator"),Z=!0),this.debugMetrics.wasmUsage.pruningCalls+=1;let s=r.reserveInputBuffer(e.length*4),c=r.reserveMetaBuffer(_.length*4),l=r.reserveAuxBuffer(_.length*3),n=r.reserveOutputBuffer(e.length*2),d=r.getF64View(s,e.length*4),p=r.getF64View(c,_.length*4),a=r.getF64View(l,_.length*3);e.forEach((B,f)=>{let u=f*4;d[u]=B.box.left,d[u+1]=B.box.top,d[u+2]=B.box.right,d[u+3]=B.box.bottom}),_.forEach((B,f)=>{let u=f*4,m=f*3;p[u]=B.bounds?.left??0,p[u+1]=B.bounds?.top??0,p[u+2]=B.bounds?.right??0,p[u+3]=B.bounds?.bottom??0,a[m]=0,a[m+1]=B.penaltyMultiplier||0,a[m+2]=B.isSegment}),r.exports.compute_pruning_overlap_stats_many(s,e.length,c,l,_.length,n);let i=r.getF64View(n,e.length*2);return e.map((B,f)=>{let u=f*2;return{labelOverlap:{count:0,area:0,blockingCount:0,blockingArea:0,penalty:0},roleObstacleOverlap:{count:0,area:0,blockingCount:0,blockingArea:0,penalty:0},segmentOverlapArea:i[u],roleObstaclePenalty:i[u+1]}})}scoreLayout(t){let e=0;for(let[r,o]of t)e+=this.scoreCandidate(this.requireMeasured(r),o,t);return e}explainState(t,e,r=this.lastLayout){let o=this.requireMeasured(t),_=this.buildPositionedState(o.input,e);return this.buildScoreExplanation(o,_,r||new Map)}explainPoint(t,e,r=this.lastLayout){let o=this.requireMeasured(t),_=this.buildCandidateAtPoint(o.input,e);return this.buildScoreExplanation(o,_,r||new Map)}getSearchBounds(t){let e=this.requireMeasured(t),o=this.getCandidateConfig(e).maxLabelTravel||0,_=H(this.bounds||{});return{left:O(e.input.target.x-o,_.left,_.right),top:O(e.input.target.y-o,_.top,_.bottom),right:O(e.input.target.x+o,_.left,_.right),bottom:O(e.input.target.y+o,_.top,_.bottom),width:Math.max(0,Math.min(_.right,e.input.target.x+o)-Math.max(_.left,e.input.target.x-o)),height:Math.max(0,Math.min(_.bottom,e.input.target.y+o)-Math.max(_.top,e.input.target.y-o))}}scoreCandidate(t,e,r){let o=performance.now(),_=this.computeCandidateScoreFast(t,e,r);return this.debugMetrics.scoringMs+=performance.now()-o,this.debugMetrics.scoreCalls+=1,_}evaluateCandidate(t,e,r){let o=performance.now(),_=this.computeCandidateMetrics(t,e,r),s=this.computeCandidateScoreFast(t,e,r,_);return this.debugMetrics.scoringMs+=performance.now()-o,this.debugMetrics.scoreCalls+=1,{score:s,overlap:{count:_.labelOverlap.count+_.roleObstacleOverlap.count,area:_.labelOverlap.area+_.roleObstacleOverlap.area,blockingCount:_.labelOverlap.blockingCount+_.roleObstacleOverlap.blockingCount,blockingArea:_.labelOverlap.blockingArea+_.roleObstacleOverlap.blockingArea},metrics:_}}computeCandidateScoreFast(t,e,r,o=null){let _=o||this.computeCandidateMetrics(t,e,r);if(e.placement==="hidden")return t.config.scoring.hiddenBucketScore;let s=b(t),c={x:e.x,y:e.y},l=e.placement==="placed"?rt(t.input.geometry,c):{x:0,y:0},n=_t(t.input.geometry),d=l.x===0&&l.y===0,p=e.x-t.input.target.x,a=e.y-t.input.target.y,i=Math.hypot(p,a),B=Math.hypot(l.x,l.y),f=Math.max(n.x,n.y,12),u=0;if(e.placement==="over"){if(u+=t.config.scoring.overBucketScore,t.input.geometry&&t.input.geometry.bounds)if(Q(e.box,t.input.geometry.bounds))u-=t.config.scoring.overInsideAnchorBonus;else{let X=tt(e.box,t.input.geometry.bounds);u+=t.config.scoring.overOutsideAnchorPenalty+X*t.config.scoring.overOutsideAnchorDistanceWeight}}else d?(u+=t.config.scoring.placedWithinMarkBucketScore,u+=i*t.config.scoring.placedInsideMidpointDistancePenalty,u-=h(n.x,p)*t.config.scoring.placedInsideMidpointRewardX,u-=h(n.y,a)*t.config.scoring.placedInsideMidpointRewardY):(u+=t.config.scoring.placedOutsideMarkBucketScore,u+=B*t.config.scoring.placedOutsideBorderDistancePenalty,u-=h(n.x,p)*t.config.scoring.placedOutsideMidpointRewardX,u-=h(n.y,a)*t.config.scoring.placedOutsideMidpointRewardY);u-=Math.max(0,f-i)*t.config.scoring.anchorPointReward,u+=i*i*(t.config.scoring.anchorDistanceQuadraticPenalty||0);let m=et(e.box,this.bounds);if(u+=m*t.config.scoring.overflowLinear+m*m*t.config.scoring.overflowQuadratic,e.placement==="placed"){let X=d?t.config.scoring.otherSegmentOverlapInsidePenalty:t.config.scoring.otherSegmentOverlapOutsidePenalty;u+=_.segmentOverlapArea*X,u+=_.roleObstaclePenalty}return u+=_.labelOverlap.penalty,Number.isFinite(u)||console.warn("[ChartLabelPlacementEngine] Non-finite fast score",{labelId:t.input.id,role:s,candidate:e,metrics:_,scoring:t.config?.scoring}),u}buildScoreExplanation(t,e,r){let o=[],_=b(t);if(e.placement==="hidden")return o.push(C("classification.hidden","Hidden bucket",t.config.scoring.hiddenBucketScore,"Label hidden")),{labelId:t.input.id,placement:"hidden",classification:"hidden",total:t.config.scoring.hiddenBucketScore,terms:o,candidate:e,geometryGap:{x:0,y:0},midpointDistance:0,borderDistance:0,withinMark:!1,midpointOffset:{x:0,y:0},labelOverlap:{count:0,area:0,detail:[]}};let s={x:e.x,y:e.y},c=e.placement==="placed"?rt(t.input.geometry,s):{x:0,y:0},l=_t(t.input.geometry),n=c.x===0&&c.y===0,d=e.x-t.input.target.x,p=e.y-t.input.target.y,a=Math.hypot(d,p),i=Math.hypot(c.x,c.y),B=Math.max(l.x,l.y,12),f=e.placement==="over"?"over":n?"placedWithinMark":"placedOutsideMark";if(e.placement==="over"){if(o.push(C("classification.over","Over bucket",t.config.scoring.overBucketScore,"On-mark candidate")),t.input.geometry&&t.input.geometry.bounds)if(Q(e.box,t.input.geometry.bounds))o.push(C("over.fitReward","Over fit reward",-t.config.scoring.overInsideAnchorBonus,"Label fits inside own mark"));else{let y=tt(e.box,t.input.geometry.bounds);o.push(C("over.fitPenalty","Over fit penalty",t.config.scoring.overOutsideAnchorPenalty+y*t.config.scoring.overOutsideAnchorDistanceWeight,`Outside own mark by ${y.toFixed(1)}`))}}else n?(o.push(C("classification.placedWithinMark","Placed inside bucket",t.config.scoring.placedWithinMarkBucketScore,"Placed and midpoint still inside own mark")),o.push(C("distance.midpointInside","Inside midpoint distance",a*t.config.scoring.placedInsideMidpointDistancePenalty,`Distance to anchor midpoint ${a.toFixed(1)}`)),o.push(C("midpoint.rewardXInside","Inside midpoint reward X",-h(l.x,d)*t.config.scoring.placedInsideMidpointRewardX,`Center x offset ${Math.abs(d).toFixed(1)}`)),o.push(C("midpoint.rewardYInside","Inside midpoint reward Y",-h(l.y,p)*t.config.scoring.placedInsideMidpointRewardY,`Center y offset ${Math.abs(p).toFixed(1)}`))):(o.push(C("classification.placedOutsideMark","Placed outside bucket",t.config.scoring.placedOutsideMarkBucketScore,"Placed and midpoint outside own mark")),o.push(C("distance.borderOutside","Outside border distance",i*t.config.scoring.placedOutsideBorderDistancePenalty,`Distance to mark border ${i.toFixed(1)}`)),o.push(C("midpoint.rewardXOutside","Outside midpoint reward X",-h(l.x,d)*t.config.scoring.placedOutsideMidpointRewardX,`Center x offset ${Math.abs(d).toFixed(1)}`)),o.push(C("midpoint.rewardYOutside","Outside midpoint reward Y",-h(l.y,p)*t.config.scoring.placedOutsideMidpointRewardY,`Center y offset ${Math.abs(p).toFixed(1)}`)));o.push(C("anchor.reward","Anchor point reward",-Math.max(0,B-a)*t.config.scoring.anchorPointReward,`Distance to anchor ${a.toFixed(1)}`)),o.push(C("anchor.distanceQuadratic","Anchor distance quadratic penalty",a*a*(t.config.scoring.anchorDistanceQuadraticPenalty||0),`Squared distance ${(a*a).toFixed(1)}`));let u=et(e.box,this.bounds);if(o.push(C("bounds.overflow","Bounds overflow",u*t.config.scoring.overflowLinear+u*u*t.config.scoring.overflowQuadratic,`Overflow ${u.toFixed(1)}`)),e.placement==="placed"){let y=0,x=[],D=this.computeNearbyObstacleOverlaps(t.input.id,e);for(let E of t.nearbyObstacleIds){let v=this.obstacleById.get(E);if(!v||v.id===t.input.targetObstacleId)continue;let I=D?.get(E)??k(e.box,v.bounds);if(!(I<=0)){if(v.role&&v.role!=="segment"){let F=this.getInteractionPolicy(_,v.role);if(F.allowOverlap===!1||F.blocksPlacement!==!1){let at=I*(F.overlapPenaltyMultiplier||1)*t.config.scoring.labelOverlapPenalty;x.push({role:v.role,value:at,detail:`${v.id} overlap ${I.toFixed(1)} (${_} vs ${v.role})`})}continue}y+=I}}if(y>0){let E=n?t.config.scoring.otherSegmentOverlapInsidePenalty:t.config.scoring.otherSegmentOverlapOutsidePenalty;o.push(C(n?"overlap.segmentInside":"overlap.segmentOutside",n?"Other segment overlap (inside)":"Other segment overlap (outside)",y*E,`Overlap area ${y.toFixed(1)}`))}if(x.length>0){let E=new Map;for(let v of x){let I=E.get(v.role)||{value:0,detail:[]};I.value+=v.value,I.detail.push(v.detail),E.set(v.role,I)}for(let[v,I]of E.entries())o.push(C(`overlap.obstacle.${v}`,`${pt(v)} overlap penalty`,I.value,I.detail.join(", ")))}}let m=this.getLabelOverlapStats(t.input.id,_,e,r||new Map);m.count>0&&o.push(C("overlap.labels","Label overlap penalty",m.penalty,m.detail.join(", ")));let X=o.reduce((y,x)=>y+x.value,0);return(!Number.isFinite(X)||o.some(y=>!Number.isFinite(y.value)))&&console.warn("[ChartLabelPlacementEngine] Non-finite score explanation",{labelId:t.input.id,role:_,placement:e.placement,bounds:this.bounds,target:t.input.target,geometry:t.input.geometry,candidate:e,scoring:t.config?.scoring,terms:o.map(y=>({key:y.key,label:y.label,value:y.value,detail:y.detail}))}),{labelId:t.input.id,placement:e.placement,classification:f,total:X,terms:o,candidate:e,geometryGap:c,midpointDistance:a,borderDistance:i,withinMark:n,midpointOffset:{x:d,y:p},labelOverlap:m}}buildPositionedState(t,e){let r=this.resolveCoords(t,e);return{placement:e.placement,angle:e.angle||0,distance:e.distance||0,dx:e.dx||0,dy:e.dy||0,x:r.x,y:r.y,leaderLength:e.placement==="placed"?Math.hypot(r.x-t.target.x,r.y-t.target.y):0,box:ut(r.x,r.y,t.size)}}buildCandidateAtPoint(t,e){return this.buildPositionedState(t,{placement:"placed",angle:0,distance:0,dx:e.x-t.target.x,dy:e.y-t.target.y})}resolveCoords(t,e){if(e.placement==="over"||e.placement==="hidden")return{x:t.target.x,y:t.target.y};let r=this.getCandidateConfigForInput(t),o=O(e.dx||0,-r.maxLabelTravel,r.maxLabelTravel),_=O(e.dy||0,-r.maxLabelTravel,r.maxLabelTravel);return{x:t.target.x+o,y:t.target.y+_}}derivePreferredAngles(t,e){let r=e.x,o=e.y;if(r===0&&o===0){let c=this.bounds.left+this.bounds.width/2,l=this.bounds.top+this.bounds.height/2;r=t.target.x-c,o=l-t.target.y}let _=L(r,o),s=t.target.x<this.bounds.left+this.bounds.width*.22?0:t.target.x>this.bounds.left+this.bounds.width*.78?180:t.target.y<this.bounds.top+this.bounds.height*.22?270:t.target.y>this.bounds.top+this.bounds.height*.78?90:_;return M([_,s],[0,45,90,135,180,225,270,315])}getCombinedBlockingStats(t,e,r,o){let _=this.computeCandidateMetrics(this.requireMeasured(t),r,o),s=_.labelOverlap,c=_.roleObstacleOverlap;return{...s,count:s.count+c.count,area:s.area+c.area,blockingCount:s.blockingCount+c.blockingCount,blockingArea:s.blockingArea+c.blockingArea}}computeCandidateMetrics(t,e,r){let o=b(t);return{labelOverlap:this.computeLabelOverlapAggregate(t,o,e,r||new Map),roleObstacleOverlap:this.computeRoleObstacleOverlapAggregate(t,o,e),segmentOverlapArea:this.computeSegmentOverlapArea(t,e),roleObstaclePenalty:this.computeRoleObstaclePenalty(t,o,e)}}getLabelOverlapStats(t,e,r,o){let _=[],s=0,c=0,l=0,n=0,d=0,p=this.requireMeasured(t).config.scoring.labelOverlapPadding||0,a=q(r.box,p),i=this.computeLayoutLabelOverlaps(t,a,o);for(let[B,f]of o){if(B===t||f.placement==="hidden")continue;let u=this.measuredById.get(B),m=u?b(u):"dataLabel",X=this.getInteractionPolicy(e,m),y=u?.config?.scoring?.labelOverlapPadding||0,x=i?.get(B)??k(a,q(f.box,y));if(!(x<=0))if(s+=1,c+=x,X.blocksPlacement!==!1&&(l+=1,n+=x),X.allowOverlap===!1){let D=x*(X.overlapPenaltyMultiplier||1)*this.requireMeasured(t).config.scoring.labelOverlapPenalty;d+=D,_.push(`${B} overlap ${x.toFixed(1)} (${e} vs ${m})`)}else _.push(`${B} overlap ${x.toFixed(1)} allowed`)}return{count:s,area:c,detail:_,penalty:d,blockingCount:l,blockingArea:n}}computeLabelOverlapAggregate(t,e,r,o){let _=[],s=t.config.scoring.labelOverlapPadding||0,c=q(r.box,s);for(let[l,n]of o){if(l===t.input.id||n?.placement==="hidden")continue;let d=this.measuredById.get(l),p=d?b(d):"dataLabel",a=this.getInteractionPolicy(e,p),i=d?.config?.scoring?.labelOverlapPadding||0;_.push({bounds:q(n.box,i),blocks:a.blocksPlacement!==!1,penaltyMultiplier:a.allowOverlap===!1?(a.overlapPenaltyMultiplier||1)*t.config.scoring.labelOverlapPenalty:0})}return this.computeOverlapAggregate(c,_)}computeLayoutLabelOverlaps(t,e,r){let o=w();if(!o)return null;$||(console.log("[ChartLabelPlacementEngine] Using WASM label-overlap accelerator"),$=!0),this.debugMetrics.wasmUsage.labelOverlapCalls+=1;let _=[];for(let[p,a]of r){if(p===t||a?.placement==="hidden")continue;let B=this.measuredById.get(p)?.config?.scoring?.labelOverlapPadding||0;_.push({id:p,box:q(a.box,B)})}if(_.length===0)return null;let s=_.length,c=o.reserveInputBuffer(s*4),l=o.reserveOutputBuffer(s),n=o.getF64View(c,s*4);for(let p=0;p<s;p++){let a=_[p].box,i=p*4;n[i]=a?.left??0,n[i+1]=a?.top??0,n[i+2]=a?.right??0,n[i+3]=a?.bottom??0}o.exports.compute_overlap_areas(e.left,e.top,e.right,e.bottom,c,s,l);let d=o.getF64View(l,s);return new Map(_.map((p,a)=>[p.id,d[a]]))}computeRoleObstacleOverlapAggregate(t,e,r){let o=[];for(let _ of t.nearbyObstacleIds){let s=this.obstacleById.get(_);if(!s||!s.role||s.role==="segment"||s.id===t.input.targetObstacleId)continue;let c=this.getInteractionPolicy(e,s.role);c.blocksPlacement===!1&&c.allowOverlap!==!1||o.push({bounds:s.bounds,blocks:c.blocksPlacement!==!1,penaltyMultiplier:0})}return this.computeOverlapAggregate(r.box,o)}computeSegmentOverlapArea(t,e){let r=[];for(let o of t.nearbyObstacleIds){let _=this.obstacleById.get(o);!_||_.id===t.input.targetObstacleId||_.role&&_.role!=="segment"||r.push({bounds:_.bounds,blocks:!1,penaltyMultiplier:0})}return this.computeOverlapAggregate(e.box,r).area}computeRoleObstaclePenalty(t,e,r){let o=[];for(let _ of t.nearbyObstacleIds){let s=this.obstacleById.get(_);if(!s||!s.role||s.role==="segment"||s.id===t.input.targetObstacleId)continue;let c=this.getInteractionPolicy(e,s.role);(c.allowOverlap===!1||c.blocksPlacement!==!1)&&o.push({bounds:s.bounds,blocks:!1,penaltyMultiplier:(c.overlapPenaltyMultiplier||1)*t.config.scoring.labelOverlapPenalty})}return this.computeOverlapAggregate(r.box,o).penalty}computeOverlapAggregate(t,e){if(!e||e.length===0)return{count:0,area:0,blockingCount:0,blockingArea:0,penalty:0};let r=w();if(r){K||(console.log("[ChartLabelPlacementEngine] Using WASM overlap-stats accelerator"),K=!0),this.debugMetrics.wasmUsage.overlapStatsCalls+=1;let n=e.length,d=r.reserveInputBuffer(n*4),p=r.reserveMetaBuffer(n*2),a=r.reserveOutputBuffer(5),i=r.getF64View(d,n*4),B=r.getF64View(p,n*2);for(let u=0;u<n;u++){let m=e[u].bounds,X=u*4,y=u*2;i[X]=m?.left??0,i[X+1]=m?.top??0,i[X+2]=m?.right??0,i[X+3]=m?.bottom??0,B[y]=e[u].blocks?1:0,B[y+1]=e[u].penaltyMultiplier||0}r.exports.compute_overlap_stats(t.left,t.top,t.right,t.bottom,d,p,n,a);let f=r.getF64View(a,5);return{count:f[0],area:f[1],blockingCount:f[2],blockingArea:f[3],penalty:f[4]}}let o=0,_=0,s=0,c=0,l=0;for(let n of e){let d=k(t,n.bounds);d<=0||(o+=1,_+=d,n.blocks&&(s+=1,c+=d),n.penaltyMultiplier&&(l+=d*n.penaltyMultiplier))}return{count:o,area:_,blockingCount:s,blockingArea:c,penalty:l}}getRoleObstacleOverlapStats(t,e,r){let o=0,_=0,s=0,c=0,l=this.computeNearbyObstacleOverlaps(t,r);for(let n of this.requireMeasured(t).nearbyObstacleIds){let d=this.obstacleById.get(n);if(!d||!d.role||d.role==="segment"||d.id===this.requireMeasured(t).input.targetObstacleId)continue;let p=this.getInteractionPolicy(e,d.role);if(p.blocksPlacement===!1&&p.allowOverlap!==!1)continue;let a=l?.get(n)??k(r.box,d.bounds);a<=0||(o+=1,_+=a,p.blocksPlacement!==!1&&(s+=1,c+=a))}return{count:o,area:_,blockingCount:s,blockingArea:c}}computeNearbyObstacleOverlaps(t,e){let r=w();if(!r)return null;Y||(console.log("[ChartLabelPlacementEngine] Using WASM overlap accelerator"),Y=!0),this.debugMetrics.wasmUsage.overlapCalls+=1;let o=this.requireMeasured(t).nearbyObstacleIds||[];if(o.length===0)return null;let _=o.length,s=r.reserveInputBuffer(_*4),c=r.reserveOutputBuffer(_),l=r.getF64View(s,_*4);for(let d=0;d<_;d++){let a=this.obstacleById.get(o[d])?.bounds,i=d*4;l[i]=a?.left??0,l[i+1]=a?.top??0,l[i+2]=a?.right??0,l[i+3]=a?.bottom??0}r.exports.compute_overlap_areas(e.box.left,e.box.top,e.box.right,e.box.bottom,s,_,c);let n=r.getF64View(c,_);return new Map(o.map((d,p)=>[d,n[p]]))}shouldIncludeNearbyObstacle(t,e,r,o){if(!e?.bounds)return!1;let _=e.role||"segment",s=this.getInteractionPolicy(t.input.role,_);if(s.blocksPlacement===!1&&s.allowOverlap!==!1)return!1;let c=T(e.bounds),l=r+e.bounds.width/2,n=o+e.bounds.height/2;if(_==="lineSegment"){let d=typeof t.input.columnIndex=="number"?t.input.columnIndex:null,p=typeof e.columnIndex=="number"?e.columnIndex:null;if(d!==null&&p!==null&&Math.abs(p-d)>3)return!1;l=Math.min(l,96),n=Math.min(n,48)}return Math.abs(c.x-t.input.target.x)<=l&&Math.abs(c.y-t.input.target.y)<=n}pruneNearbyObstacleIds(t){let e=t.nearbyObstacleIds||[];if(e.length<=1)return e;let r=[],o=[];for(let _ of e)this.obstacleById.get(_)?.role==="lineSegment"?r.push(_):o.push(_);return r.length===0?e:(r.sort((_,s)=>{let c=this.obstacleById.get(_),l=this.obstacleById.get(s);return this.getObstacleDistanceScore(t,c)-this.getObstacleDistanceScore(t,l)}),o.concat(r.slice(0,96)))}getObstacleDistanceScore(t,e){if(!e?.bounds)return Number.POSITIVE_INFINITY;let r=T(e.bounds),o=r.x-t.input.target.x,_=r.y-t.input.target.y;return o*o+_*_}getRolePreset(t){return this.preset.roles?.[t]||this.preset.roles?.dataLabel||P}getCandidateConfig(t){return R(this.preset.candidates,t.config.candidates||{})}getCandidateConfigForInput(t){return R(this.preset.candidates,this.getRolePreset(t.role).candidates||{})}getSolveAttempts(){let t=this.measured.map(e=>this.getCandidateConfig(e).attempts).filter(e=>Number.isFinite(e)&&e>0);return t.length>0?Math.max(...t):Math.max(1,this.preset.candidates.attempts||1)}getRefinePassCount(){let t=this.measured.map(e=>this.getCandidateConfig(e).refinePasses).filter(e=>Number.isFinite(e)&&e>=0);return t.length>0?Math.max(...t):Math.max(0,this.preset.candidates.refinePasses||0)}getInteractionPolicy(t,e){let r=this.preset.interactions?.[t]?.[e],o=this.preset.interactions?.[e]?.[t];return R(Nt,r||o||{})}requireMeasured(t){let e=this.measuredById.get(t);if(!e)throw new Error(`Unknown label id: ${t}`);return e}cloneLayout(t){return new Map([...t.entries()].map(([e,r])=>[e,{...r,box:{...r.box}}]))}},z={placement:"over",angle:0,distance:0,dx:0,dy:0},P={priority:10,fixedAfterPlacement:!1,candidates:{},scoring:{hiddenBucketScore:300,overBucketScore:0,anchorPointReward:0,placedWithinMarkBucketScore:120,placedOutsideMarkBucketScore:220,placedInsideMidpointDistancePenalty:2,placedInsideMidpointRewardX:1.25,placedInsideMidpointRewardY:2.5,placedOutsideBorderDistancePenalty:1,placedOutsideMidpointRewardX:0,placedOutsideMidpointRewardY:0,labelOverlapPenalty:5e3,otherSegmentOverlapInsidePenalty:0,otherSegmentOverlapOutsidePenalty:0,overflowLinear:160,overflowQuadratic:4,anchorDistanceQuadraticPenalty:0,overOutsideAnchorPenalty:280,overOutsideAnchorDistanceWeight:70,overInsideAnchorBonus:26}},Nt={allowOverlap:!1,blocksPlacement:!0,overlapPenaltyMultiplier:1,canDisplace:!1},G={candidates:{distances:[10,18,28,40,54,70,86],baseAngles:Array.from({length:18},(N,t)=>t*20),localDistances:[6,14,24],localAngles:[0,45,90,135,180,225,270,315],pruningLimit:72,maxLabelTravel:96,attempts:4,refinePasses:3},scoring:{labelOverlapPenalty:5e3,labelOverlapPadding:0},neighborhood:{densityRadius:120,preferredAngleRadius:150,nearbyPadding:12},roles:{dataLabel:P,totalLabel:{priority:100,fixedAfterPlacement:!0,candidates:{distances:[6,12,18,26,34],baseAngles:[90,78,102,66,114,45,135],localDistances:[4,8,12],localAngles:[90,78,102,66,114],pruningLimit:36,maxLabelTravel:36,attempts:2,refinePasses:1},scoring:{hiddenBucketScore:1800,overBucketScore:0,anchorPointReward:0,placedWithinMarkBucketScore:140,placedOutsideMarkBucketScore:260,placedInsideMidpointDistancePenalty:6,placedInsideMidpointRewardX:0,placedInsideMidpointRewardY:0,placedOutsideBorderDistancePenalty:4,placedOutsideMidpointRewardX:0,placedOutsideMidpointRewardY:8,labelOverlapPenalty:8e3,overOutsideAnchorPenalty:0,overOutsideAnchorDistanceWeight:0,overInsideAnchorBonus:0}}},interactions:{dataLabel:{dataLabel:{},totalLabel:{allowOverlap:!1,blocksPlacement:!0,overlapPenaltyMultiplier:1.25,canDisplace:!1}},totalLabel:{totalLabel:{allowOverlap:!1,blocksPlacement:!0,overlapPenaltyMultiplier:1.5,canDisplace:!1}}}},it={stackedBar:{dataLabel:{scoring:{hiddenBucketScore:300,overBucketScore:0,anchorPointReward:0,placedWithinMarkBucketScore:120,placedOutsideMarkBucketScore:220,placedInsideMidpointDistancePenalty:2,placedInsideMidpointRewardX:1.25,placedInsideMidpointRewardY:2.5,placedOutsideBorderDistancePenalty:1,placedOutsideMidpointRewardX:0,placedOutsideMidpointRewardY:0,labelOverlapPenalty:5e3,labelOverlapPadding:0,otherSegmentOverlapInsidePenalty:0,otherSegmentOverlapOutsidePenalty:0,overflowLinear:160,overflowQuadratic:4,overOutsideAnchorPenalty:280,overOutsideAnchorDistanceWeight:70,overInsideAnchorBonus:26}},totalLabel:{priority:100,fixedAfterPlacement:!0,candidates:{distances:[6,12,18,26,34],baseAngles:[90,78,102,66,114,45,135],localDistances:[4,8,12],localAngles:[90,78,102,66,114],pruningLimit:36,maxLabelTravel:36,attempts:2,refinePasses:1},scoring:{hiddenBucketScore:1800,overBucketScore:0,anchorPointReward:0,placedWithinMarkBucketScore:140,placedOutsideMarkBucketScore:260,placedInsideMidpointDistancePenalty:6,placedInsideMidpointRewardX:0,placedInsideMidpointRewardY:0,placedOutsideBorderDistancePenalty:4,placedOutsideMidpointRewardX:0,placedOutsideMidpointRewardY:8,labelOverlapPenalty:8e3,overOutsideAnchorPenalty:0,overOutsideAnchorDistanceWeight:0,overInsideAnchorBonus:0}},interactions:{dataLabel:{totalLabel:{allowOverlap:!1,blocksPlacement:!0,overlapPenaltyMultiplier:1.25,canDisplace:!1}},totalLabel:{totalLabel:{allowOverlap:!1,blocksPlacement:!0,overlapPenaltyMultiplier:1.5,canDisplace:!1}}}},stackedBar100:{dataLabel:{},totalLabel:{},interactions:{}}},j=R(it,typeof window<"u"?window.ChartLabelPlacementPresetConfig||{}:{}),lt={STACKED_BAR:j.stackedBar||{},STACKED_BAR_100:j.stackedBar100||j.stackedBar||{}};function nt(N){let t=R(G,{candidates:N.candidates||{},neighborhood:N.neighborhood||{},scoring:N.scoring||{}}),e=N.roles||{},o={...Object.fromEntries(Object.entries(N).filter(([s])=>!["candidates","neighborhood","scoring","roles","interactions"].includes(s))),...e},_=new Set([...Object.keys(G.roles||{}),...Object.keys(o||{})]);t.roles={};for(let s of _){let c=R(P,G.roles?.[s]||{});t.roles[s]=R(c,o?.[s]||{})}return t.interactions=dt(G.interactions||{},N.interactions||{}),t}function R(N,t){if(!t)return J(N);if(Array.isArray(N))return J(t);let e={...N};for(let r of Object.keys(t)){let o=t[r];if(o===void 0)continue;let _=e[r];_&&typeof _=="object"&&!Array.isArray(_)&&o&&typeof o=="object"&&!Array.isArray(o)?e[r]=R(_,o):e[r]=J(o)}return e}function dt(N,t){let e=J(N||{});for(let[r,o]of Object.entries(t||{})){e[r]||(e[r]={});for(let[_,s]of Object.entries(o||{}))e[r][_]=R(Nt,s||{})}return e}function J(N){return JSON.parse(JSON.stringify(N))}function b(N){return N?.input?.role||"dataLabel"}function pt(N){return N?N.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/^./,t=>t.toUpperCase()):"Obstacle"}function h(N,t){let e=g(N);if(e<=0)return 0;let r=Math.max(0,e-Math.abs(g(t)));if(r<=0)return 0;let o=r/e;return e*o*o}function H(N){let t=g(N.left!==void 0?N.left:N.x),e=g(N.top!==void 0?N.top:N.y),r=g(N.width!==void 0?N.width:N.right!==void 0?N.right-t:0),o=g(N.height!==void 0?N.height:N.bottom!==void 0?N.bottom-e:0),_=g(N.right!==void 0?N.right:t+r),s=g(N.bottom!==void 0?N.bottom:e+o);return{left:t,top:e,width:r,height:o,right:_,bottom:s}}function w(){let N=globalThis;return N?.__CHARTBUDDY_ARTIFACT__?null:N?.ChartLabelPlacementWasm||null}var Y=!1,$=!1,K=!1,Z=!1;function ut(N,t,e){let r=g(e?.width),o=g(e?.height),_=g(N),s=g(t);return{left:_-r/2,right:_+r/2,top:s-o/2,bottom:s+o/2,width:r,height:o}}function T(N){return{x:(N.left+N.right)/2,y:(N.top+N.bottom)/2}}function k(N,t){let e=Math.max(0,Math.min(N.right,t.right)-Math.max(N.left,t.left)),r=Math.max(0,Math.min(N.bottom,t.bottom)-Math.max(N.top,t.top));return e*r}function q(N,t){return{left:N.left-t,right:N.right+t,top:N.top-t,bottom:N.bottom+t,width:N.width+t*2,height:N.height+t*2}}function Q(N,t){return N.left>=t.left&&N.right<=t.right&&N.top>=t.top&&N.bottom<=t.bottom}function tt(N,t){return Math.max(0,t.left-N.left,N.right-t.right,t.top-N.top,N.bottom-t.bottom)}function et(N,t){let e={left:g(N?.left),right:g(N?.right),top:g(N?.top),bottom:g(N?.bottom)},r=H(t||{});return Math.max(0,r.left-e.left)+Math.max(0,e.right-r.right)+Math.max(0,r.top-e.top)+Math.max(0,e.bottom-r.bottom)}function g(N){let t=typeof N=="number"?N:parseFloat(N);return Number.isFinite(t)?t:0}function rt(N,t){return!N||!N.bounds?{x:0,y:0}:N.shape==="circle"&&N.radius?ft(T(N.bounds),N.radius,t):Bt(t,N.bounds)}function _t(N){return!N||!N.bounds?{x:0,y:0}:N.shape==="circle"&&N.radius?{x:N.radius,y:N.radius}:{x:N.bounds.width/2,y:N.bounds.height/2}}function Bt(N,t){return{x:N.x<t.left?t.left-N.x:N.x>t.right?N.x-t.right:0,y:N.y<t.top?t.top-N.y:N.y>t.bottom?N.y-t.bottom:0}}function ft(N,t,e){let r=e.x-N.x,o=e.y-N.y,_=Math.max(0,Math.abs(r)-t),s=Math.max(0,Math.abs(o)-t);return{x:_,y:s}}function L(N,t){let e=Math.atan2(t,N)*180/Math.PI;return U(-e)}function U(N){return(N%360+360)%360}function ot(N,t){return N.map(e=>U(e+t))}function M(N,t){let e=[],r=new Set;for(let o of[...N,...t]){let _=U(o),s=Math.round(_*10)/10;r.has(s)||(r.add(s),e.push(_))}return e}function O(N,t,e){return Math.max(t,Math.min(e,N))}function C(N,t,e,r){return{id:N,label:t,value:e,detail:r}}var S="../../../labelPlacementAccel-QHVANOZO.wasm";self.ChartLabelPlacementEngine=A;self.ChartLabelPlacementWasm=null;var V=null,W=!1;function yt(){let t=self.__chartLabelPlacementWorkerSourceUrl||self.location?.href||"";if(!S)throw new Error("Missing emitted WASM asset path");try{return new URL(S,t).toString()}catch(e){console.warn("[LabelPlacementWorker] Failed to resolve WASM URL from worker source, trying raw asset path",{workerSourceUrl:t,labelPlacementAccelUrl:S,error:e})}try{return new URL(S,self.location?.origin||t).toString()}catch(e){throw new Error(`Unable to resolve WASM asset URL from "${S}" with base "${t}": ${e instanceof Error?e.message:String(e)}`)}}async function Xt(){return self.ChartLabelPlacementWasm?(W||(console.log("[LabelPlacementWorker] Reusing loaded WASM accelerator"),W=!0),self.ChartLabelPlacementWasm):(V||(V=(async()=>{try{let N=yt();console.log("[LabelPlacementWorker] Loading WASM accelerator",{wasmUrl:N,workerSourceUrl:self.__chartLabelPlacementWorkerSourceUrl||self.location?.href||null});let t=await fetch(N);if(!t.ok)throw new Error(`Failed to fetch WASM asset: ${t.status} ${t.statusText}`);let e=await t.arrayBuffer(),{instance:r}=await WebAssembly.instantiate(e,{}),o={exports:r.exports,memory:r.exports.memory,reserveInputBuffer(_){return r.exports.reserve_input_buffer(_)},reserveMetaBuffer(_){return r.exports.reserve_meta_buffer(_)},reserveAuxBuffer(_){return r.exports.reserve_aux_buffer(_)},reserveOutputBuffer(_){return r.exports.reserve_output_buffer(_)},getF64View(_,s){return new Float64Array(r.exports.memory.buffer,_,s)}};return self.ChartLabelPlacementWasm=o,W=!0,console.log("[LabelPlacementWorker] WASM accelerator loaded",{wasmUrl:N,byteLength:e.byteLength}),o}catch(N){return console.warn("[LabelPlacementWorker] Failed to load WASM accelerator, using JS fallback",{error:N,labelPlacementAccelUrl:S,workerSourceUrl:self.__chartLabelPlacementWorkerSourceUrl||self.location?.href||null}),self.ChartLabelPlacementWasm=null,null}})()),V)}self.onmessage=function(t){Promise.resolve(Ct(t)).catch(e=>{let o=t?.data?.requestId??null;self.postMessage({requestId:o,success:!1,error:{message:e?.message||String(e),stack:e?.stack||null}})})};async function Ct(N){await Xt();let t=N.data,e=t?.requestId??null,r=t?.task||t;if(!r||!r.type){self.postMessage({requestId:e,success:!1,error:{message:"Invalid worker task payload"}});return}try{switch(r.type){case"stackedBarLabelLayout":self.postMessage({requestId:e,success:!0,result:st(r.payload)});return;case"clusteredBarLabelLayout":case"lineLabelLayout":self.postMessage({requestId:e,success:!0,result:st(r.payload)});return;case"comboLabelLayout":self.postMessage({requestId:e,success:!0,result:vt(r.payload)});return;default:self.postMessage({requestId:e,success:!1,error:{message:`Unsupported worker task: ${r.type}`}})}}catch(o){self.postMessage({requestId:e,success:!1,error:{message:o?.message||String(o),stack:o?.stack||null}})}}function st(N){let t=self.ChartLabelPlacementEngine;if(!t||typeof t!="function")throw new Error("ChartLabelPlacementEngine is not available in worker");let e=(N.labels||[]).filter(i=>i.role==="totalLabel"),r=(N.labels||[]).filter(i=>i.role!=="totalLabel"),o=new Map((N.specs||[]).map(i=>[i.id,i])),_=new Map((N.manualStates||[]).map(i=>[i.id,i.state])),s=N.manualObstacles||[],l=new t(e.filter(i=>!_.has(i.id)),[...N.obstacles||[],...s],N.totalBounds||{},N.preset||{}).layoutLabels(),n=e.map(i=>{if(_.has(i.id))return{id:i.id,state:_.get(i.id)};let B=o.get(i.id),f=l.states?.get(i.id);return{id:i.id,state:ct(B,f)}}),d=n.flatMap(i=>{if(!i?.state)return[];let B=o.get(i.id);return[{id:`placed-total-${i.id}`,bounds:{...i.state.box},fill:B?.backgroundColor==="transparent"?"#ffffff":B?.backgroundColor||"#ffffff",role:"totalLabel",columnIndex:B?.columnIndex,seriesIndex:B?.seriesIndex}]}),a=new t(r.filter(i=>!_.has(i.id)),[...N.obstacles||[],...s,...d.filter(i=>!s.some(B=>B.id===i.id))],N.plotArea||{},N.preset||{}).layoutLabels();return{manualStates:Array.from(_.entries()).map(([i,B])=>({id:i,state:B})),manualObstacles:s,finalTotalStates:n,totalObstacles:d,dataStates:Array.from(a.states.entries()).map(([i,B])=>({id:i,state:B}))}}function vt(N){let t=self.ChartLabelPlacementEngine;if(!t||typeof t!="function")throw new Error("ChartLabelPlacementEngine is not available in worker");let e=new Map((N.specs||[]).map(p=>[p.id,p])),r=new Map((N.manualStates||[]).map(p=>[p.id,p.state])),o=N.manualObstacles||[],_=[...N.obstacles||[],...o],s=new Map(r),c={},l=[],n=[{role:"barTotalLabel",bounds:N.totalBounds||{}},{role:"barDataLabel",bounds:N.plotArea||{}},{role:"lineDataLabel",bounds:N.plotArea||{}}],d=[..._];for(let p of n){let a=(N.labels||[]).filter(m=>m.role===p.role&&!r.has(m.id)),B=new t(a,d,p.bounds,N.preset||{}).layoutLabels(),f=[],u=[];a.forEach(m=>{let X=e.get(m.id),y=B.states?.get(m.id);if(p.role==="barTotalLabel"&&(y=ct(X,y)),!!y&&(s.set(m.id,y),f.push({id:m.id,state:y}),p.role!=="lineDataLabel"&&y.box)){let x=p.role==="barTotalLabel"?"barTotalLabel":"barDataLabel";u.push({id:`placed-${p.role}-${m.id}`,bounds:{...y.box},fill:X?.backgroundColor==="transparent"?"#ffffff":X?.backgroundColor||"#ffffff",role:x,columnIndex:X?.columnIndex,seriesIndex:X?.seriesIndex})}}),d.push(...u),l.push(...u),c[p.role]={states:f,autoObstacles:u}}return{manualStates:Array.from(r.entries()).map(([p,a])=>({id:p,state:a})),manualObstacles:o,roleResults:c,states:Array.from(s.entries()).map(([p,a])=>({id:p,state:a})),autoObstacles:l}}function ct(N,t){if(t&&t.placement!=="hidden"&&Number.isFinite(t.x)&&Number.isFinite(t.y))return t;let e=N?.size?.width||0,r=N?.size?.height||0;return{placement:"over",angle:0,distance:0,dx:0,dy:0,x:N.anchorX,y:N.anchorY,leaderLength:0,box:{left:N.anchorX-e/2,right:N.anchorX+e/2,top:N.anchorY-r/2,bottom:N.anchorY+r/2,width:e,height:r}}}})();
|
|
2
|
+
//# sourceMappingURL=labelPlacementWorker.js.map
|
|
Binary file
|