jbrowse-plugin-mafviewer 1.3.0 → 1.3.2
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 +1 -1
- package/dist/BigMafAdapter/BigMafAdapter.js +39 -28
- package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -1
- package/dist/LinearMafDisplay/components/Crosshairs.js +1 -1
- package/dist/LinearMafDisplay/components/Crosshairs.js.map +1 -1
- package/dist/LinearMafDisplay/components/MAFTooltip.d.ts +2 -3
- package/dist/LinearMafDisplay/components/MAFTooltip.js +6 -19
- package/dist/LinearMafDisplay/components/MAFTooltip.js.map +1 -1
- package/dist/LinearMafDisplay/stateModel.d.ts +8 -0
- package/dist/LinearMafDisplay/stateModel.js +10 -0
- package/dist/LinearMafDisplay/stateModel.js.map +1 -1
- package/dist/LinearMafDisplay/util.d.ts +20 -0
- package/dist/LinearMafDisplay/util.js +29 -0
- package/dist/LinearMafDisplay/util.js.map +1 -1
- package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +3 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.js +1 -2
- package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -1
- package/dist/LinearMafRenderer/components/ReactComponent.d.ts +3 -0
- package/dist/LinearMafRenderer/components/ReactComponent.js +41 -2
- package/dist/LinearMafRenderer/components/ReactComponent.js.map +1 -1
- package/dist/LinearMafRenderer/components/util.d.ts +1 -0
- package/dist/LinearMafRenderer/components/util.js +13 -0
- package/dist/LinearMafRenderer/components/util.js.map +1 -0
- package/dist/LinearMafRenderer/makeImageData.d.ts +4 -5
- package/dist/LinearMafRenderer/makeImageData.js +28 -146
- package/dist/LinearMafRenderer/makeImageData.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/features.d.ts +21 -0
- package/dist/LinearMafRenderer/rendering/features.js +58 -0
- package/dist/LinearMafRenderer/rendering/features.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/gaps.d.ts +12 -0
- package/dist/LinearMafRenderer/rendering/gaps.js +35 -0
- package/dist/LinearMafRenderer/rendering/gaps.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/index.d.ts +8 -0
- package/dist/LinearMafRenderer/rendering/index.js +10 -0
- package/dist/LinearMafRenderer/rendering/index.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/insertions.d.ts +14 -0
- package/dist/LinearMafRenderer/rendering/insertions.js +84 -0
- package/dist/LinearMafRenderer/rendering/insertions.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/matches.d.ts +13 -0
- package/dist/LinearMafRenderer/rendering/matches.js +41 -0
- package/dist/LinearMafRenderer/rendering/matches.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/mismatches.d.ts +13 -0
- package/dist/LinearMafRenderer/rendering/mismatches.js +47 -0
- package/dist/LinearMafRenderer/rendering/mismatches.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/spatialIndex.d.ts +60 -0
- package/dist/LinearMafRenderer/rendering/spatialIndex.js +99 -0
- package/dist/LinearMafRenderer/rendering/spatialIndex.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/text.d.ts +12 -0
- package/dist/LinearMafRenderer/rendering/text.js +42 -0
- package/dist/LinearMafRenderer/rendering/text.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/types.d.ts +67 -0
- package/dist/LinearMafRenderer/rendering/types.js +15 -0
- package/dist/LinearMafRenderer/rendering/types.js.map +1 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.js +48 -22
- package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +7 -8
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
- package/dist/out.js +34520 -0
- package/dist/out.js.map +7 -0
- package/dist/util/fastaUtils.js.map +1 -1
- package/package.json +5 -3
- package/src/BigMafAdapter/BigMafAdapter.ts +50 -29
- package/src/LinearMafDisplay/components/Crosshairs.tsx +1 -7
- package/src/LinearMafDisplay/components/MAFTooltip.tsx +14 -33
- package/src/LinearMafDisplay/stateModel.ts +10 -0
- package/src/LinearMafDisplay/util.ts +57 -0
- package/src/LinearMafRenderer/LinearMafRenderer.ts +1 -2
- package/src/LinearMafRenderer/components/ReactComponent.tsx +70 -2
- package/src/LinearMafRenderer/components/util.ts +13 -0
- package/src/LinearMafRenderer/makeImageData.ts +49 -196
- package/src/LinearMafRenderer/rendering/features.ts +138 -0
- package/src/LinearMafRenderer/rendering/gaps.ts +71 -0
- package/src/LinearMafRenderer/rendering/index.ts +9 -0
- package/src/LinearMafRenderer/rendering/insertions.ts +170 -0
- package/src/LinearMafRenderer/rendering/matches.ts +79 -0
- package/src/LinearMafRenderer/rendering/mismatches.ts +125 -0
- package/src/LinearMafRenderer/rendering/spatialIndex.ts +136 -0
- package/src/LinearMafRenderer/rendering/text.ts +72 -0
- package/src/LinearMafRenderer/rendering/types.ts +81 -0
- package/src/MafTabixAdapter/MafTabixAdapter.ts +77 -22
- package/src/util/fastaUtils.ts +2 -1
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { createJBrowseTheme } from '@jbrowse/core/ui';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
return showAsUpperCase ? a.toUpperCase() : a;
|
|
6
|
-
}
|
|
2
|
+
import RBush from 'rbush';
|
|
3
|
+
import { FONT_CONFIG, processFeatureAlignment, processFeatureInsertions, } from './rendering';
|
|
4
|
+
import { getColorBaseMap, getContrastBaseMap } from './util';
|
|
7
5
|
export function makeImageData({ ctx, renderArgs, }) {
|
|
8
6
|
const { regions, bpPerPx, rowHeight, showAllLetters, theme: configTheme, mismatchRendering, samples, rowProportion, features, showAsUpperCase, } = renderArgs;
|
|
9
7
|
const region = regions[0];
|
|
@@ -12,154 +10,38 @@ export function makeImageData({ ctx, renderArgs, }) {
|
|
|
12
10
|
const theme = createJBrowseTheme(configTheme);
|
|
13
11
|
const colorForBase = getColorBaseMap(theme);
|
|
14
12
|
const contrastForBase = getContrastBaseMap(theme);
|
|
15
|
-
const { charHeight } = getCharWidthHeight();
|
|
16
13
|
const sampleToRowMap = new Map(samples.map((s, i) => [s.id, i]));
|
|
17
14
|
const scale = 1 / bpPerPx;
|
|
18
|
-
const f = 0.4;
|
|
19
|
-
const h2 = rowHeight / 2;
|
|
20
15
|
const hp2 = h / 2;
|
|
21
16
|
const offset = (rowHeight - h) / 2;
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
ctx.font = FONT_CONFIG;
|
|
18
|
+
const renderingContext = {
|
|
19
|
+
ctx,
|
|
20
|
+
scale,
|
|
21
|
+
canvasWidth,
|
|
22
|
+
rowHeight,
|
|
23
|
+
h,
|
|
24
|
+
hp2,
|
|
25
|
+
offset,
|
|
26
|
+
colorForBase,
|
|
27
|
+
contrastForBase,
|
|
28
|
+
showAllLetters,
|
|
29
|
+
mismatchRendering,
|
|
30
|
+
showAsUpperCase,
|
|
31
|
+
spatialIndex: new RBush(),
|
|
32
|
+
lastInsertedX: -Infinity, // Start with -Infinity so first item is always inserted
|
|
33
|
+
};
|
|
34
|
+
// First pass: render alignments (gaps, matches, mismatches, text)
|
|
24
35
|
for (const feature of features.values()) {
|
|
25
|
-
|
|
26
|
-
const vals = feature.get('alignments');
|
|
27
|
-
const seq = feature.get('seq').toLowerCase();
|
|
28
|
-
const r = Object.entries(vals);
|
|
29
|
-
for (const [sample, val] of r) {
|
|
30
|
-
const origAlignment = val.seq;
|
|
31
|
-
const alignment = origAlignment.toLowerCase();
|
|
32
|
-
const row = sampleToRowMap.get(sample);
|
|
33
|
-
if (row === undefined) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
const t = rowHeight * row;
|
|
37
|
-
const t2 = offset + t;
|
|
38
|
-
// gaps
|
|
39
|
-
ctx.beginPath();
|
|
40
|
-
ctx.fillStyle = 'black';
|
|
41
|
-
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
42
|
-
if (seq[i] !== '-') {
|
|
43
|
-
if (alignment[i] === '-') {
|
|
44
|
-
const l = leftPx + scale * o;
|
|
45
|
-
ctx.moveTo(l, t + h2);
|
|
46
|
-
ctx.lineTo(l + scale + f, t + h2);
|
|
47
|
-
}
|
|
48
|
-
o++;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
ctx.stroke();
|
|
52
|
-
if (!showAllLetters) {
|
|
53
|
-
// matches
|
|
54
|
-
ctx.fillStyle = 'lightgrey';
|
|
55
|
-
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
56
|
-
if (seq[i] !== '-') {
|
|
57
|
-
const c = alignment[i];
|
|
58
|
-
const l = leftPx + scale * o;
|
|
59
|
-
if (seq[i] === c && c !== '-' && c !== ' ') {
|
|
60
|
-
fillRect(ctx, l, t2, scale + f, h, canvasWidth);
|
|
61
|
-
}
|
|
62
|
-
o++;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// mismatches
|
|
67
|
-
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
68
|
-
const c = alignment[i];
|
|
69
|
-
if (seq[i] !== '-') {
|
|
70
|
-
if (c !== '-') {
|
|
71
|
-
const l = leftPx + scale * o;
|
|
72
|
-
if (seq[i] !== c && c !== ' ') {
|
|
73
|
-
fillRect(ctx, l, t2, scale + f, h, canvasWidth, mismatchRendering
|
|
74
|
-
? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
75
|
-
(colorForBase[c] ?? 'black')
|
|
76
|
-
: 'orange');
|
|
77
|
-
}
|
|
78
|
-
else if (showAllLetters) {
|
|
79
|
-
fillRect(ctx, l, t2, scale + f, h, canvasWidth, mismatchRendering
|
|
80
|
-
? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
81
|
-
(colorForBase[c] ?? 'black')
|
|
82
|
-
: 'lightblue');
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
o++;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
// font
|
|
89
|
-
const charSizeW = 10;
|
|
90
|
-
if (scale >= charSizeW) {
|
|
91
|
-
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
92
|
-
if (seq[i] !== '-') {
|
|
93
|
-
const l = leftPx + scale * o;
|
|
94
|
-
const offset = (scale - charSizeW) / 2 + 1;
|
|
95
|
-
const c = alignment[i];
|
|
96
|
-
if ((showAllLetters || seq[i] !== c) && c !== '-') {
|
|
97
|
-
ctx.fillStyle = mismatchRendering
|
|
98
|
-
? (contrastForBase[c] ?? 'white')
|
|
99
|
-
: 'black';
|
|
100
|
-
if (rowHeight > charHeight) {
|
|
101
|
-
ctx.fillText(getLetter(origAlignment[i] || '', showAsUpperCase), l + offset, hp2 + t + 3);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
o++;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
36
|
+
processFeatureAlignment(feature, region, bpPerPx, sampleToRowMap, renderingContext);
|
|
109
37
|
}
|
|
110
|
-
//
|
|
111
|
-
// insertions are always 'on top' of the other features
|
|
38
|
+
// Second pass: render insertions on top
|
|
112
39
|
for (const feature of features.values()) {
|
|
113
|
-
|
|
114
|
-
const vals = feature.get('alignments');
|
|
115
|
-
const seq = feature.get('seq').toLowerCase();
|
|
116
|
-
for (const [sample, val] of Object.entries(vals)) {
|
|
117
|
-
const origAlignment = val.seq;
|
|
118
|
-
const alignment = origAlignment.toLowerCase();
|
|
119
|
-
const row = sampleToRowMap.get(sample);
|
|
120
|
-
if (row === undefined) {
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
const t = rowHeight * row;
|
|
124
|
-
const t2 = offset + t;
|
|
125
|
-
for (let i = 0, o = 0, l = alignment.length; i < l; i++) {
|
|
126
|
-
let ins = '';
|
|
127
|
-
while (seq[i] === '-') {
|
|
128
|
-
if (alignment[i] !== '-' && alignment[i] !== ' ') {
|
|
129
|
-
ins += alignment[i];
|
|
130
|
-
}
|
|
131
|
-
i++;
|
|
132
|
-
}
|
|
133
|
-
if (ins.length > 0) {
|
|
134
|
-
const l = leftPx + scale * o - 1;
|
|
135
|
-
if (ins.length > 10) {
|
|
136
|
-
const txt = `${ins.length}`;
|
|
137
|
-
if (bpPerPx > 10) {
|
|
138
|
-
fillRect(ctx, l - 1, t2, 2, h, canvasWidth, 'purple');
|
|
139
|
-
}
|
|
140
|
-
else if (h > charHeight) {
|
|
141
|
-
const rwidth = measureText(txt, 10);
|
|
142
|
-
const padding = 2;
|
|
143
|
-
fillRect(ctx, l - rwidth / 2 - padding, t2, rwidth + 2 * padding, h, canvasWidth, 'purple');
|
|
144
|
-
ctx.fillStyle = 'white';
|
|
145
|
-
ctx.fillText(txt, l - rwidth / 2, t + h);
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
const padding = 2;
|
|
149
|
-
fillRect(ctx, l - padding, t2, 2 * padding, h, canvasWidth, 'purple');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
fillRect(ctx, l, t2, 1, h, canvasWidth, 'purple');
|
|
154
|
-
if (bpPerPx < 0.2 && rowHeight > 5) {
|
|
155
|
-
fillRect(ctx, l - 2, t2, 5, 1, canvasWidth);
|
|
156
|
-
fillRect(ctx, l - 2, t2 + h - 1, 5, 1, canvasWidth);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
o++;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
40
|
+
processFeatureInsertions(feature, region, bpPerPx, sampleToRowMap, renderingContext);
|
|
163
41
|
}
|
|
42
|
+
// Return serialized RBush spatial index
|
|
43
|
+
return {
|
|
44
|
+
rbush: renderingContext.spatialIndex.toJSON(),
|
|
45
|
+
};
|
|
164
46
|
}
|
|
165
47
|
//# sourceMappingURL=makeImageData.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeImageData.js","sourceRoot":"","sources":["../../src/LinearMafRenderer/makeImageData.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"makeImageData.js","sourceRoot":"","sources":["../../src/LinearMafRenderer/makeImageData.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EACL,WAAW,EAIX,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AAa5D,MAAM,UAAU,aAAa,CAAC,EAC5B,GAAG,EACH,UAAU,GAIX;IACC,MAAM,EACJ,OAAO,EACP,OAAO,EACP,SAAS,EACT,cAAc,EACd,KAAK,EAAE,WAAW,EAClB,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,QAAQ,EACR,eAAe,GAChB,GAAG,UAAU,CAAA;IAEd,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;IAC1B,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAA;IACzD,MAAM,CAAC,GAAG,SAAS,GAAG,aAAa,CAAA;IACnC,MAAM,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAA;IAC7C,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;IACjD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAChE,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAA;IACzB,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;IACjB,MAAM,MAAM,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;IAElC,GAAG,CAAC,IAAI,GAAG,WAAW,CAAA;IAEtB,MAAM,gBAAgB,GAAqB;QACzC,GAAG;QACH,KAAK;QACL,WAAW;QACX,SAAS;QACT,CAAC;QACD,GAAG;QACH,MAAM;QACN,YAAY;QACZ,eAAe;QACf,cAAc;QACd,iBAAiB;QACjB,eAAe;QACf,YAAY,EAAE,IAAI,KAAK,EAAgB;QACvC,aAAa,EAAE,CAAC,QAAQ,EAAE,wDAAwD;KACnF,CAAA;IAED,kEAAkE;IAClE,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,uBAAuB,CACrB,OAAO,EACP,MAAM,EACN,OAAO,EACP,cAAc,EACd,gBAAgB,CACjB,CAAA;IACH,CAAC;IAED,wCAAwC;IACxC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,wBAAwB,CACtB,OAAO,EACP,MAAM,EACN,OAAO,EACP,cAAc,EACd,gBAAgB,CACjB,CAAA;IACH,CAAC;IAED,wCAAwC;IACxC,OAAO;QACL,KAAK,EAAE,gBAAgB,CAAC,YAAY,CAAC,MAAM,EAAE;KAC9C,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Feature } from '@jbrowse/core/util';
|
|
2
|
+
import type { GenomicRegion, RenderingContext } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Processes alignment data for a single feature, rendering gaps, matches, mismatches, and text
|
|
5
|
+
* @param feature - JBrowse feature containing alignment data
|
|
6
|
+
* @param region - Genomic region being rendered
|
|
7
|
+
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
8
|
+
* @param sampleToRowMap - Maps sample IDs to row indices
|
|
9
|
+
* @param renderingContext - Shared rendering parameters
|
|
10
|
+
*/
|
|
11
|
+
export declare function processFeatureAlignment(feature: Feature, region: GenomicRegion, bpPerPx: number, sampleToRowMap: Map<string, number>, renderingContext: RenderingContext): void;
|
|
12
|
+
/**
|
|
13
|
+
* Processes insertion data for a single feature in a separate pass
|
|
14
|
+
* Insertions are rendered on top to ensure visibility
|
|
15
|
+
* @param feature - JBrowse feature containing alignment data
|
|
16
|
+
* @param region - Genomic region being rendered
|
|
17
|
+
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
18
|
+
* @param sampleToRowMap - Maps sample IDs to row indices
|
|
19
|
+
* @param renderingContext - Shared rendering parameters
|
|
20
|
+
*/
|
|
21
|
+
export declare function processFeatureInsertions(feature: Feature, region: GenomicRegion, bpPerPx: number, sampleToRowMap: Map<string, number>, renderingContext: RenderingContext): void;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { featureSpanPx } from '@jbrowse/core/util';
|
|
2
|
+
import { renderGaps } from './gaps';
|
|
3
|
+
import { renderInsertions } from './insertions';
|
|
4
|
+
import { renderMatches } from './matches';
|
|
5
|
+
import { renderMismatches } from './mismatches';
|
|
6
|
+
import { renderText } from './text';
|
|
7
|
+
/**
|
|
8
|
+
* Processes alignment data for a single feature, rendering gaps, matches, mismatches, and text
|
|
9
|
+
* @param feature - JBrowse feature containing alignment data
|
|
10
|
+
* @param region - Genomic region being rendered
|
|
11
|
+
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
12
|
+
* @param sampleToRowMap - Maps sample IDs to row indices
|
|
13
|
+
* @param renderingContext - Shared rendering parameters
|
|
14
|
+
*/
|
|
15
|
+
export function processFeatureAlignment(feature, region, bpPerPx, sampleToRowMap, renderingContext) {
|
|
16
|
+
const [leftPx] = featureSpanPx(feature, region, bpPerPx);
|
|
17
|
+
const alignments = feature.get('alignments');
|
|
18
|
+
const referenceSeq = feature.get('seq').toLowerCase();
|
|
19
|
+
const featureId = feature.id() || `feature_${feature.get('start')}_${feature.get('end')}`;
|
|
20
|
+
for (const [sampleId, alignmentData] of Object.entries(alignments)) {
|
|
21
|
+
const row = sampleToRowMap.get(sampleId);
|
|
22
|
+
if (row === undefined) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const originalAlignment = alignmentData.seq;
|
|
26
|
+
const alignment = originalAlignment.toLowerCase();
|
|
27
|
+
const rowTop = renderingContext.offset + renderingContext.rowHeight * row;
|
|
28
|
+
renderGaps(renderingContext, alignment, referenceSeq, leftPx, rowTop, sampleId, featureId, alignmentData.start, alignmentData.chr);
|
|
29
|
+
renderMatches(renderingContext, alignment, referenceSeq, leftPx, rowTop, sampleId, featureId, alignmentData.start, alignmentData.chr);
|
|
30
|
+
renderMismatches(renderingContext, alignment, referenceSeq, leftPx, rowTop, sampleId, featureId, alignmentData.start, alignmentData.chr);
|
|
31
|
+
renderText(renderingContext, alignment, originalAlignment, referenceSeq, leftPx, rowTop, sampleId, featureId);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Processes insertion data for a single feature in a separate pass
|
|
36
|
+
* Insertions are rendered on top to ensure visibility
|
|
37
|
+
* @param feature - JBrowse feature containing alignment data
|
|
38
|
+
* @param region - Genomic region being rendered
|
|
39
|
+
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
40
|
+
* @param sampleToRowMap - Maps sample IDs to row indices
|
|
41
|
+
* @param renderingContext - Shared rendering parameters
|
|
42
|
+
*/
|
|
43
|
+
export function processFeatureInsertions(feature, region, bpPerPx, sampleToRowMap, renderingContext) {
|
|
44
|
+
const [leftPx] = featureSpanPx(feature, region, bpPerPx);
|
|
45
|
+
const alignments = feature.get('alignments');
|
|
46
|
+
const referenceSeq = feature.get('seq').toLowerCase();
|
|
47
|
+
const featureId = feature.id() || `feature_${feature.get('start')}_${feature.get('end')}`;
|
|
48
|
+
for (const [sampleId, alignmentData] of Object.entries(alignments)) {
|
|
49
|
+
const row = sampleToRowMap.get(sampleId);
|
|
50
|
+
if (row === undefined) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const alignment = alignmentData.seq.toLowerCase();
|
|
54
|
+
const rowTop = renderingContext.offset + renderingContext.rowHeight * row;
|
|
55
|
+
renderInsertions(renderingContext, alignment, referenceSeq, leftPx, rowTop, bpPerPx, sampleId, featureId, alignmentData.start, alignmentData.chr);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=features.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/rendering/features.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RenderingContext } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Renders gap indicators (horizontal lines) where the alignment has deletions relative to reference
|
|
4
|
+
* @param context - Rendering context with canvas and styling info
|
|
5
|
+
* @param alignment - The aligned sequence for this sample
|
|
6
|
+
* @param seq - The reference sequence
|
|
7
|
+
* @param leftPx - Left pixel position of the feature
|
|
8
|
+
* @param rowTop - Top pixel position of the row
|
|
9
|
+
* @param alignmentStart - Start position of the alignment
|
|
10
|
+
* @param chr - Chromosome/sequence name
|
|
11
|
+
*/
|
|
12
|
+
export declare function renderGaps(context: RenderingContext, alignment: string, seq: string, leftPx: number, rowTop: number, sampleId: string, featureId: string, alignmentStart: number, chr: string): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { addToSpatialIndex, createRenderedBase, shouldAddToSpatialIndex, } from './spatialIndex';
|
|
2
|
+
import { GAP_STROKE_OFFSET } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Renders gap indicators (horizontal lines) where the alignment has deletions relative to reference
|
|
5
|
+
* @param context - Rendering context with canvas and styling info
|
|
6
|
+
* @param alignment - The aligned sequence for this sample
|
|
7
|
+
* @param seq - The reference sequence
|
|
8
|
+
* @param leftPx - Left pixel position of the feature
|
|
9
|
+
* @param rowTop - Top pixel position of the row
|
|
10
|
+
* @param alignmentStart - Start position of the alignment
|
|
11
|
+
* @param chr - Chromosome/sequence name
|
|
12
|
+
*/
|
|
13
|
+
export function renderGaps(context, alignment, seq, leftPx, rowTop, sampleId, featureId, alignmentStart, chr) {
|
|
14
|
+
const { ctx, scale } = context;
|
|
15
|
+
const h2 = context.rowHeight / 2;
|
|
16
|
+
ctx.beginPath();
|
|
17
|
+
ctx.fillStyle = 'black';
|
|
18
|
+
for (let i = 0, genomicOffset = 0, seqLength = alignment.length; i < seqLength; i++) {
|
|
19
|
+
if (seq[i] !== '-') {
|
|
20
|
+
if (alignment[i] === '-') {
|
|
21
|
+
const xPos = leftPx + scale * genomicOffset;
|
|
22
|
+
ctx.moveTo(xPos, rowTop + h2);
|
|
23
|
+
ctx.lineTo(xPos + scale + GAP_STROKE_OFFSET, rowTop + h2);
|
|
24
|
+
// Add to spatial index if distance filter allows
|
|
25
|
+
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
26
|
+
const renderedBase = createRenderedBase(xPos, rowTop, context, genomicOffset + alignmentStart, chr, sampleId, '-', false, false, true, false, featureId);
|
|
27
|
+
addToSpatialIndex(context, renderedBase);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
genomicOffset++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
ctx.stroke();
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=gaps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gaps.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/rendering/gaps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI3C;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CACxB,OAAyB,EACzB,SAAiB,EACjB,GAAW,EACX,MAAc,EACd,MAAc,EACd,QAAgB,EAChB,SAAiB,EACjB,cAAsB,EACtB,GAAW;IAEX,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IAC9B,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,CAAC,CAAA;IAEhC,GAAG,CAAC,SAAS,EAAE,CAAA;IACf,GAAG,CAAC,SAAS,GAAG,OAAO,CAAA;IAEvB,KACE,IAAI,CAAC,GAAG,CAAC,EAAE,aAAa,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC,MAAM,EAC1D,CAAC,GAAG,SAAS,EACb,CAAC,EAAE,EACH,CAAC;QACD,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACnB,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,aAAa,CAAA;gBAC3C,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,CAAC,CAAA;gBAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,GAAG,iBAAiB,EAAE,MAAM,GAAG,EAAE,CAAC,CAAA;gBAEzD,iDAAiD;gBACjD,IAAI,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;oBAC3C,MAAM,YAAY,GAAG,kBAAkB,CACrC,IAAI,EACJ,MAAM,EACN,OAAO,EACP,aAAa,GAAG,cAAc,EAC9B,GAAG,EACH,QAAQ,EACR,GAAG,EACH,KAAK,EACL,KAAK,EACL,IAAI,EACJ,KAAK,EACL,SAAS,CACV,CAAA;oBACD,iBAAiB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;gBAC1C,CAAC;YACH,CAAC;YACD,aAAa,EAAE,CAAA;QACjB,CAAC;IACH,CAAC;IACD,GAAG,CAAC,MAAM,EAAE,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Re-export all rendering modules
|
|
2
|
+
export * from './types';
|
|
3
|
+
export * from './spatialIndex';
|
|
4
|
+
export * from './gaps';
|
|
5
|
+
export * from './matches';
|
|
6
|
+
export * from './mismatches';
|
|
7
|
+
export * from './text';
|
|
8
|
+
export * from './insertions';
|
|
9
|
+
export * from './features';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/rendering/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,cAAc,SAAS,CAAA;AACvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,QAAQ,CAAA;AACtB,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RenderingContext } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Renders insertion markers where the alignment has bases not present in reference
|
|
4
|
+
* Large insertions show count, small ones show as colored bars with optional borders
|
|
5
|
+
* @param context - Rendering context with canvas and styling info
|
|
6
|
+
* @param alignment - The aligned sequence for this sample
|
|
7
|
+
* @param seq - The reference sequence
|
|
8
|
+
* @param leftPx - Left pixel position of the feature
|
|
9
|
+
* @param rowTop - Top pixel position of the row
|
|
10
|
+
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
11
|
+
* @param alignmentStart - Start position of the alignment
|
|
12
|
+
* @param chr - Chromosome/sequence name
|
|
13
|
+
*/
|
|
14
|
+
export declare function renderInsertions(context: RenderingContext, alignment: string, seq: string, leftPx: number, rowTop: number, bpPerPx: number, sampleId: string, featureId: string, alignmentStart: number, chr: string): void;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { measureText } from '@jbrowse/core/util';
|
|
2
|
+
import { fillRect, getCharWidthHeight } from '../util';
|
|
3
|
+
import { addToSpatialIndex, createRenderedInsertion, shouldAddToSpatialIndex, } from './spatialIndex';
|
|
4
|
+
import { CHAR_SIZE_WIDTH, HIGH_BP_PER_PX_THRESHOLD, HIGH_ZOOM_THRESHOLD, INSERTION_BORDER_HEIGHT, INSERTION_BORDER_WIDTH, INSERTION_LINE_WIDTH, INSERTION_PADDING, LARGE_INSERTION_THRESHOLD, MIN_ROW_HEIGHT_FOR_BORDERS, } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Renders insertion markers where the alignment has bases not present in reference
|
|
7
|
+
* Large insertions show count, small ones show as colored bars with optional borders
|
|
8
|
+
* @param context - Rendering context with canvas and styling info
|
|
9
|
+
* @param alignment - The aligned sequence for this sample
|
|
10
|
+
* @param seq - The reference sequence
|
|
11
|
+
* @param leftPx - Left pixel position of the feature
|
|
12
|
+
* @param rowTop - Top pixel position of the row
|
|
13
|
+
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
14
|
+
* @param alignmentStart - Start position of the alignment
|
|
15
|
+
* @param chr - Chromosome/sequence name
|
|
16
|
+
*/
|
|
17
|
+
export function renderInsertions(context, alignment, seq, leftPx, rowTop, bpPerPx, sampleId, featureId, alignmentStart, chr) {
|
|
18
|
+
const { ctx, scale, h, canvasWidth, rowHeight } = context;
|
|
19
|
+
const { charHeight } = getCharWidthHeight();
|
|
20
|
+
for (let i = 0, genomicOffset = 0, seqLength = alignment.length; i < seqLength; i++) {
|
|
21
|
+
let insertionSequence = '';
|
|
22
|
+
while (seq[i] === '-') {
|
|
23
|
+
if (alignment[i] !== '-' && alignment[i] !== ' ') {
|
|
24
|
+
insertionSequence += alignment[i];
|
|
25
|
+
}
|
|
26
|
+
i++;
|
|
27
|
+
}
|
|
28
|
+
if (insertionSequence.length > 0) {
|
|
29
|
+
// Found an insertion
|
|
30
|
+
const xPos = leftPx + scale * genomicOffset - INSERTION_LINE_WIDTH;
|
|
31
|
+
// Determine actual rendered width and position for spatial index
|
|
32
|
+
let actualXPos;
|
|
33
|
+
let actualWidth;
|
|
34
|
+
// Large insertions: show count instead of individual bases
|
|
35
|
+
if (insertionSequence.length > LARGE_INSERTION_THRESHOLD) {
|
|
36
|
+
const lengthText = `${insertionSequence.length}`;
|
|
37
|
+
if (bpPerPx > HIGH_BP_PER_PX_THRESHOLD) {
|
|
38
|
+
// Very zoomed out: simple line
|
|
39
|
+
actualXPos = xPos - INSERTION_LINE_WIDTH;
|
|
40
|
+
actualWidth = INSERTION_BORDER_WIDTH;
|
|
41
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
42
|
+
}
|
|
43
|
+
else if (h > charHeight) {
|
|
44
|
+
// Medium zoom: show count in colored box
|
|
45
|
+
const textWidth = measureText(lengthText, CHAR_SIZE_WIDTH);
|
|
46
|
+
const padding = INSERTION_PADDING;
|
|
47
|
+
actualXPos = xPos - textWidth / 2 - padding;
|
|
48
|
+
actualWidth = textWidth + 2 * padding;
|
|
49
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
50
|
+
ctx.fillStyle = 'white';
|
|
51
|
+
ctx.fillText(lengthText, xPos - textWidth / 2, rowTop + (h * 7) / 8);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const padding = INSERTION_PADDING;
|
|
55
|
+
actualXPos = xPos - padding;
|
|
56
|
+
actualWidth = 2 * padding;
|
|
57
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Small insertions: vertical line with optional border at high zoom
|
|
62
|
+
actualXPos = xPos;
|
|
63
|
+
actualWidth = INSERTION_LINE_WIDTH;
|
|
64
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
65
|
+
if (bpPerPx < HIGH_ZOOM_THRESHOLD &&
|
|
66
|
+
rowHeight > MIN_ROW_HEIGHT_FOR_BORDERS) {
|
|
67
|
+
// Add horizontal borders for visibility at high zoom
|
|
68
|
+
// Note: borders extend the effective clickable area
|
|
69
|
+
actualXPos = xPos - INSERTION_BORDER_WIDTH;
|
|
70
|
+
actualWidth = INSERTION_BORDER_HEIGHT;
|
|
71
|
+
fillRect(ctx, xPos - INSERTION_BORDER_WIDTH, rowTop, INSERTION_BORDER_HEIGHT, INSERTION_LINE_WIDTH, canvasWidth);
|
|
72
|
+
fillRect(ctx, xPos - INSERTION_BORDER_WIDTH, rowTop + h - INSERTION_LINE_WIDTH, INSERTION_BORDER_HEIGHT, INSERTION_LINE_WIDTH, canvasWidth);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Add insertion to spatial index with actual rendered dimensions
|
|
76
|
+
// Insertions always bypass distance filter
|
|
77
|
+
if (shouldAddToSpatialIndex(actualXPos, context, true)) {
|
|
78
|
+
addToSpatialIndex(context, createRenderedInsertion(actualXPos, rowTop, actualWidth, context, genomicOffset + alignmentStart, chr, sampleId, insertionSequence, featureId));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
genomicOffset++;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=insertions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insertions.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/rendering/insertions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RenderingContext } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Renders background rectangles for positions where alignment matches reference
|
|
4
|
+
* Only renders when showAllLetters is false
|
|
5
|
+
* @param context - Rendering context with canvas and styling info
|
|
6
|
+
* @param alignment - The aligned sequence for this sample
|
|
7
|
+
* @param seq - The reference sequence
|
|
8
|
+
* @param leftPx - Left pixel position of the feature
|
|
9
|
+
* @param rowTop - Top pixel position of the row
|
|
10
|
+
* @param alignmentStart - Start position of the alignment
|
|
11
|
+
* @param chr - Chromosome/sequence name
|
|
12
|
+
*/
|
|
13
|
+
export declare function renderMatches(context: RenderingContext, alignment: string, seq: string, leftPx: number, rowTop: number, sampleId: string, featureId: string, alignmentStart: number, chr: string): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { fillRect } from '../util';
|
|
2
|
+
import { addToSpatialIndex, createRenderedBase, shouldAddToSpatialIndex, } from './spatialIndex';
|
|
3
|
+
import { GAP_STROKE_OFFSET } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Renders background rectangles for positions where alignment matches reference
|
|
6
|
+
* Only renders when showAllLetters is false
|
|
7
|
+
* @param context - Rendering context with canvas and styling info
|
|
8
|
+
* @param alignment - The aligned sequence for this sample
|
|
9
|
+
* @param seq - The reference sequence
|
|
10
|
+
* @param leftPx - Left pixel position of the feature
|
|
11
|
+
* @param rowTop - Top pixel position of the row
|
|
12
|
+
* @param alignmentStart - Start position of the alignment
|
|
13
|
+
* @param chr - Chromosome/sequence name
|
|
14
|
+
*/
|
|
15
|
+
export function renderMatches(context, alignment, seq, leftPx, rowTop, sampleId, featureId, alignmentStart, chr) {
|
|
16
|
+
if (context.showAllLetters) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const { ctx, scale, h, canvasWidth } = context;
|
|
20
|
+
ctx.fillStyle = 'lightgrey';
|
|
21
|
+
// Highlight matching bases with light grey background
|
|
22
|
+
for (let i = 0, genomicOffset = 0, seqLength = alignment.length; i < seqLength; i++) {
|
|
23
|
+
if (seq[i] !== '-') {
|
|
24
|
+
// Only process non-gap positions in reference
|
|
25
|
+
const currentChar = alignment[i];
|
|
26
|
+
const xPos = leftPx + scale * genomicOffset;
|
|
27
|
+
if (seq[i] === currentChar &&
|
|
28
|
+
currentChar !== '-' &&
|
|
29
|
+
currentChar !== ' ') {
|
|
30
|
+
fillRect(ctx, xPos, rowTop, scale + GAP_STROKE_OFFSET, h, canvasWidth);
|
|
31
|
+
// Add to spatial index if distance filter allows
|
|
32
|
+
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
33
|
+
const renderedBase = createRenderedBase(xPos, rowTop, context, genomicOffset + alignmentStart, chr, sampleId, currentChar || '', true, false, false, false, featureId);
|
|
34
|
+
addToSpatialIndex(context, renderedBase);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
genomicOffset++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=matches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matches.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/rendering/matches.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI3C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAyB,EACzB,SAAiB,EACjB,GAAW,EACX,MAAc,EACd,MAAc,EACd,QAAgB,EAChB,SAAiB,EACjB,cAAsB,EACtB,GAAW;IAEX,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAM;IACR,CAAC;IAED,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAAA;IAC9C,GAAG,CAAC,SAAS,GAAG,WAAW,CAAA;IAE3B,sDAAsD;IACtD,KACE,IAAI,CAAC,GAAG,CAAC,EAAE,aAAa,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC,MAAM,EAC1D,CAAC,GAAG,SAAS,EACb,CAAC,EAAE,EACH,CAAC;QACD,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACnB,8CAA8C;YAC9C,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;YAChC,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,aAAa,CAAA;YAC3C,IACE,GAAG,CAAC,CAAC,CAAC,KAAK,WAAW;gBACtB,WAAW,KAAK,GAAG;gBACnB,WAAW,KAAK,GAAG,EACnB,CAAC;gBACD,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,GAAG,iBAAiB,EAAE,CAAC,EAAE,WAAW,CAAC,CAAA;gBAEtE,iDAAiD;gBACjD,IAAI,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;oBAC3C,MAAM,YAAY,GAAG,kBAAkB,CACrC,IAAI,EACJ,MAAM,EACN,OAAO,EACP,aAAa,GAAG,cAAc,EAC9B,GAAG,EACH,QAAQ,EACR,WAAW,IAAI,EAAE,EACjB,IAAI,EACJ,KAAK,EACL,KAAK,EACL,KAAK,EACL,SAAS,CACV,CAAA;oBACD,iBAAiB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;gBAC1C,CAAC;YACH,CAAC;YACD,aAAa,EAAE,CAAA;QACjB,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RenderingContext } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Renders colored rectangles for mismatches and matches (when showAllLetters is true)
|
|
4
|
+
* Colors are determined by base type when mismatchRendering is enabled
|
|
5
|
+
* @param context - Rendering context with canvas and styling info
|
|
6
|
+
* @param alignment - The aligned sequence for this sample
|
|
7
|
+
* @param seq - The reference sequence
|
|
8
|
+
* @param leftPx - Left pixel position of the feature
|
|
9
|
+
* @param rowTop - Top pixel position of the row
|
|
10
|
+
* @param alignmentStart - Start position of the alignment
|
|
11
|
+
* @param chr - Chromosome/sequence name
|
|
12
|
+
*/
|
|
13
|
+
export declare function renderMismatches(context: RenderingContext, alignment: string, seq: string, leftPx: number, rowTop: number, sampleId: string, featureId: string, alignmentStart: number, chr: string): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { fillRect } from '../util';
|
|
2
|
+
import { addToSpatialIndex, createRenderedBase, shouldAddToSpatialIndex, } from './spatialIndex';
|
|
3
|
+
import { GAP_STROKE_OFFSET } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Renders colored rectangles for mismatches and matches (when showAllLetters is true)
|
|
6
|
+
* Colors are determined by base type when mismatchRendering is enabled
|
|
7
|
+
* @param context - Rendering context with canvas and styling info
|
|
8
|
+
* @param alignment - The aligned sequence for this sample
|
|
9
|
+
* @param seq - The reference sequence
|
|
10
|
+
* @param leftPx - Left pixel position of the feature
|
|
11
|
+
* @param rowTop - Top pixel position of the row
|
|
12
|
+
* @param alignmentStart - Start position of the alignment
|
|
13
|
+
* @param chr - Chromosome/sequence name
|
|
14
|
+
*/
|
|
15
|
+
export function renderMismatches(context, alignment, seq, leftPx, rowTop, sampleId, featureId, alignmentStart, chr) {
|
|
16
|
+
const { ctx, scale, h, canvasWidth, showAllLetters, mismatchRendering, colorForBase, } = context;
|
|
17
|
+
for (let i = 0, genomicOffset = 0, seqLength = alignment.length; i < seqLength; i++) {
|
|
18
|
+
const currentChar = alignment[i];
|
|
19
|
+
if (seq[i] !== '-') {
|
|
20
|
+
if (currentChar !== '-') {
|
|
21
|
+
const xPos = leftPx + scale * genomicOffset;
|
|
22
|
+
if (seq[i] !== currentChar && currentChar !== ' ') {
|
|
23
|
+
// Mismatch: use base-specific color or orange
|
|
24
|
+
fillRect(ctx, xPos, rowTop, scale + GAP_STROKE_OFFSET, h, canvasWidth, mismatchRendering
|
|
25
|
+
? (colorForBase[currentChar] ?? 'black')
|
|
26
|
+
: 'orange');
|
|
27
|
+
// Add to spatial index if distance filter allows
|
|
28
|
+
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
29
|
+
addToSpatialIndex(context, createRenderedBase(xPos, rowTop, context, genomicOffset + alignmentStart, chr, sampleId, currentChar, false, true, false, false, featureId));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (showAllLetters) {
|
|
33
|
+
// Match (when showing all letters): use base-specific color or light blue
|
|
34
|
+
fillRect(ctx, xPos, rowTop, scale + GAP_STROKE_OFFSET, h, canvasWidth, mismatchRendering
|
|
35
|
+
? (colorForBase[currentChar] ?? 'black')
|
|
36
|
+
: 'lightblue');
|
|
37
|
+
// Add to spatial index if distance filter allows
|
|
38
|
+
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
39
|
+
addToSpatialIndex(context, createRenderedBase(xPos, rowTop, context, genomicOffset + alignmentStart, chr, sampleId, currentChar, true, false, false, false, featureId));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
genomicOffset++;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=mismatches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mismatches.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/rendering/mismatches.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI3C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAyB,EACzB,SAAiB,EACjB,GAAW,EACX,MAAc,EACd,MAAc,EACd,QAAgB,EAChB,SAAiB,EACjB,cAAsB,EACtB,GAAW;IAEX,MAAM,EACJ,GAAG,EACH,KAAK,EACL,CAAC,EACD,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,YAAY,GACb,GAAG,OAAO,CAAA;IAEX,KACE,IAAI,CAAC,GAAG,CAAC,EAAE,aAAa,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC,MAAM,EAC1D,CAAC,GAAG,SAAS,EACb,CAAC,EAAE,EACH,CAAC;QACD,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;QAChC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACnB,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;gBACxB,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,aAAa,CAAA;gBAC3C,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,WAAW,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;oBAClD,8CAA8C;oBAC9C,QAAQ,CACN,GAAG,EACH,IAAI,EACJ,MAAM,EACN,KAAK,GAAG,iBAAiB,EACzB,CAAC,EACD,WAAW,EACX,iBAAiB;wBACf,CAAC,CAAC,CAAC,YAAY,CAAC,WAAY,CAAC,IAAI,OAAO,CAAC;wBACzC,CAAC,CAAC,QAAQ,CACb,CAAA;oBAED,iDAAiD;oBACjD,IAAI,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;wBAC3C,iBAAiB,CACf,OAAO,EACP,kBAAkB,CAChB,IAAI,EACJ,MAAM,EACN,OAAO,EACP,aAAa,GAAG,cAAc,EAC9B,GAAG,EACH,QAAQ,EACR,WAAY,EACZ,KAAK,EACL,IAAI,EACJ,KAAK,EACL,KAAK,EACL,SAAS,CACV,CACF,CAAA;oBACH,CAAC;gBACH,CAAC;qBAAM,IAAI,cAAc,EAAE,CAAC;oBAC1B,0EAA0E;oBAC1E,QAAQ,CACN,GAAG,EACH,IAAI,EACJ,MAAM,EACN,KAAK,GAAG,iBAAiB,EACzB,CAAC,EACD,WAAW,EACX,iBAAiB;wBACf,CAAC,CAAC,CAAC,YAAY,CAAC,WAAY,CAAC,IAAI,OAAO,CAAC;wBACzC,CAAC,CAAC,WAAW,CAChB,CAAA;oBAED,iDAAiD;oBACjD,IAAI,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;wBAC3C,iBAAiB,CACf,OAAO,EACP,kBAAkB,CAChB,IAAI,EACJ,MAAM,EACN,OAAO,EACP,aAAa,GAAG,cAAc,EAC9B,GAAG,EACH,QAAQ,EACR,WAAY,EACZ,IAAI,EACJ,KAAK,EACL,KAAK,EACL,KAAK,EACL,SAAS,CACV,CACF,CAAA;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,aAAa,EAAE,CAAA;QACjB,CAAC;IACH,CAAC;AACH,CAAC"}
|