react-msaview 9.1.0 → 9.2.0
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.
- package/bundle/index.js +111 -115
- package/bundle/index.js.map +4 -4
- package/dist/blosum62.d.ts +3 -0
- package/dist/blosum62.js +43 -0
- package/dist/blosum62.js.map +1 -0
- package/dist/colorSchemes.js +1 -0
- package/dist/colorSchemes.js.map +1 -1
- package/dist/components/Loading.d.ts +3 -2
- package/dist/components/Loading.js +2 -2
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.d.ts +3 -2
- package/dist/components/MSAView.js +7 -4
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +64 -12
- package/dist/components/MetadataTable.d.ts +4 -1
- package/dist/components/MetadataTable.js +55 -16
- package/dist/components/MetadataTable.js.map +1 -1
- package/dist/components/Track.js +6 -0
- package/dist/components/Track.js.map +1 -1
- package/dist/components/controls.js +2 -1
- package/dist/components/controls.js.map +1 -1
- package/dist/components/dialogs/AnnotationFileDialog.js +7 -2
- package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -1
- package/dist/components/dialogs/FeatureDialog.js +2 -2
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/{header/MSASettingsMenu.d.ts → dialogs/GapThresholdDialog.d.ts} +3 -2
- package/dist/components/dialogs/GapThresholdDialog.js +15 -0
- package/dist/components/dialogs/GapThresholdDialog.js.map +1 -0
- package/dist/components/{header → dialogs}/GappynessSlider.d.ts +1 -1
- package/dist/components/{header → dialogs}/GappynessSlider.js +3 -10
- package/dist/components/dialogs/GappynessSlider.js.map +1 -0
- package/dist/components/{header → dialogs}/GoToBox.d.ts +4 -2
- package/dist/components/dialogs/GoToBox.js +48 -0
- package/dist/components/dialogs/GoToBox.js.map +1 -0
- package/dist/components/dialogs/GoToDialog.d.ts +6 -0
- package/dist/components/dialogs/GoToDialog.js +10 -0
- package/dist/components/dialogs/GoToDialog.js.map +1 -0
- package/dist/components/dialogs/MetadataDialog.js +11 -3
- package/dist/components/dialogs/MetadataDialog.js.map +1 -1
- package/dist/components/dialogs/goTo.d.ts +5 -0
- package/dist/components/{header → dialogs}/goTo.js +1 -1
- package/dist/components/dialogs/goTo.js.map +1 -0
- package/dist/components/dialogs/metadataLabels.d.ts +4 -0
- package/dist/components/dialogs/metadataLabels.js +52 -0
- package/dist/components/dialogs/metadataLabels.js.map +1 -0
- package/dist/components/dialogs/metadataRecord.d.ts +1 -0
- package/dist/components/dialogs/metadataRecord.js +38 -0
- package/dist/components/dialogs/metadataRecord.js.map +1 -0
- package/dist/components/header/Header.d.ts +6 -2
- package/dist/components/header/Header.js +30 -32
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/{TreeSettingsMenu.d.ts → HiddenColumnsChip.d.ts} +2 -2
- package/dist/components/header/HiddenColumnsChip.js +15 -0
- package/dist/components/header/HiddenColumnsChip.js.map +1 -0
- package/dist/components/header/MenuBar.d.ts +6 -0
- package/dist/components/header/MenuBar.js +33 -0
- package/dist/components/header/MenuBar.js.map +1 -0
- package/dist/components/header/ScrollZoomCheckbox.d.ts +7 -0
- package/dist/components/header/ScrollZoomCheckbox.js +19 -0
- package/dist/components/header/ScrollZoomCheckbox.js.map +1 -0
- package/dist/components/header/ZoomControls.js +10 -30
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/header/colorSchemeMenuItems.d.ts +4 -0
- package/dist/components/header/colorSchemeMenuItems.js +106 -0
- package/dist/components/header/colorSchemeMenuItems.js.map +1 -0
- package/dist/components/header/getAnnotationsMenu.d.ts +3 -30
- package/dist/components/header/getAnnotationsMenu.js +48 -54
- package/dist/components/header/getAnnotationsMenu.js.map +1 -1
- package/dist/components/header/menuBarItems.d.ts +11 -0
- package/dist/components/header/menuBarItems.js +277 -0
- package/dist/components/header/menuBarItems.js.map +1 -0
- package/dist/components/import/ImportForm.js +12 -6
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/minimap/Minimap.js +7 -3
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.js +2 -1
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/minimap/minimapLayout.d.ts +12 -0
- package/dist/components/minimap/minimapLayout.js +20 -0
- package/dist/components/minimap/minimapLayout.js.map +1 -1
- package/dist/components/msa/MSACanvas.js +26 -9
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +15 -11
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js +2 -2
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/WheelZoomHint.d.ts +7 -0
- package/dist/components/msa/WheelZoomHint.js +38 -0
- package/dist/components/msa/WheelZoomHint.js.map +1 -0
- package/dist/components/msa/msaKeys.js +3 -0
- package/dist/components/msa/msaKeys.js.map +1 -1
- package/dist/components/msa/msaRaster.d.ts +4 -5
- package/dist/components/msa/msaRaster.js +5 -5
- package/dist/components/msa/msaRaster.js.map +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +22 -2
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderHighlights.d.ts +0 -3
- package/dist/components/msa/renderHighlights.js +3 -3
- package/dist/components/msa/renderHighlights.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +6 -1
- package/dist/components/msa/renderMSABlock.js +44 -17
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/tileColor.js +7 -0
- package/dist/components/msa/tileColor.js.map +1 -1
- package/dist/components/rowpanels/RowPanelBlock.js +2 -2
- package/dist/components/rowpanels/RowPanelBlock.js.map +1 -1
- package/dist/components/settings/MenuItemsForm.d.ts +10 -0
- package/dist/components/settings/MenuItemsForm.js +80 -0
- package/dist/components/settings/MenuItemsForm.js.map +1 -0
- package/dist/components/settings/SettingsPanel.d.ts +12 -0
- package/dist/components/settings/SettingsPanel.js +92 -0
- package/dist/components/settings/SettingsPanel.js.map +1 -0
- package/dist/components/{header/FileMenu.d.ts → settings/TrackList.d.ts} +2 -2
- package/dist/components/settings/TrackList.js +58 -0
- package/dist/components/settings/TrackList.js.map +1 -0
- package/dist/components/tracks/TrackBlocks.js +2 -2
- package/dist/components/tracks/TrackBlocks.js.map +1 -1
- package/dist/components/tracks/TrackTooltipContent.js +2 -1
- package/dist/components/tracks/TrackTooltipContent.js.map +1 -1
- package/dist/components/tracks/drawTracks.js +13 -6
- package/dist/components/tracks/drawTracks.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +2 -2
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeMenu.js +4 -6
- package/dist/components/tree/TreeMenu.js.map +1 -1
- package/dist/components/tree/TreeOverview.js +2 -2
- package/dist/components/tree/TreeOverview.js.map +1 -1
- package/dist/constants.d.ts +4 -1
- package/dist/constants.js +7 -1
- package/dist/constants.js.map +1 -1
- package/dist/darkReader.d.ts +7 -0
- package/dist/darkReader.js +42 -0
- package/dist/darkReader.js.map +1 -0
- package/dist/element.js +22 -47
- package/dist/element.js.map +1 -1
- package/dist/featurePanels.d.ts +37 -0
- package/dist/featurePanels.js +187 -0
- package/dist/featurePanels.js.map +1 -0
- package/dist/filehandleLoader.d.ts +41 -0
- package/dist/filehandleLoader.js +99 -0
- package/dist/filehandleLoader.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model/treeModel.d.ts +9 -0
- package/dist/model/treeModel.js +12 -1
- package/dist/model/treeModel.js.map +1 -1
- package/dist/model.d.ts +148 -32
- package/dist/model.js +291 -569
- package/dist/model.js.map +1 -1
- package/dist/neighborJoining.js +1 -40
- package/dist/neighborJoining.js.map +1 -1
- package/dist/renderToSvg.js +1 -13
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rerootTree.d.ts +1 -0
- package/dist/rerootTree.js +7 -6
- package/dist/rerootTree.js.map +1 -1
- package/dist/schemeResidueColor.d.ts +12 -0
- package/dist/schemeResidueColor.js +33 -0
- package/dist/schemeResidueColor.js.map +1 -0
- package/dist/similarityColors.d.ts +11 -0
- package/dist/similarityColors.js +90 -0
- package/dist/similarityColors.js.map +1 -0
- package/dist/svgTestUtil.d.ts +64 -12
- package/dist/treeDisplay.d.ts +37 -0
- package/dist/treeDisplay.js +209 -0
- package/dist/treeDisplay.js.map +1 -0
- package/dist/types.d.ts +7 -3
- package/dist/useWheelScroll.d.ts +3 -1
- package/dist/useWheelScroll.js +36 -17
- package/dist/useWheelScroll.js.map +1 -1
- package/dist/util.d.ts +2 -0
- package/dist/util.js +2 -0
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wheelZoom.d.ts +8 -3
- package/dist/wheelZoom.js +44 -32
- package/dist/wheelZoom.js.map +1 -1
- package/dist/zoomSnapshot.d.ts +29 -0
- package/dist/zoomSnapshot.js +47 -0
- package/dist/zoomSnapshot.js.map +1 -0
- package/package.json +11 -11
- package/src/blosum62.ts +45 -0
- package/src/colorSchemes.ts +1 -0
- package/src/components/Loading.tsx +6 -2
- package/src/components/MSAView.tsx +22 -5
- package/src/components/MetadataTable.tsx +83 -26
- package/src/components/Track.tsx +13 -0
- package/src/components/controls.ts +2 -1
- package/src/components/dialogs/AnnotationFileDialog.tsx +12 -1
- package/src/components/dialogs/FeatureDialog.tsx +2 -5
- package/src/components/dialogs/GapThresholdDialog.tsx +36 -0
- package/src/components/{header → dialogs}/GappynessSlider.tsx +3 -10
- package/src/components/{header → dialogs}/GoToBox.tsx +36 -10
- package/src/components/dialogs/GoToDialog.tsx +30 -0
- package/src/components/dialogs/MetadataDialog.tsx +32 -4
- package/src/components/{header → dialogs}/goTo.ts +1 -1
- package/src/components/dialogs/metadataLabels.ts +54 -0
- package/src/components/dialogs/metadataRecord.tsx +61 -0
- package/src/components/header/Header.tsx +75 -42
- package/src/components/header/HiddenColumnsChip.tsx +39 -0
- package/src/components/header/MenuBar.tsx +64 -0
- package/src/components/header/ScrollZoomCheckbox.tsx +46 -0
- package/src/components/header/ZoomControls.tsx +20 -35
- package/src/components/header/colorSchemeMenuItems.ts +121 -0
- package/src/components/header/getAnnotationsMenu.ts +52 -56
- package/src/components/header/menuBarItems.ts +357 -0
- package/src/components/import/ImportForm.tsx +19 -7
- package/src/components/minimap/Minimap.tsx +11 -3
- package/src/components/minimap/MinimapSVG.tsx +17 -1
- package/src/components/minimap/minimapLayout.ts +27 -0
- package/src/components/msa/MSACanvas.tsx +22 -3
- package/src/components/msa/MSACanvasBlock.tsx +18 -11
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -2
- package/src/components/msa/WheelZoomHint.tsx +56 -0
- package/src/components/msa/msaKeys.ts +3 -0
- package/src/components/msa/msaRaster.ts +6 -8
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +28 -5
- package/src/components/msa/renderHighlights.ts +3 -3
- package/src/components/msa/renderMSABlock.ts +51 -15
- package/src/components/msa/tileColor.ts +7 -0
- package/src/components/rowpanels/RowPanelBlock.tsx +2 -2
- package/src/components/settings/MenuItemsForm.tsx +225 -0
- package/src/components/settings/SettingsPanel.tsx +156 -0
- package/src/components/settings/TrackList.tsx +124 -0
- package/src/components/tracks/TrackBlocks.tsx +2 -2
- package/src/components/tracks/TrackTooltipContent.tsx +2 -1
- package/src/components/tracks/drawTracks.ts +15 -7
- package/src/components/tree/TreeCanvasBlock.tsx +2 -2
- package/src/components/tree/TreeMenu.tsx +4 -6
- package/src/components/tree/TreeOverview.tsx +2 -2
- package/src/constants.ts +9 -1
- package/src/darkReader.ts +57 -0
- package/src/element.ts +34 -57
- package/src/featurePanels.ts +269 -0
- package/src/filehandleLoader.ts +136 -0
- package/src/index.ts +4 -0
- package/src/model/treeModel.ts +13 -0
- package/src/model.ts +370 -748
- package/src/neighborJoining.ts +1 -42
- package/src/renderToSvg.tsx +1 -13
- package/src/rerootTree.ts +7 -6
- package/src/schemeResidueColor.ts +37 -0
- package/src/similarityColors.ts +112 -0
- package/src/treeDisplay.ts +278 -0
- package/src/types.ts +7 -4
- package/src/useWheelScroll.ts +43 -22
- package/src/util.ts +3 -0
- package/src/version.ts +1 -1
- package/src/wheelZoom.ts +55 -33
- package/src/zoomSnapshot.ts +80 -0
- package/dist/components/header/ColorSchemeMenu.d.ts +0 -12
- package/dist/components/header/ColorSchemeMenu.js +0 -37
- package/dist/components/header/ColorSchemeMenu.js.map +0 -1
- package/dist/components/header/FileMenu.js +0 -92
- package/dist/components/header/FileMenu.js.map +0 -1
- package/dist/components/header/GappynessSlider.js.map +0 -1
- package/dist/components/header/GoToBox.js +0 -31
- package/dist/components/header/GoToBox.js.map +0 -1
- package/dist/components/header/MSASettingsMenu.js +0 -11
- package/dist/components/header/MSASettingsMenu.js.map +0 -1
- package/dist/components/header/ScrollZoomIcons.d.ts +0 -6
- package/dist/components/header/ScrollZoomIcons.js +0 -35
- package/dist/components/header/ScrollZoomIcons.js.map +0 -1
- package/dist/components/header/TreeSettingsMenu.js +0 -11
- package/dist/components/header/TreeSettingsMenu.js.map +0 -1
- package/dist/components/header/goTo.d.ts +0 -20
- package/dist/components/header/goTo.js.map +0 -1
- package/dist/components/header/settingsMenuItems.d.ts +0 -5
- package/dist/components/header/settingsMenuItems.js +0 -171
- package/dist/components/header/settingsMenuItems.js.map +0 -1
- package/src/components/header/ColorSchemeMenu.tsx +0 -56
- package/src/components/header/FileMenu.tsx +0 -107
- package/src/components/header/MSASettingsMenu.tsx +0 -26
- package/src/components/header/ScrollZoomIcons.tsx +0 -52
- package/src/components/header/TreeSettingsMenu.tsx +0 -30
- package/src/components/header/settingsMenuItems.ts +0 -216
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import ArrowDropDown from '@mui/icons-material/ArrowDropDown'
|
|
4
|
+
import ArrowRight from '@mui/icons-material/ArrowRight'
|
|
5
|
+
import Close from '@mui/icons-material/Close'
|
|
6
|
+
import { Box, ButtonBase, IconButton, Typography } from '@mui/material'
|
|
7
|
+
import { observer } from 'mobx-react'
|
|
8
|
+
|
|
9
|
+
import { settingsPanelWidth } from '../../constants.ts'
|
|
10
|
+
import { annotationsSubMenu } from '../header/getAnnotationsMenu.ts'
|
|
11
|
+
import {
|
|
12
|
+
alignmentSettingsItems,
|
|
13
|
+
colorSettingsItems,
|
|
14
|
+
gapsSubMenu,
|
|
15
|
+
trackSettingsItems,
|
|
16
|
+
treeSubMenu,
|
|
17
|
+
} from '../header/menuBarItems.ts'
|
|
18
|
+
import MenuItemsForm from './MenuItemsForm.tsx'
|
|
19
|
+
import TrackList from './TrackList.tsx'
|
|
20
|
+
|
|
21
|
+
import type { MsaViewModel } from '../../model.ts'
|
|
22
|
+
|
|
23
|
+
const collapsedKey = 'msaview-settings-collapsed'
|
|
24
|
+
|
|
25
|
+
function readCollapsed() {
|
|
26
|
+
try {
|
|
27
|
+
const parsed: unknown = JSON.parse(
|
|
28
|
+
localStorage.getItem(collapsedKey) ?? '[]',
|
|
29
|
+
)
|
|
30
|
+
return new Set(Array.isArray(parsed) ? parsed.map(String) : [])
|
|
31
|
+
} catch {
|
|
32
|
+
return new Set<string>()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function writeCollapsed(collapsed: Set<string>) {
|
|
37
|
+
try {
|
|
38
|
+
localStorage.setItem(collapsedKey, JSON.stringify([...collapsed]))
|
|
39
|
+
} catch {}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function Section({
|
|
43
|
+
title,
|
|
44
|
+
collapsed,
|
|
45
|
+
onToggle,
|
|
46
|
+
children,
|
|
47
|
+
}: {
|
|
48
|
+
title: string
|
|
49
|
+
collapsed: boolean
|
|
50
|
+
onToggle: () => void
|
|
51
|
+
children: React.ReactNode
|
|
52
|
+
}) {
|
|
53
|
+
const Arrow = collapsed ? ArrowRight : ArrowDropDown
|
|
54
|
+
return (
|
|
55
|
+
<Box sx={{ px: 1.5, py: 1, borderBottom: 1, borderColor: 'divider' }}>
|
|
56
|
+
<ButtonBase
|
|
57
|
+
aria-expanded={!collapsed}
|
|
58
|
+
onClick={onToggle}
|
|
59
|
+
sx={{ width: '100%', justifyContent: 'flex-start', ml: -0.75 }}
|
|
60
|
+
>
|
|
61
|
+
<Arrow fontSize="small" color="action" />
|
|
62
|
+
<Typography variant="overline" color="text.secondary">
|
|
63
|
+
{title}
|
|
64
|
+
</Typography>
|
|
65
|
+
</ButtonBase>
|
|
66
|
+
{collapsed ? null : children}
|
|
67
|
+
</Box>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The settings whose effect the user watches as they change them, docked to
|
|
73
|
+
* the right of the alignment so nothing it opens covers the tree or the rows.
|
|
74
|
+
* Each section folds, and the browser remembers which ones the user folded.
|
|
75
|
+
*/
|
|
76
|
+
const SettingsPanel = observer(function ({
|
|
77
|
+
model,
|
|
78
|
+
height,
|
|
79
|
+
}: {
|
|
80
|
+
model: MsaViewModel
|
|
81
|
+
height: number
|
|
82
|
+
}) {
|
|
83
|
+
const { noTree, noDomains } = model
|
|
84
|
+
const [collapsed, setCollapsed] = useState(readCollapsed)
|
|
85
|
+
const section = (title: string) => ({
|
|
86
|
+
title,
|
|
87
|
+
collapsed: collapsed.has(title),
|
|
88
|
+
onToggle: () => {
|
|
89
|
+
const next = new Set(collapsed)
|
|
90
|
+
if (!next.delete(title)) {
|
|
91
|
+
next.add(title)
|
|
92
|
+
}
|
|
93
|
+
writeCollapsed(next)
|
|
94
|
+
setCollapsed(next)
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
return (
|
|
98
|
+
<Box
|
|
99
|
+
data-testid="settings_panel"
|
|
100
|
+
sx={{
|
|
101
|
+
width: settingsPanelWidth,
|
|
102
|
+
height,
|
|
103
|
+
flexShrink: 0,
|
|
104
|
+
overflowY: 'auto',
|
|
105
|
+
borderLeft: 1,
|
|
106
|
+
borderColor: 'divider',
|
|
107
|
+
bgcolor: 'background.paper',
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
<Box
|
|
111
|
+
sx={{
|
|
112
|
+
display: 'flex',
|
|
113
|
+
alignItems: 'center',
|
|
114
|
+
justifyContent: 'space-between',
|
|
115
|
+
px: 1.5,
|
|
116
|
+
pt: 0.5,
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
<Typography variant="subtitle1">Settings</Typography>
|
|
120
|
+
<IconButton
|
|
121
|
+
aria-label="Close settings"
|
|
122
|
+
onClick={() => {
|
|
123
|
+
model.setSettingsOpen(false)
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
<Close fontSize="small" />
|
|
127
|
+
</IconButton>
|
|
128
|
+
</Box>
|
|
129
|
+
<Section {...section('Color')}>
|
|
130
|
+
<MenuItemsForm items={colorSettingsItems(model)} />
|
|
131
|
+
</Section>
|
|
132
|
+
{noTree ? null : (
|
|
133
|
+
<Section {...section('Tree')}>
|
|
134
|
+
<MenuItemsForm items={treeSubMenu(model)} />
|
|
135
|
+
</Section>
|
|
136
|
+
)}
|
|
137
|
+
<Section {...section('Alignment')}>
|
|
138
|
+
<MenuItemsForm items={alignmentSettingsItems(model)} />
|
|
139
|
+
<MenuItemsForm items={gapsSubMenu(model)} />
|
|
140
|
+
</Section>
|
|
141
|
+
{noDomains ? null : (
|
|
142
|
+
<Section {...section('Annotations')}>
|
|
143
|
+
<MenuItemsForm items={annotationsSubMenu(model)} />
|
|
144
|
+
</Section>
|
|
145
|
+
)}
|
|
146
|
+
<Section {...section('Tracks')}>
|
|
147
|
+
<TrackList model={model} />
|
|
148
|
+
<Box sx={{ mt: 1, pt: 0.5, borderTop: 1, borderColor: 'divider' }}>
|
|
149
|
+
<MenuItemsForm items={trackSettingsItems(model)} />
|
|
150
|
+
</Box>
|
|
151
|
+
</Section>
|
|
152
|
+
</Box>
|
|
153
|
+
)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
export default SettingsPanel
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Box,
|
|
5
|
+
Button,
|
|
6
|
+
Checkbox,
|
|
7
|
+
FormControlLabel,
|
|
8
|
+
TextField,
|
|
9
|
+
Typography,
|
|
10
|
+
} from '@mui/material'
|
|
11
|
+
import { observer } from 'mobx-react'
|
|
12
|
+
|
|
13
|
+
import type { MsaViewModel } from '../../model.ts'
|
|
14
|
+
|
|
15
|
+
interface Entry {
|
|
16
|
+
id: string
|
|
17
|
+
label: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function trackGroups(model: MsaViewModel) {
|
|
21
|
+
const computed = new Set(model.computedTrackModels.map(t => t.model.id))
|
|
22
|
+
const computedEntries: Entry[] = []
|
|
23
|
+
const alignmentEntries: Entry[] = []
|
|
24
|
+
const referenceEntries: Entry[] = []
|
|
25
|
+
for (const { model: t } of model.tracks) {
|
|
26
|
+
const entries =
|
|
27
|
+
t.kind === 'reference'
|
|
28
|
+
? referenceEntries
|
|
29
|
+
: computed.has(t.id)
|
|
30
|
+
? computedEntries
|
|
31
|
+
: alignmentEntries
|
|
32
|
+
entries.push({ id: t.id, label: t.name })
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
{ title: 'Computed from the alignment', entries: computedEntries },
|
|
36
|
+
{ title: 'Alignment annotations', entries: alignmentEntries },
|
|
37
|
+
{ title: 'Reference row', entries: referenceEntries },
|
|
38
|
+
].filter(g => g.entries.length > 0)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// a filter box shows once the list is long enough to need one
|
|
42
|
+
const filterFrom = 10
|
|
43
|
+
|
|
44
|
+
const TrackList = observer(function ({ model }: { model: MsaViewModel }) {
|
|
45
|
+
const [filter, setFilter] = useState('')
|
|
46
|
+
const shown = new Set(model.turnedOnTracks.map(t => t.model.id))
|
|
47
|
+
const all = trackGroups(model)
|
|
48
|
+
const needle = filter.trim().toLowerCase()
|
|
49
|
+
const groups = all
|
|
50
|
+
.map(g => ({
|
|
51
|
+
...g,
|
|
52
|
+
entries: g.entries.filter(e => e.label.toLowerCase().includes(needle)),
|
|
53
|
+
}))
|
|
54
|
+
.filter(g => g.entries.length > 0)
|
|
55
|
+
const matching = groups.flatMap(g => g.entries.map(e => e.id))
|
|
56
|
+
const long = all.reduce((n, g) => n + g.entries.length, 0) >= filterFrom
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
{long ? (
|
|
60
|
+
<>
|
|
61
|
+
<TextField
|
|
62
|
+
size="small"
|
|
63
|
+
placeholder="Filter tracks"
|
|
64
|
+
value={filter}
|
|
65
|
+
onChange={event => {
|
|
66
|
+
setFilter(event.target.value)
|
|
67
|
+
}}
|
|
68
|
+
fullWidth
|
|
69
|
+
/>
|
|
70
|
+
<Box sx={{ display: 'flex' }}>
|
|
71
|
+
<Button
|
|
72
|
+
size="small"
|
|
73
|
+
onClick={() => {
|
|
74
|
+
model.setTracksShown(matching, true)
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
Show all
|
|
78
|
+
</Button>
|
|
79
|
+
<Button
|
|
80
|
+
size="small"
|
|
81
|
+
onClick={() => {
|
|
82
|
+
model.setTracksShown(matching, false)
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
Hide all
|
|
86
|
+
</Button>
|
|
87
|
+
</Box>
|
|
88
|
+
</>
|
|
89
|
+
) : null}
|
|
90
|
+
{groups.map(({ title, entries }) => (
|
|
91
|
+
<Box key={title}>
|
|
92
|
+
{groups.length > 1 ? (
|
|
93
|
+
<Typography variant="caption" color="text.secondary">
|
|
94
|
+
{title}
|
|
95
|
+
</Typography>
|
|
96
|
+
) : null}
|
|
97
|
+
{entries.map(({ id, label }) => (
|
|
98
|
+
<FormControlLabel
|
|
99
|
+
key={id}
|
|
100
|
+
sx={{ display: 'flex' }}
|
|
101
|
+
control={
|
|
102
|
+
<Checkbox
|
|
103
|
+
size="small"
|
|
104
|
+
checked={shown.has(id)}
|
|
105
|
+
onChange={() => {
|
|
106
|
+
model.toggleTrack(id)
|
|
107
|
+
}}
|
|
108
|
+
sx={{ py: 0.25 }}
|
|
109
|
+
/>
|
|
110
|
+
}
|
|
111
|
+
label={label}
|
|
112
|
+
slotProps={{ typography: { variant: 'body2' } }}
|
|
113
|
+
/>
|
|
114
|
+
))}
|
|
115
|
+
</Box>
|
|
116
|
+
))}
|
|
117
|
+
{groups.length === 0 ? (
|
|
118
|
+
<Typography variant="body2">No track matches</Typography>
|
|
119
|
+
) : null}
|
|
120
|
+
</>
|
|
121
|
+
)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
export default TrackList
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
|
|
3
|
-
import { useTheme } from '@mui/material'
|
|
4
3
|
import { observer } from 'mobx-react'
|
|
5
4
|
|
|
5
|
+
import { useCanvasTheme } from '../../darkReader.ts'
|
|
6
6
|
import { useCanvasAutorun } from '../../useCanvasAutorun.ts'
|
|
7
7
|
import { TrackResizeHandle } from '../ResizeHandles.tsx'
|
|
8
8
|
import { drawTrackBlock } from './drawTracks.ts'
|
|
@@ -21,7 +21,7 @@ const TrackBlock = observer(function ({
|
|
|
21
21
|
}) {
|
|
22
22
|
const { blockSize, highResScaleFactor } = model
|
|
23
23
|
const { height } = track.model
|
|
24
|
-
const theme =
|
|
24
|
+
const theme = useCanvasTheme()
|
|
25
25
|
const canvasWidth = blockSize * highResScaleFactor
|
|
26
26
|
const canvasHeight = height * highResScaleFactor
|
|
27
27
|
|
|
@@ -137,7 +137,8 @@ const TrackTooltipContent = observer(function ({
|
|
|
137
137
|
case 'logo': {
|
|
138
138
|
return <LogoTooltip model={model} col={col} />
|
|
139
139
|
}
|
|
140
|
-
case 'text':
|
|
140
|
+
case 'text':
|
|
141
|
+
case 'reference': {
|
|
141
142
|
return <TextTooltip model={model} track={track} col={col} />
|
|
142
143
|
}
|
|
143
144
|
case 'arc': {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { columnLogoStack } from '../../sequenceLogo.ts'
|
|
2
2
|
import { setFontSize } from '../../setFontSize.ts'
|
|
3
3
|
import { contrastTextFn } from '../../util.ts'
|
|
4
|
+
import { tileColorFn } from '../msa/tileColor.ts'
|
|
4
5
|
import { visibleColRange } from '../msa/visibleColRange.ts'
|
|
5
6
|
|
|
6
7
|
import type { ColumnCounts } from '../../columnCounts.ts'
|
|
@@ -106,7 +107,7 @@ function drawArcs({
|
|
|
106
107
|
function drawTextTrackContent({
|
|
107
108
|
ctx,
|
|
108
109
|
data,
|
|
109
|
-
|
|
110
|
+
colorAt,
|
|
110
111
|
contrastText,
|
|
111
112
|
bgColor,
|
|
112
113
|
drawLetters,
|
|
@@ -117,7 +118,7 @@ function drawTextTrackContent({
|
|
|
117
118
|
}: {
|
|
118
119
|
ctx: RenderCtx
|
|
119
120
|
data: string | undefined
|
|
120
|
-
|
|
121
|
+
colorAt: (col: number, letter: string) => string | undefined
|
|
121
122
|
contrastText: (color: string | undefined) => string
|
|
122
123
|
bgColor: boolean
|
|
123
124
|
drawLetters: boolean
|
|
@@ -135,9 +136,9 @@ function drawTextTrackContent({
|
|
|
135
136
|
|
|
136
137
|
for (let i = 0; str && i < str.length; i++) {
|
|
137
138
|
const letter = str[i]!
|
|
138
|
-
const
|
|
139
|
-
const fill = bgColor ?
|
|
140
|
-
const x =
|
|
139
|
+
const col = xStart + i
|
|
140
|
+
const fill = bgColor ? colorAt(col, letter) : undefined
|
|
141
|
+
const x = col * colWidth
|
|
141
142
|
if (fill) {
|
|
142
143
|
ctx.fillStyle = fill
|
|
143
144
|
ctx.fillRect(x, 0, colWidth, rowHeight)
|
|
@@ -402,15 +403,22 @@ export function drawTrackBlock({
|
|
|
402
403
|
})
|
|
403
404
|
break
|
|
404
405
|
}
|
|
405
|
-
case 'text':
|
|
406
|
+
case 'text':
|
|
407
|
+
case 'reference': {
|
|
406
408
|
const { bgColor, fontSize, rowHeight, showMsaLetters } = model
|
|
409
|
+
const scheme = customColorScheme ?? model.colorScheme
|
|
407
410
|
ctx.textAlign = 'center'
|
|
408
411
|
ctx.textBaseline = 'middle'
|
|
409
412
|
setFontSize(ctx, fontSize)
|
|
410
413
|
drawTextTrackContent({
|
|
411
414
|
ctx,
|
|
412
415
|
data,
|
|
413
|
-
|
|
416
|
+
// the reference row takes its colors from the alignment's own
|
|
417
|
+
// scheme, per column under a dynamic one
|
|
418
|
+
colorAt:
|
|
419
|
+
kind === 'reference'
|
|
420
|
+
? tileColorFn(model)
|
|
421
|
+
: (_col, letter) => scheme[letter.toUpperCase()],
|
|
414
422
|
contrastText: contrastTextFn(theme),
|
|
415
423
|
bgColor,
|
|
416
424
|
drawLetters: showMsaLetters,
|
|
@@ -2,9 +2,9 @@ import React, { useState } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import BaseTooltip from '@jbrowse/core/ui/BaseTooltip'
|
|
4
4
|
import { makeStyles } from '@jbrowse/core/util/tss-react'
|
|
5
|
-
import { useTheme } from '@mui/material'
|
|
6
5
|
import { observer } from 'mobx-react'
|
|
7
6
|
|
|
7
|
+
import { useCanvasTheme } from '../../darkReader.ts'
|
|
8
8
|
import { useCanvasAutorun } from '../../useCanvasAutorun.ts'
|
|
9
9
|
import TreeMenu from './TreeMenu.tsx'
|
|
10
10
|
import { renderTreeCanvas } from './renderTreeCanvas.ts'
|
|
@@ -30,7 +30,7 @@ const TreeCanvasBlock = observer(function ({
|
|
|
30
30
|
offsetY: number
|
|
31
31
|
}) {
|
|
32
32
|
const { classes } = useStyles()
|
|
33
|
-
const theme =
|
|
33
|
+
const theme = useCanvasTheme()
|
|
34
34
|
const [menu, setMenu] = useState<TreeMenuTarget>()
|
|
35
35
|
const { clickMap, anchor, hitTest, onMouseMove, onMouseLeave } = useTreeHover(
|
|
36
36
|
{ model, offsetY },
|
|
@@ -30,7 +30,7 @@ const TreeMenu = observer(function ({
|
|
|
30
30
|
const { name, id, leaf } = node
|
|
31
31
|
const isCollapsed = collapsed.includes(id)
|
|
32
32
|
const isRoot = id === model.tree.id
|
|
33
|
-
const noun = leaf ? 'subtree' : '
|
|
33
|
+
const noun = leaf ? 'subtree' : 'clade'
|
|
34
34
|
return (
|
|
35
35
|
<Menu
|
|
36
36
|
anchorReference="anchorPosition"
|
|
@@ -73,9 +73,7 @@ const TreeMenu = observer(function ({
|
|
|
73
73
|
onClose()
|
|
74
74
|
}}
|
|
75
75
|
>
|
|
76
|
-
{showOnly === id
|
|
77
|
-
? 'Disable show only this node'
|
|
78
|
-
: 'Show only this node'}
|
|
76
|
+
{showOnly === id ? 'Show all rows' : 'Show only this clade'}
|
|
79
77
|
</MenuItem>
|
|
80
78
|
)}
|
|
81
79
|
{leaf || isCollapsed ? null : (
|
|
@@ -86,7 +84,7 @@ const TreeMenu = observer(function ({
|
|
|
86
84
|
onClose()
|
|
87
85
|
}}
|
|
88
86
|
>
|
|
89
|
-
Rotate
|
|
87
|
+
Rotate clade
|
|
90
88
|
</MenuItem>
|
|
91
89
|
)}
|
|
92
90
|
{isRoot ? null : (
|
|
@@ -108,7 +106,7 @@ const TreeMenu = observer(function ({
|
|
|
108
106
|
onClose()
|
|
109
107
|
}}
|
|
110
108
|
>
|
|
111
|
-
|
|
109
|
+
Use as reference row
|
|
112
110
|
</MenuItem>
|
|
113
111
|
) : null}
|
|
114
112
|
{leaf && relativeTo ? (
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
|
|
3
|
-
import { useTheme } from '@mui/material'
|
|
4
3
|
import { observer } from 'mobx-react'
|
|
5
4
|
|
|
5
|
+
import { useCanvasTheme } from '../../darkReader.ts'
|
|
6
6
|
import { useCanvasAutorun } from '../../useCanvasAutorun.ts'
|
|
7
7
|
import {
|
|
8
8
|
drawTreeOverview,
|
|
@@ -22,7 +22,7 @@ import type { MsaViewModel } from '../../model.ts'
|
|
|
22
22
|
*/
|
|
23
23
|
const TreeOverview = observer(function ({ model }: { model: MsaViewModel }) {
|
|
24
24
|
const { effectiveTreeAreaWidth, overviewHeight, highResScaleFactor } = model
|
|
25
|
-
const theme =
|
|
25
|
+
const theme = useCanvasTheme()
|
|
26
26
|
const [hover, setHover] = useState<{ id: string; rows: [number, number] }>()
|
|
27
27
|
const width = Math.round(effectiveTreeAreaWidth * highResScaleFactor)
|
|
28
28
|
const height = Math.round(overviewHeight * highResScaleFactor)
|
package/src/constants.ts
CHANGED
|
@@ -50,6 +50,10 @@ export const defaultScrollZoomAxis: ScrollZoomAxis = 'both'
|
|
|
50
50
|
export const minLetterRowHeight = 8
|
|
51
51
|
export const minLetterColWidth = 5
|
|
52
52
|
|
|
53
|
+
// A wheel-zoom frame draws a block's letters only when the block holds at most
|
|
54
|
+
// this many cells; the settle redraw after the gesture draws the rest
|
|
55
|
+
export const zoomFrameMaxLetters = 2000
|
|
56
|
+
|
|
53
57
|
// A feature span draws its label at two pixels under its height, capped at 11,
|
|
54
58
|
// so a span shorter than this holds no readable text: an underline bar, a
|
|
55
59
|
// sub-row band or a features panel over small rows
|
|
@@ -68,9 +72,12 @@ export const labelFitFontSize = fontSizeFor(defaultRowHeight)
|
|
|
68
72
|
// zoom-in buttons (which otherwise grow unbounded). minColWidth/minRowHeight are
|
|
69
73
|
// the smooth-zoom floors.
|
|
70
74
|
export const minColWidth = 0.2
|
|
71
|
-
export const minRowHeight =
|
|
75
|
+
export const minRowHeight = 0.2
|
|
72
76
|
export const maxCellSize = 80
|
|
73
77
|
|
|
78
|
+
// the settings panel's width, which it takes out of the view's
|
|
79
|
+
export const settingsPanelWidth = 280
|
|
80
|
+
|
|
74
81
|
// MSA model defaults
|
|
75
82
|
export const defaultBgColor = true
|
|
76
83
|
export const defaultColorSchemeName = 'maeditor'
|
|
@@ -99,6 +106,7 @@ export const defaultDrawTree = true
|
|
|
99
106
|
export const defaultDrawNodeBubbles = true
|
|
100
107
|
export const defaultDrawNodeLabels = false
|
|
101
108
|
export const defaultShowTreeOverview = false
|
|
109
|
+
export const defaultShowTreeScaleBar = false
|
|
102
110
|
export const defaultOverviewHeight = 120
|
|
103
111
|
|
|
104
112
|
// Neighbor joining does not run above this many rows. The distance matrix is
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react'
|
|
2
|
+
|
|
3
|
+
import { createJBrowseTheme } from '@jbrowse/core/ui/theme'
|
|
4
|
+
import { useTheme } from '@mui/material'
|
|
5
|
+
|
|
6
|
+
import type { Theme } from '@mui/material'
|
|
7
|
+
|
|
8
|
+
// Dark Reader's Dynamic mode rewrites the page's CSS and leaves canvas pixels
|
|
9
|
+
// alone, so a light theme's black letters land on the dark page it paints.
|
|
10
|
+
// Inlined from @jbrowse/core/util/systemColorScheme, which an older host core
|
|
11
|
+
// lacks (see CLAUDE.md on externals).
|
|
12
|
+
const DARK_READER_ATTRIBUTE = 'data-darkreader-scheme'
|
|
13
|
+
|
|
14
|
+
function darkReaderIsDark() {
|
|
15
|
+
return (
|
|
16
|
+
typeof document !== 'undefined' &&
|
|
17
|
+
document.documentElement.getAttribute(DARK_READER_ATTRIBUTE) === 'dark'
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function onDarkReaderChange(listener: () => void) {
|
|
22
|
+
if (
|
|
23
|
+
typeof MutationObserver !== 'function' ||
|
|
24
|
+
typeof document === 'undefined'
|
|
25
|
+
) {
|
|
26
|
+
return () => {}
|
|
27
|
+
}
|
|
28
|
+
const observer = new MutationObserver(listener)
|
|
29
|
+
observer.observe(document.documentElement, {
|
|
30
|
+
attributes: true,
|
|
31
|
+
attributeFilter: [DARK_READER_ATTRIBUTE],
|
|
32
|
+
})
|
|
33
|
+
return () => {
|
|
34
|
+
observer.disconnect()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let darkTheme: Theme | undefined
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The theme a canvas draws in: the surrounding MUI theme, or a dark one while
|
|
42
|
+
* Dark Reader darkens a light page. The DOM keeps the surrounding theme, which
|
|
43
|
+
* Dark Reader restyles itself, and the SVG export keeps it too.
|
|
44
|
+
*/
|
|
45
|
+
export function useCanvasTheme() {
|
|
46
|
+
const theme = useTheme()
|
|
47
|
+
const darkReader = useSyncExternalStore(
|
|
48
|
+
onDarkReaderChange,
|
|
49
|
+
darkReaderIsDark,
|
|
50
|
+
() => false,
|
|
51
|
+
)
|
|
52
|
+
if (darkReader && theme.palette.mode !== 'dark') {
|
|
53
|
+
darkTheme ??= createJBrowseTheme({ palette: { mode: 'dark' } })
|
|
54
|
+
return darkTheme
|
|
55
|
+
}
|
|
56
|
+
return theme
|
|
57
|
+
}
|
package/src/element.ts
CHANGED
|
@@ -5,16 +5,7 @@ import { mount } from './mount.tsx'
|
|
|
5
5
|
import type { MSAViewerProps } from './components/MSAViewer.tsx'
|
|
6
6
|
import type { MsaViewModel } from './model.ts'
|
|
7
7
|
import type { MountedViewer } from './mount.tsx'
|
|
8
|
-
import type {
|
|
9
|
-
Cell,
|
|
10
|
-
ColorScheme,
|
|
11
|
-
ColumnTrackSpec,
|
|
12
|
-
Feature,
|
|
13
|
-
Highlight,
|
|
14
|
-
MsaSelection,
|
|
15
|
-
ResidueMapping,
|
|
16
|
-
Viewport,
|
|
17
|
-
} from './types.ts'
|
|
8
|
+
import type { Cell, Highlight, MsaSelection, Viewport } from './types.ts'
|
|
18
9
|
|
|
19
10
|
type ElementData = Pick<
|
|
20
11
|
MSAViewerProps,
|
|
@@ -29,6 +20,17 @@ type ElementData = Pick<
|
|
|
29
20
|
| 'selection'
|
|
30
21
|
>
|
|
31
22
|
|
|
23
|
+
const dataProperties = [
|
|
24
|
+
'msa',
|
|
25
|
+
'tree',
|
|
26
|
+
'gff',
|
|
27
|
+
'features',
|
|
28
|
+
'colorScheme',
|
|
29
|
+
'highlights',
|
|
30
|
+
'columnTracks',
|
|
31
|
+
'residueMappings',
|
|
32
|
+
] as const satisfies (keyof ElementData)[]
|
|
33
|
+
|
|
32
34
|
interface NightingaleManager extends HTMLElement {
|
|
33
35
|
register: (element: HTMLElement) => void
|
|
34
36
|
unregister: (element: HTMLElement) => void
|
|
@@ -115,54 +117,29 @@ export function defineMsaElement(tagName = 'jbrowse-msa') {
|
|
|
115
117
|
#reported?: { start: number; end: number }
|
|
116
118
|
#data: ElementData = {}
|
|
117
119
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
set features(value: Feature[] | undefined) {
|
|
140
|
-
this.#setData({ features: value })
|
|
141
|
-
}
|
|
142
|
-
get colorScheme() {
|
|
143
|
-
return this.#data.colorScheme
|
|
144
|
-
}
|
|
145
|
-
set colorScheme(value: ColorScheme | undefined) {
|
|
146
|
-
this.#setData({ colorScheme: value })
|
|
147
|
-
}
|
|
148
|
-
get highlights() {
|
|
149
|
-
return this.#data.highlights
|
|
150
|
-
}
|
|
151
|
-
set highlights(value: Highlight[] | undefined) {
|
|
152
|
-
this.#setData({ highlights: value })
|
|
153
|
-
}
|
|
154
|
-
get columnTracks() {
|
|
155
|
-
return this.#data.columnTracks
|
|
156
|
-
}
|
|
157
|
-
set columnTracks(value: ColumnTrackSpec[] | undefined) {
|
|
158
|
-
this.#setData({ columnTracks: value })
|
|
159
|
-
}
|
|
160
|
-
get residueMappings() {
|
|
161
|
-
return this.#data.residueMappings
|
|
162
|
-
}
|
|
163
|
-
set residueMappings(value: ResidueMapping[] | undefined) {
|
|
164
|
-
this.#setData({ residueMappings: value })
|
|
120
|
+
declare msa: ElementData['msa']
|
|
121
|
+
declare tree: ElementData['tree']
|
|
122
|
+
declare gff: ElementData['gff']
|
|
123
|
+
declare features: ElementData['features']
|
|
124
|
+
declare colorScheme: ElementData['colorScheme']
|
|
125
|
+
declare highlights: ElementData['highlights']
|
|
126
|
+
declare columnTracks: ElementData['columnTracks']
|
|
127
|
+
declare residueMappings: ElementData['residueMappings']
|
|
128
|
+
|
|
129
|
+
static {
|
|
130
|
+
for (const key of dataProperties) {
|
|
131
|
+
Object.defineProperty(MsaElement.prototype, key, {
|
|
132
|
+
configurable: true,
|
|
133
|
+
get(this: MsaElement) {
|
|
134
|
+
return this.#data[key]
|
|
135
|
+
},
|
|
136
|
+
set(this: MsaElement, value: ElementData[typeof key]) {
|
|
137
|
+
this.#setData({ [key]: value })
|
|
138
|
+
},
|
|
139
|
+
})
|
|
140
|
+
}
|
|
165
141
|
}
|
|
142
|
+
|
|
166
143
|
// the viewer's selection, which the reader's drags change
|
|
167
144
|
get selection() {
|
|
168
145
|
return this.#model ? this.#model.selection : this.#data.selection
|