@jbrowse/bandage-core 10.2.2 → 10.2.3

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 (137) hide show
  1. package/README.md +6 -7
  2. package/dist/bubbles/bubbleHalos.js +7 -3
  3. package/dist/bubbles/bubblesFromGraph.js +4 -2
  4. package/dist/bubbles/classifyBubble.js +10 -5
  5. package/dist/bubbles/superbubbles.js +10 -6
  6. package/dist/chunks/{chunk-N6FECAXP.js → chunk-24WITXQY.js} +17 -8
  7. package/dist/chunks/{chunk-XTCNEKO5.js → chunk-2QLLQJ72.js} +15 -13
  8. package/dist/chunks/{chunk-ASSNZXCF.js → chunk-3AOGOCCQ.js} +44 -103
  9. package/dist/chunks/{chunk-TWRLC3KK.js → chunk-3XSM4OZU.js} +1 -1
  10. package/dist/chunks/{chunk-WEDZ76AK.js → chunk-4DRQTBBE.js} +1 -1
  11. package/dist/chunks/{chunk-2LQ5BWT7.js → chunk-4ETPXDO6.js} +1 -1
  12. package/dist/chunks/{chunk-FP4H7SFT.js → chunk-4HWM3FNK.js} +2 -2
  13. package/dist/chunks/{chunk-C7MZJSPT.js → chunk-54POIBVC.js} +2 -8
  14. package/dist/chunks/{chunk-PKFMP65V.js → chunk-5GMFEPWR.js} +1 -1
  15. package/dist/chunks/{chunk-CDLPYR5O.js → chunk-5I3K4R2G.js} +7 -6
  16. package/dist/chunks/{chunk-TICYLD5F.js → chunk-7CC7N3XC.js} +35 -78
  17. package/dist/chunks/{chunk-2CVHXFK7.js → chunk-7SRWJLSC.js} +19 -22
  18. package/dist/chunks/{chunk-SBMJNRTV.js → chunk-A4PFFC4Q.js} +37 -27
  19. package/dist/chunks/{chunk-IW6CYVX2.js → chunk-AR4BUBMU.js} +6 -1
  20. package/dist/chunks/{chunk-IUDJKOLB.js → chunk-B6IW3IRE.js} +15 -33
  21. package/dist/chunks/{chunk-JUIJI7RC.js → chunk-BAETMD3J.js} +9 -4
  22. package/dist/chunks/{chunk-L5WF4ZPS.js → chunk-BS4UZ44I.js} +1 -1
  23. package/dist/chunks/{chunk-HNQPEMYE.js → chunk-CM6LO6OC.js} +0 -1
  24. package/dist/chunks/{chunk-CLOP7UVD.js → chunk-CQHUZHET.js} +11 -8
  25. package/dist/chunks/{chunk-R456ME6J.js → chunk-CU6P5RUG.js} +17 -6
  26. package/dist/chunks/chunk-D5D36ZF6.js +107 -0
  27. package/dist/chunks/{chunk-AFP3NWSL.js → chunk-DY3JCAMX.js} +1 -1
  28. package/dist/chunks/{chunk-NRV7R36Q.js → chunk-EFQLEGWM.js} +3 -3
  29. package/dist/chunks/{chunk-BXEPA4KS.js → chunk-G6UIYQZR.js} +5 -2
  30. package/dist/chunks/{chunk-NNODIW4U.js → chunk-H2H4Y3TV.js} +1 -0
  31. package/dist/chunks/{chunk-MVFDSFV2.js → chunk-HNCXR2VS.js} +1 -1
  32. package/dist/chunks/{chunk-EYK7DJZV.js → chunk-J5FWKGOY.js} +1 -1
  33. package/dist/chunks/{chunk-PBENCR5L.js → chunk-JBCZIBFC.js} +0 -2
  34. package/dist/chunks/{chunk-EHUBJDDB.js → chunk-JFY5PWQC.js} +5 -3
  35. package/dist/chunks/{chunk-5BGP5Z64.js → chunk-JLSJMCDJ.js} +1 -1
  36. package/dist/chunks/{chunk-DT2GGH4D.js → chunk-JMABOQWL.js} +2 -6
  37. package/dist/chunks/{chunk-3S3YVOJ7.js → chunk-JSUCGZ6K.js} +1 -1
  38. package/dist/chunks/{chunk-MLSWIMZO.js → chunk-KBEP7VYK.js} +2 -2
  39. package/dist/chunks/{chunk-TAMCZHLW.js → chunk-N73TI3VG.js} +2 -2
  40. package/dist/chunks/chunk-O4EGE27I.js +10 -0
  41. package/dist/chunks/{chunk-3ZZSX5HN.js → chunk-PTABFYQ7.js} +10 -6
  42. package/dist/chunks/{chunk-WBCOREDZ.js → chunk-QLWI2PZ3.js} +16 -7
  43. package/dist/chunks/chunk-RBCE2OQH.js +32 -0
  44. package/dist/chunks/{chunk-BUBZ32IC.js → chunk-RPRHR56C.js} +4 -8
  45. package/dist/chunks/{chunk-47DYCZOK.js → chunk-RUCH6ZFL.js} +4 -0
  46. package/dist/chunks/{chunk-GNTTI6LA.js → chunk-T2PCSAFY.js} +1 -1
  47. package/dist/chunks/{chunk-XKWD2RY3.js → chunk-URZ3CH2R.js} +3 -10
  48. package/dist/chunks/{chunk-ALDGONEI.js → chunk-VQC7KELB.js} +1 -1
  49. package/dist/chunks/{chunk-FLFBYSJO.js → chunk-VQWHMWLF.js} +5 -1
  50. package/dist/chunks/{chunk-4R6QNG23.js → chunk-WL6ZKUVC.js} +3 -3
  51. package/dist/chunks/{chunk-CRTD2SBP.js → chunk-WZNPX7Q6.js} +6 -2
  52. package/dist/chunks/{chunk-FNGIQF43.js → chunk-XA5A27CS.js} +6 -14
  53. package/dist/chunks/{chunk-DK5P2YOL.js → chunk-XI3ZUTWF.js} +2 -2
  54. package/dist/chunks/{chunk-ZIUKZUPJ.js → chunk-XL472HHD.js} +1 -1
  55. package/dist/chunks/{chunk-BPRXQ2SS.js → chunk-XMW266WS.js} +1 -1
  56. package/dist/chunks/{chunk-DRG4236Y.js → chunk-YN6FDIBT.js} +2 -2
  57. package/dist/chunks/{chunk-WFB5TXRA.js → chunk-ZY2AFL4Y.js} +13 -31
  58. package/dist/cli/decodeText.js +6 -0
  59. package/dist/cli/figure.js +59 -60
  60. package/dist/cli/fold.js +13 -13
  61. package/dist/deletionEdges.js +6 -4
  62. package/dist/el.js +3 -1
  63. package/dist/figure.js +33 -31
  64. package/dist/figureData.js +32 -27
  65. package/dist/figureScene.js +43 -0
  66. package/dist/figureSettings.js +8 -8
  67. package/dist/foldVariants.js +2 -2
  68. package/dist/gbzCut.js +1 -1
  69. package/dist/genes/exonOutline.js +2 -2
  70. package/dist/genes/geneFiles.js +1 -1
  71. package/dist/genes/genePins.js +3 -3
  72. package/dist/gfa/gfaConverter.js +2 -2
  73. package/dist/gfa-core/gfaParser.js +1 -1
  74. package/dist/gfa-core/index.js +1 -1
  75. package/dist/graphLabels.js +4 -4
  76. package/dist/index.js +72 -73
  77. package/dist/labelLayout.js +8 -8
  78. package/dist/layout/forceCache.js +8 -8
  79. package/dist/layout/mergeRuns.js +2 -2
  80. package/dist/layout/orderedLayout.js +1 -3
  81. package/dist/layout/tubeMapLayout.js +6 -6
  82. package/dist/layout/walkRowDraw.js +11 -11
  83. package/dist/layout/walkRowLayout.js +3 -1
  84. package/dist/layout/walkStrip.js +14 -12
  85. package/dist/layoutEngines.js +1 -2
  86. package/dist/layoutModes.js +9 -9
  87. package/dist/nodeWidths.js +1 -3
  88. package/dist/pathColors.js +5 -5
  89. package/dist/pipeline.js +7 -7
  90. package/dist/referenceRampCss.js +9 -9
  91. package/dist/referenceStrip.js +9 -9
  92. package/dist/renderer/Canvas2DRenderer.js +2 -2
  93. package/dist/renderer/GeometryBuilder.js +8 -8
  94. package/dist/renderer/canvas.js +1 -1
  95. package/dist/renderer/svgCanvas.js +1 -1
  96. package/dist/tubeMap/axis.js +5 -5
  97. package/dist/tubeMap/bundle.js +7 -7
  98. package/dist/tubeMap/coarsen.js +6 -6
  99. package/dist/tubeMap/deviations.js +5 -5
  100. package/dist/tubeMap/draw.js +1 -1
  101. package/dist/tubeMap/genes.js +6 -6
  102. package/dist/tubeMap/nodeColors.js +9 -9
  103. package/dist/types/bubbles/bubblesFromGraph.d.ts +1 -0
  104. package/dist/types/bubbles/classifyBubble.d.ts +0 -1
  105. package/dist/types/cli/decodeText.d.ts +1 -0
  106. package/dist/types/cli/figure.d.ts +4 -15
  107. package/dist/types/deletionEdges.d.ts +3 -5
  108. package/dist/types/el.d.ts +1 -0
  109. package/dist/types/figureData.d.ts +7 -26
  110. package/dist/types/figureScene.d.ts +31 -0
  111. package/dist/types/genes/geneFiles.d.ts +2 -1
  112. package/dist/types/index.d.ts +1 -1
  113. package/dist/types/layout/deletionRoutes.d.ts +1 -1
  114. package/dist/types/layout/orderedLayout.d.ts +0 -6
  115. package/dist/types/layout/walkRowLayout.d.ts +1 -0
  116. package/dist/types/nodeWidths.d.ts +0 -1
  117. package/dist/types/renderer/Canvas2DRenderer.d.ts +1 -0
  118. package/dist/types/renderer/canvas.d.ts +2 -2
  119. package/dist/types/tubeMap/draw.d.ts +1 -0
  120. package/dist/types/util/geometry.d.ts +3 -3
  121. package/dist/types/version.d.ts +1 -1
  122. package/dist/util/SpatialIndex.js +4 -4
  123. package/dist/util/edgeCurves.js +3 -3
  124. package/dist/util/geometry.js +3 -3
  125. package/dist/util/hitDetection.js +5 -5
  126. package/dist/version.js +1 -1
  127. package/dist/viewport.js +8 -8
  128. package/dist/walkEncoding.js +9 -9
  129. package/dist/walkHighlight.js +10 -10
  130. package/dist/walkKey.js +5 -5
  131. package/package.json +3 -6
  132. package/dist/chunks/bandage-layout-3AR6BCUD.js +0 -4694
  133. package/dist/chunks/chunk-4BYTEJGW.js +0 -44
  134. package/dist/chunks/chunk-7XHHVYG7.js +0 -13
  135. package/dist/loadBandage.js +0 -6
  136. package/dist/types/bandage/bandage-layout.d.ts +0 -14
  137. package/dist/types/loadBandage.d.ts +0 -3
