Show current scale if not 1

This commit is contained in:
Matt
2025-12-16 14:48:50 +00:00
parent c18fd152c7
commit 1425930303

View File

@@ -13,6 +13,8 @@ let activeConfig = {
let lowRateState = { let lowRateState = {
accMin: 4096, accMin: 4096,
accMax: 0, accMax: 0,
accSum: 0,
accCount: 0,
progress: 0.0, progress: 0.0,
targetCount: 1.0 targetCount: 1.0
}; };
@@ -78,10 +80,10 @@ let viewTransform = {
// Helper to get total time (width of buffer in ms) // Helper to get total time (width of buffer in ms)
function getTotalTimeMs() { function getTotalTimeMs() {
let msPerPoint; let msPerPoint;
// If we are in low-rate mode (peak detect), we emit 2 points (min/max) // If we are in low-rate mode (peak detect), we emit 1 point (object)
// for every 'targetCount' samples of the hardware rate (which is 1kHz). // for every 'targetCount' samples of the hardware rate (which is 1kHz).
if (activeConfig.desiredRate < 1000) { if (activeConfig.desiredRate < 1000) {
msPerPoint = lowRateState.targetCount / 2.0; msPerPoint = lowRateState.targetCount;
} else { } else {
// Normal mode: 1 point = 1 sample // Normal mode: 1 point = 1 sample
msPerPoint = 1000.0 / activeConfig.desiredRate; msPerPoint = 1000.0 / activeConfig.desiredRate;
@@ -160,6 +162,11 @@ canvas.addEventListener('wheel', function (e) {
} }
viewTransform.scale = newScale; viewTransform.scale = newScale;
if (newScale < 1.001) {
statusEl.textContent = 'Connected via WebSocket';
} else {
statusEl.textContent = 'Scaled to ' + newScale.toFixed(2) + 'x';
}
draw(); draw();
// Update info if frozen to show correct values under cursor // Update info if frozen to show correct values under cursor
@@ -309,7 +316,7 @@ function processData(/** @type Uint16Array */newData) {
pushToBuffer(newData); pushToBuffer(newData);
} else { } else {
// Accumulation mode (Peak Detect) with Fractional Resampling // Accumulation mode (Peak Detect) with Fractional Resampling
let pointsToPush = new Uint16Array(newData.length * 2); // Worst case let pointsToPush = [];
let idx = 0; let idx = 0;
// We add 1.0 "samples worth" of progress for each input sample. // We add 1.0 "samples worth" of progress for each input sample.
@@ -319,29 +326,37 @@ function processData(/** @type Uint16Array */newData) {
for (const val of newData) { for (const val of newData) {
if (val < lowRateState.accMin) lowRateState.accMin = val; if (val < lowRateState.accMin) lowRateState.accMin = val;
if (val > lowRateState.accMax) lowRateState.accMax = val; if (val > lowRateState.accMax) lowRateState.accMax = val;
lowRateState.accSum += val;
lowRateState.accCount++;
lowRateState.progress += 1.0; lowRateState.progress += 1.0;
if (lowRateState.progress >= lowRateState.targetCount) { if (lowRateState.progress >= lowRateState.targetCount) {
// Push min and max to draw a vertical line // Push object with min/max/avg
pointsToPush[idx++] = lowRateState.accMin; const avg = lowRateState.accCount > 0 ? (lowRateState.accSum / lowRateState.accCount) : val;
pointsToPush[idx++] = lowRateState.accMax; pointsToPush.push({
min: lowRateState.accMin,
max: lowRateState.accMax,
avg: avg
});
// Reset Min/Max for next window // Reset Min/Max/Sum for next window
lowRateState.accMin = 4096; lowRateState.accMin = 4096;
lowRateState.accMax = 0; lowRateState.accMax = 0;
lowRateState.accSum = 0;
lowRateState.accCount = 0;
// Subtract one full window's worth of progress // Subtract one full window's worth of progress
lowRateState.progress -= lowRateState.targetCount; lowRateState.progress -= lowRateState.targetCount;
} }
} }
if (idx > 0) { if (pointsToPush.length > 0) {
pushToBuffer(pointsToPush.slice(0, idx)); pushToBuffer(pointsToPush);
} }
} }
} }
function pushToBuffer(/** @type Uint16Array */ newItems) { function pushToBuffer(/** @type Array<number|object> */ newItems) {
if (newItems.length >= countPoints) { if (newItems.length >= countPoints) {
dataBuffer = Array.from(newItems.slice(-countPoints)); dataBuffer = Array.from(newItems.slice(-countPoints));
} else { } else {
@@ -496,16 +511,25 @@ function draw() {
drawIdx = 0; drawIdx = 0;
else { else {
const triggerVal = (4096 - (parseInt(triggerLevel.value) || 2048)); const triggerVal = (4096 - (parseInt(triggerLevel.value) || 2048));
// Helper to extract value for trigger (handles numbers and avg objects)
const getVal = (i) => {
const v = dataBuffer[i];
return (typeof v === 'object' && v !== null) ? v.avg : v;
};
if (triggerLevel.invert) { if (triggerLevel.invert) {
while (drawIdx >= 0) { while (drawIdx >= 0) {
if (dataBuffer[drawIdx] < triggerVal && dataBuffer[drawIdx + 1] > triggerVal) { // Look for falling edge
if (getVal(drawIdx) < triggerVal && getVal(drawIdx + 1) > triggerVal) {
break; break;
} }
drawIdx -= 1; drawIdx -= 1;
} }
} else { } else {
while (drawIdx >= 0) { while (drawIdx >= 0) {
if (dataBuffer[drawIdx] > triggerVal && dataBuffer[drawIdx + 1] < triggerVal) { // Look for rising edge
if (getVal(drawIdx) > triggerVal && getVal(drawIdx + 1) < triggerVal) {
break; break;
} }
drawIdx -= 1; drawIdx -= 1;
@@ -521,18 +545,50 @@ function draw() {
// yp = h - (val / maxAdcVal * h) // yp = h - (val / maxAdcVal * h)
// sy = yp * scale + offsetY // sy = yp * scale + offsetY
// Pass 1: Draw Min/Max ranges for downsampled data
ctx.lineWidth = 1;
ctx.strokeStyle = '#2b7044'; // Dark green
ctx.beginPath(); ctx.beginPath();
// Using loop for continuous line
// To avoid performance hit with huge offsets, we window the loop
dataBuffer.slice(drawIdx).forEach((val, i) => { dataBuffer.slice(drawIdx).forEach((val, i) => {
// Original X pixel position (before zoom) was just 'i' (because buffer size ~ canvas width) // Check if it's an object (downsampled)
// Actually, update buffer size is 'countPoints'. if (typeof val === 'object' && val !== null) {
// Let's assume 'i' is the initial X coordinate. const sx = i * viewTransform.scale + viewTransform.offsetX;
const sx = i * viewTransform.scale + viewTransform.offsetX; const yMin = VoltsToY(YtoVolts(h - (val.min / maxAdcVal * h))); // Convert to Y pixels
// Note: simplified Y calculation:
const yTop = h - (val.max / maxAdcVal * h) * viewTransform.scale + viewTransform.offsetY;
// Wait, simple logic:
// val -> Y pixel:
// yp_raw = h - (raw / maxAdcVal * h)
// yp_screen = yp_raw * scale + offsetY
// Normalized y calculation from original draw const rawYMin = h - (val.min / maxAdcVal * h);
// val is 0..4096. const rawYMax = h - (val.max / maxAdcVal * h);
const yp = h - (val / maxAdcVal * h);
const screenYMin = rawYMin * viewTransform.scale + viewTransform.offsetY;
const screenYMax = rawYMax * viewTransform.scale + viewTransform.offsetY;
ctx.moveTo(sx, screenYMin);
ctx.lineTo(sx, screenYMax);
}
});
ctx.stroke();
// Pass 2: Draw Main Trace (Avg or raw value)
ctx.lineWidth = 2;
ctx.strokeStyle = '#4ade80'; // Bright green
ctx.beginPath();
dataBuffer.slice(drawIdx).forEach((val, i) => {
const sx = i * viewTransform.scale + viewTransform.offsetX;
let rawVal;
if (typeof val === 'object' && val !== null) {
rawVal = val.avg;
} else {
rawVal = val;
}
const yp = h - (rawVal / maxAdcVal * h);
const sy = yp * viewTransform.scale + viewTransform.offsetY; const sy = yp * viewTransform.scale + viewTransform.offsetY;
if (i === 0) ctx.moveTo(sx, sy); if (i === 0) ctx.moveTo(sx, sy);
@@ -577,7 +633,8 @@ function setParams() {
if (res.ok) { if (res.ok) {
lowRateState.accMin = 4096; lowRateState.accMin = 4096;
lowRateState.accMax = 0; lowRateState.accMax = 0;
lowRateState.accMax = 0; lowRateState.accSum = 0;
lowRateState.accCount = 0;
// Update active config // Update active config
activeConfig = { ...payload, desiredRate, trigger: parseInt(triggerLevel.value) || 2048 }; activeConfig = { ...payload, desiredRate, trigger: parseInt(triggerLevel.value) || 2048 };