Web: sync graph hover by timestamp instead of relative position
When hovering over a sparkline, the same X fraction was applied to all other canvases to compute the highlighted point index. Because different series can have different numbers of valid samples (some values are filtered out), the same fraction mapped to different indices and therefore different timestamps on each graph. Fix by reading the uptime_secs timestamp (point[0]) of the hovered point on the source canvas and finding the closest-timestamp point in each other series, instead of using the fractional position. Also de-duplicate the near-identical onmousemove/ontouchstart and onmouseleave/ontouchend handlers into syncHoverByX() and syncHoverClear() helpers, reducing the block from 34 lines to 16.
This commit is contained in:
@@ -1998,40 +1998,28 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
|||||||
};
|
};
|
||||||
canvas._updateHover = updateHover;
|
canvas._updateHover = updateHover;
|
||||||
canvas._points = points;
|
canvas._points = points;
|
||||||
canvas.onmousemove = (event) => {
|
function syncHoverByX(srcCanvas, clientX) {
|
||||||
const rect = canvas.getBoundingClientRect();
|
const rect = srcCanvas.getBoundingClientRect();
|
||||||
const width = rect.width || 1;
|
const x = Math.max(0, Math.min(rect.width || 1, clientX - rect.left));
|
||||||
const x = Math.max(0, Math.min(width, event.clientX - rect.left));
|
const srcIdx = Math.max(0, Math.min(points.length - 1, Math.round(x / (rect.width || 1) * (points.length - 1))));
|
||||||
const fraction = x / width;
|
const hoveredTs = points[srcIdx][0];
|
||||||
document.querySelectorAll('#statsTrends canvas').forEach(c => {
|
document.querySelectorAll('#statsTrends canvas').forEach(c => {
|
||||||
if (!c._updateHover || !c._points) return;
|
if (!c._updateHover || !c._points) return;
|
||||||
const idx = Math.max(0, Math.min(c._points.length - 1, Math.round(fraction * (c._points.length - 1))));
|
if (c === srcCanvas) { c._updateHover(srcIdx, true); return; }
|
||||||
c._updateHover(idx, c === canvas);
|
let bestIdx = 0, bestDiff = Infinity;
|
||||||
|
c._points.forEach((pt, i) => { const d = Math.abs(pt[0] - hoveredTs); if (d < bestDiff) { bestDiff = d; bestIdx = i; } });
|
||||||
|
c._updateHover(bestIdx, false);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
canvas.onmouseleave = () => {
|
function syncHoverClear(srcCanvas) {
|
||||||
document.querySelectorAll('#statsTrends canvas').forEach(c => {
|
document.querySelectorAll('#statsTrends canvas').forEach(c => {
|
||||||
if (c._updateHover) c._updateHover(null, c === canvas);
|
if (c._updateHover) c._updateHover(null, c === srcCanvas);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
canvas.ontouchstart = (event) => {
|
canvas.onmousemove = (e) => syncHoverByX(canvas, e.clientX);
|
||||||
const touch = event.touches && event.touches[0];
|
canvas.onmouseleave = () => syncHoverClear(canvas);
|
||||||
if (!touch) return;
|
canvas.ontouchstart = (e) => { const t = e.touches && e.touches[0]; if (t) syncHoverByX(canvas, t.clientX); };
|
||||||
const rect = canvas.getBoundingClientRect();
|
canvas.ontouchend = () => syncHoverClear(canvas);
|
||||||
const width = rect.width || 1;
|
|
||||||
const x = Math.max(0, Math.min(width, touch.clientX - rect.left));
|
|
||||||
const fraction = x / width;
|
|
||||||
document.querySelectorAll('#statsTrends canvas').forEach(c => {
|
|
||||||
if (!c._updateHover || !c._points) return;
|
|
||||||
const idx = Math.max(0, Math.min(c._points.length - 1, Math.round(fraction * (c._points.length - 1))));
|
|
||||||
c._updateHover(idx, c === canvas);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
canvas.ontouchend = () => {
|
|
||||||
document.querySelectorAll('#statsTrends canvas').forEach(c => {
|
|
||||||
if (c._updateHover) c._updateHover(null, c === canvas);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
function setTrendCardState(key, title, value) {
|
function setTrendCardState(key, title, value) {
|
||||||
const card = document.getElementById("trend-" + key);
|
const card = document.getElementById("trend-" + key);
|
||||||
|
|||||||
Reference in New Issue
Block a user