react-msaview 5.0.7 → 5.0.13

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 (169) hide show
  1. package/bundle/index.js +25 -25
  2. package/bundle/index.js.map +1 -1
  3. package/dist/components/Checkbox2.js +3 -6
  4. package/dist/components/Checkbox2.js.map +1 -1
  5. package/dist/components/MSAViewer.d.ts +14 -0
  6. package/dist/components/MSAViewer.js +34 -0
  7. package/dist/components/MSAViewer.js.map +1 -0
  8. package/dist/components/Track.js +5 -24
  9. package/dist/components/Track.js.map +1 -1
  10. package/dist/components/dialogs/DomainDialog.js +2 -5
  11. package/dist/components/dialogs/DomainDialog.js.map +1 -1
  12. package/dist/components/dialogs/InterProScanDialog.js +7 -7
  13. package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
  14. package/dist/components/dialogs/SettingsDialog.js +3 -19
  15. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  16. package/dist/components/header/ColorSchemeMenu.d.ts +6 -0
  17. package/dist/components/header/ColorSchemeMenu.js +19 -0
  18. package/dist/components/header/ColorSchemeMenu.js.map +1 -0
  19. package/dist/components/header/{ZoomStar.d.ts → FileMenu.d.ts} +2 -2
  20. package/dist/components/header/FileMenu.js +71 -0
  21. package/dist/components/header/FileMenu.js.map +1 -0
  22. package/dist/components/header/Header.js +8 -6
  23. package/dist/components/header/Header.js.map +1 -1
  24. package/dist/components/header/HeaderMenu.js +3 -145
  25. package/dist/components/header/HeaderMenu.js.map +1 -1
  26. package/dist/components/header/MSASettingsMenu.d.ts +6 -0
  27. package/dist/components/header/MSASettingsMenu.js +36 -0
  28. package/dist/components/header/MSASettingsMenu.js.map +1 -0
  29. package/dist/components/header/SettingsMenu.js +1 -21
  30. package/dist/components/header/SettingsMenu.js.map +1 -1
  31. package/dist/components/header/TreeSettingsMenu.d.ts +6 -0
  32. package/dist/components/header/TreeSettingsMenu.js +74 -0
  33. package/dist/components/header/TreeSettingsMenu.js.map +1 -0
  34. package/dist/components/header/ZoomMenu.js +0 -8
  35. package/dist/components/header/ZoomMenu.js.map +1 -1
  36. package/dist/components/header/getDomainsMenu.d.ts +31 -0
  37. package/dist/components/header/getDomainsMenu.js +75 -0
  38. package/dist/components/header/getDomainsMenu.js.map +1 -0
  39. package/dist/components/import/ImportFormExamples.js +21 -19
  40. package/dist/components/import/ImportFormExamples.js.map +1 -1
  41. package/dist/components/msa/MSACanvas.js +13 -84
  42. package/dist/components/msa/MSACanvas.js.map +1 -1
  43. package/dist/components/msa/MSACanvasBlock.js +1 -3
  44. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  45. package/dist/components/msa/renderMSABlock.js +2 -4
  46. package/dist/components/msa/renderMSABlock.js.map +1 -1
  47. package/dist/components/msa/renderMSAMouseover.js +1 -7
  48. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  49. package/dist/components/tree/TreeCanvas.js +14 -91
  50. package/dist/components/tree/TreeCanvas.js.map +1 -1
  51. package/dist/components/tree/TreeNodeMenu.js +5 -16
  52. package/dist/components/tree/TreeNodeMenu.js.map +1 -1
  53. package/dist/components/tree/renderTreeCanvas.js +4 -12
  54. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  55. package/dist/constants.d.ts +0 -2
  56. package/dist/constants.js +0 -2
  57. package/dist/constants.js.map +1 -1
  58. package/dist/fetchUtils.d.ts +0 -1
  59. package/dist/fetchUtils.js +0 -4
  60. package/dist/fetchUtils.js.map +1 -1
  61. package/dist/flatToTree.d.ts +0 -5
  62. package/dist/flatToTree.js +13 -30
  63. package/dist/flatToTree.js.map +1 -1
  64. package/dist/hierarchy.d.ts +28 -0
  65. package/dist/hierarchy.js +164 -0
  66. package/dist/hierarchy.js.map +1 -0
  67. package/dist/index.d.ts +2 -0
  68. package/dist/index.js +1 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/launchInterProScan.d.ts +0 -5
  71. package/dist/launchInterProScan.js +5 -3
  72. package/dist/launchInterProScan.js.map +1 -1
  73. package/dist/model/DataModel.d.ts +9 -0
  74. package/dist/model/DataModel.js +12 -1
  75. package/dist/model/DataModel.js.map +1 -1
  76. package/dist/model/msaModel.d.ts +3 -0
  77. package/dist/model/msaModel.js +0 -1
  78. package/dist/model/msaModel.js.map +1 -1
  79. package/dist/model/treeModel.d.ts +3 -6
  80. package/dist/model/treeModel.js +3 -15
  81. package/dist/model/treeModel.js.map +1 -1
  82. package/dist/model.d.ts +24 -77
  83. package/dist/model.js +117 -239
  84. package/dist/model.js.map +1 -1
  85. package/dist/neighborJoining.js +38 -629
  86. package/dist/neighborJoining.js.map +1 -1
  87. package/dist/parseAsn1.d.ts +0 -12
  88. package/dist/parseAsn1.js +125 -332
  89. package/dist/parseAsn1.js.map +1 -1
  90. package/dist/useWheelScroll.d.ts +8 -0
  91. package/dist/useWheelScroll.js +93 -0
  92. package/dist/useWheelScroll.js.map +1 -0
  93. package/dist/util.d.ts +1 -6
  94. package/dist/util.js +5 -34
  95. package/dist/util.js.map +1 -1
  96. package/dist/vendor/copyToClipboard.d.ts +1 -10
  97. package/dist/vendor/copyToClipboard.js +14 -109
  98. package/dist/vendor/copyToClipboard.js.map +1 -1
  99. package/dist/vendor/fileSaver.d.ts +1 -11
  100. package/dist/vendor/fileSaver.js +7 -76
  101. package/dist/vendor/fileSaver.js.map +1 -1
  102. package/dist/version.d.ts +1 -1
  103. package/dist/version.js +1 -1
  104. package/dist/version.js.map +1 -1
  105. package/package.json +10 -13
  106. package/src/collapseLogic.test.ts +115 -0
  107. package/src/components/Checkbox2.tsx +9 -18
  108. package/src/components/MSAViewer.tsx +67 -0
  109. package/src/components/Track.tsx +10 -26
  110. package/src/components/dialogs/DomainDialog.tsx +4 -5
  111. package/src/components/dialogs/InterProScanDialog.tsx +7 -7
  112. package/src/components/dialogs/SettingsDialog.tsx +0 -37
  113. package/src/components/header/ColorSchemeMenu.tsx +35 -0
  114. package/src/components/header/FileMenu.tsx +84 -0
  115. package/src/components/header/Header.tsx +8 -6
  116. package/src/components/header/HeaderMenu.tsx +4 -155
  117. package/src/components/header/MSASettingsMenu.tsx +48 -0
  118. package/src/components/header/SettingsMenu.tsx +0 -23
  119. package/src/components/header/TreeSettingsMenu.tsx +96 -0
  120. package/src/components/header/ZoomMenu.tsx +0 -8
  121. package/src/components/header/getDomainsMenu.ts +83 -0
  122. package/src/components/import/ImportFormExamples.tsx +37 -34
  123. package/src/components/msa/MSACanvas.tsx +21 -91
  124. package/src/components/msa/MSACanvasBlock.tsx +1 -3
  125. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +1 -1
  126. package/src/components/msa/renderMSABlock.ts +2 -5
  127. package/src/components/msa/renderMSAMouseover.ts +0 -6
  128. package/src/components/tree/TreeCanvas.tsx +35 -100
  129. package/src/components/tree/TreeNodeMenu.tsx +5 -14
  130. package/src/components/tree/renderTreeCanvas.ts +8 -21
  131. package/src/constants.ts +0 -2
  132. package/src/fetchUtils.ts +0 -5
  133. package/src/flatToTree.ts +20 -38
  134. package/src/hierarchy.test.ts +120 -0
  135. package/src/hierarchy.ts +220 -0
  136. package/src/index.ts +2 -0
  137. package/src/launchInterProScan.ts +4 -3
  138. package/src/model/DataModel.ts +12 -1
  139. package/src/model/msaModel.ts +0 -2
  140. package/src/model/treeModel.ts +2 -18
  141. package/src/model.ts +179 -278
  142. package/src/neighborJoining.ts +38 -628
  143. package/src/parseAsn1.test.ts +4 -1
  144. package/src/parseAsn1.ts +135 -405
  145. package/src/useWheelScroll.ts +109 -0
  146. package/src/util.ts +5 -50
  147. package/src/vendor/copyToClipboard.ts +14 -122
  148. package/src/vendor/fileSaver.ts +8 -105
  149. package/src/version.ts +1 -1
  150. package/dist/components/dialogs/AddTrackDialog.d.ts +0 -8
  151. package/dist/components/dialogs/AddTrackDialog.js +0 -30
  152. package/dist/components/dialogs/AddTrackDialog.js.map +0 -1
  153. package/dist/components/dialogs/TabPanel.d.ts +0 -6
  154. package/dist/components/dialogs/TabPanel.js +0 -6
  155. package/dist/components/dialogs/TabPanel.js.map +0 -1
  156. package/dist/components/header/ZoomStar.js +0 -40
  157. package/dist/components/header/ZoomStar.js.map +0 -1
  158. package/dist/layout.d.ts +0 -26
  159. package/dist/layout.js +0 -74
  160. package/dist/layout.js.map +0 -1
  161. package/dist/reparseTree.d.ts +0 -2
  162. package/dist/reparseTree.js +0 -15
  163. package/dist/reparseTree.js.map +0 -1
  164. package/src/components/dialogs/AddTrackDialog.tsx +0 -85
  165. package/src/components/dialogs/TabPanel.tsx +0 -19
  166. package/src/components/header/ZoomStar.tsx +0 -74
  167. package/src/createPaletteMap.test.ts +0 -57
  168. package/src/layout.ts +0 -118
  169. package/src/reparseTree.ts +0 -18
