(visibleIds: Set<string>)
| 1120 | } |
| 1121 | |
| 1122 | setNodeVisibility(visibleIds: Set<string>): void { |
| 1123 | // Detect whether the visible set actually changed (Fix #38). The |
| 1124 | // wiring effect in PixiGraphCanvas re-fires this on every Louvain |
| 1125 | // rerun because `communityData.assignments` is in its dep list — |
| 1126 | // but the resulting visible-id set is usually identical (Louvain |
| 1127 | // renames communities, doesn't change which nodes pass the |
| 1128 | // filter). Treating every fire as a real change re-culled the |
| 1129 | // labels, which the user sees as random label churn while physics |
| 1130 | // is running. |
| 1131 | let changed = false; |
| 1132 | for (const node of this.nodes.values()) { |
| 1133 | const vis = visibleIds.has(node.id); |
| 1134 | if (node.visible !== vis) { |
| 1135 | changed = true; |
| 1136 | break; |
| 1137 | } |
| 1138 | } |
| 1139 | if (!changed) return; |
| 1140 | |
| 1141 | for (const [id, node] of this.nodes) { |
| 1142 | const vis = visibleIds.has(id); |
| 1143 | node.visible = vis; |
| 1144 | node.sprite.visible = vis; |
| 1145 | // Hide labels for hidden nodes; visible nodes get re-culled below |
| 1146 | if (!vis && node.label) node.label.visible = false; |
| 1147 | } |
| 1148 | // Re-cull labels for the new visible set |
| 1149 | if (this.showAllLabels) { |
| 1150 | const lblInv = this.labelInvScale(); |
| 1151 | const wantLabel: PixiNode[] = []; |
| 1152 | for (const node of this.nodes.values()) { |
| 1153 | if (node.visible) wantLabel.push(node); |
| 1154 | } |
| 1155 | this.applyLabelCulling(wantLabel, lblInv); |
| 1156 | } |
| 1157 | // A real visibility change (e.g. hiding/un-hiding a community via |
| 1158 | // `hiddenCommunities`) can leave a wayfinder label floating over a |
| 1159 | // now-empty community. Mask the labels to the current node |
| 1160 | // visibility so a fully-hidden community's label drops out — and |
| 1161 | // reappears when un-hidden. This deliberately does NOT re-run the |
| 1162 | // overlap cull: the cull decision depends only on geometry, and |
| 1163 | // re-packing here would let a neighbour steal the freed slot (or |
| 1164 | // evict several unrelated labels), none of which return on un-hide. |
| 1165 | this.applyCommunityLabelVisibility(); |
| 1166 | if (!this.mode3d) { |
| 1167 | this.redrawAllEdges(); |
| 1168 | } |
| 1169 | } |
| 1170 | |
| 1171 | updateNodeColors(nodeColors: Map<string, string>): void { |
| 1172 | if (!this.app) return; |
no test coverage detected