jbrowse-plugin-mafviewer 1.3.2 → 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 +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 +46 -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 +4 -21
- 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/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 +12955 -15165
- package/dist/out.js.map +4 -4
- package/package.json +3 -4
- package/src/LinearMafRenderer/components/{ReactComponent.tsx → LinearMafRendering.tsx} +16 -21
- package/src/LinearMafRenderer/index.ts +1 -1
- package/src/LinearMafRenderer/makeImageData.ts +20 -5
- package/src/LinearMafRenderer/rendering/features.ts +4 -31
- package/src/LinearMafRenderer/rendering/gaps.ts +0 -38
- package/src/LinearMafRenderer/rendering/insertions.ts +12 -28
- package/src/LinearMafRenderer/rendering/matches.ts +13 -30
- package/src/LinearMafRenderer/rendering/mismatches.ts +20 -32
- package/src/LinearMafRenderer/rendering/spatialIndex.ts +9 -105
- 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.0",
|
|
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,15 @@ 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
|
-
return
|
|
34
|
+
const elt = x.findIndex(idx => items[idx]?.isInsertion)
|
|
35
|
+
const r = elt !== -1 ? items[elt]! : items[x[0]!]!
|
|
36
|
+
const s = samples[r.sampleId]
|
|
37
|
+
return {
|
|
38
|
+
...r,
|
|
39
|
+
sampleId: s?.label || s?.id || 'unknown',
|
|
40
|
+
}
|
|
46
41
|
} else {
|
|
47
42
|
return undefined
|
|
48
43
|
}
|
|
@@ -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,
|
|
@@ -42,24 +34,14 @@ export function processFeatureAlignment(
|
|
|
42
34
|
const alignment = originalAlignment.toLowerCase()
|
|
43
35
|
const rowTop = renderingContext.offset + renderingContext.rowHeight * row
|
|
44
36
|
|
|
45
|
-
renderGaps(
|
|
46
|
-
renderingContext,
|
|
47
|
-
alignment,
|
|
48
|
-
referenceSeq,
|
|
49
|
-
leftPx,
|
|
50
|
-
rowTop,
|
|
51
|
-
sampleId,
|
|
52
|
-
featureId,
|
|
53
|
-
alignmentData.start,
|
|
54
|
-
alignmentData.chr,
|
|
55
|
-
)
|
|
37
|
+
renderGaps(renderingContext, alignment, referenceSeq, leftPx, rowTop)
|
|
56
38
|
renderMatches(
|
|
57
39
|
renderingContext,
|
|
58
40
|
alignment,
|
|
59
41
|
referenceSeq,
|
|
60
42
|
leftPx,
|
|
61
43
|
rowTop,
|
|
62
|
-
|
|
44
|
+
row,
|
|
63
45
|
featureId,
|
|
64
46
|
alignmentData.start,
|
|
65
47
|
alignmentData.chr,
|
|
@@ -70,7 +52,7 @@ export function processFeatureAlignment(
|
|
|
70
52
|
referenceSeq,
|
|
71
53
|
leftPx,
|
|
72
54
|
rowTop,
|
|
73
|
-
|
|
55
|
+
row,
|
|
74
56
|
featureId,
|
|
75
57
|
alignmentData.start,
|
|
76
58
|
alignmentData.chr,
|
|
@@ -88,15 +70,6 @@ export function processFeatureAlignment(
|
|
|
88
70
|
}
|
|
89
71
|
}
|
|
90
72
|
|
|
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
73
|
export function processFeatureInsertions(
|
|
101
74
|
feature: Feature,
|
|
102
75
|
region: GenomicRegion,
|
|
@@ -129,7 +102,7 @@ export function processFeatureInsertions(
|
|
|
129
102
|
leftPx,
|
|
130
103
|
rowTop,
|
|
131
104
|
bpPerPx,
|
|
132
|
-
|
|
105
|
+
row,
|
|
133
106
|
featureId,
|
|
134
107
|
alignmentData.start,
|
|
135
108
|
alignmentData.chr,
|
|
@@ -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,8 @@ export function renderInsertions(
|
|
|
39
23
|
leftPx: number,
|
|
40
24
|
rowTop: number,
|
|
41
25
|
bpPerPx: number,
|
|
42
|
-
sampleId:
|
|
43
|
-
|
|
26
|
+
sampleId: number,
|
|
27
|
+
_featureId: string,
|
|
44
28
|
alignmentStart: number,
|
|
45
29
|
chr: string,
|
|
46
30
|
) {
|
|
@@ -151,17 +135,17 @@ export function renderInsertions(
|
|
|
151
135
|
if (shouldAddToSpatialIndex(actualXPos, context, true)) {
|
|
152
136
|
addToSpatialIndex(
|
|
153
137
|
context,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
genomicOffset + alignmentStart,
|
|
138
|
+
actualXPos,
|
|
139
|
+
rowTop,
|
|
140
|
+
actualXPos + actualWidth,
|
|
141
|
+
rowTop + context.h,
|
|
142
|
+
{
|
|
143
|
+
pos: genomicOffset + alignmentStart,
|
|
160
144
|
chr,
|
|
145
|
+
base: insertionSequence,
|
|
161
146
|
sampleId,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
),
|
|
147
|
+
isInsertion: true,
|
|
148
|
+
},
|
|
165
149
|
)
|
|
166
150
|
}
|
|
167
151
|
}
|
|
@@ -1,32 +1,17 @@
|
|
|
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
|
-
|
|
13
|
+
sampleId: number,
|
|
14
|
+
_featureId: string,
|
|
30
15
|
alignmentStart: number,
|
|
31
16
|
chr: string,
|
|
32
17
|
) {
|
|
@@ -56,21 +41,19 @@ export function renderMatches(
|
|
|
56
41
|
|
|
57
42
|
// Add to spatial index if distance filter allows
|
|
58
43
|
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
59
|
-
|
|
44
|
+
addToSpatialIndex(
|
|
45
|
+
context,
|
|
60
46
|
xPos,
|
|
61
47
|
rowTop,
|
|
62
|
-
context,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
false,
|
|
71
|
-
featureId,
|
|
48
|
+
xPos + context.scale + GAP_STROKE_OFFSET,
|
|
49
|
+
rowTop + context.h,
|
|
50
|
+
{
|
|
51
|
+
pos: genomicOffset + alignmentStart,
|
|
52
|
+
chr,
|
|
53
|
+
base: currentChar || '',
|
|
54
|
+
sampleId,
|
|
55
|
+
},
|
|
72
56
|
)
|
|
73
|
-
addToSpatialIndex(context, renderedBase)
|
|
74
57
|
}
|
|
75
58
|
}
|
|
76
59
|
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,8 @@ export function renderMismatches(
|
|
|
25
21
|
seq: string,
|
|
26
22
|
leftPx: number,
|
|
27
23
|
rowTop: number,
|
|
28
|
-
sampleId:
|
|
29
|
-
|
|
24
|
+
sampleId: number,
|
|
25
|
+
_featureId: string,
|
|
30
26
|
alignmentStart: number,
|
|
31
27
|
chr: string,
|
|
32
28
|
) {
|
|
@@ -67,20 +63,16 @@ export function renderMismatches(
|
|
|
67
63
|
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
68
64
|
addToSpatialIndex(
|
|
69
65
|
context,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
xPos,
|
|
67
|
+
rowTop,
|
|
68
|
+
xPos + context.scale + GAP_STROKE_OFFSET,
|
|
69
|
+
rowTop + context.h,
|
|
70
|
+
{
|
|
71
|
+
pos: genomicOffset + alignmentStart,
|
|
75
72
|
chr,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
true,
|
|
80
|
-
false,
|
|
81
|
-
false,
|
|
82
|
-
featureId,
|
|
83
|
-
),
|
|
73
|
+
base: currentChar!,
|
|
74
|
+
sampleId: i,
|
|
75
|
+
},
|
|
84
76
|
)
|
|
85
77
|
}
|
|
86
78
|
} else if (showAllLetters) {
|
|
@@ -101,20 +93,16 @@ export function renderMismatches(
|
|
|
101
93
|
if (shouldAddToSpatialIndex(xPos, context)) {
|
|
102
94
|
addToSpatialIndex(
|
|
103
95
|
context,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
xPos,
|
|
97
|
+
rowTop,
|
|
98
|
+
xPos + context.scale + GAP_STROKE_OFFSET,
|
|
99
|
+
rowTop + context.h,
|
|
100
|
+
{
|
|
101
|
+
pos: genomicOffset + alignmentStart,
|
|
109
102
|
chr,
|
|
103
|
+
base: currentChar!,
|
|
110
104
|
sampleId,
|
|
111
|
-
|
|
112
|
-
true,
|
|
113
|
-
false,
|
|
114
|
-
false,
|
|
115
|
-
false,
|
|
116
|
-
featureId,
|
|
117
|
-
),
|
|
105
|
+
},
|
|
118
106
|
)
|
|
119
107
|
}
|
|
120
108
|
}
|
|
@@ -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
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import RBush from 'rbush'
|
|
2
|
-
|
|
3
1
|
// Rendering constants
|
|
4
2
|
export const FONT_CONFIG = 'bold 10px Courier New,monospace'
|
|
5
3
|
export const CHAR_SIZE_WIDTH = 10
|
|
@@ -26,27 +24,12 @@ export interface GenomicRegion {
|
|
|
26
24
|
refName: string
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
/**
|
|
30
|
-
* Represents a rendered letter/base with its spatial and genomic coordinates
|
|
31
|
-
* This structure is designed for insertion into an RBush spatial index
|
|
32
|
-
*/
|
|
33
27
|
export interface RenderedBase {
|
|
34
|
-
// Spatial bounding box (required by RBush)
|
|
35
|
-
minX: number
|
|
36
|
-
minY: number
|
|
37
|
-
maxX: number
|
|
38
|
-
maxY: number
|
|
39
|
-
// Genomic information
|
|
40
28
|
pos: number
|
|
41
29
|
chr: string
|
|
42
|
-
sampleId: string
|
|
43
30
|
base: string
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
isGap: boolean
|
|
47
|
-
isInsertion: boolean
|
|
48
|
-
// Feature reference
|
|
49
|
-
featureId: string
|
|
31
|
+
sampleId: number
|
|
32
|
+
isInsertion?: boolean
|
|
50
33
|
}
|
|
51
34
|
|
|
52
35
|
/**
|
|
@@ -67,7 +50,8 @@ export interface RenderingContext {
|
|
|
67
50
|
showAsUpperCase: boolean
|
|
68
51
|
|
|
69
52
|
// RBush spatial index for efficient spatial queries
|
|
70
|
-
spatialIndex:
|
|
53
|
+
spatialIndex: RenderedBase[]
|
|
54
|
+
spatialIndexCoords: number[]
|
|
71
55
|
|
|
72
56
|
// Track last X position for spatial index optimization
|
|
73
57
|
lastInsertedX: number
|