diff --git a/Client/WebUI/hub.go b/Client/WebUI/hub.go index 81b7e2f..bddab8c 100644 --- a/Client/WebUI/hub.go +++ b/Client/WebUI/hub.go @@ -328,7 +328,7 @@ func buildSourcesMsg(sm map[string]*sourceHubState) []byte { // Run is the hub's main goroutine. Must be started with go hub.Run(). func (h *Hub) Run() { - ticker := time.NewTicker(time.Second / 20) + ticker := time.NewTicker(time.Second / 30) defer ticker.Stop() statsTicker := time.NewTicker(time.Second) diff --git a/Client/WebUI/static/app.js b/Client/WebUI/static/app.js index a4cfe12..df0e311 100644 --- a/Client/WebUI/static/app.js +++ b/Client/WebUI/static/app.js @@ -1965,18 +1965,20 @@ function renderDirtyPlots() { // via setScale instead of rebuilding all data arrays (much cheaper). if (!trig.enabled && !globalPause) { plots.forEach(p => { - if (!p.uplot || p.xRange) return; + if (!p.uplot || p.xRange || p.traces.length === 0) return; p.needsRedraw = true; }); } plots.forEach(p => { - if (!p.needsRedraw || !p.uplot) return; + if (!p.needsRedraw || !p.uplot || p.traces.length === 0) return; const inTrigModeNow = trig.enabled && trig.snapshot !== null; const isRolling = !trig.enabled && !p.xRange; - // Fast path: rolling-window plot with no new data — just shift viewport. + // Fast path: rolling-window plot with no new data — just shift viewport + // anchored to buffer timestamps so the x-range only advances when + // signal data actually moves forward. if (isRolling && _dataGen === p.lastDataGen && p.uplot.data && p.uplot.data[0] && p.uplot.data[0].length > 0) { p.needsRedraw = false; zoomGuard = true;