ml-time-graph 1.1.1 → 1.2.0
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/README.md +2 -2
- package/USAGE.md +44 -2
- package/dist/analyze/index.d.ts +15 -1
- package/dist/analyze/index.js +2 -2
- package/dist/index.d.ts +63 -5
- package/dist/index.js +20 -20
- package/dist/interaction/index.d.ts +1 -1
- package/dist/internals.d.ts +7 -7
- package/dist/internals.js +4 -4
- package/dist/{layout-DDdMtPrB.d.ts → layout-C_t250fG.d.ts} +5 -5
- package/dist/{scale-DcFBNLdU.d.ts → scale-DFyECKZq.d.ts} +46 -46
- package/docs/MKT_AGGREGATE.md +66 -68
- package/package.json +65 -65
package/README.md
CHANGED
|
@@ -86,8 +86,8 @@ Need server-side rendering of the exact same charts? There is a 1:1 Go port of t
|
|
|
86
86
|
|
|
87
87
|
Both the TypeScript and Go libraries:
|
|
88
88
|
- Process the **exact same JSON configuration schema**.
|
|
89
|
-
-
|
|
90
|
-
-
|
|
89
|
+
- Support **multiple stacked Y-axes** on both left and right sides (with configurable pixel `offset` and automatic step offsets).
|
|
90
|
+
- Ensure the **time axis baseline spans the entire plot area** with exact parity between TypeScript and Go.
|
|
91
91
|
- Are continuously tested for rendering parity using shared test fixtures.
|
|
92
92
|
|
|
93
93
|
---
|
package/USAGE.md
CHANGED
|
@@ -98,7 +98,7 @@ underneath, add `markers` for points, set `style.line: false` for points only.
|
|
|
98
98
|
'dense-dash' | 'dash-dot' | 'dash-dot-dot' | 'loose-dash'`.
|
|
99
99
|
|
|
100
100
|
A point with `value: null` (or a slot with `min/max/avg: null`) marks a **gap** — the
|
|
101
|
-
line breaks there.
|
|
101
|
+
line breaks there. Multiple y-axes are supported via `yAxisIndex: 0 | 1 | 2 | ...` on the series.
|
|
102
102
|
|
|
103
103
|
## Thresholds (incident analysis)
|
|
104
104
|
|
|
@@ -187,7 +187,7 @@ new MLTimeGraph({
|
|
|
187
187
|
label: 'Time',
|
|
188
188
|
domain: 'auto', // or [tMin, tMax]
|
|
189
189
|
format: (d) => d.toISOString().slice(0, 10),
|
|
190
|
-
axis: { color: '#7c3aed' }, // baseline + ticks
|
|
190
|
+
axis: { color: '#7c3aed' }, // baseline + ticks (spans full chart width)
|
|
191
191
|
},
|
|
192
192
|
left: {
|
|
193
193
|
label: 'Temperature (°C)',
|
|
@@ -202,6 +202,48 @@ new MLTimeGraph({
|
|
|
202
202
|
});
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
+
### Multi-Axis Layout (N Stacked Y-Axes)
|
|
206
|
+
|
|
207
|
+
To support 3 or more vertical axes (or arbitrary left/right positioning), define `axes.y: YAxisConfig[]` and assign series using `yAxisIndex`:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
new MLTimeGraph({
|
|
211
|
+
margin: { top: 30, right: 180, bottom: 50, left: 100 },
|
|
212
|
+
series: [
|
|
213
|
+
{ name: 'RPM', yAxisIndex: 0, data: rpmData },
|
|
214
|
+
{ name: 'Temp', yAxisIndex: 1, data: tempData },
|
|
215
|
+
{ name: 'Vibration', yAxisIndex: 2, data: vibData },
|
|
216
|
+
],
|
|
217
|
+
axes: {
|
|
218
|
+
x: { label: 'Time of Day' },
|
|
219
|
+
y: [
|
|
220
|
+
{ position: 'left', label: 'Spindle RPM' },
|
|
221
|
+
{ position: 'right', offset: 0, label: 'Temp (°C)' },
|
|
222
|
+
{ position: 'right', offset: 60, label: 'Vibration (mm/s)' }, // explicit 60px offset
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
- **`position: 'left' | 'right'`**: Selects which side of the plot area the axis is anchored to.
|
|
229
|
+
- **`offset?: number`**: Sets an explicit pixel offset from the chart boundary. If omitted, sequential axes step outwards by 50px automatically.
|
|
230
|
+
- **Full Baseline Range**: The horizontal time-axis baseline always spans the complete chart plot area (`chartX` to `chartX + chartWidth`), even if ticks do not extend to the boundary.
|
|
231
|
+
|
|
232
|
+
### Coordinate Projections & Inversion
|
|
233
|
+
|
|
234
|
+
`MLTimeGraph` provides mathematical projection methods for building interactive tools (tooltips, scrubbers, crosshairs, zoom windows):
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
chart.renderCommands(); // initializes scale mappings
|
|
238
|
+
|
|
239
|
+
// Data -> Pixel (with yAxisIndex)
|
|
240
|
+
const { x, y } = chart.project(timestampMs, value, yAxisIndex);
|
|
241
|
+
|
|
242
|
+
// Pixel -> Data
|
|
243
|
+
const time = chart.invertTime(pixelX);
|
|
244
|
+
const val = chart.invertValue(pixelY, yAxisIndex);
|
|
245
|
+
```
|
|
246
|
+
|
|
205
247
|
## Localization (i18n)
|
|
206
248
|
|
|
207
249
|
The time axis is **locale-aware**: tick labels are formatted with
|
package/dist/analyze/index.d.ts
CHANGED
|
@@ -147,7 +147,7 @@ declare function aggregateBySlot(data: DataPoint[], mode?: "hourly" | "daily" |
|
|
|
147
147
|
declare function createAggr(time: number, values: number[]): AggregatedPoint;
|
|
148
148
|
/**
|
|
149
149
|
* Detect gaps in time-series data (autoDetect).
|
|
150
|
-
*
|
|
150
|
+
* Returns all time gaps where the interval is > minGapMs.
|
|
151
151
|
*/
|
|
152
152
|
declare function detectGaps(data: DataPoint[], minGapMs?: number): DetectedGap[];
|
|
153
153
|
interface LongTermInsight {
|
|
@@ -350,6 +350,13 @@ interface NamedSeries {
|
|
|
350
350
|
/** Time-ordered samples. `value: null` is treated as a gap and ignored. */
|
|
351
351
|
data: DataPoint[];
|
|
352
352
|
}
|
|
353
|
+
|
|
354
|
+
/*!
|
|
355
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
356
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
357
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
358
|
+
*/
|
|
359
|
+
|
|
353
360
|
/**
|
|
354
361
|
* Per-timestamp summary of a multi-sensor recording.
|
|
355
362
|
* `delta = max - min` is the room's "spatial spread" at that instant.
|
|
@@ -382,6 +389,13 @@ interface SpatialPoint {
|
|
|
382
389
|
* silently skipped for that point.
|
|
383
390
|
*/
|
|
384
391
|
declare function spatialDelta(sensors: NamedSeries[]): SpatialPoint[];
|
|
392
|
+
|
|
393
|
+
/*!
|
|
394
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
395
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
396
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
397
|
+
*/
|
|
398
|
+
|
|
385
399
|
/** Aggregate statistics for one sensor across the full observation window. */
|
|
386
400
|
interface SensorStat {
|
|
387
401
|
name: string;
|
package/dist/analyze/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var H=class{static interpolateDataPoint(n,i,t){return {time:n.time+t*(i.time-n.time),value:(n.value??0)+t*((i.value??0)-(n.value??0))}}static interpolateAggregatedPoint(n,i,t){let u=(e,l)=>e!==null&&l!==null?e+t*(l-e):null;return {time:n.time+t*(i.time-n.time),min:u(n.min,i.min),max:u(n.max,i.max),avg:u(n.avg,i.avg),count:Math.round(n.count+t*(i.count-n.count))}}static getRuns(n,i,t=0){let u=[...n].sort((r,o)=>r.time-o.time),e=[],l=[],a=null;for(let r of u){let o=i(r),m=t>0&&a&&r.time-a.time>t;(o||m)&&l.length&&(e.push(l),l=[]),o||l.push(r),a=r;}return l.length&&e.push(l),e}static splitByBoundaries(n,i,t,u){if(n.length===0)return [];if(i.length===0)return [{data:n,zoneIndex:0}];let e=[...i].sort((o,m)=>o-m),l=[],a=o=>{let m=0;for(let s=0;s<e.length&&o>=e[s];s++)m=s+1;return m},r=[n[0]];for(let o=1;o<n.length;o++){let m=n[o-1],s=n[o],h=t(m),g=t(s),d;g>h?d=e.filter(c=>c>h&&c<=g):g<h?d=e.filter(c=>c>=g&&c<h).reverse():d=[];for(let c of d){let p=(c-h)/(g-h),x=u(m,s,p);r.push(x),l.push({data:r,zoneIndex:a((h+c)/2)}),r=[x];}r.push(s);}if(r.length>0){let o=t(r[0]),m=t(r[r.length-1]);l.push({data:r,zoneIndex:a((o+m)/2)});}return l}static splitByThreshold(n,i,t,u){let e=this.splitByBoundaries(n,[i],t,u),l={above:[],below:[]};for(let a of e)a.zoneIndex===0?l.below.push(a.data):l.above.push(a.data);return l}},
|
|
1
|
+
var H=class{static interpolateDataPoint(n,i,t){return {time:n.time+t*(i.time-n.time),value:(n.value??0)+t*((i.value??0)-(n.value??0))}}static interpolateAggregatedPoint(n,i,t){let u=(e,l)=>e!==null&&l!==null?e+t*(l-e):null;return {time:n.time+t*(i.time-n.time),min:u(n.min,i.min),max:u(n.max,i.max),avg:u(n.avg,i.avg),count:Math.round(n.count+t*(i.count-n.count))}}static getRuns(n,i,t=0){let u=[...n].sort((r,o)=>r.time-o.time),e=[],l=[],a=null;for(let r of u){let o=i(r),m=t>0&&a&&r.time-a.time>t;(o||m)&&l.length&&(e.push(l),l=[]),o||l.push(r),a=r;}return l.length&&e.push(l),e}static splitByBoundaries(n,i,t,u){if(n.length===0)return [];if(i.length===0)return [{data:n,zoneIndex:0}];let e=[...i].sort((o,m)=>o-m),l=[],a=o=>{let m=0;for(let s=0;s<e.length&&o>=e[s];s++)m=s+1;return m},r=[n[0]];for(let o=1;o<n.length;o++){let m=n[o-1],s=n[o],h=t(m),g=t(s),d;g>h?d=e.filter(c=>c>h&&c<=g):g<h?d=e.filter(c=>c>=g&&c<h).reverse():d=[];for(let c of d){let p=(c-h)/(g-h),x=u(m,s,p);r.push(x),l.push({data:r,zoneIndex:a((h+c)/2)}),r=[x];}r.push(s);}if(r.length>0){let o=t(r[0]),m=t(r[r.length-1]);l.push({data:r,zoneIndex:a((o+m)/2)});}return l}static splitByThreshold(n,i,t,u){let e=this.splitByBoundaries(n,[i],t,u),l={above:[],below:[]};for(let a of e)a.zoneIndex===0?l.below.push(a.data):l.above.push(a.data);return l}},S={pharma_cold:{limitLow:2,limitHigh:8,activationEnergy:83144},pharma_ambient:{limitLow:15,limitHigh:25,activationEnergy:83144},blood:{limitLow:2,limitHigh:6,activationEnergy:83144},food_chilled:{limitLow:0,limitHigh:4},frozen:{limitLow:-40,limitHigh:-18}},T=8.314462618,w=273.15;function y(n,i,t,u=1){let e=i.filter(f=>f.value!==null&&f.value!==void 0&&!isNaN(f.value)).map(f=>f.value);if(!e.length)return {time:n,min:null,max:null,avg:null,mkt:null,deltaMkt:null,stdDev:null,minutesAboveHigh:t?0:null,minutesBelowLow:t?0:null,count:0};let l=Math.min(...e),a=Math.max(...e),r=e.reduce((f,v)=>f+v,0)/e.length,o=t?0:null,m=t?0:null;if(t)for(let f=0;f<i.length;f++){let v=i[f];if(v.value!==null&&v.value!==void 0){let b=i[f+1],M=(b?b.time-v.time:0)/(1e3*60);v.value>t.limitHigh&&(o+=M),v.value<t.limitLow&&(m+=M);}}let s=0,h=0,g=(t?.activationEnergy??83144)/T;for(let f of e){s+=Math.pow(f-r,2);let v=f+w;h+=Math.exp(-g/v);}let d=s/e.length,c=Math.sqrt(d),p=null,x=null;if(e.length>=u){let f=h/e.length,v=g/-Math.log(f);p=Number((v-w).toFixed(2)),x=Number((p-r).toFixed(2));}return {time:n,min:Number(l.toFixed(2)),max:Number(a.toFixed(2)),avg:Number(r.toFixed(2)),mkt:p,deltaMkt:x,stdDev:Number(c.toFixed(2)),minutesAboveHigh:o!==null?Number(o.toFixed(1)):null,minutesBelowLow:m!==null?Number(m.toFixed(1)):null,count:e.length}}function D(n,i="hourly",t,u,e=1){if(!n.length)return [];let l=i==="hourly"?36e5:i==="daily"?864e5:t??3600*1e3,a=[...n].sort((s,h)=>s.time-h.time),r=[],o=a[0].time,m=[];for(let s of a){for(;s.time-o>=l;)r.push(y(o,m,u,e)),o+=l,m=[];m.push(s);}return r.push(y(o,m,u,e)),r}function E(n,i){let t=Math.min(...i),u=Math.max(...i),e=i.reduce((l,a)=>l+a,0)/i.length;return {time:n,min:t,max:u,avg:e,count:i.length}}function B(n,i=6e4){if(n.length<2)return [];let t=[...n].sort((e,l)=>e.time-l.time),u=[];for(let e=1;e<t.length;e++)t[e].time-t[e-1].time>i&&u.push({startTime:t[e-1].time,endTime:t[e].time});return u}function z(n){let i=[],t=0,u=0,e=0,l=0;for(let a of n)a.count>0&&(e++,a.minutesAboveHigh&&(t+=a.minutesAboveHigh),a.stdDev&&a.stdDev>u&&(u=a.stdDev),a.deltaMkt&&a.deltaMkt>2&&l++);return e===0?[]:(t>120&&i.push({type:"critical",message:`Kritische Gesamtbelastung: Das Produkt war im gesamten Zeitraum insgesamt ${Math.round(t)} Minuten zu warm.`,metric:"Total Excursion Time"}),l>e*.15&&i.push({type:"warning",message:"Frequent thermal shocks detected. The kinetic temperature deviates strongly from the average (possible regular door openings).",metric:"Delta MKT Instability"}),u>4&&i.push({type:"warning",message:`High instability measured. Maximum standard deviation was ${u}\xB0C. The cooling system controls imprecisely.`,metric:"Standard Deviation Peak"}),i)}function I(n,i){if(n.length<=i)return n;let t=[],u=Math.ceil(n.length/i);t.push(n[0]);for(let e=1;e<n.length;e+=u)t.push(n[Math.min(e,n.length-1)]);return t}function C(n,i="hourly",t){let u={limitLow:t.low,limitHigh:t.high,activationEnergy:t.activationEnergy};return D(n,i,t.interval,u,t.minCountForMkt??1)}var P=class{static compute(n){let i=n.map(r=>r.value).filter(r=>r!==null).sort((r,o)=>r-o);if(i.length===0)return {min:NaN,max:NaN,avg:NaN,mean:NaN,median:NaN,stdDev:NaN,count:0};let t=i.length,u=i.reduce((r,o)=>r+o,0)/t,e=t%2===1?i[Math.floor(t/2)]:(i[t/2-1]+i[t/2])/2,l=i.reduce((r,o)=>r+Math.pow(o-u,2),0)/t,a=Math.sqrt(l);return {min:i[0],max:i[t-1],avg:u,mean:u,median:e,stdDev:a,count:t}}static computeInRange(n,i,t){let u=n.filter(e=>e.time>=i&&e.time<=t);return this.compute(u)}};function _(n,i){let t=typeof n=="number"?n:n.mean,u=typeof n=="number"?i??NaN:n.stdDev;return !Number.isFinite(t)||!Number.isFinite(u)||t===0?null:Math.abs(u/t)*100}var q=83144;function k(n,i=83144){let t=i/8.314,u=0,e=0;for(let a of n)a!==null&&(u+=Math.exp(-t/(a+273.15)),e++);if(e===0)return null;let l=u/e;return t/-Math.log(l)-273.15}function R(n,i,t=83144){let u=new Array(n.length),e=0;for(let l=0;l<n.length;l++){let a=n[l].time,r=a-i;for(;e<l&&n[e].time<r;)e++;let o=n.slice(e,l+1).map(s=>s.value),m=k(o,t);u[l]={time:a,value:m,synthetic:true};}return u}function F(n){let i=0,t=0;for(let l of n)l!==null&&(i+=l,t++);if(t===0)return null;let u=i/t,e=0;for(let l of n){if(l===null)continue;let a=l-u;e+=a*a;}return Math.sqrt(e/t)}function L(n){let i=0,t=0;for(let l of n)l!==null&&(i+=l,t++);if(t<2)return null;let u=i/t,e=0;for(let l of n){if(l===null)continue;let a=l-u;e+=a*a;}return Math.sqrt(e/(t-1))}function G(n,i,t=false){let u=new Array(n.length),e=0,l=t?L:F;for(let a=0;a<n.length;a++){let r=n[a].time,o=r-i;for(;e<a&&n[e].time<o;)e++;let m=n.slice(e,a+1).map(h=>h.value),s=l(m);u[a]={time:r,value:s,synthetic:true};}return u}function K(n,i){let{high:t,low:u}=i,e={msAboveHigh:0,msBelowLow:0,globalMax:null,globalMin:null,excursions:[]},l=null;for(let a=0;a<n.length;a++){let r=n[a];if(r.value===null){l&&(e.excursions.push(l),l=null);continue}(e.globalMax===null||r.value>e.globalMax)&&(e.globalMax=r.value),(e.globalMin===null||r.value<e.globalMin)&&(e.globalMin=r.value);let o=t!==void 0&&r.value>t,m=u!==void 0&&r.value<u,s=o?"above":m?"below":null,h=n[a-1];if(h&&h.value!==null&&s!==null){let g=r.time-h.time;s==="above"?e.msAboveHigh+=g:e.msBelowLow+=g;}if(s===null){l&&(e.excursions.push(l),l=null);continue}l&&l.side===s?(l.endTime=r.time,l.durationMs=l.endTime-l.startTime,(s==="above"&&r.value>l.extremum||s==="below"&&r.value<l.extremum)&&(l.extremum=r.value)):(l&&e.excursions.push(l),l={startTime:r.time,endTime:r.time,side:s,extremum:r.value,durationMs:0});}return l&&e.excursions.push(l),e}function O(n){if(n.length===0)return [];let i=new Map;for(let u of n)for(let e of u.data){if(e.value===null)continue;let l=i.get(e.time);l||(l=[],i.set(e.time,l)),l.push({name:u.name,value:e.value});}let t=[];for(let u of [...i.keys()].sort((e,l)=>e-l)){let e=i.get(u);if(e.length===0){t.push({time:u,min:null,max:null,delta:null,minSensor:null,maxSensor:null});continue}let l=e[0],a=e[0];for(let r=1;r<e.length;r++)e[r].value<l.value&&(l=e[r]),e[r].value>a.value&&(a=e[r]);t.push({time:u,min:l.value,max:a.value,delta:e.length<2?null:a.value-l.value,minSensor:l.name,maxSensor:a.name});}return t}function U(n){let i=[];for(let e of n){let l=0,a=0,r=1/0,o=-1/0;for(let m of e.data)m.value!==null&&(l+=m.value,a++,m.value<r&&(r=m.value),m.value>o&&(o=m.value));a!==0&&i.push({name:e.name,mean:l/a,min:r,max:o,count:a});}if(i.length===0)return {sensors:[],hottest:null,coldest:null,meanDelta:null};let t=i[0],u=i[0];for(let e=1;e<i.length;e++)i[e].mean>t.mean&&(t=i[e]),i[e].mean<u.mean&&(u=i[e]);return {sensors:i,hottest:t,coldest:u,meanDelta:t.mean-u.mean}}function N(n){let i=0,t=0,u=0,e=0,l=0;for(let m of n)m.value!==null&&(i++,t+=m.time,u+=m.value,e+=m.time*m.value,l+=m.time*m.time);if(i<2)return null;let a=i*l-t*t;if(a===0)return null;let r=(i*e-t*u)/a,o=(u-r*t)/i;return {slope:r,intercept:o,n:i}}function A(n,i){if(n.length===0)return null;let t=n[n.length-1].time,u=t-i,e=n.filter(l=>l.time>=u&&l.time<=t);return N(e)}function V(n,i){let t=[],u=0;for(let e=0;e<n.length;e++){let l=n[e].time,a=l-i;for(;u<n.length&&n[u].time<a;)u++;let r=N(n.slice(u,e+1));t.push({time:l,fit:r});}return t}function W(n,i,t={}){let u=t.lookbackMs??9e5,e=t.side??"either";if(n.length===0)return null;let l=n[n.length-1];if(l.value===null)return null;let a=A(n,u);if(!a||a.slope===0)return null;let r=a.slope>0&&l.value<i,o=a.slope<0&&l.value>i;if(e==="above"&&!r||e==="below"&&!o||e==="either"&&!r&&!o)return null;let m=(i-a.intercept)/a.slope,s=m-l.time;return s<=0?null:{msUntil:s,eta:m,fit:a,currentValue:l.value}}function Y(n,i={}){let t=i.refTempCelsius??121.11,u=i.zValueKelvin??10,e=0;for(let l=0;l<n.length-1;l++){let a=n[l],r=n[l+1];if(a.value===null||r.value===null)continue;let o=(r.time-a.time)/6e4;if(o<=0)continue;let m=Math.pow(10,(a.value-t)/u),s=Math.pow(10,(r.value-t)/u);e+=(m+s)/2*o;}return e}/*!
|
|
2
2
|
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
3
3
|
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
4
4
|
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
@@ -12,4 +12,4 @@ var H=class{static interpolateDataPoint(n,i,t){return {time:n.time+t*(i.time-n.t
|
|
|
12
12
|
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
13
13
|
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
14
14
|
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
15
|
-
*/export{
|
|
15
|
+
*/export{q as DEFAULT_ACTIVATION_ENERGY,S as PRODUCT_PROFILES,H as SeriesProcessor,P as StatsAggregator,D as aggregateBySlot,C as aggregateWithStats,z as analyzeLongTermTrends,K as computeLimitExcursions,E as createAggr,A as currentTrend,B as detectGaps,I as downsample,Y as f0Sterilization,U as hotColdSpots,N as linearFit,k as mkt,W as predictTimeToThreshold,R as rollingMkt,G as rollingStdDev,V as rollingTrend,L as sampleStdDev,O as spatialDelta,F as stdDev,_ as varianceCoefficient};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { e as LegendOrientation, f as Renderer, M as Marker, d as LegendItem, b as LayoutResult, R as RenderOutput, t as theme } from './layout-
|
|
2
|
-
import { U as LineVariant, g as AnySeries, aa as Threshold, P as Highlight, I as Gap, N as GapsConfig, d as Annotation, e as AnnotationBandConfig, o as DrawCommand, ad as TimeScale, V as LinearScale,
|
|
3
|
-
export { b as AggregationConfig, c as AggregationMode, l as DataPointRef, E as EnumMap, F as FillBound, x as FillDirectionType, y as FillRegion, z as FillSide, H as FillStyle, J as GapConfig, K as GapLabel, L as GapRegion, M as GapStyle, R as LineDashStyle, T as LineStyle, X as MarkerStyle, a2 as SensorType, a3 as SeriesOverlay, a4 as SeriesOverlayKind, a6 as SeriesType, a7 as ShadowStyle, ab as ThresholdLabelConfig } from './scale-
|
|
1
|
+
import { e as LegendOrientation, f as Renderer, M as Marker, d as LegendItem, b as LayoutResult, R as RenderOutput, t as theme } from './layout-C_t250fG.js';
|
|
2
|
+
import { U as LineVariant, g as AnySeries, aa as Threshold, P as Highlight, I as Gap, N as GapsConfig, d as Annotation, e as AnnotationBandConfig, o as DrawCommand, ad as TimeScale, V as LinearScale, a5 as SeriesStyle, G as FillSpec, af as TimeSeries, O as HatchVariant, ac as ThresholdLabelPosition, _ as PointStyleType, f as AnnotationBandItem, A as AggregatedPoint, a as AggregatedSeries, k as DataPoint } from './scale-DFyECKZq.js';
|
|
3
|
+
export { b as AggregationConfig, c as AggregationMode, l as DataPointRef, E as EnumMap, F as FillBound, x as FillDirectionType, y as FillRegion, z as FillSide, H as FillStyle, J as GapConfig, K as GapLabel, L as GapRegion, M as GapStyle, R as LineDashStyle, T as LineStyle, X as MarkerStyle, a2 as SensorType, a3 as SeriesOverlay, a4 as SeriesOverlayKind, a6 as SeriesType, a7 as ShadowStyle, ab as ThresholdLabelConfig } from './scale-DFyECKZq.js';
|
|
4
4
|
|
|
5
5
|
/*!
|
|
6
6
|
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
@@ -47,6 +47,8 @@ interface AxisLabelsStyle {
|
|
|
47
47
|
interface YAxisConfig {
|
|
48
48
|
/** Position is 'left' or 'right' to determine placement side. Defaults to 'left'. */
|
|
49
49
|
position?: "left" | "right";
|
|
50
|
+
/** Optional explicit horizontal pixel offset from chart edge (defaults to index * 50px). */
|
|
51
|
+
offset?: number;
|
|
50
52
|
/** Rotated label drawn next to the axis. */
|
|
51
53
|
label?: string;
|
|
52
54
|
/** Override the value domain. `'auto'` lets the chart compute it from data. */
|
|
@@ -82,6 +84,7 @@ interface XAxisConfig {
|
|
|
82
84
|
/**
|
|
83
85
|
* Top-level axes container on {@link MLTimeGraphOptions}.
|
|
84
86
|
* `left` and `right` correspond to `yAxisIndex: 0` and `yAxisIndex: 1` series.
|
|
87
|
+
* Additional axes can be defined in the `y` array, with indices mapping to series via `yAxisIndex`.
|
|
85
88
|
*/
|
|
86
89
|
interface AxesConfig {
|
|
87
90
|
x?: XAxisConfig;
|
|
@@ -105,7 +108,7 @@ interface Margin {
|
|
|
105
108
|
left: number;
|
|
106
109
|
}
|
|
107
110
|
/** Legend placement position — inside or outside the chart area. */
|
|
108
|
-
type LegendPosition =
|
|
111
|
+
type LegendPosition = "inside-right" | "inside-left" | "outside-right" | "outside-left" | "separate";
|
|
109
112
|
interface LegendOptions {
|
|
110
113
|
/** Show the legend (default false). */
|
|
111
114
|
show?: boolean;
|
|
@@ -465,6 +468,13 @@ declare class GraphBuilder {
|
|
|
465
468
|
*/
|
|
466
469
|
mount(target: HTMLElement | string): MLTimeGraph;
|
|
467
470
|
}
|
|
471
|
+
|
|
472
|
+
/*!
|
|
473
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
474
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
475
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
476
|
+
*/
|
|
477
|
+
|
|
468
478
|
/**
|
|
469
479
|
* TimeSeriesBuilder simplifies constructing raw TimeSeries datasets.
|
|
470
480
|
*/
|
|
@@ -473,6 +483,11 @@ declare class TimeSeriesBuilder {
|
|
|
473
483
|
constructor(name: string);
|
|
474
484
|
/** Appends a value-point to the series. */
|
|
475
485
|
addPoint(time: number, value: number | null): this;
|
|
486
|
+
/** Sets the data points array for the series. */
|
|
487
|
+
setData(points: Array<{
|
|
488
|
+
time: number;
|
|
489
|
+
value: number | null;
|
|
490
|
+
}>): this;
|
|
476
491
|
/** Appends an array of data points directly to the series. */
|
|
477
492
|
addPoints(points: Array<{
|
|
478
493
|
time: number;
|
|
@@ -482,6 +497,10 @@ declare class TimeSeriesBuilder {
|
|
|
482
497
|
addFloats(times: number[], values: Array<number | null>): this;
|
|
483
498
|
/** Appends a null point (signaling gaps/offline state). */
|
|
484
499
|
addNullPoint(time: number): this;
|
|
500
|
+
/** Assigns the target Y-axis index (0=left, 1=right, 2+=multi-axis). */
|
|
501
|
+
setYAxisIndex(index: number): this;
|
|
502
|
+
/** Shortcut to apply a primary stroke color to the series line. */
|
|
503
|
+
setColor(color: string): this;
|
|
485
504
|
/** Assigns the visual styles configuration. */
|
|
486
505
|
setStyle(style: SeriesStyle): this;
|
|
487
506
|
/** Shortcut to apply custom stroke styling (color, width, dash style). */
|
|
@@ -497,6 +516,13 @@ declare class TimeSeriesBuilder {
|
|
|
497
516
|
/** Compiles and returns the TimeSeries object. */
|
|
498
517
|
build(): TimeSeries;
|
|
499
518
|
}
|
|
519
|
+
|
|
520
|
+
/*!
|
|
521
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
522
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
523
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
524
|
+
*/
|
|
525
|
+
|
|
500
526
|
/**
|
|
501
527
|
* ThresholdBuilder simplifies constructing value boundaries.
|
|
502
528
|
*/
|
|
@@ -518,6 +544,13 @@ declare class ThresholdBuilder {
|
|
|
518
544
|
/** Compiles and returns the Threshold object. */
|
|
519
545
|
build(): Threshold;
|
|
520
546
|
}
|
|
547
|
+
|
|
548
|
+
/*!
|
|
549
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
550
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
551
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
552
|
+
*/
|
|
553
|
+
|
|
521
554
|
/**
|
|
522
555
|
* MarkerBuilder simplifies constructing vertical pins/markers.
|
|
523
556
|
*/
|
|
@@ -539,6 +572,13 @@ declare class MarkerBuilder {
|
|
|
539
572
|
/** Compiles and returns the Marker object. */
|
|
540
573
|
build(): Marker;
|
|
541
574
|
}
|
|
575
|
+
|
|
576
|
+
/*!
|
|
577
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
578
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
579
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
580
|
+
*/
|
|
581
|
+
|
|
542
582
|
/**
|
|
543
583
|
* HighlightBuilder simplifies constructing highlighted time bands.
|
|
544
584
|
*/
|
|
@@ -558,6 +598,13 @@ declare class HighlightBuilder {
|
|
|
558
598
|
/** Compiles and returns the Highlight object. */
|
|
559
599
|
build(): Highlight;
|
|
560
600
|
}
|
|
601
|
+
|
|
602
|
+
/*!
|
|
603
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
604
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
605
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
606
|
+
*/
|
|
607
|
+
|
|
561
608
|
/**
|
|
562
609
|
* AnnotationBuilder simplifies constructing free-form annotations.
|
|
563
610
|
*/
|
|
@@ -607,6 +654,13 @@ declare class AnnotationBuilder {
|
|
|
607
654
|
/** Compiles and returns the Annotation object. */
|
|
608
655
|
build(): Annotation;
|
|
609
656
|
}
|
|
657
|
+
|
|
658
|
+
/*!
|
|
659
|
+
* MLTimeGraph — Copyright (c) 2026 Michael Lechner
|
|
660
|
+
* MIT with Attribution: free use incl. commercial requires visible credit to
|
|
661
|
+
* "Michael Lechner". Commercial license (no attribution) on request. See LICENSE.
|
|
662
|
+
*/
|
|
663
|
+
|
|
610
664
|
/**
|
|
611
665
|
* AnnotationBandBuilder simplifies constructing annotation bands below the chart.
|
|
612
666
|
*/
|
|
@@ -645,7 +699,7 @@ declare class AnnotationBandItemBuilder {
|
|
|
645
699
|
/** Sets the border stroke width. */
|
|
646
700
|
setStrokeWidth(w: number): this;
|
|
647
701
|
/** Sets the text label and optional label formatting fields. */
|
|
648
|
-
setLabel(lbl: string, fontSize?: number, fill?: string, baseline?:
|
|
702
|
+
setLabel(lbl: string, fontSize?: number, fill?: string, baseline?: "top" | "middle" | "bottom"): this;
|
|
649
703
|
/** Compiles and returns the AnnotationBandItem object. */
|
|
650
704
|
build(): AnnotationBandItem;
|
|
651
705
|
}
|
|
@@ -661,7 +715,11 @@ declare class SVGRenderer extends Renderer {
|
|
|
661
715
|
constructor(options?: {
|
|
662
716
|
width?: number | string;
|
|
663
717
|
height?: number | string;
|
|
718
|
+
/** Optional solid background colour, drawn as a full-size rect (e.g. "white"). */
|
|
719
|
+
background?: string;
|
|
664
720
|
});
|
|
721
|
+
/** Set a solid background colour, drawn as a full-size rect behind the chart. */
|
|
722
|
+
setBackgroundColor(color: string): void;
|
|
665
723
|
render(commands: DrawCommand[]): RenderOutput;
|
|
666
724
|
_toSVG(cmd: DrawCommand): string;
|
|
667
725
|
/** Register or retrieve a hatch pattern by variant. Returns the pattern id for use as fill="url(#id)". */
|