Show current scale if not 1
This commit is contained in:
@@ -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 };
|
||||||
|
|||||||
Reference in New Issue
Block a user