ml-time-graph 1.0.0 → 1.0.5

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.
@@ -1,4 +1,4 @@
1
- import { l as DataPoint, p as DrawCommand, ae as TimeScale, W as LinearScale } from '../scale-Cbr0KpPz.js';
1
+ import { k as DataPoint, o as DrawCommand, ad as TimeScale, V as LinearScale } from '../scale-BRE_QhbZ.js';
2
2
 
3
3
  /*!
4
4
  * MLTimeGraph — Copyright (c) 2026 Michael Lechner
@@ -1,438 +1,5 @@
1
- // src/core/scale.ts
2
- var LinearScale = class {
3
- #domain;
4
- #range;
5
- constructor(config) {
6
- this.#domain = [...config.domain];
7
- this.#range = [...config.range];
8
- }
9
- map(value) {
10
- const v = Number(value);
11
- const [d0, d1] = this.#domain;
12
- const [r0, r1] = this.#range;
13
- if (d1 === d0) return r0;
14
- return r0 + (v - d0) / (d1 - d0) * (r1 - r0);
15
- }
16
- invert(pixel) {
17
- const [d0, d1] = this.#domain;
18
- const [r0, r1] = this.#range;
19
- if (r1 === r0) return d0;
20
- return d0 + (pixel - r0) / (r1 - r0) * (d1 - d0);
21
- }
22
- domain() {
23
- return [...this.#domain];
24
- }
25
- range() {
26
- return [...this.#range];
27
- }
28
- };
29
- var TIME_INTERVALS = [
30
- { label: "second", ms: 1e3 },
31
- { label: "2_seconds", ms: 2e3 },
32
- { label: "5_seconds", ms: 5e3 },
33
- { label: "10_seconds", ms: 1e4 },
34
- { label: "30_seconds", ms: 3e4 },
35
- { label: "minute", ms: 6e4 },
36
- { label: "5_minutes", ms: 3e5 },
37
- { label: "15_minutes", ms: 9e5 },
38
- { label: "30_minutes", ms: 18e5 },
39
- { label: "hour", ms: 36e5 },
40
- { label: "3_hours", ms: 108e5 },
41
- { label: "6_hours", ms: 216e5 },
42
- { label: "day", ms: 864e5 },
43
- { label: "week", ms: 6048e5 },
44
- { label: "month", ms: 2592e6 },
45
- { label: "3_months", ms: 7776e6 },
46
- { label: "6_months", ms: 15552e6 },
47
- { label: "year", ms: 31536e6 },
48
- { label: "2_years", ms: 63072e6 },
49
- { label: "5_years", ms: 15768e7 }
50
- ];
51
- var TimeScale = class {
52
- #linear;
53
- #locale;
54
- constructor(config) {
55
- this.#linear = new LinearScale({
56
- domain: config.domain,
57
- range: config.range
58
- });
59
- this.#locale = config.locale || (typeof navigator !== "undefined" ? navigator.language : "en-US");
60
- }
61
- map(value) {
62
- return this.#linear.map(Number(value));
63
- }
64
- invert(pixel) {
65
- return this.#linear.invert(pixel);
66
- }
67
- domain() {
68
- return this.#linear.domain();
69
- }
70
- range() {
71
- return this.#linear.range();
72
- }
73
- get locale() {
74
- return this.#locale;
75
- }
76
- /**
77
- * Pick the "nicest" time interval that yields roughly `targetTicks` ticks
78
- * across the visible range. Clamps to minTicks / maxTicks bounds.
79
- */
80
- tickInterval(targetTicks, minTicks = 3, maxTicks = 12) {
81
- const [d0, d1] = this.#linear.domain();
82
- const totalMs = d1 - d0;
83
- if (totalMs <= 0) return { interval: TIME_INTERVALS[0].ms };
84
- const ideal = totalMs / targetTicks;
85
- let picked = TIME_INTERVALS[0].ms;
86
- for (const t of TIME_INTERVALS) {
87
- if (t.ms >= ideal) {
88
- picked = t.ms;
89
- break;
90
- }
91
- }
92
- let candidate = picked;
93
- let count = Math.round(totalMs / candidate);
94
- while (count > maxTicks && candidate < TIME_INTERVALS[TIME_INTERVALS.length - 1].ms) {
95
- const idx = TIME_INTERVALS.findIndex((t) => t.ms === candidate);
96
- candidate = TIME_INTERVALS[Math.min(idx + 1, TIME_INTERVALS.length - 1)].ms;
97
- count = Math.round(totalMs / candidate);
98
- }
99
- while (count < minTicks && candidate > TIME_INTERVALS[0].ms) {
100
- const idx = TIME_INTERVALS.findIndex((t) => t.ms === candidate);
101
- candidate = TIME_INTERVALS[Math.max(idx - 1, 0)].ms;
102
- count = Math.round(totalMs / candidate);
103
- }
104
- return { interval: candidate };
105
- }
106
- /**
107
- * Generate tick positions (timestamps) across the domain.
108
- */
109
- ticks(opts) {
110
- const minT = opts?.minTicks ?? 5;
111
- const maxT = opts?.maxTicks ?? 12;
112
- const { interval } = this.tickInterval(
113
- (minT + maxT) / 2,
114
- minT,
115
- maxT
116
- );
117
- const [d0, d1] = this.#linear.domain();
118
- const result = [];
119
- const start = Math.ceil(d0 / interval) * interval;
120
- for (let t = start; t <= d1; t += interval) {
121
- result.push(t);
122
- }
123
- return result;
124
- }
125
- /** Format a timestamp using Intl.DateTimeFormat */
126
- format(timestamp, formatOpts) {
127
- return new Intl.DateTimeFormat(this.#locale, formatOpts).format(
128
- new Date(timestamp)
129
- );
130
- }
131
- };
132
-
133
- // src/interaction/zoom.ts
134
- var Zoom = class {
135
- _config;
136
- _state;
137
- constructor(initialDomain, config) {
138
- this._config = {
139
- enabled: config?.enabled ?? true,
140
- zoomSpeed: config?.zoomSpeed ?? 0.1,
141
- minDomainMs: config?.minDomainMs ?? 0,
142
- maxDomainMs: config?.maxDomainMs ?? 365 * 24 * 60 * 60 * 1e3
143
- };
144
- this._state = {
145
- domain: [...initialDomain],
146
- originalDomain: [...initialDomain],
147
- scale: 1,
148
- offset: 0
149
- };
150
- }
151
- get state() {
152
- return { ...this._state, domain: [...this._state.domain] };
153
- }
154
- applyZoom(x, delta, rangeWidth) {
155
- if (!this._config.enabled) return;
156
- const factor = 1 + Math.sign(delta) * this._config.zoomSpeed;
157
- if (factor <= 0) return;
158
- const [d0, d1] = this._state.domain;
159
- const span = d1 - d0;
160
- const ratio = x / rangeWidth;
161
- let newSpan = span / factor;
162
- const minSpan = this._config.minDomainMs ?? 0;
163
- const maxSpan = this._config.maxDomainMs ?? Infinity;
164
- if (newSpan < minSpan) newSpan = minSpan;
165
- if (newSpan > maxSpan) newSpan = maxSpan;
166
- const focalPoint = d0 + span * ratio;
167
- let newD0 = focalPoint - newSpan * ratio;
168
- let newD1 = focalPoint + newSpan * (1 - ratio);
169
- const [orig0, orig1] = this._state.originalDomain;
170
- if (newD1 - newD0 > orig1 - orig0) {
171
- newD0 = orig0;
172
- newD1 = orig1;
173
- newSpan = orig1 - orig0;
174
- } else {
175
- if (newD0 < orig0) {
176
- newD1 = orig1 - (orig1 - orig0) * ((newD1 - newD0) / (orig1 - orig0));
177
- newD0 = orig0;
178
- }
179
- if (newD1 > orig1) {
180
- newD0 = orig0 + (orig1 - orig0) * ((newD0 - orig0) / (orig1 - orig0));
181
- newD1 = orig1;
182
- }
183
- }
184
- this._state.domain = [newD0, newD1];
185
- this._state.scale = (d1 - d0) / newSpan;
186
- }
187
- applyPan(pixelDelta, rangeWidth) {
188
- if (!this._config.enabled) return;
189
- const [d0, d1] = this._state.domain;
190
- const span = d1 - d0;
191
- const [orig0, orig1] = this._state.originalDomain;
192
- let shift = -(pixelDelta / rangeWidth) * span;
193
- let newD0 = d0 + shift;
194
- let newD1 = d1 + shift;
195
- if (newD0 < orig0) {
196
- shift -= newD0 - orig0;
197
- }
198
- if (newD1 > orig1) {
199
- shift -= newD1 - orig1;
200
- }
201
- this._state.domain = [d0 + shift, d1 + shift];
202
- }
203
- reset() {
204
- this._state.domain = [...this._state.originalDomain];
205
- this._state.scale = 1;
206
- this._state.offset = 0;
207
- }
208
- get enabled() {
209
- return this._config.enabled ?? true;
210
- }
211
- };
212
-
213
- // src/theme/defaults.ts
214
- var theme = {
215
- // ── Tooltip ──
216
- /** Tooltip box background */
217
- tooltipBg: "#fff",
218
- /** Tooltip border */
219
- tooltipBorder: "#cbd5e1",
220
- /** Tooltip text color */
221
- tooltipText: "#1e293b",
222
- /** Tooltip snap radius in pixels */
223
- tooltipSnapRadius: 20,
224
- // ── Minimap ──
225
- /** Minimap overview line stroke */
226
- minimapStroke: "#94a3b8",
227
- /** Minimap background */
228
- minimapBg: "#f8f9fa",
229
- /** Minimap brush (viewport) fill */
230
- minimapBrush: "#3b82f644"};
231
-
232
- // src/interaction/minimap.ts
233
- var Minimap = class {
234
- _data;
235
- _width;
236
- _height;
237
- _x;
238
- _y;
239
- _zoom;
240
- _stroke;
241
- _bgColor;
242
- _brushColor;
243
- constructor(config) {
244
- this._data = config.data;
245
- this._width = config.width;
246
- this._height = config.height;
247
- this._x = config.x;
248
- this._y = config.y;
249
- this._zoom = config.zoom;
250
- this._stroke = config.stroke ?? theme.minimapStroke;
251
- this._bgColor = config.bgColor ?? theme.minimapBg;
252
- this._brushColor = config.brushColor ?? theme.minimapBrush;
253
- }
254
- /** Render minimap as draw commands */
255
- render() {
256
- if (this._data.length === 0) return [];
257
- const commands = [];
258
- const times = this._data.map((d) => d.time);
259
- const values = this._data.map((d) => d.value).filter((v) => v !== null);
260
- const timeDomain = [Math.min(...times), Math.max(...times)];
261
- const valueDomain = [Math.min(...values), Math.max(...values)];
262
- const timeScale = new TimeScale({
263
- domain: timeDomain,
264
- range: [0, this._width]
265
- });
266
- const valueScale = new LinearScale({
267
- domain: valueDomain,
268
- range: [this._height, 0]
269
- });
270
- commands.push({
271
- type: "rect",
272
- x: this._x,
273
- y: this._y,
274
- w: this._width,
275
- h: this._height,
276
- fill: this._bgColor
277
- });
278
- const points = this._data.map((d) => ({
279
- x: this._x + timeScale.map(d.time),
280
- y: this._y + valueScale.map(d.value)
281
- }));
282
- commands.push({
283
- type: "path",
284
- points,
285
- smoothing: false,
286
- stroke: this._stroke,
287
- strokeWidth: 1
288
- });
289
- if (this._zoom) {
290
- const zoomState = this._zoom.state;
291
- const brushX0 = this._x + timeScale.map(zoomState.domain[0]);
292
- const brushX1 = this._x + timeScale.map(zoomState.domain[1]);
293
- const brushW = Math.max(2, brushX1 - brushX0);
294
- commands.push({
295
- type: "rect",
296
- x: brushX0,
297
- y: this._y,
298
- w: brushW,
299
- h: this._height,
300
- fill: this._brushColor
301
- });
302
- }
303
- return commands;
304
- }
305
- /** Convert minimap pixel X to time value (for click-to-navigate) */
306
- navigateTo(pixelX) {
307
- const times = this._data.map((d) => d.time);
308
- const timeDomain = [Math.min(...times), Math.max(...times)];
309
- const timeScale = new TimeScale({ domain: timeDomain, range: [0, this._width] });
310
- const localX = pixelX - this._x;
311
- return timeScale.invert(localX);
312
- }
313
- };
314
-
315
- // src/interaction/tooltip.ts
316
- var Tooltip = class {
317
- _mouseX;
318
- _mouseY;
319
- _timeScale;
320
- _valueScale;
321
- _data;
322
- _xRange;
323
- _yRange;
324
- _snapRadius;
325
- _bgColor;
326
- _borderColor;
327
- _textColor;
328
- constructor(config) {
329
- this._mouseX = config.mouseX;
330
- this._mouseY = config.mouseY;
331
- this._timeScale = config.timeScale;
332
- this._valueScale = config.valueScale;
333
- this._data = config.data;
334
- this._xRange = config.xRange;
335
- this._yRange = config.yRange;
336
- this._snapRadius = config.snapRadius ?? theme.tooltipSnapRadius;
337
- this._bgColor = config.bgColor ?? theme.tooltipBg;
338
- this._borderColor = config.borderColor ?? theme.tooltipBorder;
339
- this._textColor = config.textColor ?? theme.tooltipText;
340
- }
341
- /** Compute tooltip visibility and render commands */
342
- compute() {
343
- this._timeScale.invert(this._mouseX);
344
- const sorted = [...this._data].filter((d) => d.value !== null).sort((a, b) => a.time - b.time);
345
- let closest;
346
- let closestDist = Infinity;
347
- for (const dp of sorted) {
348
- const px = this._timeScale.map(dp.time);
349
- const dist = Math.abs(this._mouseX - px);
350
- if (dist < closestDist) {
351
- closestDist = dist;
352
- closest = dp;
353
- }
354
- }
355
- if (!closest || closestDist > this._snapRadius) {
356
- return { visible: false, commands: [] };
357
- }
358
- const snapX = this._timeScale.map(closest.time);
359
- const snapY = this._valueScale.map(closest.value);
360
- const commands = [];
361
- commands.push({
362
- type: "line",
363
- x1: snapX,
364
- y1: this._yRange[0],
365
- x2: snapX,
366
- y2: this._yRange[1],
367
- stroke: "#94a3b8",
368
- strokeWidth: 1
369
- });
370
- commands.push({
371
- type: "line",
372
- x1: this._xRange[0],
373
- y1: snapY,
374
- x2: this._xRange[1],
375
- y2: snapY,
376
- stroke: "#94a3b8",
377
- strokeWidth: 1
378
- });
379
- commands.push({
380
- type: "circle",
381
- cx: snapX,
382
- cy: snapY,
383
- r: 5,
384
- fill: "#3b82f6"
385
- });
386
- const timeLabel = new Date(closest.time).toLocaleString();
387
- const valueLabel = closest.value.toFixed(2);
388
- const boxW = 120;
389
- const boxH = 44;
390
- let boxX = snapX + 12;
391
- let boxY = snapY - boxH - 4;
392
- if (boxX + boxW > this._xRange[1]) {
393
- boxX = snapX - boxW - 12;
394
- }
395
- if (boxY < this._yRange[0]) {
396
- boxY = snapY + 12;
397
- }
398
- commands.push({
399
- type: "rect",
400
- x: boxX,
401
- y: boxY,
402
- w: boxW,
403
- h: boxH,
404
- fill: this._bgColor,
405
- stroke: this._borderColor,
406
- strokeWidth: 1
407
- });
408
- commands.push({
409
- type: "text",
410
- content: timeLabel,
411
- x: boxX + 8,
412
- y: boxY + 16,
413
- fontSize: 10,
414
- fill: this._textColor
415
- });
416
- commands.push({
417
- type: "text",
418
- content: `Value: ${valueLabel}`,
419
- x: boxX + 8,
420
- y: boxY + 32,
421
- fontSize: 11,
422
- fill: "#3b82f6"
423
- });
424
- return {
425
- visible: true,
426
- commands,
427
- dataPoint: closest,
428
- snapX
429
- };
430
- }
431
- };
432
- /*!
1
+ var f=class{#t;#e;constructor(t){this.#t=[...t.domain],this.#e=[...t.range];}map(t){let n=Number(t),[o,i]=this.#t,[a,r]=this.#e;return i===o?a:a+(n-o)/(i-o)*(r-a)}invert(t){let[n,o]=this.#t,[i,a]=this.#e;return a===i?n:n+(t-i)/(a-i)*(o-n)}domain(){return [...this.#t]}range(){return [...this.#e]}},_=[{label:"second",ms:1e3},{label:"2_seconds",ms:2e3},{label:"5_seconds",ms:5e3},{label:"10_seconds",ms:1e4},{label:"30_seconds",ms:3e4},{label:"minute",ms:6e4},{label:"5_minutes",ms:3e5},{label:"15_minutes",ms:9e5},{label:"30_minutes",ms:18e5},{label:"hour",ms:36e5},{label:"3_hours",ms:108e5},{label:"6_hours",ms:216e5},{label:"day",ms:864e5},{label:"week",ms:6048e5},{label:"month",ms:2592e6},{label:"3_months",ms:7776e6},{label:"6_months",ms:15552e6},{label:"year",ms:31536e6},{label:"2_years",ms:63072e6},{label:"5_years",ms:15768e7}],y=class{#t;#e;constructor(t){this.#t=new f({domain:t.domain,range:t.range}),this.#e=t.locale||(typeof navigator<"u"?navigator.language:"en-US");}map(t){return this.#t.map(Number(t))}invert(t){return this.#t.invert(t)}domain(){return this.#t.domain()}range(){return this.#t.range()}get locale(){return this.#e}tickInterval(t,n=3,o=12){let[i,a]=this.#t.domain(),r=a-i;if(r<=0)return {interval:_[0].ms};let s=r/t,m=_[0].ms;for(let u of _)if(u.ms>=s){m=u.ms;break}let e=m,l=Math.round(r/e);for(;l>o&&e<_[_.length-1].ms;){let u=_.findIndex(d=>d.ms===e);e=_[Math.min(u+1,_.length-1)].ms,l=Math.round(r/e);}for(;l<n&&e>_[0].ms;){let u=_.findIndex(d=>d.ms===e);e=_[Math.max(u-1,0)].ms,l=Math.round(r/e);}return {interval:e}}ticks(t){let n=t?.minTicks??5,o=t?.maxTicks??12,{interval:i}=this.tickInterval((n+o)/2,n,o),[a,r]=this.#t.domain(),s=[],m=Math.ceil(a/i)*i;for(let e=m;e<=r;e+=i)s.push(e);return s}format(t,n){return new Intl.DateTimeFormat(this.#e,n).format(new Date(t))}};var S=class{_config;_state;constructor(t,n){this._config={enabled:n?.enabled??true,zoomSpeed:n?.zoomSpeed??.1,minDomainMs:n?.minDomainMs??0,maxDomainMs:n?.maxDomainMs??365*24*60*60*1e3},this._state={domain:[...t],originalDomain:[...t],scale:1,offset:0};}get state(){return {...this._state,domain:[...this._state.domain]}}applyZoom(t,n,o){if(!this._config.enabled)return;let i=1+Math.sign(n)*this._config.zoomSpeed;if(i<=0)return;let[a,r]=this._state.domain,s=r-a,m=t/o,e=s/i,l=this._config.minDomainMs??0,u=this._config.maxDomainMs??1/0;e<l&&(e=l),e>u&&(e=u);let d=a+s*m,b=d-e*m,p=d+e*(1-m),[h,c]=this._state.originalDomain;p-b>c-h?(b=h,p=c,e=c-h):(b<h&&(p=c-(c-h)*((p-b)/(c-h)),b=h),p>c&&(b=h+(c-h)*((b-h)/(c-h)),p=c)),this._state.domain=[b,p],this._state.scale=(r-a)/e;}applyPan(t,n){if(!this._config.enabled)return;let[o,i]=this._state.domain,a=i-o,[r,s]=this._state.originalDomain,m=-(t/n)*a,e=o+m,l=i+m;e<r&&(m-=e-r),l>s&&(m-=l-s),this._state.domain=[o+m,i+m];}reset(){this._state.domain=[...this._state.originalDomain],this._state.scale=1,this._state.offset=0;}get enabled(){return this._config.enabled??true}};var g={tooltipBg:"#fff",tooltipBorder:"#cbd5e1",tooltipText:"#1e293b",tooltipSnapRadius:20,minimapStroke:"#94a3b8",minimapBg:"#f8f9fa",minimapBrush:"#3b82f644"};var C=class{_data;_width;_height;_x;_y;_zoom;_stroke;_bgColor;_brushColor;constructor(t){this._data=t.data,this._width=t.width,this._height=t.height,this._x=t.x,this._y=t.y,this._zoom=t.zoom,this._stroke=t.stroke??g.minimapStroke,this._bgColor=t.bgColor??g.minimapBg,this._brushColor=t.brushColor??g.minimapBrush;}render(){if(this._data.length===0)return [];let t=[],n=this._data.map(e=>e.time),o=this._data.map(e=>e.value).filter(e=>e!==null),i=[Math.min(...n),Math.max(...n)],a=[Math.min(...o),Math.max(...o)],r=new y({domain:i,range:[0,this._width]}),s=new f({domain:a,range:[this._height,0]});t.push({type:"rect",x:this._x,y:this._y,w:this._width,h:this._height,fill:this._bgColor});let m=this._data.map(e=>({x:this._x+r.map(e.time),y:this._y+s.map(e.value)}));if(t.push({type:"path",points:m,smoothing:false,stroke:this._stroke,strokeWidth:1}),this._zoom){let e=this._zoom.state,l=this._x+r.map(e.domain[0]),u=this._x+r.map(e.domain[1]),d=Math.max(2,u-l);t.push({type:"rect",x:l,y:this._y,w:d,h:this._height,fill:this._brushColor});}return t}navigateTo(t){let n=this._data.map(r=>r.time),o=[Math.min(...n),Math.max(...n)],i=new y({domain:o,range:[0,this._width]}),a=t-this._x;return i.invert(a)}};var v=class{_mouseX;_mouseY;_timeScale;_valueScale;_data;_xRange;_yRange;_snapRadius;_bgColor;_borderColor;_textColor;constructor(t){this._mouseX=t.mouseX,this._mouseY=t.mouseY,this._timeScale=t.timeScale,this._valueScale=t.valueScale,this._data=t.data,this._xRange=t.xRange,this._yRange=t.yRange,this._snapRadius=t.snapRadius??g.tooltipSnapRadius,this._bgColor=t.bgColor??g.tooltipBg,this._borderColor=t.borderColor??g.tooltipBorder,this._textColor=t.textColor??g.tooltipText;}compute(){this._timeScale.invert(this._mouseX);let n=[...this._data].filter(p=>p.value!==null).sort((p,h)=>p.time-h.time),o,i=1/0;for(let p of n){let h=this._timeScale.map(p.time),c=Math.abs(this._mouseX-h);c<i&&(i=c,o=p);}if(!o||i>this._snapRadius)return {visible:false,commands:[]};let a=this._timeScale.map(o.time),r=this._valueScale.map(o.value),s=[];s.push({type:"line",x1:a,y1:this._yRange[0],x2:a,y2:this._yRange[1],stroke:"#94a3b8",strokeWidth:1}),s.push({type:"line",x1:this._xRange[0],y1:r,x2:this._xRange[1],y2:r,stroke:"#94a3b8",strokeWidth:1}),s.push({type:"circle",cx:a,cy:r,r:5,fill:"#3b82f6"});let m=new Date(o.time).toLocaleString(),e=o.value.toFixed(2),l=120,u=44,d=a+12,b=r-u-4;return d+l>this._xRange[1]&&(d=a-l-12),b<this._yRange[0]&&(b=r+12),s.push({type:"rect",x:d,y:b,w:l,h:u,fill:this._bgColor,stroke:this._borderColor,strokeWidth:1}),s.push({type:"text",content:m,x:d+8,y:b+16,fontSize:10,fill:this._textColor}),s.push({type:"text",content:`Value: ${e}`,x:d+8,y:b+32,fontSize:11,fill:"#3b82f6"}),{visible:true,commands:s,dataPoint:o,snapX:a}}};/*!
433
2
  * MLTimeGraph — Copyright (c) 2026 Michael Lechner
434
3
  * MIT with Attribution: free use incl. commercial requires visible credit to
435
4
  * "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
436
- */
437
-
438
- export { Minimap, Tooltip, Zoom };
5
+ */export{C as Minimap,v as Tooltip,S as Zoom};
@@ -1,7 +1,7 @@
1
- import { M as Marker } from './layout-Sc5UkC0r.js';
2
- export { L as Layout, a as LayoutConfig, b as LayoutResult, c as LegendConfig, d as LegendItem, e as LegendOrientation, f as Renderer, m as measureLegend, r as renderLegend, t as theme } from './layout-Sc5UkC0r.js';
3
- import { A as AggregatedPoint, ae as TimeScale, W as LinearScale, $ as PointStyleType, p as DrawCommand, l as DataPoint, ab as Threshold, J as Gap, P as HatchVariant, Q as Highlight, e as Annotation, E as EnumMap, B as BandScale, _ as Point, g as AnnotationBandItem, V as LineVariant, H as FillSpec, N as GapStyle, ag as TimeSeries } from './scale-Cbr0KpPz.js';
4
- export { i as AxisOrientation, j as AxisPosition, k as BandScaleConfig, C as CircleParams, D as Dashstyle_t, n as DomainScaleConfig, o as DrawCircle, q as DrawGap, r as DrawGapType_t, s as DrawGradient, t as DrawGroup, u as DrawLine, v as DrawPath, w as DrawRect, x as DrawText, R as LabelAnchor, T as LineParams, X as LinearScaleConfig, Z as PathParams, a0 as RectParams, a1 as Scale, a2 as ScaleConfig, a9 as TIME_INTERVALS, aa as TextParams, af as TimeScaleConfig, ah as getHatch } from './scale-Cbr0KpPz.js';
1
+ import { M as Marker } from './layout-BOYtrsZa.js';
2
+ export { L as Layout, a as LayoutConfig, b as LayoutResult, c as LegendConfig, d as LegendItem, e as LegendOrientation, f as Renderer, m as measureLegend, r as renderLegend, t as theme } from './layout-BOYtrsZa.js';
3
+ import { A as AggregatedPoint, ad as TimeScale, V as LinearScale, _ as PointStyleType, o as DrawCommand, k as DataPoint, aa as Threshold, I as Gap, O as HatchVariant, P as Highlight, d as Annotation, E as EnumMap, B as BandScale, Z as Point, f as AnnotationBandItem, U as LineVariant, G as FillSpec, M as GapStyle, af as TimeSeries } from './scale-BRE_QhbZ.js';
4
+ export { h as AxisOrientation, i as AxisPosition, j as BandScaleConfig, C as CircleParams, D as Dashstyle_t, m as DomainScaleConfig, n as DrawCircle, p as DrawGap, q as DrawGapType_t, r as DrawGradient, s as DrawGroup, t as DrawLine, u as DrawPath, v as DrawRect, w as DrawText, Q as LabelAnchor, S as LineParams, W as LinearScaleConfig, Y as PathParams, $ as RectParams, a0 as Scale, a1 as ScaleConfig, a8 as TIME_INTERVALS, a9 as TextParams, ae as TimeScaleConfig, ag as getHatch } from './scale-BRE_QhbZ.js';
5
5
 
