@jbrowse/bandage-core 11.7.1 → 11.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +106 -48
  2. package/dist/bubbles/bubbleHalos.js +6 -6
  3. package/dist/bubbles/classifyBubble.js +5 -5
  4. package/dist/bubbles/superbubbles.js +7 -7
  5. package/dist/chunks/{chunk-3PZSBNLI.js → chunk-22ZMVREZ.js} +19 -14
  6. package/dist/chunks/{chunk-VB4IXIPM.js → chunk-2H3ALI6L.js} +223 -45
  7. package/dist/chunks/{chunk-FBPAX5K6.js → chunk-2RCKHCF7.js} +1 -1
  8. package/dist/chunks/{chunk-5NZRT7GL.js → chunk-3CXZUC2Y.js} +2 -2
  9. package/dist/chunks/{chunk-WUZH2OJ6.js → chunk-3XYLEK4H.js} +2 -2
  10. package/dist/chunks/{chunk-F7O56DVR.js → chunk-4OVIUCSB.js} +2 -2
  11. package/dist/chunks/{chunk-JGH2V54E.js → chunk-4YPCUVMC.js} +2 -2
  12. package/dist/chunks/{chunk-FU57ZNRQ.js → chunk-6CXLLJ2C.js} +3 -3
  13. package/dist/chunks/{chunk-SACSQ45G.js → chunk-6MD4VS2F.js} +1 -1
  14. package/dist/chunks/{chunk-VACK24HF.js → chunk-735MPLUL.js} +35 -9
  15. package/dist/chunks/chunk-7GDNDQD7.js +504 -0
  16. package/dist/chunks/{chunk-IN4IYSA2.js → chunk-7PEYA3NA.js} +2 -2
  17. package/dist/chunks/{chunk-CWCVQJYY.js → chunk-AXE3RR7J.js} +1 -1
  18. package/dist/chunks/{chunk-BXE3SBBN.js → chunk-C3KAPREU.js} +1 -1
  19. package/dist/chunks/{chunk-ATDVS2CW.js → chunk-G3GLGDKV.js} +2 -2
  20. package/dist/chunks/{chunk-RB2MDFQU.js → chunk-G4WQBRDS.js} +4 -4
  21. package/dist/chunks/{chunk-SDI6BVG7.js → chunk-J4PDHWP2.js} +1 -1
  22. package/dist/chunks/{chunk-3UGWYQNY.js → chunk-JKIAHYAW.js} +14 -8
  23. package/dist/chunks/{chunk-TCSV3II7.js → chunk-L2RQV23D.js} +1 -1
  24. package/dist/chunks/{chunk-6XDTAKO7.js → chunk-LA6JHEVV.js} +1 -1
  25. package/dist/chunks/{chunk-G7SG4XMK.js → chunk-LODKC7PJ.js} +7 -0
  26. package/dist/chunks/{chunk-RK7ZOFPR.js → chunk-MO4DIRHD.js} +80 -38
  27. package/dist/chunks/{chunk-PCHEUVHB.js → chunk-N2GAA7RB.js} +1 -1
  28. package/dist/chunks/{chunk-I5SGYTRM.js → chunk-N4AJV4GH.js} +25 -14
  29. package/dist/chunks/{chunk-Q7I563MH.js → chunk-NHOXLUIL.js} +2 -2
  30. package/dist/chunks/{chunk-RT4K2JMZ.js → chunk-NQWEYJDD.js} +1 -1
  31. package/dist/chunks/{chunk-3Y2EFDID.js → chunk-OIOAK7BS.js} +1 -1
  32. package/dist/chunks/{chunk-EZGNBDHD.js → chunk-R3NPBUKT.js} +8 -8
  33. package/dist/chunks/{chunk-KJDERUQF.js → chunk-R4XCTRIU.js} +45 -10
  34. package/dist/chunks/{chunk-HTF32WSW.js → chunk-S3ICPPXC.js} +3 -3
  35. package/dist/chunks/{chunk-OXW5OHYQ.js → chunk-S4CH434Z.js} +1 -1
  36. package/dist/chunks/{chunk-HMEAGAGC.js → chunk-S7BCZVRK.js} +2 -2
  37. package/dist/chunks/{chunk-UV2IJMIG.js → chunk-SDDMV2MM.js} +1 -1
  38. package/dist/chunks/{chunk-J6XHW4KI.js → chunk-SIXFXXRI.js} +3 -3
  39. package/dist/chunks/{chunk-LKQOIPGE.js → chunk-U6JPSXJ3.js} +90 -21
  40. package/dist/chunks/{chunk-SENPGW4O.js → chunk-VCUOYVLC.js} +1 -1
  41. package/dist/chunks/{chunk-XTF2VWJN.js → chunk-VSRRIFRF.js} +1 -1
  42. package/dist/chunks/{chunk-BFUS3ENH.js → chunk-X5ULFAMM.js} +2 -2
  43. package/dist/chunks/{chunk-PJWLYGRL.js → chunk-XOIYBEU7.js} +1 -1
  44. package/dist/chunks/{chunk-JLIVX2SF.js → chunk-YEDZ37PH.js} +1 -1
  45. package/dist/chunks/{chunk-APLWFV4I.js → chunk-YF6T33PU.js} +10 -2
  46. package/dist/chunks/{chunk-2VMKQKVO.js → chunk-YIWN32ZX.js} +1 -1
  47. package/dist/chunks/{chunk-3WSA4NNP.js → chunk-ZKIH2USC.js} +1 -1
  48. package/dist/cli/figure.js +31 -30
  49. package/dist/cli/fold.js +6 -6
  50. package/dist/deletionEdges.js +2 -2
  51. package/dist/figure.js +27 -26
  52. package/dist/figureData.js +25 -24
  53. package/dist/figureScene.js +18 -17
  54. package/dist/figureSettings.js +6 -6
  55. package/dist/foldVariants.js +2 -2
  56. package/dist/genes/genePins.js +3 -3
  57. package/dist/graphLabels.js +4 -4
  58. package/dist/index.js +45 -44
  59. package/dist/labelLayout.js +8 -8
  60. package/dist/layout/forceCache.js +6 -6
  61. package/dist/layout/mergeRuns.js +2 -2
  62. package/dist/layout/orientToReference.js +3 -1
  63. package/dist/layout/tubeMapLayout.js +9 -9
  64. package/dist/layout/walkRowDraw.js +9 -8
  65. package/dist/layout/walkRowLayout.js +3 -3
  66. package/dist/layout/walkRowRuns.js +1 -1
  67. package/dist/layout/walkRows.js +2 -2
  68. package/dist/layout/walkStrip.js +13 -12
  69. package/dist/layoutModes.js +11 -11
  70. package/dist/pathColors.js +5 -5
  71. package/dist/pipeline.js +5 -5
  72. package/dist/referenceStrip.js +9 -8
  73. package/dist/renderer/GeometryBuilder.js +8 -7
  74. package/dist/renderer/walkLanes.js +44 -0
  75. package/dist/tubeMap/axis.js +5 -5
  76. package/dist/tubeMap/bundle.js +10 -10
  77. package/dist/tubeMap/coarsen.js +10 -10
  78. package/dist/tubeMap/deviations.js +11 -11
  79. package/dist/tubeMap/draw.js +5 -5
  80. package/dist/tubeMap/genes.js +6 -6
  81. package/dist/tubeMap/nodeColors.js +9 -8
  82. package/dist/tubeMap/reads.js +2 -2
  83. package/dist/types/figureData.d.ts +22 -0
  84. package/dist/types/foldVariants.d.ts +3 -1
  85. package/dist/types/renderer/types.d.ts +20 -0
  86. package/dist/types/renderer/walkLanes.d.ts +60 -0
  87. package/dist/types/types.d.ts +1 -0
  88. package/dist/types/util/geometry.d.ts +13 -1
  89. package/dist/types/version.d.ts +1 -1
  90. package/dist/types/walkEncoding.d.ts +7 -5
  91. package/dist/types/walkHighlight.d.ts +3 -0
  92. package/dist/util/SpatialIndex.js +4 -4
  93. package/dist/util/edgeCurves.js +3 -3
  94. package/dist/util/geometry.js +7 -1
  95. package/dist/util/hitDetection.js +5 -5
  96. package/dist/version.js +1 -1
  97. package/dist/viewport.js +6 -6
  98. package/dist/walkEncoding.js +9 -8
  99. package/dist/walkHighlight.js +10 -9
  100. package/dist/walkKey.js +5 -5
  101. package/package.json +1 -1
