@jbrowse/bandage-core 9.0.0 → 9.2.0

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 (69) hide show
  1. package/dist/bubbles/bubbleHalos.js +9 -5
  2. package/dist/bubbles/bubbleLine.js +3 -1
  3. package/dist/bubbles/bubblesFromGraph.js +8 -4
  4. package/dist/bubbles/classifyBubble.js +2 -2
  5. package/dist/bubbles/superbubbles.js +21 -0
  6. package/dist/chunks/{chunk-ISEI2FH3.js → chunk-2AWUWGAD.js} +10 -4
  7. package/dist/chunks/{chunk-YOYLCLIG.js → chunk-2ZT7ZF7A.js} +6 -2
  8. package/dist/chunks/{chunk-LLP3FXPM.js → chunk-75HR3756.js} +24 -7
  9. package/dist/chunks/{chunk-FFFQNQUI.js → chunk-A4MYLGKG.js} +1 -1
  10. package/dist/chunks/chunk-B4645SM2.js +358 -0
  11. package/dist/chunks/chunk-B4YH42OP.js +24 -0
  12. package/dist/chunks/{chunk-6VBDMZBZ.js → chunk-BLRJ6IGK.js} +1 -1
  13. package/dist/chunks/{chunk-SKKYLBRA.js → chunk-BV64PQ2C.js} +1 -1
  14. package/dist/chunks/{chunk-W253V6RR.js → chunk-CVYDR2OP.js} +1 -1
  15. package/dist/chunks/{chunk-AMS3MAFP.js → chunk-FM6XRXPX.js} +1 -1
  16. package/dist/chunks/{chunk-MFKORG3F.js → chunk-FX4RDMDN.js} +5 -1
  17. package/dist/chunks/{chunk-MIW3HYPE.js → chunk-GFRPX6M2.js} +2 -2
  18. package/dist/chunks/{chunk-4S47XRYA.js → chunk-GOZYKNQ2.js} +16 -11
  19. package/dist/chunks/{chunk-TLQ7F2ZT.js → chunk-HOOVOF2Y.js} +21 -21
  20. package/dist/chunks/{chunk-MBB7ATM6.js → chunk-LFKMASER.js} +1 -1
  21. package/dist/chunks/{chunk-6ZNQJ5ZD.js → chunk-OXTR3BVF.js} +1 -1
  22. package/dist/chunks/{chunk-WDTXW7T2.js → chunk-UD5FOCI2.js} +1 -1
  23. package/dist/chunks/{chunk-2WNBVB55.js → chunk-WBCOREDZ.js} +121 -74
  24. package/dist/chunks/{chunk-TL4B342F.js → chunk-XKM5OHQQ.js} +1 -1
  25. package/dist/chunks/{chunk-WOO7QYKB.js → chunk-XKWD2RY3.js} +8 -2
  26. package/dist/chunks/{chunk-DPV2CUIE.js → chunk-XPT66H6H.js} +1 -1
  27. package/dist/chunks/chunk-ZDJDM77V.js +273 -0
  28. package/dist/cli/figure.js +26 -26
  29. package/dist/cli/fold.js +72 -0
  30. package/dist/figure.js +16 -16
  31. package/dist/figureSettings.js +4 -4
  32. package/dist/foldVariants.js +9 -0
  33. package/dist/gfa/writeRgfa.js +6 -0
  34. package/dist/index.js +84 -74
  35. package/dist/layout/forceCache.js +4 -4
  36. package/dist/layout/trimToWindow.js +13 -0
  37. package/dist/layout/walkRowDraw.js +4 -4
  38. package/dist/layout/walkStrip.js +5 -5
  39. package/dist/layoutModes.js +2 -2
  40. package/dist/pipeline.js +3 -3
  41. package/dist/referenceRampCss.js +3 -3
  42. package/dist/referenceStrip.js +3 -3
  43. package/dist/renderer/Canvas2DRenderer.js +1 -1
  44. package/dist/renderer/GeometryBuilder.js +2 -2
  45. package/dist/renderer/recordingCanvas.js +12 -1
  46. package/dist/tubeMap/connectors.js +3 -1
  47. package/dist/tubeMap/draw.js +3 -1
  48. package/dist/tubeMap/nodeColors.js +3 -3
  49. package/dist/types/bubbles/bubbleHalos.d.ts +2 -0
  50. package/dist/types/bubbles/bubbleLine.d.ts +3 -0
  51. package/dist/types/bubbles/bubblesFromGraph.d.ts +12 -2
  52. package/dist/types/bubbles/superbubbles.d.ts +5 -0
  53. package/dist/types/cli/fold.d.ts +1 -0
  54. package/dist/types/foldVariants.d.ts +2 -0
  55. package/dist/types/gfa/writeRgfa.d.ts +2 -0
  56. package/dist/types/index.d.ts +3 -2
  57. package/dist/types/layout/trimToWindow.d.ts +4 -0
  58. package/dist/types/renderer/Canvas2DRenderer.d.ts +6 -3
  59. package/dist/types/tubeMap/connectors.d.ts +1 -0
  60. package/dist/types/tubeMap/draw.d.ts +1 -0
  61. package/dist/types/version.d.ts +1 -1
  62. package/dist/version.js +1 -1
  63. package/dist/viewport.js +4 -4
  64. package/dist/walkEncoding.js +3 -3
  65. package/dist/walkHighlight.js +4 -4
  66. package/package.json +3 -2
  67. package/dist/chunks/{chunk-HBEKUQO4.js → chunk-BR25DGIJ.js} +4 -4
  68. package/dist/chunks/{chunk-WNUZP3WQ.js → chunk-M7SRZJ32.js} +3 -3
  69. package/dist/chunks/{chunk-5OIVTEF7.js → chunk-ZGRYFUXE.js} +7 -7
