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,63 @@
1
+ import React, { useState } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { Button, Container, Grid, Typography } from '@mui/material'
4
+ import { FileSelector } from '@jbrowse/core/ui'
5
+ import { FileLocation } from '@jbrowse/core/util/types'
6
+
7
+ // locals
8
+ import { MsaViewModel } from '../../model'
9
+ import { load } from './util'
10
+ import ImportFormExamples from './ImportFormExamples'
11
+
12
+ export default observer(({ model }: { model: MsaViewModel }) => {
13
+ const [msaFile, setMsaFile] = useState<FileLocation>()
14
+ const [treeFile, setTreeFile] = useState<FileLocation>()
15
+ const { error } = model
16
+
17
+ return (
18
+ <Container>
19
+ <div style={{ width: '50%' }}>
20
+ {error ? (
21
+ <div style={{ padding: 20 }}>
22
+ <Typography color="error">Error: {`${error}`}</Typography>
23
+ </div>
24
+ ) : null}
25
+ <Typography>
26
+ Open an MSA file (stockholm or clustal format) and/or a tree file
27
+ (newick format).
28
+ </Typography>
29
+ <Typography color="error">
30
+ Note: you can open up just an MSA or just a tree, both are not
31
+ required. Some MSA files e.g. stockholm format have an embedded tree
32
+ also and this is fine, and opening a separate tree file is not
33
+ required.
34
+ </Typography>
35
+ </div>
36
+
37
+ <Grid container spacing={10} justifyContent="center" alignItems="center">
38
+ <Grid item>
39
+ <Typography>MSA file or URL</Typography>
40
+ <FileSelector location={msaFile} setLocation={setMsaFile} />
41
+ <Typography>Tree file or URL</Typography>
42
+ <FileSelector location={treeFile} setLocation={setTreeFile} />
43
+ </Grid>
44
+
45
+ <Grid item>
46
+ <Button
47
+ onClick={() => load(model, msaFile, treeFile)}
48
+ variant="contained"
49
+ color="primary"
50
+ disabled={!msaFile && !treeFile}
51
+ >
52
+ Open
53
+ </Button>
54
+ </Grid>
55
+
56
+ <Grid item>
57
+ <Typography>Examples</Typography>
58
+ <ImportFormExamples model={model} />
59
+ </Grid>
60
+ </Grid>
61
+ </Container>
62
+ )
63
+ })
@@ -0,0 +1,20 @@
1
+ import { FileLocation } from '@jbrowse/core/util'
2
+ import { MsaViewModel } from '../../model'
3
+
4
+ export async function load(
5
+ model: MsaViewModel,
6
+ msaFile?: FileLocation,
7
+ treeFile?: FileLocation,
8
+ ) {
9
+ model.setError(undefined)
10
+ try {
11
+ if (msaFile) {
12
+ await model.setMSAFilehandle(msaFile)
13
+ }
14
+ if (treeFile) {
15
+ await model.setTreeFilehandle(treeFile)
16
+ }
17
+ } catch (e) {
18
+ model.setError(e)
19
+ }
20
+ }
@@ -0,0 +1,16 @@
1
+ import { CircularProgress, Typography } from '@mui/material'
2
+ import React from 'react'
3
+ export default function Loading() {
4
+ return (
5
+ <div
6
+ style={{
7
+ position: 'absolute',
8
+ left: '50%',
9
+ top: '50%',
10
+ }}
11
+ >
12
+ <CircularProgress />
13
+ <Typography>Loading...</Typography>
14
+ </div>
15
+ )
16
+ }
@@ -0,0 +1,81 @@
1
+ import React, { useEffect, useRef, useMemo } from 'react'
2
+ import { autorun } from 'mobx'
3
+ import { useTheme } from '@mui/material'
4
+ import { observer } from 'mobx-react'
5
+
6
+ // locals
7
+ import { renderBlock } from './renderMSABlock'
8
+ import { MsaViewModel } from '../../model'
9
+ import { colorContrast } from '../../util'
10
+
11
+ const MSABlock = observer(function ({
12
+ model,
13
+ offsetX,
14
+ offsetY,
15
+ }: {
16
+ model: MsaViewModel
17
+ offsetX: number
18
+ offsetY: number
19
+ }) {
20
+ const {
21
+ colWidth,
22
+ rowHeight,
23
+ scrollY,
24
+ scrollX,
25
+ colorScheme,
26
+ blockSize,
27
+ highResScaleFactor,
28
+ } = model
29
+ const theme = useTheme()
30
+
31
+ const contrastScheme = useMemo(
32
+ () => colorContrast(colorScheme, theme),
33
+ [colorScheme, theme],
34
+ )
35
+
36
+ const ref = useRef<HTMLCanvasElement>(null)
37
+ useEffect(() => {
38
+ const ctx = ref.current?.getContext('2d')
39
+ if (!ctx) {
40
+ return
41
+ }
42
+ return autorun(() => {
43
+ renderBlock({
44
+ ctx,
45
+ offsetX,
46
+ offsetY,
47
+ contrastScheme,
48
+ model,
49
+ })
50
+ })
51
+ }, [model, offsetX, offsetY, contrastScheme])
52
+ return (
53
+ <canvas
54
+ ref={ref}
55
+ onMouseMove={event => {
56
+ if (!ref.current) {
57
+ return
58
+ }
59
+ const { left, top } = ref.current.getBoundingClientRect()
60
+ const mouseX = event.clientX - left + offsetX
61
+ const mouseY = event.clientY - top + offsetY
62
+ model.setMousePos(
63
+ Math.floor(mouseX / colWidth) + 1,
64
+ Math.floor(mouseY / rowHeight),
65
+ )
66
+ }}
67
+ onMouseLeave={() => model.setMousePos()}
68
+ width={blockSize * highResScaleFactor}
69
+ height={blockSize * highResScaleFactor}
70
+ style={{
71
+ position: 'absolute',
72
+ top: scrollY + offsetY,
73
+ left: scrollX + offsetX,
74
+ width: blockSize,
75
+ height: blockSize,
76
+ }}
77
+ />
78
+ )
79
+ })
80
+
81
+ export default MSABlock
@@ -1,11 +1,11 @@
1
1
  import React, { useEffect, useState, useRef } from 'react'