package/README.md CHANGED
@@ -1,47 +1,94 @@
1
1
  # @jbrowse/bandage-core
2
2
 
3
- Pangenome graph layout and drawing with no host, the engine behind
3
+ TypeScript library that lays out and draws pangenome graphs, used by
4
4
  [jbrowse-plugin-graphgenomeviewer](https://github.com/GMOD/jbrowse-plugin-graphgenomeviewer)
5
- and [BandageJS](https://github.com/cmdcolin/BandageJS).
5
+ and [BandageJS](https://github.com/cmdcolin/BandageJS). It imports no React,
6
+ MobX or JBrowse code. BandageJS's
7
+ [`src/main.ts`](https://github.com/cmdcolin/BandageJS/blob/main/src/main.ts) is
8
+ the worked example.
6
9
 
7
10
  ```
8
11
  npm install @jbrowse/bandage-core
9
12
  ```
10
13
 
11
- - GFA and rGFA text in (`loadGraph`), or the same graph as typed arrays a worker
12
- can transfer (`GraphTables`)
13
- - A walk-file cut's W lines tag what lies past each fragment's start and end as
14
- `ws:Z:`/`we:Z:`, such as `break,bp=19021` or
14
+ ## Reading a graph
15
+
16
+ - `loadGraph` reads GFA or rGFA text. The caller decompresses a `.gfa.gz` first
17
+ - `loadGraph` also takes `GraphTables`, the typed arrays that
18
+ [@jbrowse/graph-walks](https://github.com/GMOD/graph-walks) cuts from a
19
+ [gfa-to-tabix](https://github.com/GMOD/gfa-to-tabix) walk file
20
+ (`.walks.bed.gz` beside its `.tbi`) for a region on the reference. A worker
21
+ can transfer them without copying, and `graphTablesGFA` writes them as GFA
22
+ - `openGbz` and `cutGbzRegion` cut a window from a
23
+ [gbz-base](https://github.com/jltsiren/gbz-base) database (`.gbz.db`) to GFA
24
+ text
25
+ - In a walk-file cut, the `ws:Z:` and `we:Z:` tags on each W line record what
26
+ lies past the fragment's start and end, such as `break,bp=19021` or
15
27
  `elsewhere,trimmed=400,chunk=GRCh38#0#chr22:20316160`
16
- (`src/gfa/walkStops.ts`). Walk rows split each gap by those stops into parts
17
- that name their cause
18
- - Layouts: Bandage's FMMM engine as WASM from
19
- [@jbrowse/graph-fmmm-layout](https://github.com/GMOD/graph-fmmm-layout)
20
- (`loadBandage`, `forceLayout`), ordered, anchored, sample rows, walk rows,
21
- tube map
22
- - A Canvas2D renderer (`buildGeometry`, `Canvas2DRenderer`), hit testing and
23
- label placement
24
- - Bubbles, deletion edges, path colors, gbz-base windows cut to GFA
25
- - Walks lifted out of the drawing (`walkLift`), one facet panel per walk
26
- (`facetLifts`, `facetGrid`) and each walk's key in words (`walkKey`)
27
- - Which assembly a backbone lies on (`graphBackbone`, `backboneAssembly`,
28
- `assemblyWalk`), and the genes on it: `featuresOnBackbone` renames an
29
- assembly's genes onto the backbone's refNames, and `genePins` pins only those
30
-
31
- - Figures: `figureSvg` draws a graph and its lifted walks to a standalone SVG,
32
- and the `bandage-figure` CLI makes one from a JSON spec with no browser:
28
+ (`src/gfa/walkStops.ts`). Walk rows split each gap at those stops and label
29
+ each part with its cause
30
+
31
+ ## Laying out and drawing
32
+
33
+ - `loadBandage` loads Bandage's FMMM engine, compiled to WASM in
34
+ [@jbrowse/graph-fmmm-layout](https://github.com/GMOD/graph-fmmm-layout), and
35
+ `forceLayout` runs it. The other layouts are ordered, anchored, sample rows,
36
+ walk rows and tube map
37
+ - `buildGeometry` and `Canvas2DRenderer` draw to a canvas, with hit testing and
38
+ label placement. The library also finds bubbles and deletion edges and colors
39
+ paths
40
+ - `walkLift` lifts a walk out of the drawing, `facetLifts` and `facetGrid` draw
41
+ one panel per walk, and `walkKey` describes each walk in words
42
+ - `graphBackbone`, `backboneAssembly` and `assemblyWalk` find which assembly a
43
+ backbone lies on. `featuresOnBackbone` renames that assembly's genes onto the
44
+ backbone's refNames, and `genePins` pins only those
45
+
46
+ ## Figures
47
+
48
+ - `figureSvg` draws a graph and its lifted walks to a standalone SVG. The
49
+ `bandage-figure` CLI makes one from a JSON spec with no browser:
33
50
  `npx -p @jbrowse/bandage-core bandage-figure spec.json -o figure.svg`. See
34
51
  [docs/figures.md](docs/figures.md)
35
- - Coarse tier: the `bandage-fold` CLI folds every variant under a size into the
36
- reference, so a graph track draws a whole chromosome. See
37
- [docs/coarse-tier.md](docs/coarse-tier.md)
38
- - Figure data: `figureData` returns what `figureSvg` would paint as columnar
39
- tables, for another graphics system to draw;
52
+ - `figureData` returns what `figureSvg` would draw as columnar tables, for
53
+ another graphics system to draw;
40
54
  [ggbandage](https://github.com/GMOD/ggbandage) draws them in ggplot2
41
55
 
42
- Nothing here imports React, MobX or a JBrowse host. BandageJS's
43
- [`src/main.ts`](https://github.com/cmdcolin/BandageJS/blob/main/src/main.ts) is
44
- the worked example.
56
+ ## Coarse tier: `bandage-fold`
57
+
58
+ `bandage-fold` writes an rGFA with every variant under `--below` bp folded into
59
+ the reference. Indexed by gfa-to-tabix, the output is the coarse tier a graph
60
+ track draws once zoomed out past the fine index, so a whole chromosome fits.
61
+ [`gfa-to-tabix fold`](https://github.com/GMOD/gfa-to-tabix/blob/main/docs/subcommands.md#fold)
62
+ documents the fold and the handover from the fine index.
63
+
64
+ ```console
65
+ npx -p @jbrowse/bandage-core bandage-fold graph.rgfa.gz --below 10000 \
66
+ | gfa-to-tabix - -o graph.fold10000
67
+ ```
68
+
69
+ - The input is a GFA or rGFA, plain or gzipped, or `-` for stdin. `-o out.gfa`
70
+ writes a file in place of stdout
71
+ - `--reference PATH` names a plain GFA's backbone path. In an rGFA, the segments
72
+ tagged `SR:i:0` form the backbone
73
+ - The fold keeps the backbone, every allele whose own length or the reference it
74
+ replaces reaches `--below`, and the shortest way from each one's ends back to
75
+ the backbone. It joins the reference between kept alleles into one segment
76
+ - `bandage-fold` drops paths and walks from the output. It writes forward a
77
+ segment that a plain GFA's path reads reversed, and flips its links to match,
78
+ so the output re-reads as the graph that was folded
79
+ - gfa-to-tabix's `--layout anchored|contig` should match the fine index's. An
80
+ anchored window inside a large bubble then returns the whole bubble in both
81
+ tiers, and a contig one only what links reach from it
82
+ - The graph track folds each cut it draws at ten pixels (`FOLD_PX` in
83
+ jbrowse-plugin-graphgenomeviewer), and folding a fold again at a larger size
84
+ closely matches folding the original at that size. A tier folded at N and
85
+ handed over at N / 10 bp per pixel, such as
86
+ `coarse: { uri: "graph.fold10000", aboveBpPerPx: 1000 }`, therefore draws
87
+ nearly what the fine cut drew
88
+ - Node caps a string at 512 MB, and `bandage-fold` reads the whole graph into
89
+ one, so it cannot fold a whole human pangenome. `gfa-to-tabix fold`, a port of
90
+ the same fold, writes the index in one pass:
91
+ `gfa-to-tabix fold graph.rgfa.gz --below 10000 -o graph.fold10000`
45
92
 
46
93
  ## Developing
47
94
 
@@ -51,27 +98,38 @@ pnpm test # unit tests
51
98
  pnpm build # dist/ with declarations
52
99
  ```
53
100
 
54
- The FMMM engine and its wasm build live in
55
- [graph-fmmm-layout](https://github.com/GMOD/graph-fmmm-layout).
56
-
57
- CI also packs the core and runs
58
- [BandageJS](https://github.com/cmdcolin/BandageJS) and
59
- [jbrowse-plugin-graphgenomeviewer](https://github.com/GMOD/jbrowse-plugin-graphgenomeviewer)
60
- against it. An API change lands with the consumer's side on a `core-next` branch
61
- in that repo, which CI tests in place of `main` until the release.
62
-
63
- Release with `pnpm version patch`: it lints, tests, stamps `src/version.ts`,
64
- writes the changelog with git-cliff and pushes the `v*` tag. `publish.yml` then
65
- runs CI, consumers included, and publishes to npm with trusted publishing only
66
- if it passes. When a consumer fails, land its side on `core-next` and rerun the
67
- failed jobs.
101
+ - The FMMM engine and its wasm build are in
102
+ [graph-fmmm-layout](https://github.com/GMOD/graph-fmmm-layout)
103
+ - CI also packs the core and runs the typecheck and tests of
104
+ [BandageJS](https://github.com/cmdcolin/BandageJS) and
105
+ [jbrowse-plugin-graphgenomeviewer](https://github.com/GMOD/jbrowse-plugin-graphgenomeviewer)
106
+ against it. For an API change, push the consumer's matching change to a
107
+ `core-next` branch in that consumer's repo, which CI tests in place of `main`
108
+ until the release
109
+ - `src/foldParity.test.ts` folds a few hundred random rGFA graphs with
110
+ `foldVariants` and with the gfa-to-tabix release that
111
+ `.github/actions/gfa-to-tabix` pins, and fails when they fold differently.
112
+ Locally the test runs the `gfa-to-tabix` on PATH or named by `GFA_TO_TABIX`,
113
+ and skips without one. In the other direction, gfa-to-tabix's
114
+ `scripts/parity-fold.sh` checks that `gfa-to-tabix fold` writes the same bytes
115
+ as `bandage-fold | gfa-to-tabix -`, and its CI tests the port against a pinned
116
+ bandage-core
117
+ - Release with `pnpm version patch`: it lints, tests, stamps `src/version.ts`,
118
+ writes the changelog with git-cliff and pushes the `v*` tag. `publish.yml`
119
+ then runs CI, consumers included, and publishes to npm with trusted publishing
120
+ only if it passes. When a consumer fails, push its side to `core-next` and
121
+ rerun the failed jobs
68
122
 
69
123
  ## See also
70
124
 
71
125
  - [jbrowse-plugin-graphgenomeviewer](https://github.com/GMOD/jbrowse-plugin-graphgenomeviewer) -
72
126
  JBrowse 2 plugin that browses these graphs by locus
73
- - [BandageJS](https://github.com/cmdcolin/BandageJS) - standalone page for GFA
74
- and gbz-base graphs
127
+ - [BandageJS](https://github.com/cmdcolin/BandageJS) - browser viewer for GFA
128
+ files, walk files and gbz-base databases
129
+ - [gfa-to-tabix](https://github.com/GMOD/gfa-to-tabix) - indexes a GFA by
130
+ reference position, writing the `.walks.bed.gz` walk files
131
+ - [@jbrowse/graph-walks](https://github.com/GMOD/graph-walks) - range-request
132
+ reader for walk files
75
133
  - [@jbrowse/graph-fmmm-layout](https://github.com/GMOD/graph-fmmm-layout) -
76
134
  Bandage's FMMM layout as wasm
77
135
  - [@jbrowse/graph-stress-layout](https://github.com/GMOD/graph-stress-layout) -
@@ -83,7 +141,7 @@ failed jobs.
83
141
  - [@jbrowse/tubemap-core](https://github.com/GMOD/tubemap-core) -
84
142
  sequenceTubeMap's layout, without the DOM
85
143
 
86
- Tutorials on [jbrowse.org](https://jbrowse.org/jb2/docs/tutorials/)
144
+ Tutorials on [jbrowse.org](https://jbrowse.org/jb2/docs/tutorials/):
87
145
 
88
146
  - [HPRC part 1: graph alleles and haplotypes](https://jbrowse.org/jb2/docs/tutorials/pangenome_hprc/)
89
147
  - [HPRC part 3: repeat lengths](https://jbrowse.org/jb2/docs/tutorials/pangenome_hprc_repeats/)
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  bubbleHalos,
3
3
  coversGraph
4
- } from "../chunks/chunk-JGH2V54E.js";
5
- import "../chunks/chunk-3Y2EFDID.js";
4
+ } from "../chunks/chunk-4YPCUVMC.js";
5
+ import "../chunks/chunk-OIOAK7BS.js";
6
6
  import "../chunks/chunk-FX4RDMDN.js";
7
- import "../chunks/chunk-FU57ZNRQ.js";
7
+ import "../chunks/chunk-6CXLLJ2C.js";
8
8
  import "../chunks/chunk-HMXCN6PG.js";
9
9
  import "../chunks/chunk-AB35TJST.js";
10
- import "../chunks/chunk-2VMKQKVO.js";
11
- import "../chunks/chunk-5NZRT7GL.js";
10
+ import "../chunks/chunk-YIWN32ZX.js";
11
+ import "../chunks/chunk-3CXZUC2Y.js";
12
12
  import "../chunks/chunk-TLWXLNLY.js";
13
13
  import "../chunks/chunk-3YBP46PB.js";
14
- import "../chunks/chunk-VACK24HF.js";
14
+ import "../chunks/chunk-735MPLUL.js";
15
15
  import "../chunks/chunk-CPMHA4W5.js";
16
16
  import "../chunks/chunk-ZPZ7GNBT.js";
17
17
  import "../chunks/chunk-BSOZW3FC.js";
@@ -3,16 +3,16 @@ import {
3
3
  BUBBLE_KIND_NAMES,
4
4
  bubbleSegmentIds,
5
5
  classifyBubble
6
- } from "../chunks/chunk-3Y2EFDID.js";
6
+ } from "../chunks/chunk-OIOAK7BS.js";
7
7
  import "../chunks/chunk-FX4RDMDN.js";
8
- import "../chunks/chunk-FU57ZNRQ.js";
8
+ import "../chunks/chunk-6CXLLJ2C.js";
9
9
  import "../chunks/chunk-HMXCN6PG.js";
10
10
  import "../chunks/chunk-AB35TJST.js";
11
- import "../chunks/chunk-2VMKQKVO.js";
12
- import "../chunks/chunk-5NZRT7GL.js";
11
+ import "../chunks/chunk-YIWN32ZX.js";
12
+ import "../chunks/chunk-3CXZUC2Y.js";
13
13
  import "../chunks/chunk-TLWXLNLY.js";
14
14
  import "../chunks/chunk-3YBP46PB.js";
15
- import "../chunks/chunk-VACK24HF.js";
15
+ import "../chunks/chunk-735MPLUL.js";
16
16
  import "../chunks/chunk-CPMHA4W5.js";
17
17
  import "../chunks/chunk-ZPZ7GNBT.js";
18
18
  import "../chunks/chunk-BSOZW3FC.js";
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  graphBubbles,
3
3
  superbubblesFromGraph
4
- } from "../chunks/chunk-J6XHW4KI.js";
5
- import "../chunks/chunk-JGH2V54E.js";
4
+ } from "../chunks/chunk-SIXFXXRI.js";
5
+ import "../chunks/chunk-4YPCUVMC.js";
6
6
  import "../chunks/chunk-RFG42VIO.js";
7
- import "../chunks/chunk-3Y2EFDID.js";
7
+ import "../chunks/chunk-OIOAK7BS.js";
8
8
  import "../chunks/chunk-FX4RDMDN.js";
9
9
  import "../chunks/chunk-MHZTTLBU.js";
10
10
  import "../chunks/chunk-UAFATXYA.js";
11
11
  import "../chunks/chunk-VX656OAZ.js";
12
- import "../chunks/chunk-FU57ZNRQ.js";
12
+ import "../chunks/chunk-6CXLLJ2C.js";
13
13
  import "../chunks/chunk-HMXCN6PG.js";
14
14
  import "../chunks/chunk-AB35TJST.js";
15
- import "../chunks/chunk-2VMKQKVO.js";
16
- import "../chunks/chunk-5NZRT7GL.js";
15
+ import "../chunks/chunk-YIWN32ZX.js";
16
+ import "../chunks/chunk-3CXZUC2Y.js";
17
17
  import "../chunks/chunk-TLWXLNLY.js";
18
18
  import "../chunks/chunk-3YBP46PB.js";
19
- import "../chunks/chunk-VACK24HF.js";
19
+ import "../chunks/chunk-735MPLUL.js";
20
20
  import "../chunks/chunk-CPMHA4W5.js";
21
21
  import "../chunks/chunk-ZPZ7GNBT.js";
22
22
  import "../chunks/chunk-BSOZW3FC.js";
@@ -1,24 +1,26 @@
1
+ import {
2
+ ownStrand
3
+ } from "./chunk-735MPLUL.js";
1
4
  import {
2
5
  isBackbone
3
6
  } from "./chunk-RJWPJCIB.js";
4
7
 
5
8
  // src/layout/orientToReference.ts
6
9
  function orientToReference(graph, positions) {
7
- const backbone = graph.nodes.filter(
8
- (node) => isBackbone(node) && (positions[node.id]?.length ?? 0) > 0
9
- );
10
- if (backbone.length < 2) {
11
- return positions;
12
- }
13
- const points = backbone.map((node) => {
10
+ const backbone = graph.nodes.filter(isBackbone).filter((node) => (positions[node.id]?.length ?? 0) > 0);
11
+ const points = backbone.flatMap((node) => {
14
12
  const segments = positions[node.id];
15
- const mid = segments[Math.floor(segments.length / 2)];
16
- return {
17
- x: mid.x,
18
- y: mid.y,
19
- r: node.stable.start + node.length / 2,
20
- w: node.length
21
- };
13
+ const last = segments.length - 1;
14
+ const forwards = ownStrand(node.id) === (node.stable.strand ?? "+");
15
+ return segments.map((p, i) => {
16
+ const along = last === 0 ? 0.5 : i / last;
17
+ return {
18
+ x: p.x,
19
+ y: p.y,
20
+ r: node.stable.start + node.length * (forwards ? along : 1 - along),
21
+ w: node.length / segments.length
22
+ };
23
+ });
22
24
  });
23
25
  const weight = points.reduce((sum, p) => sum + p.w, 0);
24
26
  if (weight === 0) {
@@ -33,6 +35,9 @@ function orientToReference(graph, positions) {
33
35
  sxr += p.w * (p.x - cx) * (p.r - cr);
34
36
  syr += p.w * (p.y - cy) * (p.r - cr);
35
37
  }
38
+ if (sxr === 0 && syr === 0) {
39
+ return positions;
40
+ }
36
41
  const angle = -Math.atan2(syr, sxr);
37
42
  const c = Math.cos(angle);
38
43
  const s = Math.sin(angle);