@@ -1,11 +1,15 @@
1
1
  import {
2
- bubbleHalos
3
- } from "../chunks/chunk-ISEI2FH3.js";
4
- import "../chunks/chunk-WOO7QYKB.js";
5
- import "../chunks/chunk-MFKORG3F.js";
2
+ WHOLE_FRACTION,
3
+ bubbleHalos,
4
+ coversGraph
5
+ } from "../chunks/chunk-2AWUWGAD.js";
6
+ import "../chunks/chunk-XKWD2RY3.js";
7
+ import "../chunks/chunk-FX4RDMDN.js";
6
8
  import "../chunks/chunk-2CVHXFK7.js";
7
9
  import "../chunks/chunk-CPMHA4W5.js";
8
10
  import "../chunks/chunk-FYQWPEEY.js";
9
11
  export {
10
- bubbleHalos
12
+ WHOLE_FRACTION,
13
+ bubbleHalos,
14
+ coversGraph
11
15
  };
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  SATURATED_PATH_COUNT,
3
3
  bubbleDescription,
4
+ bubbleKey,
4
5
  bubbleLabel,
5
6
  parseBubbleLine,
6
7
  sameBubble
7
- } from "../chunks/chunk-MFKORG3F.js";
8
+ } from "../chunks/chunk-FX4RDMDN.js";
8
9
  export {
9
10
  SATURATED_PATH_COUNT,
10
11
  bubbleDescription,
12
+ bubbleKey,
11
13
  bubbleLabel,
12
14
  parseBubbleLine,
13
15
  sameBubble
@@ -1,10 +1,14 @@
1
1
  import {
2
- bubblesFromGraph
3
- } from "../chunks/chunk-4S47XRYA.js";
4
- import "../chunks/chunk-MFKORG3F.js";
2
+ bubblesFromGraph,
3
+ walkIndexOf,
4
+ walkRoutes
5
+ } from "../chunks/chunk-GOZYKNQ2.js";
6
+ import "../chunks/chunk-FX4RDMDN.js";
5
7
  import "../chunks/chunk-HNQPEMYE.js";
6
8
  import "../chunks/chunk-CPMHA4W5.js";
7
9
  import "../chunks/chunk-FYQWPEEY.js";
8
10
  export {
9
- bubblesFromGraph
11
+ bubblesFromGraph,
12
+ walkIndexOf,
13
+ walkRoutes
10
14
  };