@@ -1,9 +1,10 @@
1
- import React, { useEffect, useRef, useState } from 'react'
1
+ import React, { useCallback, useRef } from 'react'
2
2
 
3
3
  import { observer } from 'mobx-react'
4
4
 
5
5
  import Loading from './Loading.tsx'
6
6
  import MSACanvasBlock from './MSACanvasBlock.tsx'
7
+ import { useWheelScroll } from '../../useWheelScroll.ts'
7
8
 
8
9
  import type { MsaViewModel } from '../../model.ts'
9
10
 
@@ -17,100 +18,29 @@ const MSACanvas = observer(function ({ model }: { model: MsaViewModel }) {
17
18
  blocks2d,
18
19
  } = model
19
20
  const ref = useRef<HTMLDivElement>(null)
20
- // wheel
21
- const scheduled = useRef(false)
22
- const deltaX = useRef(0)
23
- const deltaY = useRef(0)
24
- // mouse click-and-drag scrolling
25
- const prevX = useRef(0)
26
- const prevY = useRef(0)
27
- const [mouseDragging, setMouseDragging] = useState(false)
28
- useEffect(() => {
29
- const curr = ref.current
30
- if (!curr) {
31
- return
32
- }
33
- function onWheel(event: WheelEvent) {
34
- deltaX.current += event.deltaX
35
- deltaY.current += event.deltaY
36
-
37
- if (!scheduled.current) {
38
- scheduled.current = true
39
- requestAnimationFrame(() => {
40
- model.doScrollX(-deltaX.current)
41
- model.doScrollY(-deltaY.current)
42
- deltaX.current = 0
43
- deltaY.current = 0
44
- scheduled.current = false
45
- })
46
- }
47
- event.preventDefault()
48
- event.stopPropagation()
49
- }
50
- curr.addEventListener('wheel', onWheel, { passive: false })
51
- return () => {
52
- curr.removeEventListener('wheel', onWheel)
53
- }
54
- }, [model])
55
-
56
- useEffect(() => {
57
- if (mouseDragging) {
58
- function globalMouseMove(event: MouseEvent) {
59
- event.preventDefault()
60
- const currX = event.clientX
61
- const currY = event.clientY
62
- const distanceX = currX - prevX.current
63
- const distanceY = currY - prevY.current
64
- if (distanceX || distanceY) {
65
- if (!scheduled.current) {
66
- scheduled.current = true
67
- window.requestAnimationFrame(() => {
68
- model.doScrollX(distanceX)
69
- model.doScrollY(distanceY)
70
- scheduled.current = false
71
- prevX.current = event.clientX
72
- prevY.current = event.clientY
73
- })
74
- }
75
- }
76
- }
77
-
78
- function globalMouseUp() {
79
- prevX.current = 0
80
- setMouseDragging(false)
81
- }
82
-
83
- window.addEventListener('mousemove', globalMouseMove, true)
84
- window.addEventListener('mouseup', globalMouseUp, true)
85
- return () => {
86
- window.removeEventListener('mousemove', globalMouseMove, true)
87
- window.removeEventListener('mouseup', globalMouseUp, true)
88
- }
89
- }
90
- return undefined
91
- }, [model, mouseDragging])
21
+ const onScrollX = useCallback(
22
+ (d: number) => {
23
+ model.doScrollX(d)
24
+ },
25
+ [model],
26
+ )
27
+ const onScrollY = useCallback(
28
+ (d: number) => {
29
+ model.doScrollY(d)
30
+ },
31
+ [model],
32
+ )
33
+ const { onMouseDown, onMouseUp } = useWheelScroll({
34
+ ref,
35
+ onScrollX,
36
+ onScrollY,
37
+ })
92
38
 
93
39
  return (
94
40
  <div
95
41
  ref={ref}
96
- onMouseDown={event => {
97
- // check if clicking a draggable element or a resize handle
98
- const target = event.target as HTMLElement
99
- if (target.draggable || target.dataset.resizer) {
100
- return
101
- }
102
-
103
- // otherwise do click and drag scroll
104
- if (event.button === 0) {
105
- prevX.current = event.clientX
106
- prevY.current = event.clientY
107
- setMouseDragging(true)
108
- }
109
- }}
110
- onMouseUp={event => {
111
- event.preventDefault()
112
- setMouseDragging(false)
113
- }}
42
+ onMouseDown={onMouseDown}
43
+ onMouseUp={onMouseUp}
114
44
  onMouseLeave={event => {
115
45
  event.preventDefault()
116
46
  }}
@@ -52,8 +52,7 @@ const MSACanvasBlock = observer(function ({
52
52
  blockSize * highResScaleFactor,
53
53
  blockSize * highResScaleFactor,
54
54
  )
55
- const { actuallyShowDomains } = model
56
- if (actuallyShowDomains) {
55
+ if (model.actuallyShowDomains) {
57
56
  renderBoxFeatureCanvasBlock({
58
57
  ctx,
59
58
  offsetX,
@@ -102,7 +101,6 @@ const MSACanvasBlock = observer(function ({
102
101
  if (x >= 0 && x < model.numColumns && y >= 0 && y < model.numRows) {
103
102
  model.setMousePos(x, y)
104
103
  } else {
105
- // Clear mouse position when outside bounds
106
104
  model.setMousePos(undefined, undefined)
107
105
  }
108
106
  }}
@@ -1,6 +1,6 @@
1
+ import type { HierarchyNode } from '../../hierarchy.ts'
1
2
  import type { MsaViewModel } from '../../model.ts'
2
3
  import type { NodeWithIdsAndLength } from '../../types.ts'
3
- import type { HierarchyNode } from 'd3-hierarchy'
4
4
 
5
5
  export function renderBoxFeatureCanvasBlock({
6
6
  model,
@@ -1,7 +1,7 @@
1
+ import type { HierarchyNode } from '../../hierarchy.ts'
1
2
  import type { MsaViewModel } from '../../model.ts'
2
3
  import type { NodeWithIdsAndLength } from '../../types.ts'
3
4
  import type { Theme } from '@mui/material'
4
- import type { HierarchyNode } from 'd3-hierarchy'
5
5
 
6
6
  export function renderMSABlock({
7
7
  model,
@@ -180,7 +180,6 @@ function drawText({
180
180
  colorScheme,
181
181
  columns,
182
182
  colWidth,
183
- contrastLettering,
184
183
  rowHeight,
185
184
  relativeTo,
186
185
  } = model
@@ -214,9 +213,7 @@ function drawText({
214
213
  const displayLetter = isMatchingReference ? '.' : letter
215
214
 
216
215
  const color = colorScheme[letter.toUpperCase()]
217
- const contrast = contrastLettering
218
- ? contrastScheme[letter.toUpperCase()] || 'black'
219
- : 'black'
216
+ const contrast = contrastScheme[letter.toUpperCase()] || 'black'
220
217
 
221
218
  // note: -rowHeight/4 matches +rowHeight/4 in tree
222
219
  ctx.fillStyle = actuallyShowDomains
@@ -22,8 +22,6 @@ export function renderMouseover({
22
22
  scrollX,
23
23
  scrollY,
24
24
  mouseRow,
25
- // @ts-expect-error
26
- mouseCol2,
27
25
  mouseClickRow,
28
26
  mouseClickCol,
29
27
  relativeTo,
@@ -79,8 +77,4 @@ export function renderMouseover({
79
77
  ctx.fillStyle = highlightColor
80
78
  ctx.fillRect(0, mouseClickRow * rowHeight + scrollY, width, rowHeight)
81
79
  }
82
- if (mouseCol2 !== undefined) {
83
- ctx.fillStyle = highlightColor
84
- ctx.fillRect(mouseCol2 * colWidth + scrollX, 0, colWidth, height)
85
- }
86
80
  }
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react'
1
+ import React, { useCallback, useEffect, useRef } from 'react'
2
2
 
3
3
  import { isAlive } from '@jbrowse/mobx-state-tree'
4
4
  import { autorun } from 'mobx'
@@ -6,79 +6,25 @@ import { observer } from 'mobx-react'
6
6
 
7
7
  import TreeCanvasBlock from './TreeCanvasBlock.tsx'
8
8
  import { padding } from './renderTreeCanvas.ts'
9
+ import { useWheelScroll } from '../../useWheelScroll.ts'
9
10
 
10
11
  import type { MsaViewModel } from '../../model.ts'
11
12
 
13
+ const referenceColor = 'rgba(0,128,255,0.3)'
14
+ const treeHoverColor = 'rgba(255,165,0,0.2)'
15
+
12
16
  const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
13
17
  const ref = useRef<HTMLDivElement>(null)
14
18
  const mouseoverRef = useRef<HTMLCanvasElement>(null)
15
- const scheduled = useRef(false)
16
- const deltaY = useRef(0)
17
- const prevY = useRef(0)
18
19
  const { treeWidth, height, blocksY, treeAreaWidth } = model
19
- const [mouseDragging, setMouseDragging] = useState(false)
20
-
21
- useEffect(() => {
22
- const curr = ref.current
23
- if (!curr) {
24
- return
25
- }
26
- function onWheel(event: WheelEvent) {
27
- deltaY.current += event.deltaY
28
-
29
- if (!scheduled.current) {
30
- scheduled.current = true
31
- requestAnimationFrame(() => {
32
- model.doScrollY(-deltaY.current)
33
- deltaY.current = 0
34
- scheduled.current = false
35
- })
36
- }
37
- event.preventDefault()
38
- event.stopPropagation()
39
- }
40
- curr.addEventListener('wheel', onWheel, { passive: false })
41
- return () => {
42
- curr.removeEventListener('wheel', onWheel)
43
- }
44
- }, [model])
45
-
46
- useEffect(() => {
47
- if (mouseDragging) {
48
- function globalMouseMove(event: MouseEvent) {
49
- event.preventDefault()
50
- const currY = event.clientY
51
- const distanceY = currY - prevY.current
52
- if (distanceY) {
53
- if (!scheduled.current) {
54
- scheduled.current = true
55
- window.requestAnimationFrame(() => {
56
- model.doScrollY(distanceY)
57
- scheduled.current = false
58
- prevY.current = event.clientY
59
- })
60
- }
61
- }
62
- }
63
-
64
- function globalMouseUp() {
65
- prevY.current = 0
66
- setMouseDragging(false)
67
- }
68
-
69
- window.addEventListener('mousemove', globalMouseMove, true)
70
- window.addEventListener('mouseup', globalMouseUp, true)
71
- return () => {
72
- window.removeEventListener('mousemove', globalMouseMove, true)
73
- window.removeEventListener('mouseup', globalMouseUp, true)
74
- }
75
- }
76
- return undefined
77
- }, [model, mouseDragging])
20
+ const onScrollY = useCallback(
21
+ (d: number) => {
22
+ model.doScrollY(d)
23
+ },
24
+ [model],
25
+ )
26
+ const { onMouseDown, onMouseUp } = useWheelScroll({ ref, onScrollY })
78
27
 
79
- // Global tree mouseover effect. Only [model] is needed in the dependency
80
- // array because autorun internally tracks all accessed observables
81
- // (treeAreaWidth, height, scrollY, etc.) and re-runs when they change
82
28
  useEffect(() => {
83
29
  const ctx = mouseoverRef.current?.getContext('2d')
84
30
  return ctx
@@ -97,33 +43,38 @@ const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
97
43
  ctx.resetTransform()
98
44
  ctx.clearRect(0, 0, w, h)
99
45
 
100
- // Highlight reference row (relativeTo) persistently
101
46
  if (relativeTo) {
102
47
  const referenceLeaf = leaves.find(
103
48
  leaf => leaf.data.name === relativeTo,
104
49
  )
105
50
  if (referenceLeaf) {
106
- const y = referenceLeaf.x! + sy
107
- ctx.fillStyle = 'rgba(0,128,255,0.3)' // Blue highlight for reference row
108
- ctx.fillRect(0, y - rowHeight / 2, w, rowHeight)
51
+ ctx.fillStyle = referenceColor
52
+ ctx.fillRect(
53
+ 0,
54
+ referenceLeaf.x! + sy - rowHeight / 2,
55
+ w,
56
+ rowHeight,
57
+ )
109
58
  }
110
59
  }
111
60
 
112
- // Highlight multiple rows when hovering over tree nodes
113
61
  if (hoveredTreeNode) {
114
- ctx.fillStyle = 'rgba(255,165,0,0.2)' // Orange highlight for tree hover
62
+ ctx.fillStyle = treeHoverColor
115
63
  for (const descendantName of hoveredTreeNode.descendantNames) {
116
64
  const matchingLeaf = leaves.find(
117
65
  leaf => leaf.data.name === descendantName,
118
66
  )
119
67
  if (matchingLeaf) {
120
- const y = matchingLeaf.x! + sy
121
- ctx.fillRect(0, y - rowHeight / 2, w, rowHeight)
68
+ ctx.fillRect(
69
+ 0,
70
+ matchingLeaf.x! + sy - rowHeight / 2,
71
+ w,
72
+ rowHeight,
73
+ )
122
74
  }
123
75
  }
124
76
  }
125
77
 
126
- // Highlight single tree row corresponding to MSA mouseover (if not part of multi-row hover)
127
78
  if (
128
79
  mouseOverRowName &&
129
80
  mouseOverRowName !== relativeTo &&
@@ -133,9 +84,13 @@ const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
133
84
  leaf => leaf.data.name === mouseOverRowName,
134
85
  )
135
86
  if (matchingLeaf) {
136
- const y = matchingLeaf.x! + sy
137
- ctx.fillStyle = 'rgba(255,165,0,0.2)' // Orange highlight for MSA sync
138
- ctx.fillRect(0, y - rowHeight / 2, w, rowHeight)
87
+ ctx.fillStyle = treeHoverColor
88
+ ctx.fillRect(
89
+ 0,
90
+ matchingLeaf.x! + sy - rowHeight / 2,
91
+ w,
92
+ rowHeight,
93
+ )
139
94
  }
140
95
  }
141
96
  }
@@ -143,31 +98,11 @@ const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
143
98
  : undefined
144
99
  }, [model])
145
100
 
146
- function mouseDown(event: React.MouseEvent) {
147
- // check if clicking a draggable element or a resize handle
148
- const target = event.target as HTMLElement
149
- if (target.draggable || target.dataset.resizer) {
150
- return
151
- }
152
-
153
- // otherwise do click and drag scroll
154
- if (event.button === 0) {
155
- prevY.current = event.clientY
156
- setMouseDragging(true)
157
- }
158
- }
159
-
160
101
  return (
161
102
  <div
162
103
  ref={ref}
163
- onMouseDown={mouseDown}
164
- onMouseUp={event => {
165
- // this local mouseup is used in addition to the global because
166
- // sometimes the global add/remove are not called in time, resulting in
167
- // issue #533
168
- event.preventDefault()
169
- setMouseDragging(false)
170
- }}
104
+ onMouseDown={onMouseDown}
105
+ onMouseUp={onMouseUp}
171
106
  onMouseLeave={event => {
172
107
  event.preventDefault()
173
108
  }}
@@ -24,8 +24,9 @@ const TreeMenu = observer(function ({
24
24
  model: MsaViewModel
25
25
  onClose: () => void
26
26
  }) {
27
- const { collapsed, collapsedLeaves } = model
28
- const { name } = node
27
+ const { collapsed } = model
28
+ const { name, id } = node
29
+ const isCollapsed = collapsed.includes(id)
29
30
  return (
30
31
  <Menu
31
32
  anchorReference="anchorPosition"
@@ -62,21 +63,11 @@ const TreeMenu = observer(function ({
62
63
  <MenuItem
63
64
  dense
64
65
  onClick={() => {
65
- if (collapsed.includes(node.id)) {
66
- model.toggleCollapsed(node.id)
67
- } else {
68
- if (node.id.endsWith('-leafnode')) {
69
- model.toggleCollapsedLeaf(node.id)
70
- } else {
71
- model.toggleCollapsedLeaf(`${node.id}-leafnode`)
72
- }
73
- }
66
+ model.toggleCollapsed(id)
74
67
  onClose()
75
68
  }}
76
69
  >
77
- {collapsed.includes(node.id) || collapsedLeaves.includes(node.id)
78
- ? 'Show node'
79
- : 'Hide node'}
70
+ {isCollapsed ? 'Show node' : 'Hide node'}
80
71
  </MenuItem>
81
72
  <MenuItem
82
73
  dense
@@ -1,3 +1,5 @@
1
+ import { descendants, links } from '../../hierarchy.ts'
2
+
1
3
  import type { MsaViewModel } from '../../model.ts'
2
4
  import type { Theme } from '@mui/material'
3
5
 
@@ -45,15 +47,15 @@ export function renderTree({
45
47
  const { hierarchy, showBranchLenEffective: showBranchLen, blockSize } = model
46
48
  const by = blockSizeYOverride || blockSize
47
49
  ctx.strokeStyle = theme.palette.text.primary
48
- for (const link of hierarchy.links()) {
50
+ for (const link of links(hierarchy)) {
49
51
  const { source, target } = link
50
52
  if (target.height === 0 && !showBranchLen) {
51
53
  continue
52
54
  }
53
55
  const sy = source.x!
54
56
  const ty = target.x!
55
- const tx = showBranchLen ? (target as { len?: number }).len : target.y
56
- const sx = showBranchLen ? (source as { len?: number }).len : source.y
57
+ const tx = showBranchLen ? target.len : target.y
58
+ const sx = showBranchLen ? source.len : source.y
57
59
  if (tx === undefined || sx === undefined) {
58
60
  continue
59
61
  }
@@ -94,8 +96,8 @@ export function renderNodeBubbles({
94
96
  marginLeft: ml,
95
97
  } = model
96
98
  const by = blockSizeYOverride || blockSize
97
- for (const node of hierarchy.descendants()) {
98
- const x = showBranchLen ? (node as { len?: number }).len : node.y
99
+ for (const node of descendants(hierarchy)) {
100
+ const x = showBranchLen ? node.len : node.y
99
101
  if (x === undefined) {
100
102
  continue
101
103
  }
@@ -146,14 +148,10 @@ export function renderTreeLabels({
146
148
  fontSize,
147
149
  showBranchLenEffective: showBranchLen,
148
150
  treeMetadata,
149
- hierarchy,
150
- collapsed,
151
- collapsedLeaves,
152
151
  blockSize,
153
152
  labelsAlignRight,
154
153
  drawTree,
155
154
  treeAreaWidth,
156
- treeWidth,
157
155
  treeAreaWidthMinusMargin,
158
156
  marginLeft,
159
157
  leaves,
@@ -171,7 +169,7 @@ export function renderTreeLabels({
171
169
  const {
172
170
  data: { name, id },
173
171
  } = node
174
- const len = (node as { len?: number }).len
172
+ const len = node.len
175
173
  const y = node.x!
176
174
  const x = node.y!
177
175
 
@@ -182,17 +180,6 @@ export function renderTreeLabels({
182
180
  let xp = 0
183
181
  if (!noTree) {
184
182
  xp = (showBranchLen ? len : x) || 0
185
- if (
186
- !showBranchLen &&
187
- !collapsed.includes(id) &&
188
- !collapsedLeaves.includes(id)
189
- ) {
190
- // this subtraction is a hack to compensate for the leafnode rendering
191
- // glitch (issue #71). the context is that an extra leaf node is added
192
- // so that 'collapsing/hiding leaf nodes is possible' but this causes
193
- // weird workarounds
194
- xp -= treeWidth / hierarchy.height
195
- }
196
183
  }
197
184
 
198
185
  const { width } = ctx.measureText(displayName)
package/src/constants.ts CHANGED
@@ -8,7 +8,6 @@ export const defaultCurrentAlignment = 0
8
8
  export const defaultShowDomains = false
9
9
  export const defaultHideGaps = true
10
10
  export const defaultAllowedGappyness = 100
11
- export const defaultContrastLettering = true
12
11
  export const defaultSubFeatureRows = false
13
12
  export const defaultDrawMsaLetters = true
14
13
 
@@ -21,7 +20,6 @@ export const defaultDrawLabels = true
21
20
  export const defaultLabelsAlignRight = false
22
21
  export const defaultTreeAreaWidth = 400
23
22
  export const defaultTreeWidth = 300
24
- export const defaultTreeWidthMatchesArea = true
25
23
  export const defaultShowBranchLen = true
26
24
  export const defaultDrawTree = true
27
25
  export const defaultDrawNodeBubbles = true
package/src/fetchUtils.ts CHANGED
@@ -20,11 +20,6 @@ export async function jsonfetch<T>(url: string, args?: RequestInit) {
20
20
  return response.json() as T
21
21
  }
22
22
 
23
- export async function arraybufferfetch(url: string) {
24
- const res = await myfetch(url)
25
- return res.arrayBuffer()
26
- }
27
-
28
23
  export function timeout(time: number) {
29
24
  return new Promise(res => setTimeout(res, time))
30
25
  }
package/src/flatToTree.ts CHANGED
@@ -1,10 +1,8 @@
1
- // Define the input item interface
2
1
  interface FlatItem {
3
2
  id: number
4
3
  parent?: number
5
4
  }
6
5
 
7
- // Define the tree node interface
8
6
  interface TreeNode {
9
7
  id: string
10
8
  name: string
@@ -12,46 +10,30 @@ interface TreeNode {
12
10
  children: TreeNode[]
13
11
  }
14
12
 
15
- /**
16
- * Parses a flat list of items into a tree structure
17
- * @param items - Array of flat items with id and optional parent
18
- * @returns Array of root tree nodes
19
- */
20
13
  export function flatToTree(items: FlatItem[]): TreeNode {
21
- // Create a map to store all nodes by their id for quick lookup
22
- const nodeMap = new Map<number, TreeNode>()
14
+ const nodeMap = new Map(
15
+ items.map(item => [
16
+ item.id,
17
+ {
18
+ id: `${item.id}`,
19
+ name: `${item.id}`,
20
+ parent: item.parent !== undefined ? `${item.parent}` : undefined,
21
+ children: [] as TreeNode[],
22
+ },
23
+ ]),
24
+ )
23
25
 
24
- // First pass: Create all tree nodes
25
- items.forEach(item => {
26
- nodeMap.set(item.id, {
27
- ...item,
28
- id: `${item.id}`,
29
- name: `${item.id}`,
30
- parent: item.parent !== undefined ? `${item.parent}` : undefined,
31
- children: [],
32
- })
33
- })
34
-
35
- // Second pass: Build parent-child relationships
36
- const roots: TreeNode[] = []
37
-
38
- items.forEach(item => {
26
+ let root: TreeNode | undefined
27
+ for (const item of items) {
39
28
  const node = nodeMap.get(item.id)!
40
-
41
- if (item.parent !== undefined) {
42
- // This item has a parent, add it to parent's children
43
- const parentNode = nodeMap.get(item.parent)
44
- if (parentNode) {
45
- parentNode.children.push(node)
46
- } else {
47
- // Parent doesn't exist, treat as root
48
- roots.push(node)
49
- }
29
+ const parent =
30
+ item.parent !== undefined ? nodeMap.get(item.parent) : undefined
31
+ if (parent) {
32
+ parent.children.push(node)
50
33
  } else {
51
- // This item has no parent, it's a root node
52
- roots.push(node)
34
+ root ??= node
53
35
  }
54
- })
36
+ }
55
37
 
56
- return roots[0]!
38
+ return root!
57
39
  }