react-msaview 2.1.5 → 3.0.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.
Files changed (199) hide show
  1. package/bundle/index.js +37 -255
  2. package/dist/DialogQueue.d.ts +25 -0
  3. package/dist/DialogQueue.js +46 -0
  4. package/dist/DialogQueue.js.map +1 -0
  5. package/dist/UniprotTrack.js.map +1 -1
  6. package/dist/colorSchemes.js.map +1 -1
  7. package/dist/components/BoxTrackBlock.js +3 -2
  8. package/dist/components/BoxTrackBlock.js.map +1 -1
  9. package/dist/components/Header.js +12 -20
  10. package/dist/components/Header.js.map +1 -1
  11. package/dist/components/HeaderInfoArea.d.ts +6 -0
  12. package/dist/components/HeaderInfoArea.js +12 -0
  13. package/dist/components/HeaderInfoArea.js.map +1 -0
  14. package/dist/components/ImportForm/ImportFormExamples.d.ts +6 -0
  15. package/dist/components/ImportForm/ImportFormExamples.js +50 -0
  16. package/dist/components/ImportForm/ImportFormExamples.js.map +1 -0
  17. package/dist/components/ImportForm/data/seq2.js.map +1 -0
  18. package/dist/components/{ImportForm.d.ts → ImportForm/index.d.ts} +1 -1
  19. package/dist/components/ImportForm/index.js +31 -0
  20. package/dist/components/ImportForm/index.js.map +1 -0
  21. package/dist/components/ImportForm/util.d.ts +3 -0
  22. package/dist/components/ImportForm/util.js +15 -0
  23. package/dist/components/ImportForm/util.js.map +1 -0
  24. package/dist/components/MSAPanel/Loading.d.ts +2 -0
  25. package/dist/components/MSAPanel/Loading.js +12 -0
  26. package/dist/components/MSAPanel/Loading.js.map +1 -0
  27. package/dist/components/{MSABlock.d.ts → MSAPanel/MSABlock.d.ts} +1 -1
  28. package/dist/components/MSAPanel/MSABlock.js +46 -0
  29. package/dist/components/MSAPanel/MSABlock.js.map +1 -0
  30. package/dist/components/{MSACanvas.d.ts → MSAPanel/MSACanvas.d.ts} +1 -1
  31. package/dist/components/{MSACanvas.js → MSAPanel/MSACanvas.js} +2 -4
  32. package/dist/components/MSAPanel/MSACanvas.js.map +1 -0
  33. package/dist/components/{MSAMouseoverCanvas.d.ts → MSAPanel/MSAMouseoverCanvas.d.ts} +1 -1
  34. package/dist/components/MSAPanel/MSAMouseoverCanvas.js +29 -0
  35. package/dist/components/MSAPanel/MSAMouseoverCanvas.js.map +1 -0
  36. package/dist/components/MSAPanel/index.d.ts +5 -0
  37. package/dist/components/MSAPanel/index.js +9 -0
  38. package/dist/components/MSAPanel/index.js.map +1 -0
  39. package/dist/components/MSAPanel/renderMSABlock.d.ts +8 -0
  40. package/dist/components/MSAPanel/renderMSABlock.js +80 -0
  41. package/dist/components/MSAPanel/renderMSABlock.js.map +1 -0
  42. package/dist/components/MSAPanel/renderMSAMouseover.d.ts +5 -0
  43. package/dist/components/MSAPanel/renderMSAMouseover.js +24 -0
  44. package/dist/components/MSAPanel/renderMSAMouseover.js.map +1 -0
  45. package/dist/components/MSAView.d.ts +2 -2
  46. package/dist/components/MSAView.js +26 -31
  47. package/dist/components/MSAView.js.map +1 -1
  48. package/dist/components/Minimap.d.ts +6 -0
  49. package/dist/components/Minimap.js +72 -0
  50. package/dist/components/Minimap.js.map +1 -0
  51. package/dist/components/ResizeHandles.js.map +1 -1
  52. package/dist/components/TextTrack.js +3 -2
  53. package/dist/components/TextTrack.js.map +1 -1
  54. package/dist/components/Track.js +5 -5
  55. package/dist/components/Track.js.map +1 -1
  56. package/dist/components/{TreeBranchMenu.d.ts → TreePanel/TreeBranchMenu.d.ts} +1 -1
  57. package/dist/components/TreePanel/TreeBranchMenu.js.map +1 -0
  58. package/dist/components/{TreeCanvas.d.ts → TreePanel/TreeCanvas.d.ts} +1 -1
  59. package/dist/components/{TreeCanvas.js → TreePanel/TreeCanvas.js} +1 -1
  60. package/dist/components/TreePanel/TreeCanvas.js.map +1 -0
  61. package/dist/components/{TreeCanvasBlock.d.ts → TreePanel/TreeCanvasBlock.d.ts} +1 -1
  62. package/dist/components/TreePanel/TreeCanvasBlock.js +121 -0
  63. package/dist/components/TreePanel/TreeCanvasBlock.js.map +1 -0
  64. package/dist/components/{TreeMenu.d.ts → TreePanel/TreeNodeMenu.d.ts} +2 -1
  65. package/dist/components/{TreeMenu.js → TreePanel/TreeNodeMenu.js} +16 -8
  66. package/dist/components/TreePanel/TreeNodeMenu.js.map +1 -0
  67. package/dist/components/{TreeRuler.d.ts → TreePanel/TreeRuler.d.ts} +1 -1
  68. package/dist/components/TreePanel/TreeRuler.js +8 -0
  69. package/dist/components/TreePanel/TreeRuler.js.map +1 -0
  70. package/dist/components/{dialogs/TreeNodeInfoDlg.d.ts → TreePanel/dialogs/TreeNodeInfoDialog.d.ts} +1 -1
  71. package/dist/components/{dialogs/TreeNodeInfoDlg.js → TreePanel/dialogs/TreeNodeInfoDialog.js} +2 -2
  72. package/dist/components/TreePanel/dialogs/TreeNodeInfoDialog.js.map +1 -0
  73. package/dist/components/TreePanel/index.d.ts +6 -0
  74. package/dist/components/TreePanel/index.js +10 -0
  75. package/dist/components/TreePanel/index.js.map +1 -0
  76. package/dist/components/TreePanel/renderTreeCanvas.d.ts +41 -0
  77. package/dist/components/TreePanel/renderTreeCanvas.js +154 -0
  78. package/dist/components/TreePanel/renderTreeCanvas.js.map +1 -0
  79. package/dist/components/dialogs/{AboutDlg.js → AboutDialog.js} +1 -1
  80. package/dist/components/dialogs/AboutDialog.js.map +1 -0
  81. package/dist/components/dialogs/{AddTrackDlg.js → AddTrackDialog.js} +1 -1
  82. package/dist/components/dialogs/AddTrackDialog.js.map +1 -0
  83. package/dist/components/dialogs/{MetadataDlg.js → MetadataDialog.js} +1 -1
  84. package/dist/components/dialogs/MetadataDialog.js.map +1 -0
  85. package/dist/components/dialogs/SettingsDialog.js +63 -0
  86. package/dist/components/dialogs/SettingsDialog.js.map +1 -0
  87. package/dist/components/dialogs/{TrackInfoDlg.js → TrackInfoDialog.js} +1 -1
  88. package/dist/components/dialogs/TrackInfoDialog.js.map +1 -0
  89. package/dist/components/dialogs/{TracklistDlg.js → TracklistDialog.js} +1 -1
  90. package/dist/components/dialogs/TracklistDialog.js.map +1 -0
  91. package/dist/components/util.js.map +1 -1
  92. package/dist/layout.js.map +1 -1
  93. package/dist/model.d.ts +179 -88
  94. package/dist/model.js +287 -175
  95. package/dist/model.js.map +1 -1
  96. package/dist/parseNewick.js.map +1 -1
  97. package/dist/parsers/ClustalMSA.d.ts +1 -1
  98. package/dist/parsers/ClustalMSA.js +1 -1
  99. package/dist/parsers/ClustalMSA.js.map +1 -1
  100. package/dist/parsers/FastaMSA.d.ts +1 -1
  101. package/dist/parsers/FastaMSA.js +2 -2
  102. package/dist/parsers/FastaMSA.js.map +1 -1
  103. package/dist/parsers/StockholmMSA.d.ts +1 -1
  104. package/dist/parsers/StockholmMSA.js +2 -2
  105. package/dist/parsers/StockholmMSA.js.map +1 -1
  106. package/dist/util.d.ts +1 -0
  107. package/dist/util.js +15 -7
  108. package/dist/util.js.map +1 -1
  109. package/dist/version.d.ts +1 -1
  110. package/dist/version.js +1 -1
  111. package/package.json +6 -4
  112. package/src/DialogQueue.ts +47 -0
  113. package/src/components/BoxTrackBlock.tsx +3 -1
  114. package/src/components/Header.tsx +13 -20
  115. package/src/components/HeaderInfoArea.tsx +21 -0
  116. package/src/components/ImportForm/ImportFormExamples.tsx +133 -0
  117. package/src/components/ImportForm/index.tsx +63 -0
  118. package/src/components/ImportForm/util.ts +20 -0
  119. package/src/components/MSAPanel/Loading.tsx +16 -0
  120. package/src/components/MSAPanel/MSABlock.tsx +81 -0
  121. package/src/components/{MSACanvas.tsx → MSAPanel/MSACanvas.tsx} +3 -6
  122. package/src/components/MSAPanel/MSAMouseoverCanvas.tsx +44 -0
  123. package/src/components/MSAPanel/index.tsx +13 -0
  124. package/src/components/MSAPanel/renderMSABlock.ts +158 -0
  125. package/src/components/MSAPanel/renderMSAMouseover.ts +51 -0
  126. package/src/components/MSAView.tsx +36 -56
  127. package/src/components/Minimap.tsx +102 -0
  128. package/src/components/TextTrack.tsx +3 -1
  129. package/src/components/Track.tsx +5 -5
  130. package/src/components/{TreeBranchMenu.tsx → TreePanel/TreeBranchMenu.tsx} +1 -1
  131. package/src/components/{TreeCanvas.tsx → TreePanel/TreeCanvas.tsx} +2 -3
  132. package/src/components/TreePanel/TreeCanvasBlock.tsx +195 -0
  133. package/src/components/{TreeMenu.tsx → TreePanel/TreeNodeMenu.tsx} +21 -8
  134. package/src/components/{TreeRuler.tsx → TreePanel/TreeRuler.tsx} +3 -3
  135. package/src/components/{dialogs/TreeNodeInfoDlg.tsx → TreePanel/dialogs/TreeNodeInfoDialog.tsx} +2 -2
  136. package/src/components/TreePanel/index.tsx +16 -0
  137. package/src/components/TreePanel/renderTreeCanvas.ts +254 -0
  138. package/src/components/dialogs/SettingsDialog.tsx +196 -0
  139. package/src/model.ts +414 -211
  140. package/src/parsers/ClustalMSA.ts +1 -1
  141. package/src/parsers/FastaMSA.ts +1 -1
  142. package/src/parsers/StockholmMSA.ts +1 -1
  143. package/src/util.ts +19 -6
  144. package/src/version.ts +1 -1
  145. package/dist/components/ImportForm.js +0 -84
  146. package/dist/components/ImportForm.js.map +0 -1
  147. package/dist/components/MSABlock.js +0 -103
  148. package/dist/components/MSABlock.js.map +0 -1
  149. package/dist/components/MSACanvas.js.map +0 -1
  150. package/dist/components/MSAMouseoverCanvas.js +0 -61
  151. package/dist/components/MSAMouseoverCanvas.js.map +0 -1
  152. package/dist/components/Rubberband.d.ts +0 -8
  153. package/dist/components/Rubberband.js +0 -173
  154. package/dist/components/Rubberband.js.map +0 -1
  155. package/dist/components/Ruler.d.ts +0 -6
  156. package/dist/components/Ruler.js +0 -52
  157. package/dist/components/Ruler.js.map +0 -1
  158. package/dist/components/TreeBranchMenu.js.map +0 -1
  159. package/dist/components/TreeCanvas.js.map +0 -1
  160. package/dist/components/TreeCanvasBlock.js +0 -255
  161. package/dist/components/TreeCanvasBlock.js.map +0 -1
  162. package/dist/components/TreeMenu.js.map +0 -1
  163. package/dist/components/TreeRuler.js +0 -8
  164. package/dist/components/TreeRuler.js.map +0 -1
  165. package/dist/components/data/seq2.js.map +0 -1
  166. package/dist/components/dialogs/AboutDlg.js.map +0 -1
  167. package/dist/components/dialogs/AddTrackDlg.js.map +0 -1
  168. package/dist/components/dialogs/AnnotationDlg.d.ts +0 -11
  169. package/dist/components/dialogs/AnnotationDlg.js +0 -65
  170. package/dist/components/dialogs/AnnotationDlg.js.map +0 -1
  171. package/dist/components/dialogs/MetadataDlg.js.map +0 -1
  172. package/dist/components/dialogs/SettingsDlg.js +0 -48
  173. package/dist/components/dialogs/SettingsDlg.js.map +0 -1
  174. package/dist/components/dialogs/TrackInfoDlg.js.map +0 -1
  175. package/dist/components/dialogs/TracklistDlg.js.map +0 -1
  176. package/dist/components/dialogs/TreeNodeInfoDlg.js.map +0 -1
  177. package/src/components/ImportForm.tsx +0 -192
  178. package/src/components/MSABlock.tsx +0 -164
  179. package/src/components/MSAMouseoverCanvas.tsx +0 -99
  180. package/src/components/Rubberband.tsx +0 -270
  181. package/src/components/Ruler.tsx +0 -123
  182. package/src/components/TreeCanvasBlock.tsx +0 -363
  183. package/src/components/dialogs/AnnotationDlg.tsx +0 -144
  184. package/src/components/dialogs/SettingsDlg.tsx +0 -154
  185. /package/dist/components/{data → ImportForm/data}/seq2.d.ts +0 -0
  186. /package/dist/components/{data → ImportForm/data}/seq2.js +0 -0
  187. /package/dist/components/{TreeBranchMenu.js → TreePanel/TreeBranchMenu.js} +0 -0
  188. /package/dist/components/dialogs/{AboutDlg.d.ts → AboutDialog.d.ts} +0 -0
  189. /package/dist/components/dialogs/{AddTrackDlg.d.ts → AddTrackDialog.d.ts} +0 -0
  190. /package/dist/components/dialogs/{MetadataDlg.d.ts → MetadataDialog.d.ts} +0 -0
  191. /package/dist/components/dialogs/{SettingsDlg.d.ts → SettingsDialog.d.ts} +0 -0
  192. /package/dist/components/dialogs/{TrackInfoDlg.d.ts → TrackInfoDialog.d.ts} +0 -0
  193. /package/dist/components/dialogs/{TracklistDlg.d.ts → TracklistDialog.d.ts} +0 -0
  194. /package/src/components/{data → ImportForm/data}/seq2.ts +0 -0
  195. /package/src/components/dialogs/{AboutDlg.tsx → AboutDialog.tsx} +0 -0
  196. /package/src/components/dialogs/{AddTrackDlg.tsx → AddTrackDialog.tsx} +0 -0
  197. /package/src/components/dialogs/{MetadataDlg.tsx → MetadataDialog.tsx} +0 -0
  198. /package/src/components/dialogs/{TrackInfoDlg.tsx → TrackInfoDialog.tsx} +0 -0
  199. /package/src/components/dialogs/{TracklistDlg.tsx → TracklistDialog.tsx} +0 -0
