@jbrowse/bandage-core 9.9.2 → 10.0.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 (79) hide show
  1. package/README.md +3 -0
  2. package/dist/bubbles/popBubble.js +3 -2
  3. package/dist/bubbles/superbubbles.js +5 -4
  4. package/dist/chunks/{chunk-YAN2ZPNV.js → chunk-33T67FPZ.js} +1 -1
  5. package/dist/chunks/{chunk-TOVOJNT7.js → chunk-3APK25GI.js} +1 -1
  6. package/dist/chunks/{chunk-A6PSWTLX.js → chunk-4QTNXTGW.js} +1 -1
  7. package/dist/chunks/{chunk-ROQGMTFB.js → chunk-BEWLQADP.js} +6 -6
  8. package/dist/chunks/{chunk-BQ33OOLC.js → chunk-CDPYXHVR.js} +1 -1
  9. package/dist/chunks/{chunk-YS7VA5SI.js → chunk-DCJC32QW.js} +1 -1
  10. package/dist/chunks/{chunk-YGN4KL7W.js → chunk-E5UEYZWK.js} +1 -1
  11. package/dist/chunks/{chunk-IGJCTPFB.js → chunk-EMUUNWRU.js} +52 -43
  12. package/dist/chunks/{chunk-PIN7ZMTZ.js → chunk-EU6FBTQF.js} +4 -4
  13. package/dist/chunks/{chunk-WVBYR6Y7.js → chunk-FG762CCP.js} +3 -8
  14. package/dist/chunks/{chunk-73RSLGZT.js → chunk-FLFBYSJO.js} +1 -1
  15. package/dist/chunks/{chunk-IJRNMO4D.js → chunk-ICXMWYOA.js} +5 -5
  16. package/dist/chunks/{chunk-HOZI3FBG.js → chunk-IM4SJUPO.js} +12 -22
  17. package/dist/chunks/{chunk-6PYZYBBF.js → chunk-KAN2WTG5.js} +1 -1
  18. package/dist/chunks/{chunk-RK3MF4FD.js → chunk-KJYSOHVN.js} +1 -1
  19. package/dist/chunks/{chunk-F4BKWWLS.js → chunk-NP356MC2.js} +4 -4
  20. package/dist/chunks/{chunk-KJEMKHVB.js → chunk-OEPCRURR.js} +1 -1
  21. package/dist/chunks/{chunk-ZBLKAWSD.js → chunk-OOLNLCIO.js} +1 -1
  22. package/dist/chunks/chunk-OPPVSPEF.js +57 -0
  23. package/dist/chunks/{chunk-OA7RIMZ2.js → chunk-PSMKPSO4.js} +89 -22
  24. package/dist/chunks/chunk-Q6IOQP4J.js +292 -0
  25. package/dist/chunks/{chunk-LTUWJKHD.js → chunk-Q7LYHGGQ.js} +114 -6
  26. package/dist/chunks/{chunk-EE37PVQY.js → chunk-QIVPRZ4H.js} +12 -7
  27. package/dist/chunks/{chunk-J7YKQ5YW.js → chunk-QXAB2FLJ.js} +1 -1
  28. package/dist/chunks/chunk-RAEABQNW.js +227 -0
  29. package/dist/chunks/{chunk-EDASNMLY.js → chunk-REE4GUDM.js} +4 -4
  30. package/dist/chunks/{chunk-IZ3W5IU2.js → chunk-RJXPPYA7.js} +36 -36
  31. package/dist/chunks/{chunk-F5BYHLIN.js → chunk-VOWI544A.js} +1 -1
  32. package/dist/chunks/{chunk-P6O4RSOQ.js → chunk-VZNKA3K2.js} +5 -5
  33. package/dist/chunks/{chunk-FPTI3WAV.js → chunk-W4GZCVUK.js} +18 -13
  34. package/dist/chunks/{chunk-MECWJY2R.js → chunk-WI7ZHJ27.js} +5 -5
  35. package/dist/cli/figure.js +50 -48
  36. package/dist/cli/fold.js +8 -6
  37. package/dist/figure.js +31 -29
  38. package/dist/figureData.js +63 -0
  39. package/dist/figureSettings.js +9 -7
  40. package/dist/gbzCut.js +3 -2
  41. package/dist/gbzWindow.js +6 -1
  42. package/dist/gfa/gfaConverter.js +3 -2
  43. package/dist/gfa/graphTables.js +2 -1
  44. package/dist/index.js +173 -156
  45. package/dist/layout/forceCache.js +9 -7
  46. package/dist/layout/smoothChains.js +6 -0
  47. package/dist/layout/trimToWindow.js +17 -23
  48. package/dist/layout/tubeMapLayout.js +5 -4
  49. package/dist/layout/walkRowDraw.js +10 -9
  50. package/dist/layout/walkRowLayout.js +4 -3
  51. package/dist/layout/walkRows.js +3 -2
  52. package/dist/layout/walkStrip.js +11 -10
  53. package/dist/layoutModes.js +11 -10
  54. package/dist/pathAnchoring.js +2 -1
  55. package/dist/pathColors.js +4 -3
  56. package/dist/pathVisits.js +8 -0
  57. package/dist/pipeline.js +8 -6
  58. package/dist/referenceRampCss.js +8 -7
  59. package/dist/referenceStrip.js +8 -7
  60. package/dist/renderer/GeometryBuilder.js +7 -6
  61. package/dist/tubeMap/bundle.js +6 -5
  62. package/dist/tubeMap/coarsen.js +17 -15
  63. package/dist/tubeMap/draw.js +4 -3
  64. package/dist/tubeMap/nodeColors.js +8 -7
  65. package/dist/types/figureData.d.ts +146 -0
  66. package/dist/types/gbzWindow.d.ts +15 -1
  67. package/dist/types/gfa/gfaConverter.d.ts +1 -1
  68. package/dist/types/index.d.ts +4 -1
  69. package/dist/types/layout/deletionRoutes.d.ts +1 -1
  70. package/dist/types/layout/smoothChains.d.ts +2 -0
  71. package/dist/types/pathAnchoring.d.ts +3 -2
  72. package/dist/types/pathVisits.d.ts +64 -0
  73. package/dist/types/types.d.ts +2 -1
  74. package/dist/types/version.d.ts +1 -1
  75. package/dist/version.js +1 -1
  76. package/dist/viewport.js +9 -7
  77. package/dist/walkEncoding.js +8 -7
  78. package/dist/walkHighlight.js +9 -8
  79. package/package.json +1 -1
