jbrowse-plugin-mafviewer 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -48
- 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 +9 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.js +1 -2
- package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -1
- package/dist/LinearMafRenderer/components/LinearMafRendering.d.ts +13 -0
- package/dist/LinearMafRenderer/components/LinearMafRendering.js +46 -0
- package/dist/LinearMafRenderer/components/LinearMafRendering.js.map +1 -0
- 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/index.js +1 -1
- package/dist/LinearMafRenderer/index.js.map +1 -1
- package/dist/LinearMafRenderer/makeImageData.d.ts +6 -5
- package/dist/LinearMafRenderer/makeImageData.js +35 -146
- package/dist/LinearMafRenderer/makeImageData.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/features.d.ts +4 -0
- package/dist/LinearMafRenderer/rendering/features.js +41 -0
- package/dist/LinearMafRenderer/rendering/features.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/gaps.d.ts +2 -0
- package/dist/LinearMafRenderer/rendering/gaps.js +19 -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 +2 -0
- package/dist/LinearMafRenderer/rendering/insertions.js +78 -0
- package/dist/LinearMafRenderer/rendering/insertions.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/matches.d.ts +2 -0
- package/dist/LinearMafRenderer/rendering/matches.js +34 -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 +57 -0
- package/dist/LinearMafRenderer/rendering/mismatches.js.map +1 -0
- package/dist/LinearMafRenderer/rendering/spatialIndex.d.ts +9 -0
- package/dist/LinearMafRenderer/rendering/spatialIndex.js +19 -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 +55 -0
- package/dist/LinearMafRenderer/rendering/types.js +15 -0
- package/dist/LinearMafRenderer/rendering/types.js.map +1 -0
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +37 -35
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js.map +1 -1
- package/dist/MafTabixAdapter/MafTabixAdapter.js +48 -22
- package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +5 -29
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
- package/dist/out.js +32310 -0
- package/dist/out.js.map +7 -0
- package/dist/util/fastaUtils.js.map +1 -1
- package/package.json +3 -2
- package/src/BigMafAdapter/BigMafAdapter.ts +49 -28
- 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/LinearMafRendering.tsx +76 -0
- package/src/LinearMafRenderer/components/util.ts +13 -0
- package/src/LinearMafRenderer/index.ts +1 -1
- package/src/LinearMafRenderer/makeImageData.ts +64 -196
- package/src/LinearMafRenderer/rendering/features.ts +111 -0
- package/src/LinearMafRenderer/rendering/gaps.ts +33 -0
- package/src/LinearMafRenderer/rendering/index.ts +9 -0
- package/src/LinearMafRenderer/rendering/insertions.ts +154 -0
- package/src/LinearMafRenderer/rendering/matches.ts +62 -0
- package/src/LinearMafRenderer/rendering/mismatches.ts +113 -0
- package/src/LinearMafRenderer/rendering/spatialIndex.ts +40 -0
- package/src/LinearMafRenderer/rendering/text.ts +72 -0
- package/src/LinearMafRenderer/rendering/types.ts +65 -0
- package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +5 -6
- package/src/MafTabixAdapter/MafTabixAdapter.ts +77 -22
- package/src/index.ts +0 -2
- package/src/util/fastaUtils.ts +2 -1
- package/src/BgzipTaffyAdapter/BgzipTaffyAdapter.ts +0 -307
- package/src/BgzipTaffyAdapter/configSchema.ts +0 -59
- package/src/BgzipTaffyAdapter/index.ts +0 -16
- package/src/BgzipTaffyAdapter/rowInstructions.ts +0 -91
- package/src/BgzipTaffyAdapter/types.ts +0 -16
- package/src/BgzipTaffyAdapter/util.ts +0 -25
- package/src/BgzipTaffyAdapter/virtualOffset.ts +0 -29
- package/src/LinearMafRenderer/components/ReactComponent.tsx +0 -13
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/components/util.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM,CAAI,GAAgB,EAAE,EAAsB;IAChE,IAAI,GAAG,GAAG,QAAQ,CAAA;IAClB,IAAI,UAAyB,CAAA;IAC7B,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;QAErB,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;YACd,GAAG,GAAG,GAAG,CAAA;YACT,UAAU,GAAG,KAAK,CAAA;QACpB,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import LinearMafRenderer from './LinearMafRenderer';
|
|
2
|
-
import ReactComponent from './components/
|
|
2
|
+
import ReactComponent from './components/LinearMafRendering';
|
|
3
3
|
import configSchema from './configSchema';
|
|
4
4
|
export default function LinearMafRendererF(pluginManager) {
|
|
5
5
|
pluginManager.addRendererType(() => new LinearMafRenderer({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/LinearMafRenderer/index.ts"],"names":[],"mappings":"AAEA,OAAO,iBAAiB,MAAM,qBAAqB,CAAA;AACnD,OAAO,cAAc,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/LinearMafRenderer/index.ts"],"names":[],"mappings":"AAEA,OAAO,iBAAiB,MAAM,qBAAqB,CAAA;AACnD,OAAO,cAAc,MAAM,iCAAiC,CAAA;AAC5D,OAAO,YAAY,MAAM,gBAAgB,CAAA;AAEzC,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,aAA4B;IACrE,aAAa,CAAC,eAAe,CAC3B,GAAG,EAAE,CACH,IAAI,iBAAiB,CAAC;QACpB,IAAI,EAAE,mBAAmB;QACzB,cAAc;QACd,YAAY;QACZ,aAAa;KACd,CAAC,CACL,CAAA;AACH,CAAC"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { RenderArgsDeserialized } from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType';
|
|
2
2
|
import { Feature } from '@jbrowse/core/util';
|
|
3
|
-
|
|
4
|
-
id: string;
|
|
5
|
-
color?: string;
|
|
6
|
-
}
|
|
3
|
+
import { Sample } from './rendering';
|
|
7
4
|
interface RenderArgs extends RenderArgsDeserialized {
|
|
8
5
|
samples: Sample[];
|
|
9
6
|
rowHeight: number;
|
|
@@ -17,5 +14,9 @@ interface RenderArgs extends RenderArgsDeserialized {
|
|
|
17
14
|
export declare function makeImageData({ ctx, renderArgs, }: {
|
|
18
15
|
ctx: CanvasRenderingContext2D;
|
|
19
16
|
renderArgs: RenderArgs;
|
|
20
|
-
}):
|
|
17
|
+
}): {
|
|
18
|
+
flatbush: ArrayBufferLike;
|
|
19
|
+
items: import("./rendering").RenderedBase[];
|
|
20
|
+
samples: Sample[];
|
|
21
|
+
};
|
|
21
22
|
export {};
|
|
@@ -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 Flatbush from 'flatbush';
|
|
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,45 @@ 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: [],
|
|
32
|
+
spatialIndexCoords: [],
|
|
33
|
+
lastInsertedX: -Infinity, // Start with -Infinity so first item is always inserted
|
|
34
|
+
};
|
|
35
|
+
// First pass: render alignments (gaps, matches, mismatches, text)
|
|
24
36
|
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
|
-
}
|
|
37
|
+
processFeatureAlignment(feature, region, bpPerPx, sampleToRowMap, renderingContext);
|
|
109
38
|
}
|
|
110
|
-
//
|
|
111
|
-
// insertions are always 'on top' of the other features
|
|
39
|
+
// Second pass: render insertions on top
|
|
112
40
|
for (const feature of features.values()) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
}
|
|
41
|
+
processFeatureInsertions(feature, region, bpPerPx, sampleToRowMap, renderingContext);
|
|
42
|
+
}
|
|
43
|
+
const flatbush = new Flatbush(renderingContext.spatialIndex.length);
|
|
44
|
+
for (let i = 0, l = renderingContext.spatialIndexCoords.length; i < l; i += 4) {
|
|
45
|
+
flatbush.add(renderingContext.spatialIndexCoords[i], renderingContext.spatialIndexCoords[i + 1], renderingContext.spatialIndexCoords[i + 2], renderingContext.spatialIndexCoords[i + 3]);
|
|
163
46
|
}
|
|
47
|
+
flatbush.finish();
|
|
48
|
+
return {
|
|
49
|
+
flatbush: flatbush.data,
|
|
50
|
+
items: renderingContext.spatialIndex,
|
|
51
|
+
samples,
|
|
52
|
+
};
|
|
164
53
|
}
|
|
165
54
|
//# 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":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Feature } from '@jbrowse/core/util';
|
|
2
|
+
import type { GenomicRegion, RenderingContext } from './types';
|
|
3
|
+
export declare function processFeatureAlignment(feature: Feature, region: GenomicRegion, bpPerPx: number, sampleToRowMap: Map<string, number>, renderingContext: RenderingContext): void;
|
|
4
|
+
export declare function processFeatureInsertions(feature: Feature, region: GenomicRegion, bpPerPx: number, sampleToRowMap: Map<string, number>, renderingContext: RenderingContext): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
export function processFeatureAlignment(feature, region, bpPerPx, sampleToRowMap, renderingContext) {
|
|
8
|
+
const [leftPx] = featureSpanPx(feature, region, bpPerPx);
|
|
9
|
+
const alignments = feature.get('alignments');
|
|
10
|
+
const referenceSeq = feature.get('seq').toLowerCase();
|
|
11
|
+
const featureId = feature.id() || `feature_${feature.get('start')}_${feature.get('end')}`;
|
|
12
|
+
for (const [sampleId, alignmentData] of Object.entries(alignments)) {
|
|
13
|
+
const row = sampleToRowMap.get(sampleId);
|
|
14
|
+
if (row === undefined) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const originalAlignment = alignmentData.seq;
|
|
18
|
+
const alignment = originalAlignment.toLowerCase();
|
|
19
|
+
const rowTop = renderingContext.offset + renderingContext.rowHeight * row;
|
|
20
|
+
renderGaps(renderingContext, alignment, referenceSeq, leftPx, rowTop);
|
|
21
|
+
renderMatches(renderingContext, alignment, referenceSeq, leftPx, rowTop, row, featureId, alignmentData.start, alignmentData.chr);
|
|
22
|
+
renderMismatches(renderingContext, alignment, referenceSeq, leftPx, rowTop, row, featureId, alignmentData.start, alignmentData.chr);
|
|
23
|
+
renderText(renderingContext, alignment, originalAlignment, referenceSeq, leftPx, rowTop, sampleId, featureId);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function processFeatureInsertions(feature, region, bpPerPx, sampleToRowMap, renderingContext) {
|
|
27
|
+
const [leftPx] = featureSpanPx(feature, region, bpPerPx);
|
|
28
|
+
const alignments = feature.get('alignments');
|
|
29
|
+
const referenceSeq = feature.get('seq').toLowerCase();
|
|
30
|
+
const featureId = feature.id() || `feature_${feature.get('start')}_${feature.get('end')}`;
|
|
31
|
+
for (const [sampleId, alignmentData] of Object.entries(alignments)) {
|
|
32
|
+
const row = sampleToRowMap.get(sampleId);
|
|
33
|
+
if (row === undefined) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const alignment = alignmentData.seq.toLowerCase();
|
|
37
|
+
const rowTop = renderingContext.offset + renderingContext.rowHeight * row;
|
|
38
|
+
renderInsertions(renderingContext, alignment, referenceSeq, leftPx, rowTop, bpPerPx, row, featureId, alignmentData.start, alignmentData.chr);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# 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,19 @@
|
|
|
1
|
+
import { GAP_STROKE_OFFSET } from './types';
|
|
2
|
+
export function renderGaps(context, alignment, seq, leftPx, rowTop) {
|
|
3
|
+
const { ctx, scale } = context;
|
|
4
|
+
const h2 = context.rowHeight / 2;
|
|
5
|
+
ctx.beginPath();
|
|
6
|
+
ctx.fillStyle = 'black';
|
|
7
|
+
for (let i = 0, genomicOffset = 0, seqLength = alignment.length; i < seqLength; i++) {
|
|
8
|
+
if (seq[i] !== '-') {
|
|
9
|
+
if (alignment[i] === '-') {
|
|
10
|
+
const xPos = leftPx + scale * genomicOffset;
|
|
11
|
+
ctx.moveTo(xPos, rowTop + h2);
|
|
12
|
+
ctx.lineTo(xPos + scale + GAP_STROKE_OFFSET, rowTop + h2);
|
|
13
|
+
}
|
|
14
|
+
genomicOffset++;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
ctx.stroke();
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=gaps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gaps.js","sourceRoot":"","sources":["../../../src/LinearMafRenderer/rendering/gaps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI3C,MAAM,UAAU,UAAU,CACxB,OAAyB,EACzB,SAAiB,EACjB,GAAW,EACX,MAAc,EACd,MAAc;IAEd,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;YAC3D,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,2 @@
|
|
|
1
|
+
import type { RenderingContext } from './types';
|
|
2
|
+
export declare function renderInsertions(context: RenderingContext, alignment: string, seq: string, leftPx: number, rowTop: number, bpPerPx: number, sampleId: number, _featureId: string, alignmentStart: number, chr: string): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { measureText } from '@jbrowse/core/util';
|
|
2
|
+
import { fillRect, getCharWidthHeight } from '../util';
|
|
3
|
+
import { addToSpatialIndex, 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
|
+
export function renderInsertions(context, alignment, seq, leftPx, rowTop, bpPerPx, sampleId, _featureId, alignmentStart, chr) {
|
|
6
|
+
const { ctx, scale, h, canvasWidth, rowHeight } = context;
|
|
7
|
+
const { charHeight } = getCharWidthHeight();
|
|
8
|
+
for (let i = 0, genomicOffset = 0, seqLength = alignment.length; i < seqLength; i++) {
|
|
9
|
+
let insertionSequence = '';
|
|
10
|
+
while (seq[i] === '-') {
|
|
11
|
+
if (alignment[i] !== '-' && alignment[i] !== ' ') {
|
|
12
|
+
insertionSequence += alignment[i];
|
|
13
|
+
}
|
|
14
|
+
i++;
|
|
15
|
+
}
|
|
16
|
+
if (insertionSequence.length > 0) {
|
|
17
|
+
// Found an insertion
|
|
18
|
+
const xPos = leftPx + scale * genomicOffset - INSERTION_LINE_WIDTH;
|
|
19
|
+
// Determine actual rendered width and position for spatial index
|
|
20
|
+
let actualXPos;
|
|
21
|
+
let actualWidth;
|
|
22
|
+
// Large insertions: show count instead of individual bases
|
|
23
|
+
if (insertionSequence.length > LARGE_INSERTION_THRESHOLD) {
|
|
24
|
+
const lengthText = `${insertionSequence.length}`;
|
|
25
|
+
if (bpPerPx > HIGH_BP_PER_PX_THRESHOLD) {
|
|
26
|
+
// Very zoomed out: simple line
|
|
27
|
+
actualXPos = xPos - INSERTION_LINE_WIDTH;
|
|
28
|
+
actualWidth = INSERTION_BORDER_WIDTH;
|
|
29
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
30
|
+
}
|
|
31
|
+
else if (h > charHeight) {
|
|
32
|
+
// Medium zoom: show count in colored box
|
|
33
|
+
const textWidth = measureText(lengthText, CHAR_SIZE_WIDTH);
|
|
34
|
+
const padding = INSERTION_PADDING;
|
|
35
|
+
actualXPos = xPos - textWidth / 2 - padding;
|
|
36
|
+
actualWidth = textWidth + 2 * padding;
|
|
37
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
38
|
+
ctx.fillStyle = 'white';
|
|
39
|
+
ctx.fillText(lengthText, xPos - textWidth / 2, rowTop + (h * 7) / 8);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const padding = INSERTION_PADDING;
|
|
43
|
+
actualXPos = xPos - padding;
|
|
44
|
+
actualWidth = 2 * padding;
|
|
45
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Small insertions: vertical line with optional border at high zoom
|
|
50
|
+
actualXPos = xPos;
|
|
51
|
+
actualWidth = INSERTION_LINE_WIDTH;
|
|
52
|
+
fillRect(ctx, actualXPos, rowTop, actualWidth, h, canvasWidth, 'purple');
|
|
53
|
+
if (bpPerPx < HIGH_ZOOM_THRESHOLD &&
|
|
54
|
+
rowHeight > MIN_ROW_HEIGHT_FOR_BORDERS) {
|
|
55
|
+
// Add horizontal borders for visibility at high zoom
|
|
56
|
+
// Note: borders extend the effective clickable area
|
|
57
|
+
actualXPos = xPos - INSERTION_BORDER_WIDTH;
|
|
58
|
+
actualWidth = INSERTION_BORDER_HEIGHT;
|
|
59
|
+
fillRect(ctx, xPos - INSERTION_BORDER_WIDTH, rowTop, INSERTION_BORDER_HEIGHT, INSERTION_LINE_WIDTH, canvasWidth);
|
|
60
|
+
fillRect(ctx, xPos - INSERTION_BORDER_WIDTH, rowTop + h - INSERTION_LINE_WIDTH, INSERTION_BORDER_HEIGHT, INSERTION_LINE_WIDTH, canvasWidth);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Add insertion to spatial index with actual rendered dimensions
|
|
64
|
+
// Insertions always bypass distance filter
|
|
65
|
+
if (shouldAddToSpatialIndex(actualXPos, context, true)) {
|
|
66
|
+
addToSpatialIndex(context, actualXPos, rowTop, actualXPos + actualWidth, rowTop + context.h, {
|
|
67
|
+
pos: genomicOffset + alignmentStart,
|
|
68
|
+
chr,
|
|
69
|
+
base: insertionSequence,
|
|
70
|
+
sampleId,
|
|
71
|
+
isInsertion: true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
genomicOffset++;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# 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,34 @@
|
|
|
1
|
+
import { fillRect } from '../util';
|
|
2
|
+
import { addToSpatialIndex, shouldAddToSpatialIndex } from './spatialIndex';
|
|
3
|
+
import { GAP_STROKE_OFFSET } from './types';
|
|
4
|
+
export function renderMatches(context, alignment, seq, leftPx, rowTop, sampleId, _featureId, alignmentStart, chr) {
|
|
5
|
+
if (context.showAllLetters) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const { ctx, scale, h, canvasWidth } = context;
|
|
9
|
+
ctx.fillStyle = 'lightgrey';
|
|
10
|
+
// Highlight matching bases with light grey background
|
|
11
|
+
for (let i = 0, genomicOffset = 0, seqLength = alignment.length; i < seqLength; i++) {
|
|
12
|
+
if (seq[i] !== '-') {
|
|
13
|
+
// Only process non-gap positions in reference
|
|
14
|
+
const currentChar = alignment[i];
|
|
15
|
+
const xPos = leftPx + scale * genomicOffset;
|
|
16
|
+
if (seq[i] === currentChar &&
|
|
17
|
+
currentChar !== '-' &&
|
|
18
|
+
currentChar !== ' ') {
|
|
19
|
+
fillRect(ctx, xPos, rowTop, scale + GAP_STROKE_OFFSET, h, canvasWidth);
|
|
20
|
+
// Add to spatial index if distance filter allows
|
|
21
|
+
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
22
|
+
addToSpatialIndex(context, xPos, rowTop, xPos + context.scale + GAP_STROKE_OFFSET, rowTop + context.h, {
|
|
23
|
+
pos: genomicOffset + alignmentStart,
|
|
24
|
+
chr,
|
|
25
|
+
base: currentChar || '',
|
|
26
|
+
sampleId,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
genomicOffset++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# 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,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAI3C,MAAM,UAAU,aAAa,CAC3B,OAAyB,EACzB,SAAiB,EACjB,GAAW,EACX,MAAc,EACd,MAAc,EACd,QAAgB,EAChB,UAAkB,EAClB,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,iBAAiB,CACf,OAAO,EACP,IAAI,EACJ,MAAM,EACN,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,iBAAiB,EACxC,MAAM,GAAG,OAAO,CAAC,CAAC,EAClB;wBACE,GAAG,EAAE,aAAa,GAAG,cAAc;wBACnC,GAAG;wBACH,IAAI,EAAE,WAAW,IAAI,EAAE;wBACvB,QAAQ;qBACT,CACF,CAAA;gBACH,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: number, _featureId: string, alignmentStart: number, chr: string): void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { fillRect } from '../util';
|
|
2
|
+
import { addToSpatialIndex, 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, xPos, rowTop, xPos + context.scale + GAP_STROKE_OFFSET, rowTop + context.h, {
|
|
30
|
+
pos: genomicOffset + alignmentStart,
|
|
31
|
+
chr,
|
|
32
|
+
base: currentChar,
|
|
33
|
+
sampleId: i,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (showAllLetters) {
|
|
38
|
+
// Match (when showing all letters): use base-specific color or light blue
|
|
39
|
+
fillRect(ctx, xPos, rowTop, scale + GAP_STROKE_OFFSET, h, canvasWidth, mismatchRendering
|
|
40
|
+
? (colorForBase[currentChar] ?? 'black')
|
|
41
|
+
: 'lightblue');
|
|
42
|
+
// Add to spatial index if distance filter allows
|
|
43
|
+
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
44
|
+
addToSpatialIndex(context, xPos, rowTop, xPos + context.scale + GAP_STROKE_OFFSET, rowTop + context.h, {
|
|
45
|
+
pos: genomicOffset + alignmentStart,
|
|
46
|
+
chr,
|
|
47
|
+
base: currentChar,
|
|
48
|
+
sampleId,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
genomicOffset++;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# 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,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAC3E,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,UAAkB,EAClB,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,IAAI,EACJ,MAAM,EACN,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,iBAAiB,EACxC,MAAM,GAAG,OAAO,CAAC,CAAC,EAClB;4BACE,GAAG,EAAE,aAAa,GAAG,cAAc;4BACnC,GAAG;4BACH,IAAI,EAAE,WAAY;4BAClB,QAAQ,EAAE,CAAC;yBACZ,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,IAAI,EACJ,MAAM,EACN,IAAI,GAAG,OAAO,CAAC,KAAK,GAAG,iBAAiB,EACxC,MAAM,GAAG,OAAO,CAAC,CAAC,EAClB;4BACE,GAAG,EAAE,aAAa,GAAG,cAAc;4BACnC,GAAG;4BACH,IAAI,EAAE,WAAY;4BAClB,QAAQ;yBACT,CACF,CAAA;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,aAAa,EAAE,CAAA;QACjB,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RenderedBase, RenderingContext } from './types';
|
|
2
|
+
export declare function createRenderedBaseCoords(xPos: number, rowTop: number, context: RenderingContext): {
|
|
3
|
+
minX: number;
|
|
4
|
+
minY: number;
|
|
5
|
+
maxX: number;
|
|
6
|
+
maxY: number;
|
|
7
|
+
};
|
|
8
|
+
export declare function shouldAddToSpatialIndex(xPos: number, context: RenderingContext, bypassDistanceFilter?: boolean): boolean;
|
|
9
|
+
export declare function addToSpatialIndex(context: RenderingContext, minX: number, minY: number, maxX: number, maxY: number, renderedBase: RenderedBase): void;
|