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.
Files changed (58) hide show
  1. package/README.md +0 -47
  2. package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +9 -3
  3. package/dist/LinearMafRenderer/components/LinearMafRendering.d.ts +13 -0
  4. package/dist/LinearMafRenderer/components/LinearMafRendering.js +46 -0
  5. package/dist/LinearMafRenderer/components/LinearMafRendering.js.map +1 -0
  6. package/dist/LinearMafRenderer/index.js +1 -1
  7. package/dist/LinearMafRenderer/index.js.map +1 -1
  8. package/dist/LinearMafRenderer/makeImageData.d.ts +3 -1
  9. package/dist/LinearMafRenderer/makeImageData.js +11 -4
  10. package/dist/LinearMafRenderer/makeImageData.js.map +1 -1
  11. package/dist/LinearMafRenderer/rendering/features.d.ts +0 -17
  12. package/dist/LinearMafRenderer/rendering/features.js +4 -21
  13. package/dist/LinearMafRenderer/rendering/features.js.map +1 -1
  14. package/dist/LinearMafRenderer/rendering/gaps.d.ts +1 -11
  15. package/dist/LinearMafRenderer/rendering/gaps.js +1 -17
  16. package/dist/LinearMafRenderer/rendering/gaps.js.map +1 -1
  17. package/dist/LinearMafRenderer/rendering/insertions.d.ts +1 -13
  18. package/dist/LinearMafRenderer/rendering/insertions.js +9 -15
  19. package/dist/LinearMafRenderer/rendering/insertions.js.map +1 -1
  20. package/dist/LinearMafRenderer/rendering/matches.d.ts +1 -12
  21. package/dist/LinearMafRenderer/rendering/matches.js +8 -15
  22. package/dist/LinearMafRenderer/rendering/matches.js.map +1 -1
  23. package/dist/LinearMafRenderer/rendering/mismatches.d.ts +1 -1
  24. package/dist/LinearMafRenderer/rendering/mismatches.js +14 -4
  25. package/dist/LinearMafRenderer/rendering/mismatches.js.map +1 -1
  26. package/dist/LinearMafRenderer/rendering/spatialIndex.d.ts +7 -58
  27. package/dist/LinearMafRenderer/rendering/spatialIndex.js +5 -85
  28. package/dist/LinearMafRenderer/rendering/spatialIndex.js.map +1 -1
  29. package/dist/LinearMafRenderer/rendering/types.d.ts +4 -16
  30. package/dist/LinearMafRenderer/rendering/types.js.map +1 -1
  31. package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +37 -35
  32. package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js.map +1 -1
  33. package/dist/index.js +0 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +5 -28
  36. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
  37. package/dist/out.js +12955 -15165
  38. package/dist/out.js.map +4 -4
  39. package/package.json +3 -4
  40. package/src/LinearMafRenderer/components/{ReactComponent.tsx → LinearMafRendering.tsx} +16 -21
  41. package/src/LinearMafRenderer/index.ts +1 -1
  42. package/src/LinearMafRenderer/makeImageData.ts +20 -5
  43. package/src/LinearMafRenderer/rendering/features.ts +4 -31
  44. package/src/LinearMafRenderer/rendering/gaps.ts +0 -38
  45. package/src/LinearMafRenderer/rendering/insertions.ts +12 -28
  46. package/src/LinearMafRenderer/rendering/matches.ts +13 -30
  47. package/src/LinearMafRenderer/rendering/mismatches.ts +20 -32
  48. package/src/LinearMafRenderer/rendering/spatialIndex.ts +9 -105
  49. package/src/LinearMafRenderer/rendering/types.ts +4 -20
  50. package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +5 -6
  51. package/src/index.ts +0 -2
  52. package/src/BgzipTaffyAdapter/BgzipTaffyAdapter.ts +0 -307
  53. package/src/BgzipTaffyAdapter/configSchema.ts +0 -59
  54. package/src/BgzipTaffyAdapter/index.ts +0 -16
  55. package/src/BgzipTaffyAdapter/rowInstructions.ts +0 -91
  56. package/src/BgzipTaffyAdapter/types.ts +0 -16
  57. package/src/BgzipTaffyAdapter/util.ts +0 -25
  58. package/src/BgzipTaffyAdapter/virtualOffset.ts +0 -29
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.2",
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 RBush from 'rbush'
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
- rbush: SerializedRBush
15
+ flatbush: SerializedRBush
16
+ items: RenderedBase[]
17
+ samples: Sample[]
21
18
  }) {
22
- const { displayModel, height, rbush } = props
19
+ const { items, displayModel, height, samples, flatbush } = props
23
20
  const ref = useRef<HTMLDivElement>(null)
24
- const rbush2 = useMemo(() => new RBush<RBushData>().fromJSON(rbush), [rbush])
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
- // prioritize insertions
43
- const { minX, minY, maxX, maxY, ...rest } =
44
- x.find(f => f.isInsertion) || x[0]!
45
- return rest
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/ReactComponent'
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 RBush from 'rbush'
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: new RBush<RenderedBase>(),
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
- // Return serialized RBush spatial index
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
- rbush: renderingContext.spatialIndex.toJSON(),
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
- sampleId,
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
- sampleId,
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
- sampleId,
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: string,
43
- featureId: string,
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
- createRenderedInsertion(
155
- actualXPos,
156
- rowTop,
157
- actualWidth,
158
- context,
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
- insertionSequence,
163
- featureId,
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: string,
29
- featureId: string,
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
- const renderedBase = createRenderedBase(
44
+ addToSpatialIndex(
45
+ context,
60
46
  xPos,
61
47
  rowTop,
62
- context,
63
- genomicOffset + alignmentStart,
64
- chr,
65
- sampleId,
66
- currentChar || '',
67
- true,
68
- false,
69
- false,
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: string,
29
- featureId: string,
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
- createRenderedBase(
71
- xPos,
72
- rowTop,
73
- context,
74
- genomicOffset + alignmentStart,
66
+ xPos,
67
+ rowTop,
68
+ xPos + context.scale + GAP_STROKE_OFFSET,
69
+ rowTop + context.h,
70
+ {
71
+ pos: genomicOffset + alignmentStart,
75
72
  chr,
76
- sampleId,
77
- currentChar!,
78
- false,
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
- createRenderedBase(
105
- xPos,
106
- rowTop,
107
- context,
108
- genomicOffset + alignmentStart,
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
- currentChar!,
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
- pos: number,
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.insert(renderedBase)
135
- context.lastInsertedX = renderedBase.minX
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
- isMatch: boolean
45
- isMismatch: boolean
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: RBush<RenderedBase>
53
+ spatialIndex: RenderedBase[]
54
+ spatialIndexCoords: number[]
71
55
 
72
56
  // Track last X position for spatial index optimization
73
57
  lastInsertedX: number