react-msaview 7.0.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 +11 -10
- package/bundle/index.js +122 -111
- 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.map +1 -1
- package/dist/components/MSAView.js +17 -6
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +64 -7
- package/dist/components/MSAViewer.js +128 -23
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/PortalTooltip.d.ts +11 -0
- package/dist/components/PortalTooltip.js +29 -0
- package/dist/components/PortalTooltip.js.map +1 -0
- package/dist/components/ResizeHandles.js +11 -29
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/SequenceTextArea.js +3 -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/ExportSVGDialog.js +5 -3
- package/dist/components/dialogs/ExportSVGDialog.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 +3 -0
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/LoadWarnings.js +3 -4
- package/dist/components/header/LoadWarnings.js.map +1 -1
- package/dist/components/header/ScrollZoomIcons.d.ts +6 -0
- package/dist/components/header/ScrollZoomIcons.js +35 -0
- package/dist/components/header/ScrollZoomIcons.js.map +1 -0
- package/dist/components/header/TreeSettingsMenu.js +1 -3
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/UnshareableDataWarning.js +2 -4
- package/dist/components/header/UnshareableDataWarning.js.map +1 -1
- package/dist/components/header/ZoomControls.js +49 -6
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/header/getAnnotationsMenu.js +3 -6
- package/dist/components/header/getAnnotationsMenu.js.map +1 -1
- package/dist/components/header/settingsMenuItems.js +10 -7
- package/dist/components/header/settingsMenuItems.js.map +1 -1
- package/dist/components/import/util.js +1 -2
- package/dist/components/import/util.js.map +1 -1
- package/dist/components/minimap/Minimap.js +1 -2
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/msa/AnnotationLegend.js +27 -19
- package/dist/components/msa/AnnotationLegend.js.map +1 -1
- package/dist/components/msa/MSACanvas.js +1 -1
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +13 -15
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js +2 -1
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/domainBandCursor.d.ts +7 -11
- package/dist/components/msa/domainBandCursor.js +7 -11
- package/dist/components/msa/domainBandCursor.js.map +1 -1
- package/dist/components/msa/drawFeatureSpans.d.ts +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 +24 -31
- package/dist/components/msa/msaRaster.js +30 -39
- package/dist/components/msa/msaRaster.js.map +1 -1
- package/dist/components/msa/packDomainLanes.d.ts +20 -0
- package/dist/components/msa/packDomainLanes.js +33 -0
- package/dist/components/msa/packDomainLanes.js.map +1 -0
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +3 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +51 -87
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderHighlights.d.ts +15 -13
- package/dist/components/msa/renderHighlights.js +43 -20
- package/dist/components/msa/renderHighlights.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +5 -4
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/tileColor.js +4 -7
- package/dist/components/msa/tileColor.js.map +1 -1
- package/dist/components/msa/useMsaBlockMouse.d.ts +5 -3
- package/dist/components/msa/useMsaBlockMouse.js +6 -6
- package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
- package/dist/components/rowpanels/RowPanelBlock.d.ts +9 -0
- package/dist/components/rowpanels/RowPanelBlock.js +86 -0
- package/dist/components/rowpanels/RowPanelBlock.js.map +1 -0
- package/dist/components/rowpanels/RowPanelHeaders.d.ts +12 -0
- package/dist/components/rowpanels/RowPanelHeaders.js +38 -0
- package/dist/components/rowpanels/RowPanelHeaders.js.map +1 -0
- package/dist/components/{msa/ColumnStats.d.ts → rowpanels/RowPanels.d.ts} +2 -2
- package/dist/components/rowpanels/RowPanels.js +32 -0
- package/dist/components/rowpanels/RowPanels.js.map +1 -0
- package/dist/components/rowpanels/headerLayout.d.ts +1 -0
- package/dist/components/rowpanels/headerLayout.js +5 -0
- package/dist/components/rowpanels/headerLayout.js.map +1 -0
- package/dist/components/rowpanels/renderFeaturePanel.d.ts +21 -0
- package/dist/components/rowpanels/renderFeaturePanel.js +37 -0
- package/dist/components/rowpanels/renderFeaturePanel.js.map +1 -0
- package/dist/components/rowpanels/renderRowPanel.d.ts +23 -0
- package/dist/components/rowpanels/renderRowPanel.js +22 -0
- package/dist/components/rowpanels/renderRowPanel.js.map +1 -0
- package/dist/components/rowpanels/renderStrip.d.ts +20 -0
- package/dist/components/rowpanels/renderStrip.js +26 -0
- package/dist/components/rowpanels/renderStrip.js.map +1 -0
- package/dist/components/tracks/TrackBlocks.js +3 -5
- package/dist/components/tracks/TrackBlocks.js.map +1 -1
- package/dist/components/tracks/TrackTooltipContent.d.ts +15 -0
- package/dist/components/tracks/TrackTooltipContent.js +109 -0
- package/dist/components/tracks/TrackTooltipContent.js.map +1 -0
- package/dist/components/tracks/drawTracks.d.ts +4 -4
- package/dist/components/tracks/drawTracks.js +17 -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 +4 -1
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +4 -21
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeOverview.d.ts +14 -0
- package/dist/components/tree/TreeOverview.js +75 -0
- package/dist/components/tree/TreeOverview.js.map +1 -0
- package/dist/components/tree/TreeRuler.js +9 -13
- package/dist/components/tree/TreeRuler.js.map +1 -1
- package/dist/components/tree/cladeBrackets.d.ts +25 -0
- package/dist/components/tree/cladeBrackets.js +51 -0
- package/dist/components/tree/cladeBrackets.js.map +1 -0
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +2 -2
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +158 -24
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/tree/renderTreeOverview.d.ts +52 -0
- package/dist/components/tree/renderTreeOverview.js +138 -0
- package/dist/components/tree/renderTreeOverview.js.map +1 -0
- package/dist/components/tree/useTreeHover.js +2 -4
- package/dist/components/tree/useTreeHover.js.map +1 -1
- package/dist/constants.d.ts +15 -0
- package/dist/constants.js +48 -22
- package/dist/constants.js.map +1 -1
- package/dist/createPaletteMap.d.ts +7 -6
- package/dist/createPaletteMap.js +10 -9
- package/dist/createPaletteMap.js.map +1 -1
- package/dist/element.d.ts +13 -0
- package/dist/element.js +269 -0
- package/dist/element.js.map +1 -0
- package/dist/featureFields.d.ts +11 -0
- package/dist/featureFields.js +17 -0
- package/dist/featureFields.js.map +1 -0
- package/dist/flatToTree.js +1 -2
- package/dist/flatToTree.js.map +1 -1
- package/dist/ggplotPalettes.d.ts +10 -0
- package/dist/ggplotPalettes.js +58 -0
- package/dist/ggplotPalettes.js.map +1 -1
- package/dist/hierarchy.d.ts +27 -0
- package/dist/hierarchy.js +66 -9
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/model/DataModel.js +2 -5
- package/dist/model/DataModel.js.map +1 -1
- package/dist/model/msaModel.d.ts +3 -2
- package/dist/model/msaModel.js +3 -2
- package/dist/model/msaModel.js.map +1 -1
- package/dist/model/treeModel.d.ts +30 -0
- package/dist/model/treeModel.js +37 -1
- package/dist/model/treeModel.js.map +1 -1
- package/dist/model.d.ts +531 -275
- package/dist/model.js +1295 -547
- package/dist/model.js.map +1 -1
- package/dist/mount.d.ts +11 -0
- package/dist/mount.js +22 -0
- package/dist/mount.js.map +1 -0
- package/dist/neighborJoining.js +8 -32
- package/dist/neighborJoining.js.map +1 -1
- package/dist/renderToStaticMarkup.d.ts +10 -19
- package/dist/renderToStaticMarkup.js +13 -24
- package/dist/renderToStaticMarkup.js.map +1 -1
- package/dist/renderToSvg.js +180 -56
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +4 -6
- package/dist/rowCoordinateCalculations.js +4 -6
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/scales.d.ts +22 -0
- package/dist/scales.js +30 -0
- package/dist/scales.js.map +1 -0
- package/dist/seqPosToGlobalCol.d.ts +2 -3
- package/dist/seqPosToGlobalCol.js +2 -3
- package/dist/seqPosToGlobalCol.js.map +1 -1
- package/dist/sequenceLogo.d.ts +6 -11
- package/dist/sequenceLogo.js +6 -11
- package/dist/sequenceLogo.js.map +1 -1
- package/dist/stripDefault.d.ts +7 -14
- package/dist/stripDefault.js +7 -14
- package/dist/stripDefault.js.map +1 -1
- package/dist/svgTestUtil.d.ts +172 -52
- package/dist/types.d.ts +219 -21
- package/dist/umd.d.ts +2 -0
- package/dist/umd.js +4 -2
- package/dist/umd.js.map +1 -1
- package/dist/useCanvasAutorun.d.ts +5 -10
- package/dist/useCanvasAutorun.js +5 -10
- package/dist/useCanvasAutorun.js.map +1 -1
- package/dist/useMsaSvgFigure.d.ts +20 -0
- package/dist/useMsaSvgFigure.js +46 -0
- package/dist/useMsaSvgFigure.js.map +1 -0
- package/dist/util.d.ts +5 -6
- package/dist/util.js +13 -6
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +19 -12
- package/src/colorSchemes.ts +1 -2
- package/src/columnStats.ts +58 -0
- package/src/components/DragHandle.tsx +18 -7
- package/src/components/Loading.tsx +2 -6
- package/src/components/MSAView.tsx +19 -5
- package/src/components/MSAViewer.tsx +240 -28
- package/src/components/PortalTooltip.tsx +47 -0
- package/src/components/ResizeHandles.tsx +17 -32
- package/src/components/SequenceTextArea.tsx +3 -3
- package/src/components/Track.tsx +55 -18
- package/src/components/dialogs/ExportSVGDialog.tsx +7 -2
- package/src/components/dialogs/TrackInfoDialog.tsx +1 -1
- package/src/components/header/GappynessSlider.tsx +6 -11
- package/src/components/header/Header.tsx +6 -0
- package/src/components/header/LoadWarnings.tsx +3 -4
- package/src/components/header/ScrollZoomIcons.tsx +52 -0
- package/src/components/header/TreeSettingsMenu.tsx +1 -3
- package/src/components/header/UnshareableDataWarning.tsx +2 -4
- package/src/components/header/ZoomControls.tsx +74 -14
- package/src/components/header/getAnnotationsMenu.ts +3 -6
- package/src/components/header/settingsMenuItems.ts +11 -6
- package/src/components/import/ImportFormExamples.tsx +2 -2
- package/src/components/import/util.ts +1 -2
- package/src/components/minimap/Minimap.tsx +1 -2
- package/src/components/msa/AnnotationLegend.tsx +48 -38
- package/src/components/msa/MSACanvas.tsx +3 -5
- package/src/components/msa/MSACanvasBlock.tsx +13 -16
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -1
- package/src/components/msa/domainBandCursor.ts +7 -11
- package/src/components/msa/drawFeatureSpans.ts +150 -0
- package/src/components/msa/legendRows.ts +24 -0
- package/src/components/msa/msaRaster.ts +30 -39
- package/src/components/msa/packDomainLanes.ts +36 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +69 -123
- package/src/components/msa/renderHighlights.ts +53 -20
- package/src/components/msa/renderMSABlock.ts +5 -3
- package/src/components/msa/tileColor.ts +4 -7
- package/src/components/msa/useMsaBlockMouse.ts +6 -6
- package/src/components/rowpanels/RowPanelBlock.tsx +139 -0
- package/src/components/rowpanels/RowPanelHeaders.tsx +57 -0
- package/src/components/rowpanels/RowPanels.tsx +77 -0
- package/src/components/rowpanels/headerLayout.ts +5 -0
- package/src/components/rowpanels/renderFeaturePanel.ts +66 -0
- package/src/components/rowpanels/renderRowPanel.ts +41 -0
- package/src/components/rowpanels/renderStrip.ts +46 -0
- package/src/components/tracks/TrackBlocks.tsx +3 -5
- package/src/components/tracks/TrackTooltipContent.tsx +156 -0
- package/src/components/tracks/drawTracks.ts +17 -34
- package/src/components/tracks/useTrackHover.ts +42 -0
- package/src/components/tree/CladeLabels.tsx +77 -0
- package/src/components/tree/TreeCanvas.tsx +2 -0
- package/src/components/tree/TreeCanvasBlock.tsx +8 -32
- package/src/components/tree/TreeOverview.tsx +106 -0
- package/src/components/tree/TreeRuler.tsx +11 -22
- package/src/components/tree/cladeBrackets.ts +73 -0
- package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +2 -2
- package/src/components/tree/renderTreeCanvas.ts +240 -20
- package/src/components/tree/renderTreeOverview.ts +212 -0
- package/src/components/tree/useTreeHover.ts +2 -4
- package/src/constants.ts +56 -22
- package/src/createPaletteMap.ts +10 -9
- package/src/element.ts +321 -0
- package/src/featureFields.ts +19 -0
- package/src/flatToTree.ts +1 -2
- package/src/ggplotPalettes.ts +60 -0
- package/src/hierarchy.ts +77 -9
- package/src/index.ts +31 -7
- package/src/model/DataModel.ts +2 -5
- package/src/model/msaModel.ts +3 -2
- package/src/model/treeModel.ts +42 -0
- package/src/model.ts +1523 -560
- package/src/mount.tsx +32 -0
- package/src/neighborJoining.ts +8 -32
- package/src/renderToStaticMarkup.ts +13 -24
- package/src/renderToSvg.tsx +335 -68
- package/src/rowCoordinateCalculations.ts +4 -6
- package/src/scales.ts +47 -0
- package/src/seqPosToGlobalCol.ts +2 -3
- package/src/sequenceLogo.ts +6 -11
- package/src/stripDefault.ts +7 -14
- package/src/types.ts +258 -45
- package/src/umd.ts +4 -2
- package/src/useCanvasAutorun.ts +5 -10
- package/src/useMsaSvgFigure.ts +72 -0
- package/src/util.ts +15 -6
- package/src/version.ts +1 -1
- package/dist/components/msa/ColumnStats.js +0 -42
- package/dist/components/msa/ColumnStats.js.map +0 -1
- package/src/components/msa/ColumnStats.tsx +0 -54
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { subFeatureRowHeight } from '../../constants.ts'
|
|
1
|
+
import { domainUnderlineHeight, subFeatureRowHeight } from '../../constants.ts'
|
|
2
|
+
import { contrastTextFn } from '../../util.ts'
|
|
2
3
|
import { getVisibleLeaves } from '../getVisibleLeaves.ts'
|
|
4
|
+
import { drawFeatureSpans, spanRows } from './drawFeatureSpans.ts'
|
|
3
5
|
|
|
4
|
-
import type { HierarchyNode } from '../../hierarchy.ts'
|
|
5
6
|
import type { MsaViewModel } from '../../model.ts'
|
|
6
|
-
import type {
|
|
7
|
+
import type { DomainBand } from '../../types.ts'
|
|
7
8
|
import type { RenderCtx } from '../renderCtx.ts'
|
|
9
|
+
import type { Theme } from '@mui/material'
|
|
8
10
|
|
|
9
11
|
export function renderBoxFeatureCanvasBlock({
|
|
10
12
|
model,
|
|
13
|
+
theme,
|
|
11
14
|
offsetX,
|
|
12
15
|
offsetY,
|
|
13
16
|
ctx,
|
|
@@ -18,144 +21,87 @@ export function renderBoxFeatureCanvasBlock({
|
|
|
18
21
|
offsetX: number
|
|
19
22
|
offsetY: number
|
|
20
23
|
model: MsaViewModel
|
|
24
|
+
theme: Theme
|
|
21
25
|
ctx: RenderCtx
|
|
22
26
|
highResScaleFactorOverride?: number
|
|
23
27
|
blockSizeXOverride?: number
|
|
24
28
|
blockSizeYOverride?: number
|
|
25
|
-
}) {
|
|
26
|
-
const { blockSize, rowHeight, highResScaleFactor, actuallyShowDomains } =
|
|
27
|
-
model
|
|
28
|
-
if (actuallyShowDomains) {
|
|
29
|
-
const k = highResScaleFactorOverride ?? highResScaleFactor
|
|
30
|
-
const bx = blockSizeXOverride ?? blockSize
|
|
31
|
-
const by = blockSizeYOverride ?? blockSize
|
|
32
|
-
ctx.resetTransform()
|
|
33
|
-
ctx.scale(k, k)
|
|
34
|
-
ctx.translate(-offsetX, rowHeight / 2 - offsetY)
|
|
35
|
-
|
|
36
|
-
drawTiles({
|
|
37
|
-
model,
|
|
38
|
-
ctx,
|
|
39
|
-
visibleLeaves: getVisibleLeaves({ model, offsetY, blockSizeY: by }),
|
|
40
|
-
offsetX,
|
|
41
|
-
blockWidth: bx,
|
|
42
|
-
})
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function drawTiles({
|
|
47
|
-
model,
|
|
48
|
-
ctx,
|
|
49
|
-
visibleLeaves,
|
|
50
|
-
offsetX,
|
|
51
|
-
blockWidth,
|
|
52
|
-
}: {
|
|
53
|
-
model: MsaViewModel
|
|
54
|
-
ctx: RenderCtx
|
|
55
|
-
visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
|
|
56
|
-
offsetX: number
|
|
57
|
-
blockWidth: number
|
|
58
29
|
}) {
|
|
59
30
|
const {
|
|
31
|
+
blockSize,
|
|
32
|
+
rowHeight,
|
|
33
|
+
highResScaleFactor,
|
|
34
|
+
actuallyShowDomains,
|
|
60
35
|
subFeatureRows,
|
|
61
36
|
colWidth,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
strokePalette,
|
|
37
|
+
featureColors,
|
|
38
|
+
featureLabels,
|
|
65
39
|
segmentLabels,
|
|
66
40
|
showMsaLetters,
|
|
41
|
+
domainUnderline,
|
|
67
42
|
domainBands,
|
|
68
43
|
} = model
|
|
69
|
-
|
|
44
|
+
if (!actuallyShowDomains) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
const k = highResScaleFactorOverride ?? highResScaleFactor
|
|
48
|
+
const bx = blockSizeXOverride ?? blockSize
|
|
49
|
+
const by = blockSizeYOverride ?? blockSize
|
|
50
|
+
ctx.resetTransform()
|
|
51
|
+
ctx.scale(k, k)
|
|
52
|
+
ctx.translate(-offsetX, rowHeight / 2 - offsetY)
|
|
53
|
+
|
|
54
|
+
// the plain and underline modes give every band the same height; a sub-row
|
|
55
|
+
// band is thinner, and how thin depends on how many lanes its row needs
|
|
56
|
+
const barHeight = domainUnderline
|
|
57
|
+
? Math.min(domainUnderlineHeight, rowHeight)
|
|
58
|
+
: rowHeight
|
|
70
59
|
// exon numbers label the bands only when residue letters aren't drawn (zoomed
|
|
71
60
|
// out); when letters show, the alternating shades alone mark the boundaries
|
|
72
|
-
// and a number would collide with the sequence
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const cull = h + colWidth
|
|
77
|
-
const xMin = offsetX - cull
|
|
78
|
-
const xMax = offsetX + blockWidth + cull
|
|
79
|
-
|
|
61
|
+
// and a number would collide with the sequence. A featureLabel encoding names
|
|
62
|
+
// what every span carries instead
|
|
63
|
+
const drawSegmentLabels =
|
|
64
|
+
!featureLabels && !showMsaLetters && !subFeatureRows && barHeight >= 9
|
|
80
65
|
// a segment (exon) number labels its band once per block, on the topmost
|
|
81
66
|
// visible row carrying that segment, so it reads as a column header for the
|
|
82
67
|
// whole band. Keyed by accession rather than drawn on row 0, because the rows
|
|
83
68
|
// carrying the gene model are often not the first ones in the alignment
|
|
84
69
|
const labelled = drawSegmentLabels ? new Set<string>() : undefined
|
|
70
|
+
// gene arrow heads stick out up to a row height past the band, so pad the
|
|
71
|
+
// cull window enough that a band just outside the block still draws its head
|
|
72
|
+
const cull = rowHeight + colWidth
|
|
85
73
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// A gene arrow: a full-width rectangular body spanning the feature's
|
|
127
|
-
// start..end columns, plus a triangular head that points *beyond* that end in
|
|
128
|
-
// the strand direction (right for +, left for -). Keeping the body aligned to
|
|
129
|
-
// the exact start/end columns means + and - strand features read as having the
|
|
130
|
-
// same boundaries; the arrow lives outside them purely to show transcription
|
|
131
|
-
// direction, preserving the column-by-column homology down the rows.
|
|
132
|
-
function drawGeneArrow({
|
|
133
|
-
ctx,
|
|
134
|
-
x,
|
|
135
|
-
t,
|
|
136
|
-
w,
|
|
137
|
-
h,
|
|
138
|
-
strand,
|
|
139
|
-
}: {
|
|
140
|
-
ctx: RenderCtx
|
|
141
|
-
x: number
|
|
142
|
-
t: number
|
|
143
|
-
w: number
|
|
144
|
-
h: number
|
|
145
|
-
strand: number
|
|
146
|
-
}) {
|
|
147
|
-
// body spans bodyStart..bodyEnd (the exact columns); the head extends one
|
|
148
|
-
// row-height past bodyEnd in the strand direction
|
|
149
|
-
const dir = strand > 0 ? 1 : -1
|
|
150
|
-
const bodyStart = strand > 0 ? x : x + w
|
|
151
|
-
const bodyEnd = strand > 0 ? x + w : x
|
|
152
|
-
ctx.beginPath()
|
|
153
|
-
ctx.moveTo(bodyStart, t)
|
|
154
|
-
ctx.lineTo(bodyEnd, t)
|
|
155
|
-
ctx.lineTo(bodyEnd + dir * h, t + h / 2)
|
|
156
|
-
ctx.lineTo(bodyEnd, t + h)
|
|
157
|
-
ctx.lineTo(bodyStart, t + h)
|
|
158
|
-
ctx.closePath()
|
|
159
|
-
ctx.fill()
|
|
160
|
-
ctx.stroke()
|
|
74
|
+
drawFeatureSpans<DomainBand>({
|
|
75
|
+
ctx,
|
|
76
|
+
rows: spanRows(
|
|
77
|
+
getVisibleLeaves({ model, offsetY, blockSizeY: by }),
|
|
78
|
+
domainBands,
|
|
79
|
+
),
|
|
80
|
+
layout: {
|
|
81
|
+
// sub-rows are thin, but a row whose lanes would spill onto the row below
|
|
82
|
+
// shares out the row height between them instead
|
|
83
|
+
height: laneCount =>
|
|
84
|
+
subFeatureRows
|
|
85
|
+
? Math.min(subFeatureRowHeight, rowHeight / laneCount)
|
|
86
|
+
: barHeight,
|
|
87
|
+
top: (y, lane, h) =>
|
|
88
|
+
y -
|
|
89
|
+
rowHeight +
|
|
90
|
+
(subFeatureRows ? lane * h : domainUnderline ? rowHeight - h : 0),
|
|
91
|
+
// the head keeps its full size on an underline bar, since a head as short
|
|
92
|
+
// as the bar reads as a nub rather than as a direction
|
|
93
|
+
headLength: h => (domainUnderline ? rowHeight / 2 : h),
|
|
94
|
+
},
|
|
95
|
+
xOf: band => [band.startCol * colWidth, band.endCol * colWidth],
|
|
96
|
+
colors: featureColors,
|
|
97
|
+
labelOf: band =>
|
|
98
|
+
featureLabels?.get(band.annotation) ??
|
|
99
|
+
(labelled && !labelled.has(band.annotation.accession)
|
|
100
|
+
? segmentLabels.get(band.annotation.accession)
|
|
101
|
+
: undefined),
|
|
102
|
+
labelDrawn: band => labelled?.add(band.annotation.accession),
|
|
103
|
+
contrastText: contrastTextFn(theme),
|
|
104
|
+
xMin: offsetX - cull,
|
|
105
|
+
xMax: offsetX + bx + cull,
|
|
106
|
+
})
|
|
161
107
|
}
|
|
@@ -5,17 +5,16 @@ import type { MsaViewModel } from '../../model.ts'
|
|
|
5
5
|
import type { RenderCtx } from '../renderCtx.ts'
|
|
6
6
|
import type { Theme } from '@mui/material'
|
|
7
7
|
|
|
8
|
-
// a
|
|
9
|
-
//
|
|
10
|
-
// against clustalx coloring)
|
|
8
|
+
// a fill plus a solid border; the hover wash alone is invisible over clustalx
|
|
9
|
+
// coloring
|
|
11
10
|
export const highlightFill = 'rgba(255,140,0,0.28)'
|
|
12
11
|
export const highlightBorder = 'rgba(210,90,0,0.95)'
|
|
13
12
|
export const highlightRowFill = 'rgba(255,140,0,0.18)'
|
|
14
13
|
|
|
15
14
|
export const labelFontSize = 11
|
|
16
15
|
const labelPad = 3
|
|
17
|
-
// the label box a highlight
|
|
18
|
-
//
|
|
16
|
+
// the label box above a highlight band; tree blocks also check rows this far
|
|
17
|
+
// outside themselves
|
|
19
18
|
export const highlightLabelHeight = labelFontSize + labelPad * 2
|
|
20
19
|
|
|
21
20
|
export interface LabelBox {
|
|
@@ -29,11 +28,9 @@ export interface LabelBox {
|
|
|
29
28
|
* A highlight's label, over its band where it fits and beside it where it does
|
|
30
29
|
* not, kept inside `bounds` and out of the way of the labels already placed.
|
|
31
30
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* smudge, the second left the visible band untitled. Pass `placed` and each
|
|
36
|
-
* later label steps down a row instead of over the one before.
|
|
31
|
+
* `bounds` keeps the label of a band scrolled partly off the left edge visible.
|
|
32
|
+
* With `placed`, a label that would overlap an earlier one, as two
|
|
33
|
+
* single-residue highlights a column apart do, steps down a row.
|
|
37
34
|
*/
|
|
38
35
|
export function drawHighlightLabel({
|
|
39
36
|
ctx,
|
|
@@ -81,11 +78,16 @@ export function drawHighlightLabel({
|
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
/**
|
|
84
|
-
* The persistent
|
|
85
|
-
*
|
|
86
|
-
*
|
|
81
|
+
* The persistent overlay on the alignment: the band behind each clade of
|
|
82
|
+
* `clades`, the `rowTint` encoding's wash, the row tints and bordered column
|
|
83
|
+
* bands of `highlights`, and a label above each band. `offsetX`/`offsetY` are
|
|
84
|
+
* the content coordinates at the canvas origin, the convention renderMSABlock
|
|
87
85
|
* uses, so the live overlay passes -scrollX/-scrollY and the export passes its
|
|
88
86
|
* layout offsets.
|
|
87
|
+
*
|
|
88
|
+
* Rows are culled to the ones this block covers. A tint over every row of a
|
|
89
|
+
* large alignment would otherwise draw the whole column of rects in each block,
|
|
90
|
+
* and again on every pointer move through renderMouseover.
|
|
89
91
|
*/
|
|
90
92
|
export function renderHighlights({
|
|
91
93
|
ctx,
|
|
@@ -104,13 +106,45 @@ export function renderHighlights({
|
|
|
104
106
|
width: number
|
|
105
107
|
height: number
|
|
106
108
|
}) {
|
|
107
|
-
const { resolvedHighlights, colWidth, rowHeight } =
|
|
109
|
+
const { resolvedClades, resolvedHighlights, rowTints, colWidth, rowHeight } =
|
|
110
|
+
model
|
|
108
111
|
const placed: LabelBox[] = []
|
|
109
112
|
ctx.lineWidth = 2
|
|
113
|
+
const firstRow = Math.max(0, Math.floor(offsetY / rowHeight))
|
|
114
|
+
const lastRow = Math.ceil((offsetY + height) / rowHeight)
|
|
115
|
+
const fillRow = (index: number) => {
|
|
116
|
+
ctx.fillRect(0, index * rowHeight - offsetY, width, rowHeight)
|
|
117
|
+
}
|
|
118
|
+
for (const { rows, color, mark } of resolvedClades) {
|
|
119
|
+
if (mark === 'highlight' && rows[1] >= firstRow && rows[0] <= lastRow) {
|
|
120
|
+
ctx.fillStyle = color
|
|
121
|
+
ctx.fillRect(
|
|
122
|
+
0,
|
|
123
|
+
rows[0] * rowHeight - offsetY,
|
|
124
|
+
width,
|
|
125
|
+
(rows[1] - rows[0] + 1) * rowHeight,
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (rowTints) {
|
|
130
|
+
for (
|
|
131
|
+
let index = firstRow;
|
|
132
|
+
index <= Math.min(lastRow, rowTints.length - 1);
|
|
133
|
+
index++
|
|
134
|
+
) {
|
|
135
|
+
const color = rowTints[index]
|
|
136
|
+
if (color) {
|
|
137
|
+
ctx.fillStyle = color
|
|
138
|
+
fillRow(index)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
110
142
|
for (const { rowIndices, color } of resolvedHighlights) {
|
|
111
143
|
ctx.fillStyle = color ?? highlightRowFill
|
|
112
144
|
for (const index of rowIndices) {
|
|
113
|
-
|
|
145
|
+
if (index >= firstRow && index <= lastRow) {
|
|
146
|
+
fillRow(index)
|
|
147
|
+
}
|
|
114
148
|
}
|
|
115
149
|
}
|
|
116
150
|
for (const { startCol, endCol, label, color } of resolvedHighlights) {
|
|
@@ -139,11 +173,10 @@ export function renderHighlights({
|
|
|
139
173
|
}
|
|
140
174
|
|
|
141
175
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* a shared link that opens with columns highlighted exports with them too.
|
|
176
|
+
* The overlay parts that come from the snapshot: the reference row's tint, a
|
|
177
|
+
* bordered band per run of highlighted columns, and the `highlights` layer. The
|
|
178
|
+
* live overlay draws these under its hover and click bands; the SVG export
|
|
179
|
+
* draws only these.
|
|
147
180
|
*/
|
|
148
181
|
export function renderPersistentHighlights({
|
|
149
182
|
ctx,
|
|
@@ -116,6 +116,7 @@ function drawTilesAndText({
|
|
|
116
116
|
relativeTo,
|
|
117
117
|
showMsaLetters,
|
|
118
118
|
subFeatureRows,
|
|
119
|
+
domainUnderline,
|
|
119
120
|
domainBandsByStart,
|
|
120
121
|
} = model
|
|
121
122
|
|
|
@@ -136,8 +137,9 @@ function drawTilesAndText({
|
|
|
136
137
|
const quarterRowHeight = rowHeight / 4
|
|
137
138
|
// with the tiles coming from the domain overlay instead, letters sit either
|
|
138
139
|
// on a domain box or on the plain background; sub-row layout stacks the boxes
|
|
139
|
-
// above the letters
|
|
140
|
-
|
|
140
|
+
// above the letters and letter-color mode shrinks them to a bar under the
|
|
141
|
+
// row, so neither leaves anything behind a letter
|
|
142
|
+
const overDomains = !drawTiles && !subFeatureRows && !domainUnderline
|
|
141
143
|
|
|
142
144
|
for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
|
|
143
145
|
const node = visibleLeaves[i]!
|
|
@@ -179,7 +181,7 @@ function drawTilesAndText({
|
|
|
179
181
|
? // on top of a colored tile, or on the background where the
|
|
180
182
|
// scheme gives that cell no color
|
|
181
183
|
contrastText(color)
|
|
182
|
-
:
|
|
184
|
+
: bgColor || !color
|
|
183
185
|
? // plain background, uncolored letters
|
|
184
186
|
theme.palette.text.primary
|
|
185
187
|
: // letter-color mode: darken/lighten to stay readable
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { MsaViewModel } from '../../model.ts'
|
|
2
2
|
|
|
3
|
-
// Per-cell tile color for the active scheme
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// scheme needs also keeps the other one -- a per-column map for every column of
|
|
7
|
-
// the alignment -- from being computed at all.
|
|
3
|
+
// Per-cell tile color for the active scheme, resolved once per block. Reading
|
|
4
|
+
// only the active scheme's column table leaves the other per-column table
|
|
5
|
+
// uncomputed.
|
|
8
6
|
export function tileColorFn(model: MsaViewModel) {
|
|
9
7
|
const { colorSchemeName } = model
|
|
10
8
|
if (colorSchemeName === 'clustalx_protein_dynamic') {
|
|
@@ -23,8 +21,7 @@ export function tileColorFn(model: MsaViewModel) {
|
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
// The column table the active scheme colors from, or undefined for the static
|
|
26
|
-
// schemes.
|
|
27
|
-
// colors has to key on.
|
|
24
|
+
// schemes. A cache of rendered colors keys on its identity plus the scheme name.
|
|
28
25
|
export function tileColorTable(model: MsaViewModel) {
|
|
29
26
|
const { colorSchemeName } = model
|
|
30
27
|
if (colorSchemeName === 'clustalx_protein_dynamic') {
|
|
@@ -29,9 +29,11 @@ function eventToColRow({
|
|
|
29
29
|
* Translates pointer events over one MSA block into model column/row hover and
|
|
30
30
|
* click state, and reports where a tooltip should be anchored.
|
|
31
31
|
*
|
|
32
|
-
* The anchor is only tracked when there is something to show (an insertion
|
|
33
|
-
* domain under the cursor
|
|
34
|
-
*
|
|
32
|
+
* The anchor is only tracked when there is something to show (an insertion or a
|
|
33
|
+
* domain under the cursor), so plain mouse movement over the alignment updates
|
|
34
|
+
* the canvas overlay without re-rendering this component. Each track tooltips
|
|
35
|
+
* its own column statistics, and the header reads out the hovered row, residue
|
|
36
|
+
* and position.
|
|
35
37
|
*/
|
|
36
38
|
export function useMsaBlockMouse({
|
|
37
39
|
model,
|
|
@@ -62,9 +64,7 @@ export function useMsaBlockMouse({
|
|
|
62
64
|
model.setMousePos(hit ? pos.col : undefined, hit ? pos.row : undefined)
|
|
63
65
|
|
|
64
66
|
const hasTooltip =
|
|
65
|
-
!!model.hoveredInsertion ||
|
|
66
|
-
model.mouseOverDomains.length > 0 ||
|
|
67
|
-
(model.showColumnStats && !!model.mouseOverColumnStats)
|
|
67
|
+
!!model.hoveredInsertion || model.mouseOverDomains.length > 0
|
|
68
68
|
setTooltipPoint(
|
|
69
69
|
hasTooltip ? { x: event.clientX, y: event.clientY } : undefined,
|
|
70
70
|
)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { useTheme } from '@mui/material'
|
|
4
|
+
import { observer } from 'mobx-react'
|
|
5
|
+
|
|
6
|
+
import { featureField, featureName } from '../../featureFields.ts'
|
|
7
|
+
import { useCanvasAutorun } from '../../useCanvasAutorun.ts'
|
|
8
|
+
import PortalTooltip from '../PortalTooltip.tsx'
|
|
9
|
+
import { renderRowPanel } from './renderRowPanel.ts'
|
|
10
|
+
|
|
11
|
+
import type { MsaViewModel } from '../../model.ts'
|
|
12
|
+
import type { ResolvedRowPanel } from '../../types.ts'
|
|
13
|
+
|
|
14
|
+
interface Hover {
|
|
15
|
+
name: string
|
|
16
|
+
lines: string[]
|
|
17
|
+
clientX: number
|
|
18
|
+
clientY: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// what the cell or span under the pointer reads, which is the field a strip
|
|
22
|
+
// colors by, and a span's name, its coordinates and its encoded field
|
|
23
|
+
function hoverLines({
|
|
24
|
+
model,
|
|
25
|
+
panel,
|
|
26
|
+
name,
|
|
27
|
+
x,
|
|
28
|
+
}: {
|
|
29
|
+
model: MsaViewModel
|
|
30
|
+
panel: ResolvedRowPanel
|
|
31
|
+
name: string
|
|
32
|
+
x: number
|
|
33
|
+
}) {
|
|
34
|
+
if (panel.kind === 'strip') {
|
|
35
|
+
return [
|
|
36
|
+
`${panel.header}: ${model.rowDataOf(name)?.[panel.field] ?? '(none)'}`,
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
const span = panel.spans
|
|
40
|
+
.get(name)
|
|
41
|
+
?.findLast(s => x >= s.xStart && x <= s.xEnd)
|
|
42
|
+
if (!span) {
|
|
43
|
+
return []
|
|
44
|
+
}
|
|
45
|
+
const { annotation } = span
|
|
46
|
+
const strand =
|
|
47
|
+
annotation.strand === undefined
|
|
48
|
+
? ''
|
|
49
|
+
: annotation.strand < 0
|
|
50
|
+
? ' (-)'
|
|
51
|
+
: ' (+)'
|
|
52
|
+
const value = panel.field ? featureField(annotation, panel.field) : undefined
|
|
53
|
+
return [
|
|
54
|
+
featureName(annotation) ?? annotation.accession,
|
|
55
|
+
`${annotation.start}-${annotation.end}${strand}`,
|
|
56
|
+
...(value === undefined ? [] : [`${panel.field}: ${value}`]),
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const RowPanelBlock = observer(function ({
|
|
61
|
+
model,
|
|
62
|
+
panel,
|
|
63
|
+
offsetY,
|
|
64
|
+
}: {
|
|
65
|
+
model: MsaViewModel
|
|
66
|
+
panel: ResolvedRowPanel
|
|
67
|
+
offsetY: number
|
|
68
|
+
}) {
|
|
69
|
+
const [hovered, setHovered] = useState<Hover>()
|
|
70
|
+
const theme = useTheme()
|
|
71
|
+
const { blockSize, highResScaleFactor, rowHeight } = model
|
|
72
|
+
const width = panel.width
|
|
73
|
+
const height = blockSize
|
|
74
|
+
const canvasWidth = width * highResScaleFactor
|
|
75
|
+
const canvasHeight = height * highResScaleFactor
|
|
76
|
+
|
|
77
|
+
const ref = useCanvasAutorun({
|
|
78
|
+
draw: ctx => {
|
|
79
|
+
ctx.resetTransform()
|
|
80
|
+
ctx.clearRect(0, 0, canvasWidth, canvasHeight)
|
|
81
|
+
renderRowPanel({ ctx, model, theme, panel, x: 0, offsetY })
|
|
82
|
+
},
|
|
83
|
+
width: canvasWidth,
|
|
84
|
+
height: canvasHeight,
|
|
85
|
+
deps: [model, theme, panel, offsetY],
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<>
|
|
90
|
+
<canvas
|
|
91
|
+
ref={ref}
|
|
92
|
+
width={canvasWidth}
|
|
93
|
+
height={canvasHeight}
|
|
94
|
+
style={{ position: 'absolute', top: offsetY, left: 0, width, height }}
|
|
95
|
+
onMouseMove={event => {
|
|
96
|
+
// the blocks are laid out in row space and scrolled by a transform
|
|
97
|
+
// on their container, so the pointer's row comes off the canvas box
|
|
98
|
+
const { left, top } = event.currentTarget.getBoundingClientRect()
|
|
99
|
+
const row = Math.floor((event.clientY - top + offsetY) / rowHeight)
|
|
100
|
+
const name = model.leaves[row]?.data.name
|
|
101
|
+
const lines =
|
|
102
|
+
name === undefined
|
|
103
|
+
? []
|
|
104
|
+
: hoverLines({
|
|
105
|
+
model,
|
|
106
|
+
panel,
|
|
107
|
+
name,
|
|
108
|
+
x: event.clientX - left,
|
|
109
|
+
})
|
|
110
|
+
setHovered(
|
|
111
|
+
name === undefined || lines.length === 0
|
|
112
|
+
? undefined
|
|
113
|
+
: {
|
|
114
|
+
name,
|
|
115
|
+
lines,
|
|
116
|
+
clientX: event.clientX,
|
|
117
|
+
clientY: event.clientY,
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
model.setMousePos(undefined, name === undefined ? undefined : row)
|
|
121
|
+
}}
|
|
122
|
+
onMouseLeave={() => {
|
|
123
|
+
setHovered(undefined)
|
|
124
|
+
model.setMousePos(undefined, undefined)
|
|
125
|
+
}}
|
|
126
|
+
/>
|
|
127
|
+
{hovered ? (
|
|
128
|
+
<PortalTooltip clientX={hovered.clientX} clientY={hovered.clientY}>
|
|
129
|
+
<div>{hovered.name}</div>
|
|
130
|
+
{hovered.lines.map(line => (
|
|
131
|
+
<div key={line}>{line}</div>
|
|
132
|
+
))}
|
|
133
|
+
</PortalTooltip>
|
|
134
|
+
) : null}
|
|
135
|
+
</>
|
|
136
|
+
)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
export default RowPanelBlock
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { observer } from 'mobx-react'
|
|
4
|
+
|
|
5
|
+
import { headerRunsAcross } from './headerLayout.ts'
|
|
6
|
+
|
|
7
|
+
import type { MsaViewModel } from '../../model.ts'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The row panel headers, in a band above the panels beside the tree ruler and
|
|
11
|
+
* the minimap. A narrow strip's name is DOM text turned on its side, since the
|
|
12
|
+
* canvas layer has no rotation, and the SVG export draws it with a
|
|
13
|
+
* `rotate(-90)`. A panel wider than the band is tall writes its name across.
|
|
14
|
+
*/
|
|
15
|
+
const RowPanelHeaders = observer(function ({ model }: { model: MsaViewModel }) {
|
|
16
|
+
const { resolvedRowPanels, rowPanelsHeaderHeight, fontSize } = model
|
|
17
|
+
return resolvedRowPanels.length > 0 ? (
|
|
18
|
+
<div
|
|
19
|
+
style={{
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexShrink: 0,
|
|
22
|
+
height: rowPanelsHeaderHeight,
|
|
23
|
+
alignItems: 'flex-end',
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
{resolvedRowPanels.map(panel => {
|
|
27
|
+
const across = headerRunsAcross(panel.width)
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
key={panel.id}
|
|
31
|
+
title={panel.header}
|
|
32
|
+
style={{
|
|
33
|
+
width: panel.width,
|
|
34
|
+
overflow: 'hidden',
|
|
35
|
+
textOverflow: 'ellipsis',
|
|
36
|
+
whiteSpace: 'nowrap',
|
|
37
|
+
...(across
|
|
38
|
+
? { fontSize, textAlign: 'center' }
|
|
39
|
+
: {
|
|
40
|
+
height: rowPanelsHeaderHeight,
|
|
41
|
+
fontSize: Math.min(fontSize, panel.width),
|
|
42
|
+
// vertical-rl reads top to bottom, and the half turn makes
|
|
43
|
+
// it read upwards from the strip, as rotate(-90) exports
|
|
44
|
+
writingMode: 'vertical-rl',
|
|
45
|
+
transform: 'rotate(180deg)',
|
|
46
|
+
}),
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
{panel.header}
|
|
50
|
+
</div>
|
|
51
|
+
)
|
|
52
|
+
})}
|
|
53
|
+
</div>
|
|
54
|
+
) : null
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
export default RowPanelHeaders
|