Răsfoiți Sursa

web topo: cluster chips render as the topmost SVG layer with opaque fill; down state mutes saturation instead of alpha (no frame border shows through badges)

Alexander Korolev 1 lună în urmă
părinte
comite
23c8fb202f
1 a modificat fișierele cu 9 adăugiri și 8 ștergeri
  1. 9 8
      src/web/ui.html

+ 9 - 8
src/web/ui.html

@@ -330,7 +330,7 @@
   #topo .cluster-frame:hover .frame { stroke-width: 2.2; }
   #topo .fchip { cursor: pointer; }
   #topo .fchip:hover rect { stroke-width: 2; }
-  #topo .fchip.down rect, #topo .fchip.down text { opacity: .55; }
+  #topo .fchip.down { filter: saturate(.5); }
   #topo .frame { stroke-width: 1.5; transition: opacity .4s; }
   #topo .cluster-frame.down .frame { stroke-dasharray: 5 4; opacity: .5; }
   #topo .fchip rect { fill: var(--panel); stroke-width: 1.2; }
@@ -927,11 +927,11 @@ function topoFrames(snap) {
   for (const r of rects) {
     state.topoGroupTitles[r.g.clusters[0].name] = r.g.clusters.map((c) => c.name).join(" · ");
   }
-  // pass 1: frame rectangles (all of them first — no frame edge ever
-  // crosses a chip); pass 2: chips on top
-  let out = "";
+  // two layers: frame rects (below cables/devices) and chips (topmost —
+  // opaque badges, nothing shows through, always clickable)
+  let frames = "", chips = "";
   for (const r of rects) {
-    out += `<g class="cluster-frame" data-cluster="${esc(r.g.clusters[0].name)}">
+    frames += `<g class="cluster-frame" data-cluster="${esc(r.g.clusters[0].name)}">
     <title>${esc(r.g.clusters.map((c) => c.name).join(" · "))}</title>
     <rect class="frame" style="stroke:${r.hue};fill:color-mix(in srgb, ${r.hue} 6%, transparent)"
       x="${r.x}" y="${r.y}" width="${r.w}" height="${r.h}" rx="14"/>
@@ -940,7 +940,7 @@ function topoFrames(snap) {
   for (const r of rects) {
     for (const c of r.g.clusters) {
       const chip = bands.get(r.y).find((x) => x.c === c);
-      out += `<g class="fchip" data-cluster="${esc(c.name)}" transform="translate(${chip.x},${r.y - 8})">
+      chips += `<g class="fchip" data-cluster="${esc(c.name)}" transform="translate(${chip.x},${r.y - 8})">
       <title>${esc(c.name)}</title>
       <rect width="${chip.cw}" height="16" rx="8" style="stroke:${c._hue}"/>
       <circle class="cdot" cx="10" cy="8" r="3.5"/>
@@ -948,7 +948,7 @@ function topoFrames(snap) {
     </g>`;
     }
   }
-  return out;
+  return { frames, chips };
 }
 
 function cablesSvg(t) {
@@ -1062,8 +1062,9 @@ function renderTopo(snap) {
   const sig = topoSig(t);
   if (state.topoSig !== sig) {
     state.topoSig = sig;
+    const tf = topoFrames(snap);
     host.innerHTML = `<svg viewBox="0 0 ${TG_W} ${TG_H}" preserveAspectRatio="xMidYMid meet">
-      ${topoFrames(snap)}${cablesSvg(t)}${switchesSvg(t)}${devsSvg(t)}${legendSvg()}
+      ${tf.frames}${cablesSvg(t)}${switchesSvg(t)}${devsSvg(t)}${legendSvg()}${tf.chips}
     </svg>`;
     for (const g of host.querySelectorAll("[data-cluster]")) {
       g.onclick = () => {