@zenfg/inspector 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -0
  3. package/dist/FrameGraphInspector.d.ts +153 -0
  4. package/dist/FrameGraphInspector.d.ts.map +1 -0
  5. package/dist/FrameGraphInspector.js +580 -0
  6. package/dist/FrameGraphInspector.js.map +1 -0
  7. package/dist/debugCaptureModel.d.ts +166 -0
  8. package/dist/debugCaptureModel.d.ts.map +1 -0
  9. package/dist/debugCaptureModel.js +364 -0
  10. package/dist/debugCaptureModel.js.map +1 -0
  11. package/dist/index.d.ts +17 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +15 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/panelAliasAnalysis.d.ts +20 -0
  16. package/dist/panelAliasAnalysis.d.ts.map +1 -0
  17. package/dist/panelAliasAnalysis.js +113 -0
  18. package/dist/panelAliasAnalysis.js.map +1 -0
  19. package/dist/panelCytoscapeGraphRenderer.d.ts +71 -0
  20. package/dist/panelCytoscapeGraphRenderer.d.ts.map +1 -0
  21. package/dist/panelCytoscapeGraphRenderer.js +559 -0
  22. package/dist/panelCytoscapeGraphRenderer.js.map +1 -0
  23. package/dist/panelDiagnosticsView.d.ts +22 -0
  24. package/dist/panelDiagnosticsView.d.ts.map +1 -0
  25. package/dist/panelDiagnosticsView.js +123 -0
  26. package/dist/panelDiagnosticsView.js.map +1 -0
  27. package/dist/panelDomHelpers.d.ts +26 -0
  28. package/dist/panelDomHelpers.d.ts.map +1 -0
  29. package/dist/panelDomHelpers.js +129 -0
  30. package/dist/panelDomHelpers.js.map +1 -0
  31. package/dist/panelGraphLayout.d.ts +28 -0
  32. package/dist/panelGraphLayout.d.ts.map +1 -0
  33. package/dist/panelGraphLayout.js +223 -0
  34. package/dist/panelGraphLayout.js.map +1 -0
  35. package/dist/panelGraphRenderer.d.ts +20 -0
  36. package/dist/panelGraphRenderer.d.ts.map +1 -0
  37. package/dist/panelGraphRenderer.js +2 -0
  38. package/dist/panelGraphRenderer.js.map +1 -0
  39. package/dist/panelGraphScene.d.ts +98 -0
  40. package/dist/panelGraphScene.d.ts.map +1 -0
  41. package/dist/panelGraphScene.js +559 -0
  42. package/dist/panelGraphScene.js.map +1 -0
  43. package/dist/panelGraphView.d.ts +9 -0
  44. package/dist/panelGraphView.d.ts.map +1 -0
  45. package/dist/panelGraphView.js +88 -0
  46. package/dist/panelGraphView.js.map +1 -0
  47. package/dist/panelGraphVisuals.d.ts +38 -0
  48. package/dist/panelGraphVisuals.d.ts.map +1 -0
  49. package/dist/panelGraphVisuals.js +330 -0
  50. package/dist/panelGraphVisuals.js.map +1 -0
  51. package/dist/panelIcons.d.ts +4 -0
  52. package/dist/panelIcons.d.ts.map +1 -0
  53. package/dist/panelIcons.js +43 -0
  54. package/dist/panelIcons.js.map +1 -0
  55. package/dist/panelInspectorView.d.ts +33 -0
  56. package/dist/panelInspectorView.d.ts.map +1 -0
  57. package/dist/panelInspectorView.js +357 -0
  58. package/dist/panelInspectorView.js.map +1 -0
  59. package/dist/panelMemoryView.d.ts +21 -0
  60. package/dist/panelMemoryView.d.ts.map +1 -0
  61. package/dist/panelMemoryView.js +134 -0
  62. package/dist/panelMemoryView.js.map +1 -0
  63. package/dist/panelPassesView.d.ts +31 -0
  64. package/dist/panelPassesView.d.ts.map +1 -0
  65. package/dist/panelPassesView.js +183 -0
  66. package/dist/panelPassesView.js.map +1 -0
  67. package/dist/panelResourcesView.d.ts +19 -0
  68. package/dist/panelResourcesView.d.ts.map +1 -0
  69. package/dist/panelResourcesView.js +89 -0
  70. package/dist/panelResourcesView.js.map +1 -0
  71. package/dist/panelSelection.d.ts +5 -0
  72. package/dist/panelSelection.d.ts.map +1 -0
  73. package/dist/panelSelection.js +88 -0
  74. package/dist/panelSelection.js.map +1 -0
  75. package/dist/panelTypes.d.ts +40 -0
  76. package/dist/panelTypes.d.ts.map +1 -0
  77. package/dist/panelTypes.js +2 -0
  78. package/dist/panelTypes.js.map +1 -0
  79. package/dist/panelVisualTheme.d.ts +76 -0
  80. package/dist/panelVisualTheme.d.ts.map +1 -0
  81. package/dist/panelVisualTheme.js +39 -0
  82. package/dist/panelVisualTheme.js.map +1 -0
  83. package/dist/panelWorkbenchHelpers.d.ts +34 -0
  84. package/dist/panelWorkbenchHelpers.d.ts.map +1 -0
  85. package/dist/panelWorkbenchHelpers.js +162 -0
  86. package/dist/panelWorkbenchHelpers.js.map +1 -0
  87. package/dist/panelWorkbenchView.d.ts +77 -0
  88. package/dist/panelWorkbenchView.d.ts.map +1 -0
  89. package/dist/panelWorkbenchView.js +409 -0
  90. package/dist/panelWorkbenchView.js.map +1 -0
  91. package/dist/query.d.ts +11 -0
  92. package/dist/query.d.ts.map +1 -0
  93. package/dist/query.js +21 -0
  94. package/dist/query.js.map +1 -0
  95. package/dist/styles.d.ts +8 -0
  96. package/dist/styles.d.ts.map +1 -0
  97. package/dist/styles.js +1073 -0
  98. package/dist/styles.js.map +1 -0
  99. package/package.json +29 -0
  100. package/src/FrameGraphInspector.ts +632 -0
  101. package/src/debugCaptureModel.ts +583 -0
  102. package/src/index.ts +21 -0
  103. package/src/panelAliasAnalysis.ts +164 -0
  104. package/src/panelCytoscapeGraphRenderer.ts +617 -0
  105. package/src/panelDiagnosticsView.ts +160 -0
  106. package/src/panelDomHelpers.ts +151 -0
  107. package/src/panelGraphLayout.ts +281 -0
  108. package/src/panelGraphRenderer.ts +21 -0
  109. package/src/panelGraphScene.ts +787 -0
  110. package/src/panelGraphView.ts +108 -0
  111. package/src/panelGraphVisuals.ts +364 -0
  112. package/src/panelIcons.ts +56 -0
  113. package/src/panelInspectorView.ts +377 -0
  114. package/src/panelMemoryView.ts +154 -0
  115. package/src/panelPassesView.ts +222 -0
  116. package/src/panelResourcesView.ts +115 -0
  117. package/src/panelSelection.ts +99 -0
  118. package/src/panelTypes.ts +28 -0
  119. package/src/panelVisualTheme.ts +39 -0
  120. package/src/panelWorkbenchHelpers.ts +216 -0
  121. package/src/panelWorkbenchView.ts +465 -0
  122. package/src/query.ts +22 -0
  123. package/src/styles.ts +1076 -0
