()
| 1410 | } |
| 1411 | |
| 1412 | private redrawAllEdges(): void { |
| 1413 | if (!this.edgeBgGfx || !this.edgeFgGfx) return; |
| 1414 | |
| 1415 | this.edgeBgGfx.clear(); |
| 1416 | this.edgeFgGfx.clear(); |
| 1417 | |
| 1418 | if (!this.edgesEnabled) return; |
| 1419 | |
| 1420 | const bgAlpha = this.hasHighlight |
| 1421 | ? EDGE_OPACITY_DIMMED |
| 1422 | : EDGE_OPACITY_DEFAULT; |
| 1423 | const edgeWidth = 0.5 * this.zoomInvScale(); |
| 1424 | const doCull = this.bp.edgeViewportCulling; |
| 1425 | |
| 1426 | // Draw background edges using pre-computed color groups |
| 1427 | for (const [color, indices] of this.edgeColorGroups) { |
| 1428 | let drawn = false; |
| 1429 | for (const i of indices) { |
| 1430 | const e = this.edges[i]; |
| 1431 | if (this.hiddenLinkTypes.has(e.label)) continue; |
| 1432 | const s = this.nodes.get(e.sourceId); |
| 1433 | const t = this.nodes.get(e.targetId); |
| 1434 | if (!s?.visible || !t?.visible) continue; |
| 1435 | // Viewport culling: skip edges where both endpoints are off-screen. |
| 1436 | // Note: this can miss edges that cross the viewport diagonally (both endpoints |
| 1437 | // outside but the line segment passes through). A full segment-rect intersection |
| 1438 | // test is more expensive; this heuristic is sufficient for layout animation. |
| 1439 | if ( |
| 1440 | doCull && |
| 1441 | !this.isInViewport(s.x, s.y) && |
| 1442 | !this.isInViewport(t.x, t.y) |
| 1443 | ) |
| 1444 | continue; |
| 1445 | this.drawEdge(this.edgeBgGfx, s.x, s.y, t.x, t.y); |
| 1446 | drawn = true; |
| 1447 | } |
| 1448 | if (drawn) { |
| 1449 | this.edgeBgGfx.stroke({ |
| 1450 | width: edgeWidth, |
| 1451 | color: hexToNum(color), |
| 1452 | alpha: bgAlpha, |
| 1453 | }); |
| 1454 | } |
| 1455 | } |
| 1456 | |
| 1457 | // Foreground highlight edges |
| 1458 | if (this.hasHighlight) { |
| 1459 | const hlColorGroups = new Map< |
| 1460 | string, |
| 1461 | { sx: number; sy: number; tx: number; ty: number }[] |
| 1462 | >(); |
| 1463 | for (let i = 0; i < this.edges.length; i++) { |
| 1464 | const e = this.edges[i]; |
| 1465 | if (this.hiddenLinkTypes.has(e.label)) continue; |
| 1466 | const linkKey = `${e.sourceId}-${e.targetId}`; |
| 1467 | if (!this.highlightLinks.has(linkKey)) continue; |
| 1468 | const s = this.nodes.get(e.sourceId); |
| 1469 | const t = this.nodes.get(e.targetId); |
no test coverage detected