react-msaview 4.4.0 → 4.4.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 (63) hide show
  1. package/bundle/index.js +15 -15
  2. package/bundle/index.js.LICENSE.txt +5 -13
  3. package/bundle/index.js.map +1 -1
  4. package/dist/colorSchemes.js +2 -2
  5. package/dist/colorSchemes.js.map +1 -1
  6. package/dist/components/VerticalScrollbar.js +2 -2
  7. package/dist/components/VerticalScrollbar.js.map +1 -1
  8. package/dist/components/dialogs/SettingsDialog.js +3 -2
  9. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  10. package/dist/components/header/Header.js +1 -1
  11. package/dist/components/header/Header.js.map +1 -1
  12. package/dist/components/header/HeaderInfoArea.js +3 -2
  13. package/dist/components/header/HeaderInfoArea.js.map +1 -1
  14. package/dist/components/header/HeaderMenu.js +15 -97
  15. package/dist/components/header/HeaderMenu.js.map +1 -1
  16. package/dist/components/header/SettingsMenu.js +57 -73
  17. package/dist/components/header/SettingsMenu.js.map +1 -1
  18. package/dist/components/header/ZoomMenu.js +14 -2
  19. package/dist/components/header/ZoomMenu.js.map +1 -1
  20. package/dist/components/msa/MSAMouseoverCanvas.js +4 -1
  21. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
  22. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +4 -4
  23. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  24. package/dist/components/msa/renderMSABlock.js +13 -9
  25. package/dist/components/msa/renderMSABlock.js.map +1 -1
  26. package/dist/model.d.ts +17 -5
  27. package/dist/model.js +70 -57
  28. package/dist/model.js.map +1 -1
  29. package/dist/rowCoordinateCalculations.d.ts +13 -2
  30. package/dist/rowCoordinateCalculations.js +60 -17
  31. package/dist/rowCoordinateCalculations.js.map +1 -1
  32. package/dist/rowCoordinateCalculations.test.js +96 -2
  33. package/dist/rowCoordinateCalculations.test.js.map +1 -1
  34. package/dist/seqCoordToRowSpecificGlobalCoord.d.ts +4 -0
  35. package/dist/seqCoordToRowSpecificGlobalCoord.js +15 -0
  36. package/dist/seqCoordToRowSpecificGlobalCoord.js.map +1 -0
  37. package/dist/seqCoordToRowSpecificGlobalCoord.test.d.ts +1 -0
  38. package/dist/seqCoordToRowSpecificGlobalCoord.test.js +42 -0
  39. package/dist/seqCoordToRowSpecificGlobalCoord.test.js.map +1 -0
  40. package/dist/util.d.ts +1 -6
  41. package/dist/util.js +5 -22
  42. package/dist/util.js.map +1 -1
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +1 -1
  46. package/src/colorSchemes.ts +2 -2
  47. package/src/components/VerticalScrollbar.tsx +2 -3
  48. package/src/components/dialogs/SettingsDialog.tsx +4 -2
  49. package/src/components/header/Header.tsx +1 -1
  50. package/src/components/header/HeaderInfoArea.tsx +5 -2
  51. package/src/components/header/HeaderMenu.tsx +15 -110
  52. package/src/components/header/SettingsMenu.tsx +64 -81
  53. package/src/components/header/ZoomMenu.tsx +15 -2
  54. package/src/components/msa/MSAMouseoverCanvas.tsx +4 -1
  55. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +4 -4
  56. package/src/components/msa/renderMSABlock.ts +26 -22
  57. package/src/model.ts +89 -67
  58. package/src/rowCoordinateCalculations.test.ts +138 -2
  59. package/src/rowCoordinateCalculations.ts +95 -18
  60. package/src/seqCoordToRowSpecificGlobalCoord.test.ts +53 -0
  61. package/src/seqCoordToRowSpecificGlobalCoord.ts +20 -0
  62. package/src/util.ts +5 -28
  63. package/src/version.ts +1 -1
@@ -1,16 +1,13 @@
1
1
  import React, { lazy } from 'react'
2
2
 
3
3
  import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
4
- import AccountTreeIcon from '@mui/icons-material/AccountTree'
5
4
  import Assignment from '@mui/icons-material/Assignment'
6
5
  import FilterAlt from '@mui/icons-material/FilterAlt'
7
6
  import FolderOpen from '@mui/icons-material/FolderOpen'
8
- import GridOn from '@mui/icons-material/GridOn'
9
7
  import List from '@mui/icons-material/List'
10
8
  import MoreVert from '@mui/icons-material/Menu'
