@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.
- package/README.md +3 -0
- package/dist/bubbles/popBubble.js +3 -2
- package/dist/bubbles/superbubbles.js +5 -4
- package/dist/chunks/{chunk-YAN2ZPNV.js → chunk-33T67FPZ.js} +1 -1
- package/dist/chunks/{chunk-TOVOJNT7.js → chunk-3APK25GI.js} +1 -1
- package/dist/chunks/{chunk-A6PSWTLX.js → chunk-4QTNXTGW.js} +1 -1
- package/dist/chunks/{chunk-ROQGMTFB.js → chunk-BEWLQADP.js} +6 -6
- package/dist/chunks/{chunk-BQ33OOLC.js → chunk-CDPYXHVR.js} +1 -1
- package/dist/chunks/{chunk-YS7VA5SI.js → chunk-DCJC32QW.js} +1 -1
- package/dist/chunks/{chunk-YGN4KL7W.js → chunk-E5UEYZWK.js} +1 -1
- package/dist/chunks/{chunk-IGJCTPFB.js → chunk-EMUUNWRU.js} +52 -43
- package/dist/chunks/{chunk-PIN7ZMTZ.js → chunk-EU6FBTQF.js} +4 -4
- package/dist/chunks/{chunk-WVBYR6Y7.js → chunk-FG762CCP.js} +3 -8
- package/dist/chunks/{chunk-73RSLGZT.js → chunk-FLFBYSJO.js} +1 -1
- package/dist/chunks/{chunk-IJRNMO4D.js → chunk-ICXMWYOA.js} +5 -5
- package/dist/chunks/{chunk-HOZI3FBG.js → chunk-IM4SJUPO.js} +12 -22
- package/dist/chunks/{chunk-6PYZYBBF.js → chunk-KAN2WTG5.js} +1 -1
- package/dist/chunks/{chunk-RK3MF4FD.js → chunk-KJYSOHVN.js} +1 -1
- package/dist/chunks/{chunk-F4BKWWLS.js → chunk-NP356MC2.js} +4 -4
- package/dist/chunks/{chunk-KJEMKHVB.js → chunk-OEPCRURR.js} +1 -1
- package/dist/chunks/{chunk-ZBLKAWSD.js → chunk-OOLNLCIO.js} +1 -1
- package/dist/chunks/chunk-OPPVSPEF.js +57 -0
- package/dist/chunks/{chunk-OA7RIMZ2.js → chunk-PSMKPSO4.js} +89 -22
- package/dist/chunks/chunk-Q6IOQP4J.js +292 -0
- package/dist/chunks/{chunk-LTUWJKHD.js → chunk-Q7LYHGGQ.js} +114 -6
- package/dist/chunks/{chunk-EE37PVQY.js → chunk-QIVPRZ4H.js} +12 -7
- package/dist/chunks/{chunk-J7YKQ5YW.js → chunk-QXAB2FLJ.js} +1 -1
- package/dist/chunks/chunk-RAEABQNW.js +227 -0
- package/dist/chunks/{chunk-EDASNMLY.js → chunk-REE4GUDM.js} +4 -4
- package/dist/chunks/{chunk-IZ3W5IU2.js → chunk-RJXPPYA7.js} +36 -36
- package/dist/chunks/{chunk-F5BYHLIN.js → chunk-VOWI544A.js} +1 -1
- package/dist/chunks/{chunk-P6O4RSOQ.js → chunk-VZNKA3K2.js} +5 -5
- package/dist/chunks/{chunk-FPTI3WAV.js → chunk-W4GZCVUK.js} +18 -13
- package/dist/chunks/{chunk-MECWJY2R.js → chunk-WI7ZHJ27.js} +5 -5
- package/dist/cli/figure.js +50 -48
- package/dist/cli/fold.js +8 -6
- package/dist/figure.js +31 -29
- package/dist/figureData.js +63 -0
- package/dist/figureSettings.js +9 -7
- package/dist/gbzCut.js +3 -2
- package/dist/gbzWindow.js +6 -1
- package/dist/gfa/gfaConverter.js +3 -2
- package/dist/gfa/graphTables.js +2 -1
- package/dist/index.js +173 -156
- package/dist/layout/forceCache.js +9 -7
- package/dist/layout/smoothChains.js +6 -0
- package/dist/layout/trimToWindow.js +17 -23
- package/dist/layout/tubeMapLayout.js +5 -4
- package/dist/layout/walkRowDraw.js +10 -9
- package/dist/layout/walkRowLayout.js +4 -3
- package/dist/layout/walkRows.js +3 -2
- package/dist/layout/walkStrip.js +11 -10
- package/dist/layoutModes.js +11 -10
- package/dist/pathAnchoring.js +2 -1
- package/dist/pathColors.js +4 -3
- package/dist/pathVisits.js +8 -0
- package/dist/pipeline.js +8 -6
- package/dist/referenceRampCss.js +8 -7
- package/dist/referenceStrip.js +8 -7
- package/dist/renderer/GeometryBuilder.js +7 -6
- package/dist/tubeMap/bundle.js +6 -5
- package/dist/tubeMap/coarsen.js +17 -15
- package/dist/tubeMap/draw.js +4 -3
- package/dist/tubeMap/nodeColors.js +8 -7
- package/dist/types/figureData.d.ts +146 -0
- package/dist/types/gbzWindow.d.ts +15 -1
- package/dist/types/gfa/gfaConverter.d.ts +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/layout/deletionRoutes.d.ts +1 -1
- package/dist/types/layout/smoothChains.d.ts +2 -0
- package/dist/types/pathAnchoring.d.ts +3 -2
- package/dist/types/pathVisits.d.ts +64 -0
- package/dist/types/types.d.ts +2 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport.js +9 -7
- package/dist/walkEncoding.js +8 -7
- package/dist/walkHighlight.js +9 -8
- 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-
|
|
4
|
-
import "../chunks/chunk-
|
|
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-
|
|
5
|
-
import "../chunks/chunk-
|
|
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-
|
|
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,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-
|
|
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,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
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
if (visits
|
|
54
|
-
|
|
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
|
-
|
|
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(
|
|
69
|
-
const sorted = [...new Set(
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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-
|
|
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-
|
|
3
|
+
} from "./chunk-IM4SJUPO.js";
|
|
4
4
|
import {
|
|
5
5
|
pathOrigin
|
|
6
|
-
} from "./chunk-
|
|
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
|
|
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
|
|
|
@@ -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-
|
|
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-
|
|
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-
|
|
9
|
+
} from "./chunk-REE4GUDM.js";
|
|
10
10
|
import {
|
|
11
11
|
pathOrigin
|
|
12
|
-
} from "./chunk-
|
|
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
|
|
26
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
212
|
-
|
|
200
|
+
pathVisits: graph.pathVisits?.filter(
|
|
201
|
+
() => true,
|
|
202
|
+
(segment) => !absorbedNames.has(segment)
|
|
213
203
|
)
|
|
214
204
|
};
|
|
215
205
|
}
|
|
@@ -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-
|
|
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";
|
|
@@ -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
|
+
};
|