package/README.md CHANGED
@@ -25,6 +25,9 @@ npm install @jbrowse/bandage-core
25
25
  and the `bandage-figure` CLI makes one from a JSON spec with no browser:
26
26
  `npx -p @jbrowse/bandage-core bandage-figure spec.json -o figure.svg`. See
27
27
  [docs/figures.md](docs/figures.md)
28
+ - Figure data: `figureData` returns what `figureSvg` would paint as columnar
29
+ tables, for another graphics system to draw;
30
+ [ggbandage](https://github.com/GMOD/ggbandage) draws them in ggplot2
28
31
 
29
32
  Nothing here imports React, MobX or a JBrowse host. BandageJS's
30
33
  [`src/main.ts`](https://github.com/cmdcolin/BandageJS/blob/main/src/main.ts) is
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  bubbleSubgraph
3
- } from "../chunks/chunk-A6PSWTLX.js";
4
- import "../chunks/chunk-IGJCTPFB.js";
3
+ } from "../chunks/chunk-4QTNXTGW.js";
4
+ import "../chunks/chunk-EMUUNWRU.js";
5
+ import "../chunks/chunk-RAEABQNW.js";
5
6
  import "../chunks/chunk-BPLIXMH7.js";
6
7
  import "../chunks/chunk-FYQWPEEY.js";
7
8
  export {
@@ -1,14 +1,15 @@
1
1
  import {
2
2
  graphBubbles,
3
3
  superbubblesFromGraph
4
- } from "../chunks/chunk-ROQGMTFB.js";
5
- import "../chunks/chunk-A6PSWTLX.js";
4
+ } from "../chunks/chunk-BEWLQADP.js";
5
+ import "../chunks/chunk-CLOP7UVD.js";
6
+ import "../chunks/chunk-4QTNXTGW.js";
6
7
  import "../chunks/chunk-EHUBJDDB.js";
