@jbrowse/bandage-core 10.2.7 → 10.3.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 (190) hide show
  1. package/dist/alleleProjection/projectAlleles.js +8 -4
  2. package/dist/anchoredNodes.js +2 -1
  3. package/dist/bubbleSpreads.js +2 -2
  4. package/dist/bubbles/bubbleHalos.js +10 -11
  5. package/dist/bubbles/bubblesFromGraph.js +8 -3
  6. package/dist/bubbles/classifyBubble.js +9 -6
  7. package/dist/bubbles/popBubble.js +7 -5
  8. package/dist/bubbles/superbubbles.js +18 -14
  9. package/dist/chunks/{chunk-RAKOB6IV.js → chunk-234NFZS4.js} +8 -6
  10. package/dist/chunks/{chunk-ABUIN5AK.js → chunk-2Q22S52W.js} +29 -24
  11. package/dist/chunks/{chunk-6JEWNXCQ.js → chunk-34BOZKIE.js} +0 -2
  12. package/dist/chunks/{chunk-RVS2QCOX.js → chunk-3GLG3ZLE.js} +2 -11
  13. package/dist/chunks/{chunk-3XSM4OZU.js → chunk-3GP3KT5L.js} +5 -5
  14. package/dist/chunks/{chunk-PUG7LXDF.js → chunk-3PZSBNLI.js} +4 -1
  15. package/dist/chunks/{chunk-JLSJMCDJ.js → chunk-3UST3ZQE.js} +3 -3
  16. package/dist/chunks/{chunk-KBEP7VYK.js → chunk-3VCKBSML.js} +4 -4
  17. package/dist/chunks/{chunk-BPLIXMH7.js → chunk-4XWZNPQ2.js} +14 -0
  18. package/dist/chunks/{chunk-4DRQTBBE.js → chunk-6EOB6ANX.js} +1 -1
  19. package/dist/chunks/{chunk-L2HDM2R3.js → chunk-A2TJ5UX6.js} +7 -7
  20. package/dist/chunks/{chunk-URZ3CH2R.js → chunk-A4JDEUAI.js} +1 -1
  21. package/dist/chunks/{chunk-CWFNEKST.js → chunk-A7H753BA.js} +3 -3
  22. package/dist/chunks/{chunk-CG35S2S2.js → chunk-AQCOIE5R.js} +1 -1
  23. package/dist/chunks/{chunk-TKIJ5535.js → chunk-AZ4EEF6Q.js} +6 -6
  24. package/dist/chunks/{chunk-M6LK4GII.js → chunk-B5X2RLJG.js} +17 -10
  25. package/dist/chunks/{chunk-A7CFWFQS.js → chunk-BKEZLETL.js} +1 -1
  26. package/dist/chunks/{chunk-RPRHR56C.js → chunk-BS6HPYCZ.js} +3 -3
  27. package/dist/chunks/chunk-BSOZW3FC.js +30 -0
  28. package/dist/chunks/{chunk-XXT2JCAC.js → chunk-BX4AUMZE.js} +11 -13
  29. package/dist/chunks/{chunk-N73TI3VG.js → chunk-BZFOFC4D.js} +6 -9
  30. package/dist/chunks/{chunk-4ETPXDO6.js → chunk-CGFPFBT2.js} +1 -1
  31. package/dist/chunks/{chunk-24WITXQY.js → chunk-CGMSKIEO.js} +9 -25
  32. package/dist/chunks/{chunk-VV6KGJ7M.js → chunk-CHNESV7L.js} +18 -27
  33. package/dist/chunks/{chunk-IGVV37VI.js → chunk-CKUVEHSS.js} +3 -3
  34. package/dist/chunks/{chunk-JBCZIBFC.js → chunk-CRCD3ODN.js} +0 -1
  35. package/dist/chunks/{chunk-AUFAPUO4.js → chunk-D7WIYPG3.js} +3 -1
  36. package/dist/chunks/{chunk-OIV2GBAJ.js → chunk-DBLV7PGG.js} +27 -17
  37. package/dist/chunks/{chunk-VQC7KELB.js → chunk-DO62DG26.js} +11 -3
  38. package/dist/chunks/{chunk-JA2HJIYS.js → chunk-E4ZM4OOJ.js} +3 -5
  39. package/dist/chunks/{chunk-QLWI2PZ3.js → chunk-EJRJAAN7.js} +24 -21
  40. package/dist/chunks/{chunk-QBHPHLAQ.js → chunk-EWLXU3UG.js} +41 -36
  41. package/dist/chunks/{chunk-XI3ZUTWF.js → chunk-FW2R7UDZ.js} +14 -20
  42. package/dist/chunks/{chunk-Q7LYHGGQ.js → chunk-GIHTHYXY.js} +5 -4
  43. package/dist/chunks/{chunk-L3O7AWLI.js → chunk-GJLZ2MKE.js} +2 -2
  44. package/dist/chunks/{chunk-LOEA5IHZ.js → chunk-GJU6BJJA.js} +8 -8
  45. package/dist/chunks/{chunk-XL472HHD.js → chunk-GQZVR5DW.js} +12 -7
  46. package/dist/chunks/{chunk-UVBGRJQX.js → chunk-HKYXWZQS.js} +1 -1
  47. package/dist/chunks/chunk-HMXCN6PG.js +17 -0
  48. package/dist/chunks/{chunk-WSIFAZU7.js → chunk-HNWJ4B7S.js} +12 -13
  49. package/dist/chunks/chunk-HOAIOEI7.js +18 -0
  50. package/dist/chunks/{chunk-XMW266WS.js → chunk-HSVFCA2J.js} +18 -20
  51. package/dist/chunks/{chunk-QXUEF3AJ.js → chunk-KMBE2Q42.js} +22 -17
  52. package/dist/chunks/{chunk-VQWHMWLF.js → chunk-M5NPD55W.js} +18 -14
  53. package/dist/chunks/chunk-MWOVW4AH.js +327 -0
  54. package/dist/chunks/{chunk-HK5Y2YWV.js → chunk-MYDHU2UV.js} +6 -11
  55. package/dist/chunks/{chunk-TZFWUT2C.js → chunk-MYLAJDKB.js} +2 -2
  56. package/dist/chunks/{chunk-AR4BUBMU.js → chunk-NZTYV3JL.js} +34 -35
  57. package/dist/chunks/{chunk-4HWM3FNK.js → chunk-OMUPUB4J.js} +39 -56
  58. package/dist/chunks/{chunk-LKW2TP4N.js → chunk-OOIOX36I.js} +18 -16
  59. package/dist/chunks/{chunk-EQ2NIFRH.js → chunk-OXRUPNSV.js} +1 -1
  60. package/dist/chunks/{chunk-PTABFYQ7.js → chunk-PFRQBCGC.js} +49 -60
  61. package/dist/chunks/{chunk-T6V4KI2L.js → chunk-PNMJFFNB.js} +1 -1
  62. package/dist/chunks/{chunk-KC7T5RWG.js → chunk-PSCSZSVK.js} +9 -16
  63. package/dist/chunks/{chunk-23YFB5BB.js → chunk-QH2MIXBA.js} +29 -13
  64. package/dist/chunks/{chunk-5GMFEPWR.js → chunk-R2PJKD3Y.js} +16 -28
  65. package/dist/chunks/{chunk-CQHUZHET.js → chunk-RFG42VIO.js} +46 -30
  66. package/dist/chunks/{chunk-FYQWPEEY.js → chunk-RJWPJCIB.js} +5 -11
  67. package/dist/chunks/{chunk-WBSWROE6.js → chunk-SFP3E4RI.js} +14 -18
  68. package/dist/chunks/{chunk-2CMYNW3E.js → chunk-SI3BB4DO.js} +1 -1
  69. package/dist/chunks/{chunk-DY3JCAMX.js → chunk-SOMZGDVS.js} +7 -16
  70. package/dist/chunks/{chunk-A4PFFC4Q.js → chunk-SWCULW6S.js} +60 -102
  71. package/dist/chunks/{chunk-XV4P5KEQ.js → chunk-TGUFT6KK.js} +6 -3
  72. package/dist/chunks/{chunk-CM6LO6OC.js → chunk-UAFATXYA.js} +10 -14
  73. package/dist/chunks/{chunk-7SRWJLSC.js → chunk-UBQSRCWR.js} +11 -8
  74. package/dist/chunks/{chunk-RUCH6ZFL.js → chunk-V4YML3GR.js} +2 -1
  75. package/dist/chunks/{chunk-ES2N6V56.js → chunk-VX656OAZ.js} +6 -11
  76. package/dist/chunks/chunk-WA5WNP6V.js +37 -0
  77. package/dist/chunks/{chunk-B6IW3IRE.js → chunk-WYJQIC75.js} +14 -15
  78. package/dist/chunks/{chunk-T2PCSAFY.js → chunk-XVS52NMZ.js} +2 -2
  79. package/dist/chunks/{chunk-CU6P5RUG.js → chunk-YZQI35UJ.js} +22 -16
  80. package/dist/chunks/{chunk-G45YY72K.js → chunk-Z6XZWPXK.js} +17 -25
  81. package/dist/chunks/{chunk-EFQLEGWM.js → chunk-ZJBOM73S.js} +7 -8
  82. package/dist/chunks/{chunk-RAEABQNW.js → chunk-ZPZ7GNBT.js} +1 -0
  83. package/dist/cli/figure.js +59 -56
  84. package/dist/cli/fold.js +19 -17
  85. package/dist/deletionEdges.js +5 -7
  86. package/dist/facetGrid.js +2 -1
  87. package/dist/figure.js +45 -42
  88. package/dist/figureData.js +48 -44
  89. package/dist/figureScene.js +34 -29
  90. package/dist/figureSettings.js +19 -17
  91. package/dist/foldVariants.js +5 -3
  92. package/dist/gbzCut.js +12 -7
  93. package/dist/gbzJoin.js +2 -1
  94. package/dist/gbzWindow.js +11 -6
  95. package/dist/genes/genePins.js +6 -4
  96. package/dist/gfa/gfaConverter.js +7 -5
  97. package/dist/gfa/gfaTables.js +2 -1
  98. package/dist/gfa/graphTables.js +3 -3
  99. package/dist/graphLabels.js +8 -5
  100. package/dist/index.js +88 -85
  101. package/dist/labelLayout.js +12 -9
  102. package/dist/layout/anchoredLayout.js +8 -5
  103. package/dist/layout/drawnScale.js +1 -5
  104. package/dist/layout/forceCache.js +19 -17
  105. package/dist/layout/mergeRuns.js +5 -3
  106. package/dist/layout/orderedLayout.js +5 -2
  107. package/dist/layout/orientToReference.js +3 -2
  108. package/dist/layout/placeOffReference.js +7 -4
  109. package/dist/layout/referenceSeeds.js +6 -4
  110. package/dist/layout/sampleRowLayout.js +8 -5
  111. package/dist/layout/trimToWindow.js +6 -4
  112. package/dist/layout/tubeMapLayout.js +17 -19
  113. package/dist/layout/walkRowDraw.js +18 -17
  114. package/dist/layout/walkRowLayout.js +10 -6
  115. package/dist/layout/walkRows.js +9 -5
  116. package/dist/layout/walkStrip.js +21 -18
  117. package/dist/layoutModes.js +23 -20
  118. package/dist/nodeWidths.js +1 -3
  119. package/dist/pansn.js +5 -1
  120. package/dist/pathAnchoring.js +6 -4
  121. package/dist/pathColors.js +12 -9
  122. package/dist/pathVisits.js +3 -1
  123. package/dist/pipeline.js +18 -16
  124. package/dist/reference.js +5 -3
  125. package/dist/referenceRampCss.js +9 -17
  126. package/dist/referenceSpan.js +4 -2
  127. package/dist/referenceStrip.js +18 -14
  128. package/dist/renderer/Canvas2DRenderer.js +1 -1
  129. package/dist/renderer/GeometryBuilder.js +19 -14
  130. package/dist/renderer/svgCanvas.js +1 -1
  131. package/dist/tubeMap/axis.js +11 -6
  132. package/dist/tubeMap/bundle.js +16 -12
  133. package/dist/tubeMap/coarsen.js +20 -345
  134. package/dist/tubeMap/deviations.js +53 -23
  135. package/dist/tubeMap/draw.js +11 -8
  136. package/dist/tubeMap/frame.js +3 -2
  137. package/dist/tubeMap/genes.js +10 -7
  138. package/dist/tubeMap/mismatches.js +1 -1
  139. package/dist/tubeMap/nodeColors.js +18 -14
  140. package/dist/tubeMap/reads.js +1 -1
  141. package/dist/tubeMap/warp.js +2 -1
  142. package/dist/types/alleleProjection/projectAlleles.d.ts +1 -4
  143. package/dist/types/bubbles/bubbleHalos.d.ts +0 -2
  144. package/dist/types/bubbles/bubblesFromGraph.d.ts +6 -4
  145. package/dist/types/bubbles/classifyBubble.d.ts +2 -1
  146. package/dist/types/deletionEdges.d.ts +0 -8
  147. package/dist/types/figureScene.d.ts +17 -7
  148. package/dist/types/figureSettings.d.ts +2 -0
  149. package/dist/types/gbzCut.d.ts +4 -0
  150. package/dist/types/gbzWindow.d.ts +1 -0
  151. package/dist/types/gfa-core/gfaParser.d.ts +1 -1
  152. package/dist/types/graphLabels.d.ts +2 -1
  153. package/dist/types/layout/drawnScale.d.ts +0 -2
  154. package/dist/types/layout/referenceSeeds.d.ts +2 -1
  155. package/dist/types/layout/tubeMapLayout.d.ts +0 -7
  156. package/dist/types/layout/walkRowDraw.d.ts +0 -1
  157. package/dist/types/layout/walkRowLayout.d.ts +1 -0
  158. package/dist/types/layout/walkRows.d.ts +1 -0
  159. package/dist/types/nodeWidths.d.ts +0 -1
  160. package/dist/types/pansn.d.ts +9 -0
  161. package/dist/types/pathVisits.d.ts +6 -0
  162. package/dist/types/referenceRampCss.d.ts +4 -0
  163. package/dist/types/renderer/Canvas2DRenderer.d.ts +1 -0
  164. package/dist/types/renderer/GeometryBuilder.d.ts +3 -2
  165. package/dist/types/tubeMap/axis.d.ts +3 -1
  166. package/dist/types/tubeMap/coarsen.d.ts +3 -1
  167. package/dist/types/tubeMap/deviations.d.ts +2 -1
  168. package/dist/types/tubeMap/mismatches.d.ts +0 -1
  169. package/dist/types/tubeMap/warp.d.ts +2 -1
  170. package/dist/types/util/SpatialIndex.d.ts +1 -1
  171. package/dist/types/util/geometry.d.ts +4 -0
  172. package/dist/types/util/groups.d.ts +3 -0
  173. package/dist/types/util/hitDetection.d.ts +2 -2
  174. package/dist/types/util/partitionPoint.d.ts +1 -0
  175. package/dist/types/util/weakMemo.d.ts +1 -0
  176. package/dist/types/version.d.ts +1 -1
  177. package/dist/util/SpatialIndex.js +8 -5
  178. package/dist/util/edgeCurves.js +7 -4
  179. package/dist/util/geometry.js +3 -1
  180. package/dist/util/groups.js +10 -0
  181. package/dist/util/hitDetection.js +9 -6
  182. package/dist/util/partitionPoint.js +6 -0
  183. package/dist/util/weakMemo.js +6 -0
  184. package/dist/version.js +1 -1
  185. package/dist/viewport.js +19 -17
  186. package/dist/walkEncoding.js +18 -14
  187. package/dist/walkHighlight.js +19 -15
  188. package/dist/walkKey.js +9 -6
  189. package/package.json +2 -2
  190. package/dist/chunks/chunk-ZY2AFL4Y.js +0 -43