2
- import { Typography, CircularProgress } from '@mui/material'
3
2
  import { observer } from 'mobx-react'
4
3
  import normalizeWheel from 'normalize-wheel'
5
4
 
6
5
  // locals
7
- import { MsaViewModel } from '../model'
6
+ import { MsaViewModel } from '../../model'
8
7
  import MSABlock from './MSABlock'
8
+ import Loading from './Loading'
9
9
 
10
10
  const MSACanvas = observer(function ({ model }: { model: MsaViewModel }) {
11
11
  const { MSA, msaFilehandle, height, msaAreaWidth, blocks2d } = model
@@ -121,10 +121,7 @@ const MSACanvas = observer(function ({ model }: { model: MsaViewModel }) {
121
121
  }}
122
122
  >
123
123
  {!MSA && !msaFilehandle ? null : !MSA ? (
124
- <div style={{ position: 'absolute', left: '50%', top: '50%' }}>
125
- <CircularProgress />
126
- <Typography>Loading...</Typography>
127
- </div>
124
+ <Loading />
128
125
  ) : (
129
126
  blocks2d.map(([bx, by]) => (
130
127
  <MSABlock
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { autorun } from 'mobx'
4
+
5
+ // locals
6
+ import { MsaViewModel } from '../../model'
7
+ import { renderMouseover } from './renderMSAMouseover'
8
+
9
+ const MSAMouseoverCanvas = observer(function ({
10
+ model,
11
+ }: {
12
+ model: MsaViewModel
13
+ }) {
14
+ const ref = useRef<HTMLCanvasElement>(null)
15
+ const { height, width } = model
16
+ useEffect(() => {
17
+ const ctx = ref.current?.getContext('2d')
18
+ if (!ctx) {
19
+ return
20
+ }
21
+ return autorun(() => {
22
+ renderMouseover({ ctx, model })
23
+ })
24
+ }, [model])
25
+
26
+ return (
27
+ <canvas
28
+ ref={ref}
29
+ width={width}
30
+ height={height}
31
+ style={{
32
+ position: 'absolute',
33
+ top: 0,
34
+ left: 0,
35
+ width,
36
+ height,
37
+ zIndex: 1000,
38
+ pointerEvents: 'none',
39
+ }}
40
+ />
41
+ )
42
+ })
43
+
44
+ export default MSAMouseoverCanvas
@@ -0,0 +1,13 @@
1
+ import React from 'react'
2
+ import MSACanvas from './MSACanvas'
3
+ import MSAMouseoverCanvas from './MSAMouseoverCanvas'
4
+ import { MsaViewModel } from '../../model'
5
+
6
+ export default function MSAPanel({ model }: { model: MsaViewModel }) {
7
+ return (
8
+ <>
9
+ <MSACanvas model={model} />
10
+ <MSAMouseoverCanvas model={model} />
11
+ </>
12
+ )
13
+ }
@@ -0,0 +1,158 @@
1
+ // locals
2
+ import { MsaViewModel } from '../../model'
3
+ import { getClustalXColor, getPercentIdentityColor } from '../../colorSchemes'
4
+ import { NodeWithIdsAndLength } from '../../util'
5
+ import { HierarchyNode } from 'd3-hierarchy'
6
+
7
+ export function renderBlock({
8
+ model,
9
+ offsetX,
10
+ offsetY,
11
+ contrastScheme,
12
+ ctx,
13
+ }: {
14
+ offsetX: number
15
+ offsetY: number
16
+ model: MsaViewModel
17
+ contrastScheme: Record<string, string>
18
+ ctx: CanvasRenderingContext2D
19
+ }) {
20
+ const {
21
+ hierarchy,
22
+ colWidth,
23
+ blockSize,
24
+ rowHeight,
25
+ fontSize,
26
+ highResScaleFactor,
27
+ } = model
28
+ ctx.resetTransform()
29
+ ctx.scale(highResScaleFactor, highResScaleFactor)
30
+ ctx.clearRect(0, 0, blockSize, blockSize)
31
+ ctx.translate(-offsetX, rowHeight / 2 - offsetY)
32
+ ctx.textAlign = 'center'
33
+ ctx.font = ctx.font.replace(/\d+px/, `${fontSize}px`)
34
+
35
+ const leaves = hierarchy.leaves()
36
+ const b = blockSize
37
+
38
+ const yStart = Math.max(0, Math.floor((offsetY - rowHeight) / rowHeight))
39
+ const yEnd = Math.max(0, Math.ceil((offsetY + b + rowHeight) / rowHeight))
40
+ const xStart = Math.max(0, Math.floor(offsetX / colWidth))
41
+ const xEnd = Math.max(0, Math.ceil((offsetX + b) / colWidth))
42
+ const visibleLeaves = leaves.slice(yStart, yEnd)
43
+
44
+ drawTiles({
45
+ model,
46
+ ctx,
47
+ offsetX,
48
+ offsetY,
49
+ xStart,
50
+ xEnd,
51
+ visibleLeaves,
52
+ })
53
+ drawText({
54
+ model,
55
+ ctx,
56
+ offsetX,
57
+ contrastScheme,
58
+ xStart,
59
+ xEnd,
60
+ visibleLeaves,
61
+ })
62
+ }
63
+
64
+ function drawTiles({
65
+ model,
66
+ offsetX,
67
+ ctx,
68
+ visibleLeaves,
69
+ xStart,
70
+ xEnd,
71
+ }: {
72
+ model: MsaViewModel
73
+ offsetX: number
74
+ offsetY: number
75
+ ctx: CanvasRenderingContext2D
76
+ visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
77
+ xStart: number
78
+ xEnd: number
79
+ }) {
80
+ const {
81
+ bgColor,
82
+ colorSchemeName,
83
+ colorScheme,
84
+ colStats,
85
+ columns,
86
+ colWidth,
87
+ rowHeight,
88
+ } = model
89
+
90
+ for (const node of visibleLeaves) {
91
+ const {
92
+ // @ts-expect-error
93
+ x: y,
94
+ data: { name },
95
+ } = node
96
+
97
+ const str = columns[name]?.slice(xStart, xEnd)
98
+ for (let i = 0; i < str?.length; i++) {
99
+ const letter = str[i]
100
+ const color =
101
+ colorSchemeName === 'clustalx_protein_dynamic'
102
+ ? getClustalXColor(colStats[xStart + i], model, name, xStart + i)
103
+ : colorSchemeName === 'percent_identity_dynamic'
104
+ ? getPercentIdentityColor(
105
+ colStats[xStart + i],
106
+ model,
107
+ name,
108
+ xStart + i,
109
+ )
110
+ : colorScheme[letter.toUpperCase()]
111
+ if (bgColor) {
112
+ const x = i * colWidth + offsetX - (offsetX % colWidth)
113
+ ctx.fillStyle = color || 'white'
114
+ ctx.fillRect(x, y - rowHeight, colWidth, rowHeight)
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ function drawText({
121
+ model,
122
+ offsetX,
123
+ contrastScheme,
124
+ ctx,
125
+ visibleLeaves,
126
+ xStart,
127
+ xEnd,
128
+ }: {
129
+ offsetX: number
130
+ model: MsaViewModel
131
+ contrastScheme: Record<string, string>
132
+ ctx: CanvasRenderingContext2D
133
+ visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
134
+ xStart: number
135
+ xEnd: number
136
+ }) {
137
+ const { bgColor, colorScheme, columns, colWidth, rowHeight } = model
138
+ if (rowHeight >= 5 && colWidth > rowHeight / 2) {
139
+ for (const node of visibleLeaves) {
140
+ const {
141
+ // @ts-expect-error
142
+ x: y,
143
+ data: { name },
144
+ } = node
145
+ const str = columns[name]?.slice(xStart, xEnd)
146
+ for (let i = 0; i < str?.length; i++) {
147
+ const letter = str[i]
148
+ const color = colorScheme[letter.toUpperCase()]
149
+ const contrast = contrastScheme[letter.toUpperCase()] || 'black'
150
+ const x = i * colWidth + offsetX - (offsetX % colWidth)
151
+
152
+ // note: -rowHeight/4 matches +rowHeight/4 in tree
153
+ ctx.fillStyle = bgColor ? contrast : color || 'black'
154
+ ctx.fillText(letter, x + colWidth / 2, y - rowHeight / 4)
155
+ }
156
+ }
157
+ }
158
+ }
@@ -0,0 +1,51 @@
1
+ import { MsaViewModel } from '../../model'
2
+
3
+ export function renderMouseover({
4
+ ctx,
5
+ model,
6
+ }: {
7
+ ctx: CanvasRenderingContext2D
8
+ model: MsaViewModel
9
+ }) {
10
+ const {
11
+ mouseCol,
12
+ colWidth,
13
+ treeAreaWidth,
14
+ resizeHandleWidth,
15
+ width,
16
+ height,
17
+ rowHeight,
18
+ scrollX,
19
+ scrollY,
20
+ mouseRow,
21
+ // @ts-expect-error
22
+ mouseCol2,
23
+ minimapHeight,
24
+ totalTrackAreaHeight,
25
+ } = model
26
+ ctx.resetTransform()
27
+ ctx.clearRect(0, 0, width, height)
28
+ console.log({ mouseCol })
29
+
30
+ if (mouseCol !== undefined) {
31
+ ctx.fillStyle = 'rgba(0,0,0,0.15)'
32
+ const x =
33
+ (mouseCol - 1) * colWidth + scrollX + treeAreaWidth + resizeHandleWidth
34
+
35
+ ctx.fillRect(x, minimapHeight, colWidth, height)
36
+ }
37
+
38
+ if (mouseRow !== undefined) {
39
+ ctx.fillStyle = 'rgba(0,0,0,0.15)'
40
+ const y =
41
+ mouseRow * rowHeight + scrollY + minimapHeight + totalTrackAreaHeight
42
+ ctx.fillRect(treeAreaWidth + resizeHandleWidth, y, width, rowHeight)
43
+ }
44
+ if (mouseCol2 !== undefined) {
45
+ ctx.fillStyle = 'rgba(255,255,0,0.2)'
46
+ const x =
47
+ (mouseCol2 - 1) * colWidth + scrollX + treeAreaWidth + resizeHandleWidth
48
+
49
+ ctx.fillRect(x, 0, colWidth, height)
50
+ }
51
+ }
@@ -1,26 +1,21 @@
1
- import React, { lazy, Suspense } from 'react'
1
+ import React, { Suspense } from 'react'
2
2
 
3
3
  import { observer } from 'mobx-react'
4
4
  import { Typography } from '@mui/material'
5
5
 
6
6
  // locals
7
7
  import ImportForm from './ImportForm'
8
- import Rubberband from './Rubberband'
9
- import TreeCanvas from './TreeCanvas'
10
- import MSACanvas from './MSACanvas'
11
- import Ruler from './Ruler'
12
- import TreeRuler from './TreeRuler'
8
+ import TreeRuler from './TreePanel/TreeRuler'
13
9
  import Header from './Header'
14
10
  import Track from './Track'
15
-
16
11
  import { HorizontalResizeHandle, VerticalResizeHandle } from './ResizeHandles'
17
12
  import { MsaViewModel } from '../model'
18
- import MSAMouseoverCanvas from './MSAMouseoverCanvas'
19
-
20
- const AnnotationDialog = lazy(() => import('./dialogs/AnnotationDlg'))
13
+ import MSAPanel from './MSAPanel'
14
+ import TreePanel from './TreePanel'
15
+ import Minimap from './Minimap'
21
16
 
22
- export default observer(function ({ model }: { model: MsaViewModel }) {
23
- const { done, initialized, treeAreaWidth, height, turnedOnTracks } = model
17
+ const MSAView = observer(function ({ model }: { model: MsaViewModel }) {
18
+ const { done, initialized } = model
24
19
 
25
20
  return (
26
21
  <div>
@@ -29,58 +24,43 @@ export default observer(function ({ model }: { model: MsaViewModel }) {
29
24
  ) : !done ? (
30
25
  <Typography variant="h4">Loading...</Typography>
31
26
  ) : (
32
- <div>
33
- <div style={{ height, overflow: 'hidden' }}>
34
- <Header model={model} />
35
- <div>
36
- <div style={{ position: 'relative' }}>
37
- <div style={{ display: 'flex' }}>
38
- <div style={{ flexShrink: 0, width: treeAreaWidth }}>
39
- <TreeRuler model={model} />
40
- </div>
27
+ <MSAView2 model={model} />
28
+ )}
29
+ </div>
30
+ )
31
+ })
41
32
 
42
- <Rubberband
43
- model={model}
44
- ControlComponent={<Ruler model={model} />}
45
- />
46
- </div>
47
- {turnedOnTracks?.map(track => (
48
- <Track key={track.model.id} model={model} track={track} />
49
- ))}
33
+ const MSAView2 = observer(function ({ model }: { model: MsaViewModel }) {
34
+ const { height, turnedOnTracks, DialogComponent, DialogProps } = model
35
+ return (
36
+ <div>
37
+ <div style={{ height, overflow: 'hidden' }}>
38
+ <Header model={model} />
39
+ <div style={{ position: 'relative' }}>
40
+ <div style={{ display: 'flex' }}>
41
+ <TreeRuler model={model} />
42
+ <Minimap model={model} />
43
+ </div>
44
+ {turnedOnTracks?.map(track => (
45
+ <Track key={track.model.id} model={model} track={track} />
46
+ ))}
50
47
 
51
- <div style={{ display: 'flex' }}>
52
- <div style={{ flexShrink: 0, width: treeAreaWidth }}>
53
- <TreeCanvas model={model} />
54
- </div>
55
- <VerticalResizeHandle model={model} />
56
- <MSACanvas model={model} />
57
- <MSAMouseoverCanvas model={model} />
58
- </div>
59
- </div>
60
- </div>
48
+ <div style={{ display: 'flex' }}>
49
+ <TreePanel model={model} />
50
+ <VerticalResizeHandle model={model} />
51
+ <MSAPanel model={model} />
61
52
  </div>
62
- <HorizontalResizeHandle model={model} />
63
53
  </div>
64
- )}
54
+ </div>
55
+ <HorizontalResizeHandle model={model} />
65
56
 
66
- {model.DialogComponent ? (
57
+ {DialogComponent ? (
67
58
  <Suspense fallback={null}>
68
- <model.DialogComponent
69
- {...(model.DialogProps || {})}
70
- onClose={() => model.setDialogComponent()}
71
- />
72
- </Suspense>
73
- ) : null}
74
-
75
- {model.annotPos ? (
76
- <Suspense fallback={null}>
77
- <AnnotationDialog
78
- data={model.annotPos}
79
- model={model}
80
- onClose={() => model.clearAnnotationClickBoundaries()}
81
- />
59
+ <DialogComponent {...DialogProps} />
82
60
  </Suspense>
83
61
  ) : null}
84
62
  </div>
85
63
  )
86
64
  })
65
+
66
+ export default MSAView