'use strict'; // LTTB (Largest Triangle Three Buckets) decimation — O(n). // Runs off-main-thread to avoid blocking the render loop. function lttb(t, v, threshold) { const len = t.length; if (len <= threshold) { // Copy to new arrays so we can transfer them back without detaching the input. return { t: new Float64Array(t), v: new Float64Array(v) }; } const outT = new Float64Array(threshold); const outV = new Float64Array(threshold); outT[0] = t[0]; outV[0] = v[0]; outT[threshold - 1] = t[len - 1]; outV[threshold - 1] = v[len - 1]; const every = (len - 2) / (threshold - 2); let a = 0; for (let i = 0; i < threshold - 2; i++) { const avgS = Math.floor((i + 1) * every) + 1; const avgE = Math.min(Math.floor((i + 2) * every) + 1, len); let avgT = 0, avgV = 0, n = 0; for (let j = avgS; j < avgE; j++) { avgT += t[j]; avgV += v[j]; n++; } if (n) { avgT /= n; avgV /= n; } const rS = Math.floor(i * every) + 1; const rE = Math.min(Math.floor((i + 1) * every) + 1, len); let maxA = -1, next = rS; const aT = t[a], aV = v[a]; for (let j = rS; j < rE; j++) { const area = Math.abs((aT - avgT) * (v[j] - aV) - (aT - t[j]) * (avgV - aV)); if (area > maxA) { maxA = area; next = j; } } outT[i + 1] = t[next]; outV[i + 1] = v[next]; a = next; } return { t: outT, v: outV }; } self.onmessage = function({ data: { id, t, v, threshold } }) { const result = lttb(t, v, threshold); // Transfer the output buffers back to the main thread zero-copy. self.postMessage({ id, t: result.t, v: result.v }, [result.t.buffer, result.v.buffer]); };