@@ -4,8 +4,8 @@ import {
4
4
  bubbleSegmentIds,
5
5
  classifyBubble,
6
6
  formatBp
7
- } from "../chunks/chunk-WOO7QYKB.js";
8
- import "../chunks/chunk-MFKORG3F.js";
7
+ } from "../chunks/chunk-XKWD2RY3.js";
8
+ import "../chunks/chunk-FX4RDMDN.js";
9
9
  export {
10
10
  BUBBLE_KIND_COLORS,
11
11
  BUBBLE_KIND_NAMES,
@@ -0,0 +1,21 @@
1
+ import {
2
+ MAX_SUPERBUBBLES,
3
+ graphBubbles,
4
+ superbubblesFromGraph
5
+ } from "../chunks/chunk-ZDJDM77V.js";
6
+ import "../chunks/chunk-VHW7FDHU.js";
7
+ import "../chunks/chunk-2AWUWGAD.js";
8
+ import "../chunks/chunk-XKWD2RY3.js";
9
+ import "../chunks/chunk-GOZYKNQ2.js";
10
+ import "../chunks/chunk-FX4RDMDN.js";
11
+ import "../chunks/chunk-HNQPEMYE.js";
12
+ import "../chunks/chunk-ST2IBUAN.js";
13
+ import "../chunks/chunk-BPLIXMH7.js";
14
+ import "../chunks/chunk-2CVHXFK7.js";
15
+ import "../chunks/chunk-CPMHA4W5.js";
16
+ import "../chunks/chunk-FYQWPEEY.js";
17
+ export {
18
+ MAX_SUPERBUBBLES,
19
+ graphBubbles,
20
+ superbubblesFromGraph
21
+ };
@@ -2,7 +2,7 @@ import {
2
2
  bubbleSegmentIds,
3
3
  classifyBubble,
4
4
  formatBp
5
- } from "./chunk-WOO7QYKB.js";
5
+ } from "./chunk-XKWD2RY3.js";
6
6
  import {
7
7
  svgPath
8
8
  } from "./chunk-2CVHXFK7.js";
