@jbrowse/bandage-core 8.2.0 → 9.1.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/dist/bubbles/bubbleHalos.js +9 -5
- package/dist/bubbles/bubbleLine.js +3 -1
- package/dist/bubbles/bubblesFromGraph.js +8 -4
- package/dist/bubbles/classifyBubble.js +2 -2
- package/dist/bubbles/superbubbles.js +21 -0
- package/dist/chunks/{chunk-ISEI2FH3.js → chunk-2AWUWGAD.js} +10 -4
- package/dist/chunks/{chunk-GQ2AOHU4.js → chunk-2ZT7ZF7A.js} +13 -31
- package/dist/chunks/{chunk-DE4UFDUZ.js → chunk-3TGUKQWQ.js} +4 -4
- package/dist/chunks/{chunk-KCRL5JB2.js → chunk-75HR3756.js} +55 -17
- package/dist/chunks/{chunk-DRA7733Q.js → chunk-BPRXQ2SS.js} +8 -3
- package/dist/chunks/{chunk-TEDQJPMI.js → chunk-CWFNEKST.js} +22 -7
- package/dist/chunks/chunk-FUVI4WQP.js +273 -0
- package/dist/chunks/{chunk-MFKORG3F.js → chunk-FX4RDMDN.js} +5 -1
- package/dist/chunks/{chunk-4S47XRYA.js → chunk-GOZYKNQ2.js} +16 -11
- package/dist/chunks/chunk-INJ2UVOT.js +370 -0
- package/dist/chunks/{chunk-TL4B342F.js → chunk-MXDQGA7A.js} +1 -1
- package/dist/chunks/{chunk-SKKYLBRA.js → chunk-RRZMMYBG.js} +1 -1
- package/dist/chunks/{chunk-3FXPFVKJ.js → chunk-UID3QBWH.js} +1 -1
- package/dist/chunks/{chunk-2WNBVB55.js → chunk-WBCOREDZ.js} +121 -74
- package/dist/chunks/{chunk-OWFPAIJI.js → chunk-WEDZ76AK.js} +1 -1
- package/dist/chunks/{chunk-CF62U3QS.js → chunk-WNUZP3WQ.js} +2 -2
- package/dist/chunks/{chunk-WOO7QYKB.js → chunk-XKWD2RY3.js} +8 -2
- package/dist/chunks/{chunk-6VBDMZBZ.js → chunk-XLCTQHBE.js} +1 -1
- package/dist/chunks/{chunk-733L2TS6.js → chunk-XXT2JCAC.js} +10 -7
- package/dist/cli/figure.js +9 -9
- package/dist/figure.js +6 -6
- package/dist/figureSettings.js +3 -3
- package/dist/index.js +45 -33
- package/dist/layout/forceCache.js +3 -3
- package/dist/layout/tubeMapLayout.js +12 -6
- package/dist/layoutModes.js +3 -3
- package/dist/pipeline.js +2 -2
- package/dist/renderer/Canvas2DRenderer.js +1 -1
- package/dist/renderer/recordingCanvas.js +12 -1
- package/dist/tubeMap/axis.js +1 -1
- package/dist/tubeMap/coarsen.js +11 -23
- package/dist/tubeMap/connectors.js +3 -4
- package/dist/tubeMap/deviations.js +15 -19
- package/dist/tubeMap/draw.js +11 -5
- package/dist/tubeMap/genes.js +2 -2
- package/dist/tubeMap/mismatches.js +1 -1
- package/dist/tubeMap/reads.js +1 -1
- package/dist/types/bubbles/bubbleHalos.d.ts +2 -0
- package/dist/types/bubbles/bubbleLine.d.ts +3 -0
- package/dist/types/bubbles/bubblesFromGraph.d.ts +12 -2
- package/dist/types/bubbles/superbubbles.d.ts +5 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/layout/tubeMapLayout.d.ts +15 -2
- package/dist/types/layoutModes.d.ts +5 -5
- package/dist/types/renderer/Canvas2DRenderer.d.ts +6 -3
- package/dist/types/tubeMap/axis.d.ts +6 -3
- package/dist/types/tubeMap/connectors.d.ts +3 -11
- package/dist/types/tubeMap/deviations.d.ts +2 -3
- package/dist/types/tubeMap/draw.d.ts +5 -1
- package/dist/types/tubeMap/mismatches.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport.js +3 -3
- package/package.json +1 -1
- package/dist/chunks/chunk-W2I4DOL4.js +0 -230
- package/dist/chunks/{chunk-5OIVTEF7.js → chunk-OOXIMURX.js} +3 -3
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
WHOLE_FRACTION,
|
|
3
|
+
bubbleHalos,
|
|
4
|
+
coversGraph
|
|
5
|
+
} from "../chunks/chunk-2AWUWGAD.js";
|
|
6
|
+
import "../chunks/chunk-XKWD2RY3.js";
|
|
7
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
6
8
|
import "../chunks/chunk-2CVHXFK7.js";
|
|
7
9
|
import "../chunks/chunk-CPMHA4W5.js";
|
|
8
10
|
import "../chunks/chunk-FYQWPEEY.js";
|
|
9
11
|
export {
|
|
10
|
-
|
|
12
|
+
WHOLE_FRACTION,
|
|
13
|
+
bubbleHalos,
|
|
14
|
+
coversGraph
|
|
11
15
|
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SATURATED_PATH_COUNT,
|
|
3
3
|
bubbleDescription,
|
|
4
|
+
bubbleKey,
|
|
4
5
|
bubbleLabel,
|
|
5
6
|
parseBubbleLine,
|
|
6
7
|
sameBubble
|
|
7
|
-
} from "../chunks/chunk-
|
|
8
|
+
} from "../chunks/chunk-FX4RDMDN.js";
|
|
8
9
|
export {
|
|
9
10
|
SATURATED_PATH_COUNT,
|
|
10
11
|
bubbleDescription,
|
|
12
|
+
bubbleKey,
|
|
11
13
|
bubbleLabel,
|
|
12
14
|
parseBubbleLine,
|
|
13
15
|
sameBubble
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
bubblesFromGraph
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
bubblesFromGraph,
|
|
3
|
+
walkIndexOf,
|
|
4
|
+
walkRoutes
|
|
5
|
+
} from "../chunks/chunk-GOZYKNQ2.js";
|
|
6
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
5
7
|
import "../chunks/chunk-HNQPEMYE.js";
|
|
6
8
|
import "../chunks/chunk-CPMHA4W5.js";
|
|
7
9
|
import "../chunks/chunk-FYQWPEEY.js";
|
|
8
10
|
export {
|
|
9
|
-
bubblesFromGraph
|
|
11
|
+
bubblesFromGraph,
|
|
12
|
+
walkIndexOf,
|
|
13
|
+
walkRoutes
|
|
10
14
|
};
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
bubbleSegmentIds,
|
|
5
5
|
classifyBubble,
|
|
6
6
|
formatBp
|
|
7
|
-
} from "../chunks/chunk-
|
|
8
|
-
import "../chunks/chunk-
|
|
7
|
+
} from "../chunks/chunk-XKWD2RY3.js";
|
|
8
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
9
9
|
export {
|
|
10
10
|
BUBBLE_KIND_COLORS,
|
|
11
11
|
BUBBLE_KIND_NAMES,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_SUPERBUBBLES,
|
|
3
|
+
graphBubbles,
|
|
4
|
+
superbubblesFromGraph
|
|
5
|
+
} from "../chunks/chunk-FUVI4WQP.js";
|
|
6
|
+
import "../chunks/chunk-VHW7FDHU.js";
|
|
7
|
+
import "../chunks/chunk-2AWUWGAD.js";
|
|
8
|
+
import "../chunks/chunk-GOZYKNQ2.js";
|
|
9
|
+
import "../chunks/chunk-XKWD2RY3.js";
|
|
10
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
11
|
+
import "../chunks/chunk-HNQPEMYE.js";
|
|
12
|
+
import "../chunks/chunk-ST2IBUAN.js";
|
|
13
|
+
import "../chunks/chunk-BPLIXMH7.js";
|
|
14
|
+
import "../chunks/chunk-2CVHXFK7.js";
|
|
15
|
+
import "../chunks/chunk-CPMHA4W5.js";
|
|
16
|
+
import "../chunks/chunk-FYQWPEEY.js";
|
|
17
|
+
export {
|
|
18
|
+
MAX_SUPERBUBBLES,
|
|
19
|
+
graphBubbles,
|
|
20
|
+
superbubblesFromGraph
|
|
21
|
+
};
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
bubbleSegmentIds,
|
|
3
3
|
classifyBubble,
|
|
4
4
|
formatBp
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XKWD2RY3.js";
|
|
6
6
|
import {
|
|
7
7
|
svgPath
|
|
8
8
|
} from "./chunk-2CVHXFK7.js";
|
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
|
|
13
13
|
// src/bubbles/bubbleHalos.ts
|
|
14
14
|
var WHOLE_FRACTION = 0.9;
|
|
15
|
+
function coversGraph(members, nodes) {
|
|
16
|
+
return members + 2 >= nodes || members >= WHOLE_FRACTION * nodes;
|
|
17
|
+
}
|
|
15
18
|
var NAMED_WALKS = 2;
|
|
16
19
|
var MIN_CHIPPED_BP = 1e3;
|
|
17
20
|
function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repeats = []) {
|
|
@@ -24,13 +27,14 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
|
|
|
24
27
|
let minY = Infinity;
|
|
25
28
|
const nodeIds = [];
|
|
26
29
|
const ends = [];
|
|
27
|
-
|
|
30
|
+
const names = bubbleSegmentIds(bubble);
|
|
31
|
+
for (const [i, name] of names.entries()) {
|
|
28
32
|
const node = byName.get(name);
|
|
29
33
|
const line = node && positions[node.id];
|
|
30
34
|
if (!node || !line?.length) {
|
|
31
35
|
continue;
|
|
32
36
|
}
|
|
33
|
-
if (isBackbone(node) && (node.stable.start < bubble.start || node.stable.start >= bubble.end)) {
|
|
37
|
+
if (bubble.key ? i === 0 || i === names.length - 1 : isBackbone(node) && (node.stable.start < bubble.start || node.stable.start >= bubble.end)) {
|
|
34
38
|
ends.push(line[Math.floor(line.length / 2)]);
|
|
35
39
|
continue;
|
|
36
40
|
}
|
|
@@ -90,7 +94,7 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
|
|
|
90
94
|
labelAt,
|
|
91
95
|
members: nodeIds.length,
|
|
92
96
|
nodeIds,
|
|
93
|
-
whole: nodeIds.length
|
|
97
|
+
whole: coversGraph(nodeIds.length, graph.nodes.length),
|
|
94
98
|
routes
|
|
95
99
|
});
|
|
96
100
|
}
|
|
@@ -104,5 +108,7 @@ function routeText(route, walkLabel) {
|
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
export {
|
|
111
|
+
WHOLE_FRACTION,
|
|
112
|
+
coversGraph,
|
|
107
113
|
bubbleHalos
|
|
108
114
|
};
|
|
@@ -1,35 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
isBackbone
|
|
3
|
-
} from "./chunk-FYQWPEEY.js";
|
|
4
|
-
|
|
5
1
|
// src/tubeMap/connectors.ts
|
|
6
|
-
function
|
|
7
|
-
const nodeById = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
8
|
-
const out = [];
|
|
9
|
-
layout.nodes.forEach((node) => {
|
|
10
|
-
const graphNode = nodeById.get(node.name);
|
|
11
|
-
if (node.order >= 0 && graphNode && isBackbone(graphNode)) {
|
|
12
|
-
out.push({
|
|
13
|
-
node: node.name,
|
|
14
|
-
bp0: graphNode.stable.start,
|
|
15
|
-
bp1: graphNode.stable.start + node.sequenceLength,
|
|
16
|
-
x0: node.x,
|
|
17
|
-
x1: node.x + node.pixelWidth
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
return out;
|
|
22
|
-
}
|
|
23
|
-
function tubeMapConnectors(nodes, bpToScreen, tubeToScreen, width) {
|
|
2
|
+
function tubeMapConnectors(boxes, bpToScreen, tubeToScreen, width) {
|
|
24
3
|
const out = [];
|
|
25
|
-
for (const
|
|
26
|
-
const bottom0 = tubeToScreen(
|
|
27
|
-
const bottom1 = tubeToScreen(
|
|
4
|
+
for (const box of boxes) {
|
|
5
|
+
const bottom0 = tubeToScreen(box.x0);
|
|
6
|
+
const bottom1 = tubeToScreen(box.x1);
|
|
28
7
|
if (bottom1 >= 0 && bottom0 <= width) {
|
|
29
8
|
out.push({
|
|
30
|
-
node:
|
|
31
|
-
top0: bpToScreen(
|
|
32
|
-
top1: bpToScreen(
|
|
9
|
+
node: box.name,
|
|
10
|
+
top0: bpToScreen(box.bp0),
|
|
11
|
+
top1: bpToScreen(box.bp1),
|
|
33
12
|
bottom0,
|
|
34
13
|
bottom1
|
|
35
14
|
});
|
|
@@ -90,7 +69,10 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
|
|
|
90
69
|
ctx.strokeStyle = `rgba(${ink},0.35)`;
|
|
91
70
|
ctx.lineWidth = 0.5;
|
|
92
71
|
ctx.stroke();
|
|
93
|
-
|
|
72
|
+
drawLitConnector(ctx, connectors, bottom, highlightNode);
|
|
73
|
+
}
|
|
74
|
+
function drawLitConnector(ctx, connectors, bottom, node) {
|
|
75
|
+
const lit = bottom > 0 && node ? connectors.find((c) => c.node === node) : void 0;
|
|
94
76
|
if (lit) {
|
|
95
77
|
ctx.beginPath();
|
|
96
78
|
band(ctx, lit, bottom);
|
|
@@ -105,8 +87,8 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
|
|
|
105
87
|
}
|
|
106
88
|
|
|
107
89
|
export {
|
|
108
|
-
referenceNodes,
|
|
109
90
|
tubeMapConnectors,
|
|
110
91
|
connectorAt,
|
|
111
|
-
drawTubeMapConnectors
|
|
92
|
+
drawTubeMapConnectors,
|
|
93
|
+
drawLitConnector
|
|
112
94
|
};
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./chunk-MIW3HYPE.js";
|
|
17
17
|
import {
|
|
18
18
|
Canvas2DRenderer
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-WBCOREDZ.js";
|
|
20
20
|
import {
|
|
21
21
|
EXON_COLOR,
|
|
22
22
|
exonOutlineTree,
|
|
@@ -42,10 +42,10 @@ import {
|
|
|
42
42
|
} from "./chunk-HBEKUQO4.js";
|
|
43
43
|
import {
|
|
44
44
|
version
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-UID3QBWH.js";
|
|
46
46
|
import {
|
|
47
47
|
axisScaleOf
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-MXDQGA7A.js";
|
|
49
49
|
import {
|
|
50
50
|
walkRowLabels,
|
|
51
51
|
walkRowsExtent
|
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
FIT_PADDING,
|
|
92
92
|
drawingBounds,
|
|
93
93
|
fitTransform
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-OOXIMURX.js";
|
|
95
95
|
import {
|
|
96
96
|
deletionDrawing,
|
|
97
97
|
deletionEdges
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
tubeMapMismatches
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XXT2JCAC.js";
|
|
4
4
|
import {
|
|
5
5
|
readColor
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CWFNEKST.js";
|
|
7
7
|
|
|
8
8
|
// src/tubeMap/draw.ts
|
|
9
9
|
import { curvePaths, nodeOutlinePath } from "@jbrowse/tubemap-core";
|
|
@@ -53,9 +53,9 @@ function extentOf(commands) {
|
|
|
53
53
|
}
|
|
54
54
|
return { x0, x1 };
|
|
55
55
|
}
|
|
56
|
-
function shapeOf(d, color,
|
|
56
|
+
function shapeOf(d, color, id, haplotype) {
|
|
57
57
|
const commands = parsePath(d);
|
|
58
|
-
return { commands, color,
|
|
58
|
+
return { commands, color, id, haplotype, ...extentOf(commands) };
|
|
59
59
|
}
|
|
60
60
|
function trackColors(layout, pathColors) {
|
|
61
61
|
return new Map(
|
|
@@ -67,20 +67,21 @@ function trackColors(layout, pathColors) {
|
|
|
67
67
|
}
|
|
68
68
|
function layerOf(layout, type, colors) {
|
|
69
69
|
const { shapes } = layout;
|
|
70
|
+
const haplotype = type === "haplotype";
|
|
70
71
|
const colorOf = (s) => colors.get(s.id);
|
|
71
|
-
const trackOf = (s) => type === "haplotype" ? s.id : void 0;
|
|
72
72
|
const rects = [...shapes.rectangles, ...shapes.verticalRectangles].filter((r) => r.type === type).map((r) => ({
|
|
73
73
|
color: colorOf(r),
|
|
74
|
-
|
|
74
|
+
id: r.id,
|
|
75
|
+
haplotype,
|
|
75
76
|
x0: r.xStart,
|
|
76
77
|
x1: r.xEnd + 1,
|
|
77
78
|
y0: r.yStart,
|
|
78
79
|
y1: r.yEnd + 1
|
|
79
80
|
}));
|
|
80
81
|
const curves = curvePaths(shapes.curves, type).map(
|
|
81
|
-
(c) => shapeOf(c.path, colorOf(c),
|
|
82
|
+
(c) => shapeOf(c.path, colorOf(c), c.id, haplotype)
|
|
82
83
|
);
|
|
83
|
-
const corners = shapes.corners.filter((c) => c.type === type).map((c) => shapeOf(c.path, colorOf(c),
|
|
84
|
+
const corners = shapes.corners.filter((c) => c.type === type).map((c) => shapeOf(c.path, colorOf(c), c.id, haplotype));
|
|
84
85
|
return { rects, shapes: [...curves, ...corners] };
|
|
85
86
|
}
|
|
86
87
|
function tubeMapPicture({
|
|
@@ -177,7 +178,7 @@ var NODE_TINT_ALPHA = 0.55;
|
|
|
177
178
|
function drawTubeMap(ctx, picture, frame) {
|
|
178
179
|
const { x, y, width } = frame;
|
|
179
180
|
const visible = (item) => x(item.x1) >= 0 && x(item.x0) <= width;
|
|
180
|
-
const colorOf = (item) => item.
|
|
181
|
+
const colorOf = (item) => item.haplotype && frame.tubeColors?.[item.id] || item.color;
|
|
181
182
|
ctx.globalAlpha = 1;
|
|
182
183
|
for (const layer of picture.layers) {
|
|
183
184
|
fillByColor(ctx, layer.rects, visible, colorOf, (r) => {
|
|
@@ -191,24 +192,40 @@ function drawTubeMap(ctx, picture, frame) {
|
|
|
191
192
|
}
|
|
192
193
|
const stroke = frame.darkMode ? "#d0d0d0" : "#000000";
|
|
193
194
|
const fill = frame.darkMode ? "rgba(40,40,40,0.4)" : "rgba(255,255,255,0.4)";
|
|
194
|
-
ctx.lineWidth =
|
|
195
|
+
ctx.lineWidth = outlineWidth(frame);
|
|
195
196
|
for (const node of picture.nodes) {
|
|
196
|
-
if (visible(node)) {
|
|
197
|
-
const lit = node.name === frame.highlightNode;
|
|
197
|
+
if (visible(node) && node.name !== frame.highlightNode) {
|
|
198
198
|
ctx.beginPath();
|
|
199
199
|
trace(ctx, node.commands, x, y);
|
|
200
|
-
const tint =
|
|
201
|
-
ctx.fillStyle =
|
|
202
|
-
ctx.strokeStyle =
|
|
200
|
+
const tint = frame.nodeColors?.get(node.name);
|
|
201
|
+
ctx.fillStyle = tint ?? fill;
|
|
202
|
+
ctx.strokeStyle = stroke;
|
|
203
203
|
ctx.globalAlpha = tint ? NODE_TINT_ALPHA : 1;
|
|
204
204
|
ctx.fill();
|
|
205
|
-
ctx.globalAlpha =
|
|
205
|
+
ctx.globalAlpha = outlineAlpha(x(node.x1) - x(node.x0));
|
|
206
206
|
ctx.stroke();
|
|
207
207
|
ctx.globalAlpha = 1;
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
+
drawTubeMapHighlight(ctx, picture, frame);
|
|
210
211
|
drawMismatches(ctx, picture.mismatches, frame);
|
|
211
212
|
}
|
|
213
|
+
function outlineWidth(frame) {
|
|
214
|
+
return 2 * Math.max(0.25, Math.min(1, frame.yScale));
|
|
215
|
+
}
|
|
216
|
+
function drawTubeMapHighlight(ctx, picture, frame) {
|
|
217
|
+
const node = frame.highlightNode ? picture.nodes.find((n) => n.name === frame.highlightNode) : void 0;
|
|
218
|
+
if (node) {
|
|
219
|
+
ctx.beginPath();
|
|
220
|
+
trace(ctx, node.commands, frame.x, frame.y);
|
|
221
|
+
ctx.globalAlpha = 1;
|
|
222
|
+
ctx.lineWidth = outlineWidth(frame);
|
|
223
|
+
ctx.fillStyle = "rgba(255,192,203,0.5)";
|
|
224
|
+
ctx.strokeStyle = "#ff0000";
|
|
225
|
+
ctx.fill();
|
|
226
|
+
ctx.stroke();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
212
229
|
var MISMATCH_FONT_PX = 12;
|
|
213
230
|
var MIN_MISMATCH_FONT_PX = 6;
|
|
214
231
|
function mismatchesLegible(yScale) {
|
|
@@ -235,6 +252,7 @@ function drawMismatches(ctx, marks, frame) {
|
|
|
235
252
|
}
|
|
236
253
|
ctx.fill();
|
|
237
254
|
ctx.font = `${fontPx}px monospace`;
|
|
255
|
+
ctx.textAlign = "left";
|
|
238
256
|
ctx.textBaseline = "alphabetic";
|
|
239
257
|
ctx.fillStyle = darkMode ? "#ffffff" : "#000000";
|
|
240
258
|
for (const m of marks) {
|
|
@@ -248,12 +266,32 @@ function drawMismatches(ctx, marks, frame) {
|
|
|
248
266
|
}
|
|
249
267
|
}
|
|
250
268
|
}
|
|
269
|
+
function tubeMapTrackAt(picture, { x, y }, sx, sy) {
|
|
270
|
+
for (let l = picture.layers.length - 1; l >= 0; l--) {
|
|
271
|
+
for (const r of picture.layers[l].rects) {
|
|
272
|
+
if (x(r.x0) <= sx && sx <= x(r.x1) && y(r.y0) <= sy && sy <= y(r.y1)) {
|
|
273
|
+
return r.id;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
var INSERTION_SLOP_PX = 4;
|
|
280
|
+
function tubeMapMismatchAt(picture, frame, sx, sy) {
|
|
281
|
+
const { x, y, yScale } = frame;
|
|
282
|
+
return mismatchesLegible(yScale) ? picture.mismatches.find(
|
|
283
|
+
(m) => y(m.y) <= sy && sy <= y(m.y + m.height) && (m.kind === "insertion" ? Math.abs(x(m.x) - sx) <= INSERTION_SLOP_PX : x(m.x0) <= sx && sx <= x(m.x1))
|
|
284
|
+
) : void 0;
|
|
285
|
+
}
|
|
251
286
|
|
|
252
287
|
export {
|
|
253
288
|
parsePath,
|
|
254
289
|
trackColors,
|
|
255
290
|
tubeMapPicture,
|
|
256
291
|
drawTubeMap,
|
|
292
|
+
drawTubeMapHighlight,
|
|
257
293
|
mismatchesLegible,
|
|
258
|
-
mismatchOnScreen
|
|
294
|
+
mismatchOnScreen,
|
|
295
|
+
tubeMapTrackAt,
|
|
296
|
+
tubeMapMismatchAt
|
|
259
297
|
};
|
|
@@ -6,17 +6,22 @@ import {
|
|
|
6
6
|
} from "./chunk-FYQWPEEY.js";
|
|
7
7
|
|
|
8
8
|
// src/tubeMap/axis.ts
|
|
9
|
-
function referenceBoxes(
|
|
9
|
+
function referenceBoxes({
|
|
10
|
+
graph,
|
|
11
|
+
layout
|
|
12
|
+
}) {
|
|
10
13
|
const nodeById = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
11
14
|
const byRefName = /* @__PURE__ */ new Map();
|
|
12
|
-
layout.nodes.forEach((node) => {
|
|
15
|
+
layout.nodes.forEach((node, index) => {
|
|
13
16
|
const graphNode = nodeById.get(node.name);
|
|
14
17
|
if (node.order >= 0 && graphNode && isBackbone(graphNode)) {
|
|
15
18
|
const { refName, start } = graphNode.stable;
|
|
16
19
|
const boxes = byRefName.get(refName) ?? byRefName.set(refName, []).get(refName);
|
|
17
20
|
boxes.push({
|
|
21
|
+
name: node.name,
|
|
22
|
+
index,
|
|
18
23
|
bp0: start,
|
|
19
|
-
bp1: start +
|
|
24
|
+
bp1: start + graphNode.length,
|
|
20
25
|
x0: node.x,
|
|
21
26
|
x1: node.x + node.pixelWidth
|
|
22
27
|
});
|
|
@@ -30,16 +30,30 @@ function mismatchesByStep(record, lengths) {
|
|
|
30
30
|
return byStep;
|
|
31
31
|
}
|
|
32
32
|
const starts = stepStarts(lengths, record.pathLength);
|
|
33
|
+
const known = starts.flatMap((start, s) => start === void 0 ? [] : [s]);
|
|
34
|
+
const startOf = (k) => starts[known[k]];
|
|
35
|
+
const endOf = (k) => startOf(k) + lengths[known[k]];
|
|
36
|
+
let first = 0;
|
|
33
37
|
const stepAt = (pos2, atEnd = false) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
while (first < known.length && endOf(first) < pos2) {
|
|
39
|
+
first++;
|
|
40
|
+
}
|
|
41
|
+
for (let k = first; k < known.length && startOf(k) <= pos2; k++) {
|
|
42
|
+
const end = endOf(k);
|
|
43
|
+
if (pos2 < end || atEnd && pos2 === end) {
|
|
44
|
+
return { s: known[k], local: pos2 - startOf(k), room: end - pos2 };
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
return void 0;
|
|
42
48
|
};
|
|
49
|
+
const unplacedFrom = (pos2) => {
|
|
50
|
+
for (let k = first; k < known.length; k++) {
|
|
51
|
+
if (startOf(k) > pos2) {
|
|
52
|
+
return startOf(k) - pos2;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return Infinity;
|
|
56
|
+
};
|
|
43
57
|
const add = (s, mismatch) => {
|
|
44
58
|
const list = byStep[s];
|
|
45
59
|
const last = list.at(-1);
|
|
@@ -68,7 +82,7 @@ function mismatchesByStep(record, lengths) {
|
|
|
68
82
|
let left = op.length;
|
|
69
83
|
while (left > 0) {
|
|
70
84
|
const at = stepAt(pos);
|
|
71
|
-
const take =
|
|
85
|
+
const take = Math.min(left, at ? at.room : unplacedFrom(pos));
|
|
72
86
|
if (at) {
|
|
73
87
|
add(at.s, { type: "deletion", pos: at.local, length: take });
|
|
74
88
|
}
|
|
@@ -106,7 +120,8 @@ function tubeMapReads(graph, records, firstId) {
|
|
|
106
120
|
})),
|
|
107
121
|
firstNodeOffset: first === 0 ? record.pathStart : 0,
|
|
108
122
|
finalNodeCoverLength: last === record.path.length - 1 ? lastLength - (record.pathLength - record.pathEnd) : lastLength,
|
|
109
|
-
|
|
123
|
+
// 255 is GAF's missing MAPQ
|
|
124
|
+
mapping_quality: record.mappingQuality === 255 ? void 0 : record.mappingQuality,
|
|
110
125
|
is_secondary: record.secondary,
|
|
111
126
|
is_reverse: record.strand === "-"
|
|
112
127
|
});
|