@@ -1,32 +1,24 @@
1
1
  import {
2
2
  layoutEngine
3
- } from "./chunk-DT2GGH4D.js";
3
+ } from "./chunk-JMABOQWL.js";
4
4
  import {
5
5
  layoutModeByValue
6
- } from "./chunk-4R6QNG23.js";
6
+ } from "./chunk-WL6ZKUVC.js";
7
7
  import {
8
8
  parseRegion
9
- } from "./chunk-FLFBYSJO.js";
10
- import {
11
- layoutGeometryInputs
12
- } from "./chunk-LOCJN3BZ.js";
9
+ } from "./chunk-VQWHMWLF.js";
13
10
  import {
14
11
  version
15
- } from "./chunk-EYK7DJZV.js";
12
+ } from "./chunk-J5FWKGOY.js";
16
13
  import {
17
14
  axisScaleOf
18
- } from "./chunk-L5WF4ZPS.js";
19
- import {
20
- facetLifts,
21
- walkLift
22
- } from "./chunk-R456ME6J.js";
15
+ } from "./chunk-BS4UZ44I.js";
23
16
  import {
24
17
  walkKey
25
- } from "./chunk-2LQ5BWT7.js";
18
+ } from "./chunk-4ETPXDO6.js";
26
19
  import {
27
- buildGeometry,
28
- computeReferenceRamp
29
- } from "./chunk-SBMJNRTV.js";
20
+ figureScene
21
+ } from "./chunk-D5D36ZF6.js";
30
22
  import {
31
23
  abgrAlpha,
32
24
  abgrBlue,
@@ -34,32 +26,16 @@ import {
34
26
  abgrRed
35
27
  } from "./chunk-G2FD7S3C.js";
36
28
  import {
37
- pathLegend,
38
- walkLabelsOf
39
- } from "./chunk-TWRLC3KK.js";
40
- import {
41
- drawingBounds,
42
29
  engineSettingsOf,
43
30
  fitTransform,
44
31
  forceLayout,
45
32
  loadGraph
46
- } from "./chunk-XTCNEKO5.js";
47
- import {
48
- referenceLabel
49
- } from "./chunk-RAKOB6IV.js";
50
- import {
51
- resolveColorScheme
52
- } from "./chunk-JKJWSY4V.js";
53
- import {
54
- deletionDrawing,
55
- deletionEdges
56
- } from "./chunk-N6FECAXP.js";
33
+ } from "./chunk-2QLLQJ72.js";
57
34
  import {
58
35
  isBackbone
59
36
  } from "./chunk-FYQWPEEY.js";