@@ -12,6 +12,9 @@ import {
12
12
 
13
13
  // src/bubbles/bubbleHalos.ts
14
14
  var WHOLE_FRACTION = 0.9;
15
+ function coversGraph(members, nodes) {
16
+ return members + 2 >= nodes || members >= WHOLE_FRACTION * nodes;
17
+ }
15
18
  var NAMED_WALKS = 2;
16
19
  var MIN_CHIPPED_BP = 1e3;
17
20
  function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repeats = []) {
@@ -24,13 +27,14 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
24
27
  let minY = Infinity;
25
28
  const nodeIds = [];
26
29
  const ends = [];
27
- for (const name of bubbleSegmentIds(bubble)) {
30
+ const names = bubbleSegmentIds(bubble);
31
+ for (const [i, name] of names.entries()) {
28
32
  const node = byName.get(name);
29
33
  const line = node && positions[node.id];
30
34
  if (!node || !line?.length) {
31
35
  continue;
32
36
  }
33
- if (isBackbone(node) && (node.stable.start < bubble.start || node.stable.start >= bubble.end)) {
37
+ if (bubble.key ? i === 0 || i === names.length - 1 : isBackbone(node) && (node.stable.start < bubble.start || node.stable.start >= bubble.end)) {
34
38
  ends.push(line[Math.floor(line.length / 2)]);
35
39
  continue;
36
40
  }
@@ -90,7 +94,7 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
90
94
  labelAt,
91
95
  members: nodeIds.length,
92
96
  nodeIds,
93
- whole: nodeIds.length >= WHOLE_FRACTION * graph.nodes.length,
97
+ whole: coversGraph(nodeIds.length, graph.nodes.length),
94
98
  routes
95
99
  });
96
100
  }
@@ -104,5 +108,7 @@ function routeText(route, walkLabel) {
104
108
  }
105
109
 
106
110
  export {
111
+ WHOLE_FRACTION,
112
+ coversGraph,
107
113
  bubbleHalos
108
114
  };
@@ -69,7 +69,10 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
69
69
  ctx.strokeStyle = `rgba(${ink},0.35)`;
70
70
  ctx.lineWidth = 0.5;
71
71
  ctx.stroke();
72
- const lit = connectors.find((c) => c.node === highlightNode);
72
+ drawLitConnector(ctx, connectors, bottom, highlightNode);
73
+ }
74
+ function drawLitConnector(ctx, connectors, bottom, node) {
75
+ const lit = bottom > 0 && node ? connectors.find((c) => c.node === node) : void 0;
73
76
  if (lit) {
74
77
  ctx.beginPath();
75
78
  band(ctx, lit, bottom);
@@ -86,5 +89,6 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
86
89
  export {
87
90
  tubeMapConnectors,
88
91
  connectorAt,
89
- drawTubeMapConnectors
92
+ drawTubeMapConnectors,
93
+ drawLitConnector
90
94
  };
@@ -192,24 +192,40 @@ function drawTubeMap(ctx, picture, frame) {
192
192
  }
193
193
  const stroke = frame.darkMode ? "#d0d0d0" : "#000000";
194
194
  const fill = frame.darkMode ? "rgba(40,40,40,0.4)" : "rgba(255,255,255,0.4)";
195
- ctx.lineWidth = 2 * Math.max(0.25, Math.min(1, frame.yScale));
195
+ ctx.lineWidth = outlineWidth(frame);
196
196
  for (const node of picture.nodes) {
197
- if (visible(node)) {
198
- const lit = node.name === frame.highlightNode;
197
+ if (visible(node) && node.name !== frame.highlightNode) {
199
198
  ctx.beginPath();
200
199
  trace(ctx, node.commands, x, y);
201
- const tint = lit ? void 0 : frame.nodeColors?.get(node.name);
202
- ctx.fillStyle = lit ? "rgba(255,192,203,0.5)" : tint ?? fill;
203
- ctx.strokeStyle = lit ? "#ff0000" : stroke;
200
+ const tint = frame.nodeColors?.get(node.name);
201
+ ctx.fillStyle = tint ?? fill;
202
+ ctx.strokeStyle = stroke;
204
203
  ctx.globalAlpha = tint ? NODE_TINT_ALPHA : 1;
205
204
  ctx.fill();
206
- ctx.globalAlpha = lit ? 1 : outlineAlpha(x(node.x1) - x(node.x0));
205
+ ctx.globalAlpha = outlineAlpha(x(node.x1) - x(node.x0));
207
206
  ctx.stroke();
208
207
  ctx.globalAlpha = 1;
209
208
  }
210
209
  }
210
+ drawTubeMapHighlight(ctx, picture, frame);
211
211
  drawMismatches(ctx, picture.mismatches, frame);
212
212
  }
213
+ function outlineWidth(frame) {
214
+ return 2 * Math.max(0.25, Math.min(1, frame.yScale));
215
+ }
216
+ function drawTubeMapHighlight(ctx, picture, frame) {
217
+ const node = frame.highlightNode ? picture.nodes.find((n) => n.name === frame.highlightNode) : void 0;
218
+ if (node) {
219
+ ctx.beginPath();
220
+ trace(ctx, node.commands, frame.x, frame.y);
221
+ ctx.globalAlpha = 1;
222
+ ctx.lineWidth = outlineWidth(frame);
223
+ ctx.fillStyle = "rgba(255,192,203,0.5)";
224
+ ctx.strokeStyle = "#ff0000";
225
+ ctx.fill();
226
+ ctx.stroke();
227
+ }
228
+ }
213
229
  var MISMATCH_FONT_PX = 12;
214
230
  var MIN_MISMATCH_FONT_PX = 6;
215
231
  function mismatchesLegible(yScale) {
@@ -273,6 +289,7 @@ export {
273
289
  trackColors,
274
290
  tubeMapPicture,
275
291
  drawTubeMap,
292
+ drawTubeMapHighlight,
276
293
  mismatchesLegible,
277
294
  mismatchOnScreen,
278
295
  tubeMapTrackAt,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  computeColorSchemeRange,
3
3
  getNodeColor
4
- } from "./chunk-HBEKUQO4.js";
4
+ } from "./chunk-BR25DGIJ.js";
5
5
  import {
6
6
  abgrToCssRgba
7
7
  } from "./chunk-G2FD7S3C.js";
@@ -0,0 +1,358 @@
1
+ import {
2
+ ownStrand
3
+ } from "./chunk-2CVHXFK7.js";
4
+ import {
5
+ isBackbone
6
+ } from "./chunk-FYQWPEEY.js";
7
+
8
+ // src/foldVariants.ts
9
+ function foldVariants(graph, belowBp) {
10
+ if (!(belowBp > 0) || graph.paths?.length || !graph.nodes.some((node) => isBackbone(node))) {
11
+ return graph;
12
+ }
13
+ const { nodes, edges } = graph;
14
+ const index = new Map(nodes.map((node, i) => [node.id, i]));
15
+ const sides = edges.map(forwardSides);
16
+ const links = linksAt(nodes.length, edges, sides, index);
17
+ const allele = alleleOf(nodes, edges, sides, index);
18
+ const members = groupBy(allele);
19
+ const kept = new Uint8Array(nodes.length);
20
+ const big = [];
21
+ for (const group of members.values()) {
22
+ if (alleleContent(group, nodes, links, allele) >= belowBp) {
23
+ for (const i of group) {
24
+ kept[i] = 1;
25
+ }
26
+ if (!isBackbone(nodes[group[0]])) {
27
+ big.push(group);
28
+ }
29
+ }
30
+ }
31
+ const { dist, pred } = distancesFromBackbone(nodes, links);
32
+ for (const group of big) {
33
+ for (const [i, side] of alleleEnds(group, nodes, links, allele)) {
34
+ let next = nearestOutside(i, side, links, allele, dist, nodes);
35
+ while (next !== void 0 && !kept[next]) {
36
+ kept[next] = 1;
37
+ next = isBackbone(nodes[next]) ? void 0 : pred[next];
38
+ }
39
+ }
40
+ }
41
+ const keptEdges = edges.filter((edge, k) => {
42
+ const a = index.get(edge.from);
43
+ const b = index.get(edge.to);
44
+ if (a === void 0 || b === void 0) {
45
+ return false;
46
+ }
47
+ const skip = skipped(nodes[a], sides[k].from, nodes[b], sides[k].to);
48
+ return kept[a] && kept[b] && !(skip > 0 && skip < belowBp);
49
+ });
50
+ return mergeAlleleRuns({ ...graph, edges: keptEdges }, kept, allele);
51
+ }
52
+ function forwardSides(edge) {
53
+ return {
54
+ from: (edge.fromStrand ?? ownStrand(edge.from)) === "+" ? "e" : "s",
55
+ to: (edge.toStrand ?? ownStrand(edge.to)) === "+" ? "s" : "e"
56
+ };
57
+ }
58
+ function linksAt(count, edges, sides, index) {
59
+ const links = Array.from({ length: count }, () => []);
60
+ edges.forEach((edge, k) => {
61
+ const a = index.get(edge.from);
62
+ const b = index.get(edge.to);
63
+ if (a !== void 0 && b !== void 0) {
64
+ links[a].push({ other: b, side: sides[k].from });
65
+ links[b].push({ other: a, side: sides[k].to });
66
+ }
67
+ });
68
+ return links;
69
+ }
70
+ function onOneSequence(a, b) {
71
+ const sa = a.stable;
72
+ const sb = b.stable;
73
+ return sa && sb?.refName === sa.refName && sb.rank === sa.rank ? [sa, sb] : void 0;
74
+ }
75
+ function continues(a, aSide, b, bSide) {
76
+ const pair = onOneSequence(a, b);
77
+ if (!pair || aSide === bSide) {
78
+ return false;
79
+ }
80
+ const [sa, sb] = pair;
81
+ return sa.start + a.length === sb.start || sb.start + b.length === sa.start;
82
+ }
83
+ function skipped(a, aSide, b, bSide) {
84
+ const pair = onOneSequence(a, b);
85
+ if (!pair || continues(a, aSide, b, bSide)) {
86
+ return 0;
87
+ }
88
+ const [sa, sb] = pair;
89
+ return Math.max(
90
+ sb.start - (sa.start + a.length),
91
+ sa.start - (sb.start + b.length)
92
+ );
93
+ }
94
+ function alleleOf(nodes, edges, sides, index) {
95
+ const parent = nodes.map((_, i) => i);
96
+ const find = (i) => {
97
+ while (parent[i] !== i) {
98
+ parent[i] = parent[parent[i]];
99
+ i = parent[i];
100
+ }
101
+ return i;
102
+ };
103
+ edges.forEach((edge, k) => {
104
+ const a = index.get(edge.from);
105
+ const b = index.get(edge.to);
106
+ if (a !== void 0 && b !== void 0 && continues(nodes[a], sides[k].from, nodes[b], sides[k].to)) {
107
+ parent[find(a)] = find(b);
108
+ }
109
+ });
110
+ return nodes.map((_, i) => find(i));
111
+ }
112
+ function groupBy(allele) {
113
+ const groups = /* @__PURE__ */ new Map();
114
+ allele.forEach((root, i) => {
115
+ const group = groups.get(root);
116
+ if (group) {
117
+ group.push(i);
118
+ } else {
119
+ groups.set(root, [i]);
120
+ }
121
+ });
122
+ return groups;
123
+ }
124
+ function alleleContent(group, nodes, links, allele) {
125
+ if (isBackbone(nodes[group[0]])) {
126
+ return Infinity;
127
+ }
128
+ let length = 0;
129
+ let refName;
130
+ let lo = Infinity;
131
+ let hi = -Infinity;
132
+ let oneSequence = true;
133
+ for (const i of group) {
134
+ length += nodes[i].length;
135
+ for (const { other } of links[i]) {
136
+ const node = nodes[other];
137
+ if (allele[other] !== allele[i] && isBackbone(node)) {
138
+ refName ??= node.stable.refName;
139
+ oneSequence &&= node.stable.refName === refName;
140
+ lo = Math.min(lo, node.stable.start + node.length);
141
+ hi = Math.max(hi, node.stable.start);
142
+ }
143
+ }
144
+ }
145
+ return oneSequence && hi > lo ? Math.max(length, hi - lo) : length;
146
+ }
147
+ function alleleEnds(group, nodes, links, allele) {
148
+ const start = (i) => nodes[i].stable?.start ?? 0;
149
+ const end = (i) => start(i) + nodes[i].length;
150
+ let first = group[0];
151
+ let last = group[0];
152
+ for (const i of group) {
153
+ if (start(i) < start(first)) {
154
+ first = i;
155
+ }
156
+ if (end(i) > end(last)) {
157
+ last = i;
158
+ }
159
+ }
160
+ const ends = [];
161
+ for (const i of /* @__PURE__ */ new Set([first, last])) {
162
+ for (const side of ["s", "e"]) {
163
+ if (!links[i].some(
164
+ (link) => link.side === side && allele[link.other] === allele[i]
165
+ )) {
166
+ ends.push([i, side]);
167
+ }
168
+ }
169
+ }
170
+ return ends;
171
+ }
172
+ function nearestOutside(i, side, links, allele, dist, nodes) {
173
+ let best;
174
+ for (const link of links[i]) {
175
+ const j = link.other;
176
+ if (link.side === side && allele[j] !== allele[i] && Number.isFinite(dist[j]) && (best === void 0 || dist[j] < dist[best] || dist[j] === dist[best] && nodes[j].id < nodes[best].id)) {
177
+ best = j;
178
+ }
179
+ }
180
+ return best;
181
+ }
182
+ function distancesFromBackbone(nodes, links) {
183
+ const dist = new Float64Array(nodes.length).fill(Infinity);
184
+ const pred = new Int32Array(nodes.length).fill(-1);
185
+ const heap = new MinHeap(
186
+ ([da, a], [db, b]) => da - db || cmp(nodes[a].id, nodes[b].id)
187
+ );
188
+ nodes.forEach((node, i) => {
189
+ if (isBackbone(node)) {
190
+ dist[i] = 0;
191
+ heap.push([0, i]);
192
+ }
193
+ });
194
+ for (let top = heap.pop(); top !== void 0; top = heap.pop()) {
195
+ const [d0, i] = top;
196
+ if (d0 > dist[i]) {
197
+ continue;
198
+ }
199
+ for (const { other } of links[i]) {
200
+ if (isBackbone(nodes[other])) {
201
+ continue;
202
+ }
203
+ const d = d0 + nodes[other].length;
204
+ if (d < dist[other]) {
205
+ dist[other] = d;
206
+ pred[other] = i;
207
+ heap.push([d, other]);
208
+ } else if (d === dist[other] && cmp(nodes[i].id, nodes[pred[other]].id) < 0) {
209
+ pred[other] = i;
210
+ }
211
+ }
212
+ }
213
+ return { dist, pred: Array.from(pred, (p) => p < 0 ? void 0 : p) };
214
+ }
215
+ function cmp(a, b) {
216
+ return a < b ? -1 : a > b ? 1 : 0;
217
+ }
218
+ var MinHeap = class {
219
+ constructor(order) {
220
+ this.order = order;
221
+ this.items = [];
222
+ }
223
+ push(item) {
224
+ const { items } = this;
225
+ items.push(item);
226
+ let i = items.length - 1;
227
+ while (i > 0) {
228
+ const up = i - 1 >> 1;
229
+ if (this.order(items[i], items[up]) >= 0) {
230
+ break;
231
+ }
232
+ ;
233
+ [items[i], items[up]] = [items[up], items[i]];
234
+ i = up;
235
+ }
236
+ }
237
+ pop() {
238
+ const { items } = this;
239
+ const top = items[0];
240
+ const last = items.pop();
241
+ if (items.length > 0 && last !== void 0) {
242
+ items[0] = last;
243
+ let i = 0;
244
+ for (; ; ) {
245
+ const l = 2 * i + 1;
246
+ const r = l + 1;
247
+ let m = i;
248
+ if (l < items.length && this.order(items[l], items[m]) < 0) {
249
+ m = l;
250
+ }
251
+ if (r < items.length && this.order(items[r], items[m]) < 0) {
252
+ m = r;
253
+ }
254
+ if (m === i) {
255
+ break;
256
+ }
257
+ ;
258
+ [items[i], items[m]] = [items[m], items[i]];
259
+ i = m;
260
+ }
261
+ }
262
+ return top;
263
+ }
264
+ };
265
+ function mergeAlleleRuns(graph, kept, allele) {
266
+ const { nodes, edges } = graph;
267
+ const index = new Map(nodes.map((node, i) => [node.id, i]));
268
+ const sides = edges.map(forwardSides);
269
+ const ends = edges.map((edge, k) => [
270
+ { i: index.get(edge.from), side: sides[k].from },
271
+ { i: index.get(edge.to), side: sides[k].to }
272
+ ]);
273
+ const degree = /* @__PURE__ */ new Map();
274
+ const sideKey = (i, side) => `${i}${side}`;
275
+ for (const pair of ends) {
276
+ for (const { i, side } of pair) {
277
+ degree.set(sideKey(i, side), (degree.get(sideKey(i, side)) ?? 0) + 1);
278
+ }
279
+ }
280
+ const next = /* @__PURE__ */ new Map();
281
+ const hasPrev = /* @__PURE__ */ new Set();
282
+ const internal = /* @__PURE__ */ new Set();
283
+ ends.forEach(([a, b], k) => {
284
+ if (a.i !== b.i && allele[a.i] === allele[b.i] && continues(nodes[a.i], a.side, nodes[b.i], b.side) && degree.get(sideKey(a.i, a.side)) === 1 && degree.get(sideKey(b.i, b.side)) === 1) {
285
+ const [left, right] = nodes[a.i].stable.start < nodes[b.i].stable.start ? [a, b] : [b, a];
286
+ next.set(left.i, { j: right.i, out: left.side, in: right.side });
287
+ hasPrev.add(right.i);
288
+ internal.add(k);
289
+ }
290
+ });
291
+ const headOf = nodes.map((_, i) => i);
292
+ const outer = /* @__PURE__ */ new Map();
293
+ const merged = /* @__PURE__ */ new Map();
294
+ nodes.forEach((_, i) => {
295
+ if (!kept[i] || hasPrev.has(i) || !next.has(i)) {
296
+ return;
297
+ }
298
+ const run = [i];
299
+ let into = flip(next.get(i).out);
300
+ outer.set(sideKey(i, into), "s");
301
+ for (let step = next.get(i); step; step = next.get(step.j)) {
302
+ run.push(step.j);
303
+ into = step.in;
304
+ }
305
+ outer.set(sideKey(run.at(-1), flip(into)), "e");
306
+ for (const j of run) {
307
+ headOf[j] = i;
308
+ }
309
+ merged.set(i, mergedNode(run.map((j) => nodes[j])));
310
+ });
311
+ const endpoint = ({ i, side }) => ({
312
+ id: nodes[headOf[i]].id,
313
+ side: headOf[i] === i && !merged.has(i) ? side : outer.get(sideKey(i, side))
314
+ });
315
+ return {
316
+ ...graph,
317
+ nodes: nodes.flatMap(
318
+ (node, i) => !kept[i] || headOf[i] !== i ? [] : [merged.get(i) ?? node]
319
+ ),
320
+ edges: edges.flatMap((edge, k) => {
321
+ if (internal.has(k)) {
322
+ return [];
323
+ }
324
+ const [a, b] = ends[k];
325
+ if (!merged.has(headOf[a.i]) && !merged.has(headOf[b.i])) {
326
+ return [edge];
327
+ }
328
+ const from = endpoint(a);
329
+ const to = endpoint(b);
330
+ return [
331
+ {
332
+ ...edge,
333
+ from: from.id,
334
+ to: to.id,
335
+ fromStrand: from.side === "e" ? "+" : "-",
336
+ toStrand: to.side === "s" ? "+" : "-"
337
+ }
338
+ ];
339
+ })
340
+ };
341
+ }
342
+ function flip(side) {
343
+ return side === "s" ? "e" : "s";
344
+ }
345
+ function mergedNode(run) {
346
+ const { samples: firstSamples, ...first } = run[0];
347
+ const length = run.reduce((sum, node) => sum + node.length, 0);
348
+ const depth = length > 0 ? run.reduce((sum, node) => sum + node.depth * node.length, 0) / length : first.depth;
349
+ const samples = run.every((node) => node.samples) ? run.reduce(
350
+ (common, node) => common.filter((s) => node.samples.includes(s)),
351
+ firstSamples
352
+ ) : void 0;
353
+ return samples ? { ...first, length, depth, samples } : { ...first, length, depth };
354
+ }
355
+
356
+ export {
357
+ foldVariants
358
+ };
@@ -0,0 +1,24 @@
1
+ // src/gfa/writeRgfa.ts
2
+ function writeRgfa(graph) {
3
+ const nameOf = new Map(graph.nodes.map((n) => [n.id, n.name]));
4
+ return [
5
+ "H VN:Z:1.0",
6
+ ...graph.nodes.map(segmentLine),
7
+ ...graph.edges.map(
8
+ (e) => `L ${nameOf.get(e.from)} ${e.fromStrand ?? "+"} ${nameOf.get(e.to)} ${e.toStrand ?? "+"} 0M`
9
+ ),
10
+ ""
11
+ ].join("\n");
12
+ }
13
+ function segmentLine(node) {
14
+ const { stable } = node;
15
+ if (!stable) {
16
+ throw new Error(`segment ${node.name} has no stable coordinate to file`);
17
+ }
18
+ const samples = node.samples?.length ? ` SM:Z:${node.samples.join(",")}` : "";
19
+ return `S ${node.name} * LN:i:${node.length} SN:Z:${stable.refName} SO:i:${stable.start} SR:i:${stable.rank}${samples}`;
20
+ }
21
+
22
+ export {
23
+ writeRgfa
24
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ENGINE_DEFAULTS
3
- } from "./chunk-5OIVTEF7.js";
3
+ } from "./chunk-ZGRYFUXE.js";
4
4
 
5
5
  // src/figureSettings.ts
6
6
  var FIGURE_DEFAULTS = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  engineKey,
3
3
  forceLayout
4
- } from "./chunk-5OIVTEF7.js";
4
+ } from "./chunk-ZGRYFUXE.js";
5
5
 
