viewers: symmetric Y-axis on geo waveforms + clarify timestamp labels

Two fixes from the second screenshot review:

1. Geophone waveform Y-axis now renders SYMMETRIC around zero — zero
   line sits in the middle of the chart, signal goes both above and
   below.  Standard seismograph display convention; matches the
   Instantel printout look.  Previously Chart.js auto-scaled to the
   data range so e.g. Vert showing values from -0.005 to -0.015 had
   the zero line completely off-screen.

   Mic channel (sound pressure, always positive) keeps the default
   auto-scale anchored at zero.  Histograms (per-interval peaks, also
   always positive) likewise keep bars rising from a zero baseline.

2. Modal labels clarified to remove the 'Timestamp' vs 'Captured at'
   ambiguity:
     'Timestamp'   →  'Recorded at'         (when the seismograph
                                              recorded the event —
                                              from BW report's Event
                                              Time field)
     'Captured at' →  'Received by server at' (when our sfm-db
                                              inserted the row)
   Both have tooltips explaining the distinction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 20:26:23 +00:00
parent 784f2cca36
commit 5d5441604b
2 changed files with 40 additions and 2 deletions
+23 -2
View File
@@ -2670,6 +2670,24 @@ function _renderScWaveform(data) {
return String(v) + xAxisLabel;
};
// Y-axis bounds. Convention:
// - Geophones (Tran/Vert/Long) on waveform-mode events:
// symmetric around zero so the zero line sits in the middle and
// positive/negative excursions are visually balanced.
// - Mic (always positive sound pressure) + histograms (per-interval
// peaks, always positive): default auto-scale, zero at the bottom.
let yBounds = {};
const isGeoWaveform = !isHistogram && ch !== 'MicL';
if (isGeoWaveform) {
let absMax = 0;
for (const v of values) {
const a = Math.abs(v);
if (a > absMax) absMax = a;
}
const padded = (absMax || 1) * 1.10;
yBounds = { min: -padded, max: padded };
}
_scCharts[ch] = new Chart(canvas, {
type: isHistogram ? 'bar' : 'line',
data: {
@@ -2709,6 +2727,7 @@ function _renderScWaveform(data) {
grid: { color: '#21262d', drawTicks: showX },
},
y: {
...yBounds,
ticks: { color: '#484f58', maxTicksLimit: 4 },
grid: { color: '#21262d' },
title: { display: true, text: chData.unit || '', color: '#484f58', font: { size: 9 } },
@@ -3072,7 +3091,8 @@ if (currentSection === 'db') {
<h4>Event</h4>
<dl class="sc-grid">
<dt>Serial</dt> <dd id="sc-f-serial"></dd>
<dt>Timestamp</dt> <dd id="sc-f-ts"></dd>
<dt title="When the seismograph recorded this event (from the BW report's Event Time field)">Recorded at</dt>
<dd id="sc-f-ts"></dd>
<dt>Record type</dt> <dd id="sc-f-rt"></dd>
<dt>Sample rate</dt> <dd id="sc-f-sr"></dd>
<dt>Waveform key</dt> <dd id="sc-f-key"></dd>
@@ -3104,7 +3124,8 @@ if (currentSection === 'db') {
<dt id="sc-l-bwsize">File size</dt> <dd id="sc-f-bwsize"></dd>
<dt id="sc-l-sha">File sha256</dt> <dd id="sc-f-sha"></dd>
<dt>Source kind</dt> <dd id="sc-f-src"></dd>
<dt>Captured at</dt> <dd id="sc-f-cap"></dd>
<dt title="When our server received and stored this event (sfm-db insert time, not the recording time)">Received by server at</dt>
<dd id="sc-f-cap"></dd>
</dl>
</div>
<div class="sc-section">