jbrowse-plugin-mafviewer 1.3.1 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +1 -1
  2. package/dist/BigMafAdapter/BigMafAdapter.js +39 -28
  3. package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -1
  4. package/dist/LinearMafDisplay/components/Crosshairs.js +1 -1
  5. package/dist/LinearMafDisplay/components/Crosshairs.js.map +1 -1
  6. package/dist/LinearMafDisplay/components/MAFTooltip.d.ts +2 -3
  7. package/dist/LinearMafDisplay/components/MAFTooltip.js +6 -19
  8. package/dist/LinearMafDisplay/components/MAFTooltip.js.map +1 -1
  9. package/dist/LinearMafDisplay/stateModel.d.ts +8 -0
  10. package/dist/LinearMafDisplay/stateModel.js +10 -0
  11. package/dist/LinearMafDisplay/stateModel.js.map +1 -1
  12. package/dist/LinearMafDisplay/util.d.ts +20 -0
  13. package/dist/LinearMafDisplay/util.js +29 -0
  14. package/dist/LinearMafDisplay/util.js.map +1 -1
  15. package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +3 -0
  16. package/dist/LinearMafRenderer/LinearMafRenderer.js +1 -2
  17. package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -1
  18. package/dist/LinearMafRenderer/components/ReactComponent.d.ts +3 -0
  19. package/dist/LinearMafRenderer/components/ReactComponent.js +41 -2
  20. package/dist/LinearMafRenderer/components/ReactComponent.js.map +1 -1
  21. package/dist/LinearMafRenderer/components/util.d.ts +1 -0
  22. package/dist/LinearMafRenderer/components/util.js +13 -0
  23. package/dist/LinearMafRenderer/components/util.js.map +1 -0
  24. package/dist/LinearMafRenderer/makeImageData.d.ts +4 -5
  25. package/dist/LinearMafRenderer/makeImageData.js +28 -146
  26. package/dist/LinearMafRenderer/makeImageData.js.map +1 -1
  27. package/dist/LinearMafRenderer/rendering/features.d.ts +21 -0
  28. package/dist/LinearMafRenderer/rendering/features.js +58 -0
  29. package/dist/LinearMafRenderer/rendering/features.js.map +1 -0
  30. package/dist/LinearMafRenderer/rendering/gaps.d.ts +12 -0
  31. package/dist/LinearMafRenderer/rendering/gaps.js +35 -0
  32. package/dist/LinearMafRenderer/rendering/gaps.js.map +1 -0
  33. package/dist/LinearMafRenderer/rendering/index.d.ts +8 -0
  34. package/dist/LinearMafRenderer/rendering/index.js +10 -0
  35. package/dist/LinearMafRenderer/rendering/index.js.map +1 -0
  36. package/dist/LinearMafRenderer/rendering/insertions.d.ts +14 -0
  37. package/dist/LinearMafRenderer/rendering/insertions.js +84 -0
  38. package/dist/LinearMafRenderer/rendering/insertions.js.map +1 -0
  39. package/dist/LinearMafRenderer/rendering/matches.d.ts +13 -0
  40. package/dist/LinearMafRenderer/rendering/matches.js +41 -0
  41. package/dist/LinearMafRenderer/rendering/matches.js.map +1 -0
  42. package/dist/LinearMafRenderer/rendering/mismatches.d.ts +13 -0
  43. package/dist/LinearMafRenderer/rendering/mismatches.js +47 -0
  44. package/dist/LinearMafRenderer/rendering/mismatches.js.map +1 -0
  45. package/dist/LinearMafRenderer/rendering/spatialIndex.d.ts +60 -0
  46. package/dist/LinearMafRenderer/rendering/spatialIndex.js +99 -0
  47. package/dist/LinearMafRenderer/rendering/spatialIndex.js.map +1 -0
  48. package/dist/LinearMafRenderer/rendering/text.d.ts +12 -0
  49. package/dist/LinearMafRenderer/rendering/text.js +42 -0
  50. package/dist/LinearMafRenderer/rendering/text.js.map +1 -0
  51. package/dist/LinearMafRenderer/rendering/types.d.ts +67 -0
  52. package/dist/LinearMafRenderer/rendering/types.js +15 -0
  53. package/dist/LinearMafRenderer/rendering/types.js.map +1 -0
  54. package/dist/MafTabixAdapter/MafTabixAdapter.js +48 -22
  55. package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -1
  56. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +7 -8
  57. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
  58. package/dist/out.js +34520 -0
  59. package/dist/out.js.map +7 -0
  60. package/dist/util/fastaUtils.js.map +1 -1
  61. package/package.json +5 -3
  62. package/src/BigMafAdapter/BigMafAdapter.ts +49 -28
  63. package/src/LinearMafDisplay/components/Crosshairs.tsx +1 -7
  64. package/src/LinearMafDisplay/components/MAFTooltip.tsx +14 -33
  65. package/src/LinearMafDisplay/stateModel.ts +10 -0
  66. package/src/LinearMafDisplay/util.ts +57 -0
  67. package/src/LinearMafRenderer/LinearMafRenderer.ts +1 -2
  68. package/src/LinearMafRenderer/components/ReactComponent.tsx +70 -2
  69. package/src/LinearMafRenderer/components/util.ts +13 -0
  70. package/src/LinearMafRenderer/makeImageData.ts +49 -196
  71. package/src/LinearMafRenderer/rendering/features.ts +138 -0
  72. package/src/LinearMafRenderer/rendering/gaps.ts +71 -0
  73. package/src/LinearMafRenderer/rendering/index.ts +9 -0
  74. package/src/LinearMafRenderer/rendering/insertions.ts +170 -0
  75. package/src/LinearMafRenderer/rendering/matches.ts +79 -0
  76. package/src/LinearMafRenderer/rendering/mismatches.ts +125 -0
  77. package/src/LinearMafRenderer/rendering/spatialIndex.ts +136 -0
  78. package/src/LinearMafRenderer/rendering/text.ts +72 -0
  79. package/src/LinearMafRenderer/rendering/types.ts +81 -0
  80. package/src/MafTabixAdapter/MafTabixAdapter.ts +77 -22
  81. package/src/util/fastaUtils.ts +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"fastaUtils.js","sourceRoot":"","sources":["../../src/util/fastaUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fastaUtils.js","sourceRoot":"","sources":["../../src/util/fastaUtils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.1",
2
+ "version": "1.3.2",
3
3
  "license": "MIT",
4
4
  "name": "jbrowse-plugin-mafviewer",
5
5
  "keywords": [
@@ -38,6 +38,7 @@
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",
41
42
  "@types/react": "^19.0.1",
42
43
  "chalk": "^5.3.0",
43
44
  "esbuild": "^0.25.0",
@@ -45,7 +46,7 @@
45
46
  "eslint-plugin-import": "^2.31.0",
46
47
  "eslint-plugin-react": "^7.20.3",
47
48
  "eslint-plugin-react-hooks": "^5.1.0",
48
- "eslint-plugin-unicorn": "^59.0.1",
49
+ "eslint-plugin-unicorn": "^60.0.0",
49
50
  "mobx": "^6.0.0",
50
51
  "mobx-react": "^9.0.1",
51
52
  "mobx-state-tree": "^5.4.1",
@@ -69,6 +70,7 @@
69
70
  "d3-hierarchy": "^3.1.2",
70
71
  "fast-deep-equal": "^3.1.3",
71
72
  "generic-filehandle2": "^2.0.1",
72
- "long": "^5.2.3"
73
+ "long": "^5.2.3",
74
+ "rbush": "^4.0.1"
73
75
  }
74
76
  }
@@ -57,6 +57,9 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
57
57
 
58
58
  getFeatures(query: Region, opts?: BaseOptions) {
59
59
  const { statusCallback = () => {} } = opts || {}
60
+ // Pre-compile regex for better performance
61
+ const WHITESPACE_REGEX = / +/
62
+
60
63
  return ObservableCreate<Feature>(async observer => {
61
64
  const { adapter } = await this.setup()
62
65
  const features = await updateStatus(
@@ -68,39 +71,57 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
68
71
  for (const feature of features) {
69
72
  const maf = feature.get('mafBlock') as string
70
73
  const blocks = maf.split(';')
71
- let aln: string | undefined
72
- const alns = [] as string[]
73
- const alignments = {} as Record<string, OrganismRecord>
74
- const blocks2 = [] as string[]
74
+
75
+ // Count sequence blocks first to pre-size arrays
76
+ let sequenceBlockCount = 0
75
77
  for (const block of blocks) {
76
78
  if (block.startsWith('s')) {
77
- if (aln) {
78
- alns.push(block.split(/ +/)[6]!)
79
- blocks2.push(block)
80
- } else {
81
- aln = block.split(/ +/)[6]
82
- alns.push(aln!)
83
- blocks2.push(block)
84
- }
79
+ sequenceBlockCount++
85
80
  }
86
81
  }
87
82
 
88
- for (let i = 0; i < blocks2.length; i++) {
89
- const elt = blocks2[i]!
90
- const ad = elt.split(/ +/)
91
- const y = ad[1]!.split('.')
92
- const org = y[0]!
93
- const chr = y[1]!
94
-
95
- alignments[org] = {
96
- chr: chr,
97
- start: +ad[1]!,
98
- srcSize: +ad[2]!,
99
- strand: ad[3] === '+' ? 1 : -1,
100
- unknown: +ad[4]!,
101
- seq: alns[i]!,
83
+ // Pre-size arrays based on actual sequence block count
84
+ const alns = new Array<string>(sequenceBlockCount)
85
+ const alignments = {} as Record<string, OrganismRecord>
86
+
87
+ let sequenceIndex = 0
88
+ let referenceSeq: string | undefined
89
+
90
+ // Single-pass processing: combine both loops
91
+ for (const block of blocks) {
92
+ if (block.startsWith('s')) {
93
+ // Split once and cache the result
94
+ const parts = block.split(WHITESPACE_REGEX)
95
+ const sequence = parts[6]!
96
+ const organismChr = parts[1]!
97
+
98
+ // Store sequence in pre-sized array
99
+ alns[sequenceIndex] = sequence
100
+
101
+ // Set reference sequence from first block
102
+ if (referenceSeq === undefined) {
103
+ referenceSeq = sequence
104
+ }
105
+
106
+ // Parse organism and chromosome once
107
+ const dotIndex = organismChr.indexOf('.')
108
+ const org = organismChr.slice(0, Math.max(0, dotIndex))
109
+ const chr = organismChr.slice(Math.max(0, dotIndex + 1))
110
+
111
+ // Create alignment record directly
112
+ alignments[org] = {
113
+ chr,
114
+ start: +parts[2]!,
115
+ srcSize: +parts[3]!,
116
+ strand: parts[4] === '+' ? 1 : -1,
117
+ unknown: +parts[5]!,
118
+ seq: sequence,
119
+ }
120
+
121
+ sequenceIndex++
102
122
  }
103
123
  }
124
+
104
125
  observer.next(
105
126
  new SimpleFeature({
106
127
  id: feature.id(),
@@ -108,8 +129,8 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
108
129
  start: feature.get('start'),
109
130
  end: feature.get('end'),
110
131
  refName: feature.get('refName'),
111
- seq: alns[0],
112
- alignments: alignments,
132
+ seq: referenceSeq,
133
+ alignments,
113
134
  },
114
135
  }),
115
136
  )
@@ -35,13 +35,7 @@ const Crosshairs = ({
35
35
  top: scrollTop,
36
36
  }}
37
37
  >
38
- <line
39
- x1={0}
40
- x2={width}
41
- y1={mouseY - scrollTop}
42
- y2={mouseY - scrollTop}
43
- stroke="black"
44
- />
38
+ <line x1={0} x2={width} y1={mouseY} y2={mouseY} stroke="black" />
45
39
  <line x1={mouseX} x2={mouseX} y1={0} y2={height} stroke="black" />
46
40
  </svg>
47
41
  )
@@ -2,55 +2,36 @@ import React from 'react'
2
2
 
3
3
  import { SanitizedHTML } from '@jbrowse/core/ui'
4
4
  import BaseTooltip from '@jbrowse/core/ui/BaseTooltip'
5
- import {
6
- getBpDisplayStr,
7
- getContainingView,
8
- toLocale,
9
- } from '@jbrowse/core/util'
5
+ import { getContainingView } from '@jbrowse/core/util'
10
6
  import { observer } from 'mobx-react'
11
7
 
8
+ import { generateTooltipContent } from '../util'
9
+
12
10
  import type { LinearMafDisplayModel } from '../stateModel'
11
+ import type { HoveredInfo } from '../util'
13
12
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
14
13
 
15
- interface MAFTooltipProps {
14
+ const MAFTooltip = observer(function ({
15
+ model,
16
+ mouseX,
17
+ origMouseX,
18
+ }: {
16
19
  mouseY: number
17
20
  mouseX: number
18
21
  rowHeight: number
19
22
  sources: Record<string, any>[]
20
23
  model: LinearMafDisplayModel
21
24
  origMouseX?: number
22
- }
23
-
24
- const MAFTooltip = observer(function ({
25
- model,
26
- mouseY,
27
- mouseX,
28
- origMouseX,
29
- rowHeight,
30
- sources,
31
- }: MAFTooltipProps) {
25
+ }) {
26
+ const { hoveredInfo } = model
32
27
  const view = getContainingView(model) as LinearGenomeViewModel
33
- const ret = Object.entries(sources[Math.floor(mouseY / rowHeight)] || {})
34
- .filter(([key]) => key !== 'color' && key !== 'id')
35
- .map(([key, value]) => `${key}:${value}`)
36
- .join('\n')
37
28
  const p1 = origMouseX ? view.pxToBp(origMouseX) : undefined
38
29
  const p2 = view.pxToBp(mouseX)
39
- return ret ? (
30
+
31
+ return hoveredInfo ? (
40
32
  <BaseTooltip>
41
33
  <SanitizedHTML
42
- html={[
43
- ret,
44
- ...(p1
45
- ? [
46
- `Start: ${p1.refName}:${toLocale(p1.coord)}`,
47
- `End: ${p2.refName}:${toLocale(p2.coord)}`,
48
- `Length: ${getBpDisplayStr(Math.abs(p1.coord - p2.coord))}`,
49
- ]
50
- : [`${p2.refName}:${toLocale(p2.coord)}`]),
51
- ]
52
- .filter(f => !!f)
53
- .join('<br/>')}
34
+ html={generateTooltipContent(hoveredInfo as HoveredInfo, p1, p2)}
54
35
  />
55
36
  </BaseTooltip>
56
37
  ) : null
@@ -85,6 +85,10 @@ export default function stateModelFactory(
85
85
  }),
86
86
  )
87
87
  .volatile(() => ({
88
+ /**
89
+ * #volatile
90
+ */
91
+ hoveredInfo: undefined as Record<string, unknown> | undefined,
88
92
  /**
89
93
  * #volatile
90
94
  */
@@ -99,6 +103,12 @@ export default function stateModelFactory(
99
103
  volatileTree: undefined as any,
100
104
  }))
101
105
  .actions(self => ({
106
+ /**
107
+ * #action
108
+ */
109
+ setHoveredInfo(arg?: Record<string, unknown>) {
110
+ self.hoveredInfo = arg
111
+ },
102
112
  /**
103
113
  * #action
104
114
  */
@@ -1,8 +1,65 @@
1
+ import { getBpDisplayStr, toLocale } from '@jbrowse/core/util'
1
2
  import { max } from 'd3-array'
2
3
 
3
4
  import type { NodeWithIds } from './types'
4
5
  import type { HierarchyNode } from 'd3-hierarchy'
5
6
 
7
+ export interface HoveredInfo {
8
+ sampleId: string
9
+ pos: number
10
+ base: string
11
+ chr: string
12
+ [key: string]: unknown // Allow additional properties for compatibility
13
+ }
14
+
15
+ export interface GenomicPosition {
16
+ refName: string
17
+ coord: number
18
+ }
19
+
20
+ /**
21
+ * Generates tooltip HTML content for MAF alignments
22
+ * Truncates long sequences to 50 characters, with ellipses added if display exceeds 20 characters
23
+ * @param hoveredInfo - Information about the hovered base/position
24
+ * @param p1 - Start position (for range selections)
25
+ * @param p2 - End position (current mouse position)
26
+ * @returns HTML string for tooltip content
27
+ */
28
+ export function generateTooltipContent(
29
+ hoveredInfo: HoveredInfo | undefined,
30
+ p1: GenomicPosition | undefined,
31
+ p2: GenomicPosition,
32
+ ): string {
33
+ const contentLines: string[] = []
34
+
35
+ if (p1) {
36
+ // Range selection mode
37
+ contentLines.push(
38
+ `Start: ${p1.refName}:${toLocale(p1.coord)}`,
39
+ `End: ${p2.refName}:${toLocale(p2.coord)}`,
40
+ `Length: ${getBpDisplayStr(Math.abs(p1.coord - p2.coord))}`,
41
+ )
42
+ } else {
43
+ // Single position mode
44
+ contentLines.push(`Ref: ${p2.refName}:${toLocale(p2.coord)}`)
45
+
46
+ if (hoveredInfo) {
47
+ const { base, sampleId, pos, chr } = hoveredInfo
48
+ const thresh = 20
49
+ const len = base.length
50
+ const lengthSuffix = len > 1 ? ` ${len}bp` : ''
51
+ const baseDisplay =
52
+ base.length > thresh ? base.slice(0, thresh) + '...' : base
53
+
54
+ contentLines.push(
55
+ `Alt ${sampleId}: ${chr}:${pos.toLocaleString('en-US')} (${baseDisplay}${lengthSuffix})`,
56
+ )
57
+ }
58
+ }
59
+
60
+ return contentLines.filter(line => !!line).join('<br/>')
61
+ }
62
+
6
63
  // basically same as maxLength from https://observablehq.com/@d3/tree-of-life
7
64
  export function maxLength(d: HierarchyNode<NodeWithIds>): number {
8
65
  return (
@@ -48,14 +48,13 @@ export default class LinearMafRenderer extends FeatureRendererType {
48
48
  const features = await this.getFeatures(renderProps)
49
49
  const res = await updateStatus('Rendering alignment', statusCallback, () =>
50
50
  renderToAbstractCanvas(width, height, renderProps, ctx => {
51
- makeImageData({
51
+ return makeImageData({
52
52
  ctx,
53
53
  renderArgs: {
54
54
  ...renderProps,
55
55
  features,
56
56
  },
57
57
  })
58
- return undefined
59
58
  }),
60
59
  )
61
60
  const results = await super.render({
@@ -1,13 +1,81 @@
1
- import React from 'react'
1
+ import React, { useMemo, useRef } from 'react'
2
2
 
3
3
  import { PrerenderedCanvas } from '@jbrowse/core/ui'
4
4
  import { observer } from 'mobx-react'
5
+ import RBush from 'rbush'
5
6
 
7
+ type SerializedRBush = any
8
+
9
+ interface RBushData {
10
+ minX: number
11
+ maxX: number
12
+ minY: number
13
+ maxY: number
14
+ isInsertion: boolean
15
+ }
6
16
  const LinearMafRendering = observer(function (props: {
7
17
  width: number
8
18
  height: number
19
+ displayModel: any
20
+ rbush: SerializedRBush
9
21
  }) {
10
- return <PrerenderedCanvas {...props} />
22
+ const { displayModel, height, rbush } = props
23
+ const ref = useRef<HTMLDivElement>(null)
24
+ const rbush2 = useMemo(() => new RBush<RBushData>().fromJSON(rbush), [rbush])
25
+
26
+ function getFeatureUnderMouse(eventClientX: number, eventClientY: number) {
27
+ let offsetX = 0
28
+ let offsetY = 0
29
+ if (ref.current) {
30
+ const r = ref.current.getBoundingClientRect()
31
+ offsetX = eventClientX - r.left
32
+ offsetY = eventClientY - r.top
33
+ }
34
+
35
+ const x = rbush2.search({
36
+ minX: offsetX,
37
+ maxX: offsetX + 1,
38
+ minY: offsetY,
39
+ maxY: offsetY + 1,
40
+ })
41
+ if (x.length) {
42
+ // prioritize insertions
43
+ const { minX, minY, maxX, maxY, ...rest } =
44
+ x.find(f => f.isInsertion) || x[0]!
45
+ return rest
46
+ } else {
47
+ return undefined
48
+ }
49
+ }
50
+ return (
51
+ <div
52
+ ref={ref}
53
+ onMouseMove={e =>
54
+ displayModel.setHoveredInfo?.(
55
+ getFeatureUnderMouse(e.clientX, e.clientY),
56
+ )
57
+ }
58
+ onMouseLeave={() => {
59
+ displayModel.setHoveredInfo?.(undefined)
60
+ }}
61
+ onMouseOut={() => {
62
+ displayModel.setHoveredInfo?.(undefined)
63
+ }}
64
+ style={{
65
+ overflow: 'visible',
66
+ position: 'relative',
67
+ height,
68
+ }}
69
+ >
70
+ <PrerenderedCanvas
71
+ {...props}
72
+ style={{
73
+ position: 'absolute',
74
+ left: 0,
75
+ }}
76
+ />
77
+ </div>
78
+ )
11
79
  })
12
80
 
13
81
  export default LinearMafRendering
@@ -0,0 +1,13 @@
1
+ export function minElt<T>(arr: Iterable<T>, cb: (arg: T) => number) {
2
+ let min = Infinity
3
+ let minElement: T | undefined
4
+ for (const entry of arr) {
5
+ const val = cb(entry)
6
+
7
+ if (val < min) {
8
+ min = val
9
+ minElement = entry
10
+ }
11
+ }
12
+ return minElement
13
+ }