7
8
  import "../chunks/chunk-XKWD2RY3.js";
8
- import "../chunks/chunk-CLOP7UVD.js";
9
9
  import "../chunks/chunk-FX4RDMDN.js";
10
10
  import "../chunks/chunk-HNQPEMYE.js";
11
- import "../chunks/chunk-IGJCTPFB.js";
11
+ import "../chunks/chunk-EMUUNWRU.js";
12
+ import "../chunks/chunk-RAEABQNW.js";
12
13
  import "../chunks/chunk-BPLIXMH7.js";
13
14
  import "../chunks/chunk-2CVHXFK7.js";
14
15
  import "../chunks/chunk-CPMHA4W5.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  engineKey,
3
3
  forceLayout
4
- } from "./chunk-FPTI3WAV.js";
4
+ } from "./chunk-W4GZCVUK.js";
5
5
 
6
6
  // src/layout/forceCache.ts
7
7
  var DEFAULT_SIZE = 4;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  walkRows
3
- } from "./chunk-6PYZYBBF.js";
3
+ } from "./chunk-KAN2WTG5.js";
4
4
  import {
5
5
  ROW_HEIGHT_PX
6
6
  } from "./chunk-CPMHA4W5.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  trimOrigins
3
- } from "./chunk-IGJCTPFB.js";
3
+ } from "./chunk-EMUUNWRU.js";
4
4
 
5
5
  // src/bubbles/popBubble.ts
6
6
  function bubbleSubgraph(graph, segmentIds) {
@@ -1,17 +1,17 @@
1
+ import {
2
+ bubblesFromGraph,
3
+ walkIndexOf,
4
+ walkRoutes
5
+ } from "./chunk-CLOP7UVD.js";
1
6
  import {
2
7
  bubbleSubgraph
3
- } from "./chunk-A6PSWTLX.js";
8
+ } from "./chunk-4QTNXTGW.js";
4
9
  import {
5
10
  coversGraph
6
11
  } from "./chunk-EHUBJDDB.js";
7
12
  import {
8
13
  bubbleSegmentIds
9
14
  } from "./chunk-XKWD2RY3.js";
10
- import {
11
- bubblesFromGraph,
12
- walkIndexOf,
13
- walkRoutes
14
- } from "./chunk-CLOP7UVD.js";
15
15
  import {
16
16
  SATURATED_PATH_COUNT
17
17
  } from "./chunk-FX4RDMDN.js";
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "9.9.2";
2
+ var version = "10.0.0";
3
3
 
4
4
  export {
5
5
  version
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  REFERENCE_RAMP_MAX_HUE
3
- } from "./chunk-F4BKWWLS.js";
3
+ } from "./chunk-NP356MC2.js";
4
4
 
5
5
  // src/referenceRampCss.ts
6
6
  function rampHueCss(hue) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ENGINE_DEFAULTS
3
- } from "./chunk-FPTI3WAV.js";
3
+ } from "./chunk-W4GZCVUK.js";
4
4
 
5
5
  // src/figureSettings.ts
