@jbrowse/bandage-core 0.1.14 → 0.1.16

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/index.js CHANGED
@@ -2147,6 +2147,7 @@ var LAYOUT_MODES = [
2147
2147
  description: "x is reference bp, one row per stable rank. Needs rGFA tags or a reference path.",
2148
2148
  run: anchoredLayout,
2149
2149
  cutMargins: true,
2150
+ wholeWalks: false,
2150
2151
  available: hasBackbone,
2151
2152
  drawsLocally: hasBackbone
2152
2153
  },
@@ -2156,6 +2157,7 @@ var LAYOUT_MODES = [
2156
2157
  description: "x is reference bp, one row per contributing assembly. Needs rGFA tags or a reference path.",
2157
2158
  run: sampleRowLayout,
2158
2159
  cutMargins: true,
2160
+ wholeWalks: false,
2159
2161
  available: hasAlleles,
2160
2162
  drawsLocally: hasAlleles
2161
2163
  },
@@ -2165,6 +2167,7 @@ var LAYOUT_MODES = [
2165
2167
  description: "x is each walk's own bp: one bar per haplotype, sequence the reference also carries in blue and sequence it does not in purple, so a repeat expansion reads as bar length. Needs W or P lines.",
2166
2168
  run: walkRowLayout,
2167
2169
  cutMargins: false,
2170
+ wholeWalks: true,
2168
2171
  available: hasWalks,
2169
2172
  drawsLocally: hasWalks
2170
2173
  },
@@ -2174,6 +2177,7 @@ var LAYOUT_MODES = [
2174
2177
  description: "x is reference order, not bp: every node gets room, bubbles read as lenses. Needs rGFA tags or a reference path.",
2175
2178
  run: orderedLayout,
2176
2179
  cutMargins: false,
2180
+ wholeWalks: false,
2177
2181
  available: hasBackbone,
2178
2182
  drawsLocally: hasBackbone
2179
2183
  },
@@ -2183,6 +2187,7 @@ var LAYOUT_MODES = [
2183
2187
  description: "sequenceTubeMap: every path a coloured tube through boxed nodes, columns in node order and node widths log-scaled. Needs P or W lines.",
2184
2188
  run: tubeMapLayout,
2185
2189
  cutMargins: false,
2190
+ wholeWalks: false,
2186
2191
  available: hasTubeMapPaths,
2187
2192
  drawsLocally: hasTubeMapPaths
2188
2193
  },
@@ -2192,6 +2197,7 @@ var LAYOUT_MODES = [
2192
2197
  description: "The tube map with each column at the reference bp it covers, so the tubes line up with the tracks around them. Needs P or W lines and a reference path.",
2193
2198
  run: tubeMapReferenceLayout,
2194
2199
  cutMargins: true,
2200
+ wholeWalks: false,
2195
2201
  available: hasTubeMapBackbone,
2196
2202
  drawsLocally: hasTubeMapBackbone
2197
2203
  },
@@ -2201,6 +2207,7 @@ var LAYOUT_MODES = [
2201
2207
  description: "OGDF FMMM, via the external Bandage engine.",
2202
2208
  run: () => void 0,
2203
2209
  cutMargins: false,
2210
+ wholeWalks: false,
2204
2211
  available: () => true,
2205
2212
  drawsLocally: () => false
2206
2213
  }
@@ -2848,11 +2855,10 @@ var EDGE_DEFAULT_COLOR = packAbgr2(119, 119, 119, 217);
2848
2855
  var EDGE_PATH_FALLBACK_COLOR = packAbgr2(136, 136, 136, 217);
2849
2856
  var EDGE_DELETION_COLOR = packAbgr2(24, 24, 28, 240);
2850
2857
  var DELETION_THICKNESS_FACTOR = 2.2;
2851
- var EDGE_WALK_COLOR = packAbgr2(30, 30, 36, 245);
2852
- var WALK_EDGE_THICKNESS_FACTOR = 1.8;
2853
2858
  var FADED_ALPHA = 0.18;
2854
2859
  var DELETION_DASH_PX = 11;
2855
2860
  var MIN_PATH_STRIPE_PX = 1.2;
2861
+ var MIN_WALK_LANE_PX = 3;
2856
2862
  var MIN_SCALE_FOR_OFFSET = 1e-6;
2857
2863
  var ARROW_LENGTH_BASE_PX = 7;
2858
2864
  var ARROW_LENGTH_PER_EDGE_PX = 3;