@@ -1,11 +1,15 @@
1
1
  import {
2
2
  GBZ_CUT_DEFAULTS,
3
+ NoReferenceSampleError,
4
+ aliasedSample,
3
5
  cutWindowGFA,
4
6
  haplotypeWanted,
5
7
  referencePathQuery,
6
- referenceSamplesOf,
7
- resolveReferenceSample
8
- } from "./chunk-Q7LYHGGQ.js";
8
+ referenceSamplesOf
9
+ } from "./chunk-GIHTHYXY.js";
10
+ import {
11
+ panSNSample
12
+ } from "./chunk-4XWZNPQ2.js";
9
13
 
10
14
  // src/gbzCut.ts
11
15
  import { GBZBase } from "@gmod/gbz-base";
@@ -13,6 +17,9 @@ var HPRC_GBZ = {
13
17
  db: "https://s3-us-west-2.amazonaws.com/human-pangenomics/pangenomes/freeze/release2/minigraph-cactus/v2.1/hprc-v2.1-mc-grch38/hprc-v2.1-mc-grch38.gbz.db",
14
18
  index: "https://jbrowse.org/demos/hprc/hprc-v2.1-mc-grch38.haplotype-index.f3.db"
15
19
  };
20
+ function gbzLocations({ db, index }) {
21
+ return db === "hprc" ? { db: HPRC_GBZ.db, index: index ?? HPRC_GBZ.index } : { db, index };
22
+ }
16
23
  function haplotypeIndexBeside(db) {
17
24
  const GBZ_DB = /\.gbz\.db$/i;
18
25
  return GBZ_DB.test(db) ? db.replace(GBZ_DB, ".haplotype-index.db") : void 0;
@@ -36,18 +43,14 @@ async function openGbz(db, index) {
36
43
  return { base, referenceSamples: await referenceSamplesOf(base) };
37
44
  }
38
45
  function referenceSample(ref, samples) {
39
- try {
40
- return resolveReferenceSample({
41
- configured: "",
42
- anchorPrefix: ref ?? samples[0] ?? "",
43
- referenceSamples: samples
44
- });
45
- } catch (e) {
46
- if (ref) {
47
- return ref;
48
- }
49
- throw e;
46
+ if (ref) {
47
+ return aliasedSample(panSNSample(ref), samples) ?? ref;
48
+ }
49
+ const first = samples[0];
50
+ if (first === void 0) {
51
+ throw new NoReferenceSampleError("", samples);
50
52
  }
53
+ return first;
51
54
  }
52
55
  async function cutGbzRegion({ base, referenceSamples }, src, signal) {
53
56
  const region = parseRegion(src.region);
@@ -70,6 +73,7 @@ async function cutGbzRegion({ base, referenceSamples }, src, signal) {
70
73
 
71
74
  export {
72
75
  HPRC_GBZ,
76
+ gbzLocations,
73
77
  haplotypeIndexBeside,
74
78
  parseRegion,
75
79
  openGbz,
@@ -0,0 +1,327 @@
1
+ import {
2
+ pathSteps
3
+ } from "./chunk-FW2R7UDZ.js";
4
+ import {
5
+ pathOrigin
6
+ } from "./chunk-B5X2RLJG.js";
7
+ import {
8
+ PathVisitsBuilder
9
+ } from "./chunk-ZPZ7GNBT.js";
10
+ import {
11
+ isBackbone
12
+ } from "./chunk-RJWPJCIB.js";
13
+ import {
14
+ partitionPoint
15
+ } from "./chunk-HOAIOEI7.js";
16
+
17
+ // src/tubeMap/coarsen.ts
18
+ function readWalk(path, steps) {
19
+ const runs = [];
20
+ const open = () => ({ a: -Infinity, b: Infinity, detour: [], bp: 0 });
21
+ const gaps = [open()];
22
+ for (const { node, strand } of steps) {
23
+ const gap = gaps.at(-1);
24
+ const last = runs.at(-1);
25
+ if (isBackbone(node)) {
26
+ const start = node.stable.start;
27
+ const end = start + node.length;
28
+ const inverted = strand !== (node.stable.strand ?? "+");
29
+ const joins = last !== void 0 && gap.detour.length === 0;
30
+ if (joins && !last.inverted && !inverted && last.end === start) {
31
+ last.end = end;
32
+ } else if (joins && last.inverted && inverted && last.start === end) {
33
+ last.start = start;
34
+ } else {
35
+ runs.push({ start, end, inverted });
36
+ gaps.push(open());
37
+ }
38
+ } else {
39
+ gap.detour.push({ node, strand });
40
+ gap.bp += node.length;
41
+ }
42
+ }
43
+ runs.forEach((run, i) => {
44
+ gaps[i].b = run.start;
45
+ gaps[i + 1].a = run.end;
46
+ });
47
+ return { path, runs, gaps };
48
+ }
49
+ function isSmall(gap, sigma) {
50
+ return Number.isFinite(gap.a) && Number.isFinite(gap.b) && gap.b >= gap.a && Math.max(gap.b - gap.a, gap.bp) < sigma;
51
+ }
52
+ function strictlyInside(cuts, a, b) {
53
+ const i = partitionPoint(cuts.length, (j) => cuts[j] <= a);
54
+ return i < cuts.length && cuts[i] < b;
55
+ }
56
+ function referenceGaps(backbone) {
57
+ const cuts = /* @__PURE__ */ new Map();
58
+ for (let i = 1; i < backbone.length; i++) {
59
+ const prev = backbone[i - 1];
60
+ const node = backbone[i];
61
+ const end = prev.stable.start + prev.length;
62
+ if (end !== node.stable.start) {
63
+ cuts.set(end, "reference-gap");
64
+ cuts.set(node.stable.start, "reference-gap");
65
+ }
66
+ }
67
+ return cuts;
68
+ }
69
+ function findCuts(walks, sigma, cuts) {
70
+ const cut = (bp, cause) => {
71
+ if (Number.isFinite(bp) && !cuts.has(bp)) {
72
+ cuts.set(bp, cause);
73
+ }
74
+ };
75
+ for (const { runs, gaps } of walks) {
76
+ const first = runs[0];
77
+ const last = runs.at(-1);
78
+ if (first && last) {
79
+ cut(first.start, "walk-end");
80
+ cut(last.end, "walk-end");
81
+ }
82
+ for (const run of runs) {
83
+ if (run.inverted && run.end - run.start >= sigma) {
84
+ cut(run.start, "inversion");
85
+ cut(run.end, "inversion");
86
+ }
87
+ }
88
+ for (const gap of gaps) {
89
+ if (gap.b < gap.a) {
90
+ cut(gap.a, "backward");
91
+ cut(gap.b, "backward");
92
+ } else if (!isSmall(gap, sigma)) {
93
+ cut(gap.a, "variant");
94
+ cut(gap.b, "variant");
95
+ }
96
+ }
97
+ }
98
+ const spans = walks.flatMap(({ runs, gaps }) => [
99
+ ...gaps.filter((g) => isSmall(g, sigma)).map((g) => [g.a, g.b]),
100
+ ...runs.filter((r) => r.inverted && r.end - r.start < sigma).map((r) => [r.start, r.end])
101
+ ]);
102
+ for (let changed = true; changed; ) {
103
+ changed = false;
104
+ const sorted = [...cuts.keys()].sort((x, y) => x - y);
105
+ for (const [a, b] of spans) {
106
+ if (strictlyInside(sorted, a, b)) {
107
+ changed ||= !cuts.has(a) || !cuts.has(b);
108
+ cut(a, "overlap");
109
+ cut(b, "overlap");
110
+ }
111
+ }
112
+ }
113
+ return cuts;
114
+ }
115
+ function mergeReference(backbone, cuts) {
116
+ const merged = [];
117
+ let group = [];
118
+ const close = () => {
119
+ const first = group[0];
120
+ const last = group.at(-1);
121
+ if (first && last) {
122
+ const bp0 = first.stable.start;
123
+ const bp1 = last.stable.start + last.length;
124
+ const name = `${bp0}-${bp1}`;
125
+ merged.push({
126
+ node: {
127
+ id: `${name}+`,
128
+ name,
129
+ length: bp1 - bp0,
130
+ depth: 0,
131
+ stable: {
132
+ refName: first.stable.refName,
133
+ start: bp0,
134
+ rank: 0,
135
+ strand: "+"
136
+ }
137
+ },
138
+ members: group
139
+ });
140
+ }
141
+ group = [];
142
+ };
143
+ for (const node of backbone) {
144
+ if (cuts.has(node.stable.start)) {
145
+ close();
146
+ }
147
+ group.push(node);
148
+ }
149
+ close();
150
+ return merged;
151
+ }
152
+ function lastAtMost(items, key, x) {
153
+ return Math.max(0, partitionPoint(items.length, (i) => key(items[i]) <= x) - 1);
154
+ }
155
+ function coarsenTubeMap(graph, sigma) {
156
+ const backbone = graph.nodes.filter(isBackbone).sort((a, b) => a.stable.start - b.stable.start);
157
+ const paths = graph.paths ?? [];
158
+ if (backbone.length === 0 || paths.length === 0) {
159
+ return void 0;
160
+ }
161
+ const stepsOf = pathSteps(graph);
162
+ const walks = paths.map((p, i) => readWalk(p, stepsOf[i]));
163
+ const cuts = findCuts(walks, sigma, referenceGaps(backbone));
164
+ const sortedCuts = [...cuts.keys()].sort((x, y) => x - y);
165
+ const merged = mergeReference(backbone, cuts);
166
+ const mergedAt = (bp) => lastAtMost(merged, (m) => m.node.stable.start, bp);
167
+ const members = /* @__PURE__ */ new Map();
168
+ const coarseOf = /* @__PURE__ */ new Map();
169
+ for (const m of merged) {
170
+ members.set(
171
+ m.node.id,
172
+ m.members.map((n) => n.id)
173
+ );
174
+ for (const n of m.members) {
175
+ coarseOf.set(n.id, m.node.id);
176
+ }
177
+ }
178
+ const routes = /* @__PURE__ */ new Map();
179
+ const routeFor = (gap) => {
180
+ const key = `${gap.a} ${gap.b} ${gap.detour.map((s) => s.node.id + s.strand).join(",")}`;
181
+ let node = routes.get(key);
182
+ if (!node) {
183
+ const name = `r${routes.size}`;
184
+ node = {
185
+ id: `${name}+`,
186
+ name,
187
+ length: gap.bp,
188
+ depth: 0,
189
+ stable: {
190
+ refName: backbone[0].stable.refName,
191
+ start: Number.isFinite(gap.a) ? gap.a : gap.b,
192
+ rank: 1,
193
+ strand: "+"
194
+ }
195
+ };
196
+ routes.set(key, node);
197
+ members.set(
198
+ node.id,
199
+ gap.detour.map((s) => s.node.id)
200
+ );
201
+ for (const s of gap.detour) {
202
+ if (!coarseOf.has(s.node.id)) {
203
+ coarseOf.set(s.node.id, node.id);
204
+ }
205
+ }
206
+ }
207
+ return node;
208
+ };
209
+ const deviations = /* @__PURE__ */ new Map();
210
+ const coarsePaths = [];
211
+ const pathVisits = new PathVisitsBuilder();
212
+ const edges = /* @__PURE__ */ new Map();
213
+ const depth = /* @__PURE__ */ new Map();
214
+ for (const { path, runs, gaps } of walks) {
215
+ const steps = [];
216
+ const devs = [];
217
+ let continuing = false;
218
+ const append = (node, strand) => {
219
+ const last = steps.at(-1);
220
+ if (!(continuing && last?.node === node && last.strand === strand)) {
221
+ steps.push({ node, strand });
222
+ }
223
+ continuing = true;
224
+ };
225
+ const structural = (gap) => {
226
+ continuing = false;
227
+ if (gap.detour.length > 0) {
228
+ append(routeFor(gap), "+");
229
+ continuing = false;
230
+ }
231
+ };
232
+ const fold = (gap) => {
233
+ if (gap.bp > 0 || gap.b > gap.a) {
234
+ devs.push({ start: gap.a, end: gap.b, bp: gap.bp });
235
+ }
236
+ const home = merged[mergedAt(gap.b > gap.a ? gap.a : gap.a - 1)];
237
+ for (const s of gap.detour) {
238
+ if (!coarseOf.has(s.node.id)) {
239
+ coarseOf.set(s.node.id, home.node.id);
240
+ members.get(home.node.id).push(s.node.id);
241
+ }
242
+ }
243
+ };
244
+ runs.forEach((run, i) => {
245
+ const gap = gaps[i];
246
+ if (isSmall(gap, sigma) && !strictlyInside(sortedCuts, gap.a, gap.b)) {
247
+ fold(gap);
248
+ } else {
249
+ structural(gap);
250
+ }
251
+ const i0 = mergedAt(run.start);
252
+ const i1 = mergedAt(run.end - 1);
253
+ const small = run.end - run.start < sigma;
254
+ if (run.inverted && !small) {
255
+ continuing = false;
256
+ for (let j = i1; j >= i0; j--) {
257
+ append(merged[j].node, "-");
258
+ }
259
+ continuing = false;
260
+ } else {
261
+ if (run.inverted) {
262
+ devs.push({
263
+ start: run.start,
264
+ end: run.end,
265
+ bp: run.end - run.start,
266
+ inverted: true
267
+ });
268
+ }
269
+ for (let j = i0; j <= i1; j++) {
270
+ append(merged[j].node, "+");
271
+ }
272
+ }
273
+ });
274
+ structural(gaps.at(-1));
275
+ const visitName = pathOrigin(path.name).name;
276
+ let pos = 0;
277
+ steps.forEach(({ node, strand }, i) => {
278
+ depth.set(node.id, (depth.get(node.id) ?? 0) + 1);
279
+ pathVisits.add(
280
+ node.name,
281
+ visitName,
282
+ path.sample ?? visitName,
283
+ pos,
284
+ strand === "-"
285
+ );
286
+ pos += node.length;
287
+ const next = steps[i + 1];
288
+ if (next) {
289
+ const key = `${node.id}${strand} ${next.node.id}${next.strand}`;
290
+ const edge = edges.get(key);
291
+ if (edge) {
292
+ edge.pathIds.push(path.name);
293
+ } else {
294
+ edges.set(key, {
295
+ from: node.id,
296
+ to: next.node.id,
297
+ fromStrand: strand,
298
+ toStrand: next.strand,
299
+ pathIds: [path.name]
300
+ });
301
+ }
302
+ }
303
+ });
304
+ coarsePaths.push({ ...path, nodeIds: steps.map((s) => s.node.id) });
305
+ deviations.set(path.name, devs);
306
+ }
307
+ const nodes = [...merged.map((m) => m.node), ...routes.values()].filter((n) => depth.has(n.id)).map((n) => ({ ...n, depth: depth.get(n.id) }));
308
+ return {
309
+ graph: {
310
+ ...graph,
311
+ nodes,
312
+ edges: [...edges.values()],
313
+ paths: coarsePaths,
314
+ pathVisits: pathVisits.build(),
315
+ reads: void 0
316
+ },
317
+ members,
318
+ coarseOf,
319
+ deviations,
320
+ cuts
321
+ };
322
+ }
323
+
324
+ export {
325
+ lastAtMost,
326
+ coarsenTubeMap
327
+ };
@@ -1,3 +1,7 @@
1
+ import {
2
+ partitionPoint
3
+ } from "./chunk-HOAIOEI7.js";
4
+
1
5
  // src/tubeMap/warp.ts
2
6
  var MAX_GAP_PX = 24;
3
7
  var MAX_GAP_SHARE = 0.5;
@@ -55,17 +59,8 @@ function warpX(knots, tx) {
55
59
  if (tx >= last.tx) {
56
60
  return last.sx + (tx - last.tx);
57
61
  }
58
- let lo = 0;
59
- let hi = n - 1;
60
- while (hi - lo > 1) {
61
- const mid = lo + hi >> 1;
62
- if (knots[mid].tx <= tx) {
63
- lo = mid;
64
- } else {
65
- hi = mid;
66
- }
67
- }
68
- const a = knots[lo];
62
+ const hi = 1 + partitionPoint(n - 2, (i) => knots[i + 1].tx <= tx);
63
+ const a = knots[hi - 1];
69
64
  const b = knots[hi];
70
65
  const span = b.tx - a.tx;
71
66
  return span > 0 ? a.sx + (tx - a.tx) / span * (b.sx - a.sx) : a.sx;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  projectAlleles
3
- } from "./chunk-RVS2QCOX.js";
3
+ } from "./chunk-3GLG3ZLE.js";
4
4
  import {
5
5
  buildNeighbors
6
- } from "./chunk-ES2N6V56.js";
6
+ } from "./chunk-VX656OAZ.js";
7
7
 
8
8
  // src/layout/placeOffReference.ts
9
9
  var MIN_DELETION_BP = 1;
@@ -4,10 +4,10 @@ import {
4
4
  import {
5
5
  pathOrigin,
6
6
  surveyPaths
7
- } from "./chunk-M6LK4GII.js";
7
+ } from "./chunk-B5X2RLJG.js";
8
8
 
9
9
  // src/gfa/gfaConverter.ts
10
- function surveySegments(gfaGraph) {
10
+ function surveySegments(gfaGraph, pathSteps) {
11
11
  const canonical = /* @__PURE__ */ new Map();
12
12
  const traversals = /* @__PURE__ */ new Map();
13
13
  function claim(id, strand) {
@@ -26,36 +26,35 @@ function surveySegments(gfaGraph) {
26
26
  claim(link.source, link.strand1 === "-" ? "-" : "+");
27
27
  claim(link.target, link.strand2 === "-" ? "-" : "+");
28
28
  }
29
- for (const gfaPath of gfaGraph.paths) {
30
- for (const segment of gfaPath.path.split(",")) {
31
- traverse(segment.slice(0, -1), segment.endsWith("-") ? "-" : "+");
29
+ for (const { steps } of pathSteps) {
30
+ for (const step of steps) {
31
+ traverse(step.id, step.strand);
32
32
  }
33
33
  }
34
34
  for (const walk of gfaGraph.walks) {
35
- for (const seg of walk.segments) {
36
- traverse(seg.id, seg.strand === "-" ? "-" : "+");
35
+ for (const step of walk.segments) {
36
+ traverse(step.id, step.strand);
37
37
  }
38
38
  }
39
39
  return { canonical, traversals };
40
40
  }
41
41
  var walkStart = (w) => w.start === -1 ? 0 : w.start;
42
- var stranded = (s) => s.strand === "+" || s.strand === "-";
43
- function anchorablePaths(gfaGraph) {
42
+ function stepsOfPath(p) {
43
+ return {
44
+ ...pathOrigin(p.name),
45
+ steps: p.path.split(",").map((segment) => ({
46
+ id: segment.slice(0, -1),
47
+ strand: segment.endsWith("-") ? "-" : "+"
48
+ }))
49
+ };
50
+ }
51
+ function anchorablePaths(gfaGraph, pathSteps) {
44
52
  return [
45
- ...gfaGraph.paths.map((p) => ({
46
- ...pathOrigin(p.name),
47
- steps: p.path.split(",").map((segment) => ({
48
- id: segment.slice(0, -1),
49
- strand: segment.endsWith("-") ? "-" : "+"
50
- }))
51
- })),
53
+ ...pathSteps,
52
54
  ...gfaGraph.walks.map((w) => ({
53
55
  name: `${w.sample}#${w.haplotype}#${w.contig}`,
54
56
  start: walkStart(w),
55
- steps: w.segments.every(stranded) ? w.segments : w.segments.map((s) => ({
56
- id: s.id,
57
- strand: s.strand === "-" ? "-" : "+"
58
- }))
57
+ steps: w.segments
59
58
  }))
60
59
  ];
61
60
  }
@@ -85,7 +84,8 @@ function makeNode(gfaNode, strand, depth) {
85
84
  function convertGFAToGraph(gfaGraph, name = "Imported GFA") {
86
85
  const nodes = [];
87
86
  const edges = [];
88
- const { canonical, traversals } = surveySegments(gfaGraph);
87
+ const pathSteps = gfaGraph.paths.map(stepsOfPath);
88
+ const { canonical, traversals } = surveySegments(gfaGraph, pathSteps);
89
89
  const nodeIds = /* @__PURE__ */ new Map();
90
90
  const nodeId = (segmentId) => {
91
91
  let id = nodeIds.get(segmentId);
@@ -95,12 +95,12 @@ function convertGFAToGraph(gfaGraph, name = "Imported GFA") {
95
95
  }
96
96
  return id;
97
97
  };
98
- const declared = /* @__PURE__ */ new Set();
98
+ const lengths = /* @__PURE__ */ new Map();
99
99
  for (const gfaNode of gfaGraph.nodes) {
100
- if (declared.has(gfaNode.id)) {
100
+ if (lengths.has(gfaNode.id)) {
101
101
  continue;
102
102
  }
103
- declared.add(gfaNode.id);
103
+ lengths.set(gfaNode.id, gfaNode.length);
104
104
  const depth = statedDepth(gfaNode) ?? Math.max(traversals.get(gfaNode.id) ?? 1, 1);
105
105
  nodes.push(makeNode(gfaNode, canonical.get(gfaNode.id) ?? "+", depth));
106
106
  }
@@ -137,15 +137,12 @@ function convertGFAToGraph(gfaGraph, name = "Imported GFA") {
137
137
  pairPaths(nodeIds2[i], nodeIds2[i + 1])?.add(name2);
138
138
  }
139
139
  }
140
- for (const gfaPath of gfaGraph.paths) {
141
- const nodeIds2 = gfaPath.path.split(",").map((segment) => nodeId(segment.slice(0, -1)));
142
- paths.push({
143
- name: gfaPath.name,
144
- nodeIds: nodeIds2,
145
- start: pathOrigin(gfaPath.name).start
146
- });
147
- recordPathEdges(nodeIds2, gfaPath.name);
148
- }
140
+ gfaGraph.paths.forEach(({ name: name2 }, i) => {
141
+ const { start, steps } = pathSteps[i];
142
+ const nodeIds2 = steps.map((step) => nodeId(step.id));
143
+ paths.push({ name: name2, nodeIds: nodeIds2, start });
144
+ recordPathEdges(nodeIds2, name2);
145
+ });
149
146
  for (const walk of gfaGraph.walks) {
150
147
  const nodeIds2 = walk.segments.map((seg) => nodeId(seg.id));
151
148
  const name2 = `${walk.sample}#${walk.haplotype}#${walk.contig}`;
@@ -165,8 +162,10 @@ function convertGFAToGraph(gfaGraph, name = "Imported GFA") {
165
162
  edge.pathIds = [...pathIds];
166
163
  }
167
164
  });
168
- const lengths = new Map(gfaGraph.nodes.map((n) => [n.id, n.length]));
169
- const anchoring = gfaGraph.paths.length > 0 || gfaGraph.walks.length > 0 ? surveyPaths(anchorablePaths(gfaGraph), (id) => lengths.get(id) ?? 0) : void 0;
165
+ const anchoring = gfaGraph.paths.length > 0 || gfaGraph.walks.length > 0 ? surveyPaths(
166
+ anchorablePaths(gfaGraph, pathSteps),
167
+ (id) => lengths.get(id) ?? 0
168
+ ) : void 0;
170
169
  return {
171
170
  name,
172
171
  nodes,
@@ -1,12 +1,15 @@
1
1
  import {
2
2
  EdgeSpatialIndex,
3
3
  SpatialIndex
4
- } from "./chunk-KBEP7VYK.js";
4
+ } from "./chunk-3VCKBSML.js";
5
+ import {
6
+ weakMemo
7
+ } from "./chunk-HMXCN6PG.js";
5
8
  import {
6
9
  pathRibbonOffsets,
7
10
  translateCurves,
8
11
  yToXOf
9
- } from "./chunk-7SRWJLSC.js";
12
+ } from "./chunk-UBQSRCWR.js";
10
13
 
11
14
  // src/util/hitDetection.ts
12
15
  function distanceToSegment(px, py, x1, y1, x2, y2) {
@@ -19,40 +22,26 @@ function distanceToSegment(px, py, x1, y1, x2, y2) {
19
22
  const t = Math.max(0, Math.min(1, ((px - x1) * dx + (py - y1) * dy) / lenSq));
20
23
  return Math.hypot(px - (x1 + t * dx), py - (y1 + t * dy));
21
24
  }
22
- function distanceToCubicBezier(px, py, x1, y1, cx1, cy1, cx2, cy2, x2, y2) {
25
+ function distanceToCubicBezier(px, py, c) {
23
26
  let minDist = Infinity;
24
27
  const samples = 20;
25
- let lastX = x1;
26
- let lastY = y1;
28
+ let lastX = c.x0;
29
+ let lastY = c.y0;
27
30
  for (let i = 1; i <= samples; i++) {
28
31
  const t = i / samples;
29
32
  const u = 1 - t;
30
- const bx = u * u * u * x1 + 3 * u * u * t * cx1 + 3 * u * t * t * cx2 + t * t * t * x2;
31
- const by = u * u * u * y1 + 3 * u * u * t * cy1 + 3 * u * t * t * cy2 + t * t * t * y2;
33
+ const bx = u * u * u * c.x0 + 3 * u * u * t * c.cx0 + 3 * u * t * t * c.cx1 + t * t * t * c.x1;
34
+ const by = u * u * u * c.y0 + 3 * u * u * t * c.cy0 + 3 * u * t * t * c.cy1 + t * t * t * c.y1;
32
35
  minDist = Math.min(minDist, distanceToSegment(px, py, lastX, lastY, bx, by));
33
36
  lastX = bx;
34
37
  lastY = by;
35
38
  }
36
39
  return minDist;
37
40
  }
38
- function distanceToBezierCurve(px, py, c) {
39
- return distanceToCubicBezier(
40
- px,
41
- py,
42
- c.x0,
43
- c.y0,
44
- c.cx0,
45
- c.cy0,
46
- c.cx1,
47
- c.cy1,
48
- c.x1,
49
- c.y1
50
- );
51
- }
52
41
  function distanceToEdgeCurves(px, py, curves, yToX = 1) {
53
42
  let minDist = Infinity;
54
43
  for (const c of curves) {
55
- const d = distanceToBezierCurve(
44
+ const d = distanceToCubicBezier(
56
45
  px,
57
46
  py,
58
47
  yToX === 1 ? c : {
@@ -72,45 +61,39 @@ function distanceToEdgeCurves(px, py, curves, yToX = 1) {
72
61
  }
73
62
  return minDist;
74
63
  }
75
- var nodeCache = /* @__PURE__ */ new WeakMap();
64
+ var nodeCache = weakMemo();
76
65
  function getSpatialIndex(nodePositions, version) {
77
- const cached = nodeCache.get(nodePositions);
78
- if (cached?.version === version) {
79
- return cached.index;
80
- }
81
- const index = new SpatialIndex(nodePositions);
82
- nodeCache.set(nodePositions, { version, index });
83
- return index;
66
+ return nodeCache(
67
+ nodePositions,
68
+ [version],
69
+ () => new SpatialIndex(nodePositions)
70
+ );
84
71
  }
85
- var edgeCache = /* @__PURE__ */ new WeakMap();
72
+ var edgeCache = weakMemo();
86
73
  function getEdgeSpatialIndex(nodePositions, graph, drawPaths, axis, version, deletions, routes, stranded = false) {
87
- const cached = edgeCache.get(nodePositions);
88
- if (cached?.graph === graph && cached.drawPaths === drawPaths && cached.scaleX === axis.scaleX && cached.scaleY === axis.scaleY && cached.version === version && cached.deletions === deletions && cached.routes === routes && cached.stranded === stranded) {
89
- return cached.index;
90
- }
91
- const index = new EdgeSpatialIndex(
74
+ return edgeCache(
92
75
  nodePositions,
93
- graph,
94
- drawPaths,
95
- axis,
96
- void 0,
97
- deletions,
98
- version,
99
- routes,
100
- stranded
76
+ [
77
+ graph,
78
+ drawPaths,
79
+ axis.scaleX,
80
+ axis.scaleY,
81
+ version,
82
+ deletions,
83
+ routes,
84
+ stranded
85
+ ],
86
+ () => new EdgeSpatialIndex(
87
+ nodePositions,
88
+ graph,
89
+ drawPaths,
90
+ axis,
91
+ deletions,
92
+ version,
93
+ routes,
94
+ stranded
95
+ )
101
96
  );
102
- edgeCache.set(nodePositions, {
103
- graph,
104
- drawPaths,
105
- scaleX: axis.scaleX,
106
- scaleY: axis.scaleY,
107
- version,
108
- index,
109
- deletions,
110
- routes,
111
- stranded
112
- });
113
- return index;
114
97
  }
115
98
  var MIN_NODE_REACH_PX = 5;
116
99
  function findHoveredNode(nodePositions, graphX, graphY, axis, version = 0, ink) {