6
6
  // src/layout/forceCache.ts
7
7
  var DEFAULT_SIZE = 4;
@@ -2,7 +2,7 @@ import {
2
2
  LIFT_BACKDROP_CSS,
3
3
  computeColorSchemeRange,
4
4
  getNodeColor
5
- } from "./chunk-HBEKUQO4.js";
5
+ } from "./chunk-BR25DGIJ.js";
6
6
  import {
7
7
  abgrToCssRgba
8
8
  } from "./chunk-G2FD7S3C.js";
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "9.0.0";
2
+ var version = "9.2.0";
3
3
 
4
4
  export {
5
5
  version
@@ -19,7 +19,10 @@ function parseBubbleLine(line) {
19
19
  };
20
20
  }
21
21
  function sameBubble(a, b) {
22
- return a.refName === b.refName && a.start === b.start && a.end === b.end;
22
+ return a.key !== void 0 || b.key !== void 0 ? a.key === b.key : a.refName === b.refName && a.start === b.start && a.end === b.end;
23
+ }
24
+ function bubbleKey(b) {
25
+ return b.key ?? `${b.refName}:${b.start}-${b.end}`;
23
26
  }
24
27
  function bubbleLabel(bubble) {
25
28
  const { shortestAlleleLength: min, longestAlleleLength: max } = bubble;
@@ -38,6 +41,7 @@ function bubbleDescription(bubble) {
38
41
  export {
39
42
  parseBubbleLine,
40
43
  sameBubble,
44
+ bubbleKey,
41
45
  bubbleLabel,
42
46
  SATURATED_PATH_COUNT,
43
47
  bubbleDescription
@@ -3,10 +3,10 @@ import {
3
3
  RAMP_GRADIENT_STOPS,
4
4
  rampHueCss,
5
5
  rampStops
6
- } from "./chunk-6ZNQJ5ZD.js";
6
+ } from "./chunk-OXTR3BVF.js";
7
7
  import {
8
8
  REFERENCE_RAMP_ALT_CSS
9
- } from "./chunk-HBEKUQO4.js";
9
+ } from "./chunk-BR25DGIJ.js";
10
10
  import {
11
11
  LABEL_CHAR_PX
12
12
  } from "./chunk-AB35TJST.js";