@jbrowse/bandage-core 6.0.0 → 6.0.2

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 (162) hide show
  1. package/README.md +23 -7
  2. package/dist/alleleProjection/projectAlleles.js +10 -0
  3. package/dist/anchoredNodes.js +24 -0
  4. package/dist/bubbleSpreads.js +11 -0
  5. package/dist/bubbles/bubbleHalos.js +11 -0
  6. package/dist/bubbles/bubbleLine.js +14 -0
  7. package/dist/bubbles/bubblesFromGraph.js +10 -0
  8. package/dist/bubbles/classifyBubble.js +15 -0
  9. package/dist/bubbles/popBubble.js +9 -0
  10. package/dist/chunks/chunk-3C2LGJKY.js +108 -0
  11. package/dist/chunks/chunk-3PLYZLYV.js +513 -0
  12. package/dist/chunks/chunk-3S3YVOJ7.js +69 -0
  13. package/dist/chunks/chunk-3WHKR5TY.js +726 -0
  14. package/dist/chunks/chunk-47DYCZOK.js +115 -0
  15. package/dist/chunks/chunk-4S47XRYA.js +149 -0
  16. package/dist/chunks/chunk-527AI7CP.js +122 -0
  17. package/dist/chunks/chunk-57ZIXHZA.js +90 -0
  18. package/dist/chunks/chunk-5QT6NPSO.js +40 -0
  19. package/dist/chunks/chunk-6JEWNXCQ.js +90 -0
  20. package/dist/chunks/chunk-6Q6HFBJT.js +170 -0
  21. package/dist/chunks/chunk-6SBUFFTB.js +97 -0
  22. package/dist/chunks/chunk-6YRRNX2P.js +61 -0
  23. package/dist/chunks/chunk-72N5DJHZ.js +155 -0
  24. package/dist/chunks/chunk-73RSLGZT.js +73 -0
  25. package/dist/chunks/chunk-7CHJKABZ.js +82 -0
  26. package/dist/chunks/chunk-7XHHVYG7.js +13 -0
  27. package/dist/chunks/chunk-AB35TJST.js +67 -0
  28. package/dist/chunks/chunk-AE3UQZY3.js +43 -0
  29. package/dist/chunks/chunk-BJV2W4KZ.js +257 -0
  30. package/dist/chunks/chunk-BPLIXMH7.js +52 -0
  31. package/dist/chunks/chunk-BXEPA4KS.js +179 -0
  32. package/dist/chunks/chunk-C44YRP5F.js +85 -0
  33. package/dist/chunks/chunk-CDLPYR5O.js +135 -0
  34. package/dist/chunks/chunk-CPMHA4W5.js +6 -0
  35. package/dist/chunks/chunk-CR7EGAFE.js +241 -0
  36. package/dist/chunks/chunk-CZ54VG2H.js +431 -0
  37. package/dist/chunks/chunk-D3M7SBKL.js +210 -0
  38. package/dist/chunks/chunk-EJ5OZTCK.js +52 -0
  39. package/dist/chunks/chunk-ES2N6V56.js +83 -0
  40. package/dist/chunks/chunk-EZPBJPK6.js +54 -0
  41. package/dist/chunks/chunk-FYQWPEEY.js +65 -0
  42. package/dist/chunks/chunk-GQ2AOHU4.js +112 -0
  43. package/dist/chunks/chunk-HB6PDCOU.js +177 -0
  44. package/dist/chunks/chunk-HCANBJDD.js +326 -0
  45. package/dist/chunks/chunk-HIJVRRYE.js +174 -0
  46. package/dist/chunks/chunk-HNQPEMYE.js +297 -0
  47. package/dist/chunks/chunk-IGVV37VI.js +60 -0
  48. package/dist/chunks/chunk-IMW3AK27.js +102 -0
  49. package/dist/chunks/chunk-JKJWSY4V.js +32 -0
  50. package/dist/chunks/chunk-KCW7L3NV.js +6 -0
  51. package/dist/chunks/chunk-KQFOCDFY.js +73 -0
  52. package/dist/chunks/chunk-L3O7AWLI.js +52 -0
  53. package/dist/chunks/chunk-L5RYUPZI.js +53 -0
  54. package/dist/chunks/chunk-LOEA5IHZ.js +71 -0
  55. package/dist/chunks/chunk-LTUWJKHD.js +112 -0
  56. package/dist/chunks/chunk-LVZZH2NI.js +181 -0
  57. package/dist/chunks/chunk-MFKORG3F.js +44 -0
  58. package/dist/chunks/chunk-MHGHYHTL.js +205 -0
  59. package/dist/chunks/chunk-MI35EUIE.js +76 -0
  60. package/dist/chunks/chunk-MNUSQCLG.js +29 -0
  61. package/dist/chunks/chunk-NNODIW4U.js +26 -0
  62. package/dist/chunks/chunk-P7B3GDAY.js +232 -0
  63. package/dist/chunks/chunk-PBENCR5L.js +60 -0
  64. package/dist/chunks/chunk-PUG7LXDF.js +70 -0
  65. package/dist/chunks/chunk-Q3KCTA4N.js +202 -0
  66. package/dist/chunks/chunk-QCYM44UL.js +476 -0
  67. package/dist/chunks/chunk-QYBZZI5H.js +0 -0
  68. package/dist/chunks/chunk-RAKOB6IV.js +169 -0
  69. package/dist/chunks/chunk-RVS2QCOX.js +135 -0
  70. package/dist/chunks/chunk-SDGM243E.js +190 -0
  71. package/dist/chunks/chunk-ST2IBUAN.js +119 -0
  72. package/dist/chunks/chunk-SV27AJCC.js +101 -0
  73. package/dist/chunks/chunk-SZNZ2T6D.js +198 -0
  74. package/dist/chunks/chunk-TDQLINVI.js +16 -0
  75. package/dist/chunks/chunk-TEDQJPMI.js +131 -0
  76. package/dist/chunks/chunk-TZFWUT2C.js +66 -0
  77. package/dist/chunks/chunk-UVBGRJQX.js +50 -0
  78. package/dist/chunks/chunk-VHW7FDHU.js +42 -0
  79. package/dist/chunks/chunk-VKB57ZYE.js +218 -0
  80. package/dist/chunks/chunk-VZQ4FKLR.js +38 -0
  81. package/dist/chunks/chunk-WOO7QYKB.js +121 -0
  82. package/dist/chunks/chunk-WSIFAZU7.js +132 -0
  83. package/dist/chunks/chunk-X32PABB7.js +117 -0
  84. package/dist/chunks/chunk-YJQ7CT7F.js +23 -0
  85. package/dist/cli/figure.js +84 -17
  86. package/dist/colorSchemes.js +10 -0
  87. package/dist/deletionEdges.js +13 -0
  88. package/dist/el.js +8 -0
  89. package/dist/facetGrid.js +16 -0
  90. package/dist/figure.js +51 -0
  91. package/dist/gaf/parseGaf.js +12 -0
  92. package/dist/gbzCut.js +19 -0
  93. package/dist/gbzJoin.js +6 -0
  94. package/dist/gbzWindow.js +28 -0
  95. package/dist/genes/exonOutline.js +11 -0
  96. package/dist/genes/geneFiles.js +14 -0
  97. package/dist/genes/genePins.js +10 -0
  98. package/dist/gfa/gfaConverter.js +11 -0
  99. package/dist/gfa-core/gfaParser.js +8 -0
  100. package/dist/gfa-core/index.js +9 -0
  101. package/dist/graphLabels.js +24 -0
  102. package/dist/index.js +262 -1407
  103. package/dist/labelLayout.js +24 -0
  104. package/dist/layout/anchoredLayout.js +11 -0
  105. package/dist/layout/deletionRoutes.js +10 -0
  106. package/dist/layout/drawnScale.js +22 -0
  107. package/dist/layout/mergeRuns.js +15 -0
  108. package/dist/layout/orderedLayout.js +12 -0
  109. package/dist/layout/orientToReference.js +7 -0
  110. package/dist/layout/placeOffReference.js +9 -0
  111. package/dist/layout/referenceSeeds.js +11 -0
  112. package/dist/layout/rowSpacing.js +6 -0
  113. package/dist/layout/sampleRowLayout.js +11 -0
  114. package/dist/layout/trimToWindow.js +99 -0
  115. package/dist/layout/tubeMapLayout.js +28 -0
  116. package/dist/layout/walkRowDraw.js +65 -0
  117. package/dist/layout/walkRowLayout.js +13 -0
  118. package/dist/layout/walkRows.js +11 -0
  119. package/dist/layout/walkStrip.js +40 -0
  120. package/dist/layoutModes.js +35 -0
  121. package/dist/loadBandage.js +6 -0
  122. package/dist/nodeWidths.js +18 -0
  123. package/dist/overlayLabels.js +18 -0
  124. package/dist/pansn.js +18 -0
  125. package/dist/pathAnchoring.js +18 -0
  126. package/dist/pathColors.js +31 -0
  127. package/dist/pipeline.js +40 -0
  128. package/dist/reference.js +24 -0
  129. package/dist/referenceRampCss.js +29 -0
  130. package/dist/referenceSpan.js +11 -0
  131. package/dist/referenceStrip.js +35 -0
  132. package/dist/renderer/Canvas2DRenderer.js +9 -0
  133. package/dist/renderer/GeometryBuilder.js +42 -0
  134. package/dist/renderer/colorBits.js +8 -0
  135. package/dist/renderer/recordingCanvas.js +44 -0
  136. package/dist/renderer/svgCanvas.js +6 -0
  137. package/dist/renderer/types.js +0 -0
  138. package/dist/tubeMap/axis.js +25 -0
  139. package/dist/tubeMap/coarsen.js +361 -0
  140. package/dist/tubeMap/connectors.js +13 -0
  141. package/dist/tubeMap/deviations.js +85 -0
  142. package/dist/tubeMap/draw.js +15 -0
  143. package/dist/tubeMap/frame.js +9 -0
  144. package/dist/tubeMap/genes.js +20 -0
  145. package/dist/tubeMap/mismatches.js +6 -0
  146. package/dist/tubeMap/nodeColors.js +21 -0
  147. package/dist/tubeMap/reads.js +17 -0
  148. package/dist/tubeMap/warp.js +8 -0
  149. package/dist/types/version.d.ts +1 -1
  150. package/dist/types.js +0 -0
  151. package/dist/util/SpatialIndex.js +13 -0
  152. package/dist/util/edgeCurves.js +10 -0
  153. package/dist/util/geometry.js +39 -0
  154. package/dist/util/hitDetection.js +20 -0
  155. package/dist/util/wheelZoom.js +6 -0
  156. package/dist/version.js +6 -0
  157. package/dist/viewport.js +33 -0
  158. package/dist/walkEncoding.js +39 -0
  159. package/dist/walkHighlight.js +26 -0
  160. package/dist/walkKey.js +17 -0
  161. package/package.json +38 -5
  162. package/dist/chunks/chunk-OHMWSW6U.js +0 -7400
