ml-time-graph 1.0.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/LICENSE +32 -0
- package/MKT_AGGREGATE.md +154 -0
- package/README.de.md +154 -0
- package/README.md +152 -0
- package/USAGE.md +343 -0
- package/dist/aggregated_subtypes-DZNZyFTX.d.ts +43 -0
- package/dist/analyze/index.d.ts +296 -0
- package/dist/analyze/index.js +574 -0
- package/dist/index.d.ts +481 -0
- package/dist/index.js +3432 -0
- package/dist/interaction/index.d.ts +141 -0
- package/dist/interaction/index.js +438 -0
- package/dist/internals.d.ts +899 -0
- package/dist/internals.js +2465 -0
- package/dist/layout-Sc5UkC0r.d.ts +246 -0
- package/dist/scale-Cbr0KpPz.d.ts +824 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
MLTimeGraph License (MIT with Attribution)
|
|
2
|
+
Copyright (c) 2026 Michael Lechner
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person or organization
|
|
5
|
+
obtaining a copy of this software and associated documentation files (the
|
|
6
|
+
"Software"), to deal in the Software without restriction, including without
|
|
7
|
+
limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
8
|
+
sublicense, and/or sell copies of the Software, and to permit persons to whom
|
|
9
|
+
the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
1. The above copyright notice and this permission notice shall be included in
|
|
12
|
+
all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
2. Attribution. Any product or service that uses the Software, including
|
|
15
|
+
commercial and closed-source products, must give clearly visible credit to
|
|
16
|
+
the author "Michael Lechner" in a location reasonably accessible to end
|
|
17
|
+
users (for example: product documentation, an "About" / credits screen, a
|
|
18
|
+
legal-notices page, or a comparable place).
|
|
19
|
+
|
|
20
|
+
3. Commercial license (attribution waiver). Organizations that do not wish to
|
|
21
|
+
display the attribution required by Section 2 may obtain a separate
|
|
22
|
+
commercial license that waives this requirement. Such a license is available
|
|
23
|
+
from the author on request.
|
|
24
|
+
Contact: mlcgo.eu@michael-lechner.de
|
|
25
|
+
|
|
26
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
27
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
28
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
29
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
30
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
31
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
32
|
+
SOFTWARE.
|
package/MKT_AGGREGATE.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Dokumentation: Kinetische Temperaturaggregation (`aggregateBySlot`)
|
|
2
|
+
|
|
3
|
+
Dieses Modul bietet eine mathematische Kernfunktion zur zeitlichen Aggregation von Temperatur-Loggerdaten. Neben klassischen statistischen Werten (`min`, `max`, `avg`, `stdDev`) berechnet die Funktion die **Mean Kinetic Temperature (MKT)** sowie die präzise Dauer von Grenzwertverletzungen in Minuten.
|
|
4
|
+
|
|
5
|
+
Die Funktion ist vollständig **entkoppelt**, besitzt kein inhärentes Wissen über spezifische Produkte (Blut, Pharma, Lebensmittel) und wird rein über mathematische Parameter gesteuert.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Was ist die Mean Kinetic Temperature (MKT)?
|
|
10
|
+
|
|
11
|
+
Die MKT ist eine Methode zur Bewertung von Temperaturschwankungen bei der Lagerung und dem Transport von temperaturempfindlichen Gütern. Im Gegensatz zum arithmetischen Mittelwert (`avg`) gewichtet die MKT **höhere Temperaturen exponentiell stärker**. Dies bildet das reale biologische und chemische Degradationsverhalten (Verderb) von Produkten ab, da chemische Reaktionen bei Wärme beschleunigt ablaufen (Arrhenius-Gleichung).
|
|
12
|
+
|
|
13
|
+
### Mathematische Formel (nach USP <1079.2>)
|
|
14
|
+
|
|
15
|
+
$$T_{K} = \frac{\frac{\Delta H}{R}}{-\ln\left(\frac{e^{-\frac{\Delta H}{R \cdot T_1}} + e^{-\frac{\Delta H}{R \cdot T_2}} + \dots + e^{-\frac{\Delta H}{R \cdot T_n}}}{n}\right)}$$
|
|
16
|
+
|
|
17
|
+
* **$T_K$**: Mittlere kinetische Temperatur in Kelvin.
|
|
18
|
+
* **$\Delta H$**: Aktivierungsenergie. Der globale Standard für Pharma- und GDP-Audits beträgt **$83.144\text{ kJ/mol}$** ($83144\text{ J/mol}$).
|
|
19
|
+
* **$R$**: Universelle Gaskonstante ($8.31446\text{ J/(mol}\cdot\text{K)}$).
|
|
20
|
+
* **$T_n$**: Gemessene Temperatur zum Zeitpunkt $n$ in Kelvin.
|
|
21
|
+
* **$n$**: Anzahl der gültigen Messwerte im Intervall.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 2. Datenstrukturen & Interfaces
|
|
26
|
+
|
|
27
|
+
### Eingangsdaten (`DataPoint`)
|
|
28
|
+
Die Rohdaten erlauben explizit `null`-Werte (z. B. bei temporärem Sensorausfall).
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
export interface DataPoint {
|
|
32
|
+
time: number; // Unix-Zeitstempel in Millisekunden
|
|
33
|
+
value: number | null; // Temperaturwert in °C oder null
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Konfiguration (`AggregationThresholds`)
|
|
38
|
+
Ermöglicht die Übergabe dynamischer Grenzwerte zur Bestimmung der Abweichungsminuten.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
export interface AggregationThresholds {
|
|
42
|
+
limitLow: number; // Unterer Grenzwert in °C
|
|
43
|
+
limitHigh: number; // Oberer Grenzwert in °C
|
|
44
|
+
activationEnergy?: number; // Optional: Aktivierungsenergie in J/mol (Standard: 83144.0)
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Ausgangsdaten (`StatsAggregatedPoint`)
|
|
49
|
+
|
|
50
|
+
`aggregateBySlot()` mit `thresholds`-Parameter liefert
|
|
51
|
+
`StatsAggregatedPoint[]` — eine Intersection aus `MktPoint`,
|
|
52
|
+
`StdDevPoint` und `LimitStatsPoint`. Die Basis-`AggregatedPoint` trägt
|
|
53
|
+
nur die statistischen Pflichtfelder; alles MKT/σ/Limit-spezifische lebt
|
|
54
|
+
auf den spezialisierten Untertypen, sodass User unfallfrei zwischen
|
|
55
|
+
"reine min/max/avg"-Aggregation und "voll dekoriertem" Slot
|
|
56
|
+
unterscheiden können.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
export interface AggregatedPoint {
|
|
60
|
+
time: number; // Startzeitpunkt des Slots in ms
|
|
61
|
+
min: number | null; // Niedrigste Temperatur im Slot
|
|
62
|
+
max: number | null; // Höchste Temperatur im Slot
|
|
63
|
+
avg: number | null; // Arithmetischer Mittelwert
|
|
64
|
+
count: number; // Anzahl valider Messwerte
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface MktPoint extends AggregatedPoint {
|
|
68
|
+
mkt: number | null; // Mean Kinetic Temperature in °C
|
|
69
|
+
deltaMkt?: number | null; // Delta zur Vor-Slot-MKT (optional)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface StdDevPoint extends AggregatedPoint {
|
|
73
|
+
stdDev: number | null; // Standardabweichung
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface LimitStatsPoint extends AggregatedPoint {
|
|
77
|
+
minutesAboveHigh?: number | null;
|
|
78
|
+
minutesBelowLow?: number | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type StatsAggregatedPoint = MktPoint & StdDevPoint & LimitStatsPoint;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 3. Kern-Features des Algorithmus
|
|
87
|
+
|
|
88
|
+
1. **Umgang mit Lücken & Ausfällen (`null`-Werte):**
|
|
89
|
+
* `null`-Werte in den Rohdaten werden vor der mathematischen Berechnung strikt herausgefiltert. Sie verfälschen weder Minimum, Maximum noch die MKT-Exponentialsumme.
|
|
90
|
+
* Ein Slot, der *ausschließlich* aus `null`-Daten besteht, bleibt im Ausgabe-Array als Platzhalter erhalten (`count: 0`, alle Werte sind `null`), um Zeitleisten-Lücken in Diagrammen zu verhindern.
|
|
91
|
+
2. **Präzise Zeitsynchronität (Feste Slots):**
|
|
92
|
+
* Die Funktion verwendet ein festes Intervallgitter. Unabhängig davon, wann Datenpunkte eintreffen, springt das Raster präzise um die exakte Intervall-Länge (z. B. stündlich).
|
|
93
|
+
3. **MKT-Stabilitätsschutz (`minCountForMkt`):**
|
|
94
|
+
* Die MKT benötigt eine statistisch relevante Anzahl an Messwerten. Über einen Parameter kann definiert werden, ab wie vielen validen Punkten im Slot die MKT berechnet wird. Wird die Schwelle unterschritten, wird `mkt` sicher auf `null` gesetzt, anstatt mathematische Artefakte zu erzeugen.
|
|
95
|
+
4. **Präzise Abweichungsdauer (Dauer in Minuten):**
|
|
96
|
+
* Anstatt nur Datenpunkte zu zählen, berechnet die Funktion die reale zeitliche Differenz zwischen aufeinanderfolgenden Loggereinträgen. Dadurch werden unregelmäßige Datenaufzeichnungen (z. B. Event-basierte Logger) exakt in Minuten erfasst.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 4. Integration & Nutzung im System
|
|
101
|
+
|
|
102
|
+
Da die Kernfunktion mathematisch dumm gehalten ist, werden die branchenspezifischen Vorgaben (Pharma, Blut, Lebensmittel) **außerhalb** über die Konfigurationsschicht verwaltet.
|
|
103
|
+
|
|
104
|
+
### Typische Produkt-Grenzwerte im Überblick
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
| Produktkategorie | Unteres Limit (`limitLow`) | Oberes Limit (`limitHigh`) | Aktivierungsenergie ($\Delta H$) |
|
|
108
|
+
| :--- | :--- | :--- | :--- |
|
|
109
|
+
| **Pharma (Kühlkette)** | $+2.0^\circ\text{C}$ | $+8.0^\circ\text{C}$ | $83144\text{ J/mol}$ (USP Standard) |
|
|
110
|
+
| **Pharma (Raumtemperatur)** | $+15.0^\circ\text{C}$ | $+25.0^\circ\text{C}$ | $83144\text{ J/mol}$ (USP Standard) |
|
|
111
|
+
| **Blutkonserven** | $+2.0^\circ\text{C}$ | $+6.0^\circ\text{C}$ | $83144\text{ J/mol}$ (Standard-Anwendung) |
|
|
112
|
+
| **Lebensmittel (Frische)** | $0.0^\circ\text{C}$ | $+4.0^\circ\text{C}$ | *MKT irrelevant / entfällt meist* |
|
|
113
|
+
| **Tiefkühlkost** | $-40.0^\circ\text{C}$ | $-18.0^\circ\text{C}$ | *MKT irrelevant / entfällt meist* |
|
|
114
|
+
|
|
115
|
+
### Code-Beispiele zur Verwendung
|
|
116
|
+
|
|
117
|
+
#### Beispiel 1: Standard-Aggregation stündlich ohne Limits
|
|
118
|
+
Es werden nur die Basis-Statistiken und die MKT berechnet. Die Alarmminuten bleiben `null`.
|
|
119
|
+
```typescript
|
|
120
|
+
import { aggregateBySlot } from "ml-time-graph/analyze";
|
|
121
|
+
|
|
122
|
+
const hourlyStats = aggregateBySlot(rawLoggerData, "hourly");
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Beispiel 2: Aggregation für Blutkonserven (Tägliches Intervall)
|
|
126
|
+
Hier werden die Grenzwerte injiziert. Die Funktion berechnet automatisch, wie viele Minuten die Blutkonserven außerhalb der erlaubten $2^\circ\text{C} - 6^\circ\text{C}$ lagen.
|
|
127
|
+
```typescript
|
|
128
|
+
const bloodThresholds = {
|
|
129
|
+
limitLow: 2.0,
|
|
130
|
+
limitHigh: 6.0
|
|
131
|
+
// activationEnergy wird weggelassen -> nutzt automatisch internen 83144 J/mol Fallback
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const dailyBloodReport = aggregateBySlot(
|
|
135
|
+
rawLoggerData,
|
|
136
|
+
"daily",
|
|
137
|
+
undefined, // customInterval
|
|
138
|
+
bloodThresholds,
|
|
139
|
+
12 // MKT erst berechnen, wenn mindestens 12 gültige Werte im Tag liegen
|
|
140
|
+
);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### Beispiel 3: Spezial-Laborwert (Custom Aktivierungsenergie)
|
|
144
|
+
Sollte ein Audit für ein bestimmtes biologisches Plasma-Protein eine abweichende Aktivierungsenergie vorschreiben, kann diese direkt mitgegeben werden:
|
|
145
|
+
```typescript
|
|
146
|
+
const customLabThresholds = {
|
|
147
|
+
limitLow: 1.0,
|
|
148
|
+
limitHigh: 4.5,
|
|
149
|
+
activationEnergy: 65000.0 // 65 kJ/mol statt 83.144 kJ/mol
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const labReport = aggregateBySlot(rawLoggerData, "hourly", undefined, customLabThresholds);
|
|
153
|
+
```
|
|
154
|
+
|
package/README.de.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# 📈 MLTimeGraph
|
|
2
|
+
|
|
3
|
+
*[English](README.md) · Deutsch*
|
|
4
|
+
|
|
5
|
+
**TypeScript-Library für die grafische Darstellung von Messwerten** — Zeitreihen
|
|
6
|
+
schnell und unkompliziert aufbereiten, mit Fokus auf Reporting und Incident-Analyse.
|
|
7
|
+
|
|
8
|
+
> Voll typisiert · i18n-aware · DOM-freier SVG-Renderer (Browser & serverseitig) · keine Laufzeit-Abhängigkeiten · ESM-only
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install ml-time-graph # oder: pnpm add / yarn add
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Voraussetzung: **Node 18+**. Die Library ist **ESM-only** — funktioniert
|
|
17
|
+
out of the box mit jedem modernen Bundler (Vite, Rollup, esbuild,
|
|
18
|
+
Webpack 5+, Next.js, Astro, …) und in Node-ESM (`"type": "module"` in
|
|
19
|
+
deiner `package.json`, oder `.mjs`-Dateien).
|
|
20
|
+
|
|
21
|
+
Vier Subpath-Imports:
|
|
22
|
+
|
|
23
|
+
| Import | Zweck |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `ml-time-graph` | User-API — `mount`, `MLTimeGraph`, `SVGRenderer`, `attachTooltip`, alle Input- + Style-Typen |
|
|
26
|
+
| `ml-time-graph/analyze` | Aggregation + Statistik (`aggregateBySlot`, `rollingMkt`, `rollingStdDev`, `downsample`, …) |
|
|
27
|
+
| `ml-time-graph/interaction` | Optionale Widgets (`Zoom`, `Minimap`, `Tooltip`) |
|
|
28
|
+
| `ml-time-graph/internals` | Building Blocks für eigene Renderer (freie Render-Funktionen, Scales, Axis-Klassen, `DrawCommand`-Modell, …) |
|
|
29
|
+
|
|
30
|
+
### Reines HTML / CDN
|
|
31
|
+
|
|
32
|
+
Kein Build-Schritt? Hol's direkt von einem ESM-CDN, der npm proxyed:
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<div id="chart"></div>
|
|
36
|
+
<script type="module">
|
|
37
|
+
import { mount } from 'https://esm.sh/ml-time-graph@1';
|
|
38
|
+
// oder: 'https://cdn.jsdelivr.net/npm/ml-time-graph@1/+esm'
|
|
39
|
+
|
|
40
|
+
mount('#chart', {
|
|
41
|
+
series: [{ name: 'Temp', data: [/* … */] }],
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Pinne eine Major-Version (`@1`), damit dich Breaking Changes nicht überraschen.
|
|
47
|
+
|
|
48
|
+
## Quickstart
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { mount } from 'ml-time-graph';
|
|
52
|
+
|
|
53
|
+
mount('#chart', {
|
|
54
|
+
series: [{
|
|
55
|
+
name: 'Temperatur',
|
|
56
|
+
style: { line: { color: '#ef4444' } },
|
|
57
|
+
data: [
|
|
58
|
+
{ time: Date.UTC(2026, 0, 1, 0), value: 18.2 },
|
|
59
|
+
{ time: Date.UTC(2026, 0, 1, 1), value: 19.1 },
|
|
60
|
+
],
|
|
61
|
+
}],
|
|
62
|
+
tooltip: { show: true }, // optionaler Hover-Tooltip mit Visual-Picks
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
📖 **Nutzung & API → [USAGE.md](USAGE.md)** *(englisch)*
|
|
67
|
+
|
|
68
|
+
## Galerie
|
|
69
|
+
|
|
70
|
+
<p align="center">
|
|
71
|
+
<a href="ex1.svg"><img src="ex1.svg" alt="Linie mit Zonen-Färbung und Threshold-Fills" width="300"></a>
|
|
72
|
+
<a href="ex2.svg"><img src="ex2.svg" alt="Multi-Zonen-Hatch-Fills" width="300"></a>
|
|
73
|
+
<a href="ex3.svg"><img src="ex3.svg" alt="stdDevBand + movingMkt-Overlays auf einem Sensorstrom" width="300"></a>
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
Typische Sensor-Darstellung (links), Multi-Zonen-Schraffuren für
|
|
77
|
+
Incident-Reports (Mitte), Sensorstrom mit Statistik-Overlays (rechts:
|
|
78
|
+
±2σ-Band + 12-h-MKT) — alles dieselbe Library, alle in der
|
|
79
|
+
Demo-Galerie zu sehen (`pnpm dev`).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Warum schon wieder eine neue Library?
|
|
84
|
+
|
|
85
|
+
Alle Libraries, die ich in der Vergangenheit professionell genutzt habe, haben
|
|
86
|
+
irgendwann ihr Lizenzmodell von *frei* auf *kostenpflichtig* umgestellt. Das wird
|
|
87
|
+
zum Problem, sobald ein Wechsel nicht möglich ist: Man muss „alte" Libraries
|
|
88
|
+
plötzlich ersetzen oder selbst weiterpflegen (z. B. an aktuelle Browser-Entwicklungen
|
|
89
|
+
anpassen).
|
|
90
|
+
|
|
91
|
+
Ich brauche keine 100 Chart Typen.
|
|
92
|
+
|
|
93
|
+
MLTimeGraph ist **nicht** dazu gedacht, tausend verschiedene Chart-Typen
|
|
94
|
+
abzudecken. Der Fokus liegt darauf, **Messwerte — also Zeit + Daten — schnell und
|
|
95
|
+
unkompliziert grafisch aufzubereiten**. Ein besonderes Augenmerk liegt auf der
|
|
96
|
+
**Incident-Analyse**: etwa wenn Sensoren zur Überwachung von Geräten eingesetzt
|
|
97
|
+
werden und die nachträgliche Auswertung entscheidend ist.
|
|
98
|
+
|
|
99
|
+
## Ziele
|
|
100
|
+
|
|
101
|
+
- ✅ **Keine Browser-Abhängigkeit** — das Rendering ist vom DOM entkoppelt (SVG-String, im Browser und serverseitig)
|
|
102
|
+
- ✅ **Voll typisiert** — durchgängig TypeScript
|
|
103
|
+
- ✅ **Einfache Integration** in bestehende Projekte
|
|
104
|
+
- ✅ **i18n-aware** — lokalisierte Zeitachsen und Formatierung
|
|
105
|
+
- ✅ **Einfache, aber umfangreiche Konfiguration** — Farben, Linienstärken, Styles
|
|
106
|
+
- ✅ Typische Darstellungen für Messwerte:
|
|
107
|
+
- Markierung von Bereichen (Highlights)
|
|
108
|
+
- Thresholds (Bänder, Linien, Flächen)
|
|
109
|
+
- min / max / avg-Darstellungen
|
|
110
|
+
- Incident-Analysen — markante Ereignisse und Werte markieren
|
|
111
|
+
|
|
112
|
+
## Nicht-Ziele
|
|
113
|
+
|
|
114
|
+
- ❌ **High Performance** — für den Hauptanwendungsfall (Reporting, Analyse) nicht notwendig
|
|
115
|
+
- ❌ **Volle Interaktivität** — Zoom/Pan ja, aber in Grenzen
|
|
116
|
+
- ❌ GPU-Performance-Optimierungen o. Ä.
|
|
117
|
+
|
|
118
|
+
## Ausblick / in Überlegung
|
|
119
|
+
|
|
120
|
+
- Möglichkeiten der „Live"-Darstellung
|
|
121
|
+
- Einfache Anbindung von Backends (woher kommen meine Daten?)
|
|
122
|
+
- svelte wrapper
|
|
123
|
+
|
|
124
|
+
## Demos & Entwicklung
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pnpm install
|
|
128
|
+
pnpm dev # startet die Demo-Galerie (Vite)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
| Script | Zweck |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| `pnpm dev` | Demo-Galerie lokal starten |
|
|
134
|
+
| `pnpm test` | Test-Suite (Vitest) |
|
|
135
|
+
| `pnpm typecheck` | Library typprüfen |
|
|
136
|
+
| `pnpm typecheck:demos` | Demos typprüfen |
|
|
137
|
+
| `pnpm build` | Library bauen (ESM-Bundle + Types) |
|
|
138
|
+
|
|
139
|
+
## Lizenz
|
|
140
|
+
|
|
141
|
+
© 2026 Michael Lechner — **MIT mit Attribution-Klausel** (siehe [LICENSE](LICENSE)).
|
|
142
|
+
|
|
143
|
+
Nutzung, Änderung und Verbreitung — **auch kommerziell und in Closed-Source-Produkten** —
|
|
144
|
+
sind kostenlos erlaubt, sofern der Autor **„Michael Lechner" sichtbar genannt** wird
|
|
145
|
+
(z. B. in Doku, Impressum/Rechtliches oder einem About-/Credits-Bereich) und der
|
|
146
|
+
Copyright-Hinweis im Quellcode erhalten bleibt.
|
|
147
|
+
|
|
148
|
+
**Ohne Nennung:** Unternehmen, die die Attribution nicht zeigen möchten, können eine
|
|
149
|
+
**kommerzielle Lizenz auf Anfrage** erhalten, die diese Pflicht aufhebt — Kontakt: ‹mlcgo.eu@michael-lechner.de›.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
<sub>Das Projekt diente ursprünglich als Test für Crush-Development mit Ollama +
|
|
154
|
+
neuem LLM — bestanden 😉, brauchte aber doch einige Nacharbeit.</sub>
|
package/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# 📈 MLTimeGraph
|
|
2
|
+
|
|
3
|
+
*English · [Deutsch](README.de.md)*
|
|
4
|
+
|
|
5
|
+
**A TypeScript library for visualizing measurement data** — turn time series into
|
|
6
|
+
clear, readable charts quickly, with a focus on reporting and incident analysis.
|
|
7
|
+
|
|
8
|
+
> Fully typed · i18n-aware · DOM-free SVG output (browser & server) · zero runtime dependencies · ESM-only
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install ml-time-graph # or: pnpm add / yarn add
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Requires **Node 18+**. The library is **ESM-only** — works out of the
|
|
17
|
+
box in any modern bundler (Vite, Rollup, esbuild, Webpack 5+, Next.js,
|
|
18
|
+
Astro, …) and in Node ESM (`"type": "module"` in your `package.json`,
|
|
19
|
+
or `.mjs` files).
|
|
20
|
+
|
|
21
|
+
Four subpath imports:
|
|
22
|
+
|
|
23
|
+
| Import | Purpose |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `ml-time-graph` | User API — `mount`, `MLTimeGraph`, `SVGRenderer`, `attachTooltip`, all input + style types |
|
|
26
|
+
| `ml-time-graph/analyze` | Aggregation + statistics (`aggregateBySlot`, `rollingMkt`, `rollingStdDev`, `downsample`, …) |
|
|
27
|
+
| `ml-time-graph/interaction` | Optional widgets (`Zoom`, `Minimap`, `Tooltip`) |
|
|
28
|
+
| `ml-time-graph/internals` | Building blocks for custom renderers (free render-functions, scales, axis classes, `DrawCommand` model, …) |
|
|
29
|
+
|
|
30
|
+
### Plain HTML / CDN
|
|
31
|
+
|
|
32
|
+
No build step? Pull it straight from an ESM CDN that proxies npm:
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<div id="chart"></div>
|
|
36
|
+
<script type="module">
|
|
37
|
+
import { mount } from 'https://esm.sh/ml-time-graph@1';
|
|
38
|
+
// or: 'https://cdn.jsdelivr.net/npm/ml-time-graph@1/+esm'
|
|
39
|
+
|
|
40
|
+
mount('#chart', {
|
|
41
|
+
series: [{ name: 'Temp', data: [/* … */] }],
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Pin a major version (`@1`) to avoid surprise breaking changes.
|
|
47
|
+
|
|
48
|
+
## Quickstart
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { mount } from 'ml-time-graph';
|
|
52
|
+
|
|
53
|
+
mount('#chart', {
|
|
54
|
+
series: [{
|
|
55
|
+
name: 'Temperature',
|
|
56
|
+
style: { line: { color: '#ef4444' } },
|
|
57
|
+
data: [
|
|
58
|
+
{ time: Date.UTC(2026, 0, 1, 0), value: 18.2 },
|
|
59
|
+
{ time: Date.UTC(2026, 0, 1, 1), value: 19.1 },
|
|
60
|
+
],
|
|
61
|
+
}],
|
|
62
|
+
tooltip: { show: true }, // optional hover tooltip with visual picks
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
📖 **Usage & API → [USAGE.md](USAGE.md)**
|
|
67
|
+
|
|
68
|
+
## Gallery
|
|
69
|
+
|
|
70
|
+
<p align="center">
|
|
71
|
+
<a href="ex1.svg"><img src="ex1.svg" alt="Line chart with zoned colouring + threshold fills" width="300"></a>
|
|
72
|
+
<a href="ex2.svg"><img src="ex2.svg" alt="Hatched multi-zone threshold fills" width="300"></a>
|
|
73
|
+
<a href="ex3.svg"><img src="ex3.svg" alt="stdDevBand + movingMkt overlays on a sensor stream" width="300"></a>
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
A typical sensor visualisation (left), multi-zone hatched fills for
|
|
77
|
+
incident-style reports (center), and a sensor stream with statistic
|
|
78
|
+
overlays (right: ±2σ band + 12 h MKT) — all rendered with the same
|
|
79
|
+
library, all live in the demo gallery (`pnpm dev`).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Why another chart library?
|
|
84
|
+
|
|
85
|
+
Every charting library I relied on professionally eventually switched its license
|
|
86
|
+
from *free* to *paid* — a real problem when you can't follow that move: you end up
|
|
87
|
+
having to replace "old" libraries or maintain them yourself (e.g. keeping up with
|
|
88
|
+
browser changes).
|
|
89
|
+
|
|
90
|
+
I don't need a hundred chart types.
|
|
91
|
+
|
|
92
|
+
MLTimeGraph is **not** meant to cover a thousand chart types. The focus is on turning
|
|
93
|
+
**measurements — time + values — into clear charts quickly**, with particular
|
|
94
|
+
attention to **incident analysis**: e.g. when sensors monitor equipment and the
|
|
95
|
+
after-the-fact evaluation is what matters.
|
|
96
|
+
|
|
97
|
+
## Goals
|
|
98
|
+
|
|
99
|
+
- ✅ **No browser dependency** — rendering is decoupled from the DOM (SVG string, in the browser and server-side)
|
|
100
|
+
- ✅ **Fully typed** — TypeScript throughout
|
|
101
|
+
- ✅ **Easy integration** into existing projects
|
|
102
|
+
- ✅ **i18n-aware** — localized time axes and formatting
|
|
103
|
+
- ✅ **Simple yet thorough configuration** — colors, line widths, styles
|
|
104
|
+
- ✅ Typical measurement visualizations:
|
|
105
|
+
- region highlights
|
|
106
|
+
- thresholds (lines, fills, zones)
|
|
107
|
+
- min / max / avg displays
|
|
108
|
+
- incident analysis — mark notable events and values
|
|
109
|
+
|
|
110
|
+
## Non-goals
|
|
111
|
+
|
|
112
|
+
- ❌ **High performance** — not needed for the main use case (reporting, analysis)
|
|
113
|
+
- ❌ **Full interactivity** — zoom/pan yes, but within limits
|
|
114
|
+
- ❌ GPU performance optimizations and the like
|
|
115
|
+
|
|
116
|
+
## Outlook / under consideration
|
|
117
|
+
|
|
118
|
+
- "Live" rendering options
|
|
119
|
+
- Simple backend integration (where does my data come from?)
|
|
120
|
+
- Svelte wrapper
|
|
121
|
+
|
|
122
|
+
## Demos & development
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pnpm install
|
|
126
|
+
pnpm dev # start the demo gallery (Vite)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
| Script | Purpose |
|
|
130
|
+
| --- | --- |
|
|
131
|
+
| `pnpm dev` | run the demo gallery locally |
|
|
132
|
+
| `pnpm test` | test suite (Vitest) |
|
|
133
|
+
| `pnpm typecheck` | type-check the library |
|
|
134
|
+
| `pnpm typecheck:demos` | type-check the demos |
|
|
135
|
+
| `pnpm build` | build the library (ESM bundle + types) |
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
© 2026 Michael Lechner — **MIT with an Attribution clause** (see [LICENSE](LICENSE)).
|
|
140
|
+
|
|
141
|
+
Use, modification and distribution — **including in commercial and closed-source
|
|
142
|
+
products** — are free of charge, provided the author **"Michael Lechner" is visibly
|
|
143
|
+
credited** (e.g. in documentation, a legal-notices page, or an About/credits screen)
|
|
144
|
+
and the copyright notice is retained in the source.
|
|
145
|
+
|
|
146
|
+
**Without attribution:** organizations that prefer not to display the attribution can
|
|
147
|
+
obtain a **commercial license on request** that waives it — contact: ‹mlcgo.eu@michael-lechner.de›.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
<sub>Originally a test of Crush development with Ollama + a new LLM — passed 😉, but it
|
|
152
|
+
did need some rework.</sub>
|