@@ -0,0 +1,102 @@
1
+ import React, { useEffect, useRef, useState } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { MsaViewModel } from '../model'
4
+
5
+ const Minimap = observer(function ({ model }: { model: MsaViewModel }) {
6
+ const [mouseDown, setMouseDown] = useState<{
7
+ clientX: number
8
+ scrollX: number
9
+ }>()
10
+ const scheduled = useRef(false)
11
+ const [hovered, setHovered] = useState(false)
12
+ const {
13
+ scrollX,
14
+ msaAreaWidth: W,
15
+ minimapHeight: H,
16
+ colWidth,
17
+ numColumns,
18
+ } = model
19
+ const unit = W / numColumns / colWidth
20
+ const left = -scrollX
21
+ const right = left + W
22
+ const s = left * unit
23
+ const e = right * unit
24
+ const fill = 'rgba(66, 119, 127, 0.3)'
25
+
26
+ useEffect(() => {
27
+ function fn(event: MouseEvent) {
28
+ if (mouseDown !== undefined) {
29
+ if (!scheduled.current) {
30
+ scheduled.current = true
31
+ window.requestAnimationFrame(() => {
32
+ model.setScrollX(
33
+ mouseDown.scrollX - (event.clientX - mouseDown.clientX) / unit,
34
+ )
35
+ scheduled.current = false
36
+ })
37
+ }
38
+ }
39
+ }
40
+ function fn2() {
41
+ setMouseDown(undefined)
42
+ }
43
+ if (mouseDown !== undefined) {
44
+ document.addEventListener('mousemove', fn)
45
+ document.addEventListener('mouseup', fn2)
46
+ return () => {
47
+ document.removeEventListener('mousemove', fn)
48
+ document.removeEventListener('mousemove', fn2)
49
+ }
50
+ }
51
+ }, [model, unit, mouseDown])
52
+
53
+ const BAR_HEIGHT = 12
54
+ const H2 = H - 12
55
+ return (
56
+ <div style={{ position: 'relative', height: H, width: '100%' }}>
57
+ <div
58
+ style={{
59
+ boxSizing: 'border-box',
60
+ height: BAR_HEIGHT,
61
+ border: '1px solid #555',
62
+ }}
63
+ />
64
+ <div
65
+ style={{
66
+ position: 'absolute',
67
+ top: 0,
68
+ left: Math.max(0, s),
69
+ background: hovered ? 'rgba(66,119,127,0.6)' : fill,
70
+ cursor: 'pointer',
71
+ border: '1px solid #555',
72
+ boxSizing: 'border-box',
73
+ height: BAR_HEIGHT,
74
+ width: e - s,
75
+ zIndex: 100,
76
+ }}
77
+ onMouseOver={() => setHovered(true)}
78
+ onMouseOut={() => setHovered(false)}
79
+ onMouseDown={event => {
80
+ setMouseDown({
81
+ clientX: event.clientX,
82
+ scrollX: model.scrollX,
83
+ })
84
+ }}
85
+ />
86
+
87
+ <svg height={H2} style={{ width: '100%' }}>
88
+ <polygon
89
+ fill={fill}
90
+ points={[
91
+ [e, 0],
92
+ [s, 0],
93
+ [0, H2],
94
+ [W, H2],
95
+ ].toString()}
96
+ />
97
+ </svg>
98
+ </div>
99
+ )
100
+ })
101
+
102
+ export default Minimap
@@ -20,6 +20,7 @@ const AnnotationBlock = observer(function ({
20
20
  bgColor,
21
21
  colorScheme: modelColorScheme,
22
22
  colWidth,
23
+ fontSize,
23
24
  rowHeight,
24
25
  highResScaleFactor,
25
26
  } = model
@@ -50,7 +51,7 @@ const AnnotationBlock = observer(function ({
50
51
  ctx.clearRect(0, 0, blockSize, rowHeight)
51
52
  ctx.translate(-offsetX, 0)
52
53
  ctx.textAlign = 'center'
53
- ctx.font = ctx.font.replace(/\d+px/, `${Math.max(8, rowHeight - 8)}px`)
54
+ ctx.font = ctx.font.replace(/\d+px/, `${fontSize}px`)
54
55
 
55
56
  const xStart = Math.max(0, Math.floor(offsetX / colWidth))
56
57
  const xEnd = Math.max(0, Math.ceil((offsetX + blockSize) / colWidth))
@@ -69,6 +70,7 @@ const AnnotationBlock = observer(function ({
69
70
  }
70
71
  }
71
72
  }, [
73
+ fontSize,
72
74
  bgColor,
73
75
  blockSize,
74
76
  colWidth,
@@ -10,7 +10,7 @@ import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'
10
10
  // locals
11
11
  import { MsaViewModel } from '../model'
12
12
 
13
- const TrackInfoDialog = lazy(() => import('./dialogs/TrackInfoDlg'))
13
+ const TrackInfoDialog = lazy(() => import('./dialogs/TrackInfoDialog'))
14
14
 
15
15
  const useStyles = makeStyles()({
16
16
  button: {
@@ -27,7 +27,7 @@ export const TrackLabel = observer(function ({
27
27
  track: any
28
28
  }) {
29
29
  const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>()
30
- const [trackInfoDlgOpen, setTrackInfoDlgOpen] = useState(false)
30
+ const [trackInfoDialogOpen, setTrackInfoDialogOpen] = useState(false)
31
31
  const { rowHeight, treeAreaWidth: width } = model
32
32
  const {
33
33
  height,
@@ -76,7 +76,7 @@ export const TrackLabel = observer(function ({
76
76
  <MenuItem
77
77
  dense
78
78
  onClick={() => {
79
- setTrackInfoDlgOpen(true)
79
+ setTrackInfoDialogOpen(true)
80
80
  setAnchorEl(undefined)
81
81
  }}
82
82
  >
@@ -84,11 +84,11 @@ export const TrackLabel = observer(function ({
84
84
  </MenuItem>
85
85
  </Menu>
86
86
  ) : null}
87
- {trackInfoDlgOpen ? (
87
+ {trackInfoDialogOpen ? (
88
88
  <Suspense fallback={null}>
89
89
  <TrackInfoDialog
90
90
  model={track.model}
91
- onClose={() => setTrackInfoDlgOpen(false)}
91
+ onClose={() => setTrackInfoDialogOpen(false)}
92
92
  />
93
93
  </Suspense>
94
94
  ) : null}
@@ -3,7 +3,7 @@ import { Menu, MenuItem } from '@mui/material'
3
3
  import { observer } from 'mobx-react'
4
4
 
5
5
  // locals
6
- import { MsaViewModel } from '../model'
6
+ import { MsaViewModel } from '../../model'
7
7
 
8
8
  interface Node {
9
9
  x: number
@@ -3,10 +3,9 @@ import normalizeWheel from 'normalize-wheel'
3
3
  import { observer } from 'mobx-react'
4
4
 
5
5
  // locals
6
- import { MsaViewModel } from '../model'
6
+ import { MsaViewModel } from '../../model'
7
7
  import TreeCanvasBlock from './TreeCanvasBlock'
8
-
9
- const padding = 600
8
+ import { padding } from './renderTreeCanvas'
10
9
 
11
10
  const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
12
11
  const ref = useRef<HTMLDivElement>(null)
@@ -0,0 +1,195 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react'
2
+ import { autorun } from 'mobx'
3
+ import { observer } from 'mobx-react'
4
+ import { useTheme } from '@mui/material'
5
+ import RBush from 'rbush'
6
+
7
+ // locals
8
+ import { MsaViewModel } from '../../model'
9
+ import TreeNodeMenu from './TreeNodeMenu'
10
+ import TreeBranchMenu from './TreeBranchMenu'
11
+ import { padding, renderTreeCanvas } from './renderTreeCanvas'
12
+
13
+ interface TooltipData {
14
+ name: string
15
+ id: string
16
+ x: number
17
+ y: number
18
+ }
19
+
20
+ interface ClickEntry {
21
+ name: string
22
+ id: string
23
+ branch?: boolean
24
+ minX: number
25
+ maxX: number
26
+ minY: number
27
+ maxY: number
28
+ }
29
+
30
+ const TreeCanvasBlock = observer(function ({
31
+ model,
32
+ offsetY,
33
+ }: {
34
+ model: MsaViewModel
35
+ offsetY: number
36
+ }) {
37
+ const theme = useTheme()
38
+ const ref = useRef<HTMLCanvasElement>()
39
+ const clickMap = useRef(new RBush<ClickEntry>())
40
+ const mouseoverRef = useRef<HTMLCanvasElement>(null)
41
+ const [branchMenu, setBranchMenu] = useState<TooltipData>()
42
+ const [toggleNodeMenu, setToggleNodeMenu] = useState<TooltipData>()
43
+ const [hoverElt, setHoverElt] = useState<ClickEntry>()
44
+
45
+ const { scrollY, treeAreaWidth, margin, blockSize, highResScaleFactor } =
46
+ model
47
+
48
+ const width = treeAreaWidth + padding
49
+ const height = blockSize
50
+ const w2 = width * highResScaleFactor
51
+ const h2 = height * highResScaleFactor
52
+
53
+ const vref = useCallback(
54
+ (arg: HTMLCanvasElement) => {
55
+ model.incrementRef()
56
+ ref.current = arg
57
+ },
58
+ // eslint-disable-next-line react-hooks/exhaustive-deps
59
+ [model, height, width],
60
+ )
61
+ useEffect(() => {
62
+ const ctx = ref.current?.getContext('2d')
63
+ if (!ctx) {
64
+ return
65
+ }
66
+
67
+ return autorun(() => {
68
+ renderTreeCanvas({
69
+ ctx,
70
+ model,
71
+ offsetY,
72
+ clickMap: clickMap.current,
73
+ theme,
74
+ })
75
+ })
76
+ }, [model, offsetY, theme])
77
+
78
+ useEffect(() => {
79
+ const ctx = mouseoverRef.current?.getContext('2d')
80
+ if (!ctx) {
81
+ return
82
+ }
83
+
84
+ ctx.resetTransform()
85
+ ctx.clearRect(0, 0, treeAreaWidth + padding, blockSize)
86
+ ctx.translate(margin.left, -offsetY)
87
+
88
+ if (hoverElt) {
89
+ const { minX, maxX, minY, maxY } = hoverElt
90
+
91
+ ctx.fillStyle = 'rgba(0,0,0,0.1)'
92
+ ctx.fillRect(minX, minY, maxX - minX, maxY - minY)
93
+ }
94
+ }, [hoverElt, margin.left, offsetY, blockSize, treeAreaWidth])
95
+
96
+ function hoverBranchClickMap(event: React.MouseEvent) {
97
+ const x = event.nativeEvent.offsetX - margin.left
98
+ const y = event.nativeEvent.offsetY
99
+
100
+ const [entry] = clickMap.current.search({
101
+ minX: x,
102
+ maxX: x + 1,
103
+ minY: y + offsetY,
104
+ maxY: y + 1 + offsetY,
105
+ })
106
+
107
+ return entry && entry.branch
108
+ ? { ...entry, x: event.clientX, y: event.clientY }
109
+ : undefined
110
+ }
111
+
112
+ function hoverNameClickMap(event: React.MouseEvent) {
113
+ const x = event.nativeEvent.offsetX - margin.left
114
+ const y = event.nativeEvent.offsetY
115
+ const [entry] = clickMap.current.search({
116
+ minX: x,
117
+ maxX: x + 1,
118
+ minY: y + offsetY,
119
+ maxY: y + 1 + offsetY,
120
+ })
121
+
122
+ return entry && !entry.branch
123
+ ? { ...entry, x: event.clientX, y: event.clientY }
124
+ : undefined
125
+ }
126
+ const style = {
127
+ width,
128
+ height,
129
+ top: scrollY + offsetY,
130
+ left: 0,
131
+ position: 'absolute',
132
+ } as const
133
+ return (
134
+ <>
135
+ {branchMenu?.id ? (
136
+ <TreeBranchMenu
137
+ node={branchMenu}
138
+ model={model}
139
+ onClose={() => setBranchMenu(undefined)}
140
+ />
141
+ ) : null}
142
+
143
+ {toggleNodeMenu?.id ? (
144
+ <TreeNodeMenu
145
+ node={toggleNodeMenu}
146
+ model={model}
147
+ onClose={() => setToggleNodeMenu(undefined)}
148
+ />
149
+ ) : null}
150
+
151
+ <canvas
152
+ width={w2}
153
+ height={h2}
154
+ style={style}
155
+ onMouseMove={event => {
156
+ if (!ref.current) {
157
+ return
158
+ }
159
+
160
+ const ret = hoverNameClickMap(event) || hoverBranchClickMap(event)
161
+ console.log({ ret })
162
+ ref.current.style.cursor = ret ? 'pointer' : 'default'
163
+ setHoverElt(hoverNameClickMap(event))
164
+ }}
165
+ onClick={event => {
166
+ const { clientX: x, clientY: y } = event
167
+
168
+ const data = hoverBranchClickMap(event)
169
+ if (data?.id) {
170
+ setBranchMenu({ ...data, x, y })
171
+ }
172
+
173
+ const data2 = hoverNameClickMap(event)
174
+ if (data2?.id) {
175
+ setToggleNodeMenu({ ...data2, x, y })
176
+ }
177
+ }}
178
+ onMouseLeave={() => setHoverElt(undefined)}
179
+ ref={vref}
180
+ />
181
+ <canvas
182
+ style={{
183
+ ...style,
184
+ pointerEvents: 'none',
185
+ zIndex: 100,
186
+ }}
187
+ width={width}
188
+ height={height}
189
+ ref={mouseoverRef}
190
+ />
191
+ </>
192
+ )
193
+ })
194
+
195
+ export default TreeCanvasBlock
@@ -3,16 +3,16 @@ import { Menu, MenuItem } from '@mui/material'
3
3
  import { observer } from 'mobx-react'
4
4
 
5
5
  // locals
6
- import { MsaViewModel } from '../model'
6
+ import { MsaViewModel } from '../../model'
7
7
 
8
- const TreeNodeInfoDlg = lazy(() => import('./dialogs/TreeNodeInfoDlg'))
8
+ const TreeNodeInfoDialog = lazy(() => import('./dialogs/TreeNodeInfoDialog'))
9
9
 
10
10
  const TreeMenu = observer(function ({
11
11
  node,
12
12
  onClose,
13
13
  model,
14
14
  }: {
15
- node: { x: number; y: number; name: string }
15
+ node: { x: number; y: number; name: string; id: string }
16
16
  model: MsaViewModel
17
17
  onClose: () => void
18
18
  }) {
@@ -39,16 +39,29 @@ const TreeMenu = observer(function ({
39
39
  <MenuItem
40
40
  dense
41
41
  onClick={() => {
42
- model.setDialogComponent(TreeNodeInfoDlg, {
43
- info: model.getRowData(node.name),
44
- model,
45
- nodeName: node.name,
46
- })
42
+ model.queueDialog(onClose => [
43
+ TreeNodeInfoDialog,
44
+ {
45
+ info: model.getRowData(node.name),
46
+ model,
47
+ nodeName: node.name,
48
+ onClose,
49
+ },
50
+ ])
47
51
  onClose()
48
52
  }}
49
53
  >
50
54
  More info...
51
55
  </MenuItem>
56
+ <MenuItem
57
+ dense
58
+ onClick={() => {
59
+ model.hideNode(node.id)
60
+ onClose()
61
+ }}
62
+ >
63
+ Hide node
64
+ </MenuItem>
52
65
 
53
66
  {structures[node.name]?.map(entry => {
54
67
  return !model.selectedStructures.some(n => n.id === node.name) ? (
@@ -2,11 +2,11 @@ import React from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
 
4
4
  // locals
5
- import { MsaViewModel } from '../model'
5
+ import { MsaViewModel } from '../../model'
6
6
 
7
7
  const TreeRuler = observer(({ model }: { model: MsaViewModel }) => {
8
- const { treeWidth } = model
9
- return <div style={{ width: treeWidth }} />
8
+ const { treeAreaWidth } = model
9
+ return <div style={{ flexShrink: 0, width: treeAreaWidth }} />
10
10
  })
11
11
 
12
12
  export default TreeRuler
@@ -6,7 +6,7 @@ import {
6
6
  Attributes,
7
7
  BaseCard,
8
8
  } from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail'
9
- import { MsaViewModel } from '../../model'
9
+ import { MsaViewModel } from '../../../model'
10
10
 
11
11
  export default observer(function ({
12
12
  info,
@@ -25,7 +25,7 @@ export default observer(function ({
25
25
  <Dialog onClose={() => onClose()} open title="Tree node info">
26
26
  <DialogContent>
27
27
  <BaseCard title="Attributes">
28
- <Attributes attributes={info} />
28
+ <Attributes attributes={{ nodeName, ...info }} />
29
29
  </BaseCard>
30
30
  {metadata ? (
31
31
  <BaseCard title="Extra metadata">
@@ -0,0 +1,16 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+
4
+ import { MsaViewModel } from '../../model'
5
+ import TreeCanvas from './TreeCanvas'
6
+
7
+ const TreePanel = observer(function ({ model }: { model: MsaViewModel }) {
8
+ const { treeAreaWidth } = model
9
+ return (
10
+ <div style={{ flexShrink: 0, width: treeAreaWidth }}>
11
+ <TreeCanvas model={model} />
12
+ </div>
13
+ )
14
+ })
15
+
16
+ export default TreePanel