6
6
  var FIGURE_DEFAULTS = {
@@ -1,3 +1,6 @@
1
+ import {
2
+ PathVisitsBuilder
3
+ } from "./chunk-RAEABQNW.js";
1
4
  import {
2
5
  panSNSample
3
6
  } from "./chunk-BPLIXMH7.js";
@@ -13,23 +16,13 @@ function pathOrigin(pathName) {
13
16
  }
14
17
  function surveyPaths(paths, lengthOf) {
15
18
  const anchorPaths = [];
16
- const pathVisits = /* @__PURE__ */ new Map();
19
+ const visits = new PathVisitsBuilder();
17
20
  for (const path of paths) {
18
21
  const sample = panSNSample(path.name);
22
+ const p = visits.pathOf(path.name, sample);
19
23
  let pos = path.start;
20
24
  for (const step of path.steps) {
21
- const visit = {
22
- path: path.name,
23
- sample,
24
- start: pos,
25
- strand: step.strand
26
- };
27
- const existing = pathVisits.get(step.id);
28
- if (existing) {
29
- existing.push(visit);
30
- } else {
31
- pathVisits.set(step.id, [visit]);
32
- }
25
+ visits.addAt(visits.declare(step.id), p, pos, step.strand === "-");
33
26
  pos += lengthOf(step.id);
34
27
  }
35
28
  anchorPaths.push({
@@ -39,7 +32,7 @@ function surveyPaths(paths, lengthOf) {
39
32
  length: pos - path.start
40
33
  });
41
34
  }
42
- return { anchorPaths, pathVisits };
35
+ return { anchorPaths, pathVisits: visits.build() };
43
36
  }
44
37
  function chooseReferencePath(anchorPaths, preferred) {
45
38
  const named = anchorPaths.find(
@@ -49,41 +42,56 @@ function chooseReferencePath(anchorPaths, preferred) {
49
42
  }
50
43
  var OFF_REFERENCE_RANK = 1;
51
44
  function anchorNode(node, visits, reference, samplesOf) {
52
- let anchored = node;
53
- if (visits && visits.length > 0) {
54
- const anchor = visits.find((v) => v.path === reference) ?? visits[0];
55
- anchored = {
56
- ...node,
57
- stable: {
58
- refName: anchor.path,
59
- start: anchor.start,
60
- rank: anchor.path === reference ? REFERENCE_RANK : OFF_REFERENCE_RANK,
61
- strand: anchor.strand
62
- },
63
- samples: samplesOf(visits)
64
- };
45
+ const slot = visits.slot(node.name);
46
+ if (slot < 0 || visits.offsets[slot] === visits.offsets[slot + 1]) {
47
+ return node;
65
48
  }
66
- return anchored;
49
+ const own = visits.firstBy(slot, reference);
50
+ const anchor = own >= 0 ? own : visits.offsets[slot];
51
+ return {
52
+ ...node,
53
+ stable: {
54
+ refName: visits.paths[visits.path[anchor]],
55
+ start: visits.start[anchor],
56
+ rank: own >= 0 ? REFERENCE_RANK : OFF_REFERENCE_RANK,
57
+ strand: visits.strand(anchor)
58
+ },
59
+ samples: samplesOf(slot)
60
+ };
67
61
  }
68
- function sampleSorter(paths) {
69
- const sorted = [...new Set(paths.map((p) => p.sample))].sort();
62
+ function sampleSorter(visits) {
63
+ const sorted = [...new Set(visits.samples)].sort();
70
64
  const rank = new Map(sorted.map((sample, i) => [sample, i]));
65
+ const pathRank = Int32Array.from(visits.samples, (s) => rank.get(s));
71
66
  const seen = new Uint8Array(sorted.length);
72
- return (visits) => {
73
- const ranks = [];
74
- for (const { sample } of visits) {
75
- const r = rank.get(sample);
76
- if (r === void 0) {
77
- ranks.forEach((r2) => seen[r2] = 0);
78
- return [...new Set(visits.map((v) => v.sample))].sort();
79
- }
67
+ const ranks = new Int32Array(sorted.length);
68
+ return (slot) => {
69
+ let n = 0;
70
+ for (let i = visits.offsets[slot]; i < visits.offsets[slot + 1]; i++) {
71
+ const r = pathRank[visits.path[i]];
80
72
  if (seen[r] === 0) {
81
73
  seen[r] = 1;
82
- ranks.push(r);
74
+ ranks[n++] = r;
75
+ }
76
+ }
77
+ let out;
78
+ if (n === sorted.length) {
79
+ out = sorted;
80
+ seen.fill(0);
81
+ } else if (n * 8 < sorted.length) {
82
+ const found = ranks.subarray(0, n);
83
+ found.forEach((r) => seen[r] = 0);
84
+ out = Array.from(found.sort(), (r) => sorted[r]);
85
+ } else {
86
+ out = [];
87
+ for (let r = 0; r < sorted.length; r++) {
88
+ if (seen[r] === 1) {
89
+ seen[r] = 0;
90
+ out.push(sorted[r]);
91
+ }
83
92
  }
84
93
  }
85
- ranks.forEach((r) => seen[r] = 0);
86
- return Array.from(Int32Array.from(ranks).sort(), (r) => sorted[r]);
94
+ return out;
87
95
  };
88
96
  }
89
97
  function anchorFromPaths(graph, preferred) {
@@ -92,11 +100,12 @@ function anchorFromPaths(graph, preferred) {
92
100
  if (!reference || !anchorPaths || !pathVisits) {
93
101
  return graph;
94
102
  }
95
- const samplesOf = sampleSorter(anchorPaths);
103
+ const samplesOf = sampleSorter(pathVisits);
104
+ const referenceIndex = pathVisits.pathIndex(reference.name);
96
105
  return {
97
106
  ...graph,
98
107
  nodes: graph.nodes.map(
99
- (node) => anchorNode(node, pathVisits.get(node.name), reference.name, samplesOf)
108
+ (node) => anchorNode(node, pathVisits, referenceIndex, samplesOf)
100
109
  ),
101
110
  anchoredBy: "paths",
102
111
  referencePath: reference.name
@@ -1,15 +1,15 @@
1
- import {
2
- tubeMapMismatches
3
- } from "./chunk-XXT2JCAC.js";
4
1
  import {
5
2
  MAX_GAP_PX
6
3
  } from "./chunk-HK5Y2YWV.js";
4
+ import {
5
+ tubeMapMismatches
6
+ } from "./chunk-XXT2JCAC.js";
7
7
  import {
8
8
  readColor
9
9
  } from "./chunk-CWFNEKST.js";
10
10
  import {
11
11
  pathOrigin
12
- } from "./chunk-IGJCTPFB.js";
12
+ } from "./chunk-EMUUNWRU.js";
13
13
 
14
14
  // src/tubeMap/draw.ts
15
15
  import { curvePaths, nodeOutlinePath } from "@jbrowse/tubemap-core";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  pathSteps
3
- } from "./chunk-HOZI3FBG.js";
3
+ } from "./chunk-IM4SJUPO.js";
4
4
  import {
5
5
  pathOrigin
6
- } from "./chunk-IGJCTPFB.js";
6
+ } from "./chunk-EMUUNWRU.js";
7
7
 
8
8
  // src/tubeMap/bundle.ts
9
9
  function bundleRoutes(graph, groupOf = () => "", merge = true) {
@@ -67,12 +67,7 @@ function bundleRoutes(graph, groupOf = () => "", merge = true) {
67
67
  ...graph,
68
68
  paths: kept,
69
69
  anchorPaths: graph.anchorPaths?.filter((p) => keptWalks.has(p.name)),
70
- pathVisits: graph.pathVisits ? new Map(
71
- [...graph.pathVisits].map(([segment, visits]) => [
72
- segment,
73
- visits.filter((v) => keptWalks.has(v.path))
74
- ])
75
- ) : void 0
70
+ pathVisits: graph.pathVisits?.filter((path) => keptWalks.has(path))
76
71
  };
77
72
  }
78
73
 
@@ -5,7 +5,7 @@ import {
5
5
  referencePathQuery,
6
6
  referenceSamplesOf,
7
7
  resolveReferenceSample
8
- } from "./chunk-LTUWJKHD.js";
8
+ } from "./chunk-Q7LYHGGQ.js";
9
9
 
10
10
  // src/gbzCut.ts
11
11
  import { GBZBase } from "@gmod/gbz-base";
@@ -1,12 +1,12 @@
1
- import {
2
- sampleRowLayout
3
- } from "./chunk-LOEA5IHZ.js";
4
1
  import {
5
2
  hasTubeMapBackbone,
6
3
  hasTubeMapPaths,
7
4
  tubeMapLayout,
8
5
  tubeMapReferenceLayout
9
- } from "./chunk-HOZI3FBG.js";
6
+ } from "./chunk-IM4SJUPO.js";
7
+ import {
8
+ sampleRowLayout
9
+ } from "./chunk-LOEA5IHZ.js";
10
10
  import {
11
11
  anchoredLayout
12
12
  } from "./chunk-L3O7AWLI.js";
@@ -15,7 +15,7 @@ import {
15
15
  } from "./chunk-HNQPEMYE.js";
16
16
  import {
17
17
  walkRowLayout
18
- } from "./chunk-TOVOJNT7.js";
18
+ } from "./chunk-3APK25GI.js";
19
19
  import {
20
20
  isBackbone,
21
21
  isOffReference
@@ -6,10 +6,10 @@ import {
6
6
  import {
7
7
  pathCssColor,
8
8
  pathGreyCssColor
9
- } from "./chunk-EDASNMLY.js";
9
+ } from "./chunk-REE4GUDM.js";
10
10
  import {
11
11
  pathOrigin
12
- } from "./chunk-IGJCTPFB.js";
12
+ } from "./chunk-EMUUNWRU.js";
13
13
  import {
14
14
  ownStrand,
15
15
  strandSides
@@ -22,30 +22,19 @@ import {
22
22
  import { forward, isReverse, layoutTubeMap } from "@jbrowse/tubemap-core";
23
23
  function pathSteps(graph) {
24
24
  const nodeById = new Map(graph.nodes.map((n) => [n.id, n]));
25
- const strands = /* @__PURE__ */ new Map();
26
- for (const [segment, visits] of graph.pathVisits ?? []) {
27
- for (const visit of visits) {
28
- const key = `${visit.path} ${segment}`;
29
- const list = strands.get(key);
30
- if (list) {
31
- list.push(visit.strand);
32
- } else {
33
- strands.set(key, [visit.strand]);
34
- }
35
- }
36
- }
37
- const seen = /* @__PURE__ */ new Map();
25
+ const visits = graph.pathVisits;
26
+ const next = visits?.replay();
38
27
  return (graph.paths ?? []).map((path) => {
39
- const walk = pathOrigin(path.name).name;
28
+ const walk = visits?.pathIndex(pathOrigin(path.name).name) ?? -1;
40
29
  return path.nodeIds.flatMap((id) => {
41
30
  const node = nodeById.get(id);
42
31
  if (!node) {
43
32
  return [];
44
33
  }
45
- const key = `${walk} ${node.name}`;
46
- const k = seen.get(key) ?? 0;
47
- seen.set(key, k + 1);
48
- return [{ node, strand: strands.get(key)?.[k] ?? canonicalStrand(node) }];
34
+ const at = visits && next ? next(visits.slot(node.name), walk) : -1;
35
+ return [
36
+ { node, strand: at >= 0 ? visits.strand(at) : canonicalStrand(node) }
37
+ ];
49
38
  });
50
39
  });
51
40
  }
@@ -208,8 +197,9 @@ function boxGraph(graph, { members, flipped }) {
208
197
  ...path,
209
198
  nodeIds: path.nodeIds.filter((id) => !absorbed.has(id))
210
199
  })),
211
- pathVisits: graph.pathVisits && new Map(
212
- [...graph.pathVisits].filter(([name]) => !absorbedNames.has(name))
200
+ pathVisits: graph.pathVisits?.filter(
201
+ () => true,
202
+ (segment) => !absorbedNames.has(segment)
213
203
  )
214
204
  };
215
205
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pathOrigin
3
- } from "./chunk-IGJCTPFB.js";
3
+ } from "./chunk-EMUUNWRU.js";
4
4
  import {
5
5
  panSNContig,
6
6
  panSNSample
@@ -2,7 +2,7 @@ import {
2
2
  LIFT_BACKDROP_CSS,
3
3
  computeColorSchemeRange,
4
4
  getNodeColor
5
- } from "./chunk-F4BKWWLS.js";
5
+ } from "./chunk-NP356MC2.js";
6
6
  import {
7
7
  abgrToCssRgba
8
8
  } from "./chunk-G2FD7S3C.js";
@@ -3,19 +3,19 @@ import {
3
3
  fadeAbgr,
4
4
  packAbgr
5
5
  } from "./chunk-G2FD7S3C.js";
6
+ import {
7
+ baseEdgeCurves
8
+ } from "./chunk-WFB5TXRA.js";
6
9
  import {
7
10
  PATH_LIGHTNESS,
8
11
  PATH_SATURATION,
9
12
  nameHue,
10
13
  pathHueAt
11
- } from "./chunk-EDASNMLY.js";
14
+ } from "./chunk-REE4GUDM.js";
12
15
  import {
13
16
  meanDepth,
14
17
  nodeWidthPx
15
18
  } from "./chunk-PBENCR5L.js";
16
- import {
17
- baseEdgeCurves
18
- } from "./chunk-WFB5TXRA.js";
19
19
  import {
20
20
  referenceMidpoints
21
21
  } from "./chunk-ES2N6V56.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  computeColorSchemeRange,
3
3
  getNodeColor
4
- } from "./chunk-F4BKWWLS.js";
4
+ } from "./chunk-NP356MC2.js";
5
5
  import {
6
6
  abgrToCssRgba
7
7
  } from "./chunk-G2FD7S3C.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  clampZoom
