jbrowse-plugin-mafviewer 1.3.2 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -47
- package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +9 -3
- package/dist/LinearMafRenderer/components/LinearMafRendering.d.ts +13 -0
- package/dist/LinearMafRenderer/components/LinearMafRendering.js +47 -0
- package/dist/LinearMafRenderer/components/LinearMafRendering.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 +3 -1
- package/dist/LinearMafRenderer/makeImageData.js +11 -4
- package/dist/LinearMafRenderer/makeImageData.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/features.d.ts +0 -17
- package/dist/LinearMafRenderer/rendering/features.js +5 -24
- package/dist/LinearMafRenderer/rendering/features.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/gaps.d.ts +1 -11
- package/dist/LinearMafRenderer/rendering/gaps.js +1 -17
- package/dist/LinearMafRenderer/rendering/gaps.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/insertions.d.ts +1 -13
- package/dist/LinearMafRenderer/rendering/insertions.js +9 -15
- package/dist/LinearMafRenderer/rendering/insertions.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/matches.d.ts +1 -12
- package/dist/LinearMafRenderer/rendering/matches.js +8 -15
- package/dist/LinearMafRenderer/rendering/matches.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/mismatches.d.ts +1 -1
- package/dist/LinearMafRenderer/rendering/mismatches.js +14 -4
- package/dist/LinearMafRenderer/rendering/mismatches.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/spatialIndex.d.ts +7 -58
- package/dist/LinearMafRenderer/rendering/spatialIndex.js +5 -85
- package/dist/LinearMafRenderer/rendering/spatialIndex.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/text.d.ts +1 -1
- package/dist/LinearMafRenderer/rendering/text.js +1 -1
- package/dist/LinearMafRenderer/rendering/text.js.map +1 -1
- package/dist/LinearMafRenderer/rendering/types.d.ts +4 -16
- package/dist/LinearMafRenderer/rendering/types.js.map +1 -1
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +37 -35
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.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 -28
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
- package/dist/out.js +13356 -15572
- package/dist/out.js.map +4 -4
- package/package.json +3 -4
- package/src/LinearMafRenderer/components/{ReactComponent.tsx → LinearMafRendering.tsx} +17 -21
- package/src/LinearMafRenderer/index.ts +1 -1
- package/src/LinearMafRenderer/makeImageData.ts +20 -5
- package/src/LinearMafRenderer/rendering/features.ts +4 -41
- package/src/LinearMafRenderer/rendering/gaps.ts +0 -38
- package/src/LinearMafRenderer/rendering/insertions.ts +11 -28
- package/src/LinearMafRenderer/rendering/matches.ts +12 -30
- package/src/LinearMafRenderer/rendering/mismatches.ts +18 -31
- package/src/LinearMafRenderer/rendering/spatialIndex.ts +9 -105
- package/src/LinearMafRenderer/rendering/text.ts +0 -2
- package/src/LinearMafRenderer/rendering/types.ts +4 -20
- package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +5 -6
- package/src/index.ts +0 -2
- 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/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.4.1",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "jbrowse-plugin-mafviewer",
|
|
5
5
|
"keywords": [
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"@types/d3-array": "^3.2.1",
|
|
39
39
|
"@types/d3-hierarchy": "^3.1.7",
|
|
40
40
|
"@types/node": "^22.15.16",
|
|
41
|
-
"@types/rbush": "^4.0.0",
|
|
42
41
|
"@types/react": "^19.0.1",
|
|
43
42
|
"chalk": "^5.3.0",
|
|
44
43
|
"esbuild": "^0.25.0",
|
|
@@ -69,8 +68,8 @@
|
|
|
69
68
|
"d3-array": "^3.2.4",
|
|
70
69
|
"d3-hierarchy": "^3.1.2",
|
|
71
70
|
"fast-deep-equal": "^3.1.3",
|
|
71
|
+
"flatbush": "^4.4.1",
|
|
72
72
|
"generic-filehandle2": "^2.0.1",
|
|
73
|
-
"long": "^5.2.3"
|
|
74
|
-
"rbush": "^4.0.1"
|
|
73
|
+
"long": "^5.2.3"
|
|
75
74
|
}
|
|
76
75
|
}
|
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
import React, { useMemo, useRef } from 'react'
|
|
2
2
|
|
|
3
3
|
import { PrerenderedCanvas } from '@jbrowse/core/ui'
|
|
4
|
+
import Flatbush from 'flatbush'
|
|
4
5
|
import { observer } from 'mobx-react'
|
|
5
|
-
import
|
|
6
|
+
import { RenderedBase } from '../rendering'
|
|
7
|
+
import { Sample } from '../../LinearMafDisplay/types'
|
|
6
8
|
|
|
7
9
|
type SerializedRBush = any
|
|
8
10
|
|
|
9
|
-
interface RBushData {
|
|
10
|
-
minX: number
|
|
11
|
-
maxX: number
|
|
12
|
-
minY: number
|
|
13
|
-
maxY: number
|
|
14
|
-
isInsertion: boolean
|
|
15
|
-
}
|
|
16
11
|
const LinearMafRendering = observer(function (props: {
|
|
17
12
|
width: number
|
|
18
13
|
height: number
|
|
19
14
|
displayModel: any
|
|
20
|
-
|
|
15
|
+
flatbush: SerializedRBush
|
|
16
|
+
items: RenderedBase[]
|
|
17
|
+
samples: Sample[]
|
|
21
18
|
}) {
|
|
22
|
-
const { displayModel, height,
|
|
19
|
+
const { items, displayModel, height, samples, flatbush } = props
|
|
23
20
|
const ref = useRef<HTMLDivElement>(null)
|
|
24
|
-
const rbush2 = useMemo(() =>
|
|
21
|
+
const rbush2 = useMemo(() => Flatbush.from(flatbush), [flatbush])
|
|
25
22
|
|
|
26
23
|
function getFeatureUnderMouse(eventClientX: number, eventClientY: number) {
|
|
27
24
|
let offsetX = 0
|
|
@@ -32,17 +29,16 @@ const LinearMafRendering = observer(function (props: {
|
|
|
32
29
|
offsetY = eventClientY - r.top
|
|
33
30
|
}
|
|
34
31
|
|
|
35
|
-
const x = rbush2.search(
|
|
36
|
-
minX: offsetX,
|
|
37
|
-
maxX: offsetX + 1,
|
|
38
|
-
minY: offsetY,
|
|
39
|
-
maxY: offsetY + 1,
|
|
40
|
-
})
|
|
32
|
+
const x = rbush2.search(offsetX, offsetY, offsetX + 1, offsetY + 1)
|
|
41
33
|
if (x.length) {
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
const elt = x.find(idx => items[idx]?.isInsertion)
|
|
35
|
+
const r = elt !== undefined ? items[elt]! : items[x[0]!]!
|
|
36
|
+
console.log({ x, r })
|
|
37
|
+
const s = samples[r.sampleId]
|
|
38
|
+
return {
|
|
39
|
+
...r,
|
|
40
|
+
sampleId: s?.label || s?.id || 'unknown',
|
|
41
|
+
}
|
|
46
42
|
} else {
|
|
47
43
|
return undefined
|
|
48
44
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
2
|
|
|
3
3
|
import LinearMafRenderer from './LinearMafRenderer'
|
|
4
|
-
import ReactComponent from './components/
|
|
4
|
+
import ReactComponent from './components/LinearMafRendering'
|
|
5
5
|
import configSchema from './configSchema'
|
|
6
6
|
|
|
7
7
|
export default function LinearMafRendererF(pluginManager: PluginManager) {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { RenderArgsDeserialized } from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType'
|
|
2
2
|
import { createJBrowseTheme } from '@jbrowse/core/ui'
|
|
3
3
|
import { Feature } from '@jbrowse/core/util'
|
|
4
|
-
import
|
|
4
|
+
import Flatbush from 'flatbush'
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
FONT_CONFIG,
|
|
8
|
-
RenderedBase,
|
|
9
8
|
RenderingContext,
|
|
10
9
|
Sample,
|
|
11
10
|
processFeatureAlignment,
|
|
@@ -70,7 +69,8 @@ export function makeImageData({
|
|
|
70
69
|
showAllLetters,
|
|
71
70
|
mismatchRendering,
|
|
72
71
|
showAsUpperCase,
|
|
73
|
-
spatialIndex:
|
|
72
|
+
spatialIndex: [],
|
|
73
|
+
spatialIndexCoords: [],
|
|
74
74
|
lastInsertedX: -Infinity, // Start with -Infinity so first item is always inserted
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -96,8 +96,23 @@ export function makeImageData({
|
|
|
96
96
|
)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
const flatbush = new Flatbush(renderingContext.spatialIndex.length)
|
|
100
|
+
for (
|
|
101
|
+
let i = 0, l = renderingContext.spatialIndexCoords.length;
|
|
102
|
+
i < l;
|
|
103
|
+
i += 4
|
|
104
|
+
) {
|
|
105
|
+
flatbush.add(
|
|
106
|
+
renderingContext.spatialIndexCoords[i]!,
|
|
107
|
+
renderingContext.spatialIndexCoords[i + 1]!,
|
|
108
|
+
renderingContext.spatialIndexCoords[i + 2]!,
|
|
109
|
+
renderingContext.spatialIndexCoords[i + 3]!,
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
flatbush.finish()
|
|
100
113
|
return {
|
|
101
|
-
|
|
114
|
+
flatbush: flatbush.data,
|
|
115
|
+
items: renderingContext.spatialIndex,
|
|
116
|
+
samples,
|
|
102
117
|
}
|
|
103
118
|
}
|
|
@@ -8,14 +8,6 @@ import { renderText } from './text'
|
|
|
8
8
|
|
|
9
9
|
import type { AlignmentRecord, GenomicRegion, RenderingContext } from './types'
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Processes alignment data for a single feature, rendering gaps, matches, mismatches, and text
|
|
13
|
-
* @param feature - JBrowse feature containing alignment data
|
|
14
|
-
* @param region - Genomic region being rendered
|
|
15
|
-
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
16
|
-
* @param sampleToRowMap - Maps sample IDs to row indices
|
|
17
|
-
* @param renderingContext - Shared rendering parameters
|
|
18
|
-
*/
|
|
19
11
|
export function processFeatureAlignment(
|
|
20
12
|
feature: Feature,
|
|
21
13
|
region: GenomicRegion,
|
|
@@ -29,8 +21,6 @@ export function processFeatureAlignment(
|
|
|
29
21
|
AlignmentRecord
|
|
30
22
|
>
|
|
31
23
|
const referenceSeq = feature.get('seq').toLowerCase()
|
|
32
|
-
const featureId =
|
|
33
|
-
feature.id() || `feature_${feature.get('start')}_${feature.get('end')}`
|
|
34
24
|
|
|
35
25
|
for (const [sampleId, alignmentData] of Object.entries(alignments)) {
|
|
36
26
|
const row = sampleToRowMap.get(sampleId)
|
|
@@ -42,25 +32,14 @@ export function processFeatureAlignment(
|
|
|
42
32
|
const alignment = originalAlignment.toLowerCase()
|
|
43
33
|
const rowTop = renderingContext.offset + renderingContext.rowHeight * row
|
|
44
34
|
|
|
45
|
-
renderGaps(
|
|
46
|
-
renderingContext,
|
|
47
|
-
alignment,
|
|
48
|
-
referenceSeq,
|
|
49
|
-
leftPx,
|
|
50
|
-
rowTop,
|
|
51
|
-
sampleId,
|
|
52
|
-
featureId,
|
|
53
|
-
alignmentData.start,
|
|
54
|
-
alignmentData.chr,
|
|
55
|
-
)
|
|
35
|
+
renderGaps(renderingContext, alignment, referenceSeq, leftPx, rowTop)
|
|
56
36
|
renderMatches(
|
|
57
37
|
renderingContext,
|
|
58
38
|
alignment,
|
|
59
39
|
referenceSeq,
|
|
60
40
|
leftPx,
|
|
61
41
|
rowTop,
|
|
62
|
-
|
|
63
|
-
featureId,
|
|
42
|
+
row,
|
|
64
43
|
alignmentData.start,
|
|
65
44
|
alignmentData.chr,
|
|
66
45
|
)
|
|
@@ -70,8 +49,7 @@ export function processFeatureAlignment(
|
|
|
70
49
|
referenceSeq,
|
|
71
50
|
leftPx,
|
|
72
51
|
rowTop,
|
|
73
|
-
|
|
74
|
-
featureId,
|
|
52
|
+
row,
|
|
75
53
|
alignmentData.start,
|
|
76
54
|
alignmentData.chr,
|
|
77
55
|
)
|
|
@@ -82,21 +60,10 @@ export function processFeatureAlignment(
|
|
|
82
60
|
referenceSeq,
|
|
83
61
|
leftPx,
|
|
84
62
|
rowTop,
|
|
85
|
-
sampleId,
|
|
86
|
-
featureId,
|
|
87
63
|
)
|
|
88
64
|
}
|
|
89
65
|
}
|
|
90
66
|
|
|
91
|
-
/**
|
|
92
|
-
* Processes insertion data for a single feature in a separate pass
|
|
93
|
-
* Insertions are rendered on top to ensure visibility
|
|
94
|
-
* @param feature - JBrowse feature containing alignment data
|
|
95
|
-
* @param region - Genomic region being rendered
|
|
96
|
-
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
97
|
-
* @param sampleToRowMap - Maps sample IDs to row indices
|
|
98
|
-
* @param renderingContext - Shared rendering parameters
|
|
99
|
-
*/
|
|
100
67
|
export function processFeatureInsertions(
|
|
101
68
|
feature: Feature,
|
|
102
69
|
region: GenomicRegion,
|
|
@@ -110,9 +77,6 @@ export function processFeatureInsertions(
|
|
|
110
77
|
AlignmentRecord
|
|
111
78
|
>
|
|
112
79
|
const referenceSeq = feature.get('seq').toLowerCase()
|
|
113
|
-
const featureId =
|
|
114
|
-
feature.id() || `feature_${feature.get('start')}_${feature.get('end')}`
|
|
115
|
-
|
|
116
80
|
for (const [sampleId, alignmentData] of Object.entries(alignments)) {
|
|
117
81
|
const row = sampleToRowMap.get(sampleId)
|
|
118
82
|
if (row === undefined) {
|
|
@@ -129,8 +93,7 @@ export function processFeatureInsertions(
|
|
|
129
93
|
leftPx,
|
|
130
94
|
rowTop,
|
|
131
95
|
bpPerPx,
|
|
132
|
-
|
|
133
|
-
featureId,
|
|
96
|
+
row,
|
|
134
97
|
alignmentData.start,
|
|
135
98
|
alignmentData.chr,
|
|
136
99
|
)
|
|
@@ -1,32 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
addToSpatialIndex,
|
|
3
|
-
createRenderedBase,
|
|
4
|
-
shouldAddToSpatialIndex,
|
|
5
|
-
} from './spatialIndex'
|
|
6
1
|
import { GAP_STROKE_OFFSET } from './types'
|
|
7
2
|
|
|
8
3
|
import type { RenderingContext } from './types'
|
|
9
4
|
|
|
10
|
-
/**
|
|
11
|
-
* Renders gap indicators (horizontal lines) where the alignment has deletions relative to reference
|
|
12
|
-
* @param context - Rendering context with canvas and styling info
|
|
13
|
-
* @param alignment - The aligned sequence for this sample
|
|
14
|
-
* @param seq - The reference sequence
|
|
15
|
-
* @param leftPx - Left pixel position of the feature
|
|
16
|
-
* @param rowTop - Top pixel position of the row
|
|
17
|
-
* @param alignmentStart - Start position of the alignment
|
|
18
|
-
* @param chr - Chromosome/sequence name
|
|
19
|
-
*/
|
|
20
5
|
export function renderGaps(
|
|
21
6
|
context: RenderingContext,
|
|
22
7
|
alignment: string,
|
|
23
8
|
seq: string,
|
|
24
9
|
leftPx: number,
|
|
25
10
|
rowTop: number,
|
|
26
|
-
sampleId: string,
|
|
27
|
-
featureId: string,
|
|
28
|
-
alignmentStart: number,
|
|
29
|
-
chr: string,
|
|
30
11
|
) {
|
|
31
12
|
const { ctx, scale } = context
|
|
32
13
|
const h2 = context.rowHeight / 2
|
|
@@ -44,25 +25,6 @@ export function renderGaps(
|
|
|
44
25
|
const xPos = leftPx + scale * genomicOffset
|
|
45
26
|
ctx.moveTo(xPos, rowTop + h2)
|
|
46
27
|
ctx.lineTo(xPos + scale + GAP_STROKE_OFFSET, rowTop + h2)
|
|
47
|
-
|
|
48
|
-
// Add to spatial index if distance filter allows
|
|
49
|
-
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
50
|
-
const renderedBase = createRenderedBase(
|
|
51
|
-
xPos,
|
|
52
|
-
rowTop,
|
|
53
|
-
context,
|
|
54
|
-
genomicOffset + alignmentStart,
|
|
55
|
-
chr,
|
|
56
|
-
sampleId,
|
|
57
|
-
'-',
|
|
58
|
-
false,
|
|
59
|
-
false,
|
|
60
|
-
true,
|
|
61
|
-
false,
|
|
62
|
-
featureId,
|
|
63
|
-
)
|
|
64
|
-
addToSpatialIndex(context, renderedBase)
|
|
65
|
-
}
|
|
66
28
|
}
|
|
67
29
|
genomicOffset++
|
|
68
30
|
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { measureText } from '@jbrowse/core/util'
|
|
2
2
|
|
|
3
3
|
import { fillRect, getCharWidthHeight } from '../util'
|
|
4
|
-
import {
|
|
5
|
-
addToSpatialIndex,
|
|
6
|
-
createRenderedInsertion,
|
|
7
|
-
shouldAddToSpatialIndex,
|
|
8
|
-
} from './spatialIndex'
|
|
4
|
+
import { addToSpatialIndex, shouldAddToSpatialIndex } from './spatialIndex'
|
|
9
5
|
import {
|
|
10
6
|
CHAR_SIZE_WIDTH,
|
|
11
7
|
HIGH_BP_PER_PX_THRESHOLD,
|
|
@@ -20,18 +16,6 @@ import {
|
|
|
20
16
|
|
|
21
17
|
import type { RenderingContext } from './types'
|
|
22
18
|
|
|
23
|
-
/**
|
|
24
|
-
* Renders insertion markers where the alignment has bases not present in reference
|
|
25
|
-
* Large insertions show count, small ones show as colored bars with optional borders
|
|
26
|
-
* @param context - Rendering context with canvas and styling info
|
|
27
|
-
* @param alignment - The aligned sequence for this sample
|
|
28
|
-
* @param seq - The reference sequence
|
|
29
|
-
* @param leftPx - Left pixel position of the feature
|
|
30
|
-
* @param rowTop - Top pixel position of the row
|
|
31
|
-
* @param bpPerPx - Base pairs per pixel (zoom level)
|
|
32
|
-
* @param alignmentStart - Start position of the alignment
|
|
33
|
-
* @param chr - Chromosome/sequence name
|
|
34
|
-
*/
|
|
35
19
|
export function renderInsertions(
|
|
36
20
|
context: RenderingContext,
|
|
37
21
|
alignment: string,
|
|
@@ -39,8 +23,7 @@ export function renderInsertions(
|
|
|
39
23
|
leftPx: number,
|
|
40
24
|
rowTop: number,
|
|
41
25
|
bpPerPx: number,
|
|
42
|
-
sampleId:
|
|
43
|
-
featureId: string,
|
|
26
|
+
sampleId: number,
|
|
44
27
|
alignmentStart: number,
|
|
45
28
|
chr: string,
|
|
46
29
|
) {
|
|
@@ -151,17 +134,17 @@ export function renderInsertions(
|
|
|
151
134
|
if (shouldAddToSpatialIndex(actualXPos, context, true)) {
|
|
152
135
|
addToSpatialIndex(
|
|
153
136
|
context,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
genomicOffset + alignmentStart,
|
|
137
|
+
actualXPos,
|
|
138
|
+
rowTop,
|
|
139
|
+
actualXPos + actualWidth,
|
|
140
|
+
rowTop + context.h,
|
|
141
|
+
{
|
|
142
|
+
pos: genomicOffset + alignmentStart,
|
|
160
143
|
chr,
|
|
144
|
+
base: insertionSequence,
|
|
161
145
|
sampleId,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
),
|
|
146
|
+
isInsertion: true,
|
|
147
|
+
},
|
|
165
148
|
)
|
|
166
149
|
}
|
|
167
150
|
}
|
|
@@ -1,32 +1,16 @@
|
|
|
1
1
|
import { fillRect } from '../util'
|
|
2
|
-
import {
|
|
3
|
-
addToSpatialIndex,
|
|
4
|
-
createRenderedBase,
|
|
5
|
-
shouldAddToSpatialIndex,
|
|
6
|
-
} from './spatialIndex'
|
|
2
|
+
import { addToSpatialIndex, shouldAddToSpatialIndex } from './spatialIndex'
|
|
7
3
|
import { GAP_STROKE_OFFSET } from './types'
|
|
8
4
|
|
|
9
5
|
import type { RenderingContext } from './types'
|
|
10
6
|
|
|
11
|
-
/**
|
|
12
|
-
* Renders background rectangles for positions where alignment matches reference
|
|
13
|
-
* Only renders when showAllLetters is false
|
|
14
|
-
* @param context - Rendering context with canvas and styling info
|
|
15
|
-
* @param alignment - The aligned sequence for this sample
|
|
16
|
-
* @param seq - The reference sequence
|
|
17
|
-
* @param leftPx - Left pixel position of the feature
|
|
18
|
-
* @param rowTop - Top pixel position of the row
|
|
19
|
-
* @param alignmentStart - Start position of the alignment
|
|
20
|
-
* @param chr - Chromosome/sequence name
|
|
21
|
-
*/
|
|
22
7
|
export function renderMatches(
|
|
23
8
|
context: RenderingContext,
|
|
24
9
|
alignment: string,
|
|
25
10
|
seq: string,
|
|
26
11
|
leftPx: number,
|
|
27
12
|
rowTop: number,
|
|
28
|
-
sampleId:
|
|
29
|
-
featureId: string,
|
|
13
|
+
sampleId: number,
|
|
30
14
|
alignmentStart: number,
|
|
31
15
|
chr: string,
|
|
32
16
|
) {
|
|
@@ -56,21 +40,19 @@ export function renderMatches(
|
|
|
56
40
|
|
|
57
41
|
// Add to spatial index if distance filter allows
|
|
58
42
|
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
59
|
-
|
|
43
|
+
addToSpatialIndex(
|
|
44
|
+
context,
|
|
60
45
|
xPos,
|
|
61
46
|
rowTop,
|
|
62
|
-
context,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
false,
|
|
71
|
-
featureId,
|
|
47
|
+
xPos + context.scale + GAP_STROKE_OFFSET,
|
|
48
|
+
rowTop + context.h,
|
|
49
|
+
{
|
|
50
|
+
pos: genomicOffset + alignmentStart,
|
|
51
|
+
chr,
|
|
52
|
+
base: currentChar || '',
|
|
53
|
+
sampleId,
|
|
54
|
+
},
|
|
72
55
|
)
|
|
73
|
-
addToSpatialIndex(context, renderedBase)
|
|
74
56
|
}
|
|
75
57
|
}
|
|
76
58
|
genomicOffset++
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { fillRect } from '../util'
|
|
2
|
-
import {
|
|
3
|
-
addToSpatialIndex,
|
|
4
|
-
createRenderedBase,
|
|
5
|
-
shouldAddToSpatialIndex,
|
|
6
|
-
} from './spatialIndex'
|
|
2
|
+
import { addToSpatialIndex, shouldAddToSpatialIndex } from './spatialIndex'
|
|
7
3
|
import { GAP_STROKE_OFFSET } from './types'
|
|
8
4
|
|
|
9
5
|
import type { RenderingContext } from './types'
|
|
@@ -25,8 +21,7 @@ export function renderMismatches(
|
|
|
25
21
|
seq: string,
|
|
26
22
|
leftPx: number,
|
|
27
23
|
rowTop: number,
|
|
28
|
-
sampleId:
|
|
29
|
-
featureId: string,
|
|
24
|
+
sampleId: number,
|
|
30
25
|
alignmentStart: number,
|
|
31
26
|
chr: string,
|
|
32
27
|
) {
|
|
@@ -67,20 +62,16 @@ export function renderMismatches(
|
|
|
67
62
|
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
68
63
|
addToSpatialIndex(
|
|
69
64
|
context,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
xPos,
|
|
66
|
+
rowTop,
|
|
67
|
+
xPos + context.scale + GAP_STROKE_OFFSET,
|
|
68
|
+
rowTop + context.h,
|
|
69
|
+
{
|
|
70
|
+
pos: genomicOffset + alignmentStart,
|
|
75
71
|
chr,
|
|
72
|
+
base: currentChar!,
|
|
76
73
|
sampleId,
|
|
77
|
-
|
|
78
|
-
false,
|
|
79
|
-
true,
|
|
80
|
-
false,
|
|
81
|
-
false,
|
|
82
|
-
featureId,
|
|
83
|
-
),
|
|
74
|
+
},
|
|
84
75
|
)
|
|
85
76
|
}
|
|
86
77
|
} else if (showAllLetters) {
|
|
@@ -101,20 +92,16 @@ export function renderMismatches(
|
|
|
101
92
|
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
102
93
|
addToSpatialIndex(
|
|
103
94
|
context,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
95
|
+
xPos,
|
|
96
|
+
rowTop,
|
|
97
|
+
xPos + context.scale + GAP_STROKE_OFFSET,
|
|
98
|
+
rowTop + context.h,
|
|
99
|
+
{
|
|
100
|
+
pos: genomicOffset + alignmentStart,
|
|
109
101
|
chr,
|
|
102
|
+
base: currentChar!,
|
|
110
103
|
sampleId,
|
|
111
|
-
|
|
112
|
-
true,
|
|
113
|
-
false,
|
|
114
|
-
false,
|
|
115
|
-
false,
|
|
116
|
-
featureId,
|
|
117
|
-
),
|
|
104
|
+
},
|
|
118
105
|
)
|
|
119
106
|
}
|
|
120
107
|
}
|
|
@@ -2,113 +2,19 @@ import { GAP_STROKE_OFFSET, MIN_X_DISTANCE } from './types'
|
|
|
2
2
|
|
|
3
3
|
import type { RenderedBase, RenderingContext } from './types'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
* Creates a RenderedBase object for spatial indexing
|
|
7
|
-
* @param xPos - X coordinate of the base
|
|
8
|
-
* @param rowTop - Y coordinate of the row top
|
|
9
|
-
* @param context - Rendering context with dimensions
|
|
10
|
-
* @param pos - Genomic coordinate
|
|
11
|
-
* @param chr - Chromosome/sequence name
|
|
12
|
-
* @param sampleId - Sample identifier
|
|
13
|
-
* @param base - The base character
|
|
14
|
-
* @param isMatch - Whether this base matches the reference
|
|
15
|
-
* @param isMismatch - Whether this base is a mismatch
|
|
16
|
-
* @param isGap - Whether this is a gap
|
|
17
|
-
* @param isInsertion - Whether this is an insertion
|
|
18
|
-
* @param featureId - Feature identifier
|
|
19
|
-
*/
|
|
20
|
-
export function createRenderedBase(
|
|
5
|
+
export function createRenderedBaseCoords(
|
|
21
6
|
xPos: number,
|
|
22
7
|
rowTop: number,
|
|
23
8
|
context: RenderingContext,
|
|
24
|
-
|
|
25
|
-
chr: string,
|
|
26
|
-
sampleId: string,
|
|
27
|
-
base: string,
|
|
28
|
-
isMatch: boolean,
|
|
29
|
-
isMismatch: boolean,
|
|
30
|
-
isGap: boolean,
|
|
31
|
-
isInsertion: boolean,
|
|
32
|
-
featureId: string,
|
|
33
|
-
): RenderedBase {
|
|
9
|
+
) {
|
|
34
10
|
return {
|
|
35
11
|
minX: xPos,
|
|
36
12
|
minY: rowTop,
|
|
37
13
|
maxX: xPos + context.scale + GAP_STROKE_OFFSET,
|
|
38
14
|
maxY: rowTop + context.h,
|
|
39
|
-
pos,
|
|
40
|
-
chr,
|
|
41
|
-
sampleId,
|
|
42
|
-
base,
|
|
43
|
-
isMatch,
|
|
44
|
-
isMismatch,
|
|
45
|
-
isGap,
|
|
46
|
-
isInsertion,
|
|
47
|
-
featureId,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Creates a RenderedBase object for insertions with custom width
|
|
53
|
-
* Uses the actual rendered width instead of the standard scale-based width
|
|
54
|
-
* This ensures accurate spatial queries for different insertion rendering types:
|
|
55
|
-
* - Small insertions: INSERTION_LINE_WIDTH (1px) or INSERTION_BORDER_HEIGHT (5px) with borders
|
|
56
|
-
* - Large insertions (text): measured text width + padding
|
|
57
|
-
* - Large insertions (line): INSERTION_BORDER_WIDTH (2px)
|
|
58
|
-
*
|
|
59
|
-
* @param xPos - X coordinate of the insertion
|
|
60
|
-
* @param rowTop - Y coordinate of the row top
|
|
61
|
-
* @param width - Actual rendered width of the insertion
|
|
62
|
-
* @param context - Rendering context with dimensions
|
|
63
|
-
* @param pos - Genomic coordinate
|
|
64
|
-
* @param chr - Chromosome/sequence name
|
|
65
|
-
* @param sampleId - Sample identifier
|
|
66
|
-
* @param insertionSequence - The insertion sequence
|
|
67
|
-
* @param featureId - Feature identifier
|
|
68
|
-
*/
|
|
69
|
-
export function createRenderedInsertion(
|
|
70
|
-
xPos: number,
|
|
71
|
-
rowTop: number,
|
|
72
|
-
width: number,
|
|
73
|
-
context: RenderingContext,
|
|
74
|
-
pos: number,
|
|
75
|
-
chr: string,
|
|
76
|
-
sampleId: string,
|
|
77
|
-
insertionSequence: string,
|
|
78
|
-
featureId: string,
|
|
79
|
-
): RenderedBase {
|
|
80
|
-
return {
|
|
81
|
-
minX: xPos,
|
|
82
|
-
minY: rowTop,
|
|
83
|
-
maxX: xPos + width,
|
|
84
|
-
maxY: rowTop + context.h,
|
|
85
|
-
pos,
|
|
86
|
-
chr,
|
|
87
|
-
sampleId,
|
|
88
|
-
base: insertionSequence,
|
|
89
|
-
isMatch: false,
|
|
90
|
-
isMismatch: false,
|
|
91
|
-
isGap: false,
|
|
92
|
-
isInsertion: true,
|
|
93
|
-
featureId,
|
|
94
15
|
}
|
|
95
16
|
}
|
|
96
17
|
|
|
97
|
-
/**
|
|
98
|
-
* Checks if an item should be added to the spatial index based on distance filtering
|
|
99
|
-
* Only returns true if the X position is >0.5px away from the last inserted item
|
|
100
|
-
* This reduces spatial index density while maintaining useful spatial queries
|
|
101
|
-
*
|
|
102
|
-
* @param xPos - X position to check
|
|
103
|
-
* @param context - Rendering context with lastInsertedX tracking
|
|
104
|
-
* @param bypassDistanceFilter - If true, always return true (e.g., for insertions)
|
|
105
|
-
* @returns Whether the item should be added to spatial index
|
|
106
|
-
*
|
|
107
|
-
* @example
|
|
108
|
-
* // Items at X positions: 100.0, 100.3, 100.8, 101.5
|
|
109
|
-
* // Only items at 100.0, 100.8, 101.5 would return true (>0.5px apart)
|
|
110
|
-
* // Unless bypassDistanceFilter=true, then all would return true
|
|
111
|
-
*/
|
|
112
18
|
export function shouldAddToSpatialIndex(
|
|
113
19
|
xPos: number,
|
|
114
20
|
context: RenderingContext,
|
|
@@ -120,17 +26,15 @@ export function shouldAddToSpatialIndex(
|
|
|
120
26
|
)
|
|
121
27
|
}
|
|
122
28
|
|
|
123
|
-
/**
|
|
124
|
-
* Adds a rendered base directly to the RBush spatial index
|
|
125
|
-
* Updates the lastInsertedX tracking for distance filtering
|
|
126
|
-
*
|
|
127
|
-
* @param context - Rendering context with spatial index
|
|
128
|
-
* @param renderedBase - The base to add to the spatial index
|
|
129
|
-
*/
|
|
130
29
|
export function addToSpatialIndex(
|
|
131
30
|
context: RenderingContext,
|
|
31
|
+
minX: number,
|
|
32
|
+
minY: number,
|
|
33
|
+
maxX: number,
|
|
34
|
+
maxY: number,
|
|
132
35
|
renderedBase: RenderedBase,
|
|
133
36
|
) {
|
|
134
|
-
context.spatialIndex.
|
|
135
|
-
context.
|
|
37
|
+
context.spatialIndex.push(renderedBase)
|
|
38
|
+
context.spatialIndexCoords.push(minX, minY, maxX, maxY)
|
|
39
|
+
context.lastInsertedX = minX
|
|
136
40
|
}
|