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/flatToTree.test.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { flatToTree } from './flatToTree.ts'
|
|
4
|
-
|
|
5
|
-
describe('flatToTree', () => {
|
|
6
|
-
test('builds a tree from a flat parent list', () => {
|
|
7
|
-
const root = flatToTree([
|
|
8
|
-
{ id: 0 },
|
|
9
|
-
{ id: 1, parent: 0 },
|
|
10
|
-
{ id: 2, parent: 0 },
|
|
11
|
-
{ id: 3, parent: 1 },
|
|
12
|
-
])
|
|
13
|
-
expect(root.id).toBe('0')
|
|
14
|
-
expect(root.children.map(c => c.id)).toEqual(['1', '2'])
|
|
15
|
-
expect(root.children[0]!.children.map(c => c.id)).toEqual(['3'])
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
test('carries the label and branch length of a BioTreeContainer node', () => {
|
|
19
|
-
const root = flatToTree([
|
|
20
|
-
{ id: 0, label: 'Multiple organisms' },
|
|
21
|
-
{
|
|
22
|
-
id: 1,
|
|
23
|
-
parent: 0,
|
|
24
|
-
label: 'sodium/glucose cotransporter 4',
|
|
25
|
-
dist: '0.5',
|
|
26
|
-
},
|
|
27
|
-
{ id: 2, parent: 0 },
|
|
28
|
-
])
|
|
29
|
-
expect(root.name).toBe('Multiple organisms')
|
|
30
|
-
expect(root.children[0]).toMatchObject({
|
|
31
|
-
name: 'sodium/glucose cotransporter 4',
|
|
32
|
-
length: 0.5,
|
|
33
|
-
})
|
|
34
|
-
// no label falls back to the id, and no dist leaves the length unset
|
|
35
|
-
expect(root.children[1]!.name).toBe('2')
|
|
36
|
-
expect(root.children[1]!.length).toBeUndefined()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
test('throws on empty input rather than returning undefined', () => {
|
|
40
|
-
expect(() => flatToTree([])).toThrow(/no root/)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('throws when every node has a parent (cycle) rather than returning undefined', () => {
|
|
44
|
-
expect(() =>
|
|
45
|
-
flatToTree([
|
|
46
|
-
{ id: 0, parent: 1 },
|
|
47
|
-
{ id: 1, parent: 0 },
|
|
48
|
-
]),
|
|
49
|
-
).toThrow(/no root/)
|
|
50
|
-
})
|
|
51
|
-
})
|
package/src/hierarchy.test.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
calcDepthToLeaf,
|
|
5
|
-
collapse,
|
|
6
|
-
collapsedSubtreeMaxLength,
|
|
7
|
-
find,
|
|
8
|
-
findMaxBranchLen,
|
|
9
|
-
hierarchy,
|
|
10
|
-
leaves,
|
|
11
|
-
maxLength,
|
|
12
|
-
setBrLength,
|
|
13
|
-
sort,
|
|
14
|
-
sum,
|
|
15
|
-
} from './hierarchy.ts'
|
|
16
|
-
|
|
17
|
-
import type { NodeWithIds } from './types.ts'
|
|
18
|
-
|
|
19
|
-
// Builds a fully unbalanced "caterpillar" tree of the given depth: each internal
|
|
20
|
-
// node has one leaf child and one internal child. Recursion over this would blow
|
|
21
|
-
// the call stack; the iterative traversals must handle it.
|
|
22
|
-
function makeDeepTree(depth: number): NodeWithIds {
|
|
23
|
-
let node: NodeWithIds = { id: 'leaf0', name: 'leaf0', children: [] }
|
|
24
|
-
for (let i = 1; i <= depth; i++) {
|
|
25
|
-
node = {
|
|
26
|
-
id: `node${i}`,
|
|
27
|
-
name: `node${i}`,
|
|
28
|
-
length: 1,
|
|
29
|
-
children: [{ id: `leaf${i}`, name: `leaf${i}`, children: [] }, node],
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return node
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function makeTree(): NodeWithIds {
|
|
36
|
-
return {
|
|
37
|
-
id: 'root',
|
|
38
|
-
name: 'root',
|
|
39
|
-
children: [
|
|
40
|
-
{
|
|
41
|
-
id: 'A',
|
|
42
|
-
name: 'A',
|
|
43
|
-
children: [
|
|
44
|
-
{ id: 'A1', name: 'A1', children: [] },
|
|
45
|
-
{ id: 'A2', name: 'A2', children: [] },
|
|
46
|
-
],
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
id: 'B',
|
|
50
|
-
name: 'B',
|
|
51
|
-
children: [
|
|
52
|
-
{ id: 'B1', name: 'B1', children: [] },
|
|
53
|
-
{ id: 'B2', name: 'B2', children: [] },
|
|
54
|
-
],
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
describe('hierarchy', () => {
|
|
61
|
-
test('builds hierarchy from tree data', () => {
|
|
62
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
63
|
-
expect(h.data.id).toBe('root')
|
|
64
|
-
expect(h.children?.length).toBe(2)
|
|
65
|
-
expect(h.height).toBe(2)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('sets parent references', () => {
|
|
69
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
70
|
-
expect(h.parent).toBeNull()
|
|
71
|
-
expect(h.children![0]!.parent).toBe(h)
|
|
72
|
-
expect(h.children![0]!.children![0]!.parent).toBe(h.children![0])
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
describe('leaves', () => {
|
|
77
|
-
test('returns leaf nodes', () => {
|
|
78
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
79
|
-
const l = leaves(h)
|
|
80
|
-
expect(l.map(n => n.data.name)).toEqual(['A1', 'A2', 'B1', 'B2'])
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
describe('find', () => {
|
|
85
|
-
test('finds node by id', () => {
|
|
86
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
87
|
-
const node = find(h, n => n.data.id === 'B1')
|
|
88
|
-
expect(node?.data.name).toBe('B1')
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
test('returns undefined for missing id', () => {
|
|
92
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
93
|
-
expect(find(h, n => n.data.id === 'Z')).toBeUndefined()
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
describe('collapse', () => {
|
|
98
|
-
test('hides children of a branch node', () => {
|
|
99
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
100
|
-
const nodeA = find(h, n => n.data.id === 'A')!
|
|
101
|
-
collapse(nodeA)
|
|
102
|
-
expect(nodeA.children).toBeNull()
|
|
103
|
-
expect(nodeA._children?.length).toBe(2)
|
|
104
|
-
expect(leaves(h).map(n => n.data.name)).toEqual(['A', 'B1', 'B2'])
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
test('does nothing on a leaf node', () => {
|
|
108
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
109
|
-
const leaf = find(h, n => n.data.id === 'A1')!
|
|
110
|
-
collapse(leaf)
|
|
111
|
-
expect(leaves(h).map(n => n.data.name)).toEqual(['A1', 'A2', 'B1', 'B2'])
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
test('preserves the subtree depth so the layout stays stable', () => {
|
|
115
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
116
|
-
const nodeA = find(h, n => n.data.id === 'A')!
|
|
117
|
-
collapse(nodeA)
|
|
118
|
-
// the collapsed node keeps its real depth (1) rather than becoming a depth-0
|
|
119
|
-
// leaf, so the cladogram apex sits at the true branch point
|
|
120
|
-
expect(nodeA.depthToLeaf).toBe(1)
|
|
121
|
-
// and the root still measures the tree as 2 deep, so collapsing A does not
|
|
122
|
-
// horizontally shift the rest of the tree
|
|
123
|
-
expect(calcDepthToLeaf(h)).toBe(2)
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
describe('collapsedSubtreeMaxLength', () => {
|
|
128
|
-
// root → A(1) → [ A1(2), C(3) → [ C1(1), C2(10) ] ]
|
|
129
|
-
function makeLenTree(): NodeWithIds {
|
|
130
|
-
return {
|
|
131
|
-
id: 'root',
|
|
132
|
-
name: 'root',
|
|
133
|
-
children: [
|
|
134
|
-
{
|
|
135
|
-
id: 'A',
|
|
136
|
-
name: 'A',
|
|
137
|
-
length: 1,
|
|
138
|
-
children: [
|
|
139
|
-
{ id: 'A1', name: 'A1', length: 2, children: [] },
|
|
140
|
-
{
|
|
141
|
-
id: 'C',
|
|
142
|
-
name: 'C',
|
|
143
|
-
length: 3,
|
|
144
|
-
children: [
|
|
145
|
-
{ id: 'C1', name: 'C1', length: 1, children: [] },
|
|
146
|
-
{ id: 'C2', name: 'C2', length: 10, children: [] },
|
|
147
|
-
],
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
test('cumulative branch length to the farthest tip below a node', () => {
|
|
156
|
-
const h = hierarchy(makeLenTree(), d => d.children)
|
|
157
|
-
const nodeA = find(h, n => n.data.id === 'A')!
|
|
158
|
-
collapse(nodeA)
|
|
159
|
-
// excludes A's own branch: farthest tip C2 = 3 + 10 = 13, vs A1 = 2
|
|
160
|
-
expect(collapsedSubtreeMaxLength(nodeA)).toBe(13)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
test('returns zero for a node with no descendants', () => {
|
|
164
|
-
const h = hierarchy(makeLenTree(), d => d.children)
|
|
165
|
-
const leaf = find(h, n => n.data.id === 'A1')!
|
|
166
|
-
expect(collapsedSubtreeMaxLength(leaf)).toBe(0)
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
describe('leaf removal via parent.children filter', () => {
|
|
171
|
-
test('removing a leaf from its parent hides it from leaves()', () => {
|
|
172
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
173
|
-
const leaf = find(h, n => n.data.id === 'A1')!
|
|
174
|
-
leaf.parent!.children = leaf.parent!.children!.filter(
|
|
175
|
-
c => c.data.id !== 'A1',
|
|
176
|
-
)
|
|
177
|
-
expect(leaves(h).map(n => n.data.name)).toEqual(['A2', 'B1', 'B2'])
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
test('removing all leaves from a branch makes the branch a leaf', () => {
|
|
181
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
182
|
-
const nodeA = find(h, n => n.data.id === 'A')!
|
|
183
|
-
nodeA.children = []
|
|
184
|
-
expect(leaves(h).map(n => n.data.name)).toEqual(['B1', 'B2'])
|
|
185
|
-
})
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
describe('sort', () => {
|
|
189
|
-
test('sorts children', () => {
|
|
190
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
191
|
-
sort(h, (a, b) => b.data.name.localeCompare(a.data.name))
|
|
192
|
-
expect(h.children!.map(c => c.data.name)).toEqual(['B', 'A'])
|
|
193
|
-
})
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
describe('sum', () => {
|
|
197
|
-
test('computes leaf counts', () => {
|
|
198
|
-
const h = hierarchy(makeTree(), d => d.children)
|
|
199
|
-
sum(h, d => (d.children.length > 0 ? 0 : 1))
|
|
200
|
-
expect(h.value).toBe(4)
|
|
201
|
-
expect(find(h, n => n.data.id === 'A')?.value).toBe(2)
|
|
202
|
-
})
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
describe('deep (caterpillar) trees do not overflow the stack', () => {
|
|
206
|
-
const depth = 100_000
|
|
207
|
-
|
|
208
|
-
test('build, height, leaf count, and ordering', () => {
|
|
209
|
-
const h = hierarchy(makeDeepTree(depth), d => d.children)
|
|
210
|
-
expect(h.height).toBe(depth)
|
|
211
|
-
const l = leaves(h)
|
|
212
|
-
expect(l.length).toBe(depth + 1)
|
|
213
|
-
// each level contributes its own leafN before descending; deepest leaf last
|
|
214
|
-
expect(l[0]!.data.name).toBe(`leaf${depth}`)
|
|
215
|
-
expect(l.at(-1)!.data.name).toBe('leaf0')
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
test('accumulation helpers (sum, find, maxLength, setBrLength, depth)', () => {
|
|
219
|
-
const h = hierarchy(makeDeepTree(depth), d => d.children)
|
|
220
|
-
sum(h, d => (d.children.length > 0 ? 0 : 1))
|
|
221
|
-
expect(h.value).toBe(depth + 1)
|
|
222
|
-
expect(find(h, n => n.data.id === 'leaf0')?.data.name).toBe('leaf0')
|
|
223
|
-
expect(maxLength(h)).toBe(depth)
|
|
224
|
-
expect(calcDepthToLeaf(h)).toBe(depth)
|
|
225
|
-
setBrLength(h, 0, 1)
|
|
226
|
-
expect(findMaxBranchLen(h)).toBe(depth)
|
|
227
|
-
})
|
|
228
|
-
})
|
package/src/highlights.test.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { expect, test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import MSAModelF from './model.ts'
|
|
5
|
-
|
|
6
|
-
// seq2 skips columns 3-4 of the alignment, so its residue 3 sits at global
|
|
7
|
-
// column 5 (1-based). The all-gap column 4 is what hideGaps removes.
|
|
8
|
-
const msa = `>seq1
|
|
9
|
-
AC-DEFG
|
|
10
|
-
>seq2
|
|
11
|
-
AC--EFG
|
|
12
|
-
>seq3
|
|
13
|
-
AC-DEFG`
|
|
14
|
-
|
|
15
|
-
function makeModel(highlights: Record<string, unknown>[]) {
|
|
16
|
-
const model = MSAModelF().create({
|
|
17
|
-
id: 'highlights-test',
|
|
18
|
-
type: 'MsaView',
|
|
19
|
-
msaFormat: 'fasta',
|
|
20
|
-
data: { msa },
|
|
21
|
-
highlights,
|
|
22
|
-
})
|
|
23
|
-
model.setWidth(800)
|
|
24
|
-
return model
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
test('a column span is 1-based and lands on 0-based visible columns', () => {
|
|
28
|
-
const model = makeModel([{ start: 2, end: 4, label: 'x' }])
|
|
29
|
-
expect(model.resolvedHighlights).toEqual([
|
|
30
|
-
{ startCol: 1, endCol: 3, rowIndices: [], label: 'x', color: undefined },
|
|
31
|
-
])
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test('a residue span projects through the named row', () => {
|
|
35
|
-
const model = makeModel([{ row: 'seq2', start: 3, end: 4 }])
|
|
36
|
-
expect(model.resolvedHighlights[0]).toMatchObject({ startCol: 4, endCol: 5 })
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
test('hidden columns shift a span and drop one they swallow whole', () => {
|
|
40
|
-
const model = makeModel([
|
|
41
|
-
{ start: 5, end: 6, label: 'after' },
|
|
42
|
-
{ start: 3, end: 3, label: 'gone' },
|
|
43
|
-
{ row: 'seq2', start: 2, end: 3, label: 'across' },
|
|
44
|
-
])
|
|
45
|
-
model.setHideGaps(true)
|
|
46
|
-
model.setAllowedGappyness(50)
|
|
47
|
-
expect(model.blanks).toEqual([2])
|
|
48
|
-
expect(
|
|
49
|
-
model.resolvedHighlights.map(h => [h.label, h.startCol, h.endCol]),
|
|
50
|
-
).toEqual([
|
|
51
|
-
['after', 3, 4],
|
|
52
|
-
['across', 1, 3],
|
|
53
|
-
])
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
test('a row set resolves to row indices and ignores unknown names', () => {
|
|
57
|
-
const model = makeModel([{ rows: ['seq3', 'nope', 'seq1'], color: 'red' }])
|
|
58
|
-
expect(model.resolvedHighlights).toEqual([
|
|
59
|
-
{ rowIndices: [2, 0], label: undefined, color: 'red' },
|
|
60
|
-
])
|
|
61
|
-
expect(makeModel([{ rows: ['nope'] }]).resolvedHighlights).toEqual([])
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test('setHighlights replaces the list and reset clears it', () => {
|
|
65
|
-
const model = makeModel([])
|
|
66
|
-
model.setHighlights([{ start: 1, end: 1 }])
|
|
67
|
-
expect(model.highlights).toHaveLength(1)
|
|
68
|
-
model.reset()
|
|
69
|
-
expect(model.highlights).toHaveLength(0)
|
|
70
|
-
})
|
package/src/impgRender.test.tsx
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
//
|
|
3
|
-
// End-to-end check of the impg (https://github.com/pangenome/impg) integration:
|
|
4
|
-
// impg's scripts/faln2html.py drives the viewer exactly as below --
|
|
5
|
-
// MSAModelF().create({ type:'MsaView', data:{ msa } })
|
|
6
|
-
// model.setColorSchemeName('percent_identity_dynamic')
|
|
7
|
-
// model.setBgColor(true); model.setWidth(1300)
|
|
8
|
-
// then renders <MSAView model/>. This exercises that path headlessly via the
|
|
9
|
-
// public renderToSvg export. Polyfills mirror scripts/generateFigures.tsx.
|
|
10
|
-
import { createJBrowseTheme } from '@jbrowse/core/ui/theme'
|
|
11
|
-
import { beforeAll, expect, test } from 'vitest'
|
|
12
|
-
|
|
13
|
-
import MSAModelF from './model.ts'
|
|
14
|
-
import { renderToSvg } from './renderToSvg.tsx'
|
|
15
|
-
import { installSvgTestEnv } from './svgTestUtil.ts'
|
|
16
|
-
|
|
17
|
-
beforeAll(() => {
|
|
18
|
-
installSvgTestEnv()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
// representative `impg query -o fasta-aln` block: PanSN names with region
|
|
22
|
-
// colons, dash gaps, mixed-case (soft-masked) bases
|
|
23
|
-
const impgFastaAln = `>HG002#1#chr1:1000-1040
|
|
24
|
-
ACGTACGT--ACGTNNNNacgtACGTACGTACGTACGT
|
|
25
|
-
>HG003#1#chr1:1000-1040
|
|
26
|
-
ACGTAC-TGGACGTNNNNACGTAC--ACGTacgtACGT
|
|
27
|
-
>CHM13#0#chr1:1000-1040
|
|
28
|
-
ACGTACGTGGACGTNNNNACGT----ACGTACGTACGT`
|
|
29
|
-
|
|
30
|
-
test('renders an impg fasta-aln block with declarative impg config', async () => {
|
|
31
|
-
// everything except width is a declarative MST property, so it can be set in
|
|
32
|
-
// the create() snapshot -- no setColorSchemeName/setBgColor/setMSAFormat
|
|
33
|
-
// action calls needed. msaFormat:'fasta' forces the parser and skips the
|
|
34
|
-
// heuristic fasta-vs-a3m sniffing. width is volatile (tracks container size)
|
|
35
|
-
// so it remains an action.
|
|
36
|
-
const model = MSAModelF().create({
|
|
37
|
-
id: 'impg-test',
|
|
38
|
-
type: 'MsaView',
|
|
39
|
-
height: 400,
|
|
40
|
-
colorSchemeName: 'percent_identity_dynamic',
|
|
41
|
-
bgColor: true,
|
|
42
|
-
msaFormat: 'fasta',
|
|
43
|
-
data: { msa: impgFastaAln },
|
|
44
|
-
})
|
|
45
|
-
model.setWidth(1300)
|
|
46
|
-
|
|
47
|
-
// the declarative config took effect
|
|
48
|
-
expect(model.colorSchemeName).toBe('percent_identity_dynamic')
|
|
49
|
-
expect(model.bgColor).toBe(true)
|
|
50
|
-
expect(model.msaFormat).toBe('fasta')
|
|
51
|
-
|
|
52
|
-
// the alignment parsed and all 3 rows are present at equal width
|
|
53
|
-
expect(model.rowNames).toEqual([
|
|
54
|
-
'HG002#1#chr1:1000-1040',
|
|
55
|
-
'HG003#1#chr1:1000-1040',
|
|
56
|
-
'CHM13#0#chr1:1000-1040',
|
|
57
|
-
])
|
|
58
|
-
expect(model.numColumns).toBe(38)
|
|
59
|
-
|
|
60
|
-
const svg = await renderToSvg(model, {
|
|
61
|
-
theme: createJBrowseTheme(),
|
|
62
|
-
exportType: 'entire',
|
|
63
|
-
includeMinimap: false,
|
|
64
|
-
includeTracks: false,
|
|
65
|
-
})
|
|
66
|
-
expect(svg).toContain('<svg')
|
|
67
|
-
expect(svg).toContain('HG002#1#chr1:1000-1040')
|
|
68
|
-
})
|
package/src/largeTree.test.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { expect, test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import MSAModelF from './model.ts'
|
|
5
|
-
|
|
6
|
-
// jsdom has no 2d context, so measureTextCanvas falls back to an estimate. Only
|
|
7
|
-
// the width matters here, so a stub keeps the test about tree size.
|
|
8
|
-
HTMLCanvasElement.prototype.getContext = (() => ({
|
|
9
|
-
font: '12px sans-serif',
|
|
10
|
-
measureText: (t: string) => ({ width: t.length * 7 }),
|
|
11
|
-
})) as unknown as typeof HTMLCanvasElement.prototype.getContext
|
|
12
|
-
|
|
13
|
-
// The import form ships a "230k COVID-19 samples (tree only)" example, so a tree
|
|
14
|
-
// this size is a supported input rather than a hypothetical. Every leaf gets a
|
|
15
|
-
// measured label, and anything that then reduces over them per row has to do it
|
|
16
|
-
// without passing one argument per row.
|
|
17
|
-
function flatNewick(n: number) {
|
|
18
|
-
return `(${Array.from({ length: n }, (_, i) => `s${i}:0.1`).join(',')});`
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
test('a tree far past the argument limit still lays out', () => {
|
|
22
|
-
const model = MSAModelF().create({
|
|
23
|
-
type: 'MsaView',
|
|
24
|
-
data: { tree: flatNewick(200_000) },
|
|
25
|
-
})
|
|
26
|
-
model.setWidth(1000)
|
|
27
|
-
|
|
28
|
-
expect(model.numRows).toBe(200_000)
|
|
29
|
-
// 's199999' is the longest name, at 7 chars * 7px, scaled from the reference
|
|
30
|
-
// font size the labels are measured at down to the current one (13/16)
|
|
31
|
-
expect(model.labelsWidth).toBeCloseTo((49 * 13) / 16)
|
|
32
|
-
expect(model.treeWidth).toBeGreaterThan(0)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('re-hovering the same tree node does not re-walk the tree', () => {
|
|
36
|
-
const model = MSAModelF().create({
|
|
37
|
-
type: 'MsaView',
|
|
38
|
-
data: { tree: flatNewick(200_000) },
|
|
39
|
-
})
|
|
40
|
-
model.setWidth(1000)
|
|
41
|
-
|
|
42
|
-
const leafId = model.leaves[1000]!.data.id
|
|
43
|
-
model.setHoveredTreeNode(leafId)
|
|
44
|
-
const first = model.hoveredTreeNode
|
|
45
|
-
|
|
46
|
-
// the tree's mousemove handler fires this on every event, so an unchanged id
|
|
47
|
-
// has to leave the state object alone: rebuilding it walks all 200k nodes and
|
|
48
|
-
// invalidates every overlay that reads hoveredRowIndices
|
|
49
|
-
model.setHoveredTreeNode(leafId)
|
|
50
|
-
expect(model.hoveredTreeNode).toBe(first)
|
|
51
|
-
|
|
52
|
-
model.setHoveredTreeNode(undefined)
|
|
53
|
-
expect(model.hoveredTreeNode).toBeUndefined()
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
test('a vertical zoom does not re-measure every label', () => {
|
|
57
|
-
const model = MSAModelF().create({
|
|
58
|
-
type: 'MsaView',
|
|
59
|
-
data: { tree: flatNewick(200_000) },
|
|
60
|
-
})
|
|
61
|
-
model.setWidth(1000)
|
|
62
|
-
|
|
63
|
-
const before = model.labelWidthMap
|
|
64
|
-
model.setRowHeight(24)
|
|
65
|
-
expect(model.labelWidthMap).toBe(before)
|
|
66
|
-
expect(model.labelsWidth).toBeCloseTo((49 * 18) / 16)
|
|
67
|
-
})
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { getSession } from '@jbrowse/core/util'
|
|
2
|
-
import { interProScanResponseToAnnotations } from 'msa-parsers'
|
|
3
|
-
|
|
4
|
-
import { isAbortError, jsonfetch, textfetch, timeout } from './fetchUtils.ts'
|
|
5
|
-
|
|
6
|
-
import type { MsaViewModel } from './model.ts'
|
|
7
|
-
import type { InterProScanResponse } from 'msa-parsers'
|
|
8
|
-
|
|
9
|
-
const base = 'https://www.ebi.ac.uk/Tools/services/rest'
|
|
10
|
-
|
|
11
|
-
async function runInterProScan({
|
|
12
|
-
seq,
|
|
13
|
-
onProgress,
|
|
14
|
-
onJobId,
|
|
15
|
-
programs,
|
|
16
|
-
model,
|
|
17
|
-
signal,
|
|
18
|
-
}: {
|
|
19
|
-
seq: string
|
|
20
|
-
programs: string[]
|
|
21
|
-
onProgress: (arg?: { msg: string; url?: string }) => void
|
|
22
|
-
onJobId?: (arg: string) => void
|
|
23
|
-
model: MsaViewModel
|
|
24
|
-
signal?: AbortSignal
|
|
25
|
-
}) {
|
|
26
|
-
const jobId = await textfetch(`${base}/iprscan5/run`, {
|
|
27
|
-
method: 'POST',
|
|
28
|
-
body: new URLSearchParams({
|
|
29
|
-
email: 'colin.diesh@gmail.com',
|
|
30
|
-
sequence: seq,
|
|
31
|
-
programs: programs.join(','),
|
|
32
|
-
}),
|
|
33
|
-
signal,
|
|
34
|
-
})
|
|
35
|
-
onJobId?.(jobId)
|
|
36
|
-
await wait({
|
|
37
|
-
jobId,
|
|
38
|
-
onProgress,
|
|
39
|
-
signal,
|
|
40
|
-
})
|
|
41
|
-
await loadInterProScanResultsWithStatus({ jobId, model, onProgress, signal })
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function loadInterProScanResults(jobId: string, signal?: AbortSignal) {
|
|
45
|
-
return jsonfetch<InterProScanResponse>(
|
|
46
|
-
`${base}/iprscan5/result/${jobId}/json`,
|
|
47
|
-
{ signal },
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async function wait({
|
|
52
|
-
onProgress,
|
|
53
|
-
jobId,
|
|
54
|
-
signal,
|
|
55
|
-
}: {
|
|
56
|
-
jobId: string
|
|
57
|
-
onProgress: (arg?: { msg: string; url?: string }) => void
|
|
58
|
-
signal?: AbortSignal
|
|
59
|
-
}) {
|
|
60
|
-
const url = `${base}/iprscan5/status/${jobId}`
|
|
61
|
-
// EBI jobs run for minutes; cap polling so an unexpected/stuck status can't
|
|
62
|
-
// spin forever (the abort signal is the normal early exit). ~10s per check.
|
|
63
|
-
const maxChecks = 360
|
|
64
|
-
try {
|
|
65
|
-
let finished = false
|
|
66
|
-
for (let check = 0; check < maxChecks && !finished; check++) {
|
|
67
|
-
for (let i = 0; i < 10; i++) {
|
|
68
|
-
await timeout(1000, signal)
|
|
69
|
-
onProgress({ msg: `Checking status ${10 - i}`, url })
|
|
70
|
-
}
|
|
71
|
-
// status endpoint returns a bare status token; match exactly rather than
|
|
72
|
-
// substring so an error page mentioning "FINISHED" can't be a false hit
|
|
73
|
-
const status = (await textfetch(url, { signal })).trim()
|
|
74
|
-
if (status === 'FINISHED') {
|
|
75
|
-
finished = true
|
|
76
|
-
} else if (
|
|
77
|
-
status === 'FAILURE' ||
|
|
78
|
-
status === 'ERROR' ||
|
|
79
|
-
status === 'NOT_FOUND'
|
|
80
|
-
) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
`InterProScan job ${jobId} ended with status: ${status}`,
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (!finished) {
|
|
87
|
-
throw new Error(
|
|
88
|
-
`InterProScan job ${jobId} did not finish after ${maxChecks} status checks`,
|
|
89
|
-
)
|
|
90
|
-
}
|
|
91
|
-
} finally {
|
|
92
|
-
onProgress()
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export async function launchInterProScan({
|
|
97
|
-
algorithm,
|
|
98
|
-
seq,
|
|
99
|
-
programs,
|
|
100
|
-
onJobId,
|
|
101
|
-
onProgress,
|
|
102
|
-
model,
|
|
103
|
-
signal,
|
|
104
|
-
}: {
|
|
105
|
-
algorithm: string
|
|
106
|
-
seq: string
|
|
107
|
-
programs: string[]
|
|
108
|
-
onProgress: (arg?: { msg: string; url?: string }) => void
|
|
109
|
-
onJobId?: (arg: string) => void
|
|
110
|
-
model: MsaViewModel
|
|
111
|
-
signal?: AbortSignal
|
|
112
|
-
}) {
|
|
113
|
-
try {
|
|
114
|
-
onProgress({ msg: `Launching ${algorithm} MSA` })
|
|
115
|
-
if (algorithm === 'interproscan') {
|
|
116
|
-
await runInterProScan({
|
|
117
|
-
seq,
|
|
118
|
-
onJobId,
|
|
119
|
-
onProgress,
|
|
120
|
-
programs,
|
|
121
|
-
model,
|
|
122
|
-
signal,
|
|
123
|
-
})
|
|
124
|
-
} else {
|
|
125
|
-
throw new Error('unknown algorithm')
|
|
126
|
-
}
|
|
127
|
-
} catch (e) {
|
|
128
|
-
if (isAbortError(e)) {
|
|
129
|
-
getSession(model).notify('Cancelled InterProScan query', 'info')
|
|
130
|
-
} else {
|
|
131
|
-
throw e
|
|
132
|
-
}
|
|
133
|
-
} finally {
|
|
134
|
-
onProgress()
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function loadInterProScanResultsWithStatus({
|
|
139
|
-
jobId,
|
|
140
|
-
model,
|
|
141
|
-
onProgress,
|
|
142
|
-
signal,
|
|
143
|
-
}: {
|
|
144
|
-
jobId: string
|
|
145
|
-
model: MsaViewModel
|
|
146
|
-
onProgress: (arg?: { msg: string; url?: string }) => void
|
|
147
|
-
signal?: AbortSignal
|
|
148
|
-
}) {
|
|
149
|
-
try {
|
|
150
|
-
onProgress({
|
|
151
|
-
msg: `Downloading results of ${jobId} (for larger sequences this can be slow, click status to download and upload in the manual tab)`,
|
|
152
|
-
url: `https://www.ebi.ac.uk/Tools/services/rest/iprscan5/result/${jobId}/json`,
|
|
153
|
-
})
|
|
154
|
-
const ret = await loadInterProScanResults(jobId, signal)
|
|
155
|
-
model.setAnnotations(interProScanResponseToAnnotations(ret))
|
|
156
|
-
getSession(model).notify(`Loaded interproscan ${jobId} results`, 'success')
|
|
157
|
-
} catch (e) {
|
|
158
|
-
if (isAbortError(e)) {
|
|
159
|
-
getSession(model).notify('Cancelled InterProScan query', 'info')
|
|
160
|
-
} else {
|
|
161
|
-
console.error(e)
|
|
162
|
-
getSession(model).notifyError(`${e}`, e)
|
|
163
|
-
}
|
|
164
|
-
} finally {
|
|
165
|
-
onProgress()
|
|
166
|
-
}
|
|
167
|
-
}
|