3
- } from "./chunk-FPTI3WAV.js";
3
+ } from "./chunk-W4GZCVUK.js";
4
4
 
5
5
  // src/viewport.ts
6
6
  function axisScaleOf(scale, pixelRows) {
@@ -0,0 +1,57 @@
1
+ // src/layout/smoothChains.ts
2
+ var STEP_TURN = Math.PI / 24;
3
+ function turnAt(line, i) {
4
+ const a = line[i - 1];
5
+ const b = line[i];
6
+ const c = line[i + 1];
7
+ if (!a || !c) {
8
+ return 0;
9
+ }
10
+ const t = Math.abs(
11
+ Math.atan2(c.y - b.y, c.x - b.x) - Math.atan2(b.y - a.y, b.x - a.x)
12
+ );
13
+ return t > Math.PI ? 2 * Math.PI - t : t;
14
+ }
15
+ function centripetal(p0, p1, p2, p3, u) {
16
+ const knot = (a, b) => Math.max(Math.hypot(b.x - a.x, b.y - a.y) ** 0.5, 1e-9);
17
+ const t1 = knot(p0, p1);
18
+ const t2 = t1 + knot(p1, p2);
19
+ const t3 = t2 + knot(p2, p3);
20
+ const t = t1 + u * (t2 - t1);
21
+ const lerp = (a, b, ta, tb) => {
22
+ const f = (t - ta) / (tb - ta);
23
+ return { x: a.x + (b.x - a.x) * f, y: a.y + (b.y - a.y) * f };
24
+ };
25
+ const a1 = lerp(p0, p1, 0, t1);
26
+ const a2 = lerp(p1, p2, t1, t2);
27
+ const a3 = lerp(p2, p3, t2, t3);
28
+ return lerp(lerp(a1, a2, 0, t2), lerp(a2, a3, t1, t3), t1, t2);
29
+ }
30
+ var reflect = (p, about) => ({
31
+ x: 2 * about.x - p.x,
32
+ y: 2 * about.y - p.y
33
+ });
34
+ function smoothChain(line) {
35
+ if (line.length < 3) {
36
+ return line;
37
+ }
38
+ const out = [line[0]];
39
+ for (let i = 0; i + 1 < line.length; i++) {
40
+ const p1 = line[i];
41
+ const p2 = line[i + 1];
42
+ const steps = Math.ceil(
43
+ Math.max(turnAt(line, i), turnAt(line, i + 1)) / STEP_TURN
44
+ );
45
+ const p0 = line[i - 1] ?? reflect(p2, p1);
46
+ const p3 = line[i + 2] ?? reflect(p1, p2);
47
+ for (let s = 1; s < steps; s++) {
48
+ out.push(centripetal(p0, p1, p2, p3, s / steps));
49
+ }
50
+ out.push(p2);
51
+ }
52
+ return out;
53
+ }
54
+
55
+ export {
56
+ smoothChain
57
+ };