Bladeren bron

Web: synchronize sparkline hover highlight across all trend charts

When hovering over a sparkline chart, the hover point is now drawn
simultaneously on all other trend charts at the same relative time
position. The tooltip, however, is shown only for the chart under
the cursor to avoid visual noise.

Implementation: store _updateHover and _points directly on each
canvas element after binding. On mousemove/touchstart, compute a
normalized position fraction (0..1) and broadcast it to all canvases
inside #statsTrends via querySelectorAll, translating the fraction
to each chart's own point index. On mouseleave/touchend, reset the
hover state on all canvases. The showTooltip parameter added to
updateHover controls whether the tooltip is updated, defaulting to
true to preserve existing behavior.
Valentin V. Bartenev 3 maanden geleden
bovenliggende
commit
3a81dcf69b
1 gewijzigde bestanden met toevoegingen van 26 en 7 verwijderingen
  1. 26 7
      src/helpers/web/WebPanelServer.cpp

+ 26 - 7
src/helpers/web/WebPanelServer.cpp

@@ -1965,8 +1965,9 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
     function bindSparkHover(canvas, points, key) {
     function bindSparkHover(canvas, points, key) {
       const tooltip = document.getElementById("tooltip-" + key);
       const tooltip = document.getElementById("tooltip-" + key);
       if (!canvas || !tooltip || !Array.isArray(points) || points.length < 1) return;
       if (!canvas || !tooltip || !Array.isArray(points) || points.length < 1) return;
-      const updateHover = (index) => {
+      const updateHover = (index, showTooltip = true) => {
         drawSparkline(canvas, points, key, index);
         drawSparkline(canvas, points, key, index);
+        if (!showTooltip) return;
         if (index == null || index < 0 || index >= points.length) {
         if (index == null || index < 0 || index >= points.length) {
           tooltip.textContent = "";
           tooltip.textContent = "";
           tooltip.classList.remove("visible");
           tooltip.classList.remove("visible");
@@ -1979,24 +1980,42 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
         }
         }
         tooltip.classList.add("visible");
         tooltip.classList.add("visible");
       };
       };
+      canvas._updateHover = updateHover;
+      canvas._points = points;
       canvas.onmousemove = (event) => {
       canvas.onmousemove = (event) => {
         const rect = canvas.getBoundingClientRect();
         const rect = canvas.getBoundingClientRect();
         const width = rect.width || 1;
         const width = rect.width || 1;
         const x = Math.max(0, Math.min(width, event.clientX - rect.left));
         const x = Math.max(0, Math.min(width, event.clientX - rect.left));
-        const index = Math.max(0, Math.min(points.length - 1, Math.round((x / width) * (points.length - 1))));
-        updateHover(index);
+        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.onmouseleave = () => {
+        document.querySelectorAll('#statsTrends canvas').forEach(c => {
+          if (c._updateHover) c._updateHover(null, c === canvas);
+        });
       };
       };
-      canvas.onmouseleave = () => updateHover(null);
       canvas.ontouchstart = (event) => {
       canvas.ontouchstart = (event) => {
         const touch = event.touches && event.touches[0];
         const touch = event.touches && event.touches[0];
         if (!touch) return;
         if (!touch) return;
         const rect = canvas.getBoundingClientRect();
         const rect = canvas.getBoundingClientRect();
         const width = rect.width || 1;
         const width = rect.width || 1;
         const x = Math.max(0, Math.min(width, touch.clientX - rect.left));
         const x = Math.max(0, Math.min(width, touch.clientX - rect.left));
-        const index = Math.max(0, Math.min(points.length - 1, Math.round((x / width) * (points.length - 1))));
-        updateHover(index);
+        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);
+        });
       };
       };
-      canvas.ontouchend = () => updateHover(null);
     }
     }
     function setTrendCardState(key, title, value) {
     function setTrendCardState(key, title, value) {
       const card = document.getElementById("trend-" + key);
       const card = document.getElementById("trend-" + key);