60
37
  import {
61
- facetCells,
62
- facetSettingOf
38
+ facetCells
63
39
  } from "./chunk-XV4P5KEQ.js";
64
40
 
65
41
  // src/figureData.ts
@@ -85,39 +61,24 @@ function figureData(graph, layout, o = {}) {
85
61
  }
86
62
  const width = o.width ?? 1200;
87
63
  const height = o.height ?? 800;
88
- const region = o.region;
89
64
  const pixelRows = layout.pixelRows ?? false;
90
- const bounds = drawingBounds(layout, {
91
- region: o.fitToDrawing ? void 0 : region
92
- });
65
+ const {
66
+ bounds,
67
+ colorScheme,
68
+ drawnDeletions,
69
+ lift,
70
+ facet,
71
+ panels: facetted,
72
+ labelOf,
73
+ referenceName,
74
+ reference,
75
+ geometry
76
+ } = figureScene(graph, layout, o);
93
77
  const fit = fitTransform(bounds, width, height, pixelRows);
94
78
  if (!fit) {
95
79
  throw new Error("the layout drew nothing to fit");
96
80
  }
97
81
  const axis = axisScaleOf(fit.scale, pixelRows);
98
- const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
99
- const colorScheme = resolveColorScheme(o.colorScheme ?? "auto", graph);
100
- const rampDomain = o.colorDomain ?? region;
101
- const referenceRamp = colorScheme === "reference-position" ? computeReferenceRamp(graph, rampDomain) : void 0;
102
- const drawnDeletions = deletionDrawing(
103
- graph,
104
- deletionEdges(graph),
105
- o.showDeletionEdges
106
- );
107
- const layers = o.walks ?? [];
108
- const walkRamp = layers.some((l) => l.color?.field === "reference") ? referenceRamp ?? computeReferenceRamp(graph, rampDomain) : void 0;
109
- const lift = layers.length > 0 ? walkLift(graph, layers, walkRamp) : void 0;
110
- const facet = facetSettingOf(o.facet);
111
- const facetted = facet.field && lift && lift.walks.length > 1 ? facetLifts(graph, lift, layers, walkRamp) : void 0;
112
- const labels = walkLabelsOf(
113
- graph.paths?.length ? pathLegend(graph.paths) : []
114
- );
115
- const labelOf = (name) => labels.get(name) ?? name;
116
- const referenceName = o.referenceName ?? referenceLabel(graph, region);
117
- const reference = lift?.referenceDomain && {
118
- ...lift.referenceDomain,
119
- name: referenceName
120
- };
121
82
  const panels = [];
