Spaces:
Running
Running
| /** | |
| * Reliable node/edge inspector: wire Cytoscape mouseover + tap to inspector-focus-store. | |
| * Complements dash-cytoscape props (clearOnUnhover=false) for fewer missed hovers. | |
| */ | |
| (function () { | |
| function isLiveCy(cy) { | |
| return cy && typeof cy.destroyed === "function" && !cy.destroyed(); | |
| } | |
| function cyOf(el) { | |
| if (!el) return null; | |
| if (isLiveCy(el._cytoscape)) return el._cytoscape; | |
| // cytoscape.js registers the live instance on its container as _cyreg.cy | |
| if (el._cyreg && isLiveCy(el._cyreg.cy)) return el._cyreg.cy; | |
| return null; | |
| } | |
| function findCy(host) { | |
| if (!host) return null; | |
| let cy = cyOf(host); | |
| if (cy) return cy; | |
| for (const el of host.querySelectorAll("div")) { | |
| cy = cyOf(el); | |
| if (cy) return cy; | |
| } | |
| return null; | |
| } | |
| function setInspector(data) { | |
| if ( | |
| window.dash_clientside && | |
| typeof window.dash_clientside.set_props === "function" | |
| ) { | |
| window.dash_clientside.set_props("inspector-focus-store", { data: data }); | |
| } | |
| } | |
| function wireGraph(host) { | |
| const cy = findCy(host); | |
| if (!cy) return false; | |
| if (host.__infoBridgeCy === cy) return true; | |
| host.__infoBridgeCy = cy; | |
| cy.on("mouseover", "node, edge", (evt) => { | |
| if (evt.target === cy) return; | |
| setInspector(evt.target.data()); | |
| }); | |
| cy.on("tap", "node, edge", (evt) => { | |
| if (evt.target === cy) return; | |
| setInspector(evt.target.data()); | |
| }); | |
| return true; | |
| } | |
| function boot() { | |
| const host = document.getElementById("graph"); | |
| if (!host) return; | |
| if (!wireGraph(host)) { | |
| host.__infoBridgeCy = null; | |
| } | |
| } | |
| if (document.readyState === "loading") { | |
| document.addEventListener("DOMContentLoaded", boot); | |
| } else { | |
| boot(); | |
| } | |
| setInterval(boot, 800); | |
| })(); | |