@@ -0,0 +1,218 @@
1
+ import {
2
+ orientToReference
3
+ } from "./chunk-PUG7LXDF.js";
4
+ import {
5
+ seededNodes
6
+ } from "./chunk-IGVV37VI.js";
7
+ import {
8
+ convertGFAToGraph
9
+ } from "./chunk-72N5DJHZ.js";
10
+ import {
11
+ parseGFA
12
+ } from "./chunk-CDLPYR5O.js";
13
+ import {
14
+ routeNodes,
15
+ takeRoutes,
16
+ withDeletionRoutes
17
+ } from "./chunk-MI35EUIE.js";
18
+ import {
19
+ anchorGraph
20
+ } from "./chunk-ST2IBUAN.js";
21
+ import {
22
+ mergeRuns,
23
+ splitRuns
24
+ } from "./chunk-SDGM243E.js";
25
+ import {
26
+ spreadFor
27
+ } from "./chunk-UVBGRJQX.js";
28
+ import {
29
+ drawnLengthOf,
30
+ drawnNodeLength,
31
+ layoutScaling
32
+ } from "./chunk-6JEWNXCQ.js";
33
+ import {
34
+ deletionEdges
35
+ } from "./chunk-X32PABB7.js";
36
+ import {
37
+ isBackbone
38
+ } from "./chunk-FYQWPEEY.js";
39
+
40
+ // src/pipeline.ts
41
+ function loadGraph(text, name, opts = {}) {
42
+ const graph = anchorGraph(
43
+ convertGFAToGraph(parseGFA(text), name),
44
+ opts.referencePath
45
+ );
46
+ if (graph.nodes.length === 0) {
47
+ throw new Error(`No graph segments in ${name}`);
48
+ }
49
+ if (opts.maxNodes !== void 0 && graph.nodes.length > opts.maxNodes) {
50
+ throw new Error(
51
+ `Graph too large to draw: ${graph.nodes.length.toLocaleString()} nodes (limit ${opts.maxNodes.toLocaleString()}). Zoom in to a smaller region, or raise maxGraphNodes on this view.`
52
+ );
53
+ }
54
+ return graph;
55
+ }
56
+ var COMPONENT_SEPARATION = 15;
57
+ function engineRequest(graph, scaling, settings) {
58
+ const anchored = graph.nodes.some(isBackbone);
59
+ const spaced = {
60
+ ...scaling,
61
+ opts: {
62
+ ...scaling.opts,
63
+ edgeLength: scaling.opts.edgeLength * (settings.spacing ?? 1)
64
+ }
65
+ };
66
+ return {
67
+ graph: {
68
+ nodes: anchored ? seededNodes(graph, spaced) : spaced.nodes,
69
+ edges: graph.edges
70
+ },
71
+ options: {
72
+ quality: settings.quality,
73
+ linearLayout: settings.linearLayout,
74
+ ...spaced.opts,
75
+ componentSeparation: COMPONENT_SEPARATION * (settings.componentSeparation ?? 1),
76
+ ...anchored ? { rotateComponents: false } : {}
77
+ }
78
+ };
79
+ }
80
+ function engineKey(graph, settings) {
81
+ const anchored = graph.nodes.some(isBackbone);
82
+ return `${settings.quality}|${settings.linearLayout}|${settings.bubbleSpread}|${settings.spacing ?? 1}|${settings.componentSeparation ?? 1}|${anchored}|${graph.referencePath ?? ""}`;
83
+ }
84
+ async function forceLayout(graph, settings, engine) {
85
+ const spread = spreadFor(settings.bubbleSpread);
86
+ const deletions = deletionEdges(graph);
87
+ const routed = withDeletionRoutes(graph, deletions);
88
+ const merged = mergeRuns(routed.graph, routed.ids);
89
+ const runs = {
90
+ ...merged.graph,
91
+ nodes: merged.graph.nodes.filter((n) => !routed.ids.has(n.id))
92
+ };
93
+ const engineScaling = layoutScaling(runs, spread);
94
+ const { result, duration } = await engine(
95
+ engineRequest(
96
+ merged.graph,
97
+ {
98
+ ...engineScaling,
99
+ nodes: [
100
+ ...engineScaling.nodes,
101
+ ...routeNodes(
102
+ graph,
103
+ deletions,
104
+ routed.routes,
105
+ drawnLengthOf(runs, spread),
106
+ engineScaling.opts
107
+ )
108
+ ]
109
+ },
110
+ settings
111
+ )
112
+ );
113
+ const scaling = layoutScaling(graph, spread);
114
+ const drawn = new Map(
115
+ scaling.nodes.map((n) => [n.id, drawnNodeLength(scaling.opts, n.length)])
116
+ );
117
+ const positions = splitRuns(
118
+ result.nodePositions,
119
+ merged.runs,
120
+ (id) => drawn.get(id) ?? 0
121
+ );
122
+ const { nodePositions, deletionRoutes } = takeRoutes(
123
+ graph.nodes.some(isBackbone) ? orientToReference(graph, positions) : positions,
124
+ routed.routes
125
+ );
126
+ return {
127
+ result: {
128
+ ...result,
129
+ nodePositions,
130
+ stranded: true,
131
+ ...deletions.length ? { deletionRoutes, extent: layoutExtent(deletionRoutes) } : {}
132
+ },
133
+ duration
134
+ };
135
+ }
136
+ function layoutExtent(nodePositions) {
137
+ let minX = Infinity;
138
+ let minY = Infinity;
139
+ let maxX = -Infinity;
140
+ let maxY = -Infinity;
141
+ for (const segments of Object.values(nodePositions)) {
142
+ for (const seg of segments) {
143
+ minX = Math.min(minX, seg.x);
144
+ minY = Math.min(minY, seg.y);
145
+ maxX = Math.max(maxX, seg.x);
146
+ maxY = Math.max(maxY, seg.y);
147
+ }
148
+ }
149
+ return { minX, minY, maxX, maxY };
150
+ }
151
+ var FIT_PADDING = 40;
152
+ var MIN_ZOOM = 1e-6;
153
+ var MAX_ZOOM = 100;
154
+ function clampZoom(zoom) {
155
+ return Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoom));
156
+ }
157
+ function fittedTranslateY(bounds, usableHeight, yScale, padTop = FIT_PADDING) {
158
+ const leftoverY = usableHeight - bounds.h * yScale;
159
+ return padTop - bounds.minY * yScale + Math.max(0, leftoverY) / 2;
160
+ }
161
+ function fitTransform(bounds, paneWidth, paneHeight, pixelRows, {
162
+ minScale = 0,
163
+ padLeft = FIT_PADDING,
164
+ padTop = FIT_PADDING,
165
+ padRight = FIT_PADDING,
166
+ padBottom = FIT_PADDING
167
+ } = {}) {
168
+ const usableWidth = paneWidth - padLeft - padRight;
169
+ const usableHeight = paneHeight - padTop - padBottom;
170
+ if (usableWidth <= 0 || usableHeight <= 0 || !(bounds.w > 0 || !pixelRows && bounds.h > 0)) {
171
+ return void 0;
172
+ }
173
+ const fitX = bounds.w > 0 ? usableWidth / bounds.w : Infinity;
174
+ const fitY = bounds.h > 0 ? usableHeight / bounds.h : Infinity;
175
+ const scale = clampZoom(
176
+ Math.max(minScale, pixelRows ? fitX : Math.min(fitX, fitY))
177
+ );
178
+ const leftoverX = usableWidth - bounds.w * scale;
179
+ return {
180
+ scale,
181
+ translateX: padLeft - bounds.minX * scale + Math.max(0, leftoverX) / 2,
182
+ translateY: fittedTranslateY(
183
+ bounds,
184
+ usableHeight,
185
+ pixelRows ? 1 : scale,
186
+ padTop
187
+ )
188
+ };
189
+ }
190
+ function drawingBounds(layout, opts = {}) {
191
+ let { minX, minY, maxX, maxY } = layoutExtent(layout.nodePositions);
192
+ const { region } = opts;
193
+ if (layout.referenceAxis && region && region.end > region.start) {
194
+ minX = region.start;
195
+ maxX = region.end;
196
+ }
197
+ const extent = opts.extent ?? layout.extent;
198
+ if (extent) {
199
+ minX = Math.min(minX, extent.minX ?? minX);
200
+ minY = Math.min(minY, extent.minY ?? minY);
201
+ maxX = Math.max(maxX, extent.maxX ?? maxX);
202
+ maxY = Math.max(maxY, extent.maxY ?? maxY);
203
+ }
204
+ return { minX, minY, w: maxX - minX, h: maxY - minY };
205
+ }
206
+
207
+ export {
208
+ loadGraph,
209
+ engineRequest,
210
+ engineKey,
211
+ forceLayout,
212
+ layoutExtent,
213
+ FIT_PADDING,
214
+ clampZoom,
215
+ fittedTranslateY,
216
+ fitTransform,
217
+ drawingBounds
218
+ };
@@ -0,0 +1,38 @@
1
+ import {
2
+ referenceKnots,
3
+ warpX
4
+ } from "./chunk-KQFOCDFY.js";
5
+
6
+ // src/tubeMap/frame.ts
7
+ var MIN_TUBE_Y_SCALE = 0.05;
8
+ var NODE_BOX_PAD = 9;
9
+ function squeeze(drawing, usableHeight) {
10
+ const { minY, maxY } = drawing.layout.bounds;
11
+ const h = maxY - minY;
12
+ return drawing.columns && h > 0 ? Math.max(MIN_TUBE_Y_SCALE, Math.min(1, usableHeight / h)) : 1;
13
+ }
14
+ function tubeMapFrame(drawing, view) {
15
+ const { scaleX, translateX, translateY } = view;
16
+ const yScale = view.scaleY * squeeze(drawing, view.usableHeight);
17
+ const y = (ty) => (ty - drawing.yOffset) * yScale + translateY;
18
+ const { columns } = drawing;
19
+ if (columns) {
20
+ const knots = referenceKnots(columns, (bp) => bp * scaleX + translateX);
21
+ return { x: (tx) => warpX(knots, tx), y, yScale };
22
+ }
23
+ return { x: (tx) => tx * scaleX + translateX, y, yScale };
24
+ }
25
+ function tubeMapNodeAt(drawing, { x, y }, sx, sy) {
26
+ let hit = null;
27
+ drawing.layout.nodes.forEach((node) => {
28
+ if (node.order >= 0 && x(node.x - NODE_BOX_PAD) <= sx && sx <= x(node.x + node.pixelWidth + NODE_BOX_PAD) && y(node.y - NODE_BOX_PAD) <= sy && sy <= y(node.y + node.contentHeight + NODE_BOX_PAD)) {
29
+ hit = node.name;
30
+ }
31
+ });
32
+ return hit;
33
+ }
34
+
35
+ export {
36
+ tubeMapFrame,
37
+ tubeMapNodeAt
38
+ };
@@ -0,0 +1,121 @@
1
+ import {
2
+ SATURATED_PATH_COUNT
3
+ } from "./chunk-MFKORG3F.js";
4
+
5
+ // src/bubbles/classifyBubble.ts
6
+ var REPEAT_GROWTH = 10;
7
+ function coveringRepeat(b, repeats) {
8
+ const span = b.end - b.start;
9
+ const growth = b.longestAlleleLength - b.shortestAlleleLength;
10
+ return repeats.find(
11
+ (r) => growth <= REPEAT_GROWTH * (r.end - r.start) && (span === 0 ? r.start <= b.start && b.start <= r.end : Math.min(b.end, r.end) - Math.max(b.start, r.start) >= span / 2)
12
+ );
13
+ }
14
+ var SUPERBUBBLE_SEGMENTS = 40;
15
+ function formatBp(bp) {
16
+ if (bp >= 1e4) {
17
+ return `${(bp / 1e3).toFixed(0)} kb`;
18
+ }
19
+ if (bp >= 1e3) {
20
+ return `${(bp / 1e3).toFixed(1)} kb`;
21
+ }
22
+ return `${bp} bp`;
23
+ }
24
+ function formatBpRange(shortest, longest) {
25
+ const low = formatBp(shortest);
26
+ const high = formatBp(longest);
27
+ const unit = high.slice(high.indexOf(" "));
28
+ return low.endsWith(unit) ? `${low.slice(0, -unit.length)}\u2013${high}` : `${low}\u2013${high}`;
29
+ }
30
+ function routes(count) {
31
+ if (count >= SATURATED_PATH_COUNT) {
32
+ return "\u22652.1B routes";
33
+ }
34
+ if (count >= 1e5) {
35
+ return `${(count / 1e3).toFixed(0)}k routes`;
36
+ }
37
+ return `${count} routes`;
38
+ }
39
+ function classifyBubble(b, repeats = []) {
40
+ const c = classifyShape(b, repeats);
41
+ return b.partial ? { ...c, label: `${c.label}, partial` } : c;
42
+ }
43
+ function classifyShape(b, repeats) {
44
+ const refSpan = b.end - b.start;
45
+ const {
46
+ shortestAlleleLength: shortest,
47
+ longestAlleleLength: longest,
48
+ pathCount,
49
+ segmentCount,
50
+ inversion
51
+ } = b;
52
+ const range = formatBpRange(shortest, longest);
53
+ if (segmentCount >= SUPERBUBBLE_SEGMENTS) {
54
+ return {
55
+ kind: "superbubble",
56
+ label: `${range} superbubble, ${segmentCount} segments, ${routes(pathCount)}${inversion ? ", inv" : ""}`
57
+ };
58
+ }
59
+ if (inversion) {
60
+ return { kind: "inversion", label: `${formatBp(longest)} inv` };
61
+ }
62
+ const repeat = longest !== shortest ? coveringRepeat(b, repeats) : void 0;
63
+ if (repeat) {
64
+ const name = repeat.name ? ` (${repeat.name})` : "";
65
+ return {
66
+ kind: "repeat",
67
+ label: `${range} repeat array${name}, ${routes(pathCount)}`
68
+ };
69
+ }
70
+ const alleles = pathCount > 2 ? `, ${pathCount} alleles` : "";
71
+ if (shortest === longest && shortest === refSpan) {
72
+ return refSpan <= 1 ? { kind: "snp", label: "SNP" } : { kind: "substitution", label: `${formatBp(refSpan)} sub` };
73
+ }
74
+ if (refSpan === 0 || shortest === refSpan) {
75
+ return {
76
+ kind: "insertion",
77
+ label: `\u2264${formatBp(longest - refSpan)} ins${alleles}`
78
+ };
79
+ }
80
+ if (longest === refSpan) {
81
+ return {
82
+ kind: "deletion",
83
+ label: `${formatBp(refSpan - shortest)} del${alleles}`
84
+ };
85
+ }
86
+ return {
87
+ kind: "complex",
88
+ label: `${formatBp(refSpan)} ref \u2192 ${range}, ${pathCount} alleles`
89
+ };
90
+ }
91
+ var BUBBLE_KIND_COLORS = {
92
+ snp: "#5b6b7a",
93
+ substitution: "#5b6b7a",
94
+ insertion: "#2f8fd6",
95
+ deletion: "#c94040",
96
+ inversion: "#e07b00",
97
+ repeat: "#8e3fbf",
98
+ superbubble: "#8e3fbf",
99
+ complex: "#8e3fbf"
100
+ };
101
+ var BUBBLE_KIND_NAMES = {
102
+ snp: "SNP",
103
+ substitution: "substitution",
104
+ insertion: "insertion",
105
+ deletion: "deletion",
106
+ inversion: "inversion",
107
+ repeat: "repeat array",
108
+ superbubble: "superbubble",
109
+ complex: "site"
110
+ };
111
+ function bubbleSegmentIds(b) {
112
+ return b.segments.split(",").filter(Boolean);
113
+ }
114
+
115
+ export {
116
+ formatBp,
117
+ classifyBubble,
118
+ BUBBLE_KIND_COLORS,
119
+ BUBBLE_KIND_NAMES,
120
+ bubbleSegmentIds
121
+ };
@@ -0,0 +1,132 @@
1
+ // src/gbzJoin.ts
2
+ var UNKNOWN_SAMPLE = "unknown";
3
+ function parseWalk(line) {
4
+ const fields = line.split(" ");
5
+ return {
6
+ fields,
7
+ name: fields.slice(1, 4).join(" "),
8
+ start: +fields[4],
9
+ end: +fields[5]
10
+ };
11
+ }
12
+ var stepsOf = (walk) => walk.fields[6].match(/[<>][^<>]+/g) ?? [];
13
+ function segmentLengths(lines) {
14
+ const lengths = /* @__PURE__ */ new Map();
15
+ for (const line of lines) {
16
+ if (line.startsWith("S ")) {
17
+ const [, id, sequence, ...tags] = line.split(" ");
18
+ const ln = tags.find((tag) => tag.startsWith("LN:i:"));
19
+ lengths.set(
20
+ id,
21
+ sequence === "*" && ln ? +ln.slice("LN:i:".length) : sequence.length
22
+ );
23
+ }
24
+ }
25
+ return lengths;
26
+ }
27
+ function extend(a, b, lengths) {
28
+ if (b.end <= a.end) {
29
+ return a;
30
+ }
31
+ const steps = stepsOf(b);
32
+ let pos = b.start;
33
+ for (const [i, step] of steps.entries()) {
34
+ if (pos === a.end) {
35
+ const fields = [...a.fields];
36
+ fields[5] = String(b.end);
37
+ fields[6] = a.fields[6] + steps.slice(i).join("");
38
+ return { ...a, fields, end: b.end };
39
+ }
40
+ const length = lengths.get(step.slice(1));
41
+ if (pos > a.end || length === void 0) {
42
+ return void 0;
43
+ }
44
+ pos += length;
45
+ }
46
+ return void 0;
47
+ }
48
+ function joinPieces(pieces, lengths, startsPath) {
49
+ const joined = [];
50
+ for (const piece of pieces.sort((a, b) => a.start - b.start)) {
51
+ const last = joined.at(-1);
52
+ const [, sample, haplotype, contig] = piece.fields;
53
+ const joins = last !== void 0 && (piece.start < last.end || piece.start === last.end && !startsPath(sample, +haplotype, contig, piece.start));
54
+ const extended = joins ? extend(last, piece, lengths) : void 0;
55
+ if (extended) {
56
+ joined[joined.length - 1] = extended;
57
+ } else {
58
+ joined.push(piece);
59
+ }
60
+ }
61
+ return joined;
62
+ }
63
+ var flip = (sign) => sign === "+" ? "-" : "+";
64
+ function* stepLinks(walk) {
65
+ const steps = stepsOf(walk).map((step) => ({
66
+ id: step.slice(1),
67
+ sign: step.startsWith(">") ? "+" : "-"
68
+ }));
69
+ for (let i = 1; i < steps.length; i++) {
70
+ const a = steps[i - 1];
71
+ const b = steps[i];
72
+ yield {
73
+ forward: `L ${a.id} ${a.sign} ${b.id} ${b.sign} 0M`,
74
+ reverse: `L ${b.id} ${flip(b.sign)} ${a.id} ${flip(a.sign)} 0M`
75
+ };
76
+ }
77
+ }
78
+ function joinCuts(gfas, startsPath) {
79
+ if (gfas.length <= 1) {
80
+ return gfas[0] ?? "";
81
+ }
82
+ const cuts = gfas.map((gfa) => gfa.split("\n").filter((line) => line !== ""));
83
+ const ofType = (cut, type) => cut.filter((line) => line.startsWith(`${type} `));
84
+ const lengths = segmentLengths(cuts.flat());
85
+ let unknownOffset = 0;
86
+ const walksByCut = cuts.map((cut) => {
87
+ const walks2 = ofType(cut, "W").map(parseWalk);
88
+ const offset = unknownOffset;
89
+ for (const walk of walks2.filter((w) => w.fields[1] === UNKNOWN_SAMPLE)) {
90
+ const haplotype = +walk.fields[2] + offset;
91
+ walk.fields[2] = String(haplotype);
92
+ walk.name = walk.fields.slice(1, 4).join(" ");
93
+ unknownOffset = Math.max(unknownOffset, haplotype);
94
+ }
95
+ return walks2;
96
+ });
97
+ const byName = /* @__PURE__ */ new Map();
98
+ for (const walk of [
99
+ ...walksByCut.flatMap((walks2) => walks2.slice(0, 1)),
100
+ ...walksByCut.flatMap((walks2) => walks2.slice(1))
101
+ ]) {
102
+ const pieces = byName.get(walk.name);
103
+ if (pieces) {
104
+ pieces.push(walk);
105
+ } else {
106
+ byName.set(walk.name, [walk]);
107
+ }
108
+ }
109
+ const walks = [...byName.values()].flatMap(
110
+ (pieces) => joinPieces(pieces, lengths, startsPath)
111
+ );
112
+ const links = new Set(cuts.flatMap((cut) => ofType(cut, "L")));
113
+ for (const walk of walks) {
114
+ for (const link of stepLinks(walk)) {
115
+ if (!links.has(link.forward) && !links.has(link.reverse)) {
116
+ links.add(link.forward);
117
+ }
118
+ }
119
+ }
120
+ const lines = /* @__PURE__ */ new Set([
121
+ ...ofType(cuts[0], "H"),
122
+ ...cuts.flatMap((cut) => ofType(cut, "S")),
123
+ ...links,
124
+ ...walks.map((walk) => walk.fields.join(" "))
125
+ ]);
126
+ return `${[...lines].join("\n")}
127
+ `;
128
+ }
129
+
130
+ export {
131
+ joinCuts
132
+ };
@@ -0,0 +1,117 @@
1
+ import {
2
+ computeEdgeCurves,
3
+ edgeJoinOf,
4
+ routedEdgeCurves,
5
+ strandSides
6
+ } from "./chunk-3PLYZLYV.js";
7
+ import {
8
+ firstNodeAtOrAfter,
9
+ isBackbone
10
+ } from "./chunk-FYQWPEEY.js";
11
+
12
+ // src/deletionEdges.ts
13
+ var MIN_DELETION_BP = 1;
14
+ function bypassedPoints(nodePositions, bypassed) {
15
+ return bypassed.flatMap((id) => nodePositions[id] ?? []);
16
+ }
17
+ function deletionArcCurves(nodePositions, deletion, axis, route, stranded = false) {
18
+ const from = nodePositions[deletion.from];
19
+ const to = nodePositions[deletion.to];
20
+ if (!from?.length || !to?.length) {
21
+ return void 0;
22
+ }
23
+ return route ? routedEdgeCurves(
24
+ from,
25
+ to,
26
+ route,
27
+ stranded ? strandSides(deletion) : void 0
28
+ ) : computeEdgeCurves(
29
+ from,
30
+ to,
31
+ edgeJoinOf(deletion, stranded),
32
+ 0,
33
+ 0,
34
+ axis,
35
+ bypassedPoints(nodePositions, deletion.bypassed)
36
+ );
37
+ }
38
+ function backboneBySequence(graph) {
39
+ const bySequence = /* @__PURE__ */ new Map();
40
+ for (const node of graph.nodes) {
41
+ if (isBackbone(node)) {
42
+ const list = bySequence.get(node.stable.refName);
43
+ if (list) {
44
+ list.push(node);
45
+ } else {
46
+ bySequence.set(node.stable.refName, [node]);
47
+ }
48
+ }
49
+ }
50
+ for (const list of bySequence.values()) {
51
+ list.sort((a, b) => a.stable.start - b.stable.start);
52
+ }
53
+ return bySequence;
54
+ }
55
+ function bypassedNodes(nodes, start, end) {
56
+ const bypassed = [];
57
+ if (nodes) {
58
+ for (let i = firstNodeAtOrAfter(nodes, start); i < nodes.length; i++) {
59
+ const node = nodes[i];
60
+ if (node.stable.start >= end) {
61
+ break;
62
+ }
63
+ if (node.stable.start + node.length <= end) {
64
+ bypassed.push(node.id);
65
+ }
66
+ }
67
+ }
68
+ return bypassed;
69
+ }
70
+ function skipsBetween(edge, from, to, forwards) {
71
+ const { fromStrand, toStrand } = edge;
72
+ if (fromStrand === void 0 || toStrand === void 0) {
73
+ return true;
74
+ }
75
+ const leavesRight = fromStrand === (from.stable.strand ?? "+");
76
+ const arrivesLeft = toStrand === (to.stable.strand ?? "+");
77
+ return forwards ? leavesRight && arrivesLeft : !leavesRight && !arrivesLeft;
78
+ }
79
+ function deletionEdges(graph) {
80
+ const byId = new Map(graph.nodes.map((n) => [n.id, n]));
81
+ const backbone = backboneBySequence(graph);
82
+ const found = [];
83
+ for (let edgeIndex = 0; edgeIndex < graph.edges.length; edgeIndex++) {
84
+ const edge = graph.edges[edgeIndex];
85
+ const from = byId.get(edge.from);
86
+ const to = byId.get(edge.to);
87
+ if (from !== void 0 && to !== void 0 && isBackbone(from) && isBackbone(to) && from.stable.refName === to.stable.refName) {
88
+ const forwards = from.stable.start <= to.stable.start;
89
+ const [left, right] = forwards ? [from, to] : [to, from];
90
+ const start = left.stable.start + left.length;
91
+ const end = right.stable.start;
92
+ const bp = end - start;
93
+ if (bp >= MIN_DELETION_BP && skipsBetween(edge, from, to, forwards)) {
94
+ const refName = left.stable.refName;
95
+ found.push({
96
+ edgeIndex,
97
+ from: edge.from,
98
+ to: edge.to,
99
+ ...edge.fromStrand ? { fromStrand: edge.fromStrand } : {},
100
+ ...edge.toStrand ? { toStrand: edge.toStrand } : {},
101
+ refName,
102
+ start,
103
+ end,
104
+ bp,
105
+ bypassed: bypassedNodes(backbone.get(refName), start, end)
106
+ });
107
+ }
108
+ }
109
+ }
110
+ return found;
111
+ }
112
+
113
+ export {
114
+ bypassedPoints,
115
+ deletionArcCurves,
116
+ deletionEdges
117
+ };
@@ -0,0 +1,23 @@
1
+ import {
2
+ computeColorSchemeRange,
3
+ getNodeColor
4
+ } from "./chunk-3WHKR5TY.js";
5
+
6
+ // src/tubeMap/nodeColors.ts
7
+ import { abgrToCssRgba } from "@jbrowse/core/util/colorBits";
8
+ function tubeMapNodeColors(graph, colorScheme, referenceRamp) {
9
+ if (colorScheme === "uniform" || colorScheme === "grey") {
10
+ return void 0;
11
+ }
12
+ const range = { ...computeColorSchemeRange(graph), referenceRamp };
13
+ return new Map(
14
+ graph.nodes.map((node, index) => [
15
+ node.id,
16
+ abgrToCssRgba(getNodeColor(node, index, colorScheme, range))
17
+ ])
18
+ );
19
+ }
20
+
21
+ export {
22
+ tubeMapNodeColors
23
+ };