6
6
  /*!
7
7
  * MLTimeGraph — Copyright (c) 2026 Michael Lechner
@@ -129,7 +129,7 @@ interface ThresholdRenderConfig {
129
129
  /** Pixel X range of the chart area. */
130
130
  xRange: [number, number];
131
131
  }
132
- /** Render named thresholds as horizontal lines, half-plane fills, and labels. */
132
+ /** Flat-list variant: lines / fills / labels in one array (legacy callers). */
133
133
  declare function renderThresholds(config: ThresholdRenderConfig): DrawCommand[];
134
134
 
135
135
  /*!
@@ -229,6 +229,12 @@ interface AnnotationRenderConfig {
229
229
  /**
230
230
  * Render free-form annotations (arrow, line, rect, point, label) given in
231
231
  * data coordinates by projecting each point to pixels via the chart's scales.
232
+ *
233
+ * Each annotation that has an `id` is wrapped in a `<g class="annotation
234
+ * annotation--{slug}">` group, so external code (toggle panels, custom
235
+ * legends, CSS) can target it by class. The chart container's own id
236
+ * scopes the selector (`#chart-3 .annotation--door-defekt`) — that way the
237
+ * same annotation can appear across multiple charts without id collisions.
232
238
  */
233
239
  declare function renderAnnotations(config: AnnotationRenderConfig): DrawCommand[];
234
240
 
@@ -347,6 +353,15 @@ interface ValueAxisConfig {
347
353
  /** Position for vertical orientation */
348
354
  position?: "left" | "right";
349
355
  colors?: AxisColorspec;
356
+ /**
357
+ * Pixel positions (Y for vertical, X for horizontal) where a tick LABEL
358
+ * should be suppressed. Used to avoid colliding with threshold gutter
359
+ * labels (e.g. "Min 2,0 °C") that already sit at the same Y as a
360
+ * tick would. The tick MARK itself is kept; only the text is dropped.
361
+ */
362
+ suppressLabelsNear?: number[];
363
+ /** Pixel tolerance for `suppressLabelsNear`. Default 8. */
364
+ suppressTolerancePx?: number;
350
365
  }
351
366
  /** Tick information for value axis with computed positions and formatted labels. */
352
367
  interface ValueTickInfo {