122
83
  if (facetted) {
123
84
  const place = facetCells(
@@ -178,20 +139,7 @@ function figureData(graph, layout, o = {}) {
178
139
  "alpha"
179
140
  ]);
180
141
  for (const { highlight, name: panel } of panels) {
181
- const batch = buildGeometry({
182
- ...layoutGeometryInputs(layout, drawnDeletions),
183
- graph,
184
- nodeById,
185
- colorScheme,
186
- contigThickness: o.contigThickness ?? 6,
187
- connectorThickness: o.connectorThickness ?? 2,
188
- drawPaths: false,
189
- nodeWidth: o.nodeWidth ?? "depth",
190
- linearLayout: o.linearLayout,
191
- highlight,
192
- axis,
193
- referenceRamp
194
- });
142
+ const batch = geometry(highlight, axis);
195
143
  for (const [node, run] of batch.nodeStrokeRuns) {
196
144
  for (let i = run.start; i < run.start + run.count; i++) {
197
145
  const s = batch.nodeStrokes[i];
@@ -275,18 +223,27 @@ function figureData(graph, layout, o = {}) {
275
223
  }
276
224
  };
277
225
  }
278
- async function gfaFigureData(text, name, spec = {}) {
279
- const region = spec.region ? parseRegion(spec.region) : void 0;
226
+ async function laidOutGraph(text, name, region, spec) {
280
227
  const graph = loadGraph(text, name, { referencePath: spec.referencePath });
281
228
  const layout = layoutModeByValue(spec.layout ?? "force").run(graph, region) ?? (await forceLayout(graph, engineSettingsOf(spec), layoutEngine)).result;
229
+ return { graph, layout };
230
+ }
231
+ function walkLayers(walks) {
232
+ return walks?.map((w) => typeof w === "string" ? { walk: w } : w);
233
+ }
234
+ async function gfaFigureData(text, name, spec = {}) {
235
+ const region = spec.region ? parseRegion(spec.region) : void 0;
236
+ const { graph, layout } = await laidOutGraph(text, name, region, spec);
282
237
  return figureData(graph, layout, {
283
238
  ...spec,
284
239
  region,
285
- walks: spec.walks?.map((w) => typeof w === "string" ? { walk: w } : w)
240
+ walks: walkLayers(spec.walks)
286
241
  });
287
242
  }
288
243
 
289
244
  export {
290
245
  figureData,
246
+ laidOutGraph,
247
+ walkLayers,
291
248
  gfaFigureData
292
249
  };
@@ -206,15 +206,16 @@ function bowAround(p1x, p1y, p2x, p2y, toward, maxBow) {
206
206
  function yToXOf({ scaleX, scaleY }) {
207
207
  return scaleY / scaleX;
208
208
  }
209
- var PATH_RIBBON_SPACING = 3;
209
+ var PATH_RIBBON_SPACING_PX = 3;
210
210
  function drawnDirection(a, b, yToX) {
211
211
  const dx = b.x - a.x;
212
212
  const dy = (b.y - a.y) * yToX;
213
213
  const len = Math.hypot(dx, dy);
214
214
  return len === 0 ? void 0 : { x: dx / len, y: dy / len };
215
215
  }
216
- function pathRibbonOffsets(fromSegments, toSegments, count, axis, spacing = PATH_RIBBON_SPACING) {
216
+ function pathRibbonOffsets(fromSegments, toSegments, count, axis) {
217
217
  const yToX = yToXOf(axis);
218
+ const spacing = PATH_RIBBON_SPACING_PX / Math.max(axis.scaleX, 1e-6);
218
219
  const dir = drawnDirection(
219
220
  fromSegments[fromSegments.length - 1],
220
221
  toSegments[0],
@@ -270,15 +271,15 @@ function edgeJoinOf(edge, stranded = false) {
270
271
  const sides = strandSides(edge);
271
272
  return self === false ? sides : sides.from === sides.to ? sides.from : true;
272
273
  }
273
- function hairpinCurves(attach, reach, offsetX, offsetY) {
274
+ function hairpinCurves(attach, reach) {
274
275
  const { at, inward } = attach;
275
276
  const dx = inward ? at.x - inward.x : 1;
276
277
  const dy = inward ? at.y - inward.y : 0;
277
278
  const len = Math.hypot(dx, dy) || 1;
278
279
  const ux = dx / len;
279
280
  const uy = dy / len;
280
- const px = at.x + offsetX;
281
- const py = at.y + offsetY;
281
+ const px = at.x;
282
+ const py = at.y;
282
283
  const nearX = px + ux * reach / 3;
283
284
  const nearY = py + uy * reach / 3;
284
285
  const apexX = px + ux * reach;
@@ -308,7 +309,7 @@ function hairpinCurves(attach, reach, offsetX, offsetY) {
308
309
  }
309
310
  ];
310
311
  }
311
- function computeEdgeCurves(fromSegments, toSegments, join, offsetX, offsetY, axis, bypassed = [], maxBowIn) {
312
+ function computeEdgeCurves(fromSegments, toSegments, join, axis, bypassed = [], maxBowIn) {
312
313
  const scale = axis.scaleX;
313
314
  const yToX = yToXOf(axis);
314
315
  const maxBow = maxBowIn ?? (axis.pixelRows ? MAX_ROW_BOW_PX : void 0);
@@ -321,8 +322,6 @@ function computeEdgeCurves(fromSegments, toSegments, join, offsetX, offsetY, axi
321
322
  scaleYOf(fromSegments, yToX),
322
323
  scaleYOf(toSegments, yToX),
323
324
  join,
324
- offsetX,
325
- offsetY * yToX,
326
325
  { scaleX: scale, scaleY: scale },
327
326
  scaleYOf(bypassed, yToX),
328
327
  // the cap is a y measure and the body works in x units, so it converts
@@ -335,9 +334,7 @@ function computeEdgeCurves(fromSegments, toSegments, join, offsetX, offsetY, axi
335
334
  if (typeof join === "string") {
336
335
  return hairpinCurves(
337
336
  attachment(fromSegments, join),
338
- selfLoopReach(fromSegments, scale),
339
- offsetX,
340
- offsetY
337
+ selfLoopReach(fromSegments, scale)
341
338
  );
342
339
  }
343
340
  const loop = join === true;
@@ -346,10 +343,10 @@ function computeEdgeCurves(fromSegments, toSegments, join, offsetX, offsetY, axi
346
343
  const toAttach = attachment(toSegments, sides.to);
347
344
  const fromEnd = fromAttach.at;
348
345
  const toStart = toAttach.at;
349
- const p1x = fromEnd.x + offsetX;
350
- const p1y = fromEnd.y + offsetY;
351
- const p2x = toStart.x + offsetX;
352
- const p2y = toStart.y + offsetY;
346
+ const p1x = fromEnd.x;
347
+ const p1y = fromEnd.y;
348
+ const p2x = toStart.x;
349
+ const p2y = toStart.y;
353
350
  if (loop) {
354
351
  let segDirX = 1;
355
352
  let segDirY = 0;
@@ -365,8 +362,8 @@ function computeEdgeCurves(fromSegments, toSegments, join, offsetX, offsetY, axi
365
362
  const ext = selfLoopReach(fromSegments, scale);
366
363
  const perpX = -segDirY;
367
364
  const perpY = segDirX;
368
- const midX = (fromEnd.x + toStart.x) / 2 + offsetX + perpX * ext;
369
- const midY = (fromEnd.y + toStart.y) / 2 + offsetY + perpY * ext;
365
+ const midX = (fromEnd.x + toStart.x) / 2 + perpX * ext;
366
+ const midY = (fromEnd.y + toStart.y) / 2 + perpY * ext;
370
367
  const cp1x = p1x + segDirX * ext;
371
368
  const cp1y = p1y + segDirY * ext;
372
369
  const cp2x = p2x - segDirX * ext;
@@ -441,10 +438,10 @@ function computeEdgeCurves(fromSegments, toSegments, join, offsetX, offsetY, axi
441
438
  {
442
439
  x0: p1x,
443
440
  y0: p1y,
444
- cx0: cx1 + offsetX + bulgeX - spreadX,
445
- cy0: cy1 + offsetY + bulgeY - spreadY,
446
- cx1: cx2 + offsetX + bulgeX + spreadX,
447
- cy1: cy2 + offsetY + bulgeY + spreadY,
441
+ cx0: cx1 + bulgeX - spreadX,
442
+ cy0: cy1 + bulgeY - spreadY,
443
+ cx1: cx2 + bulgeX + spreadX,
444
+ cy1: cy2 + bulgeY + spreadY,
448
445
  x1: p2x,
449
446
  y1: p2y
450
447
  }
@@ -521,7 +518,7 @@ export {
521
518
  strandSides,
522
519
  bowAround,
523
520
  yToXOf,
524
- PATH_RIBBON_SPACING,
521
+ PATH_RIBBON_SPACING_PX,
525
522
  pathRibbonOffsets,
526
523
  selfLinkOf,
527
524
  edgeJoinOf,
@@ -5,17 +5,17 @@ import {
5
5
  } from "./chunk-G2FD7S3C.js";
6
6
  import {
7
7
  baseEdgeCurves
8
- } from "./chunk-WFB5TXRA.js";
8
+ } from "./chunk-ZY2AFL4Y.js";
9
9
  import {
10
10
  PATH_LIGHTNESS,
11
11
  PATH_SATURATION,
12
12
  nameHue,
13
13
  pathHueAt
14
- } from "./chunk-TWRLC3KK.js";
14
+ } from "./chunk-3XSM4OZU.js";
15
15
  import {
16
16
  meanDepth,
17
17
  nodeWidthPx
18
- } from "./chunk-PBENCR5L.js";
18
+ } from "./chunk-JBCZIBFC.js";
19
19
  import {
20
20
  referenceMidpoints
21
21
  } from "./chunk-ES2N6V56.js";
@@ -25,7 +25,7 @@ import {
25
25
  strandSides,
26
26
  translateCurves,
27
27
  yToXOf
28
- } from "./chunk-2CVHXFK7.js";
28
+ } from "./chunk-7SRWJLSC.js";
29
29
 
30
30
  // src/renderer/GeometryBuilder.ts
31
31
  var EDGE_DEFAULT_COLOR = packAbgr(119, 119, 119, 217);
@@ -551,25 +551,24 @@ function buildGeometry(options) {
551
551
  const edgeColor = !highlight || onWalk ? plainEdgeColor : fadeAbgr(plainEdgeColor, FADED_ALPHA);
552
552
  const toNode = nodeById.get(edge.to);
553
553
  const intoHalfWidth = (toNode ? nodeWidthPx(toNode, contigThickness, nodeWidth, depthNorm) : contigThickness) / 2;
554
- const buildSingleEdge = (offsetX, offsetY, color, arrowColor) => {
555
- const curves = offsetX === 0 && offsetY === 0 ? baseCurves : translateCurves(baseCurves, offsetX, offsetY);
556
- if (viewportBounds && !isBezierInBounds(curves, viewportBounds)) {
557
- return;
558
- }
554
+ const inView = (curves) => !viewportBounds || isBezierInBounds(curves, viewportBounds);
555
+ const stroke = (curves, thickness, color) => {
559
556
  if (isDeletion) {
560
557
  for (const dash of dashCurves(curves, DELETION_DASH_PX / scale)) {
561
- edgeCurves.push({ curves: dash, thickness: edgeThickness, color });
558
+ edgeCurves.push({ curves: dash, thickness, color });
562
559
  }
563
560
  } else {
564
- edgeCurves.push({ curves, thickness: edgeThickness, color });
561
+ edgeCurves.push({ curves, thickness, color });
565
562
  }
566
- const head = showArrows && arrowColor !== void 0 ? arrowheadFor({
563
+ };
564
+ const arrowOn = (curves) => {
565
+ const head = showArrows ? arrowheadFor({
567
566
  curves,
568
567
  edgeHalfWidth: connectorThickness / 2,
569
568
  nodeHalfWidth: intoHalfWidth,
570
569
  scale,
571
570
  yToX,
572
- color: arrowColor,
571
+ color: edgeColor,
573
572
  fromSegments,
574
573
  toSegments
575
574
  }) : void 0;
@@ -602,17 +601,22 @@ function buildGeometry(options) {
602
601
  }
603
602
  const offset = (lane - (laneWalks.length - 1) / 2) * laneWidth * worldPerScreenPx;
604
603
  const curves = offset === 0 ? baseCurves : translateCurves(baseCurves, nx * offset, ny * offset / yToX);
605
- if (viewportBounds && !isBezierInBounds(curves, viewportBounds)) {
606
- return;
604
+ if (inView(curves)) {
605
+ stroke(
606
+ curves,
607
+ laneWidth / 2,
608
+ walk.colors.get(edge.from) ?? walk.colors.get(edge.to) ?? plainEdgeColor
609
+ );
607
610
  }
608
- edgeCurves.push({
609
- curves,
610
- thickness: laneWidth / 2,
611
- color: walk.colors.get(edge.from) ?? walk.colors.get(edge.to) ?? plainEdgeColor
612
- });
613
611
  });
612
+ if (edgeCurves.length > edgeCurveStart) {
613
+ arrowOn(baseCurves);
614
+ }
614
615
  } else if (!ribbons) {
615
- buildSingleEdge(0, 0, edgeColor, edgeColor);
616
+ if (inView(baseCurves)) {
617
+ stroke(baseCurves, edgeThickness, edgeColor);
618
+ arrowOn(baseCurves);
619
+ }
616
620
  } else {
617
621
  const offsets = pathRibbonOffsets(
618
622
  fromSegments,
@@ -622,14 +626,20 @@ function buildGeometry(options) {
622
626
  );
623
627
  const arrowRibbon = Math.floor((numPaths - 1) / 2);
624
628
  for (let pathIdx = 0; pathIdx < numPaths; pathIdx++) {
625
- const offset = offsets[pathIdx];
629
+ const { x, y } = offsets[pathIdx];
630
+ const curves = x === 0 && y === 0 ? baseCurves : translateCurves(baseCurves, x, y);
631
+ if (!inView(curves)) {
632
+ continue;
633
+ }
626
634
  const ribbonColor = pathColorByName(edge.pathIds[pathIdx]);
627
- buildSingleEdge(
628
- offset.x,
629
- offset.y,
630
- highlight && (highlight.walks.length ? !highlight.names.has(edge.pathIds[pathIdx]) : !onWalk) ? fadeAbgr(ribbonColor, FADED_ALPHA) : ribbonColor,
631
- pathIdx === arrowRibbon ? edgeColor : void 0
635
+ stroke(
636
+ curves,
637
+ edgeThickness,
638
+ highlight && (highlight.walks.length ? !highlight.names.has(edge.pathIds[pathIdx]) : !onWalk) ? fadeAbgr(ribbonColor, FADED_ALPHA) : ribbonColor
632
639
  );
640
+ if (pathIdx === arrowRibbon) {
641
+ arrowOn(curves);
642
+ }
633
643
  }
634
644
  }
635
645
  const edgeCurveCount = edgeCurves.length - edgeCurveStart;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  stableCoordinate
3
- } from "./chunk-CDLPYR5O.js";
3
+ } from "./chunk-5I3K4R2G.js";
4
4
  import {
5
5
  pathOrigin,
6
6
  surveyPaths
@@ -95,7 +95,12 @@ function convertGFAToGraph(gfaGraph, name = "Imported GFA") {
95
95
  }
96
96
  return id;
97
97
  };
98
+ const declared = /* @__PURE__ */ new Set();
98
99
  for (const gfaNode of gfaGraph.nodes) {
100
+ if (declared.has(gfaNode.id)) {
101
+ continue;
102
+ }
103
+ declared.add(gfaNode.id);
99
104
  const depth = statedDepth(gfaNode) ?? Math.max(traversals.get(gfaNode.id) ?? 1, 1);
100
105
  nodes.push(makeNode(gfaNode, canonical.get(gfaNode.id) ?? "+", depth));
101
106
  }
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-M6LK4GII.js";
13
13
 
14
14
  // src/tubeMap/draw.ts
15
- import { curvePaths, nodeOutlinePath } from "@jbrowse/tubemap-core";
15
+ import { curvePaths, flattenPath, nodeOutlinePath } from "@jbrowse/tubemap-core";
16
16
  function parsePath(d) {
17
17
  const tokens = d.trim().split(/[\s,]+/);
18
18
  const commands = [];
@@ -61,7 +61,15 @@ function extentOf(commands) {
61
61
  }
62
62
  function shapeOf(d, color, id, haplotype, reference) {
63
63
  const commands = parsePath(d);
64
- return { commands, color, id, haplotype, reference, ...extentOf(commands) };
64
+ return {
65
+ commands,
66
+ outline: flattenPath(d, 12),
67
+ color,
68
+ id,
69
+ haplotype,
70
+ reference,
71
+ ...extentOf(commands)
72
+ };
65
73
  }
66
74
  function trackColors(layout, pathColors) {
67
75
  return new Map(
@@ -302,36 +310,6 @@ function drawMismatches(ctx, marks, frame) {
302
310
  }
303
311
  }
304
312
  }
305
- function outline(commands, x, y) {
306
- const points = [];
307
- let cx = 0;
308
- let cy = 0;
309
- const STEPS = 12;
310
- for (const c of commands) {
311
- if (c.op === "C" || c.op === "Q") {
312
- for (let i = 1; i <= STEPS; i++) {
313
- const t = i / STEPS;
314
- const u = 1 - t;
315
- const [px, py] = c.op === "C" ? [
316
- u * u * u * cx + 3 * u * u * t * c.x1 + 3 * u * t * t * c.x2 + t * t * t * c.x,
317
- u * u * u * cy + 3 * u * u * t * c.y1 + 3 * u * t * t * c.y2 + t * t * t * c.y
318
- ] : [
319
- u * u * cx + 2 * u * t * c.x1 + t * t * c.x,
320
- u * u * cy + 2 * u * t * c.y1 + t * t * c.y
321
- ];
322
- points.push([x(px), y(py)]);
323
- }
324
- }
325
- if (c.op !== "Z") {
326
- cx = "x" in c ? c.x : cx;
327
- cy = "y" in c ? c.y : cy;
328
- if (c.op !== "C" && c.op !== "Q") {
329
- points.push([x(cx), y(cy)]);
330
- }
331
- }
332
- }
333
- return points;
334
- }
335
313
  function inside(points, sx, sy) {
336
314
  let hit = false;
337
315
  for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
@@ -353,7 +331,11 @@ function tubeMapTrackAt(picture, { x, y }, sx, sy) {
353
331
  }
354
332
  }
355
333
  for (const s of shapes) {
356
- if (s.reference === reference && x(s.x0) <= sx && sx <= x(s.x1) && inside(outline(s.commands, x, y), sx, sy)) {
334
+ if (s.reference === reference && x(s.x0) <= sx && sx <= x(s.x1) && inside(
335
+ s.outline.map(([px, py]) => [x(px), y(py)]),
336
+ sx,
337
+ sy
338
+ )) {
357
339
  return s.id;
358
340
  }
359
341
  }
@@ -2,10 +2,13 @@ import {
2
2
  alongRow,
3
3
  boxesGenes,
4
4
  rowPitch
5
- } from "./chunk-NRV7R36Q.js";
5
+ } from "./chunk-EFQLEGWM.js";
6
6
  import {
7
7
  el
8
- } from "./chunk-NNODIW4U.js";
8
+ } from "./chunk-H2H4Y3TV.js";
9
+ import {
10
+ READOUT_ROOM
11
+ } from "./chunk-54POIBVC.js";
9
12
  import {
10
13
  pathOrigin
11
14
  } from "./chunk-M6LK4GII.js";
@@ -24,7 +27,6 @@ var PAD_PX = 6;
24
27
  var WALK_STRIP_CEILING_PX = 260;
25
28
  var LABEL_FONT_PX = 11;
26
29
  var MIN_ROW_PX = 3;
27
- var READOUT_ROOM = 1.3;
28
30
  var MARK_INK = "#111";
29
31
  var TICK_PX = 3;
30
32
  function stripMarks(graph, rows, node) {
@@ -59,7 +61,10 @@ function spansOf(graph, name) {
59
61
  return byName.get(name);
60
62
  }
61
63
  const lengthOf = new Map(graph.nodes.map((n) => [n.id, n.length]));
62
- const pieces = (graph.paths ?? []).filter((p) => p.name === name);
64
+ const origin = pathOrigin(name).name;
65
+ const pieces = (graph.paths ?? []).filter(
66
+ (p) => origin === graph.referencePath ? pathOrigin(p.name).name === origin : p.name === name
67
+ );
63
68
  let spans;
64
69
  if (pieces.every((p) => p.start !== void 0)) {
65
70
  spans = { ids: [], starts: [], ends: [] };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  clampZoom
3
- } from "./chunk-XTCNEKO5.js";
3
+ } from "./chunk-2QLLQJ72.js";
4
4
 
5
5
  // src/viewport.ts
6
6
  function axisScaleOf(scale, pixelRows) {
@@ -292,6 +292,5 @@ function orderedLayout(graph) {
292
292
 
293
293
  export {
294
294
  referenceOrder,
295
- layerGraph,
296
295
  orderedLayout
297
296
  };
@@ -3,12 +3,20 @@ import {
3
3
  } from "./chunk-FX4RDMDN.js";
4
4
  import {
5
5
  referenceOrder
6
- } from "./chunk-HNQPEMYE.js";
6
+ } from "./chunk-CM6LO6OC.js";
7
7
  import {
8
8
  isBackbone
9
9
  } from "./chunk-FYQWPEEY.js";
10
10
 
11
11
  // src/bubbles/bubblesFromGraph.ts
12
+ function relax(best, to, cur, add) {
13
+ const prev = best.get(to);
14
+ best.set(to, {
15
+ min: Math.min(prev?.min ?? Infinity, cur.min + add),
16
+ max: Math.max(prev?.max ?? -Infinity, cur.max + add),
17
+ n: Math.min(SATURATED_PATH_COUNT, cur.n + (prev?.n ?? 0))
18
+ });
19
+ }
12
20
  function bubblesFromGraph(graph) {
13
21
  if (!graph.nodes.some(isBackbone)) {
14
22
  return [];
@@ -61,13 +69,7 @@ function bubblesFromGraph(graph) {
61
69
  if (ti > i1) {
62
70
  continue;
63
71
  }
64
- const add = t === end.id ? 0 : byId.get(t).length;
65
- const prev = best.get(t);
66
- best.set(t, {
67
- min: Math.min(prev?.min ?? Infinity, cur.min + add),
68
- max: Math.max(prev?.max ?? -Infinity, cur.max + add),
69
- n: Math.min(SATURATED_PATH_COUNT, cur.n + (prev?.n ?? 0))
70
- });
72
+ relax(best, t, cur, t === end.id ? 0 : byId.get(t).length);
71
73
  }
72
74
  }
73
75
  const walked = walkIndex && walkRoutes(graph, byId, walkIndex, start.id, end.id);
@@ -167,6 +169,7 @@ function walkRoutes(graph, byId, walkIndex, startId, endId) {
167
169
  }
168
170
 
169
171
  export {
172
+ relax,
170
173
  bubblesFromGraph,
171
174
  walkIndexOf,
172
175
  walkRoutes
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  encodedColor,
3
3
  resolveEncoding
4
- } from "./chunk-ALDGONEI.js";
4
+ } from "./chunk-VQC7KELB.js";
5
5
  import {
6
6
  pathOrigin
7
7
  } from "./chunk-M6LK4GII.js";
@@ -28,10 +28,14 @@ function walkHighlight(graph, name) {
28
28
  const lengthOf = (id) => byId.get(id)?.length ?? 0;
29
29
  const bpOf = (path) => path.nodeIds.reduce((sum, id) => sum + lengthOf(id), 0);
30
30
  const bp = pieces.reduce((sum, piece) => sum + bpOf(piece), 0);
31
- const range = first.start === void 0 ? void 0 : {
31
+ const extentOf = (ps) => {
32
+ const start = Math.min(...ps.map((p) => p.start ?? Infinity));
33
+ return Number.isFinite(start) ? { start, end: Math.max(...ps.map((p) => (p.start ?? 0) + bpOf(p))) } : void 0;
34
+ };
35
+ const extent = extentOf(pieces);
36
+ const range = extent && {
32
37
  contig: first.contig ?? panSNContig(pathOrigin(name).name),
33
- start: first.start,
34
- end: Math.max(...pieces.map((p) => (p.start ?? 0) + bpOf(p)))
38
+ ...extent
35
39
  };
36
40
  const span = range ? range.end - range.start : bp;
37
41
  const nodeIds = /* @__PURE__ */ new Set();
@@ -59,7 +63,14 @@ function walkHighlight(graph, name) {
59
63
  });
60
64
  }
61
65
  const reference = isReference(graph, name);
62
- const referencePieces = reference ? [] : (graph.paths ?? []).filter((p) => isReference(graph, p.name));
66
+ const referenceSpan = () => {
67
+ const referencePieces = reference ? [] : (graph.paths ?? []).filter((p) => isReference(graph, p.name));
68
+ if (referencePieces.length === 0) {
69
+ return void 0;
70
+ }
71
+ const e = extentOf(referencePieces);
72
+ return e ? e.end - e.start : referencePieces.reduce((sum, piece) => sum + bpOf(piece), 0);
73
+ };
63
74
  return {
64
75
  name,
65
76
  reference,
@@ -69,7 +80,7 @@ function walkHighlight(graph, name) {
69
80
  progress,
70
81
  steps: pieces.reduce((sum, piece) => sum + piece.nodeIds.length, 0),
71
82
  bp,
72
- referenceBp: referencePieces.length > 0 ? referencePieces.reduce((sum, piece) => sum + bpOf(piece), 0) : void 0
83
+ referenceBp: referenceSpan()
73
84
  };
74
85
  }
75
86
  function laneColors(graph, walk, encoding, ramp) {