11
9
  import PhotoCamera from '@mui/icons-material/PhotoCamera'
12
10
  import Search from '@mui/icons-material/Search'
13
- import Settings from '@mui/icons-material/Settings'
14
11
  import Sort from '@mui/icons-material/Sort'
15
12
  import Visibility from '@mui/icons-material/Visibility'
16
13
  import { observer } from 'mobx-react'
@@ -18,30 +15,18 @@ import { observer } from 'mobx-react'
18
15
  import type { MsaViewModel } from '../../model'
19
16
 
20
17
  // lazies
21
- const SettingsDialog = lazy(() => import('../dialogs/SettingsDialog'))
22
18
  const MetadataDialog = lazy(() => import('../dialogs/MetadataDialog'))
23
19
  const TracklistDialog = lazy(() => import('../dialogs/TracklistDialog'))
24
20
  const ExportSVGDialog = lazy(() => import('../dialogs/ExportSVGDialog'))
25
21
  const FeatureFilterDialog = lazy(() => import('../dialogs/FeatureDialog'))
22
+ const SettingsDialog = lazy(() => import('../dialogs/SettingsDialog'))
26
23
  const UserProvidedDomainsDialog = lazy(
27
24
  () => import('../dialogs/UserProvidedDomainsDialog'),
28
25
  )
29
26
  const InterProScanDialog = lazy(() => import('../dialogs/InterProScanDialog'))
30
27
 
