| 118 | }; |
| 119 | |
| 120 | const createTimeSeries = (count: number): ReadonlyArray<DataPoint> => { |
| 121 | const n = Math.max(2, Math.floor(count)); |
| 122 | const out: DataPoint[] = new Array(n); |
| 123 | |
| 124 | // Fixed epoch (ms) so the options are fully structured-cloneable (no Date instances). |
| 125 | const startTs = 1704067200000; // 2024-01-01T00:00:00.000Z |
| 126 | const stepMs = 60_000; // 1 minute |
| 127 | |
| 128 | for (let i = 0; i < n; i++) { |
| 129 | const t = i / (n - 1); |
| 130 | const x = startTs + i * stepMs; |
| 131 | |
| 132 | const trend = (t - 0.5) * 1.25; |
| 133 | const slow = Math.sin(i * 0.06) * 0.9; |
| 134 | const hf = Math.sin(i * 0.28 + 0.7) * 0.18; |
| 135 | const noise = (Math.random() - 0.5) * 0.08; |
| 136 | const y = trend + slow + hf + noise; |
| 137 | |
| 138 | out[i] = [x, y] as const; |
| 139 | } |
| 140 | |
| 141 | return out; |
| 142 | }; |
| 143 | |
| 144 | async function main(): Promise<void> { |
| 145 | const container = document.getElementById('chart'); |