@@ -3341,10 +3347,10 @@ function buildGeometry(options) {
3341
3347
  const bypassed = deletions?.get(ei);
3342
3348
  const isDeletion = bypassed !== void 0;
3343
3349
  const onWalk = highlight?.edgeIndexes.has(ei) ?? false;
3344
- const edgeThickness = connectorThickness / 2 * (isDeletion ? DELETION_THICKNESS_FACTOR : 1) * (onWalk ? WALK_EDGE_THICKNESS_FACTOR : 1);
3350
+ const edgeThickness = connectorThickness / 2 * (isDeletion ? DELETION_THICKNESS_FACTOR : 1);
3345
3351
  const ribbons = drawPaths && numPaths > 0;
3346
3352
  const plainEdgeColor = isDeletion ? EDGE_DELETION_COLOR : EDGE_DEFAULT_COLOR;
3347
- const edgeColor = !highlight ? plainEdgeColor : onWalk ? EDGE_WALK_COLOR : fadeAbgr(plainEdgeColor, FADED_ALPHA);
3353
+ const edgeColor = !highlight || onWalk ? plainEdgeColor : fadeAbgr(plainEdgeColor, FADED_ALPHA);
3348
3354
  const toNode = nodeById.get(edge.to);
3349
3355
  const intoHalfWidth = (toNode ? nodeWidthPx(toNode, contigThickness, nodeWidth2, depthNorm) : contigThickness) / 2;
3350
3356
  const buildSingleEdge = (offsetX, offsetY, color, arrowColor) => {
@@ -3375,7 +3381,33 @@ function buildGeometry(options) {
3375
3381
  };
3376
3382
  const edgeCurveStart = edgeCurves.length;
3377
3383
  const arrowStart = arrows.length;
3378
- if (!ribbons) {
3384
+ const laneWalks = highlight && onWalk && !ribbons ? highlight.walks : void 0;
3385
+ if (laneWalks) {
3386
+ const fromNode = nodeById.get(edge.from);
3387
+ const width = fromNode ? nodeWidthPx(fromNode, contigThickness, nodeWidth2, depthNorm) : contigThickness;
3388
+ const laneWidth = Math.max(width / laneWalks.length, MIN_WALK_LANE_PX);
3389
+ const normals = pointNormalsOf(fromSegments, yToX);
3390
+ const { nx, ny } = (edge.fromStrand === "-" ? normals[0] : normals.at(-1)) ?? {
3391
+ nx: 0,
3392
+ ny: 0
3393
+ };
3394
+ const worldPerScreenPx = 1 / Math.max(scale, MIN_SCALE_FOR_OFFSET);
3395
+ laneWalks.forEach((walk, lane) => {
3396
+ if (!walk.edgeIndexes.has(ei)) {
3397
+ return;
3398
+ }
3399
+ const offset = (lane - (laneWalks.length - 1) / 2) * laneWidth * worldPerScreenPx;
3400
+ const curves = offset === 0 ? baseCurves : translateCurves(baseCurves, nx * offset, ny * offset / yToX);
3401
+ if (viewportBounds && !isBezierInBounds(curves, viewportBounds)) {
3402
+ return;
3403
+ }
3404
+ edgeCurves.push({
3405
+ curves,
3406
+ thickness: laneWidth / 2,
3407
+ color: walk.colors.get(edge.from) ?? walk.colors.get(edge.to) ?? plainEdgeColor
3408
+ });
3409
+ });
3410
+ } else if (!ribbons) {
3379
3411
  buildSingleEdge(0, 0, edgeColor, edgeColor);
3380
3412
  } else {
3381
3413
  const offsets = pathRibbonOffsets(
@@ -3391,7 +3423,7 @@ function buildGeometry(options) {
3391
3423
  buildSingleEdge(
3392
3424
  offset.x,
3393
3425
  offset.y,
3394
- highlight && edge.pathIds[pathIdx] !== highlight.name ? fadeAbgr(ribbonColor, FADED_ALPHA) : ribbonColor,
3426
+ highlight && !highlight.names.has(edge.pathIds[pathIdx]) ? fadeAbgr(ribbonColor, FADED_ALPHA) : ribbonColor,
3395
3427
  pathIdx === arrowRibbon ? edgeColor : void 0
3396
3428
  );
3397
3429
  }
@@ -3427,7 +3459,24 @@ function buildGeometry(options) {
3427
3459
  const slots = nodePathSlots.get(nodeId);
3428
3460
  const slotWidth = width / pathCount;
3429
3461
  const drawable = segments.length >= 2;
3430
- if (drawable && slots?.length && slotWidth >= MIN_PATH_STRIPE_PX) {
3462
+ const lanes = highlight && !faded && !slots?.length ? highlight.walks : void 0;
3463
+ if (drawable && lanes) {
3464
+ const laneWidth = Math.max(width / lanes.length, MIN_WALK_LANE_PX);
3465
+ const normals = pointNormalsOf(segments, yToX);
3466
+ const worldPerScreenPx = 1 / Math.max(scale, MIN_SCALE_FOR_OFFSET);
3467
+ lanes.forEach((walk, lane) => {
3468
+ const laneColor = walk.colors.get(nodeId);
3469
+ if (laneColor === void 0) {
3470
+ return;
3471
+ }
3472
+ const offset = (lane - (lanes.length - 1) / 2) * laneWidth * worldPerScreenPx;
3473
+ nodeStrokes.push({
3474
+ points: lanes.length === 1 ? segments : offsetPolyline(segments, normals, offset, yToX),
3475
+ thickness: laneWidth / 2,
3476
+ color: laneColor
3477
+ });
3478
+ });
3479
+ } else if (drawable && slots?.length && slotWidth >= MIN_PATH_STRIPE_PX) {
3431
3480
  const normals = pointNormalsOf(segments, yToX);
3432
3481
  const worldPerScreenPx = 1 / Math.max(scale, MIN_SCALE_FOR_OFFSET);
3433
3482
  for (const slot of slots) {
@@ -5191,7 +5240,99 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
5191
5240
  }
5192
5241
  }
5193
5242
 
5243
+ // src/walkEncoding.ts
5244
+ import { packAbgr as packAbgr3 } from "@jbrowse/core/util/colorBits";
5245
+ var WALK_FIELDS = [
5246
+ {
5247
+ value: "progress",
5248
+ label: "Progress along the walk",
5249
+ legend: "pale where the walk starts, deep where it ends"
5250
+ },
5251
+ {
5252
+ value: "reference",
5253
+ label: "Reference position",
5254
+ legend: "along the reference left to right, charcoal off it"
5255
+ },
5256
+ {
5257
+ value: "strand",
5258
+ label: "Strand against the reference",
5259
+ legend: "pale where the walk runs as the reference does, deep where reversed"
5260
+ },
5261
+ {
5262
+ value: "visits",
5263
+ label: "Visits",
5264
+ legend: "pale where the walk passes once, deep four times or more"
5265
+ }
5266
+ ];
5267
+ var WALK_SCHEMES = [
5268
+ { value: "rainbow", label: "Rainbow" },
5269
+ { value: "blues", label: "Blues", hue: 215 },
5270
+ { value: "reds", label: "Reds", hue: 0 },
5271
+ { value: "greens", label: "Greens", hue: 130 },
5272
+ { value: "oranges", label: "Oranges", hue: 30 },
5273
+ { value: "purples", label: "Purples", hue: 280 },
5274
+ { value: "greys", label: "Greys" }
5275
+ ];
5276
+ var DEFAULT_FAMILIES = [
5277
+ "blues",
5278
+ "reds",
5279
+ "greens",
5280
+ "oranges",
5281
+ "purples"
5282
+ ];
5283
+ function resolveEncoding(layer, reference, picked) {
5284
+ return {
5285
+ field: layer.color?.field ?? (reference ? "reference" : "progress"),
5286
+ scheme: layer.color?.scheme ?? (reference ? "rainbow" : DEFAULT_FAMILIES[picked % DEFAULT_FAMILIES.length])
5287
+ };
5288
+ }
5289
+ var PALE = 0.82;
5290
+ var DEEP = 0.28;
5291
+ function schemeHsl(scheme, t) {
5292
+ const x = Math.max(0, Math.min(1, t));
5293
+ if (scheme === "rainbow") {
5294
+ return { h: x * REFERENCE_RAMP_MAX_HUE, s: 0.7, l: 0.5 };
5295
+ }
5296
+ const family = WALK_SCHEMES.find((s) => s.value === scheme);
5297
+ const l = PALE + (DEEP - PALE) * x;
5298
+ return family && "hue" in family ? { h: family.hue, s: 0.75, l } : { h: 0, s: 0, l };
5299
+ }
5300
+ function schemeCss(scheme, t) {
5301
+ const { h, s, l } = schemeHsl(scheme, t);
5302
+ return `hsl(${h}, ${s * 100}%, ${l * 100}%)`;
5303
+ }
5304
+ function schemeColor(scheme, t) {
5305
+ const { h, s, l } = schemeHsl(scheme, t);
5306
+ const [r, g, b] = hslToRgb(h, s, l);
5307
+ return packAbgr3(
5308
+ Math.round(r * 255),
5309
+ Math.round(g * 255),
5310
+ Math.round(b * 255),
5311
+ 255
5312
+ );
5313
+ }
5314
+ var NO_VALUE_COLOR = REFERENCE_RAMP_ALT_COLOR;
5315
+ var STRAND_T = { same: 0.2, reversed: 0.95 };
5316
+ function encodingSwatchCss({ field, scheme }) {
5317
+ if (field === "strand") {
5318
+ const same = schemeCss(scheme, STRAND_T.same);
5319
+ const reversed = schemeCss(scheme, STRAND_T.reversed);
5320
+ return `linear-gradient(to right, ${same} 50%, ${reversed} 50%)`;
5321
+ }
5322
+ const stops = Array.from({ length: 7 }, (_, i) => {
5323
+ const t = i / 6;
5324
+ return `${schemeCss(scheme, t)} ${t * 100}%`;
5325
+ });
5326
+ return `linear-gradient(to right, ${stops.join(", ")})`;
5327
+ }
5328
+ function fieldLegend(field) {
5329
+ return WALK_FIELDS.find((f) => f.value === field).legend;
5330
+ }
5331
+
5194
5332
  // src/walkHighlight.ts
5333
+ function referenceOf(graph) {
5334
+ return graph.referencePath ? graph.paths?.find((p) => pathOrigin(p.name).name === graph.referencePath) : void 0;
5335
+ }
5195
5336
  function walkHighlight(graph, name) {
5196
5337
  const path = graph.paths?.find((p) => p.name === name);
5197
5338
  if (!path) {
@@ -5202,7 +5343,6 @@ function walkHighlight(graph, name) {
5202
5343
  graph.edges.forEach((e, i) => {
5203
5344
  edgeAt.set(`${e.from}>${e.to}`, i);
5204
5345
  });
5205
- const nodeIds = new Set(path.nodeIds);
5206
5346
  const edgeIndexes = /* @__PURE__ */ new Set();
5207
5347
  for (let i = 1; i < path.nodeIds.length; i++) {
5208
5348
  const a = path.nodeIds[i - 1];
@@ -5212,15 +5352,87 @@ function walkHighlight(graph, name) {
5212
5352
  edgeIndexes.add(index);
5213
5353
  }
5214
5354
  }
5215
- const bpOf = (ids) => ids.reduce((sum, id) => sum + (byId.get(id)?.length ?? 0), 0);
5216
- const reference = graph.referencePath ? graph.paths.find((p) => pathOrigin(p.name).name === graph.referencePath) : void 0;
5355
+ const lengthOf = (id) => byId.get(id)?.length ?? 0;
5356
+ const bp = path.nodeIds.reduce((sum, id) => sum + lengthOf(id), 0);
5357
+ const progress = /* @__PURE__ */ new Map();
5358
+ let before = 0;
5359
+ for (const id of path.nodeIds) {
5360
+ const length = lengthOf(id);
5361
+ if (!progress.has(id)) {
5362
+ progress.set(id, bp > 0 ? (before + length / 2) / bp : 0);
5363
+ }
5364
+ before += length;
5365
+ }
5366
+ const reference = referenceOf(graph);
5217
5367
  return {
5218
5368
  name,
5219
- nodeIds,
5369
+ reference: reference === path,
5370
+ nodeIds: new Set(path.nodeIds),
5220
5371
  edgeIndexes,
5372
+ progress,
5221
5373
  steps: path.nodeIds.length,
5222
- bp: bpOf(path.nodeIds),
5223
- referenceBp: reference && reference !== path ? bpOf(reference.nodeIds) : void 0
5374
+ bp,
5375
+ referenceBp: reference && reference !== path ? reference.nodeIds.reduce((sum, id) => sum + lengthOf(id), 0) : void 0
5376
+ };
5377
+ }
5378
+ function laneColors(graph, walk, { field, scheme }, ramp) {
5379
+ const colors = /* @__PURE__ */ new Map();
5380
+ const byId = new Map(graph.nodes.map((n) => [n.id, n]));
5381
+ const walkPath = pathOrigin(walk.name).name;
5382
+ const reference = referenceOf(graph);
5383
+ const referencePath = reference ? pathOrigin(reference.name).name : void 0;
5384
+ const path = graph.paths.find((p) => p.name === walk.name);
5385
+ const visits = /* @__PURE__ */ new Map();
5386
+ for (const id of path.nodeIds) {
5387
+ visits.set(id, (visits.get(id) ?? 0) + 1);
5388
+ }
5389
+ const strandOf = (segment, of) => graph.pathVisits?.get(segment)?.find((v) => v.path === of)?.strand;
5390
+ for (const [id, progress] of walk.progress) {
5391
+ const node = byId.get(id);
5392
+ let t;
5393
+ if (field === "progress") {
5394
+ t = progress;
5395
+ } else if (field === "visits") {
5396
+ t = (Math.min(visits.get(id) ?? 1, 4) - 1) / 3;
5397
+ } else if (field === "reference") {
5398
+ const mid = ramp?.midpoints.get(id);
5399
+ t = ramp && mid !== void 0 && !(node?.stable && node.stable.rank > 0) ? (mid - ramp.start) / ramp.span : void 0;
5400
+ } else if (node) {
5401
+ const own = strandOf(node.name, walkPath);
5402
+ const theirs = strandOf(node.name, referencePath);
5403
+ t = own && theirs ? own === theirs ? STRAND_T.same : STRAND_T.reversed : void 0;
5404
+ }
5405
+ colors.set(id, t === void 0 ? NO_VALUE_COLOR : schemeColor(scheme, t));
5406
+ }
5407
+ return colors;
5408
+ }
5409
+ function walkLift(graph, layers, ramp) {
5410
+ const seen = /* @__PURE__ */ new Set();
5411
+ const lifted = layers.filter((layer) => !seen.has(layer.walk) && seen.add(layer.walk)).flatMap((layer) => {
5412
+ const walk = walkHighlight(graph, layer.walk);
5413
+ return walk ? [{ walk, layer }] : [];
5414
+ }).sort((a, b) => Number(b.walk.reference) - Number(a.walk.reference));
5415
+ if (lifted.length === 0) {
5416
+ return void 0;
5417
+ }
5418
+ let picked = 0;
5419
+ const walks = lifted.map(({ walk, layer }) => {
5420
+ const encoding = resolveEncoding(
5421
+ layer,
5422
+ walk.reference,
5423
+ walk.reference ? 0 : picked++
5424
+ );
5425
+ return {
5426
+ ...walk,
5427
+ encoding,
5428
+ colors: laneColors(graph, walk, encoding, ramp)
5429
+ };
5430
+ });
5431
+ return {
5432
+ walks,
5433
+ nodeIds: new Set(walks.flatMap((w) => [...w.nodeIds])),
5434
+ edgeIndexes: new Set(walks.flatMap((w) => [...w.edgeIndexes])),
5435
+ names: new Set(walks.map((w) => w.name))
5224
5436
  };
5225
5437
  }
5226
5438
 
@@ -6053,6 +6265,8 @@ export {
6053
6265
  REFERENCE_RAMP_MAX_HUE,
6054
6266
  REFERENCE_STRIP_ZONE_PX,
6055
6267
  ROW_HEIGHT_PX,
6268
+ WALK_FIELDS,
6269
+ WALK_SCHEMES,
6056
6270
  WELL_KNOWN_SAMPLES,
6057
6271
  assemblyWalk,
6058
6272
  axisScaleOf,
@@ -6075,9 +6289,11 @@ export {
6075
6289
  drawTubeMapGenes,
6076
6290
  drawTubeMapRuler,
6077
6291
  drawingBounds,
6292
+ encodingSwatchCss,
6078
6293
  engineKey,
6079
6294
  engineRequest,
6080
6295
  featuresOnBackbone,
6296
+ fieldLegend,
6081
6297
  findHoveredEdge,
6082
6298
  findHoveredNode,
6083
6299
  fitTransform,
@@ -6111,8 +6327,10 @@ export {
6111
6327
  referenceSamplesOf,
6112
6328
  referenceStripBlocks,
6113
6329
  resolveColorScheme,
6330
+ resolveEncoding,
6114
6331
  resolveReferenceSample,
6115
6332
  rulerBoxes,
6333
+ schemeCss,
6116
6334
  screenToLayout,
6117
6335
  stripBlockAt,
6118
6336
  tubeMapConnectors,
@@ -6123,6 +6341,7 @@ export {
6123
6341
  tubeX,
6124
6342
  viewportOf,
6125
6343
  walkHighlight,
6344
+ walkLift,
6126
6345
  walkRows,
6127
6346
  walkRowsExtent,
6128
6347
  warpX,
@@ -32,7 +32,10 @@ export type { Connector, ReferenceNode } from './tubeMap/connectors.js';
32
32
  export type { TubeMapColumn, TubeMapDrawing } from './layout/tubeMapLayout.js';
33
33
  export { deletionEdges } from './deletionEdges.js';
34
34
  export type { DeletionEdge } from './deletionEdges.js';
35
- export { walkHighlight } from './walkHighlight.js';
35
+ export { walkHighlight, walkLift } from './walkHighlight.js';
36
+ export type { LiftedWalk, WalkLift } from './walkHighlight.js';
37
+ export { WALK_FIELDS, WALK_SCHEMES, encodingSwatchCss, fieldLegend, resolveEncoding, schemeCss, } from './walkEncoding.js';
38
+ export type { WalkEncoding, WalkField, WalkLayer, WalkScheme, } from './walkEncoding.js';
36
39
  export { pathColorsLegible, pathLegend } from './pathColors.js';
37
40
  export { bubblesFromGraph } from './bubbles/bubblesFromGraph.js';
38
41
  export { bubbleHalos } from './bubbles/bubbleHalos.js';
@@ -15,6 +15,7 @@ export interface LayoutMode {
15
15
  }, keepRows?: readonly string[]) => LayoutResult | undefined;
16
16
  available: (graph: Graph) => boolean;
17
17
  cutMargins: boolean;
18
+ wholeWalks: boolean;
18
19
  drawsLocally: (graph: Graph) => boolean;
19
20
  }
20
21
  export declare const LAYOUT_MODES: readonly [{
@@ -23,6 +24,7 @@ export declare const LAYOUT_MODES: readonly [{
23
24
  readonly description: "x is reference bp, one row per stable rank. Needs rGFA tags or a reference path.";
24
25
  readonly run: typeof anchoredLayout;
25
26
  readonly cutMargins: true;
27
+ readonly wholeWalks: false;
26
28
  readonly available: (graph: Graph) => boolean;
27
29
  readonly drawsLocally: (graph: Graph) => boolean;
28
30
  }, {
@@ -31,6 +33,7 @@ export declare const LAYOUT_MODES: readonly [{
31
33
  readonly description: "x is reference bp, one row per contributing assembly. Needs rGFA tags or a reference path.";
32
34
  readonly run: typeof sampleRowLayout;
33
35
  readonly cutMargins: true;
36
+ readonly wholeWalks: false;
34
37
  readonly available: (graph: Graph) => boolean;
35
38
  readonly drawsLocally: (graph: Graph) => boolean;
36
39
  }, {
@@ -39,6 +42,7 @@ export declare const LAYOUT_MODES: readonly [{
39
42
  readonly description: "x is each walk's own bp: one bar per haplotype, sequence the reference also carries in blue and sequence it does not in purple, so a repeat expansion reads as bar length. Needs W or P lines.";
40
43
  readonly run: typeof walkRowLayout;
41
44
  readonly cutMargins: false;
45
+ readonly wholeWalks: true;
42
46
  readonly available: (graph: Graph) => boolean;
43
47
  readonly drawsLocally: (graph: Graph) => boolean;
44
48
  }, {
@@ -47,6 +51,7 @@ export declare const LAYOUT_MODES: readonly [{
47
51
  readonly description: "x is reference order, not bp: every node gets room, bubbles read as lenses. Needs rGFA tags or a reference path.";
48
52
  readonly run: typeof orderedLayout;
49
53
  readonly cutMargins: false;
54
+ readonly wholeWalks: false;
50
55
  readonly available: (graph: Graph) => boolean;
51
56
  readonly drawsLocally: (graph: Graph) => boolean;
52
57
  }, {
@@ -55,6 +60,7 @@ export declare const LAYOUT_MODES: readonly [{
55
60
  readonly description: "sequenceTubeMap: every path a coloured tube through boxed nodes, columns in node order and node widths log-scaled. Needs P or W lines.";
56
61
  readonly run: typeof tubeMapLayout;
57
62
  readonly cutMargins: false;
63
+ readonly wholeWalks: false;
58
64
  readonly available: typeof hasTubeMapPaths;
59
65
  readonly drawsLocally: typeof hasTubeMapPaths;
60
66
  }, {
@@ -63,6 +69,7 @@ export declare const LAYOUT_MODES: readonly [{
63
69
  readonly description: "The tube map with each column at the reference bp it covers, so the tubes line up with the tracks around them. Needs P or W lines and a reference path.";
64
70
  readonly run: typeof tubeMapReferenceLayout;
65
71
  readonly cutMargins: true;
72
+ readonly wholeWalks: false;
66
73
  readonly available: (graph: Graph) => boolean;
67
74
  readonly drawsLocally: (graph: Graph) => boolean;
68
75
  }, {
@@ -71,6 +78,7 @@ export declare const LAYOUT_MODES: readonly [{
71
78
  readonly description: "OGDF FMMM, via the external Bandage engine.";
72
79
  readonly run: () => undefined;
73
80
  readonly cutMargins: false;
81
+ readonly wholeWalks: false;
74
82
  readonly available: () => true;
75
83
  readonly drawsLocally: () => false;
76
84
  }];
@@ -83,6 +91,7 @@ export declare function layoutModeByValue(value: string): {
83
91
  readonly description: "x is reference bp, one row per stable rank. Needs rGFA tags or a reference path.";
84
92
  readonly run: typeof anchoredLayout;
85
93
  readonly cutMargins: true;
94
+ readonly wholeWalks: false;
86
95
  readonly available: (graph: Graph) => boolean;
87
96
  readonly drawsLocally: (graph: Graph) => boolean;
88
97
  } | {
@@ -91,6 +100,7 @@ export declare function layoutModeByValue(value: string): {
91
100
  readonly description: "x is reference bp, one row per contributing assembly. Needs rGFA tags or a reference path.";
92
101
  readonly run: typeof sampleRowLayout;
93
102
  readonly cutMargins: true;
103
+ readonly wholeWalks: false;
94
104
  readonly available: (graph: Graph) => boolean;
95
105
  readonly drawsLocally: (graph: Graph) => boolean;
96
106
  } | {
@@ -99,6 +109,7 @@ export declare function layoutModeByValue(value: string): {
99
109
  readonly description: "x is each walk's own bp: one bar per haplotype, sequence the reference also carries in blue and sequence it does not in purple, so a repeat expansion reads as bar length. Needs W or P lines.";
100
110
  readonly run: typeof walkRowLayout;
101
111
  readonly cutMargins: false;
112
+ readonly wholeWalks: true;
102
113
  readonly available: (graph: Graph) => boolean;
103
114
  readonly drawsLocally: (graph: Graph) => boolean;
104
115
  } | {
@@ -107,6 +118,7 @@ export declare function layoutModeByValue(value: string): {
107
118
  readonly description: "x is reference order, not bp: every node gets room, bubbles read as lenses. Needs rGFA tags or a reference path.";
108
119
  readonly run: typeof orderedLayout;
109
120
  readonly cutMargins: false;
121
+ readonly wholeWalks: false;
110
122
  readonly available: (graph: Graph) => boolean;
111
123
  readonly drawsLocally: (graph: Graph) => boolean;
112
124
  } | {
@@ -115,6 +127,7 @@ export declare function layoutModeByValue(value: string): {
115
127
  readonly description: "sequenceTubeMap: every path a coloured tube through boxed nodes, columns in node order and node widths log-scaled. Needs P or W lines.";
116
128
  readonly run: typeof tubeMapLayout;
117
129
  readonly cutMargins: false;
130
+ readonly wholeWalks: false;
118
131
  readonly available: typeof hasTubeMapPaths;
119
132
  readonly drawsLocally: typeof hasTubeMapPaths;
120
133
  } | {
@@ -123,6 +136,7 @@ export declare function layoutModeByValue(value: string): {
123
136
  readonly description: "The tube map with each column at the reference bp it covers, so the tubes line up with the tracks around them. Needs P or W lines and a reference path.";
124
137
  readonly run: typeof tubeMapReferenceLayout;
125
138
  readonly cutMargins: true;
139
+ readonly wholeWalks: false;
126
140
  readonly available: (graph: Graph) => boolean;
127
141
  readonly drawsLocally: (graph: Graph) => boolean;
128
142
  } | {
@@ -131,6 +145,7 @@ export declare function layoutModeByValue(value: string): {
131
145
  readonly description: "OGDF FMMM, via the external Bandage engine.";
132
146
  readonly run: () => undefined;
133
147
  readonly cutMargins: false;
148
+ readonly wholeWalks: false;
134
149
  readonly available: () => true;
135
150
  readonly drawsLocally: () => false;
136
151
  };
@@ -1,7 +1,7 @@
1
1
  import type { ResolvedColorScheme } from '../colorSchemes.js';
2
2
  import type { NodeWidth } from '../nodeWidths.js';
3
3
  import type { Graph, GraphNode, NodeSegment } from '../types.js';
4
- import type { WalkHighlight } from '../walkHighlight.js';
4
+ import type { WalkLift } from '../walkHighlight.js';
5
5
  import type { RenderBatch } from './types.js';
6
6
  import type { AxisScale, BezierCurve } from '../util/geometry.js';
7
7
  export declare const FADED_ALPHA = 0.18;
@@ -14,7 +14,7 @@ export interface BuildOptions {
14
14
  connectorThickness: number;
15
15
  drawPaths: boolean;
16
16
  nodeWidth?: NodeWidth;
17
- highlight?: WalkHighlight;
17
+ highlight?: WalkLift;
18
18
  axis: AxisScale;
19
19
  linearLayout?: boolean;
20
20
  viewportBounds?: {
@@ -30,6 +30,7 @@ export interface BuildOptions {
30
30
  }
31
31
  export declare function hslToRgb(h: number, s: number, l: number): [number, number, number];
32
32
  export declare const REFERENCE_RAMP_MAX_HUE = 300;
33
+ export declare const REFERENCE_RAMP_ALT_COLOR: number;
33
34
  export declare const REFERENCE_RAMP_ALT_CSS: string;
34
35
  export interface ReferenceRamp {
35
36
  start: number;
@@ -0,0 +1,70 @@
1
+ export declare const WALK_FIELDS: readonly [{
2
+ readonly value: "progress";
3
+ readonly label: "Progress along the walk";
4
+ readonly legend: "pale where the walk starts, deep where it ends";
5
+ }, {
6
+ readonly value: "reference";
7
+ readonly label: "Reference position";
8
+ readonly legend: "along the reference left to right, charcoal off it";
9
+ }, {
10
+ readonly value: "strand";
11
+ readonly label: "Strand against the reference";
12
+ readonly legend: "pale where the walk runs as the reference does, deep where reversed";
13
+ }, {
14
+ readonly value: "visits";
15
+ readonly label: "Visits";
16
+ readonly legend: "pale where the walk passes once, deep four times or more";
17
+ }];
18
+ export type WalkField = (typeof WALK_FIELDS)[number]['value'];
19
+ export declare const WALK_SCHEMES: readonly [{
20
+ readonly value: "rainbow";
21
+ readonly label: "Rainbow";
22
+ }, {
23
+ readonly value: "blues";
24
+ readonly label: "Blues";
25
+ readonly hue: 215;
26
+ }, {
27
+ readonly value: "reds";
28
+ readonly label: "Reds";
29
+ readonly hue: 0;
30
+ }, {
31
+ readonly value: "greens";
32
+ readonly label: "Greens";
33
+ readonly hue: 130;
34
+ }, {
35
+ readonly value: "oranges";
36
+ readonly label: "Oranges";
37
+ readonly hue: 30;
38
+ }, {
39
+ readonly value: "purples";
40
+ readonly label: "Purples";
41
+ readonly hue: 280;
42
+ }, {
43
+ readonly value: "greys";
44
+ readonly label: "Greys";
45
+ }];
46
+ export type WalkScheme = (typeof WALK_SCHEMES)[number]['value'];
47
+ export interface WalkEncoding {
48
+ field: WalkField;
49
+ scheme: WalkScheme;
50
+ }
51
+ export interface WalkLayer {
52
+ walk: string;
53
+ color?: Partial<WalkEncoding>;
54
+ }
55
+ export declare function resolveEncoding(layer: WalkLayer, reference: boolean, picked: number): WalkEncoding;
56
+ export declare function schemeHsl(scheme: WalkScheme, t: number): {
57
+ h: number;
58
+ s: number;
59
+ l: number;
60
+ };
61
+ export declare function schemeCss(scheme: WalkScheme, t: number): string;
62
+ export declare function schemeColor(scheme: WalkScheme, t: number): number;
63
+ export declare const NO_VALUE_COLOR: number;
64
+ export declare const NO_VALUE_CSS: string;
65
+ export declare const STRAND_T: {
66
+ same: number;
67
+ reversed: number;
68
+ };
69
+ export declare function encodingSwatchCss({ field, scheme }: WalkEncoding): string;
70
+ export declare function fieldLegend(field: WalkField): "pale where the walk starts, deep where it ends" | "along the reference left to right, charcoal off it" | "pale where the walk runs as the reference does, deep where reversed" | "pale where the walk passes once, deep four times or more";
@@ -1,10 +1,25 @@
1
+ import type { ReferenceRamp } from './renderer/GeometryBuilder.js';
1
2
  import type { Graph } from './types.js';
3
+ import type { WalkEncoding, WalkLayer } from './walkEncoding.js';
2
4
  export interface WalkHighlight {
3
5
  name: string;
6
+ reference: boolean;
4
7
  nodeIds: Set<string>;
5
8
  edgeIndexes: Set<number>;
9
+ progress: Map<string, number>;
6
10
  steps: number;
7
11
  bp: number;
8
12
  referenceBp?: number;
9
13
  }
14
+ export interface LiftedWalk extends WalkHighlight {
15
+ encoding: WalkEncoding;
16
+ colors: Map<string, number>;
17
+ }
18
+ export interface WalkLift {
19
+ walks: LiftedWalk[];
20
+ nodeIds: Set<string>;
21
+ edgeIndexes: Set<number>;
22
+ names: Set<string>;
23
+ }
10
24
  export declare function walkHighlight(graph: Graph, name: string): WalkHighlight | undefined;
25
+ export declare function walkLift(graph: Graph, layers: readonly WalkLayer[], ramp?: ReferenceRamp): WalkLift | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/bandage-core",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
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": {