@@ -0,0 +1,559 @@
1
+ import { applyGraphLayout, layoutGraphScene, syncExpandedGroupLabelGeometry, } from "./panelGraphLayout.js";
2
+ import { selectionKey, } from "./panelGraphScene.js";
3
+ import { createGraphStyles, expandedGroupLabelMaxWidth, GRAPH_GEOMETRY, graphEdgeDisplayLabel, graphLayoutGeometryKey, isOverviewGraphScale, nodeDimensions, } from "./panelGraphVisuals.js";
4
+ export class CytoscapeGraphRenderer {
5
+ host;
6
+ environment;
7
+ canvasHost;
8
+ tooltip;
9
+ status;
10
+ statusMessage;
11
+ retryButton;
12
+ resizeSubscription;
13
+ core;
14
+ elk;
15
+ loading;
16
+ processing;
17
+ latestRequest;
18
+ appliedScene;
19
+ requestVersion = 0;
20
+ processedVersion = 0;
21
+ destroyed = false;
22
+ fitTargetContentKey;
23
+ forceRelayout = false;
24
+ anchorElementId;
25
+ anchorTargetContentKey;
26
+ failedSceneContentKey;
27
+ overview = false;
28
+ lastTap;
29
+ constructor(host, environment = browserGraphRendererEnvironment) {
30
+ this.host = host;
31
+ this.environment = environment;
32
+ this.canvasHost = environment.createElement('div');
33
+ this.canvasHost.className = 'zenfg-inspector-graph-canvas';
34
+ this.tooltip = environment.createElement('div');
35
+ this.tooltip.className = 'zenfg-inspector-graph-tooltip';
36
+ this.tooltip.hidden = true;
37
+ this.status = environment.createElement('div');
38
+ this.status.className = 'zenfg-inspector-graph-status';
39
+ this.status.hidden = true;
40
+ this.status.setAttribute('role', 'status');
41
+ this.status.setAttribute('aria-live', 'polite');
42
+ this.statusMessage = environment.createElement('span');
43
+ this.retryButton = environment.createElement('button');
44
+ this.retryButton.type = 'button';
45
+ this.retryButton.textContent = 'Retry';
46
+ this.retryButton.hidden = true;
47
+ this.retryButton.addEventListener('click', () => this.relayout());
48
+ this.status.append(this.statusMessage, this.retryButton);
49
+ this.host.replaceChildren(this.canvasHost, this.status, this.tooltip);
50
+ this.resizeSubscription = environment.observeResize?.(host, () => this.core?.resize());
51
+ }
52
+ render(request) {
53
+ if (this.destroyed)
54
+ return;
55
+ this.latestRequest = request;
56
+ if (request.fit) {
57
+ this.fitTargetContentKey = request.scene.contentKey;
58
+ }
59
+ else if (this.fitTargetContentKey !== request.scene.contentKey) {
60
+ this.fitTargetContentKey = undefined;
61
+ }
62
+ if (request.anchorElementId !== undefined) {
63
+ this.anchorElementId = request.anchorElementId;
64
+ this.anchorTargetContentKey = request.scene.contentKey;
65
+ }
66
+ else if (this.anchorTargetContentKey !== request.scene.contentKey) {
67
+ this.anchorElementId = undefined;
68
+ this.anchorTargetContentKey = undefined;
69
+ }
70
+ if (this.failedSceneContentKey && this.failedSceneContentKey !== request.scene.contentKey) {
71
+ this.failedSceneContentKey = undefined;
72
+ this.hideStatus();
73
+ }
74
+ const version = ++this.requestVersion;
75
+ if (this.failedSceneContentKey === request.scene.contentKey) {
76
+ this.syncInteraction(request);
77
+ this.processedVersion = version;
78
+ return;
79
+ }
80
+ if (!this.processing && this.core && this.appliedScene?.contentKey === request.scene.contentKey && !this.forceRelayout) {
81
+ this.appliedScene = request.scene;
82
+ this.syncInteraction(request);
83
+ this.consumeFitIfCurrentTarget();
84
+ this.consumeAnchorIfCurrentTarget();
85
+ this.processedVersion = version;
86
+ return;
87
+ }
88
+ this.scheduleProcessing();
89
+ }
90
+ resize() {
91
+ this.core?.resize();
92
+ }
93
+ fit() {
94
+ const targetContentKey = this.latestRequest?.scene.contentKey;
95
+ if (targetContentKey)
96
+ this.fitTargetContentKey = targetContentKey;
97
+ if (!this.core || !this.appliedScene)
98
+ return;
99
+ this.core.resize();
100
+ this.core.fit(undefined, GRAPH_GEOMETRY.fitPadding);
101
+ this.updateSemanticZoom();
102
+ if (!this.targetNeedsApply())
103
+ this.fitTargetContentKey = undefined;
104
+ }
105
+ relayout() {
106
+ if (!this.latestRequest || this.destroyed)
107
+ return;
108
+ this.failedSceneContentKey = undefined;
109
+ this.forceRelayout = true;
110
+ this.fitTargetContentKey = this.latestRequest.scene.contentKey;
111
+ this.anchorElementId = undefined;
112
+ this.anchorTargetContentKey = undefined;
113
+ this.hideTooltip();
114
+ ++this.requestVersion;
115
+ this.scheduleProcessing();
116
+ }
117
+ destroy() {
118
+ if (this.destroyed)
119
+ return;
120
+ this.destroyed = true;
121
+ this.requestVersion++;
122
+ this.resizeSubscription?.disconnect();
123
+ this.hideTooltip();
124
+ this.core?.destroy();
125
+ this.core = undefined;
126
+ this.elk = undefined;
127
+ this.loading = undefined;
128
+ this.latestRequest = undefined;
129
+ this.appliedScene = undefined;
130
+ this.fitTargetContentKey = undefined;
131
+ this.anchorElementId = undefined;
132
+ this.anchorTargetContentKey = undefined;
133
+ this.host.replaceChildren();
134
+ }
135
+ scheduleProcessing() {
136
+ if (this.processing || this.destroyed)
137
+ return;
138
+ this.processing = this.processRequests().finally(() => {
139
+ this.processing = undefined;
140
+ if (!this.destroyed
141
+ && !this.failedSceneContentKey
142
+ && this.processedVersion !== this.requestVersion) {
143
+ this.scheduleProcessing();
144
+ }
145
+ });
146
+ }
147
+ async processRequests() {
148
+ while (!this.destroyed && this.processedVersion !== this.requestVersion) {
149
+ let version = this.requestVersion;
150
+ let request = this.latestRequest;
151
+ if (!request)
152
+ return;
153
+ if (request.scene.nodes.length === 0) {
154
+ this.hideTooltip();
155
+ if (this.core)
156
+ replaceElements(this.core, request.scene);
157
+ this.appliedScene = request.scene;
158
+ this.forceRelayout = false;
159
+ if (this.fitTargetContentKey === request.scene.contentKey)
160
+ this.fitTargetContentKey = undefined;
161
+ this.consumeAnchorIfCurrentTarget();
162
+ this.syncInteraction(request);
163
+ this.showStatus('empty', 'No graph elements in this view.');
164
+ this.processedVersion = version;
165
+ continue;
166
+ }
167
+ try {
168
+ if (!this.core)
169
+ this.showStatus('loading', 'Loading graph runtime…');
170
+ await this.ensureRuntime();
171
+ const runtimeRequest = this.resolveCurrentRequest(version, request.scene.contentKey);
172
+ if (!runtimeRequest)
173
+ continue;
174
+ ({ version, request } = runtimeRequest);
175
+ const core = this.core;
176
+ if (this.appliedScene?.contentKey === request.scene.contentKey && !this.forceRelayout) {
177
+ this.appliedScene = request.scene;
178
+ this.syncInteraction(request);
179
+ this.consumeFitIfCurrentTarget();
180
+ this.consumeAnchorIfCurrentTarget();
181
+ this.hideStatus();
182
+ this.processedVersion = version;
183
+ continue;
184
+ }
185
+ this.hideTooltip();
186
+ const previousViewport = viewport(core);
187
+ const anchorElementId = this.anchorTargetContentKey === request.scene.contentKey
188
+ ? this.anchorElementId
189
+ : undefined;
190
+ const anchorBefore = anchorElementId === undefined
191
+ ? undefined
192
+ : renderedPosition(core, anchorElementId);
193
+ const topologyChanged = this.appliedScene?.topologyKey !== request.scene.topologyKey;
194
+ const geometryChanged = !this.appliedScene
195
+ || graphLayoutGeometryKey(this.appliedScene) !== graphLayoutGeometryKey(request.scene);
196
+ let laidOut = false;
197
+ if (geometryChanged || this.forceRelayout) {
198
+ this.showStatus('layout', 'Laying out graph…');
199
+ const result = await this.environment.layoutScene(this.elk, request.scene);
200
+ const layoutRequest = this.resolveCurrentRequest(version, request.scene.contentKey);
201
+ if (!layoutRequest)
202
+ continue;
203
+ ({ version, request } = layoutRequest);
204
+ if (topologyChanged || !this.appliedScene)
205
+ replaceElements(core, request.scene);
206
+ else
207
+ updateElementData(core, request.scene);
208
+ applyGraphLayout(core, request.scene, result);
209
+ laidOut = true;
210
+ }
211
+ else {
212
+ updateElementData(core, request.scene);
213
+ }
214
+ syncExpandedGroupLabelGeometry(core);
215
+ this.appliedScene = request.scene;
216
+ this.forceRelayout = false;
217
+ this.failedSceneContentKey = undefined;
218
+ this.syncInteraction(request);
219
+ core.resize();
220
+ if (this.fitTargetContentKey === request.scene.contentKey) {
221
+ core.fit(undefined, GRAPH_GEOMETRY.fitPadding);
222
+ this.fitTargetContentKey = undefined;
223
+ }
224
+ else if (laidOut && anchorBefore && anchorElementId) {
225
+ restoreViewport(core, previousViewport);
226
+ const anchorAfter = renderedPosition(core, anchorElementId);
227
+ if (anchorAfter)
228
+ core.panBy({ x: anchorBefore.x - anchorAfter.x, y: anchorBefore.y - anchorAfter.y });
229
+ }
230
+ else {
231
+ restoreViewport(core, previousViewport);
232
+ }
233
+ this.consumeAnchorIfCurrentTarget();
234
+ this.updateSemanticZoom(true);
235
+ this.hideStatus();
236
+ this.processedVersion = version;
237
+ }
238
+ catch (error) {
239
+ const failedRequest = this.resolveCurrentRequest(version, request.scene.contentKey);
240
+ if (!failedRequest)
241
+ continue;
242
+ ({ version, request } = failedRequest);
243
+ this.forceRelayout = false;
244
+ this.failedSceneContentKey = request.scene.contentKey;
245
+ this.processedVersion = version;
246
+ this.showStatus('error', `Failed to render graph: ${error instanceof Error ? error.message : String(error)}`, true);
247
+ return;
248
+ }
249
+ }
250
+ }
251
+ async ensureRuntime() {
252
+ if (this.core || this.destroyed)
253
+ return;
254
+ this.loading ??= this.loadRuntime().catch((error) => {
255
+ this.loading = undefined;
256
+ throw error;
257
+ });
258
+ await this.loading;
259
+ }
260
+ async loadRuntime() {
261
+ const runtime = await this.environment.loadRuntime();
262
+ if (this.destroyed)
263
+ return;
264
+ this.canvasHost.textContent = '';
265
+ this.elk = runtime.elk;
266
+ this.core = runtime.createCore({
267
+ container: this.canvasHost,
268
+ elements: [],
269
+ style: createGraphStyles(),
270
+ layout: { name: 'preset' },
271
+ minZoom: 0.03,
272
+ maxZoom: 4,
273
+ boxSelectionEnabled: false,
274
+ autoungrabify: true,
275
+ autounselectify: true,
276
+ });
277
+ this.bindEvents(this.core);
278
+ }
279
+ bindEvents(core) {
280
+ const selectElement = (event) => {
281
+ const request = this.interactiveRequest();
282
+ if (!request)
283
+ return;
284
+ const id = event.target.id();
285
+ const selection = request.scene.interaction.selectionByElementId.get(id);
286
+ if (selection)
287
+ request.onSelect(selection);
288
+ const now = performance.now();
289
+ if (this.lastTap?.id === id && now - this.lastTap.at <= 350 && selection?.kind === 'group') {
290
+ request.onToggleGroup(selection.pathKey);
291
+ this.lastTap = undefined;
292
+ }
293
+ else {
294
+ this.lastTap = { id, at: now };
295
+ }
296
+ };
297
+ core.on('tap', 'node', selectElement);
298
+ core.on('tap', 'edge', selectElement);
299
+ core.on('tap', (event) => {
300
+ if (event.target === core)
301
+ this.lastTap = undefined;
302
+ });
303
+ const hoverElement = (event) => {
304
+ const request = this.interactiveRequest();
305
+ if (!request)
306
+ return;
307
+ const id = event.target.id();
308
+ const selection = request.scene.interaction.selectionByElementId.get(id);
309
+ if (selection)
310
+ request.onHover(selection);
311
+ const title = event.target.data('tooltip');
312
+ if (title) {
313
+ this.tooltip.textContent = title;
314
+ this.tooltip.hidden = false;
315
+ this.positionTooltip(event.renderedPosition);
316
+ }
317
+ };
318
+ core.on('mouseover', 'node', hoverElement);
319
+ core.on('mouseover', 'edge', hoverElement);
320
+ const moveTooltip = (event) => this.positionTooltip(event.renderedPosition);
321
+ core.on('mousemove', 'node', moveTooltip);
322
+ core.on('mousemove', 'edge', moveTooltip);
323
+ const clearHover = () => {
324
+ this.hideTooltip();
325
+ this.latestRequest?.onHover(undefined);
326
+ };
327
+ core.on('mouseout', 'node', clearHover);
328
+ core.on('mouseout', 'edge', clearHover);
329
+ core.on('zoom', () => this.updateSemanticZoom());
330
+ }
331
+ interactiveRequest() {
332
+ const request = this.latestRequest;
333
+ return request && this.appliedScene?.contentKey === request.scene.contentKey ? request : undefined;
334
+ }
335
+ syncInteraction(request) {
336
+ const core = this.core;
337
+ if (!core || this.appliedScene?.topologyKey !== request.scene.topologyKey)
338
+ return;
339
+ core.batch(() => {
340
+ core.elements().removeClass('semantic-selected semantic-hover');
341
+ if (request.hovered) {
342
+ for (const id of request.scene.interaction.relatedElementIdsBySelection.get(selectionKey(request.hovered)) ?? []) {
343
+ core.getElementById(id).addClass('semantic-hover');
344
+ }
345
+ }
346
+ if (request.selected) {
347
+ for (const id of request.scene.interaction.primaryElementIdsBySelection.get(selectionKey(request.selected)) ?? []) {
348
+ core.getElementById(id).addClass('semantic-selected');
349
+ }
350
+ }
351
+ });
352
+ }
353
+ consumeFitIfCurrentTarget() {
354
+ const targetContentKey = this.latestRequest?.scene.contentKey;
355
+ if (!targetContentKey
356
+ || this.fitTargetContentKey !== targetContentKey
357
+ || !this.core
358
+ || this.targetNeedsApply())
359
+ return;
360
+ this.core.resize();
361
+ this.core.fit(undefined, GRAPH_GEOMETRY.fitPadding);
362
+ this.fitTargetContentKey = undefined;
363
+ this.updateSemanticZoom();
364
+ }
365
+ consumeAnchorIfCurrentTarget() {
366
+ const targetContentKey = this.latestRequest?.scene.contentKey;
367
+ if (!targetContentKey || this.anchorTargetContentKey !== targetContentKey)
368
+ return;
369
+ this.anchorElementId = undefined;
370
+ this.anchorTargetContentKey = undefined;
371
+ }
372
+ targetNeedsApply() {
373
+ const target = this.latestRequest?.scene;
374
+ if (!target || !this.appliedScene)
375
+ return target !== undefined;
376
+ return this.forceRelayout || this.appliedScene.contentKey !== target.contentKey;
377
+ }
378
+ updateSemanticZoom(force = false) {
379
+ const core = this.core;
380
+ if (!core)
381
+ return;
382
+ const overview = isOverviewGraphScale(core.zoom());
383
+ if (!force && overview === this.overview)
384
+ return;
385
+ this.overview = overview;
386
+ core.batch(() => {
387
+ for (const node of core.nodes()) {
388
+ node.data('displayLabel', overview ? node.data('overviewLabel') : node.data('detailLabel'));
389
+ }
390
+ for (const edge of core.edges()) {
391
+ edge.data('displayLabel', overview ? '' : edge.data('detailLabel'));
392
+ }
393
+ });
394
+ }
395
+ positionTooltip(position) {
396
+ const maxX = Math.max(8, this.host.clientWidth - this.tooltip.offsetWidth - 8);
397
+ const maxY = Math.max(8, this.host.clientHeight - this.tooltip.offsetHeight - 8);
398
+ this.tooltip.style.left = `${Math.max(8, Math.min(maxX, position.x + 12))}px`;
399
+ this.tooltip.style.top = `${Math.max(8, Math.min(maxY, position.y + 12))}px`;
400
+ }
401
+ hideTooltip() {
402
+ this.tooltip.hidden = true;
403
+ this.tooltip.textContent = '';
404
+ this.lastTap = undefined;
405
+ }
406
+ showStatus(kind, message, retry = false) {
407
+ this.status.dataset.state = kind;
408
+ this.statusMessage.textContent = message;
409
+ this.retryButton.hidden = !retry;
410
+ this.status.hidden = false;
411
+ this.host.setAttribute('aria-busy', kind === 'loading' || kind === 'layout' ? 'true' : 'false');
412
+ }
413
+ hideStatus() {
414
+ this.status.hidden = true;
415
+ this.retryButton.hidden = true;
416
+ this.host.setAttribute('aria-busy', 'false');
417
+ }
418
+ resolveCurrentRequest(version, contentKey) {
419
+ if (this.destroyed)
420
+ return undefined;
421
+ const request = this.latestRequest;
422
+ if (!request)
423
+ return undefined;
424
+ if (version === this.requestVersion || request.scene.contentKey === contentKey) {
425
+ return { version: this.requestVersion, request };
426
+ }
427
+ return undefined;
428
+ }
429
+ }
430
+ const browserGraphRendererEnvironment = {
431
+ createElement: (tagName) => document.createElement(tagName),
432
+ loadRuntime: async () => {
433
+ const [cytoscapeModule, elkModule] = await Promise.all([
434
+ import('cytoscape'),
435
+ import('elkjs/lib/elk.bundled.js'),
436
+ ]);
437
+ return {
438
+ createCore: cytoscapeModule.default,
439
+ elk: new elkModule.default(),
440
+ };
441
+ },
442
+ layoutScene: layoutGraphScene,
443
+ observeResize: (element, onResize) => {
444
+ if (typeof ResizeObserver === 'undefined')
445
+ return { disconnect: () => undefined };
446
+ const view = element.ownerDocument.defaultView;
447
+ let animationFrame;
448
+ const observer = new ResizeObserver(() => {
449
+ if (!view || animationFrame !== undefined)
450
+ return;
451
+ animationFrame = view.requestAnimationFrame(() => {
452
+ animationFrame = undefined;
453
+ onResize();
454
+ });
455
+ });
456
+ observer.observe(element);
457
+ return {
458
+ disconnect: () => {
459
+ observer.disconnect();
460
+ if (animationFrame !== undefined) {
461
+ view?.cancelAnimationFrame(animationFrame);
462
+ animationFrame = undefined;
463
+ }
464
+ },
465
+ };
466
+ },
467
+ };
468
+ function replaceElements(core, scene) {
469
+ const definitions = [
470
+ ...scene.nodes.map(nodeDefinition),
471
+ ...scene.edges.map(edgeDefinition),
472
+ ];
473
+ core.startBatch();
474
+ core.elements().remove();
475
+ core.add(definitions);
476
+ core.endBatch();
477
+ }
478
+ export function updateElementData(core, scene) {
479
+ core.batch(() => {
480
+ for (const node of scene.nodes) {
481
+ const element = core.getElementById(node.id);
482
+ if (element.nonempty())
483
+ element.data(nodeRenderableData(node));
484
+ }
485
+ for (const edge of scene.edges) {
486
+ const element = core.getElementById(edge.id);
487
+ if (element.nonempty())
488
+ element.data(edgeRenderableData(edge));
489
+ }
490
+ });
491
+ }
492
+ function nodeDefinition(node) {
493
+ return {
494
+ group: 'nodes',
495
+ data: {
496
+ id: node.id,
497
+ parent: node.parentId,
498
+ ...nodeRenderableData(node),
499
+ },
500
+ };
501
+ }
502
+ function nodeRenderableData(node) {
503
+ const dimensions = nodeDimensions(node);
504
+ const labelMaxWidth = node.kind === 'group' && node.collapsed
505
+ ? expandedGroupLabelMaxWidth(dimensions.width)
506
+ : 160;
507
+ return {
508
+ kind: node.kind,
509
+ passKind: node.kind === 'pass' || node.kind === 'culled-pass' ? node.passKind : undefined,
510
+ resourceKind: node.kind === 'resource' ? node.resourceKind : undefined,
511
+ collapsed: node.kind === 'group' && node.collapsed ? 1 : 0,
512
+ hasCulled: node.kind === 'group' && node.culledNodeCount > 0 ? 1 : 0,
513
+ depthBand: node.kind === 'group' ? node.depthBand : undefined,
514
+ detailLabel: node.label,
515
+ overviewLabel: node.overviewLabel,
516
+ displayLabel: node.label,
517
+ tooltip: node.title,
518
+ labelMaxWidth,
519
+ width: dimensions.width,
520
+ height: dimensions.height,
521
+ };
522
+ }
523
+ function edgeDefinition(edge) {
524
+ return {
525
+ group: 'edges',
526
+ data: {
527
+ id: edge.id,
528
+ source: edge.from,
529
+ target: edge.to,
530
+ ...edgeRenderableData(edge),
531
+ },
532
+ };
533
+ }
534
+ function edgeRenderableData(edge) {
535
+ const detailLabel = graphEdgeDisplayLabel(edge);
536
+ return {
537
+ kind: edge.kind,
538
+ dependencyKind: edge.kind === 'dependency' ? edge.dependencyKind : undefined,
539
+ accessMode: edge.kind === 'access' ? edge.accessMode : undefined,
540
+ dashed: edge.kind === 'access' && edge.dashed ? 1 : 0,
541
+ detailLabel,
542
+ displayLabel: detailLabel,
543
+ tooltip: edge.title,
544
+ };
545
+ }
546
+ function viewport(core) {
547
+ return { pan: { ...core.pan() }, zoom: core.zoom() };
548
+ }
549
+ function restoreViewport(core, state) {
550
+ core.zoom(state.zoom);
551
+ core.pan(state.pan);
552
+ }
553
+ function renderedPosition(core, id) {
554
+ const element = core.getElementById(id);
555
+ return element.nonempty() && element.isNode() ? { ...element.renderedPosition() } : undefined;
556
+ }
557
+ export { createCytoscapeEdgeRouteData, createElkLayoutGraph, layoutGraphScene, } from "./panelGraphLayout.js";
558
+ export { createGraphStyles, expandedGroupLabelMaxWidth, graphEdgeDisplayLabel, graphLayoutGeometryKey, isOverviewGraphScale, } from "./panelGraphVisuals.js";
559
+ //# sourceMappingURL=panelCytoscapeGraphRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panelCytoscapeGraphRenderer.js","sourceRoot":"","sources":["../src/panelCytoscapeGraphRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import type cytoscape from 'cytoscape';\nimport type { ELK } from 'elkjs/lib/elk-api';\n\nimport type { GraphRenderer, GraphRenderRequest } from './panelGraphRenderer.ts';\nimport {\n applyGraphLayout,\n layoutGraphScene,\n syncExpandedGroupLabelGeometry,\n type GraphLayoutResult,\n type GraphPosition,\n} from './panelGraphLayout.ts';\nimport {\n selectionKey,\n type GraphScene,\n type GraphSceneEdge,\n type GraphSceneElementId,\n type GraphSceneNode,\n} from './panelGraphScene.ts';\nimport {\n createGraphStyles,\n expandedGroupLabelMaxWidth,\n GRAPH_GEOMETRY,\n graphEdgeDisplayLabel,\n graphLayoutGeometryKey,\n isOverviewGraphScale,\n nodeDimensions,\n} from './panelGraphVisuals.ts';\n\ntype Viewport = { readonly pan: GraphPosition; readonly zoom: number };\n\ntype GraphRendererRuntime = {\n readonly createCore: (options: cytoscape.CytoscapeOptions) => cytoscape.Core;\n readonly elk: ELK;\n};\n\nexport type GraphResizeSubscription = { disconnect(): void };\n\nexport type GraphRendererEnvironment = {\n readonly createElement: (tagName: string) => HTMLElement;\n readonly loadRuntime: () => Promise<GraphRendererRuntime>;\n readonly layoutScene: (elk: ELK, scene: GraphScene) => Promise<GraphLayoutResult>;\n readonly observeResize?: (element: HTMLElement, onResize: () => void) => GraphResizeSubscription;\n};\n\nexport class CytoscapeGraphRenderer implements GraphRenderer {\n private readonly canvasHost: HTMLElement;\n private readonly tooltip: HTMLElement;\n private readonly status: HTMLElement;\n private readonly statusMessage: HTMLElement;\n private readonly retryButton: HTMLButtonElement;\n private readonly resizeSubscription: GraphResizeSubscription | undefined;\n private core: cytoscape.Core | undefined;\n private elk: ELK | undefined;\n private loading: Promise<void> | undefined;\n private processing: Promise<void> | undefined;\n private latestRequest: GraphRenderRequest | undefined;\n private appliedScene: GraphScene | undefined;\n private requestVersion = 0;\n private processedVersion = 0;\n private destroyed = false;\n private fitTargetContentKey: string | undefined;\n private forceRelayout = false;\n private anchorElementId: GraphSceneElementId | undefined;\n private anchorTargetContentKey: string | undefined;\n private failedSceneContentKey: string | undefined;\n private overview = false;\n private lastTap: { readonly id: string; readonly at: number } | undefined;\n\n constructor(\n private readonly host: HTMLElement,\n private readonly environment: GraphRendererEnvironment = browserGraphRendererEnvironment,\n ) {\n this.canvasHost = environment.createElement('div');\n this.canvasHost.className = 'zenfg-inspector-graph-canvas';\n this.tooltip = environment.createElement('div');\n this.tooltip.className = 'zenfg-inspector-graph-tooltip';\n this.tooltip.hidden = true;\n this.status = environment.createElement('div');\n this.status.className = 'zenfg-inspector-graph-status';\n this.status.hidden = true;\n this.status.setAttribute('role', 'status');\n this.status.setAttribute('aria-live', 'polite');\n this.statusMessage = environment.createElement('span');\n this.retryButton = environment.createElement('button') as HTMLButtonElement;\n this.retryButton.type = 'button';\n this.retryButton.textContent = 'Retry';\n this.retryButton.hidden = true;\n this.retryButton.addEventListener('click', () => this.relayout());\n this.status.append(this.statusMessage, this.retryButton);\n this.host.replaceChildren(this.canvasHost, this.status, this.tooltip);\n this.resizeSubscription = environment.observeResize?.(host, () => this.core?.resize());\n }\n\n render(request: GraphRenderRequest): void {\n if (this.destroyed) return;\n this.latestRequest = request;\n if (request.fit) {\n this.fitTargetContentKey = request.scene.contentKey;\n } else if (this.fitTargetContentKey !== request.scene.contentKey) {\n this.fitTargetContentKey = undefined;\n }\n if (request.anchorElementId !== undefined) {\n this.anchorElementId = request.anchorElementId;\n this.anchorTargetContentKey = request.scene.contentKey;\n } else if (this.anchorTargetContentKey !== request.scene.contentKey) {\n this.anchorElementId = undefined;\n this.anchorTargetContentKey = undefined;\n }\n if (this.failedSceneContentKey && this.failedSceneContentKey !== request.scene.contentKey) {\n this.failedSceneContentKey = undefined;\n this.hideStatus();\n }\n\n const version = ++this.requestVersion;\n if (this.failedSceneContentKey === request.scene.contentKey) {\n this.syncInteraction(request);\n this.processedVersion = version;\n return;\n }\n if (!this.processing && this.core && this.appliedScene?.contentKey === request.scene.contentKey && !this.forceRelayout) {\n this.appliedScene = request.scene;\n this.syncInteraction(request);\n this.consumeFitIfCurrentTarget();\n this.consumeAnchorIfCurrentTarget();\n this.processedVersion = version;\n return;\n }\n this.scheduleProcessing();\n }\n\n resize(): void {\n this.core?.resize();\n }\n\n fit(): void {\n const targetContentKey = this.latestRequest?.scene.contentKey;\n if (targetContentKey) this.fitTargetContentKey = targetContentKey;\n if (!this.core || !this.appliedScene) return;\n this.core.resize();\n this.core.fit(undefined, GRAPH_GEOMETRY.fitPadding);\n this.updateSemanticZoom();\n if (!this.targetNeedsApply()) this.fitTargetContentKey = undefined;\n }\n\n relayout(): void {\n if (!this.latestRequest || this.destroyed) return;\n this.failedSceneContentKey = undefined;\n this.forceRelayout = true;\n this.fitTargetContentKey = this.latestRequest.scene.contentKey;\n this.anchorElementId = undefined;\n this.anchorTargetContentKey = undefined;\n this.hideTooltip();\n ++this.requestVersion;\n this.scheduleProcessing();\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.requestVersion++;\n this.resizeSubscription?.disconnect();\n this.hideTooltip();\n this.core?.destroy();\n this.core = undefined;\n this.elk = undefined;\n this.loading = undefined;\n this.latestRequest = undefined;\n this.appliedScene = undefined;\n this.fitTargetContentKey = undefined;\n this.anchorElementId = undefined;\n this.anchorTargetContentKey = undefined;\n this.host.replaceChildren();\n }\n\n private scheduleProcessing(): void {\n if (this.processing || this.destroyed) return;\n this.processing = this.processRequests().finally(() => {\n this.processing = undefined;\n if (!this.destroyed\n && !this.failedSceneContentKey\n && this.processedVersion !== this.requestVersion) {\n this.scheduleProcessing();\n }\n });\n }\n\n private async processRequests(): Promise<void> {\n while (!this.destroyed && this.processedVersion !== this.requestVersion) {\n let version = this.requestVersion;\n let request = this.latestRequest;\n if (!request) return;\n\n if (request.scene.nodes.length === 0) {\n this.hideTooltip();\n if (this.core) replaceElements(this.core, request.scene);\n this.appliedScene = request.scene;\n this.forceRelayout = false;\n if (this.fitTargetContentKey === request.scene.contentKey) this.fitTargetContentKey = undefined;\n this.consumeAnchorIfCurrentTarget();\n this.syncInteraction(request);\n this.showStatus('empty', 'No graph elements in this view.');\n this.processedVersion = version;\n continue;\n }\n\n try {\n if (!this.core) this.showStatus('loading', 'Loading graph runtime…');\n await this.ensureRuntime();\n const runtimeRequest = this.resolveCurrentRequest(version, request.scene.contentKey);\n if (!runtimeRequest) continue;\n ({ version, request } = runtimeRequest);\n const core = this.core!;\n if (this.appliedScene?.contentKey === request.scene.contentKey && !this.forceRelayout) {\n this.appliedScene = request.scene;\n this.syncInteraction(request);\n this.consumeFitIfCurrentTarget();\n this.consumeAnchorIfCurrentTarget();\n this.hideStatus();\n this.processedVersion = version;\n continue;\n }\n\n this.hideTooltip();\n const previousViewport = viewport(core);\n const anchorElementId = this.anchorTargetContentKey === request.scene.contentKey\n ? this.anchorElementId\n : undefined;\n const anchorBefore = anchorElementId === undefined\n ? undefined\n : renderedPosition(core, anchorElementId);\n const topologyChanged = this.appliedScene?.topologyKey !== request.scene.topologyKey;\n const geometryChanged = !this.appliedScene\n || graphLayoutGeometryKey(this.appliedScene) !== graphLayoutGeometryKey(request.scene);\n let laidOut = false;\n\n if (geometryChanged || this.forceRelayout) {\n this.showStatus('layout', 'Laying out graph…');\n const result = await this.environment.layoutScene(this.elk!, request.scene);\n const layoutRequest = this.resolveCurrentRequest(version, request.scene.contentKey);\n if (!layoutRequest) continue;\n ({ version, request } = layoutRequest);\n if (topologyChanged || !this.appliedScene) replaceElements(core, request.scene);\n else updateElementData(core, request.scene);\n applyGraphLayout(core, request.scene, result);\n laidOut = true;\n } else {\n updateElementData(core, request.scene);\n }\n\n syncExpandedGroupLabelGeometry(core);\n this.appliedScene = request.scene;\n this.forceRelayout = false;\n this.failedSceneContentKey = undefined;\n this.syncInteraction(request);\n core.resize();\n if (this.fitTargetContentKey === request.scene.contentKey) {\n core.fit(undefined, GRAPH_GEOMETRY.fitPadding);\n this.fitTargetContentKey = undefined;\n } else if (laidOut && anchorBefore && anchorElementId) {\n restoreViewport(core, previousViewport);\n const anchorAfter = renderedPosition(core, anchorElementId);\n if (anchorAfter) core.panBy({ x: anchorBefore.x - anchorAfter.x, y: anchorBefore.y - anchorAfter.y });\n } else {\n restoreViewport(core, previousViewport);\n }\n this.consumeAnchorIfCurrentTarget();\n this.updateSemanticZoom(true);\n this.hideStatus();\n this.processedVersion = version;\n } catch (error) {\n const failedRequest = this.resolveCurrentRequest(version, request.scene.contentKey);\n if (!failedRequest) continue;\n ({ version, request } = failedRequest);\n this.forceRelayout = false;\n this.failedSceneContentKey = request.scene.contentKey;\n this.processedVersion = version;\n this.showStatus(\n 'error',\n `Failed to render graph: ${error instanceof Error ? error.message : String(error)}`,\n true,\n );\n return;\n }\n }\n }\n\n private async ensureRuntime(): Promise<void> {\n if (this.core || this.destroyed) return;\n this.loading ??= this.loadRuntime().catch((error) => {\n this.loading = undefined;\n throw error;\n });\n await this.loading;\n }\n\n private async loadRuntime(): Promise<void> {\n const runtime = await this.environment.loadRuntime();\n if (this.destroyed) return;\n this.canvasHost.textContent = '';\n this.elk = runtime.elk;\n this.core = runtime.createCore({\n container: this.canvasHost,\n elements: [],\n style: createGraphStyles(),\n layout: { name: 'preset' },\n minZoom: 0.03,\n maxZoom: 4,\n boxSelectionEnabled: false,\n autoungrabify: true,\n autounselectify: true,\n });\n this.bindEvents(this.core);\n }\n\n private bindEvents(core: cytoscape.Core): void {\n const selectElement = (event: cytoscape.EventObject) => {\n const request = this.interactiveRequest();\n if (!request) return;\n const id = event.target.id() as GraphSceneElementId;\n const selection = request.scene.interaction.selectionByElementId.get(id);\n if (selection) request.onSelect(selection);\n const now = performance.now();\n if (this.lastTap?.id === id && now - this.lastTap.at <= 350 && selection?.kind === 'group') {\n request.onToggleGroup(selection.pathKey);\n this.lastTap = undefined;\n } else {\n this.lastTap = { id, at: now };\n }\n };\n core.on('tap', 'node', selectElement);\n core.on('tap', 'edge', selectElement);\n core.on('tap', (event) => {\n if (event.target === core) this.lastTap = undefined;\n });\n const hoverElement = (event: cytoscape.EventObject) => {\n const request = this.interactiveRequest();\n if (!request) return;\n const id = event.target.id() as GraphSceneElementId;\n const selection = request.scene.interaction.selectionByElementId.get(id);\n if (selection) request.onHover(selection);\n const title = event.target.data('tooltip') as string | undefined;\n if (title) {\n this.tooltip.textContent = title;\n this.tooltip.hidden = false;\n this.positionTooltip(event.renderedPosition);\n }\n };\n core.on('mouseover', 'node', hoverElement);\n core.on('mouseover', 'edge', hoverElement);\n const moveTooltip = (event: cytoscape.EventObject) => this.positionTooltip(event.renderedPosition);\n core.on('mousemove', 'node', moveTooltip);\n core.on('mousemove', 'edge', moveTooltip);\n const clearHover = () => {\n this.hideTooltip();\n this.latestRequest?.onHover(undefined);\n };\n core.on('mouseout', 'node', clearHover);\n core.on('mouseout', 'edge', clearHover);\n core.on('zoom', () => this.updateSemanticZoom());\n }\n\n private interactiveRequest(): GraphRenderRequest | undefined {\n const request = this.latestRequest;\n return request && this.appliedScene?.contentKey === request.scene.contentKey ? request : undefined;\n }\n\n private syncInteraction(request: GraphRenderRequest): void {\n const core = this.core;\n if (!core || this.appliedScene?.topologyKey !== request.scene.topologyKey) return;\n core.batch(() => {\n core.elements().removeClass('semantic-selected semantic-hover');\n if (request.hovered) {\n for (const id of request.scene.interaction.relatedElementIdsBySelection.get(selectionKey(request.hovered)) ?? []) {\n core.getElementById(id).addClass('semantic-hover');\n }\n }\n if (request.selected) {\n for (const id of request.scene.interaction.primaryElementIdsBySelection.get(selectionKey(request.selected)) ?? []) {\n core.getElementById(id).addClass('semantic-selected');\n }\n }\n });\n }\n\n private consumeFitIfCurrentTarget(): void {\n const targetContentKey = this.latestRequest?.scene.contentKey;\n if (!targetContentKey\n || this.fitTargetContentKey !== targetContentKey\n || !this.core\n || this.targetNeedsApply()) return;\n this.core.resize();\n this.core.fit(undefined, GRAPH_GEOMETRY.fitPadding);\n this.fitTargetContentKey = undefined;\n this.updateSemanticZoom();\n }\n\n private consumeAnchorIfCurrentTarget(): void {\n const targetContentKey = this.latestRequest?.scene.contentKey;\n if (!targetContentKey || this.anchorTargetContentKey !== targetContentKey) return;\n this.anchorElementId = undefined;\n this.anchorTargetContentKey = undefined;\n }\n\n private targetNeedsApply(): boolean {\n const target = this.latestRequest?.scene;\n if (!target || !this.appliedScene) return target !== undefined;\n return this.forceRelayout || this.appliedScene.contentKey !== target.contentKey;\n }\n\n private updateSemanticZoom(force = false): void {\n const core = this.core;\n if (!core) return;\n const overview = isOverviewGraphScale(core.zoom());\n if (!force && overview === this.overview) return;\n this.overview = overview;\n core.batch(() => {\n for (const node of core.nodes()) {\n node.data('displayLabel', overview ? node.data('overviewLabel') : node.data('detailLabel'));\n }\n for (const edge of core.edges()) {\n edge.data('displayLabel', overview ? '' : edge.data('detailLabel'));\n }\n });\n }\n\n private positionTooltip(position: GraphPosition): void {\n const maxX = Math.max(8, this.host.clientWidth - this.tooltip.offsetWidth - 8);\n const maxY = Math.max(8, this.host.clientHeight - this.tooltip.offsetHeight - 8);\n this.tooltip.style.left = `${Math.max(8, Math.min(maxX, position.x + 12))}px`;\n this.tooltip.style.top = `${Math.max(8, Math.min(maxY, position.y + 12))}px`;\n }\n\n private hideTooltip(): void {\n this.tooltip.hidden = true;\n this.tooltip.textContent = '';\n this.lastTap = undefined;\n }\n\n private showStatus(kind: 'loading' | 'layout' | 'empty' | 'error', message: string, retry = false): void {\n this.status.dataset.state = kind;\n this.statusMessage.textContent = message;\n this.retryButton.hidden = !retry;\n this.status.hidden = false;\n this.host.setAttribute('aria-busy', kind === 'loading' || kind === 'layout' ? 'true' : 'false');\n }\n\n private hideStatus(): void {\n this.status.hidden = true;\n this.retryButton.hidden = true;\n this.host.setAttribute('aria-busy', 'false');\n }\n\n private resolveCurrentRequest(\n version: number,\n contentKey: string,\n ): { readonly version: number; readonly request: GraphRenderRequest } | undefined {\n if (this.destroyed) return undefined;\n const request = this.latestRequest;\n if (!request) return undefined;\n if (version === this.requestVersion || request.scene.contentKey === contentKey) {\n return { version: this.requestVersion, request };\n }\n return undefined;\n }\n}\n\nconst browserGraphRendererEnvironment: GraphRendererEnvironment = {\n createElement: (tagName) => document.createElement(tagName),\n loadRuntime: async () => {\n const [cytoscapeModule, elkModule] = await Promise.all([\n import('cytoscape'),\n import('elkjs/lib/elk.bundled.js'),\n ]);\n return {\n createCore: cytoscapeModule.default,\n elk: new elkModule.default(),\n };\n },\n layoutScene: layoutGraphScene,\n observeResize: (element, onResize) => {\n if (typeof ResizeObserver === 'undefined') return { disconnect: () => undefined };\n const view = element.ownerDocument.defaultView;\n let animationFrame: number | undefined;\n const observer = new ResizeObserver(() => {\n if (!view || animationFrame !== undefined) return;\n animationFrame = view.requestAnimationFrame(() => {\n animationFrame = undefined;\n onResize();\n });\n });\n observer.observe(element);\n return {\n disconnect: () => {\n observer.disconnect();\n if (animationFrame !== undefined) {\n view?.cancelAnimationFrame(animationFrame);\n animationFrame = undefined;\n }\n },\n };\n },\n};\n\nfunction replaceElements(core: cytoscape.Core, scene: GraphScene): void {\n const definitions: cytoscape.ElementDefinition[] = [\n ...scene.nodes.map(nodeDefinition),\n ...scene.edges.map(edgeDefinition),\n ];\n core.startBatch();\n core.elements().remove();\n core.add(definitions);\n core.endBatch();\n}\n\nexport function updateElementData(core: cytoscape.Core, scene: GraphScene): void {\n core.batch(() => {\n for (const node of scene.nodes) {\n const element = core.getElementById(node.id);\n if (element.nonempty()) element.data(nodeRenderableData(node));\n }\n for (const edge of scene.edges) {\n const element = core.getElementById(edge.id);\n if (element.nonempty()) element.data(edgeRenderableData(edge));\n }\n });\n}\n\nfunction nodeDefinition(node: GraphSceneNode): cytoscape.ElementDefinition {\n return {\n group: 'nodes',\n data: {\n id: node.id,\n parent: node.parentId,\n ...nodeRenderableData(node),\n },\n };\n}\n\nfunction nodeRenderableData(node: GraphSceneNode): Record<string, unknown> {\n const dimensions = nodeDimensions(node);\n const labelMaxWidth = node.kind === 'group' && node.collapsed\n ? expandedGroupLabelMaxWidth(dimensions.width)\n : 160;\n return {\n kind: node.kind,\n passKind: node.kind === 'pass' || node.kind === 'culled-pass' ? node.passKind : undefined,\n resourceKind: node.kind === 'resource' ? node.resourceKind : undefined,\n collapsed: node.kind === 'group' && node.collapsed ? 1 : 0,\n hasCulled: node.kind === 'group' && node.culledNodeCount > 0 ? 1 : 0,\n depthBand: node.kind === 'group' ? node.depthBand : undefined,\n detailLabel: node.label,\n overviewLabel: node.overviewLabel,\n displayLabel: node.label,\n tooltip: node.title,\n labelMaxWidth,\n width: dimensions.width,\n height: dimensions.height,\n };\n}\n\nfunction edgeDefinition(edge: GraphSceneEdge): cytoscape.ElementDefinition {\n return {\n group: 'edges',\n data: {\n id: edge.id,\n source: edge.from,\n target: edge.to,\n ...edgeRenderableData(edge),\n },\n };\n}\n\nfunction edgeRenderableData(edge: GraphSceneEdge): Record<string, unknown> {\n const detailLabel = graphEdgeDisplayLabel(edge);\n return {\n kind: edge.kind,\n dependencyKind: edge.kind === 'dependency' ? edge.dependencyKind : undefined,\n accessMode: edge.kind === 'access' ? edge.accessMode : undefined,\n dashed: edge.kind === 'access' && edge.dashed ? 1 : 0,\n detailLabel,\n displayLabel: detailLabel,\n tooltip: edge.title,\n };\n}\n\nfunction viewport(core: cytoscape.Core): Viewport {\n return { pan: { ...core.pan() }, zoom: core.zoom() };\n}\n\nfunction restoreViewport(core: cytoscape.Core, state: Viewport): void {\n core.zoom(state.zoom);\n core.pan(state.pan);\n}\n\nfunction renderedPosition(core: cytoscape.Core, id: GraphSceneElementId): GraphPosition | undefined {\n const element = core.getElementById(id);\n return element.nonempty() && element.isNode() ? { ...element.renderedPosition() } : undefined;\n}\n\nexport {\n createCytoscapeEdgeRouteData,\n createElkLayoutGraph,\n layoutGraphScene,\n} from './panelGraphLayout.ts';\nexport type {\n CytoscapeEdgeRouteData,\n GraphEdgeRoute,\n GraphLayoutResult,\n GraphPosition,\n} from './panelGraphLayout.ts';\nexport {\n createGraphStyles,\n expandedGroupLabelMaxWidth,\n graphEdgeDisplayLabel,\n graphLayoutGeometryKey,\n isOverviewGraphScale,\n} from './panelGraphVisuals.ts';\n"]}