@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,476 @@
1
+ import {
2
+ RAMP_GRADIENT_CSS,
3
+ RAMP_GRADIENT_STOPS,
4
+ rampHueCss,
5
+ rampStops
6
+ } from "./chunk-5QT6NPSO.js";
7
+ import {
8
+ REFERENCE_RAMP_ALT_CSS
9
+ } from "./chunk-3WHKR5TY.js";
10
+ import {
11
+ LABEL_CHAR_PX
12
+ } from "./chunk-AB35TJST.js";
13
+ import {
14
+ ROW_HEIGHT_PX
15
+ } from "./chunk-CPMHA4W5.js";
16
+ import {
17
+ el
18
+ } from "./chunk-NNODIW4U.js";
19
+
20
+ // src/layout/walkRowDraw.ts
21
+ var ON_REFERENCE = "#2f8fd6";
22
+ var OFF_REFERENCE = "#8e3fbf";
23
+ var OUTSIDE_CUT = "#bdbdbd";
24
+ var GENE_INK = "#1c1c22";
25
+ var BAR_PX = 12;
26
+ var GAP_PX = 4;
27
+ var MIN_TILE_PX = 3;
28
+ function kb(bp) {
29
+ return `${(bp / 1e3).toFixed(bp < 1e4 ? 1 : 0)} kb`;
30
+ }
31
+ function units(bp, unit) {
32
+ return unit ? ` \u2248 ${Math.round(bp / unit)} units` : "";
33
+ }
34
+ function walkRowReadout(row, reference, unit, call) {
35
+ const { bp, gapBp, complete } = row;
36
+ if (!reference) {
37
+ return `${kb(bp)}${units(bp, unit)}`;
38
+ }
39
+ const delta = bp - reference.bp;
40
+ const against = delta === 0 ? "" : ` (${delta > 0 ? "+" : "\u2212"}${kb(Math.abs(delta))})`;
41
+ const outside = gapBp > 0 ? ` \xB7 ${kb(gapBp)} outside the cut` : "";
42
+ const called = call ? ` \xB7 called ${kb(call.bp)}${call.spanningReads === 0 ? " \xB7 no spanning read" : ""}` : "";
43
+ return `${kb(bp)}${units(bp, unit)}${against}${outside}${complete ? "" : " \xB7 partial walk"}${called}`;
44
+ }
45
+ function readoutPlacement(text, endX, width) {
46
+ const x = endX + 6;
47
+ const fits = x + text.length * LABEL_CHAR_PX < width;
48
+ return fits ? { x, anchor: "start", halo: false } : { x: endX - 6, anchor: "end", halo: true };
49
+ }
50
+ function unitTicks(bp, unit, pxPerBp) {
51
+ if (unit * pxPerBp < MIN_TILE_PX) {
52
+ return [];
53
+ }
54
+ const ticks = [];
55
+ for (let k = unit; k < bp; k += unit) {
56
+ ticks.push(k);
57
+ }
58
+ return ticks;
59
+ }
60
+ function runPaint(run, ramp) {
61
+ if (run.gap) {
62
+ return { fill: OUTSIDE_CUT };
63
+ }
64
+ if (!ramp) {
65
+ return { fill: run.onReference ? ON_REFERENCE : OFF_REFERENCE };
66
+ }
67
+ if (run.referenceStart === void 0) {
68
+ return { fill: REFERENCE_RAMP_ALT_CSS };
69
+ }
70
+ const stops = rampStops({ ...run, start: run.referenceStart }, ramp);
71
+ return stops.length === 1 ? { fill: rampHueCss(stops[0]) } : { stops: stops.map(rampHueCss) };
72
+ }
73
+ function alongRow(axis, start, end) {
74
+ return axis.reversed ? { start: axis.start - end, end: axis.start - start } : { start: start - axis.start, end: end - axis.start };
75
+ }
76
+ function rowSpan(axis, bp) {
77
+ return axis.reversed ? { start: axis.start - bp, end: axis.start } : { start: axis.start, end: axis.start + bp };
78
+ }
79
+ function genesOnRow(row, genes) {
80
+ const contig = row.axis?.contig;
81
+ return genes.filter(
82
+ (g) => g.refName === contig || g.refName.endsWith(`#${contig}`)
83
+ );
84
+ }
85
+ function placeRowGenes(rows, byRow) {
86
+ const placed = /* @__PURE__ */ new Map();
87
+ for (const row of rows) {
88
+ const genes = byRow.get(row.name);
89
+ if (!row.axis || !genes) {
90
+ continue;
91
+ }
92
+ const axis = row.axis;
93
+ const clip = ({ start, end }) => ({
94
+ start: Math.max(0, start),
95
+ end: Math.min(row.bp, end)
96
+ });
97
+ placed.set(
98
+ row.name,
99
+ genes.map((g) => ({
100
+ name: g.name,
101
+ ...clip(alongRow(axis, g.start, g.end)),
102
+ exons: g.exons.map((e) => clip(alongRow(axis, e.start, e.end))).filter((e) => e.end > e.start)
103
+ })).filter((g) => g.end > g.start).sort((a, b) => a.start - b.start)
104
+ );
105
+ }
106
+ return placed;
107
+ }
108
+ var GENE_FONT_PX = 9;
109
+ var GENE_CHAR_PX = 5.2;
110
+ var MIN_LETTERED_BAR_PX = 8;
111
+ var genePad = (rowPx, barPx) => Math.min(2, (rowPx - barPx) / 2 - 1);
112
+ function boxesGenes(rowPx, barPx) {
113
+ return genePad(rowPx, barPx) >= 1;
114
+ }
115
+ function rowGeneBoxes(genes, X, y, { rowPx = ROW_HEIGHT_PX, barPx = BAR_PX } = {}) {
116
+ if (!boxesGenes(rowPx, barPx)) {
117
+ return [];
118
+ }
119
+ const pad = genePad(rowPx, barPx);
120
+ const boxes = genes.map((g) => {
121
+ const x = X(g.start);
122
+ return {
123
+ g,
124
+ x,
125
+ w: Math.max(2, X(g.end) - x)
126
+ };
127
+ });
128
+ const taken = [];
129
+ const named = new Set(
130
+ (barPx >= MIN_LETTERED_BAR_PX ? [...boxes] : []).sort((a, b) => a.w - b.w).filter(({ g, x, w }) => {
131
+ const half = g.name.length * GENE_CHAR_PX / 2;
132
+ const at = [x + w / 2 - half, x + w / 2 + half];
133
+ if (2 * half > w + 6 || taken.some(([a, b]) => at[0] < b + 2 && at[1] > a - 2)) {
134
+ return false;
135
+ }
136
+ taken.push(at);
137
+ return true;
138
+ })
139
+ );
140
+ return boxes.map((box) => ({
141
+ name: box.g.name,
142
+ x: box.x,
143
+ y: y - barPx / 2 - pad,
144
+ w: box.w,
145
+ h: barPx + 2 * pad,
146
+ exons: box.g.exons.map((e) => ({
147
+ x: X(e.start),
148
+ w: Math.max(1, X(e.end) - X(e.start))
149
+ })),
150
+ label: named.has(box) ? { x: box.x + box.w / 2, y: y + 3, size: GENE_FONT_PX } : void 0
151
+ }));
152
+ }
153
+ var rowsText = (n) => `${n} row${n === 1 ? "" : "s"}`;
154
+ function walkRowsKey(bars, o = {}) {
155
+ const entries = [
156
+ {
157
+ swatch: o.ramp ? { kind: "bar", fill: o.rampCss ?? RAMP_GRADIENT_CSS, ramp: true } : { kind: "bar", fill: ON_REFERENCE },
158
+ label: `on ${bars.reference.label}'s path`
159
+ },
160
+ {
161
+ swatch: {
162
+ kind: "bar",
163
+ fill: o.ramp ? REFERENCE_RAMP_ALT_CSS : OFF_REFERENCE
164
+ },
165
+ label: `off ${bars.reference.label}'s path`
166
+ }
167
+ ];
168
+ if ([bars.reference, ...bars.rows].some((row) => row.gapBp > 0)) {
169
+ entries.push({
170
+ swatch: { kind: "gap", fill: OUTSIDE_CUT },
171
+ label: "walked outside the cut"
172
+ });
173
+ }
174
+ if (o.genes?.crowded) {
175
+ entries.push({
176
+ swatch: { kind: "gene" },
177
+ label: "genes left out: too many rows to box them in",
178
+ note: true
179
+ });
180
+ } else if (o.genes) {
181
+ entries.push({
182
+ swatch: { kind: "gene" },
183
+ label: "genes, each row's own annotation"
184
+ });
185
+ if (o.genes.untracked) {
186
+ entries.push({
187
+ swatch: { kind: "gene" },
188
+ label: `no gene track for ${rowsText(o.genes.untracked)}`,
189
+ note: true
190
+ });
191
+ }
192
+ if (o.genes.unplaced) {
193
+ entries.push({
194
+ swatch: { kind: "gene" },
195
+ label: `no contig coordinates for ${rowsText(o.genes.unplaced)}`,
196
+ note: true
197
+ });
198
+ }
199
+ if (o.genes.unread) {
200
+ entries.push({
201
+ swatch: { kind: "gene" },
202
+ label: `genes not read for the last ${rowsText(o.genes.unread)}`,
203
+ note: true
204
+ });
205
+ }
206
+ }
207
+ return entries;
208
+ }
209
+ var CALL_TICK = "#111";
210
+ var UNBACKED_TICK = "#9e9e9e";
211
+ var DISAGREES = "#c62828";
212
+ function walkRowsKeyTree(entries, x, y, idPrefix = "walk-key") {
213
+ let at = 0;
214
+ const parts = entries.flatMap((e, i) => {
215
+ const rampId = `${idPrefix}-ramp-${i}`;
216
+ const ramp = !e.note && e.swatch.kind === "bar" && e.swatch.ramp ? el(
217
+ "linearGradient",
218
+ { id: rampId },
219
+ ...RAMP_GRADIENT_STOPS.map(
220
+ (s) => el("stop", { offset: s.offset, "stop-color": s.color })
221
+ )
222
+ ) : void 0;
223
+ const swatch = e.note ? void 0 : e.swatch.kind === "gene" ? el("rect", {
224
+ x: at,
225
+ y: 5,
226
+ width: 18,
227
+ height: 8,
228
+ fill: "none",
229
+ stroke: GENE_INK,
230
+ "stroke-width": 1.5
231
+ }) : el("rect", {
232
+ x: at,
233
+ y: e.swatch.kind === "gap" ? 7 : 5,
234
+ width: 18,
235
+ height: e.swatch.kind === "gap" ? GAP_PX : 8,
236
+ rx: 2,
237
+ fill: ramp ? `url(#${rampId})` : e.swatch.fill
238
+ });
239
+ const text = el(
240
+ "text",
241
+ {
242
+ x: e.note ? at : at + 23,
243
+ y: 13,
244
+ "font-style": e.note ? "italic" : void 0,
245
+ fill: e.note ? "#666" : void 0
246
+ },
247
+ e.label
248
+ );
249
+ at += (e.note ? 0 : 23) + e.label.length * LABEL_CHAR_PX + 16;
250
+ return [ramp, swatch, text].filter((p) => p !== void 0);
251
+ });
252
+ return {
253
+ width: at,
254
+ tree: el(
255
+ "g",
256
+ {
257
+ transform: `translate(${x} ${y})`,
258
+ "font-family": "Helvetica, Arial, sans-serif",
259
+ "font-size": 11
260
+ },
261
+ ...parts
262
+ )
263
+ };
264
+ }
265
+ function coalesceRuns(runs, pxPerBp) {
266
+ const minBp = 1 / pxPerBp;
267
+ const out = [];
268
+ let bucket = [];
269
+ const flush = () => {
270
+ if (bucket.length === 0) {
271
+ return;
272
+ }
273
+ if (bucket.length === 1) {
274
+ out.push(bucket[0]);
275
+ } else {
276
+ let on = 0;
277
+ let off = 0;
278
+ for (const r of bucket) {
279
+ if (r.onReference) {
280
+ on += r.bp;
281
+ } else {
282
+ off += r.bp;
283
+ }
284
+ }
285
+ const onReference = on >= off;
286
+ const lead = bucket.find((r) => r.onReference === onReference);
287
+ out.push({
288
+ start: bucket[0].start,
289
+ bp: on + off,
290
+ onReference,
291
+ referenceStart: onReference ? lead.referenceStart : void 0,
292
+ ...lead.reversed ? { reversed: true } : {}
293
+ });
294
+ }
295
+ bucket = [];
296
+ };
297
+ let held = 0;
298
+ for (const run of runs) {
299
+ if (run.gap || run.bp >= minBp) {
300
+ flush();
301
+ held = 0;
302
+ out.push(run);
303
+ continue;
304
+ }
305
+ bucket.push(run);
306
+ held += run.bp;
307
+ if (held >= minBp) {
308
+ flush();
309
+ held = 0;
310
+ }
311
+ }
312
+ flush();
313
+ return out;
314
+ }
315
+ function geneTree(box, y, barPx) {
316
+ return el(
317
+ "g",
318
+ { class: "row-gene", "data-testid": "graph-walk-gene" },
319
+ el("title", {}, box.name),
320
+ ...box.exons.map(
321
+ (e) => el("rect", {
322
+ x: e.x,
323
+ y: y - barPx / 2,
324
+ width: e.w,
325
+ height: barPx,
326
+ fill: GENE_INK,
327
+ opacity: 0.35
328
+ })
329
+ ),
330
+ el("rect", {
331
+ x: box.x,
332
+ y: box.y,
333
+ width: box.w,
334
+ height: box.h,
335
+ fill: "none",
336
+ stroke: GENE_INK,
337
+ "stroke-width": 1.5
338
+ }),
339
+ box.label && el(
340
+ "text",
341
+ {
342
+ x: box.label.x,
343
+ y: box.label.y,
344
+ "font-family": "sans-serif",
345
+ "font-size": box.label.size,
346
+ "font-weight": 600,
347
+ "text-anchor": "middle",
348
+ fill: GENE_INK,
349
+ stroke: "white",
350
+ "stroke-width": 2.5,
351
+ "paint-order": "stroke"
352
+ },
353
+ box.name
354
+ )
355
+ );
356
+ }
357
+ function walkRowsTree(bars, frame, o = {}) {
358
+ const X = (bp) => bp * frame.scaleX + frame.translateX;
359
+ const rowPx = frame.rowPx ?? ROW_HEIGHT_PX;
360
+ const barPx = frame.barPx ?? BAR_PX;
361
+ const Y = (row) => row * rowPx * frame.scaleY + frame.translateY;
362
+ const { origin, unit, reference, rows } = bars;
363
+ const along = (offset) => X(origin + offset);
364
+ const prefix = o.idPrefix ?? "walkrow";
365
+ const rowTree = (row, i) => {
366
+ const y = Y(i);
367
+ if (y < -barPx || y > frame.height + barPx) {
368
+ return void 0;
369
+ }
370
+ const runs = coalesceRuns(row.runs, frame.scaleX).flatMap((run) => {
371
+ const paint = runPaint(run, o.ramp);
372
+ const h = run.gap ? Math.min(GAP_PX, barPx) : barPx;
373
+ const id = `${prefix}-${i}-${run.start}`;
374
+ const rect = el("rect", {
375
+ x: along(run.start),
376
+ y: y - h / 2,
377
+ width: Math.max(1, run.bp * frame.scaleX),
378
+ height: h,
379
+ fill: "stops" in paint ? `url(#${id})` : paint.fill
380
+ });
381
+ return "stops" in paint ? [
382
+ el(
383
+ "linearGradient",
384
+ { id },
385
+ ...paint.stops.map(
386
+ (color, k) => el("stop", {
387
+ offset: k / (paint.stops.length - 1),
388
+ "stop-color": color
389
+ })
390
+ )
391
+ ),
392
+ rect
393
+ ] : [rect];
394
+ });
395
+ const ticks = unit ? unitTicks(row.bp, unit, frame.scaleX).map(
396
+ (k) => el("line", {
397
+ x1: along(k),
398
+ x2: along(k),
399
+ y1: y - barPx / 2,
400
+ y2: y + barPx / 2,
401
+ stroke: "white",
402
+ "stroke-width": 1
403
+ })
404
+ ) : [];
405
+ const { call } = row;
406
+ const text = walkRowReadout(
407
+ row,
408
+ i === 0 ? void 0 : reference,
409
+ unit,
410
+ call
411
+ );
412
+ const at = readoutPlacement(text, along(row.bp), frame.width);
413
+ const readouts = frame.readouts ?? true;
414
+ return el(
415
+ "g",
416
+ {
417
+ "data-testid": i === 0 ? "graph-walk-reference" : "graph-walk-row"
418
+ },
419
+ ...runs,
420
+ ...ticks,
421
+ ...rowGeneBoxes(o.rowGenes?.get(row.name) ?? [], along, y, {
422
+ rowPx,
423
+ barPx
424
+ }).map((box) => geneTree(box, y, barPx)),
425
+ call && el("rect", {
426
+ "data-testid": "graph-walk-call",
427
+ x: along(call.bp) - 1,
428
+ y: y - barPx / 2 - 3,
429
+ width: 2,
430
+ height: barPx + 6,
431
+ fill: call.spanningReads === 0 ? UNBACKED_TICK : CALL_TICK
432
+ }),
433
+ readouts && el(
434
+ "text",
435
+ {
436
+ x: at.x,
437
+ y: y + 4,
438
+ "font-family": "sans-serif",
439
+ "font-size": 11,
440
+ fill: call?.agrees === false ? DISAGREES : "#333",
441
+ stroke: at.halo ? "white" : void 0,
442
+ "stroke-width": at.halo ? 3 : void 0,
443
+ "paint-order": "stroke",
444
+ "text-anchor": at.anchor
445
+ },
446
+ text
447
+ )
448
+ );
449
+ };
450
+ return el("g", {}, ...[reference, ...rows].map(rowTree));
451
+ }
452
+
453
+ export {
454
+ ON_REFERENCE,
455
+ OFF_REFERENCE,
456
+ OUTSIDE_CUT,
457
+ GENE_INK,
458
+ BAR_PX,
459
+ GAP_PX,
460
+ kb,
461
+ walkRowReadout,
462
+ readoutPlacement,
463
+ unitTicks,
464
+ runPaint,
465
+ alongRow,
466
+ rowSpan,
467
+ genesOnRow,
468
+ placeRowGenes,
469
+ boxesGenes,
470
+ rowGeneBoxes,
471
+ walkRowsKey,
472
+ DISAGREES,
473
+ walkRowsKeyTree,
474
+ coalesceRuns,
475
+ walkRowsTree
476
+ };
File without changes
@@ -0,0 +1,169 @@
1
+ import {
2
+ isGenericSample,
3
+ panSNContig,
4
+ panSNHaplotype,
5
+ panSNSample
6
+ } from "./chunk-BPLIXMH7.js";
7
+ import {
8
+ isBackbone
9
+ } from "./chunk-FYQWPEEY.js";
10
+
11
+ // src/reference.ts
12
+ var WELL_KNOWN_SAMPLES = /* @__PURE__ */ new Map([
13
+ ["hg38", "GRCh38"],
14
+ ["hg19", "GRCh37"],
15
+ ["hs1", "CHM13"],
16
+ ["t2t-chm13", "CHM13"],
17
+ ["chm13v2", "CHM13"]
18
+ ]);
19
+ function wellKnownSample(assemblyName) {
20
+ return WELL_KNOWN_SAMPLES.get(assemblyName.toLowerCase());
21
+ }
22
+ function sampleOf(refName) {
23
+ const sample = refName.includes("#") ? panSNSample(refName) : void 0;
24
+ return sample === void 0 || isGenericSample(sample) ? void 0 : sample;
25
+ }
26
+ function haplotypeOf(refName) {
27
+ return panSNHaplotype(refName) ?? panSNSample(refName);
28
+ }
29
+ function graphHaplotypes(graph) {
30
+ const refNames = new Set((graph.anchorPaths ?? []).map((p) => p.name));
31
+ for (const node of graph.nodes) {
32
+ if (node.stable) {
33
+ refNames.add(node.stable.refName);
34
+ }
35
+ }
36
+ const bySample = /* @__PURE__ */ new Map();
37
+ for (const refName of refNames) {
38
+ const sample = sampleOf(refName);
39
+ if (sample !== void 0) {
40
+ const haplotypes = bySample.get(sample) ?? bySample.set(sample, /* @__PURE__ */ new Set()).get(sample);
41
+ haplotypes.add(haplotypeOf(refName));
42
+ }
43
+ }
44
+ return bySample;
45
+ }
46
+ function backboneFrom(contigs, haplotypes) {
47
+ const samples = new Set(contigs.map((c) => sampleOf(c.refName)));
48
+ const [sample] = samples;
49
+ if (samples.size !== 1 || sample === void 0) {
50
+ return { contigs, prefixes: [], named: false };
51
+ }
52
+ const own = new Set(contigs.map((c) => haplotypeOf(c.refName)));
53
+ const unique = [...haplotypes.get(sample) ?? []].every((h) => own.has(h));
54
+ const shared = new Set(contigs.map((c) => panSNHaplotype(c.refName)));
55
+ const [haplotype] = shared;
56
+ return {
57
+ contigs,
58
+ prefixes: [
59
+ ...unique ? [sample] : [],
60
+ ...shared.size === 1 && haplotype ? [haplotype] : []
61
+ ],
62
+ named: true
63
+ };
64
+ }
65
+ function graphBackbone(graph) {
66
+ const spans = /* @__PURE__ */ new Map();
67
+ for (const node of graph.nodes) {
68
+ if (isBackbone(node)) {
69
+ const { refName, start } = node.stable;
70
+ const end = start + node.length;
71
+ const span = spans.get(refName);
72
+ if (span) {
73
+ span.start = Math.min(span.start, start);
74
+ span.end = Math.max(span.end, end);
75
+ } else {
76
+ spans.set(refName, {
77
+ refName,
78
+ contig: panSNContig(refName),
79
+ start,
80
+ end
81
+ });
82
+ }
83
+ }
84
+ }
85
+ const contigs = [...spans.values()];
86
+ return contigs.length ? backboneFrom(contigs, graphHaplotypes(graph)) : void 0;
87
+ }
88
+ function referenceLabel(graph, region) {
89
+ const backbone = graphBackbone(graph);
90
+ const contig = region ? panSNContig(region.refName) : backbone?.contigs.length === 1 ? backbone.contigs[0].contig : void 0;
91
+ const sample = backbone?.named ? panSNSample(backbone.contigs[0].refName) : void 0;
92
+ return contig && (sample ? `${sample} ${contig}` : contig);
93
+ }
94
+ function backboneAssembly(backbone, assemblies) {
95
+ const names = (a) => [a.name, ...a.aliases ?? []];
96
+ const naming = (prefix) => (a) => names(a).some((n) => n.toLowerCase() === prefix.toLowerCase());
97
+ const prefixes = [...backbone?.prefixes ?? []].reverse();
98
+ const sample = backbone?.prefixes.find((p) => !p.includes("#"))?.toLowerCase();
99
+ for (const prefix of prefixes) {
100
+ const assembly = assemblies.find(naming(prefix));
101
+ if (assembly) {
102
+ return assembly;
103
+ }
104
+ }
105
+ return sample === void 0 ? void 0 : assemblies.find(
106
+ (a) => names(a).some((n) => wellKnownSample(n)?.toLowerCase() === sample)
107
+ );
108
+ }
109
+ function assemblyWalk(graph, assembly) {
110
+ const haplotypes = graphHaplotypes(graph);
111
+ return graph.anchorPaths?.find(
112
+ (walk) => backboneAssembly(
113
+ backboneFrom(
114
+ [
115
+ {
116
+ refName: walk.name,
117
+ contig: panSNContig(walk.name),
118
+ start: walk.start,
119
+ end: walk.start + walk.length
120
+ }
121
+ ],
122
+ haplotypes
123
+ ),
124
+ [assembly]
125
+ )
126
+ );
127
+ }
128
+ function contigNames(contig) {
129
+ const bare = contig.replace(/^chr/i, "");
130
+ const forms = !bare ? [] : /^(M|MT)$/i.test(bare) ? ["M", "MT"] : [bare];
131
+ return [.../* @__PURE__ */ new Set([contig, ...forms.flatMap((f) => [f, `chr${f}`])])];
132
+ }
133
+ function refNameBinding(refNames, aliases = {}) {
134
+ const exact = new Set(refNames);
135
+ const byName = /* @__PURE__ */ new Map();
136
+ for (const refName of exact) {
137
+ const contig = panSNContig(refName);
138
+ const alias = aliases[contig];
139
+ for (const name of /* @__PURE__ */ new Set([
140
+ ...contigNames(contig),
141
+ ...alias ? [alias] : []
142
+ ])) {
143
+ byName.set(name, byName.has(name) ? void 0 : refName);
144
+ }
145
+ }
146
+ return (name) => exact.has(name) ? name : byName.get(name);
147
+ }
148
+ function featuresOnBackbone(features, backbone, aliases) {
149
+ const bind = refNameBinding(
150
+ backbone.contigs.map((c) => c.refName),
151
+ aliases
152
+ );
153
+ return features.flatMap((f) => {
154
+ const refName = bind(f.refName);
155
+ return refName === void 0 ? [] : [refName === f.refName ? f : { ...f, refName }];
156
+ });
157
+ }
158
+
159
+ export {
160
+ WELL_KNOWN_SAMPLES,
161
+ wellKnownSample,
162
+ graphBackbone,
163
+ referenceLabel,
164
+ backboneAssembly,
165
+ assemblyWalk,
166
+ contigNames,
167
+ refNameBinding,
168
+ featuresOnBackbone
169
+ };