31
28
  const HeaderMenu = observer(({ model }: { model: MsaViewModel }) => {
32
- const {
33
- drawTree,
34
- showBranchLen,
35
- labelsAlignRight,
36
- drawNodeBubbles,
37
- showDomains,
38
- actuallyShowDomains,
39
- subFeatureRows,
40
- drawLabels,
41
- treeWidthMatchesArea,
42
- noDomains,
43
- noTree,
44
- } = model
29
+ const { showDomains, actuallyShowDomains, subFeatureRows, noDomains } = model
45
30
  return (
46
31
  <CascadingMenuButton
47
32
  menuItems={[
@@ -52,98 +37,6 @@ const HeaderMenu = observer(({ model }: { model: MsaViewModel }) => {
52
37
  model.reset()
53
38
  },
54
39
  },
55
- {
56
- icon: Settings,
57
- label: 'Settings',
58
- type: 'subMenu',
59
- subMenu: [
60
- {
61
- label: 'Tree settings',
62
- type: 'subMenu',
63
- icon: AccountTreeIcon,
64
- subMenu: [
65
- {
66
- label: 'Show branch length',
67
- type: 'checkbox',
68
- checked: showBranchLen,
69
- onClick: () => {
70
- model.setShowBranchLen(!showBranchLen)
71
- },
72
- },
73
- {
74
- label: 'Show tree',
75
- type: 'checkbox',
76
- checked: drawTree,
77
- onClick: () => {
78
- model.setDrawTree(!drawTree)
79
- },
80
- },
81
- {
82
- label: 'Draw clickable bubbles on tree branches',
83
- type: 'checkbox',
84
- checked: drawNodeBubbles,
85
- onClick: () => {
86
- model.setDrawNodeBubbles(!drawNodeBubbles)
87
- },
88
- },
89
- {
90
- label: 'Tree labels align right',
91
- type: 'checkbox',
92
- checked: labelsAlignRight,
93
- onClick: () => {
94
- model.setLabelsAlignRight(!labelsAlignRight)
95
- },
96
- },
97
- {
98
- label: 'Draw labels',
99
- type: 'checkbox',
100
- checked: drawLabels,
101
- onClick: () => {
102
- model.setDrawLabels(!drawLabels)
103
- },
104
- },
105
- ...(noTree
106
- ? []
107
- : [
108
- {
109
- label: 'Make tree width fit to tree area',
110
- type: 'checkbox' as const,
111
- checked: treeWidthMatchesArea,
112
- onClick: () => {
113
- model.setTreeWidthMatchesArea(!treeWidthMatchesArea)
114
- },
115
- },
116
- ]),
117
- ],
118
- },
119
- {
120
- label: 'MSA settings',
121
- type: 'subMenu',
122
- icon: GridOn,
123
- subMenu: [],
124
- },
125
- {
126
- label: 'More',
127
- icon: Settings,
128
- type: 'subMenu',
129
- subMenu: [
130
- {
131
- label: 'More settings',
132
- onClick: () => {
133
- model.queueDialog(onClose => [
134
- SettingsDialog,
135
- {
136
- model,
137
- onClose,
138
- },
139
- ])
140
- },
141
- },
142
- ],
143
- },
144
- ],
145
- },
146
-
147
40
  {
148
41
  label: 'Metadata',
149
42
  icon: Assignment,
@@ -158,7 +51,19 @@ const HeaderMenu = observer(({ model }: { model: MsaViewModel }) => {
158
51
  },
159
52
  },
160
53
  {
161
- label: ' tracks',
54
+ label: 'More settings',
55
+ onClick: () => {
56
+ model.queueDialog(onClose => [
57
+ SettingsDialog,
58
+ {
59
+ model,
60
+ onClose,
61
+ },
62
+ ])
63
+ },
64
+ },
65
+ {
66
+ label: 'Extra tracks',
162
67
  icon: List,
163
68
  onClick: () => {
164
69
  model.queueDialog(onClose => [
@@ -1,9 +1,8 @@
1
- import React, { lazy } from 'react'
1
+ import React from 'react'
2
2
 
3
3
  import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
4
- import AccountTreeIcon from '@mui/icons-material/AccountTree'
5
- import ColorLensIcon from '@mui/icons-material/ColorLens'
6
- import GridOn from '@mui/icons-material/GridOn'
4
+ import Palette from '@mui/icons-material/Palette'
5
+ import AccountTree from '@mui/icons-material/AccountTree'
7
6
  import Settings from '@mui/icons-material/Settings'
8
7
  import { observer } from 'mobx-react'
9
8
 
@@ -11,32 +10,83 @@ import colorSchemes from '../../colorSchemes'
11
10
 
12
11
  import type { MsaViewModel } from '../../model'
13
12
 
14
- // lazies
15
- const SettingsDialog = lazy(() => import('../dialogs/SettingsDialog'))
16
-
17
- const SettingsMenu = observer(({ model }: { model: MsaViewModel }) => {
13
+ const SettingsMenu = observer(function ({ model }: { model: MsaViewModel }) {
18
14
  const {
15
+ colorSchemeName,
16
+ drawMsaLetters,
17
+ contrastLettering,
18
+ hideGaps,
19
+ bgColor,
19
20
  drawTree,
20
21
  showBranchLen,
21
22
  labelsAlignRight,
22
23
  drawNodeBubbles,
23
24
  drawLabels,
24
25
  treeWidthMatchesArea,
25
- drawMsaLetters,
26
26
  noTree,
27
- bgColor,
28
- hideGaps,
29
- contrastLettering,
30
- colorSchemeName,
31
27
  } = model
32
28
  return (
33
29
  <CascadingMenuButton
34
30
  closeAfterItemClick={false}
35
31
  menuItems={[
32
+ {
33
+ label: 'Color scheme',
34
+ icon: Palette,
35
+ type: 'subMenu',
36
+ subMenu: Object.keys(colorSchemes).map(
37
+ option =>
38
+ ({
39
+ label: option,
40
+ type: 'radio',
41
+ checked: colorSchemeName === option,
42
+ onClick: () => {
43
+ model.setColorSchemeName(option)
44
+ },
45
+ }) as const,
46
+ ),
47
+ },
48
+ {
49
+ label: 'MSA settings',
50
+ type: 'subMenu',
51
+ subMenu: [
52
+ {
53
+ label: 'Draw letters',
54
+ type: 'checkbox',
55
+ checked: drawMsaLetters,
56
+ onClick: () => {
57
+ model.setDrawMsaLetters(!drawMsaLetters)
58
+ },
59
+ },
60
+ {
61
+ label: 'Color letters instead of background of tiles',
62
+ type: 'checkbox',
63
+ checked: !bgColor,
64
+ onClick: () => {
65
+ model.setBgColor(!bgColor)
66
+ },
67
+ },
68
+ {
69
+ label: 'Use contrast lettering',
70
+ type: 'checkbox',
71
+ checked: contrastLettering,
72
+ onClick: () => {
73
+ model.setContrastLettering(!contrastLettering)
74
+ },
75
+ },
76
+ {
77
+ label: 'Enable hiding gappy columns?',
78
+ type: 'checkbox',
79
+ checked: hideGaps,
80
+ onClick: () => {
81
+ model.setHideGaps(!hideGaps)
82
+ },
83
+ },
84
+ ],
85
+ },
36
86
  {
37
87
  label: 'Tree settings',
38
88
  type: 'subMenu',
39
- icon: AccountTreeIcon,
89
+ icon: AccountTree,
40
90
  subMenu: [
41
91
  {
42
92
  label: 'Show branch length',
@@ -92,73 +142,6 @@ const SettingsMenu = observer(({ model }: { model: MsaViewModel }) => {
92
142
  ]),
93
143
  ],
94
144
  },
95
- {
96
- label: 'MSA settings',
97
- type: 'subMenu',
98
- icon: GridOn,
99
- subMenu: [
100
- {
101
- label: 'Draw letters',
102
- type: 'checkbox',
103
- checked: drawMsaLetters,
104
- onClick: () => {
105
- model.setDrawMsaLetters(!drawMsaLetters)
106
- },
107
- },
108
- {
109
- label: 'Color letters instead of background of tiles',
110
- type: 'checkbox',
111
- checked: !bgColor,
112
- onClick: () => {
113
- model.setBgColor(!bgColor)
114
- },
115
- },
116
- {
117
- label: 'Use contrast lettering',
118
- type: 'checkbox',
119
- checked: contrastLettering,
120
- onClick: () => {
121
- model.setContrastLettering(!contrastLettering)
122
- },
123
- },
124
- {
125
- label: 'Enable hiding gappy columns?',
126
- type: 'checkbox',
127
- checked: hideGaps,
128
- onClick: () => {
129
- model.setHideGaps(!hideGaps)
130
- },
131
- },
132
- ],
133
- },
134
- {
135
- label: 'Color scheme',
136
- type: 'subMenu',
137
- icon: ColorLensIcon,
138
- subMenu: Object.keys(colorSchemes).map(
139
- option =>
140
- ({
141
- label: option,
142
- type: 'radio',
143
- checked: colorSchemeName === option,
144
- onClick: () => {
145
- model.setColorSchemeName(option)
146
- },
147
- }) as const,
148
- ),
149
- },
150
- {
151
- label: 'More settings',
152
- onClick: () => {
153
- model.queueDialog(onClose => [
154
- SettingsDialog,
155
- {
156
- model,
157
- onClose,
158
- },
159
- ])
160
- },
161
- },
162
145
  ]}
163
146
  >
164
147
  <Settings />
@@ -12,11 +12,24 @@ const ZoomMenu = observer(function ({ model }: { model: MsaViewModel }) {
12
12
  <CascadingMenuButton
13
13
  menuItems={[
14
14
  {
15
- label: 'Fit to view',
15
+ label: 'Fit both vertically/horizontally',
16
16
  onClick: () => {
17
- model.showEntire()
17
+ model.fit()
18
18
  },
19
19
  },
20
+ {
21
+ label: 'Fit vertically',
22
+ onClick: () => {
23
+ model.fitVertically()
24
+ },
25
+ },
26
+ {
27
+ label: 'Fit horizontally',
28
+ onClick: () => {
29
+ model.fitHorizontally()
30
+ },
31
+ },
32
+
20
33
  {
21
34
  label: 'Reset zoom to default',
22
35
  icon: RestartAlt,
@@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react'
2
2
 
3
3
  import { autorun } from 'mobx'
4
4
  import { observer } from 'mobx-react'
5
+ import { isAlive } from 'mobx-state-tree'
5
6
 
6
7
  import { renderMouseover } from './renderMSAMouseover'
7
8
 
@@ -18,7 +19,9 @@ const MSAMouseoverCanvas = observer(function ({
18
19
  const ctx = ref.current?.getContext('2d')
19
20
  return ctx
20
21
  ? autorun(() => {
21
- renderMouseover({ ctx, model })
22
+ if (isAlive(model)) {
23
+ renderMouseover({ ctx, model })
24
+ }
22
25
  })
23
26
  : undefined
24
27
  }, [model])
@@ -56,7 +56,8 @@ function drawTiles({
56
56
  tidyFilteredGatheredInterProAnnotations,
57
57
  } = model
58
58
 
59
- for (const node of visibleLeaves) {
59
+ for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
60
+ const node = visibleLeaves[i]!
60
61
  const {
61
62
  x,
62
63
  data: { name },
@@ -65,9 +66,9 @@ function drawTiles({
65
66
 
66
67
  const entry = tidyFilteredGatheredInterProAnnotations[name]
67
68
 
68
- let j = 0
69
69
  if (entry) {
70
- for (const { start, end, accession } of entry) {
70
+ for (let j = 0, l2 = entry.length; j < l2; j++) {
71
+ const { start, end, accession } = entry[j]!
71
72
  const m1 = model.seqCoordToRowSpecificGlobalCoord(name, start - 1)
72
73
  const m2 = model.seqCoordToRowSpecificGlobalCoord(name, end)
73
74
  const x = m1 * colWidth
@@ -78,7 +79,6 @@ function drawTiles({
78
79
  const lw = colWidth * (m2 - m1)
79
80
  ctx.fillRect(x, t, lw, h)
80
81
  ctx.strokeRect(x, t, lw, h)
81
- j++
82
82
  }
83
83
  }
84
84
  }
@@ -34,6 +34,7 @@ export function renderMSABlock({
34
34
  highResScaleFactor,
35
35
  actuallyShowDomains,
36
36
  leaves,
37
+ bgColor,
37
38
  } = model
38
39
  const k = highResScaleFactorOverride || highResScaleFactor
39
40
  const bx = blockSizeXOverride || blockSize
@@ -42,7 +43,7 @@ export function renderMSABlock({
42
43
  ctx.scale(k, k)
43
44
  ctx.translate(-offsetX, rowHeight / 2 - offsetY)
44
45
  ctx.textAlign = 'center'
45
- ctx.font = ctx.font.replace(/\d+px/, `${fontSize}px`)
46
+ ctx.font = ctx.font.replace(/\d+px/, `${bgColor ? '' : 'bold '}${fontSize}px`)
46
47
 
47
48
  const yStart = Math.max(0, Math.floor((offsetY - rowHeight) / rowHeight))
48
49
  const yEnd = Math.max(0, Math.ceil((offsetY + by + rowHeight) / rowHeight))
@@ -102,38 +103,40 @@ function drawTiles({
102
103
  rowHeight,
103
104
  } = model
104
105
 
105
- for (const node of visibleLeaves) {
106
+ for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
107
+ const node = visibleLeaves[i]!
106
108
  const {
107
109
  data: { name },
108
110
  } = node
109
111
  const y = node.x!
110
112
  const str = columns[name]?.slice(xStart, xEnd)
111
113
  if (str) {
112
- for (let i = 0; i < str.length; i++) {
114
+ for (let i = 0, l2 = str.length; i < l2; i++) {
113
115
  const letter = str[i]!
114
- const color =
115
- colorSchemeName === 'clustalx_protein_dynamic'
116
- ? getClustalXColor(
117
- // use model.colStats dot notation here: delay use of colStats
118
- // until absolutely needed
116
+ const r1 = colorSchemeName === 'clustalx_protein_dynamic'
117
+ const r2 = colorSchemeName === 'percent_identity_dynamic'
118
+ const color = r1
119
+ ? getClustalXColor(
120
+ // use model.colStats dot notation here: delay use of colStats
121
+ // until absolutely needed
122
+ model.colStats[xStart + i]!,
123
+ model.colStatsSums[xStart + i]!,
124
+ model,
125
+ name,
126
+ xStart + i,
127
+ )
128
+ : r2
129
+ ? getPercentIdentityColor(
130
+ // use model.colStats dot notation here: delay use of
131
+ // colStats until absolutely needed
119
132
  model.colStats[xStart + i]!,
120
133
  model.colStatsSums[xStart + i]!,
121
134
  model,
122
135
  name,
123
136
  xStart + i,
124
137
  )
125
- : colorSchemeName === 'percent_identity_dynamic'
126
- ? getPercentIdentityColor(
127
- // use model.colStats dot notation here: delay use of
128
- // colStats until absolutely needed
129
- model.colStats[xStart + i]!,
130
- model.colStatsSums[xStart + i]!,
131
- model,
132
- name,
133
- xStart + i,
134
- )
135
- : colorScheme[letter.toUpperCase()]
136
- if (bgColor) {
138
+ : colorScheme[letter.toUpperCase()]
139
+ if (bgColor || r1 || r2) {
137
140
  ctx.fillStyle = color || theme.palette.background.default
138
141
  ctx.fillRect(
139
142
  i * colWidth + offsetX - (offsetX % colWidth),
@@ -176,14 +179,15 @@ function drawText({
176
179
  rowHeight,
177
180
  } = model
178
181
  if (showMsaLetters) {
179
- for (const node of visibleLeaves) {
182
+ for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
183
+ const node = visibleLeaves[i]!
180
184
  const {
181
185
  data: { name },
182
186
  } = node
183
187
  const y = node.x!
184
188
  const str = columns[name]?.slice(xStart, xEnd)
185
189
  if (str) {
186
- for (let i = 0; i < str.length; i++) {
190
+ for (let i = 0, l2 = str.length; i < l2; i++) {
187
191
  const letter = str[i]!
188
192
  const color = colorScheme[letter.toUpperCase()]
189
193
  const contrast = contrastLettering