diff --git a/sfm/event_browser.html b/sfm/event_browser.html index 0dce1b0..c3b7516 100644 --- a/sfm/event_browser.html +++ b/sfm/event_browser.html @@ -522,8 +522,13 @@ function renderWaveform(data) { charts = {}; const channels = data.channels || {}; - const timeAxis = data.time_axis || null; // ms relative to trigger - const triggerMs = data.trigger_ms ?? 0; + // time_axis is METADATA from sfm.plot.v1 — sample_rate, pretrig_samples, + // t0_ms (first-sample time relative to trigger; negative when pretrig + // exists), dt_ms. Trigger is at t=0 by convention. + const ta = data.time_axis || {}; + const sr = ta.sample_rate || 1024; + const dtMs = ta.dt_ms || (1000.0 / sr); + const t0Ms = ta.t0_ms != null ? ta.t0_ms : 0; const isPrintMode = document.body.classList.contains('print-view'); // Which channels actually have data → determines which one renders the @@ -578,14 +583,8 @@ function renderWaveform(data) { wrap.appendChild(canvasWrap); chartsDiv.appendChild(wrap); - // Build time labels — use server-provided time_axis if present, else derive from sample_rate - let times; - if (timeAxis && timeAxis.length === values.length) { - times = timeAxis; - } else { - const sr = data.sample_rate || 1024; - times = values.map((_, i) => (i / sr * 1000 - triggerMs)); - } + // Per-sample time in ms relative to trigger. Negative for pre-trigger samples. + const times = values.map((_, i) => t0Ms + i * dtMs); // Downsample for rendering const MAX_POINTS = 4000; diff --git a/sfm/sfm_webapp.html b/sfm/sfm_webapp.html index 6c68b38..df23b3a 100644 --- a/sfm/sfm_webapp.html +++ b/sfm/sfm_webapp.html @@ -2572,8 +2572,14 @@ function _renderScWaveform(data) { _destroyScCharts(); const channels = data.channels || {}; - const timeAxis = data.time_axis || null; - const triggerMs = data.trigger_ms ?? 0; + // time_axis is METADATA, not an array — it carries sample_rate, + // pretrig_samples, t0_ms (first-sample time relative to trigger, + // negative when pretrig samples exist), and dt_ms. Trigger is at + // t=0 by convention. + const ta = data.time_axis || {}; + const sr = ta.sample_rate || 1024; + const dtMs = ta.dt_ms || (1000.0 / sr); + const t0Ms = ta.t0_ms != null ? ta.t0_ms : 0; // Which channels have data — determines which one renders the shared bottom axis. const withData = _SC_CHANNEL_ORDER.filter(ch => @@ -2612,14 +2618,8 @@ function _renderScWaveform(data) { wrap.appendChild(canvasWrap); chartsDiv.appendChild(wrap); - // Build time axis. Prefer server-provided time_axis; else derive from sample_rate. - let times; - if (timeAxis && timeAxis.length === values.length) { - times = timeAxis; - } else { - const sr = data.sample_rate || 1024; - times = values.map((_, i) => (i / sr * 1000 - triggerMs)); - } + // Per-sample time in ms relative to trigger. Negative for pre-trigger samples. + const times = values.map((_, i) => t0Ms + i * dtMs); // Downsample for rendering when very long. const MAX = 3000;