react-msaview 7.0.0 → 8.1.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/README.md +11 -10
- package/bundle/index.js +122 -111
- package/bundle/index.js.map +4 -4
- package/dist/calculateBlocks.js +5 -3
- package/dist/calculateBlocks.js.map +1 -1
- package/dist/colorSchemes.js +1 -2
- package/dist/colorSchemes.js.map +1 -1
- package/dist/columnStats.d.ts +28 -0
- package/dist/columnStats.js +34 -0
- package/dist/columnStats.js.map +1 -0
- package/dist/components/DragHandle.d.ts +3 -2
- package/dist/components/DragHandle.js +11 -5
- package/dist/components/DragHandle.js.map +1 -1
- package/dist/components/Loading.js +2 -8
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.js +17 -6
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +64 -7
- package/dist/components/MSAViewer.js +128 -23
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/PortalTooltip.d.ts +11 -0
- package/dist/components/PortalTooltip.js +29 -0
- package/dist/components/PortalTooltip.js.map +1 -0
- package/dist/components/ResizeHandles.js +11 -29
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/SequenceTextArea.js +3 -4
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/Track.js +43 -24
- package/dist/components/Track.js.map +1 -1
- package/dist/components/dialogs/AboutDialog.js +6 -6
- package/dist/components/dialogs/AboutDialog.js.map +1 -1
- package/dist/components/dialogs/AnnotationFileDialog.js +5 -2
- package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.js +6 -4
- package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
- package/dist/components/dialogs/FeatureDialog.js +8 -3
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/dialogs/TrackInfoDialog.js +1 -1
- package/dist/components/dialogs/TrackInfoDialog.js.map +1 -1
- package/dist/components/header/GappynessSlider.js +6 -11
- package/dist/components/header/GappynessSlider.js.map +1 -1
- package/dist/components/header/Header.js +4 -1
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/LoadWarnings.js +6 -23
- package/dist/components/header/LoadWarnings.js.map +1 -1
- package/dist/components/header/ScrollZoomIcons.d.ts +6 -0
- package/dist/components/header/ScrollZoomIcons.js +35 -0
- package/dist/components/header/ScrollZoomIcons.js.map +1 -0
- package/dist/components/header/TreeSettingsMenu.js +1 -3
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/UnshareableDataWarning.js +2 -4
- package/dist/components/header/UnshareableDataWarning.js.map +1 -1
- package/dist/components/header/ZoomControls.js +49 -6
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/header/getAnnotationsMenu.js +3 -6
- package/dist/components/header/getAnnotationsMenu.js.map +1 -1
- package/dist/components/header/settingsMenuItems.js +12 -9
- package/dist/components/header/settingsMenuItems.js.map +1 -1
- package/dist/components/import/ImportForm.js +1 -1
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/util.js +1 -2
- package/dist/components/import/util.js.map +1 -1
- package/dist/components/minimap/Minimap.js +1 -2
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/msa/AnnotationLegend.js +27 -19
- package/dist/components/msa/AnnotationLegend.js.map +1 -1
- package/dist/components/msa/MSACanvas.js +2 -4
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +13 -15
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js +2 -1
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/domainBandCursor.d.ts +7 -11
- package/dist/components/msa/domainBandCursor.js +7 -11
- package/dist/components/msa/domainBandCursor.js.map +1 -1
- package/dist/components/msa/drawFeatureSpans.d.ts +59 -0
- package/dist/components/msa/drawFeatureSpans.js +113 -0
- package/dist/components/msa/drawFeatureSpans.js.map +1 -0
- package/dist/components/msa/legendRows.d.ts +8 -0
- package/dist/components/msa/legendRows.js +16 -0
- package/dist/components/msa/legendRows.js.map +1 -0
- package/dist/components/msa/msaRaster.d.ts +24 -31
- package/dist/components/msa/msaRaster.js +30 -39
- package/dist/components/msa/msaRaster.js.map +1 -1
- package/dist/components/msa/packDomainLanes.d.ts +20 -0
- package/dist/components/msa/packDomainLanes.js +33 -0
- package/dist/components/msa/packDomainLanes.js.map +1 -0
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +3 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +50 -87
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderHighlights.d.ts +15 -13
- package/dist/components/msa/renderHighlights.js +43 -20
- package/dist/components/msa/renderHighlights.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +12 -12
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/tileColor.js +4 -7
- package/dist/components/msa/tileColor.js.map +1 -1
- package/dist/components/msa/useMsaBlockMouse.d.ts +5 -3
- package/dist/components/msa/useMsaBlockMouse.js +6 -6
- package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
- package/dist/components/rowpanels/RowPanelBlock.d.ts +9 -0
- package/dist/components/rowpanels/RowPanelBlock.js +86 -0
- package/dist/components/rowpanels/RowPanelBlock.js.map +1 -0
- package/dist/components/rowpanels/RowPanelHeaders.d.ts +12 -0
- package/dist/components/rowpanels/RowPanelHeaders.js +38 -0
- package/dist/components/rowpanels/RowPanelHeaders.js.map +1 -0
- package/dist/components/{msa/ColumnStats.d.ts → rowpanels/RowPanels.d.ts} +2 -2
- package/dist/components/rowpanels/RowPanels.js +32 -0
- package/dist/components/rowpanels/RowPanels.js.map +1 -0
- package/dist/components/rowpanels/headerLayout.d.ts +1 -0
- package/dist/components/rowpanels/headerLayout.js +5 -0
- package/dist/components/rowpanels/headerLayout.js.map +1 -0
- package/dist/components/rowpanels/renderFeaturePanel.d.ts +21 -0
- package/dist/components/rowpanels/renderFeaturePanel.js +37 -0
- package/dist/components/rowpanels/renderFeaturePanel.js.map +1 -0
- package/dist/components/rowpanels/renderRowPanel.d.ts +23 -0
- package/dist/components/rowpanels/renderRowPanel.js +22 -0
- package/dist/components/rowpanels/renderRowPanel.js.map +1 -0
- package/dist/components/rowpanels/renderStrip.d.ts +20 -0
- package/dist/components/rowpanels/renderStrip.js +26 -0
- package/dist/components/rowpanels/renderStrip.js.map +1 -0
- package/dist/components/tracks/TrackBlocks.js +3 -5
- package/dist/components/tracks/TrackBlocks.js.map +1 -1
- package/dist/components/tracks/TrackTooltipContent.d.ts +15 -0
- package/dist/components/tracks/TrackTooltipContent.js +109 -0
- package/dist/components/tracks/TrackTooltipContent.js.map +1 -0
- package/dist/components/tracks/drawTracks.d.ts +4 -4
- package/dist/components/tracks/drawTracks.js +25 -39
- package/dist/components/tracks/drawTracks.js.map +1 -1
- package/dist/components/tracks/useTrackHover.d.ts +22 -0
- package/dist/components/tracks/useTrackHover.js +30 -0
- package/dist/components/tracks/useTrackHover.js.map +1 -0
- package/dist/components/tree/CladeLabels.d.ts +12 -0
- package/dist/components/tree/CladeLabels.js +48 -0
- package/dist/components/tree/CladeLabels.js.map +1 -0
- package/dist/components/tree/TreeBranchMenu.js +1 -1
- package/dist/components/tree/TreeBranchMenu.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js +5 -4
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +4 -21
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeNodeMenu.js +1 -1
- package/dist/components/tree/TreeNodeMenu.js.map +1 -1
- package/dist/components/tree/TreeOverview.d.ts +14 -0
- package/dist/components/tree/TreeOverview.js +75 -0
- package/dist/components/tree/TreeOverview.js.map +1 -0
- package/dist/components/tree/TreeRuler.js +9 -13
- package/dist/components/tree/TreeRuler.js.map +1 -1
- package/dist/components/tree/cladeBrackets.d.ts +25 -0
- package/dist/components/tree/cladeBrackets.js +51 -0
- package/dist/components/tree/cladeBrackets.js.map +1 -0
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +2 -2
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +160 -25
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/tree/renderTreeOverview.d.ts +52 -0
- package/dist/components/tree/renderTreeOverview.js +138 -0
- package/dist/components/tree/renderTreeOverview.js.map +1 -0
- package/dist/components/tree/useTreeHover.js +2 -4
- package/dist/components/tree/useTreeHover.js.map +1 -1
- package/dist/constants.d.ts +16 -0
- package/dist/constants.js +52 -22
- package/dist/constants.js.map +1 -1
- package/dist/createPaletteMap.d.ts +7 -6
- package/dist/createPaletteMap.js +10 -9
- package/dist/createPaletteMap.js.map +1 -1
- package/dist/element.d.ts +13 -0
- package/dist/element.js +269 -0
- package/dist/element.js.map +1 -0
- package/dist/featureFields.d.ts +11 -0
- package/dist/featureFields.js +17 -0
- package/dist/featureFields.js.map +1 -0
- package/dist/flatToTree.js +1 -2
- package/dist/flatToTree.js.map +1 -1
- package/dist/ggplotPalettes.d.ts +10 -0
- package/dist/ggplotPalettes.js +58 -0
- package/dist/ggplotPalettes.js.map +1 -1
- package/dist/hierarchy.d.ts +27 -0
- package/dist/hierarchy.js +66 -9
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/model/DataModel.js +2 -5
- package/dist/model/DataModel.js.map +1 -1
- package/dist/model/msaModel.d.ts +3 -2
- package/dist/model/msaModel.js +3 -2
- package/dist/model/msaModel.js.map +1 -1
- package/dist/model/treeModel.d.ts +30 -0
- package/dist/model/treeModel.js +37 -1
- package/dist/model/treeModel.js.map +1 -1
- package/dist/model.d.ts +549 -294
- package/dist/model.js +1412 -621
- package/dist/model.js.map +1 -1
- package/dist/mount.d.ts +11 -0
- package/dist/mount.js +22 -0
- package/dist/mount.js.map +1 -0
- package/dist/neighborJoining.js +8 -32
- package/dist/neighborJoining.js.map +1 -1
- package/dist/renderToStaticMarkup.d.ts +10 -19
- package/dist/renderToStaticMarkup.js +13 -24
- package/dist/renderToStaticMarkup.js.map +1 -1
- package/dist/renderToSvg.js +180 -56
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +4 -6
- package/dist/rowCoordinateCalculations.js +4 -6
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/scales.d.ts +22 -0
- package/dist/scales.js +30 -0
- package/dist/scales.js.map +1 -0
- package/dist/seqPosToGlobalCol.d.ts +2 -3
- package/dist/seqPosToGlobalCol.js +2 -3
- package/dist/seqPosToGlobalCol.js.map +1 -1
- package/dist/sequenceLogo.d.ts +6 -11
- package/dist/sequenceLogo.js +6 -11
- package/dist/sequenceLogo.js.map +1 -1
- package/dist/stripDefault.d.ts +7 -14
- package/dist/stripDefault.js +7 -14
- package/dist/stripDefault.js.map +1 -1
- package/dist/svgTestUtil.d.ts +186 -70
- package/dist/types.d.ts +221 -21
- package/dist/umd.d.ts +2 -0
- package/dist/umd.js +4 -2
- package/dist/umd.js.map +1 -1
- package/dist/useCanvasAutorun.d.ts +5 -10
- package/dist/useCanvasAutorun.js +5 -10
- package/dist/useCanvasAutorun.js.map +1 -1
- package/dist/useMsaSvgFigure.d.ts +20 -0
- package/dist/useMsaSvgFigure.js +46 -0
- package/dist/useMsaSvgFigure.js.map +1 -0
- package/dist/useWheelScroll.js +0 -4
- package/dist/useWheelScroll.js.map +1 -1
- package/dist/util.d.ts +5 -6
- package/dist/util.js +13 -6
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +19 -12
- package/src/calculateBlocks.ts +5 -3
- package/src/colorSchemes.ts +1 -2
- package/src/columnStats.ts +58 -0
- package/src/components/DragHandle.tsx +18 -7
- package/src/components/Loading.tsx +4 -36
- package/src/components/MSAView.tsx +19 -5
- package/src/components/MSAViewer.tsx +240 -28
- package/src/components/PortalTooltip.tsx +47 -0
- package/src/components/ResizeHandles.tsx +17 -32
- package/src/components/SequenceTextArea.tsx +3 -4
- package/src/components/Track.tsx +57 -19
- package/src/components/dialogs/AboutDialog.tsx +35 -6
- package/src/components/dialogs/AnnotationFileDialog.tsx +10 -1
- package/src/components/dialogs/ExportSVGDialog.tsx +8 -3
- package/src/components/dialogs/FeatureDialog.tsx +11 -3
- package/src/components/dialogs/TrackInfoDialog.tsx +1 -1
- package/src/components/header/GappynessSlider.tsx +6 -11
- package/src/components/header/Header.tsx +7 -1
- package/src/components/header/LoadWarnings.tsx +11 -25
- package/src/components/header/ScrollZoomIcons.tsx +52 -0
- package/src/components/header/TreeSettingsMenu.tsx +1 -3
- package/src/components/header/UnshareableDataWarning.tsx +2 -4
- package/src/components/header/ZoomControls.tsx +74 -14
- package/src/components/header/getAnnotationsMenu.ts +3 -6
- package/src/components/header/settingsMenuItems.ts +13 -8
- package/src/components/import/ImportForm.tsx +3 -5
- package/src/components/import/ImportFormExamples.tsx +2 -2
- package/src/components/import/util.ts +1 -2
- package/src/components/minimap/Minimap.tsx +1 -2
- package/src/components/msa/AnnotationLegend.tsx +48 -38
- package/src/components/msa/MSACanvas.tsx +3 -8
- package/src/components/msa/MSACanvasBlock.tsx +13 -16
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -1
- package/src/components/msa/domainBandCursor.ts +7 -11
- package/src/components/msa/drawFeatureSpans.ts +205 -0
- package/src/components/msa/legendRows.ts +24 -0
- package/src/components/msa/msaRaster.ts +30 -39
- package/src/components/msa/packDomainLanes.ts +36 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +67 -123
- package/src/components/msa/renderHighlights.ts +53 -20
- package/src/components/msa/renderMSABlock.ts +14 -11
- package/src/components/msa/tileColor.ts +4 -7
- package/src/components/msa/useMsaBlockMouse.ts +6 -6
- package/src/components/rowpanels/RowPanelBlock.tsx +139 -0
- package/src/components/rowpanels/RowPanelHeaders.tsx +57 -0
- package/src/components/rowpanels/RowPanels.tsx +77 -0
- package/src/components/rowpanels/headerLayout.ts +5 -0
- package/src/components/rowpanels/renderFeaturePanel.ts +66 -0
- package/src/components/rowpanels/renderRowPanel.ts +41 -0
- package/src/components/rowpanels/renderStrip.ts +46 -0
- package/src/components/tracks/TrackBlocks.tsx +3 -5
- package/src/components/tracks/TrackTooltipContent.tsx +156 -0
- package/src/components/tracks/drawTracks.ts +25 -50
- package/src/components/tracks/useTrackHover.ts +42 -0
- package/src/components/tree/CladeLabels.tsx +77 -0
- package/src/components/tree/TreeBranchMenu.tsx +1 -2
- package/src/components/tree/TreeCanvas.tsx +2 -3
- package/src/components/tree/TreeCanvasBlock.tsx +8 -32
- package/src/components/tree/TreeNodeMenu.tsx +1 -2
- package/src/components/tree/TreeOverview.tsx +106 -0
- package/src/components/tree/TreeRuler.tsx +11 -22
- package/src/components/tree/cladeBrackets.ts +73 -0
- package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +2 -2
- package/src/components/tree/renderTreeCanvas.ts +242 -21
- package/src/components/tree/renderTreeOverview.ts +212 -0
- package/src/components/tree/useTreeHover.ts +2 -4
- package/src/constants.ts +61 -22
- package/src/createPaletteMap.ts +10 -9
- package/src/element.ts +321 -0
- package/src/featureFields.ts +19 -0
- package/src/flatToTree.ts +1 -2
- package/src/ggplotPalettes.ts +60 -0
- package/src/hierarchy.ts +77 -9
- package/src/index.ts +31 -7
- package/src/model/DataModel.ts +2 -5
- package/src/model/msaModel.ts +3 -2
- package/src/model/treeModel.ts +42 -0
- package/src/model.ts +1677 -643
- package/src/mount.tsx +32 -0
- package/src/neighborJoining.ts +8 -32
- package/src/renderToStaticMarkup.ts +13 -24
- package/src/renderToSvg.tsx +335 -68
- package/src/rowCoordinateCalculations.ts +4 -6
- package/src/scales.ts +47 -0
- package/src/seqPosToGlobalCol.ts +2 -3
- package/src/sequenceLogo.ts +6 -11
- package/src/stripDefault.ts +7 -14
- package/src/types.ts +260 -45
- package/src/umd.ts +4 -2
- package/src/useCanvasAutorun.ts +5 -10
- package/src/useMsaSvgFigure.ts +72 -0
- package/src/useWheelScroll.ts +0 -4
- package/src/util.ts +15 -6
- package/src/version.ts +1 -1
- package/dist/components/msa/ColumnStats.js +0 -42
- package/dist/components/msa/ColumnStats.js.map +0 -1
- package/src/components/msa/ColumnStats.tsx +0 -54
|
@@ -5,6 +5,9 @@ import ExpandMore from '@mui/icons-material/ExpandMore'
|
|
|
5
5
|
import { IconButton, Paper, Typography } from '@mui/material'
|
|
6
6
|
import { observer } from 'mobx-react'
|
|
7
7
|
|
|
8
|
+
import { legendZIndex } from '../../constants.ts'
|
|
9
|
+
import { legendRows } from './legendRows.ts'
|
|
10
|
+
|
|
8
11
|
import type { MsaViewModel } from '../../model.ts'
|
|
9
12
|
|
|
10
13
|
const AnnotationLegend = observer(function ({
|
|
@@ -12,65 +15,72 @@ const AnnotationLegend = observer(function ({
|
|
|
12
15
|
}: {
|
|
13
16
|
model: MsaViewModel
|
|
14
17
|
}) {
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
visibleDomainTypes: visible,
|
|
18
|
-
fillPalette,
|
|
19
|
-
showDomainLegend: expanded,
|
|
20
|
-
} = model
|
|
18
|
+
const { legends, showDomainLegend: expanded } = model
|
|
19
|
+
const rows = legendRows(legends)
|
|
21
20
|
const ExpandIcon = expanded ? ExpandLess : ExpandMore
|
|
22
21
|
|
|
23
|
-
return
|
|
22
|
+
return rows.length > 0 ? (
|
|
24
23
|
<Paper
|
|
25
24
|
elevation={3}
|
|
26
25
|
style={{
|
|
27
26
|
position: 'absolute',
|
|
28
27
|
top: 4,
|
|
29
28
|
right: 4,
|
|
30
|
-
zIndex:
|
|
31
|
-
maxWidth:
|
|
29
|
+
zIndex: legendZIndex,
|
|
30
|
+
maxWidth: 220,
|
|
32
31
|
maxHeight: '60%',
|
|
33
32
|
display: 'flex',
|
|
34
33
|
flexDirection: 'column',
|
|
35
34
|
opacity: 0.95,
|
|
36
35
|
}}
|
|
37
36
|
>
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
<IconButton
|
|
38
|
+
size="small"
|
|
39
|
+
title={expanded ? 'Collapse key' : 'Expand key'}
|
|
40
|
+
style={
|
|
41
|
+
expanded
|
|
42
|
+
? { position: 'absolute', top: 0, right: 0, padding: 1 }
|
|
43
|
+
: { padding: 1 }
|
|
44
|
+
}
|
|
45
|
+
onClick={() => {
|
|
46
|
+
model.setShowDomainLegend(!expanded)
|
|
44
47
|
}}
|
|
45
48
|
>
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
title={expanded ? 'Collapse key' : 'Expand key'}
|
|
49
|
-
onClick={() => {
|
|
50
|
-
model.setShowDomainLegend(!expanded)
|
|
51
|
-
}}
|
|
52
|
-
>
|
|
53
|
-
<ExpandIcon fontSize="small" />
|
|
54
|
-
</IconButton>
|
|
55
|
-
</div>
|
|
49
|
+
<ExpandIcon style={{ fontSize: 14 }} />
|
|
50
|
+
</IconButton>
|
|
56
51
|
{expanded ? (
|
|
57
|
-
<div style={{ overflow: 'auto', padding: '
|
|
58
|
-
{
|
|
52
|
+
<div style={{ overflow: 'auto', padding: '2px 6px 4px' }}>
|
|
53
|
+
{rows.map((row, i) => (
|
|
59
54
|
<div
|
|
60
|
-
key={
|
|
61
|
-
style={{
|
|
62
|
-
|
|
55
|
+
key={row.key}
|
|
56
|
+
style={{
|
|
57
|
+
display: 'flex',
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
gap: 4,
|
|
60
|
+
marginRight: i === 0 ? 18 : 0,
|
|
61
|
+
}}
|
|
62
|
+
title={row.hint}
|
|
63
63
|
>
|
|
64
|
-
|
|
64
|
+
{row.color ? (
|
|
65
|
+
<div
|
|
66
|
+
style={{
|
|
67
|
+
width: 9,
|
|
68
|
+
height: 9,
|
|
69
|
+
flexShrink: 0,
|
|
70
|
+
background: row.color,
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
) : null}
|
|
74
|
+
<Typography
|
|
75
|
+
variant="caption"
|
|
76
|
+
noWrap
|
|
65
77
|
style={{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
background: fillPalette[accession],
|
|
78
|
+
fontSize: 10,
|
|
79
|
+
lineHeight: 1.4,
|
|
80
|
+
fontWeight: row.color ? undefined : 'bold',
|
|
70
81
|
}}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{name}
|
|
82
|
+
>
|
|
83
|
+
{row.label}
|
|
74
84
|
</Typography>
|
|
75
85
|
</div>
|
|
76
86
|
))}
|
|
@@ -34,7 +34,7 @@ const MSACanvas = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
34
34
|
)
|
|
35
35
|
const onZoom = useCallback(
|
|
36
36
|
(scaleFactor: number, offsetX: number, offsetY: number) => {
|
|
37
|
-
model.zoomToPos(scaleFactor, offsetX, offsetY)
|
|
37
|
+
model.zoomToPos(scaleFactor, offsetX, offsetY, model.wheelZoomAxis)
|
|
38
38
|
},
|
|
39
39
|
[model],
|
|
40
40
|
)
|
|
@@ -49,16 +49,11 @@ const MSACanvas = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
49
49
|
return (
|
|
50
50
|
<div
|
|
51
51
|
ref={ref}
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// is what lets a screenshot callout anchor to an alignment column instead
|
|
55
|
-
// of a hand-measured pixel
|
|
52
|
+
// screenshot callouts anchor to columns from this rect's origin:
|
|
53
|
+
// col*colWidth + scrollX, row*rowHeight + scrollY
|
|
56
54
|
data-testid="msa_canvas"
|
|
57
55
|
onMouseDown={onMouseDown}
|
|
58
56
|
onMouseUp={onMouseUp}
|
|
59
|
-
onMouseLeave={event => {
|
|
60
|
-
event.preventDefault()
|
|
61
|
-
}}
|
|
62
57
|
style={{
|
|
63
58
|
position: 'relative',
|
|
64
59
|
height,
|
|
@@ -5,7 +5,6 @@ import { useTheme } from '@mui/material'
|
|
|
5
5
|
import { observer } from 'mobx-react'
|
|
6
6
|
|
|
7
7
|
import { useCanvasAutorun } from '../../useCanvasAutorun.ts'
|
|
8
|
-
import ColumnStats from './ColumnStats.tsx'
|
|
9
8
|
import { drawMsaRaster, rasterSupported } from './msaRaster.ts'
|
|
10
9
|
import { renderBoxFeatureCanvasBlock } from './renderBoxFeatureCanvasBlock.ts'
|
|
11
10
|
import { renderMSABlock } from './renderMSABlock.ts'
|
|
@@ -39,6 +38,7 @@ const MSACanvasBlock = observer(function ({
|
|
|
39
38
|
ctx.clearRect(0, 0, canvasSize, canvasSize)
|
|
40
39
|
renderBoxFeatureCanvasBlock({
|
|
41
40
|
ctx,
|
|
41
|
+
theme,
|
|
42
42
|
offsetX,
|
|
43
43
|
offsetY,
|
|
44
44
|
model,
|
|
@@ -65,7 +65,7 @@ const MSACanvasBlock = observer(function ({
|
|
|
65
65
|
deps: [model, offsetX, offsetY, theme],
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
-
const { hoveredInsertion, mouseOverDomains
|
|
68
|
+
const { hoveredInsertion, mouseOverDomains } = model
|
|
69
69
|
|
|
70
70
|
return (
|
|
71
71
|
<>
|
|
@@ -107,20 +107,17 @@ const MSACanvasBlock = observer(function ({
|
|
|
107
107
|
: hoveredInsertion.letters}
|
|
108
108
|
</>
|
|
109
109
|
) : (
|
|
110
|
-
|
|
111
|
-
{
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
))}
|
|
122
|
-
{showColumnStats ? <ColumnStats model={model} /> : null}
|
|
123
|
-
</>
|
|
110
|
+
mouseOverDomains.map(d => (
|
|
111
|
+
<div key={`${d.accession}-${d.start}-${d.end}`}>
|
|
112
|
+
<b>{d.name}</b> ({d.accession}) {d.start}-{d.end}
|
|
113
|
+
{d.description ? (
|
|
114
|
+
<>
|
|
115
|
+
<br />
|
|
116
|
+
{d.description}
|
|
117
|
+
</>
|
|
118
|
+
) : null}
|
|
119
|
+
</div>
|
|
120
|
+
))
|
|
124
121
|
)}
|
|
125
122
|
</BaseTooltip>
|
|
126
123
|
) : null}
|
|
@@ -4,6 +4,7 @@ import { isAlive } from '@jbrowse/mobx-state-tree'
|
|
|
4
4
|
import { useTheme } from '@mui/material'
|
|
5
5
|
import { observer } from 'mobx-react'
|
|
6
6
|
|
|
7
|
+
import { msaOverlayZIndex } from '../../constants.ts'
|
|
7
8
|
import { useCanvasAutorun } from '../../useCanvasAutorun.ts'
|
|
8
9
|
import { renderMouseover } from './renderMSAMouseover.ts'
|
|
9
10
|
|
|
@@ -41,7 +42,7 @@ const MSAMouseoverCanvas = observer(function ({
|
|
|
41
42
|
left: 0,
|
|
42
43
|
width,
|
|
43
44
|
height,
|
|
44
|
-
zIndex:
|
|
45
|
+
zIndex: msaOverlayZIndex,
|
|
45
46
|
pointerEvents: 'none',
|
|
46
47
|
}}
|
|
47
48
|
/>
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import type { DomainBand } from '../../types.ts'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Left-to-right cursor over one row's domain bands
|
|
5
|
-
*
|
|
6
|
-
* against.
|
|
4
|
+
* Left-to-right cursor over one row's domain bands that returns the band drawn
|
|
5
|
+
* on top at a column, for a letter's contrast color.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* actually sees is the last one painted over that column. `stackIndex` is that
|
|
12
|
-
* paint order.
|
|
7
|
+
* The overlay paints in `domainBands` order, largest first, so where signatures
|
|
8
|
+
* nest (InterProScan often emits a family enclosing a domain) the visible band
|
|
9
|
+
* is the last one painted. `stackIndex` is that paint order.
|
|
13
10
|
*
|
|
14
|
-
* `bands` must be sorted by start column (`domainBandsByStart`)
|
|
15
|
-
*
|
|
16
|
-
* Both keep this to one pass over the bands per row rather than a scan per cell.
|
|
11
|
+
* `bands` must be sorted by start column (`domainBandsByStart`) and columns
|
|
12
|
+
* visited in increasing order, which keeps this to one pass per row.
|
|
17
13
|
*/
|
|
18
14
|
export function domainBandCursor(bands: DomainBand[] | undefined) {
|
|
19
15
|
let next = 0
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { minFeatureLabelHeight } from '../../constants.ts'
|
|
2
|
+
|
|
3
|
+
import type { HierarchyNode } from '../../hierarchy.ts'
|
|
4
|
+
import type { Annotation, NodeWithIdsAndLength } from '../../types.ts'
|
|
5
|
+
import type { RenderCtx } from '../renderCtx.ts'
|
|
6
|
+
|
|
7
|
+
/** one drawn span: a feature, the lane it sits in, and its row's depth */
|
|
8
|
+
export interface SpanBand {
|
|
9
|
+
annotation: Annotation
|
|
10
|
+
lane: number
|
|
11
|
+
laneCount: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** one row's spans, at the row baseline `y` the tree layout gives it */
|
|
15
|
+
export interface SpanRow<T extends SpanBand> {
|
|
16
|
+
y: number
|
|
17
|
+
bands: T[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Where a band lands inside its row. The alignment overlay fills the row, bars
|
|
22
|
+
* it along the bottom, or stacks thin sub-rows; a `features` row panel divides
|
|
23
|
+
* the row between its lanes.
|
|
24
|
+
*/
|
|
25
|
+
export interface SpanLayout {
|
|
26
|
+
/** the band height in a row needing `laneCount` lanes */
|
|
27
|
+
height: (laneCount: number) => number
|
|
28
|
+
/** the band's top edge, from its row baseline, its lane and its height */
|
|
29
|
+
top: (y: number, lane: number, height: number) => number
|
|
30
|
+
/** how far back from the feature's end the head starts */
|
|
31
|
+
headLength: (height: number) => number
|
|
32
|
+
/**
|
|
33
|
+
* how far the head rises above the band. A bar too thin to taper reads its
|
|
34
|
+
* direction off a head taller than itself, and the bar sits on the row's
|
|
35
|
+
* bottom edge, so the room is above.
|
|
36
|
+
*/
|
|
37
|
+
headRise?: (height: number) => number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** the rows of `bandsByRow` that `leaves` covers, in display order */
|
|
41
|
+
export function spanRows<T extends SpanBand>(
|
|
42
|
+
leaves: HierarchyNode<NodeWithIdsAndLength>[],
|
|
43
|
+
bandsByRow: Map<string, T[]>,
|
|
44
|
+
): SpanRow<T>[] {
|
|
45
|
+
const rows: SpanRow<T>[] = []
|
|
46
|
+
for (const leaf of leaves) {
|
|
47
|
+
const bands = bandsByRow.get(leaf.data.name)
|
|
48
|
+
if (bands && bands.length > 0) {
|
|
49
|
+
rows.push({ y: leaf.x!, bands })
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return rows
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The span mark, in whatever x space the caller maps its bands into: alignment
|
|
57
|
+
* columns for the domain overlay, panel pixels for a `features` row panel. A
|
|
58
|
+
* feature with a strand draws as an arrow, one without as a box, and a label
|
|
59
|
+
* draws inside the span wherever the text fits.
|
|
60
|
+
*
|
|
61
|
+
* `xOf` returns the span's `[xStart, xEnd]` in the context's coordinates, and
|
|
62
|
+
* the context is translated so that `y - rowHeight` is the row's top edge.
|
|
63
|
+
*/
|
|
64
|
+
export function drawFeatureSpans<T extends SpanBand>({
|
|
65
|
+
ctx,
|
|
66
|
+
rows,
|
|
67
|
+
layout,
|
|
68
|
+
xOf,
|
|
69
|
+
colors,
|
|
70
|
+
labelOf,
|
|
71
|
+
labelDrawn,
|
|
72
|
+
contrastText,
|
|
73
|
+
xMin,
|
|
74
|
+
xMax,
|
|
75
|
+
}: {
|
|
76
|
+
ctx: RenderCtx
|
|
77
|
+
rows: SpanRow<T>[]
|
|
78
|
+
layout: SpanLayout
|
|
79
|
+
xOf: (band: T) => [number, number]
|
|
80
|
+
colors: Map<Annotation, { fill: string; stroke: string }>
|
|
81
|
+
labelOf?: (band: T) => string | undefined
|
|
82
|
+
labelDrawn?: (band: T) => void
|
|
83
|
+
contrastText: (color: string) => string
|
|
84
|
+
xMin: number
|
|
85
|
+
xMax: number
|
|
86
|
+
}) {
|
|
87
|
+
// one row's spans are drawn before any of its labels. Bands are ordered
|
|
88
|
+
// longest-first so a nested one lands on top, and drawing each label with its
|
|
89
|
+
// own span put the child's box over the parent's text: `S` covered `RBD`, and
|
|
90
|
+
// `RBD` read as `RB`. Reused across rows rather than allocated per row.
|
|
91
|
+
const placed: {
|
|
92
|
+
band: T
|
|
93
|
+
xStart: number
|
|
94
|
+
w: number
|
|
95
|
+
t: number
|
|
96
|
+
head: number
|
|
97
|
+
fill: string
|
|
98
|
+
}[] = []
|
|
99
|
+
|
|
100
|
+
for (const { y, bands } of rows) {
|
|
101
|
+
const h = layout.height(bands[0]!.laneCount)
|
|
102
|
+
const headLen = layout.headLength(h)
|
|
103
|
+
const rise = layout.headRise?.(h) ?? 0
|
|
104
|
+
const labelled = labelOf !== undefined && h >= minFeatureLabelHeight
|
|
105
|
+
placed.length = 0
|
|
106
|
+
|
|
107
|
+
for (const band of bands) {
|
|
108
|
+
const [xStart, xEnd] = xOf(band)
|
|
109
|
+
const w = xEnd - xStart
|
|
110
|
+
if (xEnd < xMin || xStart > xMax) {
|
|
111
|
+
continue
|
|
112
|
+
}
|
|
113
|
+
const t = layout.top(y, band.lane, h)
|
|
114
|
+
const { fill, stroke } = colors.get(band.annotation)!
|
|
115
|
+
ctx.fillStyle = fill
|
|
116
|
+
ctx.strokeStyle = stroke
|
|
117
|
+
const { strand } = band.annotation
|
|
118
|
+
const head = strand === undefined ? 0 : Math.min(headLen, w)
|
|
119
|
+
if (strand === undefined) {
|
|
120
|
+
ctx.fillRect(xStart, t, w, h)
|
|
121
|
+
ctx.strokeRect(xStart, t, w, h)
|
|
122
|
+
} else {
|
|
123
|
+
drawGeneArrow({ ctx, x: xStart, t, w, h, head, rise, strand })
|
|
124
|
+
}
|
|
125
|
+
if (labelled) {
|
|
126
|
+
placed.push({ band, xStart, w, t, head, fill })
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (placed.length > 0) {
|
|
131
|
+
ctx.font = `${Math.min(h - 2, 11)}px sans-serif`
|
|
132
|
+
ctx.textAlign = 'center'
|
|
133
|
+
ctx.textBaseline = 'middle'
|
|
134
|
+
for (const { band, xStart, w, t, head, fill } of placed) {
|
|
135
|
+
// asking for the label here rather than in the pass above keeps the
|
|
136
|
+
// once-per-block segment numbering in drawing order
|
|
137
|
+
const label = labelOf!(band)
|
|
138
|
+
// the head narrows to a point, so only about half of it holds text
|
|
139
|
+
if (
|
|
140
|
+
label !== undefined &&
|
|
141
|
+
ctx.measureText(label).width + 2 <= w - head / 2
|
|
142
|
+
) {
|
|
143
|
+
labelDrawn?.(band)
|
|
144
|
+
ctx.fillStyle = contrastText(fill)
|
|
145
|
+
ctx.fillText(label, xStart + w / 2, t + h / 2)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* A gene arrow, drawn the way gggenes and gggenomes draw one: the head is the
|
|
154
|
+
* last `head` pixels *of* the feature, tapering to a point at its end, and a
|
|
155
|
+
* feature shorter than the head is all head. The glyph therefore covers its
|
|
156
|
+
* start..end span and nothing else, so adjacent genes butt together instead of
|
|
157
|
+
* biting triangles out of each other, a neighbour never draws over a label, and
|
|
158
|
+
* a gene 20 columns wide reads as 20 columns wide.
|
|
159
|
+
*
|
|
160
|
+
* `rise` lifts the head above the band, for a bar too thin to taper.
|
|
161
|
+
*/
|
|
162
|
+
function drawGeneArrow({
|
|
163
|
+
ctx,
|
|
164
|
+
x,
|
|
165
|
+
t,
|
|
166
|
+
w,
|
|
167
|
+
h,
|
|
168
|
+
head,
|
|
169
|
+
rise,
|
|
170
|
+
strand,
|
|
171
|
+
}: {
|
|
172
|
+
ctx: RenderCtx
|
|
173
|
+
x: number
|
|
174
|
+
t: number
|
|
175
|
+
w: number
|
|
176
|
+
h: number
|
|
177
|
+
head: number
|
|
178
|
+
rise: number
|
|
179
|
+
strand: number
|
|
180
|
+
}) {
|
|
181
|
+
const tip = strand > 0 ? x + w : x
|
|
182
|
+
const tail = strand > 0 ? x : x + w
|
|
183
|
+
const flange = strand > 0 ? tip - head : tip + head
|
|
184
|
+
const bottom = t + h
|
|
185
|
+
const crown = t - rise
|
|
186
|
+
const point = (crown + bottom) / 2
|
|
187
|
+
ctx.beginPath()
|
|
188
|
+
if (head >= w) {
|
|
189
|
+
ctx.moveTo(tail, crown)
|
|
190
|
+
ctx.lineTo(tip, point)
|
|
191
|
+
ctx.lineTo(tail, bottom)
|
|
192
|
+
} else {
|
|
193
|
+
ctx.moveTo(tail, t)
|
|
194
|
+
ctx.lineTo(flange, t)
|
|
195
|
+
if (rise > 0) {
|
|
196
|
+
ctx.lineTo(flange, crown)
|
|
197
|
+
}
|
|
198
|
+
ctx.lineTo(tip, point)
|
|
199
|
+
ctx.lineTo(flange, bottom)
|
|
200
|
+
ctx.lineTo(tail, bottom)
|
|
201
|
+
}
|
|
202
|
+
ctx.closePath()
|
|
203
|
+
ctx.fill()
|
|
204
|
+
ctx.stroke()
|
|
205
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Legend } from '../../types.ts'
|
|
2
|
+
|
|
3
|
+
export interface LegendRow {
|
|
4
|
+
key: string
|
|
5
|
+
label: string
|
|
6
|
+
color?: string
|
|
7
|
+
hint?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// the legends flattened into the rows both the overlay and the export stack
|
|
11
|
+
// top to bottom. A title row separates one legend from the next, and a lone
|
|
12
|
+
// legend needs no title.
|
|
13
|
+
export function legendRows(legends: Legend[]): LegendRow[] {
|
|
14
|
+
const titled = legends.length > 1
|
|
15
|
+
return legends.flatMap(legend => [
|
|
16
|
+
...(titled ? [{ key: legend.id, label: legend.title }] : []),
|
|
17
|
+
...legend.entries.map(entry => ({
|
|
18
|
+
key: `${legend.id}:${entry.id}`,
|
|
19
|
+
label: entry.label,
|
|
20
|
+
color: entry.color,
|
|
21
|
+
hint: entry.id,
|
|
22
|
+
})),
|
|
23
|
+
])
|
|
24
|
+
}
|
|
@@ -36,9 +36,8 @@ const colorCache = new Map<string, number>()
|
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* CSS color string -> the packed pixel an ImageData holds for it. Painting a 1x1
|
|
39
|
-
* canvas and reading it back
|
|
40
|
-
*
|
|
41
|
-
* each distinct color is resolved once per session rather than once per cell.
|
|
39
|
+
* canvas and reading it back parses hex, rgb(), hsl() and named colors; the
|
|
40
|
+
* cache resolves each distinct color once per session.
|
|
42
41
|
*/
|
|
43
42
|
export function cssColorToPixel(css: string) {
|
|
44
43
|
const hit = colorCache.get(css)
|
|
@@ -80,13 +79,12 @@ function cellPixelFn(spec: RasterSpec, toPixel: (css: string) => number) {
|
|
|
80
79
|
/**
|
|
81
80
|
* Packs a rectangle of the alignment into one pixel per cell, in `rowNames`
|
|
82
81
|
* order, ready to hand to putImageData. Cells past the end of a row, and rows
|
|
83
|
-
* with no sequence
|
|
84
|
-
* also leaves behind.
|
|
82
|
+
* with no sequence, stay transparent, as in the per-cell painter.
|
|
85
83
|
*
|
|
86
|
-
* `colStep`/`rowStep` sample
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
84
|
+
* `colStep`/`rowStep` sample every nth cell, which fits a whole alignment into
|
|
85
|
+
* the minimap's 12px bar. `colSpan`/`rowSpan` average each block of that many
|
|
86
|
+
* cells into one pixel, so a zoom below a device pixel per column still shows
|
|
87
|
+
* every column's color without blending neighbouring rows.
|
|
90
88
|
*/
|
|
91
89
|
export function rasterPixels({
|
|
92
90
|
spec,
|
|
@@ -292,8 +290,8 @@ interface RasterCache {
|
|
|
292
290
|
|
|
293
291
|
const caches = new WeakMap<object, RasterCache>()
|
|
294
292
|
|
|
295
|
-
// Everything a cell's color depends on
|
|
296
|
-
//
|
|
293
|
+
// Everything a cell's color depends on; a change to any of them starts a fresh
|
|
294
|
+
// cache.
|
|
297
295
|
function rasterKeys(model: MsaViewModel, theme: Theme) {
|
|
298
296
|
return [
|
|
299
297
|
model.columns,
|
|
@@ -402,13 +400,12 @@ function getTile({
|
|
|
402
400
|
/**
|
|
403
401
|
* Paints the alignment background of one MSA block from cached
|
|
404
402
|
* one-pixel-per-cell tiles. The tiles do not depend on the zoom level, so a zoom
|
|
405
|
-
* frame costs a handful of drawImage calls
|
|
406
|
-
*
|
|
403
|
+
* frame costs a handful of drawImage calls. A fillRect per visible cell measured
|
|
404
|
+
* 885ms per block at the minimum column width.
|
|
407
405
|
*
|
|
408
|
-
* Below a device pixel per cell the tiles average cells together
|
|
409
|
-
*
|
|
410
|
-
*
|
|
411
|
-
* columns are narrow, every row boundary turned into a gradient.
|
|
406
|
+
* Below a device pixel per cell the tiles average cells together, per axis.
|
|
407
|
+
* The browser's image smoothing blurs both axes, which turns every row
|
|
408
|
+
* boundary into a gradient at fit-to-width, where only the columns are narrow.
|
|
412
409
|
*/
|
|
413
410
|
export function drawMsaRaster({
|
|
414
411
|
ctx,
|
|
@@ -467,12 +464,11 @@ export function drawMsaRaster({
|
|
|
467
464
|
/**
|
|
468
465
|
* A raster canvas as a PNG data URI, for embedding in the SVG export.
|
|
469
466
|
*
|
|
470
|
-
* toDataURL is the synchronous read-back. The DOM canvas
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
* signal to fall back to drawing the thing in vector.
|
|
467
|
+
* toDataURL is the synchronous read-back. The DOM canvas and a headless node
|
|
468
|
+
* canvas have it; a browser OffscreenCanvas, which the tile and thumbnail
|
|
469
|
+
* caches hold where it exists, is copied onto a DOM canvas first. Returns
|
|
470
|
+
* undefined where read-back is unavailable (jsdom), and the caller then draws
|
|
471
|
+
* in vector.
|
|
476
472
|
*/
|
|
477
473
|
export function canvasHref(canvas: RasterCanvas | undefined) {
|
|
478
474
|
if (!canvas) {
|
|
@@ -499,12 +495,10 @@ export function canvasHref(canvas: RasterCanvas | undefined) {
|
|
|
499
495
|
}
|
|
500
496
|
}
|
|
501
497
|
|
|
502
|
-
// A canvas much past this many pixels fails to allocate, and the browser's
|
|
503
|
-
// per-side limit is lower still, so a raster
|
|
504
|
-
//
|
|
505
|
-
// every row.
|
|
506
|
-
// The result is still drawn across the same rectangle -- it loses cell-exact
|
|
507
|
-
// detail at a size where no figure could show it anyway.
|
|
498
|
+
// A canvas much past this many pixels fails to allocate, and the browser's
|
|
499
|
+
// per-side limit is lower still, so a larger raster averages down per axis and
|
|
500
|
+
// is drawn across the same rectangle. An alignment that hits the limit on
|
|
501
|
+
// columns alone keeps every row.
|
|
508
502
|
const maxImagePixels = 64e6
|
|
509
503
|
const maxImageSide = 16384
|
|
510
504
|
|
|
@@ -512,14 +506,12 @@ const maxImageSide = 16384
|
|
|
512
506
|
* The alignment rectangle [col0, col0+numCols) x [row0, row0+numRows) as a PNG
|
|
513
507
|
* data URI, for the SVG export.
|
|
514
508
|
*
|
|
515
|
-
* SVG has no blit, so the export
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
* path emits a <rect> per cell, and a 200x500 alignment exhausts the heap
|
|
519
|
-
* building them.
|
|
509
|
+
* SVG has no blit, so the export draws the whole background as one <image>. The
|
|
510
|
+
* vector path emits a <rect> per cell, and a 200x500 alignment exhausts the
|
|
511
|
+
* heap building them.
|
|
520
512
|
*
|
|
521
|
-
* Returns undefined
|
|
522
|
-
*
|
|
513
|
+
* Returns undefined where a canvas cannot be read back (jsdom), and the caller
|
|
514
|
+
* then keeps the per-cell path.
|
|
523
515
|
*/
|
|
524
516
|
export function rasterImageHref({
|
|
525
517
|
model,
|
|
@@ -578,9 +570,8 @@ export function rasterImageHref({
|
|
|
578
570
|
}
|
|
579
571
|
|
|
580
572
|
/**
|
|
581
|
-
* The whole alignment sampled down to a strip
|
|
582
|
-
*
|
|
583
|
-
* exactly the same conditions.
|
|
573
|
+
* The whole alignment sampled down to a strip behind the minimap thumb, cached
|
|
574
|
+
* with the block tiles since the same keys invalidate both.
|
|
584
575
|
*/
|
|
585
576
|
export function msaThumbnail({
|
|
586
577
|
model,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assigns each of one row's bands a lane: the first lane whose last band ends
|
|
3
|
+
* before this one starts, so only bands that actually overlap stack. A row of
|
|
4
|
+
* adjacent exons packs into a single lane; a family with a domain nested inside
|
|
5
|
+
* it takes two.
|
|
6
|
+
*
|
|
7
|
+
* Packing runs left to right, but the result keeps the input's largest-first
|
|
8
|
+
* paint order. `laneCount` is the row's depth, which the renderer divides the
|
|
9
|
+
* row height by so a deep stack stays inside its own row.
|
|
10
|
+
*
|
|
11
|
+
* The coordinates are whatever the caller packs in: alignment columns for the
|
|
12
|
+
* overlay, residue positions for a `features` row panel.
|
|
13
|
+
*/
|
|
14
|
+
export function packDomainLanes<T extends { startCol: number; endCol: number }>(
|
|
15
|
+
bands: T[],
|
|
16
|
+
): (T & { lane: number; laneCount: number })[] {
|
|
17
|
+
const laneEnds: number[] = []
|
|
18
|
+
const lanes = new Array<number>(bands.length)
|
|
19
|
+
const byStart = bands
|
|
20
|
+
.map((_, i) => i)
|
|
21
|
+
.sort((a, b) => bands[a]!.startCol - bands[b]!.startCol)
|
|
22
|
+
|
|
23
|
+
for (const i of byStart) {
|
|
24
|
+
const { startCol, endCol } = bands[i]!
|
|
25
|
+
const found = laneEnds.findIndex(end => end <= startCol)
|
|
26
|
+
const lane = found === -1 ? laneEnds.length : found
|
|
27
|
+
laneEnds[lane] = endCol
|
|
28
|
+
lanes[i] = lane
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return bands.map((band, i) => ({
|
|
32
|
+
...band,
|
|
33
|
+
lane: lanes[i]!,
|
|
34
|
+
laneCount: laneEnds.length,
|
|
35
|
+
}))
|
|
36
|
+
}
|