react-msaview 6.5.0 → 8.0.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 +13 -11
- package/bundle/index.js +122 -112
- package/bundle/index.js.map +4 -4
- 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 -2
- 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 +69 -4
- package/dist/components/MSAViewer.js +201 -8
- 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.d.ts +3 -3
- package/dist/components/ResizeHandles.js +13 -24
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/SequenceTextArea.js +3 -3
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/Track.js +41 -22
- package/dist/components/Track.js.map +1 -1
- package/dist/components/dialogs/{InterProScanDialog.d.ts → AnnotationFileDialog.d.ts} +2 -2
- package/dist/components/dialogs/AnnotationFileDialog.js +92 -0
- package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -0
- package/dist/components/dialogs/ExportSVGDialog.js +5 -3
- package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
- package/dist/components/dialogs/FeatureDialog.js +13 -9
- 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 +7 -0
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HeaderStatusArea.js +0 -2
- package/dist/components/header/HeaderStatusArea.js.map +1 -1
- package/dist/components/header/LoadWarnings.d.ts +6 -0
- package/dist/components/header/LoadWarnings.js +35 -0
- package/dist/components/header/LoadWarnings.js.map +1 -0
- package/dist/components/header/MultiAlignmentSelector.js +0 -0
- package/dist/components/header/MultiAlignmentSelector.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 +7 -1
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/UnshareableDataWarning.d.ts +6 -0
- package/dist/components/header/UnshareableDataWarning.js +40 -0
- package/dist/components/header/UnshareableDataWarning.js.map +1 -0
- package/dist/components/header/ZoomControls.js +49 -6
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/header/getAnnotationsMenu.js +11 -14
- package/dist/components/header/getAnnotationsMenu.js.map +1 -1
- package/dist/components/header/settingsMenuItems.js +10 -7
- 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/ImportFormExamples.js +2 -6
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/import/util.js +2 -0
- 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 +1 -1
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +17 -20
- 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 +53 -0
- package/dist/components/msa/drawFeatureSpans.js +78 -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 +30 -27
- package/dist/components/msa/msaRaster.js +193 -90
- 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 +51 -87
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderHighlights.d.ts +44 -4
- package/dist/components/msa/renderHighlights.js +99 -11
- package/dist/components/msa/renderHighlights.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +1 -2
- package/dist/components/msa/renderMSABlock.js +28 -31
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.js +9 -30
- package/dist/components/msa/renderMSAMouseover.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/renderCtx.d.ts +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 +13 -16
- 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 +30 -12
- package/dist/components/tracks/drawTracks.js +127 -34
- 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/TreeCanvas.js +6 -4
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +6 -21
- package/dist/components/tree/TreeCanvasBlock.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 +11 -5
- 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.d.ts +0 -1
- package/dist/components/tree/renderTreeCanvas.js +221 -47
- 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/scaleBar.d.ts +10 -0
- package/dist/components/tree/scaleBar.js +24 -0
- package/dist/components/tree/scaleBar.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 +18 -1
- package/dist/constants.js +51 -8
- 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/fetchUtils.d.ts +7 -7
- package/dist/fetchUtils.js +4 -32
- package/dist/fetchUtils.js.map +1 -1
- 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 +29 -1
- package/dist/hierarchy.js +82 -19
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/model/DataModel.js +4 -4
- 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 +792 -259
- package/dist/model.js +2092 -675
- 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 +15 -13
- package/dist/renderToStaticMarkup.js +37 -25
- package/dist/renderToStaticMarkup.js.map +1 -1
- package/dist/renderToSvg.js +198 -68
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +26 -28
- package/dist/rowCoordinateCalculations.js +13 -39
- 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 +5 -4
- 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 +306 -124
- package/dist/types.d.ts +295 -3
- 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/util.d.ts +10 -4
- package/dist/util.js +37 -10
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wuss.d.ts +14 -0
- package/dist/wuss.js +55 -0
- package/dist/wuss.js.map +1 -0
- package/package.json +23 -14
- package/src/colorSchemes.ts +1 -2
- package/src/columnStats.ts +58 -0
- package/src/components/DragHandle.tsx +18 -7
- package/src/components/Loading.tsx +14 -8
- package/src/components/MSAView.tsx +19 -5
- package/src/components/MSAViewer.tsx +326 -10
- package/src/components/PortalTooltip.tsx +47 -0
- package/src/components/ResizeHandles.tsx +21 -36
- package/src/components/SequenceTextArea.tsx +3 -3
- package/src/components/Track.tsx +55 -18
- package/src/components/dialogs/AnnotationFileDialog.tsx +162 -0
- package/src/components/dialogs/ExportSVGDialog.tsx +7 -2
- package/src/components/dialogs/FeatureDialog.tsx +13 -9
- package/src/components/dialogs/TrackInfoDialog.tsx +1 -1
- package/src/components/header/GappynessSlider.tsx +6 -11
- package/src/components/header/Header.tsx +10 -0
- package/src/components/header/HeaderStatusArea.tsx +0 -5
- package/src/components/header/LoadWarnings.tsx +48 -0
- package/src/components/header/MultiAlignmentSelector.tsx +0 -0
- package/src/components/header/ScrollZoomIcons.tsx +52 -0
- package/src/components/header/TreeSettingsMenu.tsx +7 -1
- package/src/components/header/UnshareableDataWarning.tsx +56 -0
- package/src/components/header/ZoomControls.tsx +74 -14
- package/src/components/header/getAnnotationsMenu.ts +13 -17
- package/src/components/header/settingsMenuItems.ts +11 -6
- package/src/components/import/ImportForm.tsx +2 -2
- package/src/components/import/ImportFormExamples.tsx +4 -8
- package/src/components/import/util.ts +2 -0
- package/src/components/minimap/Minimap.tsx +1 -2
- package/src/components/msa/AnnotationLegend.tsx +48 -38
- package/src/components/msa/MSACanvas.tsx +3 -5
- package/src/components/msa/MSACanvasBlock.tsx +17 -21
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -1
- package/src/components/msa/domainBandCursor.ts +7 -11
- package/src/components/msa/drawFeatureSpans.ts +150 -0
- package/src/components/msa/legendRows.ts +24 -0
- package/src/components/msa/msaRaster.ts +236 -88
- package/src/components/msa/packDomainLanes.ts +36 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +69 -123
- package/src/components/msa/renderHighlights.ts +141 -10
- package/src/components/msa/renderMSABlock.ts +29 -38
- package/src/components/msa/renderMSAMouseover.ts +9 -39
- package/src/components/msa/tileColor.ts +4 -7
- package/src/components/msa/useMsaBlockMouse.ts +6 -6
- package/src/components/renderCtx.ts +1 -0
- 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 +13 -18
- package/src/components/tracks/TrackTooltipContent.tsx +156 -0
- package/src/components/tracks/drawTracks.ts +169 -38
- package/src/components/tracks/useTrackHover.ts +42 -0
- package/src/components/tree/CladeLabels.tsx +77 -0
- package/src/components/tree/TreeCanvas.tsx +4 -3
- package/src/components/tree/TreeCanvasBlock.tsx +10 -32
- package/src/components/tree/TreeOverview.tsx +106 -0
- package/src/components/tree/TreeRuler.tsx +29 -5
- package/src/components/tree/cladeBrackets.ts +73 -0
- package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +2 -2
- package/src/components/tree/renderTreeCanvas.ts +312 -48
- package/src/components/tree/renderTreeOverview.ts +212 -0
- package/src/components/tree/scaleBar.ts +23 -0
- package/src/components/tree/useTreeHover.ts +2 -4
- package/src/constants.ts +61 -8
- package/src/createPaletteMap.ts +10 -9
- package/src/element.ts +321 -0
- package/src/featureFields.ts +19 -0
- package/src/fetchUtils.ts +7 -40
- package/src/flatToTree.ts +1 -2
- package/src/ggplotPalettes.ts +60 -0
- package/src/hierarchy.ts +97 -20
- package/src/index.ts +46 -6
- package/src/model/DataModel.ts +5 -4
- package/src/model/msaModel.ts +3 -2
- package/src/model/treeModel.ts +42 -0
- package/src/model.ts +2492 -793
- package/src/mount.tsx +32 -0
- package/src/neighborJoining.ts +8 -32
- package/src/rawImports.d.ts +9 -0
- package/src/renderToStaticMarkup.ts +41 -25
- package/src/renderToSvg.tsx +365 -92
- package/src/rowCoordinateCalculations.ts +16 -62
- package/src/scales.ts +47 -0
- package/src/seqPosToGlobalCol.ts +5 -4
- package/src/sequenceLogo.ts +6 -11
- package/src/stripDefault.ts +7 -14
- package/src/types.ts +352 -12
- package/src/umd.ts +4 -2
- package/src/useCanvasAutorun.ts +5 -10
- package/src/useMsaSvgFigure.ts +72 -0
- package/src/util.ts +40 -14
- package/src/version.ts +1 -1
- package/src/wuss.ts +62 -0
- package/dist/components/dialogs/InterProScanDialog.js +0 -137
- package/dist/components/dialogs/InterProScanDialog.js.map +0 -1
- package/dist/components/dialogs/InterProScanFileDialog.d.ts +0 -7
- package/dist/components/dialogs/InterProScanFileDialog.js +0 -64
- package/dist/components/dialogs/InterProScanFileDialog.js.map +0 -1
- package/dist/components/msa/ColumnStats.js +0 -42
- package/dist/components/msa/ColumnStats.js.map +0 -1
- package/dist/launchInterProScan.d.ts +0 -13
- package/dist/launchInterProScan.js +0 -110
- package/dist/launchInterProScan.js.map +0 -1
- package/dist/useColorContrast.d.ts +0 -10
- package/dist/useColorContrast.js +0 -13
- package/dist/useColorContrast.js.map +0 -1
- package/src/clustalX.test.ts +0 -74
- package/src/colSpace.test.ts +0 -67
- package/src/collapseLogic.test.ts +0 -115
- package/src/colorSchemes.docs.test.ts +0 -57
- package/src/columnCounts.test.ts +0 -73
- package/src/columnStats.test.ts +0 -94
- package/src/columnTracks.test.ts +0 -97
- package/src/components/dialogs/InterProScanDialog.tsx +0 -214
- package/src/components/dialogs/InterProScanFileDialog.tsx +0 -138
- package/src/components/minimap/minimapLayout.test.ts +0 -71
- package/src/components/msa/ColumnStats.tsx +0 -54
- package/src/components/msa/msaRaster.test.ts +0 -145
- package/src/components/msa/renderBoxFeatureCanvasBlock.test.ts +0 -51
- package/src/components/tree/renderTreeCanvas.test.ts +0 -296
- package/src/dataInitialized.test.ts +0 -42
- package/src/domainBands.test.ts +0 -122
- package/src/domainLetterColor.test.ts +0 -80
- package/src/exportFileName.test.ts +0 -40
- package/src/fetchUtils.test.ts +0 -83
- package/src/flatToTree.test.ts +0 -51
- package/src/hierarchy.test.ts +0 -228
- package/src/highlights.test.ts +0 -70
- package/src/impgRender.test.tsx +0 -68
- package/src/largeTree.test.ts +0 -67
- package/src/launchInterProScan.ts +0 -167
- package/src/loadErrorDisplay.test.tsx +0 -102
- package/src/modelFilehandleLoaders.test.ts +0 -137
- package/src/modelReset.test.ts +0 -120
- package/src/neighborJoining.test.ts +0 -164
- package/src/parseAsn1.test.ts +0 -36
- package/src/propertyConservation.test.ts +0 -36
- package/src/renderColumnTracksSvg.test.tsx +0 -108
- package/src/renderDomainsSvg.test.tsx +0 -118
- package/src/renderHighlightsSvg.test.tsx +0 -85
- package/src/renderMinimapSvg.test.tsx +0 -62
- package/src/renderRasterSvg.test.tsx +0 -144
- package/src/renderSequenceLogoSvg.test.tsx +0 -165
- package/src/renderToSvg.test.tsx +0 -65
- package/src/reset.test.ts +0 -61
- package/src/rowCoordinateCalculations.test.ts +0 -211
- package/src/rowSpace.test.ts +0 -46
- package/src/segmentOverlay.test.ts +0 -70
- package/src/seqPosToGlobalCol.test.ts +0 -59
- package/src/sequenceLogo.test.ts +0 -88
- package/src/setFontSize.test.ts +0 -33
- package/src/stripDefault.test.ts +0 -48
- package/src/stripDefaultSnapshot.test.ts +0 -87
- package/src/treeMetadata.test.ts +0 -39
- package/src/useCanvasAutorun.test.tsx +0 -98
- package/src/useColorContrast.ts +0 -18
- package/src/viewChrome.test.tsx +0 -134
- package/src/wheelZoom.test.ts +0 -46
package/src/renderToSvg.tsx
CHANGED
|
@@ -5,16 +5,30 @@ import { when } from 'mobx'
|
|
|
5
5
|
|
|
6
6
|
import { visibleRowRange } from './components/getVisibleLeaves.ts'
|
|
7
7
|
import MinimapSVG from './components/minimap/MinimapSVG.tsx'
|
|
8
|
+
import { legendRows } from './components/msa/legendRows.ts'
|
|
8
9
|
import { rasterImageHref, rasterSupported } from './components/msa/msaRaster.ts'
|
|
9
10
|
import { renderBoxFeatureCanvasBlock } from './components/msa/renderBoxFeatureCanvasBlock.ts'
|
|
10
|
-
import {
|
|
11
|
+
import { renderPersistentHighlights } from './components/msa/renderHighlights.ts'
|
|
11
12
|
import { renderMSABlock } from './components/msa/renderMSABlock.ts'
|
|
12
13
|
import { visibleColRange } from './components/msa/visibleColRange.ts'
|
|
14
|
+
import { headerRunsAcross } from './components/rowpanels/headerLayout.ts'
|
|
15
|
+
import { renderRowPanels } from './components/rowpanels/renderRowPanel.ts'
|
|
13
16
|
import { renderAllTracks } from './components/tracks/drawTracks.ts'
|
|
17
|
+
import {
|
|
18
|
+
bracketGap,
|
|
19
|
+
cladeHeight,
|
|
20
|
+
cladeInGutter,
|
|
21
|
+
cladeLabelHorizontal,
|
|
22
|
+
cladeLabelOffset,
|
|
23
|
+
} from './components/tree/cladeBrackets.ts'
|
|
14
24
|
import { renderTreeCanvas } from './components/tree/renderTreeCanvas.ts'
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
25
|
+
import { renderTreeOverview } from './components/tree/renderTreeOverview.ts'
|
|
26
|
+
import { treeScaleBarHeight } from './constants.ts'
|
|
27
|
+
import { measureTextCanvas } from './measureTextCanvas.ts'
|
|
28
|
+
import { renderToStaticMarkup, svgSafeColors } from './renderToStaticMarkup.ts'
|
|
29
|
+
import { outlineColor } from './util.ts'
|
|
17
30
|
|
|
31
|
+
import type { LegendRow } from './components/msa/legendRows.ts'
|
|
18
32
|
import type { MsaViewModel } from './model.ts'
|
|
19
33
|
import type { Context as ContextType } from '@jbrowse/svgcanvas'
|
|
20
34
|
import type { Theme } from '@mui/material'
|
|
@@ -26,28 +40,29 @@ export interface ExportSvgOptions {
|
|
|
26
40
|
exportType: 'entire' | 'viewport'
|
|
27
41
|
}
|
|
28
42
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
43
|
+
// legend geometry, shared by the width calculation and the renderer so the
|
|
44
|
+
// reserved column on the right exactly fits the drawn legends
|
|
31
45
|
const LEGEND_PAD = 8
|
|
32
46
|
const LEGEND_ROW_H = 16
|
|
33
47
|
const LEGEND_SWATCH = 12
|
|
34
48
|
const LEGEND_FONT = 12
|
|
35
49
|
const LEGEND_CHAR_W = 7
|
|
36
50
|
|
|
51
|
+
// the width of a character as a fraction of the font size, close enough for a
|
|
52
|
+
// sans-serif average
|
|
53
|
+
const CHAR_WIDTH = 0.6
|
|
54
|
+
|
|
37
55
|
const LEGEND_MAX_W = 360
|
|
38
56
|
const LEGEND_TEXT_X = LEGEND_PAD + LEGEND_SWATCH + 6
|
|
39
57
|
|
|
40
|
-
function getLegendWidth(
|
|
41
|
-
const maxLen =
|
|
42
|
-
(a, d) => Math.max(a, d.name.length),
|
|
43
|
-
0,
|
|
44
|
-
)
|
|
58
|
+
function getLegendWidth(rows: LegendRow[]) {
|
|
59
|
+
const maxLen = rows.reduce((a, r) => Math.max(a, r.label.length), 0)
|
|
45
60
|
const w = LEGEND_TEXT_X + LEGEND_PAD + maxLen * LEGEND_CHAR_W
|
|
46
61
|
return Math.min(LEGEND_MAX_W, Math.max(120, w))
|
|
47
62
|
}
|
|
48
63
|
|
|
49
|
-
function legendHeight(
|
|
50
|
-
return LEGEND_PAD * 2 +
|
|
64
|
+
function legendHeight(rows: LegendRow[]) {
|
|
65
|
+
return LEGEND_PAD * 2 + rows.length * LEGEND_ROW_H
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
// resolved sizes/offsets (in svg user units) for the chosen export, shared by
|
|
@@ -59,6 +74,9 @@ interface Layout {
|
|
|
59
74
|
height: number
|
|
60
75
|
contentHeight: number
|
|
61
76
|
trackHeight: number
|
|
77
|
+
// the band the minimap, the row panel headers and the tree overview stacked
|
|
78
|
+
// on the scale bar share across the top
|
|
79
|
+
topHeight: number
|
|
62
80
|
offsetX: number
|
|
63
81
|
offsetY: number
|
|
64
82
|
includeMinimap: boolean
|
|
@@ -72,11 +90,15 @@ function getLayout(model: MsaViewModel, opts: ExportSvgOptions): Layout {
|
|
|
72
90
|
totalWidth,
|
|
73
91
|
totalHeight,
|
|
74
92
|
treeAreaWidth,
|
|
93
|
+
rowPanelsWidth,
|
|
94
|
+
rowPanelsHeaderHeight,
|
|
75
95
|
totalTrackAreaHeight,
|
|
76
96
|
minimapHeight,
|
|
77
97
|
msaAreaHeight,
|
|
78
98
|
msaCanvasWidth,
|
|
79
99
|
showHorizontalScrollbar,
|
|
100
|
+
treeOverviewHeight,
|
|
101
|
+
treeScaleBar,
|
|
80
102
|
} = model
|
|
81
103
|
const trackHeight = opts.includeTracks ? totalTrackAreaHeight : 0
|
|
82
104
|
// the minimap reflects the live viewport scroll position, so it's only
|
|
@@ -87,10 +109,14 @@ function getLayout(model: MsaViewModel, opts: ExportSvgOptions): Layout {
|
|
|
87
109
|
opts.exportType === 'viewport' &&
|
|
88
110
|
!!opts.includeMinimap &&
|
|
89
111
|
showHorizontalScrollbar
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
112
|
+
const rows = legendRows(model.legends)
|
|
113
|
+
const legendWidth = rows.length > 0 ? getLegendWidth(rows) : 0
|
|
114
|
+
const topHeight = Math.max(
|
|
115
|
+
includeMinimap ? minimapHeight : 0,
|
|
116
|
+
rowPanelsHeaderHeight,
|
|
117
|
+
treeOverviewHeight + (treeScaleBar ? treeScaleBarHeight : 0),
|
|
118
|
+
)
|
|
119
|
+
const gutterWidth = treeAreaWidth + rowPanelsWidth
|
|
94
120
|
|
|
95
121
|
// width stays content-only; the legend occupies an extra column added at the
|
|
96
122
|
// svg root in MsaSvg. The viewport export takes the alignment canvas's own
|
|
@@ -99,23 +125,24 @@ function getLayout(model: MsaViewModel, opts: ExportSvgOptions): Layout {
|
|
|
99
125
|
// columns the scrollbars hide on screen
|
|
100
126
|
return opts.exportType === 'entire'
|
|
101
127
|
? {
|
|
102
|
-
width: totalWidth +
|
|
128
|
+
width: totalWidth + gutterWidth,
|
|
103
129
|
msaAreaWidth: totalWidth,
|
|
104
|
-
height: totalHeight + trackHeight,
|
|
130
|
+
height: totalHeight + trackHeight + topHeight,
|
|
105
131
|
contentHeight: totalHeight,
|
|
106
132
|
trackHeight,
|
|
133
|
+
topHeight,
|
|
107
134
|
offsetX: 0,
|
|
108
135
|
offsetY: 0,
|
|
109
136
|
includeMinimap,
|
|
110
137
|
legendWidth,
|
|
111
138
|
}
|
|
112
139
|
: {
|
|
113
|
-
width: msaCanvasWidth +
|
|
140
|
+
width: msaCanvasWidth + gutterWidth,
|
|
114
141
|
msaAreaWidth: msaCanvasWidth,
|
|
115
|
-
height:
|
|
116
|
-
msaAreaHeight + (includeMinimap ? minimapHeight : 0) + trackHeight,
|
|
142
|
+
height: msaAreaHeight + topHeight + trackHeight,
|
|
117
143
|
contentHeight: msaAreaHeight,
|
|
118
144
|
trackHeight,
|
|
145
|
+
topHeight,
|
|
119
146
|
offsetX: -scrollX,
|
|
120
147
|
offsetY: -scrollY,
|
|
121
148
|
includeMinimap,
|
|
@@ -131,14 +158,26 @@ export async function renderToSvg(model: MsaViewModel, opts: ExportSvgOptions) {
|
|
|
131
158
|
throw model.error
|
|
132
159
|
}
|
|
133
160
|
const { Context } = await import('@jbrowse/svgcanvas')
|
|
134
|
-
|
|
161
|
+
// Each svgcanvas layer is already serialized SVG, and React would have to
|
|
162
|
+
// parse it into a second DOM only for the export to serialize it back out.
|
|
163
|
+
// The layers register themselves here instead, and their markup is spliced
|
|
164
|
+
// into the page as strings.
|
|
165
|
+
const layers = new Map<string, ContextType>()
|
|
166
|
+
const markup = renderToStaticMarkup(
|
|
135
167
|
<MsaSvg
|
|
136
168
|
model={model}
|
|
137
169
|
theme={opts.theme}
|
|
138
170
|
Context={Context}
|
|
139
171
|
layout={getLayout(model, opts)}
|
|
172
|
+
layers={layers}
|
|
140
173
|
/>,
|
|
141
174
|
)
|
|
175
|
+
return svgSafeColors(
|
|
176
|
+
markup.replaceAll(/<g data-layer="([^"]+)"><\/g>/g, (match, id: string) => {
|
|
177
|
+
const ctx = layers.get(id)
|
|
178
|
+
return ctx ? `<g id="${id}">${ctx.getSvg().innerHTML}</g>` : match
|
|
179
|
+
}),
|
|
180
|
+
)
|
|
142
181
|
}
|
|
143
182
|
|
|
144
183
|
function MsaSvg({
|
|
@@ -146,24 +185,28 @@ function MsaSvg({
|
|
|
146
185
|
theme,
|
|
147
186
|
Context,
|
|
148
187
|
layout,
|
|
188
|
+
layers,
|
|
149
189
|
}: {
|
|
150
190
|
model: MsaViewModel
|
|
151
191
|
theme: Theme
|
|
152
192
|
Context: typeof ContextType
|
|
153
193
|
layout: Layout
|
|
194
|
+
layers: LayerMap
|
|
154
195
|
}) {
|
|
155
|
-
const { width, trackHeight, includeMinimap, legendWidth } = layout
|
|
156
|
-
const { treeAreaWidth,
|
|
196
|
+
const { width, trackHeight, includeMinimap, legendWidth, topHeight } = layout
|
|
197
|
+
const { treeAreaWidth, rowPanelsWidth } = model
|
|
157
198
|
const totalWidth = width + legendWidth
|
|
158
|
-
const legendTop =
|
|
159
|
-
// a short alignment with many
|
|
199
|
+
const legendTop = topHeight
|
|
200
|
+
// a short alignment with many legend entries has a key taller than its rows,
|
|
160
201
|
// and the page has to hold the whole key
|
|
161
202
|
const height =
|
|
162
203
|
legendWidth > 0
|
|
163
|
-
? Math.max(
|
|
204
|
+
? Math.max(
|
|
205
|
+
layout.height,
|
|
206
|
+
legendTop + legendHeight(legendRows(model.legends)),
|
|
207
|
+
)
|
|
164
208
|
: layout.height
|
|
165
|
-
const
|
|
166
|
-
const props = { Context, model, theme, layout, contrastScheme }
|
|
209
|
+
const props = { Context, model, theme, layout, layers }
|
|
167
210
|
|
|
168
211
|
const body = (
|
|
169
212
|
<>
|
|
@@ -192,18 +235,37 @@ function MsaSvg({
|
|
|
192
235
|
height="100%"
|
|
193
236
|
fill={theme.palette.background.default}
|
|
194
237
|
/>
|
|
195
|
-
{
|
|
238
|
+
{topHeight > 0 ? (
|
|
196
239
|
<>
|
|
197
|
-
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
240
|
+
{includeMinimap ? (
|
|
241
|
+
<g
|
|
242
|
+
id="minimap-panel"
|
|
243
|
+
transform={`translate(${treeAreaWidth + rowPanelsWidth} 0)`}
|
|
244
|
+
>
|
|
245
|
+
<MinimapSVG model={model} theme={theme} />
|
|
246
|
+
</g>
|
|
247
|
+
) : null}
|
|
248
|
+
<RowPanelHeadersSVG
|
|
249
|
+
model={model}
|
|
250
|
+
theme={theme}
|
|
251
|
+
bandHeight={topHeight}
|
|
252
|
+
/>
|
|
253
|
+
{model.showTreeOverview ? (
|
|
254
|
+
<TreeOverviewSVG
|
|
255
|
+
model={model}
|
|
256
|
+
theme={theme}
|
|
257
|
+
Context={Context}
|
|
258
|
+
layers={layers}
|
|
259
|
+
/>
|
|
260
|
+
) : null}
|
|
261
|
+
<TreeScaleBarSVG model={model} theme={theme} />
|
|
262
|
+
<g transform={`translate(0 ${topHeight})`}>{body}</g>
|
|
201
263
|
</>
|
|
202
264
|
) : (
|
|
203
265
|
body
|
|
204
266
|
)}
|
|
205
267
|
{legendWidth > 0 ? (
|
|
206
|
-
<g transform={`translate(${width} ${legendTop})`}>
|
|
268
|
+
<g id="legend-panel" transform={`translate(${width} ${legendTop})`}>
|
|
207
269
|
<LegendSVG model={model} theme={theme} width={legendWidth} />
|
|
208
270
|
</g>
|
|
209
271
|
) : null}
|
|
@@ -211,8 +273,185 @@ function MsaSvg({
|
|
|
211
273
|
)
|
|
212
274
|
}
|
|
213
275
|
|
|
214
|
-
//
|
|
215
|
-
//
|
|
276
|
+
// The tree overview in the top band, over the tree column, where the live view
|
|
277
|
+
// puts it. It is part of the figure rather than chrome: the inset is what says
|
|
278
|
+
// where the focused clade sits in the whole tree.
|
|
279
|
+
function TreeOverviewSVG({
|
|
280
|
+
model,
|
|
281
|
+
theme,
|
|
282
|
+
Context,
|
|
283
|
+
layers,
|
|
284
|
+
}: {
|
|
285
|
+
model: MsaViewModel
|
|
286
|
+
theme: Theme
|
|
287
|
+
Context: typeof ContextType
|
|
288
|
+
layers: LayerMap
|
|
289
|
+
}) {
|
|
290
|
+
const { treeAreaWidth, overviewHeight, id } = model
|
|
291
|
+
const ctx = new Context(treeAreaWidth, overviewHeight)
|
|
292
|
+
renderTreeOverview({
|
|
293
|
+
model,
|
|
294
|
+
ctx,
|
|
295
|
+
theme,
|
|
296
|
+
width: treeAreaWidth,
|
|
297
|
+
height: overviewHeight,
|
|
298
|
+
})
|
|
299
|
+
return (
|
|
300
|
+
<ClipGroup
|
|
301
|
+
panelId="tree-overview"
|
|
302
|
+
clipId={`tree-overview-${id}`}
|
|
303
|
+
width={treeAreaWidth}
|
|
304
|
+
height={overviewHeight}
|
|
305
|
+
ctx={ctx}
|
|
306
|
+
layers={layers}
|
|
307
|
+
/>
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// The branch-length scale bar under the tree overview, where the live view puts
|
|
312
|
+
// it (see TreeRuler). A phylogram whose branch lengths are drawn to a scale
|
|
313
|
+
// nothing states is a figure a reader cannot measure, so the export carries the
|
|
314
|
+
// bar even though it is chrome on screen.
|
|
315
|
+
function TreeScaleBarSVG({
|
|
316
|
+
model,
|
|
317
|
+
theme,
|
|
318
|
+
}: {
|
|
319
|
+
model: MsaViewModel
|
|
320
|
+
theme: Theme
|
|
321
|
+
}) {
|
|
322
|
+
const { marginLeft, treeScaleBar: bar, treeOverviewHeight } = model
|
|
323
|
+
if (!bar) {
|
|
324
|
+
return null
|
|
325
|
+
}
|
|
326
|
+
const y = treeOverviewHeight + treeScaleBarHeight
|
|
327
|
+
const color = theme.palette.text.primary
|
|
328
|
+
return (
|
|
329
|
+
<g id="tree-scalebar">
|
|
330
|
+
<text x={marginLeft} y={y - 9} fontSize={10} fill={color}>
|
|
331
|
+
{bar.label}
|
|
332
|
+
</text>
|
|
333
|
+
<path
|
|
334
|
+
d={`M${marginLeft} ${y - 7} v6 h${bar.px} v-6`}
|
|
335
|
+
fill="none"
|
|
336
|
+
stroke={color}
|
|
337
|
+
/>
|
|
338
|
+
</g>
|
|
339
|
+
)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Each strip's header over the column it names, turned on its side, where the
|
|
343
|
+
// live view puts it (see RowPanelHeaders). The baseline runs up the figure, so
|
|
344
|
+
// the name sits to the left of it, the way TrackLabelsSVG offsets a horizontal
|
|
345
|
+
// baseline by a third of the font size.
|
|
346
|
+
function RowPanelHeadersSVG({
|
|
347
|
+
model,
|
|
348
|
+
theme,
|
|
349
|
+
bandHeight,
|
|
350
|
+
}: {
|
|
351
|
+
model: MsaViewModel
|
|
352
|
+
theme: Theme
|
|
353
|
+
bandHeight: number
|
|
354
|
+
}) {
|
|
355
|
+
const { resolvedRowPanels, treeAreaWidth, fontSize } = model
|
|
356
|
+
const y = bandHeight - 4
|
|
357
|
+
return resolvedRowPanels.length === 0 ? null : (
|
|
358
|
+
<g id="rowpanel-headers">
|
|
359
|
+
{resolvedRowPanels.map(panel => {
|
|
360
|
+
const across = headerRunsAcross(panel.width)
|
|
361
|
+
const size = across ? fontSize : Math.min(fontSize, panel.width)
|
|
362
|
+
const center = treeAreaWidth + panel.offsetX + panel.width / 2
|
|
363
|
+
const x = across ? center : center + size / 3
|
|
364
|
+
const room = across ? panel.width : y - LEGEND_PAD
|
|
365
|
+
const maxChars = Math.floor(room / (size * CHAR_WIDTH))
|
|
366
|
+
return size < 5 ? null : (
|
|
367
|
+
<text
|
|
368
|
+
key={panel.id}
|
|
369
|
+
x={x}
|
|
370
|
+
y={y}
|
|
371
|
+
{...(across
|
|
372
|
+
? { textAnchor: 'middle' }
|
|
373
|
+
: { transform: `rotate(-90 ${x} ${y})` })}
|
|
374
|
+
fontSize={size}
|
|
375
|
+
fill={theme.palette.text.primary}
|
|
376
|
+
>
|
|
377
|
+
{panel.header.length > maxChars
|
|
378
|
+
? `${panel.header.slice(0, Math.max(1, maxChars - 1))}…`
|
|
379
|
+
: panel.header}
|
|
380
|
+
</text>
|
|
381
|
+
)
|
|
382
|
+
})}
|
|
383
|
+
</g>
|
|
384
|
+
)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// A label past the room it has, cut to what fits with an ellipsis. The measure
|
|
388
|
+
// is the one cladeGutterWidth sizes the gutter with, so a label the gutter
|
|
389
|
+
// holds keeps every character.
|
|
390
|
+
function clipCladeLabel(label: string, room: number, fontSize: number) {
|
|
391
|
+
const width = measureTextCanvas(label, fontSize)
|
|
392
|
+
if (width <= room) {
|
|
393
|
+
return label
|
|
394
|
+
}
|
|
395
|
+
const fits = Math.floor((label.length * room) / width)
|
|
396
|
+
return `${label.slice(0, Math.max(1, fits - 1))}…`
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Each bracket's label in the gutter beside its bar, where the live view puts
|
|
400
|
+
// it (see CladeLabels). The canvas layer draws the bar; a label longer than the
|
|
401
|
+
// gutter or the clade is clipped, since text that overruns runs off the figure.
|
|
402
|
+
function CladeLabelsSVG({
|
|
403
|
+
model,
|
|
404
|
+
theme,
|
|
405
|
+
offsetY,
|
|
406
|
+
}: {
|
|
407
|
+
model: MsaViewModel
|
|
408
|
+
theme: Theme
|
|
409
|
+
offsetY: number
|
|
410
|
+
}) {
|
|
411
|
+
const {
|
|
412
|
+
resolvedClades,
|
|
413
|
+
cladeGutterWidth,
|
|
414
|
+
rowHeight,
|
|
415
|
+
treeAreaWidth,
|
|
416
|
+
fontSize,
|
|
417
|
+
} = model
|
|
418
|
+
if (cladeGutterWidth === 0) {
|
|
419
|
+
return null
|
|
420
|
+
}
|
|
421
|
+
const gutterLeft = treeAreaWidth - cladeGutterWidth
|
|
422
|
+
return (
|
|
423
|
+
<g id="clade-labels">
|
|
424
|
+
{resolvedClades.map((clade, index) => {
|
|
425
|
+
const { label, markColor, rows } = clade
|
|
426
|
+
if (!label || !cladeInGutter(clade)) {
|
|
427
|
+
return null
|
|
428
|
+
}
|
|
429
|
+
const left = gutterLeft + cladeLabelOffset(clade)
|
|
430
|
+
const top = rows[0] * rowHeight - offsetY
|
|
431
|
+
const height = cladeHeight(clade, rowHeight)
|
|
432
|
+
const horizontal = cladeLabelHorizontal(clade, rowHeight, fontSize)
|
|
433
|
+
const room = horizontal ? treeAreaWidth - left - bracketGap : height
|
|
434
|
+
const x = horizontal ? left : left + fontSize
|
|
435
|
+
const y = horizontal ? top + height / 2 + fontSize / 3 : top + height
|
|
436
|
+
return (
|
|
437
|
+
<text
|
|
438
|
+
key={`${rows[0]}-${rows[1]}-${index}`}
|
|
439
|
+
x={x}
|
|
440
|
+
y={y}
|
|
441
|
+
transform={horizontal ? undefined : `rotate(-90 ${x} ${y})`}
|
|
442
|
+
fontSize={fontSize}
|
|
443
|
+
fill={markColor ?? theme.palette.text.primary}
|
|
444
|
+
>
|
|
445
|
+
{clipCladeLabel(label, room, fontSize)}
|
|
446
|
+
</text>
|
|
447
|
+
)
|
|
448
|
+
})}
|
|
449
|
+
</g>
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// the color keys drawn as a reserved column to the right of the alignment,
|
|
454
|
+
// mirroring the on-screen AnnotationLegend overlay
|
|
216
455
|
function LegendSVG({
|
|
217
456
|
model,
|
|
218
457
|
theme,
|
|
@@ -222,8 +461,8 @@ function LegendSVG({
|
|
|
222
461
|
theme: Theme
|
|
223
462
|
width: number
|
|
224
463
|
}) {
|
|
225
|
-
const
|
|
226
|
-
const boxHeight = legendHeight(
|
|
464
|
+
const rows = legendRows(model.legends)
|
|
465
|
+
const boxHeight = legendHeight(rows)
|
|
227
466
|
// the column is capped at LEGEND_MAX_W, so a name too long for it has to be
|
|
228
467
|
// clipped here -- text that overruns the reserved width runs off the figure
|
|
229
468
|
const maxChars = Math.floor(
|
|
@@ -240,27 +479,30 @@ function LegendSVG({
|
|
|
240
479
|
stroke={theme.palette.divider}
|
|
241
480
|
rx={2}
|
|
242
481
|
/>
|
|
243
|
-
{
|
|
482
|
+
{rows.map((row, i) => {
|
|
244
483
|
const y = LEGEND_PAD + i * LEGEND_ROW_H
|
|
245
484
|
return (
|
|
246
|
-
<g key={
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
485
|
+
<g key={row.key}>
|
|
486
|
+
{row.color ? (
|
|
487
|
+
<rect
|
|
488
|
+
x={LEGEND_PAD}
|
|
489
|
+
y={y}
|
|
490
|
+
width={LEGEND_SWATCH}
|
|
491
|
+
height={LEGEND_SWATCH}
|
|
492
|
+
fill={row.color}
|
|
493
|
+
stroke={outlineColor(row.color)}
|
|
494
|
+
/>
|
|
495
|
+
) : null}
|
|
255
496
|
<text
|
|
256
|
-
x={LEGEND_TEXT_X}
|
|
497
|
+
x={row.color ? LEGEND_TEXT_X : LEGEND_PAD}
|
|
257
498
|
y={y + LEGEND_SWATCH - 1}
|
|
258
499
|
fontSize={LEGEND_FONT}
|
|
500
|
+
fontWeight={row.color ? undefined : 'bold'}
|
|
259
501
|
fill={theme.palette.text.primary}
|
|
260
502
|
>
|
|
261
|
-
{
|
|
262
|
-
? `${
|
|
263
|
-
:
|
|
503
|
+
{row.label.length > maxChars
|
|
504
|
+
? `${row.label.slice(0, Math.max(1, maxChars - 1))}…`
|
|
505
|
+
: row.label}
|
|
264
506
|
</text>
|
|
265
507
|
</g>
|
|
266
508
|
)
|
|
@@ -269,23 +511,19 @@ function LegendSVG({
|
|
|
269
511
|
)
|
|
270
512
|
}
|
|
271
513
|
|
|
514
|
+
type LayerMap = Map<string, ContextType>
|
|
515
|
+
|
|
272
516
|
interface LayerProps {
|
|
273
517
|
model: MsaViewModel
|
|
274
518
|
theme: Theme
|
|
275
519
|
layout: Layout
|
|
276
520
|
Context: typeof ContextType
|
|
277
|
-
|
|
521
|
+
layers: LayerMap
|
|
278
522
|
}
|
|
279
523
|
|
|
280
|
-
function CoreRendering({
|
|
281
|
-
model,
|
|
282
|
-
theme,
|
|
283
|
-
layout,
|
|
284
|
-
Context,
|
|
285
|
-
contrastScheme,
|
|
286
|
-
}: LayerProps) {
|
|
524
|
+
function CoreRendering({ model, theme, layout, Context, layers }: LayerProps) {
|
|
287
525
|
const { contentHeight, offsetX, offsetY, msaAreaWidth } = layout
|
|
288
|
-
const { treeAreaWidth, id } = model
|
|
526
|
+
const { treeAreaWidth, rowPanelsWidth, id } = model
|
|
289
527
|
|
|
290
528
|
const treeCtx = new Context(treeAreaWidth, contentHeight)
|
|
291
529
|
renderTreeCanvas({
|
|
@@ -297,11 +535,26 @@ function CoreRendering({
|
|
|
297
535
|
highResScaleFactorOverride: 1,
|
|
298
536
|
})
|
|
299
537
|
|
|
538
|
+
const rowPanelsCtx = rowPanelsWidth
|
|
539
|
+
? new Context(rowPanelsWidth, contentHeight)
|
|
540
|
+
: undefined
|
|
541
|
+
if (rowPanelsCtx) {
|
|
542
|
+
renderRowPanels({
|
|
543
|
+
model,
|
|
544
|
+
theme,
|
|
545
|
+
ctx: rowPanelsCtx,
|
|
546
|
+
offsetY,
|
|
547
|
+
blockSizeYOverride: contentHeight,
|
|
548
|
+
highResScaleFactorOverride: 1,
|
|
549
|
+
})
|
|
550
|
+
}
|
|
551
|
+
|
|
300
552
|
const raster = rasterBackground({ model, theme, layout })
|
|
301
553
|
|
|
302
554
|
const msaCtx = new Context(msaAreaWidth, contentHeight)
|
|
303
555
|
renderBoxFeatureCanvasBlock({
|
|
304
556
|
model,
|
|
557
|
+
theme,
|
|
305
558
|
ctx: msaCtx,
|
|
306
559
|
offsetX,
|
|
307
560
|
offsetY,
|
|
@@ -315,7 +568,6 @@ function CoreRendering({
|
|
|
315
568
|
model,
|
|
316
569
|
theme,
|
|
317
570
|
ctx: msaCtx,
|
|
318
|
-
contrastScheme,
|
|
319
571
|
offsetX,
|
|
320
572
|
offsetY,
|
|
321
573
|
blockSizeXOverride: msaAreaWidth,
|
|
@@ -324,7 +576,7 @@ function CoreRendering({
|
|
|
324
576
|
rasterTiles: !!raster,
|
|
325
577
|
})
|
|
326
578
|
msaCtx.resetTransform()
|
|
327
|
-
|
|
579
|
+
renderPersistentHighlights({
|
|
328
580
|
ctx: msaCtx,
|
|
329
581
|
model,
|
|
330
582
|
theme,
|
|
@@ -337,17 +589,33 @@ function CoreRendering({
|
|
|
337
589
|
return (
|
|
338
590
|
<>
|
|
339
591
|
<ClipGroup
|
|
592
|
+
panelId="tree-panel"
|
|
340
593
|
clipId={`tree-${id}`}
|
|
341
594
|
width={treeAreaWidth}
|
|
342
595
|
height={contentHeight}
|
|
343
596
|
ctx={treeCtx}
|
|
597
|
+
layers={layers}
|
|
344
598
|
/>
|
|
599
|
+
<CladeLabelsSVG model={model} theme={theme} offsetY={offsetY} />
|
|
600
|
+
{rowPanelsCtx ? (
|
|
601
|
+
<ClipGroup
|
|
602
|
+
panelId="rowpanels-panel"
|
|
603
|
+
clipId={`rowpanels-${id}`}
|
|
604
|
+
width={rowPanelsWidth}
|
|
605
|
+
height={contentHeight}
|
|
606
|
+
transform={`translate(${treeAreaWidth} 0)`}
|
|
607
|
+
ctx={rowPanelsCtx}
|
|
608
|
+
layers={layers}
|
|
609
|
+
/>
|
|
610
|
+
) : null}
|
|
345
611
|
<ClipGroup
|
|
612
|
+
panelId="msa-panel"
|
|
346
613
|
clipId={`msa-${id}`}
|
|
347
614
|
width={msaAreaWidth}
|
|
348
615
|
height={contentHeight}
|
|
349
|
-
transform={`translate(${treeAreaWidth} 0)`}
|
|
616
|
+
transform={`translate(${treeAreaWidth + rowPanelsWidth} 0)`}
|
|
350
617
|
ctx={msaCtx}
|
|
618
|
+
layers={layers}
|
|
351
619
|
underlay={raster}
|
|
352
620
|
/>
|
|
353
621
|
</>
|
|
@@ -355,15 +623,13 @@ function CoreRendering({
|
|
|
355
623
|
}
|
|
356
624
|
|
|
357
625
|
/**
|
|
358
|
-
* The alignment background as a single <image>,
|
|
359
|
-
*
|
|
360
|
-
*
|
|
626
|
+
* The alignment background as a single <image>, under the live canvas's
|
|
627
|
+
* conditions: no domain overlay boxes, background coloring on, and a canvas
|
|
628
|
+
* that reads back.
|
|
361
629
|
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
* image-rendering keeps those edges hard rather than smearing them, making it
|
|
366
|
-
* pixel-for-pixel what the rects drew.
|
|
630
|
+
* The vector path's <rect> per cell exhausts the heap on a real alignment. The
|
|
631
|
+
* image is one pixel per cell, and image-rendering keeps the upscaled cell
|
|
632
|
+
* edges hard, so it matches the rects pixel for pixel.
|
|
367
633
|
*/
|
|
368
634
|
function rasterBackground({
|
|
369
635
|
model,
|
|
@@ -412,21 +678,14 @@ function rasterBackground({
|
|
|
412
678
|
) : undefined
|
|
413
679
|
}
|
|
414
680
|
|
|
415
|
-
function TrackRendering({
|
|
416
|
-
model,
|
|
417
|
-
theme,
|
|
418
|
-
layout,
|
|
419
|
-
Context,
|
|
420
|
-
contrastScheme,
|
|
421
|
-
}: LayerProps) {
|
|
681
|
+
function TrackRendering({ model, theme, layout, Context, layers }: LayerProps) {
|
|
422
682
|
const { trackHeight, offsetX, msaAreaWidth } = layout
|
|
423
|
-
const { treeAreaWidth, id } = model
|
|
683
|
+
const { treeAreaWidth, rowPanelsWidth, id } = model
|
|
424
684
|
|
|
425
685
|
const ctx = new Context(msaAreaWidth, trackHeight)
|
|
426
686
|
renderAllTracks({
|
|
427
687
|
model,
|
|
428
688
|
ctx,
|
|
429
|
-
contrastScheme,
|
|
430
689
|
theme,
|
|
431
690
|
offsetX,
|
|
432
691
|
blockSizeXOverride: msaAreaWidth,
|
|
@@ -436,12 +695,14 @@ function TrackRendering({
|
|
|
436
695
|
return (
|
|
437
696
|
<>
|
|
438
697
|
<TrackLabelsSVG model={model} theme={theme} />
|
|
439
|
-
<g transform={`translate(${treeAreaWidth} 0)`}>
|
|
698
|
+
<g transform={`translate(${treeAreaWidth + rowPanelsWidth} 0)`}>
|
|
440
699
|
<ClipGroup
|
|
700
|
+
panelId="tracks-panel"
|
|
441
701
|
clipId={`tracks-${id}`}
|
|
442
702
|
width={msaAreaWidth}
|
|
443
703
|
height={trackHeight}
|
|
444
704
|
ctx={ctx}
|
|
705
|
+
layers={layers}
|
|
445
706
|
/>
|
|
446
707
|
</g>
|
|
447
708
|
</>
|
|
@@ -462,14 +723,17 @@ function TrackLabelsSVG({
|
|
|
462
723
|
if (!drawLabels) {
|
|
463
724
|
return null
|
|
464
725
|
}
|
|
465
|
-
|
|
726
|
+
const labels = turnedOnTracks.map((track, i) => {
|
|
727
|
+
const { id, name, height } = track.model
|
|
728
|
+
const size = Math.min(height, fontSize)
|
|
729
|
+
const top = turnedOnTracks
|
|
730
|
+
.slice(0, i)
|
|
731
|
+
.reduce((acc, t) => acc + t.model.height, 0)
|
|
732
|
+
return { id, name, size, baseline: top + height / 2 + size / 3 }
|
|
733
|
+
})
|
|
466
734
|
return (
|
|
467
735
|
<>
|
|
468
|
-
{
|
|
469
|
-
const { id, name, height } = track.model
|
|
470
|
-
const size = Math.min(height, fontSize)
|
|
471
|
-
const baseline = y + height / 2 + size / 3
|
|
472
|
-
y += height
|
|
736
|
+
{labels.map(({ id, name, size, baseline }) => {
|
|
473
737
|
return size < 5 ? null : (
|
|
474
738
|
<text
|
|
475
739
|
key={id}
|
|
@@ -487,24 +751,33 @@ function TrackLabelsSVG({
|
|
|
487
751
|
)
|
|
488
752
|
}
|
|
489
753
|
|
|
490
|
-
// Clips a svgcanvas Context to its box and
|
|
491
|
-
//
|
|
754
|
+
// Clips a svgcanvas Context to its box and leaves a placeholder for renderToSvg
|
|
755
|
+
// to splice the layer's own markup into. `underlay` draws beneath that markup,
|
|
492
756
|
// inside the same clip, for the parts of a layer React emits directly.
|
|
757
|
+
//
|
|
758
|
+
// `panelId` names the spliced group in the output, the same name in every
|
|
759
|
+
// export, so a figure can be taken apart in Illustrator or svgutils. `clipId`
|
|
760
|
+
// carries the model id, which keeps two viewers on one page from colliding.
|
|
493
761
|
function ClipGroup({
|
|
762
|
+
panelId,
|
|
494
763
|
clipId,
|
|
495
764
|
width,
|
|
496
765
|
height,
|
|
497
766
|
transform,
|
|
498
767
|
ctx,
|
|
768
|
+
layers,
|
|
499
769
|
underlay,
|
|
500
770
|
}: {
|
|
771
|
+
panelId: string
|
|
501
772
|
clipId: string
|
|
502
773
|
width: number
|
|
503
774
|
height: number
|
|
504
775
|
transform?: string
|
|
505
776
|
ctx: ContextType
|
|
777
|
+
layers: LayerMap
|
|
506
778
|
underlay?: React.ReactNode
|
|
507
779
|
}) {
|
|
780
|
+
layers.set(panelId, ctx)
|
|
508
781
|
return (
|
|
509
782
|
<>
|
|
510
783
|
<defs>
|
|
@@ -514,7 +787,7 @@ function ClipGroup({
|
|
|
514
787
|
</defs>
|
|
515
788
|
<g clipPath={`url(#${clipId})`} transform={transform}>
|
|
516
789
|
{underlay}
|
|
517
|
-
<g
|
|
790
|
+
<g data-layer={panelId} />
|
|
518
791
|
</g>
|
|
519
792
|
</>
|
|
520
793
|
)
|