@jbrowse/bandage-core 9.8.0 → 9.8.1

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.
@@ -4,6 +4,9 @@ import {
4
4
  import {
5
5
  readColor
6
6
  } from "./chunk-CWFNEKST.js";
7
+ import {
8
+ pathOrigin
9
+ } from "./chunk-ST2IBUAN.js";
7
10
 
8
11
  // src/tubeMap/draw.ts
9
12
  import { curvePaths, nodeOutlinePath } from "@jbrowse/tubemap-core";
@@ -53,9 +56,9 @@ function extentOf(commands) {
53
56
  }
54
57
  return { x0, x1 };
55
58
  }
56
- function shapeOf(d, color, id, haplotype) {
59
+ function shapeOf(d, color, id, haplotype, reference) {
57
60
  const commands = parsePath(d);
58
- return { commands, color, id, haplotype, ...extentOf(commands) };
61
+ return { commands, color, id, haplotype, reference, ...extentOf(commands) };
59
62
  }
60
63
  function trackColors(layout, pathColors) {
61
64
  return new Map(
@@ -65,30 +68,43 @@ function trackColors(layout, pathColors) {
65
68
  ])
66
69
  );
67
70
  }
68
- function layerOf(layout, type, colors) {
71
+ function layerOf(layout, type, colors, referenceIds) {
69
72
  const { shapes } = layout;
70
73
  const haplotype = type === "haplotype";
71
74
  const colorOf = (s) => colors.get(s.id);
75
+ const isReference = (s) => haplotype && referenceIds.has(s.id);
72
76
  const rects = [...shapes.rectangles, ...shapes.verticalRectangles].filter((r) => r.type === type).map((r) => ({
73
77
  color: colorOf(r),
74
78
  id: r.id,
75
79
  haplotype,
80
+ reference: isReference(r),
76
81
  x0: r.xStart,
77
82
  x1: r.xEnd + 1,
78
83
  y0: r.yStart,
79
84
  y1: r.yEnd + 1
80
85
  }));
81
86
  const curves = curvePaths(shapes.curves, type).map(
82
- (c) => shapeOf(c.path, colorOf(c), c.id, haplotype)
87
+ (c) => shapeOf(c.path, colorOf(c), c.id, haplotype, isReference(c))
83
88
  );
84
- const corners = shapes.corners.filter((c) => c.type === type).map((c) => shapeOf(c.path, colorOf(c), c.id, haplotype));
89
+ const corners = shapes.corners.filter((c) => c.type === type).map((c) => shapeOf(c.path, colorOf(c), c.id, haplotype, isReference(c)));
85
90
  return { rects, shapes: [...curves, ...corners] };
86
91
  }
92
+ function referenceTrackIds(graph) {
93
+ const ids = /* @__PURE__ */ new Set();
94
+ graph?.paths?.forEach((path, i) => {
95
+ if (pathOrigin(path.name).name === graph.referencePath) {
96
+ ids.add(i);
97
+ }
98
+ });
99
+ return ids;
100
+ }
87
101
  function tubeMapPicture({
88
102
  layout,
89
- pathColors
103
+ pathColors,
104
+ graph
90
105
  }) {
91
106
  const colors = trackColors(layout, pathColors);
107
+ const referenceIds = referenceTrackIds(graph);
92
108
  const nodes = [];
93
109
  layout.nodes.forEach((node) => {
94
110
  if (node.order >= 0) {
@@ -99,8 +115,8 @@ function tubeMapPicture({
99
115
  return {
100
116
  bounds: layout.bounds,
101
117
  layers: [
102
- layerOf(layout, "haplotype", colors),
103
- layerOf(layout, "read", colors)
118
+ layerOf(layout, "haplotype", colors, referenceIds),
119
+ layerOf(layout, "read", colors, referenceIds)
104
120
  ],
105
121
  nodes,
106
122
  mismatches: tubeMapMismatches(layout).filter(
@@ -181,14 +197,29 @@ function drawTubeMap(ctx, picture, frame) {
181
197
  const colorOf = (item) => item.haplotype && frame.tubeColors?.[item.id] || item.color;
182
198
  ctx.globalAlpha = 1;
183
199
  for (const layer of picture.layers) {
184
- fillByColor(ctx, layer.rects, visible, colorOf, (r) => {
185
- const left = x(r.x0);
186
- const top = y(r.y0);
187
- ctx.rect(left, top, x(r.x1) - left, y(r.y1) - top);
188
- });
189
- fillByColor(ctx, layer.shapes, visible, colorOf, (s) => {
190
- trace(ctx, s.commands, x, y);
191
- });
200
+ for (const reference of [false, true]) {
201
+ const inPass = (item) => item.reference === reference;
202
+ fillByColor(
203
+ ctx,
204
+ layer.rects,
205
+ (r) => inPass(r) && visible(r),
206
+ colorOf,
207
+ (r) => {
208
+ const left = x(r.x0);
209
+ const top = y(r.y0);
210
+ ctx.rect(left, top, x(r.x1) - left, y(r.y1) - top);
211
+ }
212
+ );
213
+ fillByColor(
214
+ ctx,
215
+ layer.shapes,
216
+ (s) => inPass(s) && visible(s),
217
+ colorOf,
218
+ (s) => {
219
+ trace(ctx, s.commands, x, y);
220
+ }
221
+ );
222
+ }
192
223
  }
193
224
  const stroke = frame.darkMode ? "#d0d0d0" : "#000000";
194
225
  const fill = frame.darkMode ? "rgba(40,40,40,0.4)" : "rgba(255,255,255,0.4)";
@@ -0,0 +1,77 @@
1
+ // src/tubeMap/warp.ts
2
+ var MAX_GAP_PX = 24;
3
+ var MAX_GAP_SHARE = 0.5;
4
+ var isReal = (c) => c.bp1 > c.bp0;
5
+ function referenceKnots(columns, bpToScreen) {
6
+ const real = columns.filter(isReal);
7
+ if (real.length === 0) {
8
+ const first = columns[0];
9
+ return first ? [{ tx: first.x0, sx: bpToScreen(first.bp0) }] : [];
10
+ }
11
+ const tx = [];
12
+ const target = [];
13
+ const gap = [];
14
+ real.forEach((c, i) => {
15
+ tx.push(c.x0, c.x1);
16
+ target.push(bpToScreen(c.bp0), bpToScreen(c.bp1));
17
+ gap.push(i === 0 ? 0 : Math.min(c.x0 - real[i - 1].x1, MAX_GAP_PX), 0);
18
+ });
19
+ const span = target.at(-1) - target[0];
20
+ const demand = gap.reduce((a, b) => a + b, 0);
21
+ const scale = demand > 0 ? Math.min(1, MAX_GAP_SHARE * span / demand) : 1;
22
+ return spread(target, gap, scale).map((sx, k) => ({ tx: tx[k], sx }));
23
+ }
24
+ function spread(target, gap, scale) {
25
+ const offset = [];
26
+ let sum = 0;
27
+ for (const g of gap) {
28
+ sum += g * scale;
29
+ offset.push(sum);
30
+ }
31
+ const blocks = [];
32
+ target.forEach((t, k) => {
33
+ let block = { mean: t - offset[k], n: 1 };
34
+ let last = blocks.at(-1);
35
+ while (last && last.mean >= block.mean) {
36
+ blocks.pop();
37
+ const n = last.n + block.n;
38
+ block = { mean: (last.mean * last.n + block.mean * block.n) / n, n };
39
+ last = blocks.at(-1);
40
+ }
41
+ blocks.push(block);
42
+ });
43
+ return blocks.flatMap((b) => Array(b.n).fill(b.mean)).map((q, k) => q + offset[k]);
44
+ }
45
+ function warpX(knots, tx) {
46
+ const n = knots.length;
47
+ if (n === 0) {
48
+ return tx;
49
+ }
50
+ const first = knots[0];
51
+ const last = knots[n - 1];
52
+ if (tx <= first.tx) {
53
+ return first.sx + (tx - first.tx);
54
+ }
55
+ if (tx >= last.tx) {
56
+ return last.sx + (tx - last.tx);
57
+ }
58
+ let lo = 0;
59
+ let hi = n - 1;
60
+ while (hi - lo > 1) {
61
+ const mid = lo + hi >> 1;
62
+ if (knots[mid].tx <= tx) {
63
+ lo = mid;
64
+ } else {
65
+ hi = mid;
66
+ }
67
+ }
68
+ const a = knots[lo];
69
+ const b = knots[hi];
70
+ const span = b.tx - a.tx;
71
+ return span > 0 ? a.sx + (tx - a.tx) / span * (b.sx - a.sx) : a.sx;
72
+ }
73
+
74
+ export {
75
+ referenceKnots,
76
+ warpX
77
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  referenceKnots,
3
3
  warpX
4
- } from "./chunk-KQFOCDFY.js";
4
+ } from "./chunk-IJYFJVIT.js";
5
5
 
6
6
  // src/tubeMap/frame.ts
7
7
  var MIN_TUBE_Y_SCALE = 0.05;
@@ -45,7 +45,7 @@ import {
45
45
  } from "./chunk-BOHK5BD3.js";
46
46
  import {
47
47
  version
48
- } from "./chunk-JEF73V3A.js";
48
+ } from "./chunk-YMMZUMYE.js";
49
49
  import {
50
50
  walkRowLabels,
51
51
  walkRowsExtent
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "9.8.0";
2
+ var version = "9.8.1";
3
3
 
4
4
  export {
5
5
  version
@@ -35,7 +35,7 @@ import "../chunks/chunk-LTUWJKHD.js";
35
35
  import "../chunks/chunk-WSIFAZU7.js";
36
36
  import {
37
37
  figureSvg
38
- } from "../chunks/chunk-CG77WIFD.js";
38
+ } from "../chunks/chunk-JRADQSGK.js";
39
39
  import "../chunks/chunk-QMJXHYVQ.js";
40
40
  import "../chunks/chunk-WBCOREDZ.js";
41
41
  import "../chunks/chunk-4BYTEJGW.js";
@@ -54,7 +54,7 @@ import "../chunks/chunk-2LQ5BWT7.js";
54
54
  import "../chunks/chunk-QG5IVMRS.js";
55
55
  import "../chunks/chunk-BOHK5BD3.js";
56
56
  import "../chunks/chunk-G2FD7S3C.js";
57
- import "../chunks/chunk-JEF73V3A.js";
57
+ import "../chunks/chunk-YMMZUMYE.js";
58
58
  import "../chunks/chunk-3C5UXR2U.js";
59
59
  import {
60
60
  filterSamples,
package/dist/figure.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  figureSvg
3
- } from "./chunks/chunk-CG77WIFD.js";
3
+ } from "./chunks/chunk-JRADQSGK.js";
4
4
  import "./chunks/chunk-QMJXHYVQ.js";
5
5
  import "./chunks/chunk-WBCOREDZ.js";
6
6
  import "./chunks/chunk-4BYTEJGW.js";
@@ -16,7 +16,7 @@ import "./chunks/chunk-2LQ5BWT7.js";
16
16
  import "./chunks/chunk-QG5IVMRS.js";
17
17
  import "./chunks/chunk-BOHK5BD3.js";
18
18
  import "./chunks/chunk-G2FD7S3C.js";
19
- import "./chunks/chunk-JEF73V3A.js";
19
+ import "./chunks/chunk-YMMZUMYE.js";
20
20
  import "./chunks/chunk-3C5UXR2U.js";
21
21
  import "./chunks/chunk-MAUEPAMG.js";
22
22
  import "./chunks/chunk-7GBL7SJY.js";
package/dist/index.js CHANGED
@@ -29,16 +29,16 @@ import {
29
29
  tubeMapMismatchAt,
30
30
  tubeMapPicture,
31
31
  tubeMapTrackAt
32
- } from "./chunks/chunk-75HR3756.js";
32
+ } from "./chunks/chunk-G3SZWUPA.js";
33
33
  import "./chunks/chunk-XXT2JCAC.js";
34
34
  import {
35
35
  tubeMapFrame,
36
36
  tubeMapNodeAt
37
- } from "./chunks/chunk-VZQ4FKLR.js";
37
+ } from "./chunks/chunk-JABM3MUS.js";
38
38
  import {
39
39
  referenceKnots,
40
40
  warpX
41
- } from "./chunks/chunk-KQFOCDFY.js";
41
+ } from "./chunks/chunk-IJYFJVIT.js";
42
42
  import {
43
43
  createForceLayoutCache
44
44
  } from "./chunks/chunk-BV64PQ2C.js";
@@ -122,7 +122,7 @@ import {
122
122
  } from "./chunks/chunk-AZFVORTC.js";
123
123
  import {
124
124
  figureSvg
125
- } from "./chunks/chunk-CG77WIFD.js";
125
+ } from "./chunks/chunk-JRADQSGK.js";
126
126
  import {
127
127
  WALK_STRIP_CEILING_PX,
128
128
  cutsWholeWalks,
@@ -222,7 +222,7 @@ import {
222
222
  import "./chunks/chunk-G2FD7S3C.js";
223
223
  import {
224
224
  version
225
- } from "./chunks/chunk-JEF73V3A.js";
225
+ } from "./chunks/chunk-YMMZUMYE.js";
226
226
  import {
227
227
  walkRowLabels,
228
228
  walkRowsExtent
@@ -8,10 +8,13 @@ import {
8
8
  tubeMapMismatchAt,
9
9
  tubeMapPicture,
10
10
  tubeMapTrackAt
11
- } from "../chunks/chunk-75HR3756.js";
11
+ } from "../chunks/chunk-G3SZWUPA.js";
12
12
  import "../chunks/chunk-XXT2JCAC.js";
13
13
  import "../chunks/chunk-CWFNEKST.js";
14
14
  import "../chunks/chunk-C44YRP5F.js";
15
+ import "../chunks/chunk-ST2IBUAN.js";
16
+ import "../chunks/chunk-BPLIXMH7.js";
17
+ import "../chunks/chunk-FYQWPEEY.js";
15
18
  export {
16
19
  drawTubeMap,
17
20
  drawTubeMapHighlight,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  tubeMapFrame,
3
3
  tubeMapNodeAt
4
- } from "../chunks/chunk-VZQ4FKLR.js";
5
- import "../chunks/chunk-KQFOCDFY.js";
4
+ } from "../chunks/chunk-JABM3MUS.js";
5
+ import "../chunks/chunk-IJYFJVIT.js";
6
6
  export {
7
7
  tubeMapFrame,
8
8
  tubeMapNodeAt
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  referenceKnots,
3
3
  warpX
4
- } from "../chunks/chunk-KQFOCDFY.js";
4
+ } from "../chunks/chunk-IJYFJVIT.js";
5
5
  export {
6
6
  referenceKnots,
7
7
  warpX
@@ -34,6 +34,7 @@ interface Filled {
34
34
  color: string;
35
35
  id: number;
36
36
  haplotype: boolean;
37
+ reference: boolean;
37
38
  x0: number;
38
39
  x1: number;
39
40
  }
@@ -60,7 +61,7 @@ export interface TubeMapPicture {
60
61
  mismatches: TubeMapMismatch[];
61
62
  }
62
63
  export declare function trackColors(layout: TubeMapLayout, pathColors: readonly string[]): ReadonlyMap<number, string>;
63
- export declare function tubeMapPicture({ layout, pathColors, }: Pick<TubeMapDrawing, 'layout' | 'pathColors'>): TubeMapPicture;
64
+ export declare function tubeMapPicture({ layout, pathColors, graph, }: Pick<TubeMapDrawing, 'layout' | 'pathColors'> & Partial<Pick<TubeMapDrawing, 'graph'>>): TubeMapPicture;
64
65
  export interface TubeMapFrame extends TubeMapTransform {
65
66
  width: number;
66
67
  highlightNode?: string | null;
@@ -1 +1 @@
1
- export declare const version = "9.8.0";
1
+ export declare const version = "9.8.1";
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  version
3
- } from "./chunks/chunk-JEF73V3A.js";
3
+ } from "./chunks/chunk-YMMZUMYE.js";
4
4
  export {
5
5
  version
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/bandage-core",
3
- "version": "9.8.0",
3
+ "version": "9.8.1",
4
4
  "description": "Pangenome graph layout and drawing with no host: GFA in, the Bandage force-directed engine and reference-anchored layouts, a Canvas2D renderer, hit testing and labels out",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -1,73 +0,0 @@
1
- // src/tubeMap/warp.ts
2
- var MAX_GAP_PX = 24;
3
- var isReal = (c) => c.bp1 > c.bp0;
4
- function referenceKnots(columns, bpToScreen) {
5
- const real = columns.filter(isReal);
6
- if (real.length === 0) {
7
- const first = columns[0];
8
- return first ? [{ tx: first.x0, sx: bpToScreen(first.bp0) }] : [];
9
- }
10
- const screen = real.map((c) => ({
11
- c,
12
- s0: bpToScreen(c.bp0),
13
- s1: bpToScreen(c.bp1),
14
- trimLeft: 0,
15
- trimRight: 0
16
- }));
17
- for (let i = 0; i + 1 < screen.length; i++) {
18
- const left = screen[i];
19
- const right = screen[i + 1];
20
- const demand = Math.min(right.c.x0 - left.c.x1, MAX_GAP_PX);
21
- const short = demand - (right.s0 - left.s1);
22
- if (short > 0) {
23
- const capLeft = (left.s1 - left.s0) / 2;
24
- const capRight = (right.s1 - right.s0) / 2;
25
- let fromLeft = Math.min(short / 2, capLeft);
26
- const fromRight = Math.min(short - fromLeft, capRight);
27
- fromLeft = Math.min(short - fromRight, capLeft);
28
- left.trimRight = fromLeft;
29
- right.trimLeft = fromRight;
30
- }
31
- }
32
- const knots = [];
33
- for (const { c, s0, s1, trimLeft, trimRight } of screen) {
34
- knots.push(
35
- { tx: c.x0, sx: s0 + trimLeft },
36
- { tx: c.x1, sx: s1 - trimRight }
37
- );
38
- }
39
- return knots;
40
- }
41
- function warpX(knots, tx) {
42
- const n = knots.length;
43
- if (n === 0) {
44
- return tx;
45
- }
46
- const first = knots[0];
47
- const last = knots[n - 1];
48
- if (tx <= first.tx) {
49
- return first.sx + (tx - first.tx);
50
- }
51
- if (tx >= last.tx) {
52
- return last.sx + (tx - last.tx);
53
- }
54
- let lo = 0;
55
- let hi = n - 1;
56
- while (hi - lo > 1) {
57
- const mid = lo + hi >> 1;
58
- if (knots[mid].tx <= tx) {
59
- lo = mid;
60
- } else {
61
- hi = mid;
62
- }
63
- }
64
- const a = knots[lo];
65
- const b = knots[hi];
66
- const span = b.tx - a.tx;
67
- return span > 0 ? a.sx + (tx - a.tx) / span * (b.sx - a.sx) : a.sx;
68
- }
69
-
70
- export {
71
- referenceKnots,
72
- warpX
73
- };