react-msaview 9.0.0 → 9.1.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.
- package/README.md +19 -10
- 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 +2 -3
- package/dist/colorSchemes.js.map +1 -1
- package/dist/columnCounts.d.ts +0 -1
- package/dist/columnCounts.js +1 -1
- package/dist/columnCounts.js.map +1 -1
- package/dist/components/Loading.d.ts +3 -2
- package/dist/components/Loading.js +7 -7
- 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 +1941 -4
- package/dist/components/MSAViewer.js +144 -201
- package/dist/components/MSAViewer.js.map +1 -1
- 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/ResizeHandles.js +3 -2
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/Track.js +8 -1
- package/dist/components/Track.js.map +1 -1
- package/dist/components/controls.d.ts +11 -0
- package/dist/components/controls.js +49 -0
- package/dist/components/controls.js.map +1 -0
- package/dist/components/dialogs/AnnotationFileDialog.js +12 -18
- package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.js +5 -7
- package/dist/components/dialogs/ExportSVGDialog.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/TreeSettingsMenu.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/HelpDialog.d.ts +6 -0
- package/dist/components/dialogs/HelpDialog.js +30 -0
- package/dist/components/dialogs/HelpDialog.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 -34
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HiddenColumnsChip.d.ts +6 -0
- package/dist/components/header/HiddenColumnsChip.js +15 -0
- package/dist/components/header/HiddenColumnsChip.js.map +1 -0
- package/dist/components/header/{FileMenu.d.ts → MenuBar.d.ts} +3 -3
- 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 +12 -48
- 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/import/data/seq2.d.ts +0 -1
- package/dist/components/import/data/seq2.js +0 -17
- package/dist/components/import/data/seq2.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 +28 -10
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +17 -16
- 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/drawFeatureSpans.d.ts +50 -11
- package/dist/components/msa/drawFeatureSpans.js +99 -56
- package/dist/components/msa/drawFeatureSpans.js.map +1 -1
- package/dist/components/msa/msaKeys.js +3 -0
- package/dist/components/msa/msaKeys.js.map +1 -1
- package/dist/components/msa/msaRaster.d.ts +14 -2
- package/dist/components/msa/msaRaster.js +20 -10
- package/dist/components/msa/msaRaster.js.map +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +9 -0
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +39 -8
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderHighlights.d.ts +2 -5
- package/dist/components/msa/renderHighlights.js +5 -6
- 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/renderMSAMouseover.js +2 -1
- package/dist/components/msa/renderMSAMouseover.js.map +1 -1
- package/dist/components/msa/tileColor.js +7 -0
- package/dist/components/msa/tileColor.js.map +1 -1
- package/dist/components/renderCtx.d.ts +1 -1
- package/dist/components/rowpanels/RowPanelBlock.js +2 -2
- package/dist/components/rowpanels/RowPanelBlock.js.map +1 -1
- package/dist/components/rowpanels/renderFeaturePanel.d.ts +5 -1
- package/dist/components/rowpanels/renderFeaturePanel.js +12 -5
- package/dist/components/rowpanels/renderFeaturePanel.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/ZoomMenu.d.ts → settings/TrackList.d.ts} +2 -2
- package/dist/components/settings/TrackList.js +55 -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/drawTracks.d.ts +1 -53
- package/dist/components/tracks/drawTracks.js +5 -5
- package/dist/components/tracks/drawTracks.js.map +1 -1
- package/dist/components/tree/CladeLabels.d.ts +1 -1
- package/dist/components/tree/CladeLabels.js +22 -34
- package/dist/components/tree/CladeLabels.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/components/tree/cladeBrackets.d.ts +17 -10
- package/dist/components/tree/cladeBrackets.js +33 -3
- package/dist/components/tree/cladeBrackets.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +2 -8
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/tree/renderTreeOverview.js +4 -11
- package/dist/components/tree/renderTreeOverview.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 +25 -53
- package/dist/element.js.map +1 -1
- package/dist/exportLayout.d.ts +39 -0
- package/dist/exportLayout.js +78 -0
- package/dist/exportLayout.js.map +1 -0
- 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/headlessRenderEnv.d.ts +12 -39
- package/dist/headlessRenderEnv.js +18 -12
- package/dist/headlessRenderEnv.js.map +1 -1
- package/dist/hierarchy.d.ts +5 -8
- package/dist/hierarchy.js +5 -79
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/measureTextCanvas.d.ts +7 -0
- package/dist/measureTextCanvas.js +8 -6
- package/dist/measureTextCanvas.js.map +1 -1
- package/dist/model/treeModel.d.ts +6 -2
- package/dist/model/treeModel.js +8 -4
- package/dist/model/treeModel.js.map +1 -1
- package/dist/model.d.ts +180 -76
- package/dist/model.js +358 -618
- package/dist/model.js.map +1 -1
- package/dist/neighborJoining.js +1 -40
- package/dist/neighborJoining.js.map +1 -1
- package/dist/renderToSvg.d.ts +2 -7
- package/dist/renderToSvg.js +33 -133
- 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 +74 -32
- 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 +6 -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/viewerSnapshot.d.ts +169 -0
- package/dist/viewerSnapshot.js +100 -0
- package/dist/viewerSnapshot.js.map +1 -0
- 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 +2 -4
- package/src/columnCounts.ts +1 -1
- package/src/components/Loading.tsx +25 -14
- package/src/components/MSAView.tsx +22 -5
- package/src/components/MSAViewer.tsx +275 -251
- package/src/components/MetadataTable.tsx +83 -26
- package/src/components/ResizeHandles.tsx +9 -2
- package/src/components/Track.tsx +15 -1
- package/src/components/controls.ts +62 -0
- package/src/components/dialogs/AnnotationFileDialog.tsx +16 -21
- package/src/components/dialogs/ExportSVGDialog.tsx +8 -19
- 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/HelpDialog.tsx +79 -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 -44
- 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 +23 -74
- 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/import/data/seq2.ts +0 -18
- 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 +24 -4
- package/src/components/msa/MSACanvasBlock.tsx +20 -17
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -2
- package/src/components/msa/WheelZoomHint.tsx +56 -0
- package/src/components/msa/drawFeatureSpans.ts +160 -79
- package/src/components/msa/msaKeys.ts +3 -0
- package/src/components/msa/msaRaster.ts +26 -10
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +62 -24
- package/src/components/msa/renderHighlights.ts +5 -6
- package/src/components/msa/renderMSABlock.ts +51 -15
- package/src/components/msa/renderMSAMouseover.ts +5 -1
- package/src/components/msa/tileColor.ts +7 -0
- package/src/components/renderCtx.ts +0 -1
- package/src/components/rowpanels/RowPanelBlock.tsx +2 -2
- package/src/components/rowpanels/renderFeaturePanel.ts +26 -7
- package/src/components/settings/MenuItemsForm.tsx +225 -0
- package/src/components/settings/SettingsPanel.tsx +156 -0
- package/src/components/settings/TrackList.tsx +119 -0
- package/src/components/tracks/TrackBlocks.tsx +2 -2
- package/src/components/tracks/drawTracks.ts +5 -5
- package/src/components/tree/CladeLabels.tsx +30 -54
- 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/components/tree/cladeBrackets.ts +50 -3
- package/src/components/tree/renderTreeCanvas.ts +2 -13
- package/src/components/tree/renderTreeOverview.ts +7 -14
- package/src/constants.ts +9 -1
- package/src/darkReader.ts +57 -0
- package/src/element.ts +37 -64
- package/src/exportLayout.ts +134 -0
- package/src/featurePanels.ts +269 -0
- package/src/filehandleLoader.ts +136 -0
- package/src/headlessRenderEnv.ts +24 -11
- package/src/hierarchy.ts +5 -88
- package/src/index.ts +9 -5
- package/src/measureTextCanvas.ts +8 -6
- package/src/model/treeModel.ts +9 -3
- package/src/model.ts +452 -807
- package/src/neighborJoining.ts +1 -42
- package/src/renderToSvg.tsx +56 -207
- 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 +6 -4
- package/src/useWheelScroll.ts +43 -22
- package/src/util.ts +3 -0
- package/src/version.ts +1 -1
- package/src/viewerSnapshot.ts +147 -0
- 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 -66
- 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.d.ts +0 -6
- 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 -42
- package/dist/components/header/TreeSettingsMenu.js.map +0 -1
- package/dist/components/header/ZoomMenu.js +0 -37
- package/dist/components/header/ZoomMenu.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 -4
- package/dist/components/header/settingsMenuItems.js +0 -127
- package/dist/components/header/settingsMenuItems.js.map +0 -1
- package/src/components/header/ColorSchemeMenu.tsx +0 -56
- package/src/components/header/FileMenu.tsx +0 -81
- package/src/components/header/MSASettingsMenu.tsx +0 -26
- package/src/components/header/ScrollZoomIcons.tsx +0 -52
- package/src/components/header/TreeSettingsMenu.tsx +0 -60
- package/src/components/header/ZoomMenu.tsx +0 -48
- package/src/components/header/settingsMenuItems.ts +0 -157
|
@@ -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)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { labelFitFontSize } from '../../constants.ts'
|
|
2
2
|
import { measureTextCanvas } from '../../measureTextCanvas.ts'
|
|
3
3
|
|
|
4
|
+
import type { MsaViewModel } from '../../model.ts'
|
|
4
5
|
import type { Clade, ResolvedClade } from '../../types.ts'
|
|
5
6
|
|
|
6
7
|
// The bar of the bracket mark and the space around it, in px.
|
|
@@ -19,7 +20,7 @@ export function cladeInGutter(clade: Pick<Clade, 'mark' | 'label'>) {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
/** the pixel height of the rows a clade covers */
|
|
22
|
-
|
|
23
|
+
function cladeHeight(clade: ResolvedClade, rowHeight: number) {
|
|
23
24
|
return (clade.rows[1] - clade.rows[0] + 1) * rowHeight
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -27,7 +28,7 @@ export function cladeHeight(clade: ResolvedClade, rowHeight: number) {
|
|
|
27
28
|
* Whether a label reads across the rows. It does where they are taller than the
|
|
28
29
|
* font, and runs up the bar where they are not.
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
+
function cladeLabelHorizontal(
|
|
31
32
|
clade: ResolvedClade,
|
|
32
33
|
rowHeight: number,
|
|
33
34
|
fontSize: number,
|
|
@@ -36,7 +37,7 @@ export function cladeLabelHorizontal(
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/** the px between the left edge of the gutter and the label's own column */
|
|
39
|
-
|
|
40
|
+
function cladeLabelOffset(clade: Pick<Clade, 'mark'>) {
|
|
40
41
|
return clade.mark === 'bracket'
|
|
41
42
|
? bracketGap + bracketBarWidth + bracketGap
|
|
42
43
|
: bracketGap
|
|
@@ -64,3 +65,49 @@ export function cladeGutterWidth(clades: Pick<Clade, 'mark' | 'label'>[]) {
|
|
|
64
65
|
// the measurement here sized the gutter for
|
|
65
66
|
return Math.min(maxCladeGutterWidth, Math.ceil(widest))
|
|
66
67
|
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The box each gutter label takes, in unscrolled tree-area px: from the
|
|
71
|
+
* label's column to the right edge of the gutter, across the clade's rows. The
|
|
72
|
+
* live view sets DOM text in it, and the SVG export a `<text>`.
|
|
73
|
+
*/
|
|
74
|
+
export function cladeLabelBoxes(
|
|
75
|
+
model: Pick<
|
|
76
|
+
MsaViewModel,
|
|
77
|
+
| 'resolvedClades'
|
|
78
|
+
| 'cladeGutterWidth'
|
|
79
|
+
| 'rowHeight'
|
|
80
|
+
| 'effectiveTreeAreaWidth'
|
|
81
|
+
| 'fontSize'
|
|
82
|
+
>,
|
|
83
|
+
) {
|
|
84
|
+
const {
|
|
85
|
+
resolvedClades,
|
|
86
|
+
cladeGutterWidth,
|
|
87
|
+
rowHeight,
|
|
88
|
+
effectiveTreeAreaWidth,
|
|
89
|
+
fontSize,
|
|
90
|
+
} = model
|
|
91
|
+
const gutterLeft = effectiveTreeAreaWidth - cladeGutterWidth
|
|
92
|
+
return cladeGutterWidth === 0
|
|
93
|
+
? []
|
|
94
|
+
: resolvedClades.flatMap((clade, index) => {
|
|
95
|
+
const { label, markColor, rows } = clade
|
|
96
|
+
if (!label || !cladeInGutter(clade)) {
|
|
97
|
+
return []
|
|
98
|
+
}
|
|
99
|
+
const left = gutterLeft + cladeLabelOffset(clade)
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
key: `${rows[0]}-${rows[1]}-${index}`,
|
|
103
|
+
label,
|
|
104
|
+
color: markColor,
|
|
105
|
+
left,
|
|
106
|
+
top: rows[0] * rowHeight,
|
|
107
|
+
width: effectiveTreeAreaWidth - left - bracketGap,
|
|
108
|
+
height: cladeHeight(clade, rowHeight),
|
|
109
|
+
horizontal: cladeLabelHorizontal(clade, rowHeight, fontSize),
|
|
110
|
+
},
|
|
111
|
+
]
|
|
112
|
+
})
|
|
113
|
+
}
|
|
@@ -36,7 +36,7 @@ function inYBlock(y: number, offsetY: number, by: number, pad: number) {
|
|
|
36
36
|
/**
|
|
37
37
|
* Every node whose subtree reaches into the block, skipping the subtrees that
|
|
38
38
|
* do not. A subtree's leaves are one contiguous run of rows, recorded by
|
|
39
|
-
*
|
|
39
|
+
* layoutTree as xMin/xMax, so a block of a 200k-tip tree visits a few dozen
|
|
40
40
|
* nodes.
|
|
41
41
|
*
|
|
42
42
|
* A link out of a visited node is drawn even when its child is pruned, so a
|
|
@@ -706,18 +706,7 @@ export function renderTreeCanvas({
|
|
|
706
706
|
|
|
707
707
|
// memoized on the model and shared across the tree/bubble/label passes (and
|
|
708
708
|
// across all tree blocks) rather than re-traversing the hierarchy in each
|
|
709
|
-
const {
|
|
710
|
-
maxBranchLength,
|
|
711
|
-
maxDepthToLeaf,
|
|
712
|
-
showBranchLenEffective,
|
|
713
|
-
effectiveTreeWidth,
|
|
714
|
-
} = model
|
|
715
|
-
// pixel x of the tips. A phylogram scales branch lengths so the longest
|
|
716
|
-
// root-to-tip path lands at maxBranchLength; a cladogram ignores lengths and
|
|
717
|
-
// spreads topological depth across the whole tree area instead. Reusing
|
|
718
|
-
// maxBranchLength for the cladogram would pin every node to x=0 for a tree
|
|
719
|
-
// with no branch lengths -- which is exactly what forces cladogram mode.
|
|
720
|
-
const tipX = showBranchLenEffective ? maxBranchLength : effectiveTreeWidth
|
|
709
|
+
const { maxDepthToLeaf, effectiveTreeWidth: tipX } = model
|
|
721
710
|
// built once for all three passes: each of them asks about a different node on
|
|
722
711
|
// every block of every redraw, and `collapsed` is a list
|
|
723
712
|
const collapsedSet = new Set(model.collapsed)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { descendants } from '../../hierarchy.ts'
|
|
2
|
+
import { makeOffscreenCanvas } from '../msa/msaRaster.ts'
|
|
2
3
|
import { getNodeX } from './renderTreeCanvas.ts'
|
|
3
4
|
|
|
4
5
|
import type { HierarchyNode } from '../../hierarchy.ts'
|
|
@@ -62,10 +63,10 @@ export function drawTreeOverview({
|
|
|
62
63
|
continue
|
|
63
64
|
}
|
|
64
65
|
const sx = nodeX(source)
|
|
65
|
-
const sy = rowY(source.x
|
|
66
|
+
const sy = rowY(source.x)
|
|
66
67
|
for (const target of source.children) {
|
|
67
68
|
const tx = nodeX(target)
|
|
68
|
-
const ty = rowY(target.x
|
|
69
|
+
const ty = rowY(target.x)
|
|
69
70
|
if (Math.abs(tx - sx) < 1 && Math.abs(ty - sy) < 1) {
|
|
70
71
|
continue
|
|
71
72
|
}
|
|
@@ -158,17 +159,8 @@ function overviewKeys({
|
|
|
158
159
|
]
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
typeof OffscreenCanvas !== 'undefined'
|
|
164
|
-
? new OffscreenCanvas(width, height)
|
|
165
|
-
: typeof document !== 'undefined'
|
|
166
|
-
? Object.assign(document.createElement('canvas'), { width, height })
|
|
167
|
-
: undefined
|
|
168
|
-
const ctx = canvas?.getContext('2d')
|
|
169
|
-
return ctx && typeof (ctx as CanvasRenderingContext2D).stroke === 'function'
|
|
170
|
-
? { canvas: canvas as RasterCanvas, ctx: ctx as CanvasRenderingContext2D }
|
|
171
|
-
: undefined
|
|
162
|
+
function canStroke(ctx: unknown): ctx is CanvasRenderingContext2D {
|
|
163
|
+
return typeof (ctx as CanvasRenderingContext2D | null)?.stroke === 'function'
|
|
172
164
|
}
|
|
173
165
|
|
|
174
166
|
/**
|
|
@@ -198,9 +190,10 @@ export function treeOverviewImage({
|
|
|
198
190
|
if (prev && keys.every((key, i) => key === prev.keys[i])) {
|
|
199
191
|
return prev.canvas
|
|
200
192
|
}
|
|
201
|
-
const made =
|
|
193
|
+
const made = makeOffscreenCanvas(
|
|
202
194
|
Math.max(1, Math.round(width * scale)),
|
|
203
195
|
Math.max(1, Math.round(height * scale)),
|
|
196
|
+
canStroke,
|
|
204
197
|
)
|
|
205
198
|
if (made) {
|
|
206
199
|
made.ctx.scale(scale, scale)
|
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
|
|
@@ -49,10 +51,6 @@ const ownAttributes = [
|
|
|
49
51
|
// the attributes a <nightingale-manager> writes on the elements it holds
|
|
50
52
|
const nightingaleAttributes = ['display-start', 'display-end', 'highlight']
|
|
51
53
|
|
|
52
|
-
function location(uri: string | null) {
|
|
53
|
-
return uri ? { uri, locationType: 'UriLocation' as const } : undefined
|
|
54
|
-
}
|
|
55
|
-
|
|
56
54
|
function numberAttribute(value: string | null | undefined) {
|
|
57
55
|
const n = value ? Number(value) : Number.NaN
|
|
58
56
|
return Number.isFinite(n) ? n : undefined
|
|
@@ -119,54 +117,29 @@ export function defineMsaElement(tagName = 'jbrowse-msa') {
|
|
|
119
117
|
#reported?: { start: number; end: number }
|
|
120
118
|
#data: ElementData = {}
|
|
121
119
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
set features(value: Feature[] | undefined) {
|
|
144
|
-
this.#setData({ features: value })
|
|
145
|
-
}
|
|
146
|
-
get colorScheme() {
|
|
147
|
-
return this.#data.colorScheme
|
|
148
|
-
}
|
|
149
|
-
set colorScheme(value: ColorScheme | undefined) {
|
|
150
|
-
this.#setData({ colorScheme: value })
|
|
151
|
-
}
|
|
152
|
-
get highlights() {
|
|
153
|
-
return this.#data.highlights
|
|
154
|
-
}
|
|
155
|
-
set highlights(value: Highlight[] | undefined) {
|
|
156
|
-
this.#setData({ highlights: value })
|
|
157
|
-
}
|
|
158
|
-
get columnTracks() {
|
|
159
|
-
return this.#data.columnTracks
|
|
160
|
-
}
|
|
161
|
-
set columnTracks(value: ColumnTrackSpec[] | undefined) {
|
|
162
|
-
this.#setData({ columnTracks: value })
|
|
163
|
-
}
|
|
164
|
-
get residueMappings() {
|
|
165
|
-
return this.#data.residueMappings
|
|
166
|
-
}
|
|
167
|
-
set residueMappings(value: ResidueMapping[] | undefined) {
|
|
168
|
-
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
|
+
}
|
|
169
141
|
}
|
|
142
|
+
|
|
170
143
|
// the viewer's selection, which the reader's drags change
|
|
171
144
|
get selection() {
|
|
172
145
|
return this.#model ? this.#model.selection : this.#data.selection
|
|
@@ -188,9 +161,9 @@ export function defineMsaElement(tagName = 'jbrowse-msa') {
|
|
|
188
161
|
const theme = this.getAttribute('theme')
|
|
189
162
|
return {
|
|
190
163
|
...this.#data,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
164
|
+
msaUrl: this.getAttribute('msa-url') ?? undefined,
|
|
165
|
+
treeUrl: this.getAttribute('tree-url') ?? undefined,
|
|
166
|
+
gffUrl: this.getAttribute('gff-url') ?? undefined,
|
|
194
167
|
colorScheme:
|
|
195
168
|
this.#data.colorScheme ??
|
|
196
169
|
this.getAttribute('color-scheme') ??
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { legendRows } from './components/msa/legendRows.ts'
|
|
2
|
+
import { treeScaleBarHeight } from './constants.ts'
|
|
3
|
+
|
|
4
|
+
import type { LegendRow } from './components/msa/legendRows.ts'
|
|
5
|
+
import type { MsaViewModel } from './model.ts'
|
|
6
|
+
import type { Theme } from '@mui/material'
|
|
7
|
+
|
|
8
|
+
export interface ExportSvgOptions {
|
|
9
|
+
theme: Theme
|
|
10
|
+
includeMinimap?: boolean
|
|
11
|
+
includeTracks?: boolean
|
|
12
|
+
exportType: 'entire' | 'viewport'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// legend geometry, shared by the width calculation and the renderer so the
|
|
16
|
+
// reserved column on the right exactly fits the drawn legends
|
|
17
|
+
export const LEGEND_PAD = 8
|
|
18
|
+
export const LEGEND_ROW_H = 16
|
|
19
|
+
export const LEGEND_SWATCH = 12
|
|
20
|
+
export const LEGEND_FONT = 12
|
|
21
|
+
export const LEGEND_CHAR_W = 7
|
|
22
|
+
|
|
23
|
+
export const LEGEND_MAX_W = 360
|
|
24
|
+
export const LEGEND_TEXT_X = LEGEND_PAD + LEGEND_SWATCH + 6
|
|
25
|
+
|
|
26
|
+
export function getLegendWidth(rows: LegendRow[]) {
|
|
27
|
+
const maxLen = rows.reduce((a, r) => Math.max(a, r.label.length), 0)
|
|
28
|
+
const w = LEGEND_TEXT_X + LEGEND_PAD + maxLen * LEGEND_CHAR_W
|
|
29
|
+
return Math.min(LEGEND_MAX_W, Math.max(120, w))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function legendHeight(rows: LegendRow[]) {
|
|
33
|
+
return LEGEND_PAD * 2 + rows.length * LEGEND_ROW_H
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// resolved sizes/offsets (in svg user units) for the chosen export, shared by
|
|
37
|
+
// every layer; 'entire' renders the whole alignment unscrolled, 'viewport'
|
|
38
|
+
// mirrors the live scroll position
|
|
39
|
+
export interface Layout {
|
|
40
|
+
width: number
|
|
41
|
+
msaAreaWidth: number
|
|
42
|
+
height: number
|
|
43
|
+
contentHeight: number
|
|
44
|
+
trackHeight: number
|
|
45
|
+
// the band the minimap, the row panel headers and the tree overview stacked
|
|
46
|
+
// on the scale bar share across the top
|
|
47
|
+
topHeight: number
|
|
48
|
+
offsetX: number
|
|
49
|
+
offsetY: number
|
|
50
|
+
includeMinimap: boolean
|
|
51
|
+
legendWidth: number
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getLayout(model: MsaViewModel, opts: ExportSvgOptions): Layout {
|
|
55
|
+
const {
|
|
56
|
+
scrollX,
|
|
57
|
+
scrollY,
|
|
58
|
+
totalWidth,
|
|
59
|
+
totalHeight,
|
|
60
|
+
effectiveTreeAreaWidth,
|
|
61
|
+
rowPanelsWidth,
|
|
62
|
+
rowPanelsHeaderHeight,
|
|
63
|
+
totalTrackAreaHeight,
|
|
64
|
+
minimapHeight,
|
|
65
|
+
msaAreaHeight,
|
|
66
|
+
msaCanvasWidth,
|
|
67
|
+
showHorizontalScrollbar,
|
|
68
|
+
treeOverviewHeight,
|
|
69
|
+
treeScaleBar,
|
|
70
|
+
} = model
|
|
71
|
+
const trackHeight = opts.includeTracks ? totalTrackAreaHeight : 0
|
|
72
|
+
// the minimap reflects the live viewport scroll position, so it's only
|
|
73
|
+
// meaningful for a viewport export, never for the entire alignment -- and
|
|
74
|
+
// only when the live view shows one at all, since a minimap over an alignment
|
|
75
|
+
// that already fits marks a viewport wider than the bar
|
|
76
|
+
const includeMinimap =
|
|
77
|
+
opts.exportType === 'viewport' &&
|
|
78
|
+
!!opts.includeMinimap &&
|
|
79
|
+
showHorizontalScrollbar
|
|
80
|
+
const rows = legendRows(model.legends)
|
|
81
|
+
const legendWidth = rows.length > 0 ? getLegendWidth(rows) : 0
|
|
82
|
+
const topHeight = Math.max(
|
|
83
|
+
includeMinimap ? minimapHeight : 0,
|
|
84
|
+
rowPanelsHeaderHeight,
|
|
85
|
+
treeOverviewHeight + (treeScaleBar ? treeScaleBarHeight : 0),
|
|
86
|
+
)
|
|
87
|
+
const gutterWidth = effectiveTreeAreaWidth + rowPanelsWidth
|
|
88
|
+
|
|
89
|
+
// width stays content-only; the legend occupies an extra column added at the
|
|
90
|
+
// svg root in MsaSvg. The viewport export takes the alignment canvas's own
|
|
91
|
+
// size rather than the widget's -- the widget box also covers the header, the
|
|
92
|
+
// resize handle and the scrollbars, and rendering that box exports rows and
|
|
93
|
+
// columns the scrollbars hide on screen
|
|
94
|
+
return opts.exportType === 'entire'
|
|
95
|
+
? {
|
|
96
|
+
width: totalWidth + gutterWidth,
|
|
97
|
+
msaAreaWidth: totalWidth,
|
|
98
|
+
height: totalHeight + trackHeight + topHeight,
|
|
99
|
+
contentHeight: totalHeight,
|
|
100
|
+
trackHeight,
|
|
101
|
+
topHeight,
|
|
102
|
+
offsetX: 0,
|
|
103
|
+
offsetY: 0,
|
|
104
|
+
includeMinimap,
|
|
105
|
+
legendWidth,
|
|
106
|
+
}
|
|
107
|
+
: {
|
|
108
|
+
width: msaCanvasWidth + gutterWidth,
|
|
109
|
+
msaAreaWidth: msaCanvasWidth,
|
|
110
|
+
height: msaAreaHeight + topHeight + trackHeight,
|
|
111
|
+
contentHeight: msaAreaHeight,
|
|
112
|
+
trackHeight,
|
|
113
|
+
topHeight,
|
|
114
|
+
offsetX: -scrollX,
|
|
115
|
+
offsetY: -scrollY,
|
|
116
|
+
includeMinimap,
|
|
117
|
+
legendWidth,
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* the exported page's size: the layout plus the legend column, and as tall as
|
|
123
|
+
* the legend where the key outgrows a short alignment
|
|
124
|
+
*/
|
|
125
|
+
export function exportPageSize(model: MsaViewModel, layout: Layout) {
|
|
126
|
+
const { width, height, legendWidth, topHeight } = layout
|
|
127
|
+
return {
|
|
128
|
+
width: width + legendWidth,
|
|
129
|
+
height:
|
|
130
|
+
legendWidth > 0
|
|
131
|
+
? Math.max(height, topHeight + legendHeight(legendRows(model.legends)))
|
|
132
|
+
: height,
|
|
133
|
+
}
|
|
134
|
+
}
|