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.
Files changed (310) hide show
  1. package/README.md +11 -10
  2. package/bundle/index.js +122 -111
  3. package/bundle/index.js.map +4 -4
  4. package/dist/colorSchemes.js +1 -2
  5. package/dist/colorSchemes.js.map +1 -1
  6. package/dist/columnStats.d.ts +28 -0
  7. package/dist/columnStats.js +34 -0
  8. package/dist/columnStats.js.map +1 -0
  9. package/dist/components/DragHandle.d.ts +3 -2
  10. package/dist/components/DragHandle.js +11 -5
  11. package/dist/components/DragHandle.js.map +1 -1
  12. package/dist/components/Loading.js.map +1 -1
  13. package/dist/components/MSAView.js +17 -6
  14. package/dist/components/MSAView.js.map +1 -1
  15. package/dist/components/MSAViewer.d.ts +64 -7
  16. package/dist/components/MSAViewer.js +128 -23
  17. package/dist/components/MSAViewer.js.map +1 -1
  18. package/dist/components/PortalTooltip.d.ts +11 -0
  19. package/dist/components/PortalTooltip.js +29 -0
  20. package/dist/components/PortalTooltip.js.map +1 -0
  21. package/dist/components/ResizeHandles.js +11 -29
  22. package/dist/components/ResizeHandles.js.map +1 -1
  23. package/dist/components/SequenceTextArea.js +3 -3
  24. package/dist/components/SequenceTextArea.js.map +1 -1
  25. package/dist/components/Track.js +41 -22
  26. package/dist/components/Track.js.map +1 -1
  27. package/dist/components/dialogs/ExportSVGDialog.js +5 -3
  28. package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
  29. package/dist/components/dialogs/TrackInfoDialog.js +1 -1
  30. package/dist/components/dialogs/TrackInfoDialog.js.map +1 -1
  31. package/dist/components/header/GappynessSlider.js +6 -11
  32. package/dist/components/header/GappynessSlider.js.map +1 -1
  33. package/dist/components/header/Header.js +3 -0
  34. package/dist/components/header/Header.js.map +1 -1
  35. package/dist/components/header/LoadWarnings.js +3 -4
  36. package/dist/components/header/LoadWarnings.js.map +1 -1
  37. package/dist/components/header/ScrollZoomIcons.d.ts +6 -0
  38. package/dist/components/header/ScrollZoomIcons.js +35 -0
  39. package/dist/components/header/ScrollZoomIcons.js.map +1 -0
  40. package/dist/components/header/TreeSettingsMenu.js +1 -3
  41. package/dist/components/header/TreeSettingsMenu.js.map +1 -1
  42. package/dist/components/header/UnshareableDataWarning.js +2 -4
  43. package/dist/components/header/UnshareableDataWarning.js.map +1 -1
  44. package/dist/components/header/ZoomControls.js +49 -6
  45. package/dist/components/header/ZoomControls.js.map +1 -1
  46. package/dist/components/header/getAnnotationsMenu.js +3 -6
  47. package/dist/components/header/getAnnotationsMenu.js.map +1 -1
  48. package/dist/components/header/settingsMenuItems.js +10 -7
  49. package/dist/components/header/settingsMenuItems.js.map +1 -1
  50. package/dist/components/import/util.js +1 -2
  51. package/dist/components/import/util.js.map +1 -1
  52. package/dist/components/minimap/Minimap.js +1 -2
  53. package/dist/components/minimap/Minimap.js.map +1 -1
  54. package/dist/components/msa/AnnotationLegend.js +27 -19
  55. package/dist/components/msa/AnnotationLegend.js.map +1 -1
  56. package/dist/components/msa/MSACanvas.js +1 -1
  57. package/dist/components/msa/MSACanvas.js.map +1 -1
  58. package/dist/components/msa/MSACanvasBlock.js +13 -15
  59. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  60. package/dist/components/msa/MSAMouseoverCanvas.js +2 -1
  61. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
  62. package/dist/components/msa/domainBandCursor.d.ts +7 -11
  63. package/dist/components/msa/domainBandCursor.js +7 -11
  64. package/dist/components/msa/domainBandCursor.js.map +1 -1
  65. package/dist/components/msa/drawFeatureSpans.d.ts +53 -0
  66. package/dist/components/msa/drawFeatureSpans.js +78 -0
  67. package/dist/components/msa/drawFeatureSpans.js.map +1 -0
  68. package/dist/components/msa/legendRows.d.ts +8 -0
  69. package/dist/components/msa/legendRows.js +16 -0
  70. package/dist/components/msa/legendRows.js.map +1 -0
  71. package/dist/components/msa/msaRaster.d.ts +24 -31
  72. package/dist/components/msa/msaRaster.js +30 -39
  73. package/dist/components/msa/msaRaster.js.map +1 -1
  74. package/dist/components/msa/packDomainLanes.d.ts +20 -0
  75. package/dist/components/msa/packDomainLanes.js +33 -0
  76. package/dist/components/msa/packDomainLanes.js.map +1 -0
  77. package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +3 -1
  78. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +51 -87
  79. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  80. package/dist/components/msa/renderHighlights.d.ts +15 -13
  81. package/dist/components/msa/renderHighlights.js +43 -20
  82. package/dist/components/msa/renderHighlights.js.map +1 -1
  83. package/dist/components/msa/renderMSABlock.js +5 -4
  84. package/dist/components/msa/renderMSABlock.js.map +1 -1
  85. package/dist/components/msa/tileColor.js +4 -7
  86. package/dist/components/msa/tileColor.js.map +1 -1
  87. package/dist/components/msa/useMsaBlockMouse.d.ts +5 -3
  88. package/dist/components/msa/useMsaBlockMouse.js +6 -6
  89. package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
  90. package/dist/components/rowpanels/RowPanelBlock.d.ts +9 -0
  91. package/dist/components/rowpanels/RowPanelBlock.js +86 -0
  92. package/dist/components/rowpanels/RowPanelBlock.js.map +1 -0
  93. package/dist/components/rowpanels/RowPanelHeaders.d.ts +12 -0
  94. package/dist/components/rowpanels/RowPanelHeaders.js +38 -0
  95. package/dist/components/rowpanels/RowPanelHeaders.js.map +1 -0
  96. package/dist/components/{msa/ColumnStats.d.ts → rowpanels/RowPanels.d.ts} +2 -2
  97. package/dist/components/rowpanels/RowPanels.js +32 -0
  98. package/dist/components/rowpanels/RowPanels.js.map +1 -0
  99. package/dist/components/rowpanels/headerLayout.d.ts +1 -0
  100. package/dist/components/rowpanels/headerLayout.js +5 -0
  101. package/dist/components/rowpanels/headerLayout.js.map +1 -0
  102. package/dist/components/rowpanels/renderFeaturePanel.d.ts +21 -0
  103. package/dist/components/rowpanels/renderFeaturePanel.js +37 -0
  104. package/dist/components/rowpanels/renderFeaturePanel.js.map +1 -0
  105. package/dist/components/rowpanels/renderRowPanel.d.ts +23 -0
  106. package/dist/components/rowpanels/renderRowPanel.js +22 -0
  107. package/dist/components/rowpanels/renderRowPanel.js.map +1 -0
  108. package/dist/components/rowpanels/renderStrip.d.ts +20 -0
  109. package/dist/components/rowpanels/renderStrip.js +26 -0
  110. package/dist/components/rowpanels/renderStrip.js.map +1 -0
  111. package/dist/components/tracks/TrackBlocks.js +3 -5
  112. package/dist/components/tracks/TrackBlocks.js.map +1 -1
  113. package/dist/components/tracks/TrackTooltipContent.d.ts +15 -0
  114. package/dist/components/tracks/TrackTooltipContent.js +109 -0
  115. package/dist/components/tracks/TrackTooltipContent.js.map +1 -0
  116. package/dist/components/tracks/drawTracks.d.ts +4 -4
  117. package/dist/components/tracks/drawTracks.js +17 -34
  118. package/dist/components/tracks/drawTracks.js.map +1 -1
  119. package/dist/components/tracks/useTrackHover.d.ts +22 -0
  120. package/dist/components/tracks/useTrackHover.js +30 -0
  121. package/dist/components/tracks/useTrackHover.js.map +1 -0
  122. package/dist/components/tree/CladeLabels.d.ts +12 -0
  123. package/dist/components/tree/CladeLabels.js +48 -0
  124. package/dist/components/tree/CladeLabels.js.map +1 -0
  125. package/dist/components/tree/TreeCanvas.js +4 -1
  126. package/dist/components/tree/TreeCanvas.js.map +1 -1
  127. package/dist/components/tree/TreeCanvasBlock.js +4 -21
  128. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  129. package/dist/components/tree/TreeOverview.d.ts +14 -0
  130. package/dist/components/tree/TreeOverview.js +75 -0
  131. package/dist/components/tree/TreeOverview.js.map +1 -0
  132. package/dist/components/tree/TreeRuler.js +9 -13
  133. package/dist/components/tree/TreeRuler.js.map +1 -1
  134. package/dist/components/tree/cladeBrackets.d.ts +25 -0
  135. package/dist/components/tree/cladeBrackets.js +51 -0
  136. package/dist/components/tree/cladeBrackets.js.map +1 -0
  137. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +2 -2
  138. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
  139. package/dist/components/tree/renderTreeCanvas.js +158 -24
  140. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  141. package/dist/components/tree/renderTreeOverview.d.ts +52 -0
  142. package/dist/components/tree/renderTreeOverview.js +138 -0
  143. package/dist/components/tree/renderTreeOverview.js.map +1 -0
  144. package/dist/components/tree/useTreeHover.js +2 -4
  145. package/dist/components/tree/useTreeHover.js.map +1 -1
  146. package/dist/constants.d.ts +15 -0
  147. package/dist/constants.js +48 -22
  148. package/dist/constants.js.map +1 -1
  149. package/dist/createPaletteMap.d.ts +7 -6
  150. package/dist/createPaletteMap.js +10 -9
  151. package/dist/createPaletteMap.js.map +1 -1
  152. package/dist/element.d.ts +13 -0
  153. package/dist/element.js +269 -0
  154. package/dist/element.js.map +1 -0
  155. package/dist/featureFields.d.ts +11 -0
  156. package/dist/featureFields.js +17 -0
  157. package/dist/featureFields.js.map +1 -0
  158. package/dist/flatToTree.js +1 -2
  159. package/dist/flatToTree.js.map +1 -1
  160. package/dist/ggplotPalettes.d.ts +10 -0
  161. package/dist/ggplotPalettes.js +58 -0
  162. package/dist/ggplotPalettes.js.map +1 -1
  163. package/dist/hierarchy.d.ts +27 -0
  164. package/dist/hierarchy.js +66 -9
  165. package/dist/hierarchy.js.map +1 -1
  166. package/dist/index.d.ts +9 -1
  167. package/dist/index.js +5 -3
  168. package/dist/index.js.map +1 -1
  169. package/dist/model/DataModel.js +2 -5
  170. package/dist/model/DataModel.js.map +1 -1
  171. package/dist/model/msaModel.d.ts +3 -2
  172. package/dist/model/msaModel.js +3 -2
  173. package/dist/model/msaModel.js.map +1 -1
  174. package/dist/model/treeModel.d.ts +30 -0
  175. package/dist/model/treeModel.js +37 -1
  176. package/dist/model/treeModel.js.map +1 -1
  177. package/dist/model.d.ts +531 -275
  178. package/dist/model.js +1295 -547
  179. package/dist/model.js.map +1 -1
  180. package/dist/mount.d.ts +11 -0
  181. package/dist/mount.js +22 -0
  182. package/dist/mount.js.map +1 -0
  183. package/dist/neighborJoining.js +8 -32
  184. package/dist/neighborJoining.js.map +1 -1
  185. package/dist/renderToStaticMarkup.d.ts +10 -19
  186. package/dist/renderToStaticMarkup.js +13 -24
  187. package/dist/renderToStaticMarkup.js.map +1 -1
  188. package/dist/renderToSvg.js +180 -56
  189. package/dist/renderToSvg.js.map +1 -1
  190. package/dist/rowCoordinateCalculations.d.ts +4 -6
  191. package/dist/rowCoordinateCalculations.js +4 -6
  192. package/dist/rowCoordinateCalculations.js.map +1 -1
  193. package/dist/scales.d.ts +22 -0
  194. package/dist/scales.js +30 -0
  195. package/dist/scales.js.map +1 -0
  196. package/dist/seqPosToGlobalCol.d.ts +2 -3
  197. package/dist/seqPosToGlobalCol.js +2 -3
  198. package/dist/seqPosToGlobalCol.js.map +1 -1
  199. package/dist/sequenceLogo.d.ts +6 -11
  200. package/dist/sequenceLogo.js +6 -11
  201. package/dist/sequenceLogo.js.map +1 -1
  202. package/dist/stripDefault.d.ts +7 -14
  203. package/dist/stripDefault.js +7 -14
  204. package/dist/stripDefault.js.map +1 -1
  205. package/dist/svgTestUtil.d.ts +172 -52
  206. package/dist/types.d.ts +219 -21
  207. package/dist/umd.d.ts +2 -0
  208. package/dist/umd.js +4 -2
  209. package/dist/umd.js.map +1 -1
  210. package/dist/useCanvasAutorun.d.ts +5 -10
  211. package/dist/useCanvasAutorun.js +5 -10
  212. package/dist/useCanvasAutorun.js.map +1 -1
  213. package/dist/useMsaSvgFigure.d.ts +20 -0
  214. package/dist/useMsaSvgFigure.js +46 -0
  215. package/dist/useMsaSvgFigure.js.map +1 -0
  216. package/dist/util.d.ts +5 -6
  217. package/dist/util.js +13 -6
  218. package/dist/util.js.map +1 -1
  219. package/dist/version.d.ts +1 -1
  220. package/dist/version.js +1 -1
  221. package/package.json +19 -12
  222. package/src/colorSchemes.ts +1 -2
  223. package/src/columnStats.ts +58 -0
  224. package/src/components/DragHandle.tsx +18 -7
  225. package/src/components/Loading.tsx +2 -6
  226. package/src/components/MSAView.tsx +19 -5
  227. package/src/components/MSAViewer.tsx +240 -28
  228. package/src/components/PortalTooltip.tsx +47 -0
  229. package/src/components/ResizeHandles.tsx +17 -32
  230. package/src/components/SequenceTextArea.tsx +3 -3
  231. package/src/components/Track.tsx +55 -18
  232. package/src/components/dialogs/ExportSVGDialog.tsx +7 -2
  233. package/src/components/dialogs/TrackInfoDialog.tsx +1 -1
  234. package/src/components/header/GappynessSlider.tsx +6 -11
  235. package/src/components/header/Header.tsx +6 -0
  236. package/src/components/header/LoadWarnings.tsx +3 -4
  237. package/src/components/header/ScrollZoomIcons.tsx +52 -0
  238. package/src/components/header/TreeSettingsMenu.tsx +1 -3
  239. package/src/components/header/UnshareableDataWarning.tsx +2 -4
  240. package/src/components/header/ZoomControls.tsx +74 -14
  241. package/src/components/header/getAnnotationsMenu.ts +3 -6
  242. package/src/components/header/settingsMenuItems.ts +11 -6
  243. package/src/components/import/ImportFormExamples.tsx +2 -2
  244. package/src/components/import/util.ts +1 -2
  245. package/src/components/minimap/Minimap.tsx +1 -2
  246. package/src/components/msa/AnnotationLegend.tsx +48 -38
  247. package/src/components/msa/MSACanvas.tsx +3 -5
  248. package/src/components/msa/MSACanvasBlock.tsx +13 -16
  249. package/src/components/msa/MSAMouseoverCanvas.tsx +2 -1
  250. package/src/components/msa/domainBandCursor.ts +7 -11
  251. package/src/components/msa/drawFeatureSpans.ts +150 -0
  252. package/src/components/msa/legendRows.ts +24 -0
  253. package/src/components/msa/msaRaster.ts +30 -39
  254. package/src/components/msa/packDomainLanes.ts +36 -0
  255. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +69 -123
  256. package/src/components/msa/renderHighlights.ts +53 -20
  257. package/src/components/msa/renderMSABlock.ts +5 -3
  258. package/src/components/msa/tileColor.ts +4 -7
  259. package/src/components/msa/useMsaBlockMouse.ts +6 -6
  260. package/src/components/rowpanels/RowPanelBlock.tsx +139 -0
  261. package/src/components/rowpanels/RowPanelHeaders.tsx +57 -0
  262. package/src/components/rowpanels/RowPanels.tsx +77 -0
  263. package/src/components/rowpanels/headerLayout.ts +5 -0
  264. package/src/components/rowpanels/renderFeaturePanel.ts +66 -0
  265. package/src/components/rowpanels/renderRowPanel.ts +41 -0
  266. package/src/components/rowpanels/renderStrip.ts +46 -0
  267. package/src/components/tracks/TrackBlocks.tsx +3 -5
  268. package/src/components/tracks/TrackTooltipContent.tsx +156 -0
  269. package/src/components/tracks/drawTracks.ts +17 -34
  270. package/src/components/tracks/useTrackHover.ts +42 -0
  271. package/src/components/tree/CladeLabels.tsx +77 -0
  272. package/src/components/tree/TreeCanvas.tsx +2 -0
  273. package/src/components/tree/TreeCanvasBlock.tsx +8 -32
  274. package/src/components/tree/TreeOverview.tsx +106 -0
  275. package/src/components/tree/TreeRuler.tsx +11 -22
  276. package/src/components/tree/cladeBrackets.ts +73 -0
  277. package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +2 -2
  278. package/src/components/tree/renderTreeCanvas.ts +240 -20
  279. package/src/components/tree/renderTreeOverview.ts +212 -0
  280. package/src/components/tree/useTreeHover.ts +2 -4
  281. package/src/constants.ts +56 -22
  282. package/src/createPaletteMap.ts +10 -9
  283. package/src/element.ts +321 -0
  284. package/src/featureFields.ts +19 -0
  285. package/src/flatToTree.ts +1 -2
  286. package/src/ggplotPalettes.ts +60 -0
  287. package/src/hierarchy.ts +77 -9
  288. package/src/index.ts +31 -7
  289. package/src/model/DataModel.ts +2 -5
  290. package/src/model/msaModel.ts +3 -2
  291. package/src/model/treeModel.ts +42 -0
  292. package/src/model.ts +1523 -560
  293. package/src/mount.tsx +32 -0
  294. package/src/neighborJoining.ts +8 -32
  295. package/src/renderToStaticMarkup.ts +13 -24
  296. package/src/renderToSvg.tsx +335 -68
  297. package/src/rowCoordinateCalculations.ts +4 -6
  298. package/src/scales.ts +47 -0
  299. package/src/seqPosToGlobalCol.ts +2 -3
  300. package/src/sequenceLogo.ts +6 -11
  301. package/src/stripDefault.ts +7 -14
  302. package/src/types.ts +258 -45
  303. package/src/umd.ts +4 -2
  304. package/src/useCanvasAutorun.ts +5 -10
  305. package/src/useMsaSvgFigure.ts +72 -0
  306. package/src/util.ts +15 -6
  307. package/src/version.ts +1 -1
  308. package/dist/components/msa/ColumnStats.js +0 -42
  309. package/dist/components/msa/ColumnStats.js.map +0 -1
  310. package/src/components/msa/ColumnStats.tsx +0 -54
@@ -2,27 +2,13 @@ import React, { useState } from 'react';
2
2
  import { makeStyles } from '@jbrowse/core/util/tss-react';
3
3
  import { useTheme } from '@mui/material';
4
4
  import { observer } from 'mobx-react';
5
- import { createPortal } from 'react-dom';
6
5
  import { useCanvasAutorun } from '../../useCanvasAutorun.js';
6
+ import PortalTooltip from '../PortalTooltip.js';
7
7
  import TreeBranchMenu from './TreeBranchMenu.js';
8
8
  import TreeNodeMenu from './TreeNodeMenu.js';
9
9
  import { renderTreeCanvas } from './renderTreeCanvas.js';
10
10
  import { useTreeHover } from './useTreeHover.js';
11
- const useStyles = makeStyles()(theme => ({
12
- tooltip: {
13
- position: 'fixed',
14
- pointerEvents: 'none',
15
- zIndex: 10000,
16
- backgroundColor: theme.palette.grey[700],
17
- color: theme.palette.common.white,
18
- padding: '4px 8px',
19
- borderRadius: 4,
20
- fontSize: 12,
21
- whiteSpace: 'nowrap',
22
- maxWidth: 300,
23
- overflow: 'hidden',
24
- textOverflow: 'ellipsis',
25
- },
11
+ const useStyles = makeStyles()(() => ({
26
12
  hover: {
27
13
  position: 'absolute',
28
14
  pointerEvents: 'none',
@@ -37,8 +23,7 @@ const TreeCanvasBlock = observer(function ({ model, offsetY, }) {
37
23
  const [nodeMenu, setNodeMenu] = useState();
38
24
  const { clickMap, hovered, hitTest, onMouseMove, onMouseLeave } = useTreeHover({ model, offsetY });
39
25
  const { treeAreaWidth, blockSize, highResScaleFactor } = model;
40
- // TreePanel clips to treeAreaWidth, so anything wider is backing store the
41
- // viewer never sees -- it was 600px of it per block, at dpr squared
26
+ // TreePanel clips to treeAreaWidth, so a wider canvas is wasted backing store
42
27
  const width = treeAreaWidth;
43
28
  const height = blockSize;
44
29
  const canvasWidth = width * highResScaleFactor;
@@ -100,9 +85,7 @@ const TreeCanvasBlock = observer(function ({ model, offsetY, }) {
100
85
  width: hovered.maxX - hovered.minX,
101
86
  height: hovered.maxY - hovered.minY,
102
87
  } })) : null,
103
- hovered
104
- ? createPortal(React.createElement("div", { className: classes.tooltip, style: { left: hovered.clientX + 12, top: hovered.clientY + 12 } }, hovered.name), document.body)
105
- : null));
88
+ hovered ? (React.createElement(PortalTooltip, { clientX: hovered.clientX, clientY: hovered.clientY }, hovered.name)) : null));
106
89
  });
107
90
  export default TreeCanvasBlock;
108
91
  //# sourceMappingURL=TreeCanvasBlock.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TreeCanvasBlock.js","sourceRoot":"","sources":["../../../src/components/tree/TreeCanvasBlock.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TreeCanvasBlock.js","sourceRoot":"","sources":["../../../src/components/tree/TreeCanvasBlock.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { MsaViewModel } from '../../model.ts';
3
+ /**
4
+ * The brush on the row scale: the whole tree drawn small above the tree panel,
5
+ * with the focused subtree boxed. A click focuses the subtree under the
6
+ * pointer, and a click inside the box clears the focus.
7
+ *
8
+ * The tree itself comes off a cached offscreen canvas, so the frames a pointer
9
+ * moving across it costs are a blit and two boxes.
10
+ */
11
+ declare const TreeOverview: ({ model }: {
12
+ model: MsaViewModel;
13
+ }) => React.JSX.Element;
14
+ export default TreeOverview;
@@ -0,0 +1,75 @@
1
+ import React, { useState } from 'react';
2
+ import { useTheme } from '@mui/material';
3
+ import { observer } from 'mobx-react';
4
+ import { useCanvasAutorun } from '../../useCanvasAutorun.js';
5
+ import { drawTreeOverview, drawTreeOverviewBox, treeOverviewImage, } from './renderTreeOverview.js';
6
+ /**
7
+ * The brush on the row scale: the whole tree drawn small above the tree panel,
8
+ * with the focused subtree boxed. A click focuses the subtree under the
9
+ * pointer, and a click inside the box clears the focus.
10
+ *
11
+ * The tree itself comes off a cached offscreen canvas, so the frames a pointer
12
+ * moving across it costs are a blit and two boxes.
13
+ */
14
+ const TreeOverview = observer(function ({ model }) {
15
+ const { treeAreaWidth, overviewHeight, highResScaleFactor } = model;
16
+ const theme = useTheme();
17
+ const [hover, setHover] = useState();
18
+ const width = Math.round(treeAreaWidth * highResScaleFactor);
19
+ const height = Math.round(overviewHeight * highResScaleFactor);
20
+ const ref = useCanvasAutorun({
21
+ draw: ctx => {
22
+ ctx.resetTransform();
23
+ ctx.clearRect(0, 0, width, height);
24
+ const image = treeOverviewImage({
25
+ model,
26
+ theme,
27
+ width: treeAreaWidth,
28
+ height: overviewHeight,
29
+ scale: highResScaleFactor,
30
+ });
31
+ ctx.scale(highResScaleFactor, highResScaleFactor);
32
+ const box = { model, ctx, width: treeAreaWidth, height: overviewHeight };
33
+ if (image) {
34
+ ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, box.width, box.height);
35
+ }
36
+ else {
37
+ drawTreeOverview({ ...box, theme });
38
+ }
39
+ if (hover) {
40
+ drawTreeOverviewBox({
41
+ ...box,
42
+ rows: hover.rows,
43
+ color: theme.palette.text.secondary,
44
+ });
45
+ }
46
+ const focus = model.treeOverviewFocusRows;
47
+ if (focus) {
48
+ drawTreeOverviewBox({
49
+ ...box,
50
+ rows: focus,
51
+ color: theme.palette.text.primary,
52
+ });
53
+ }
54
+ },
55
+ width,
56
+ height,
57
+ deps: [model, theme, hover],
58
+ });
59
+ return (React.createElement("canvas", { "data-testid": "tree_overview", ref: ref, width: width, height: height, style: {
60
+ display: 'block',
61
+ flexShrink: 0,
62
+ cursor: 'pointer',
63
+ width: treeAreaWidth,
64
+ height: overviewHeight,
65
+ }, onMouseMove: event => {
66
+ const hit = model.treeOverviewHit(event.nativeEvent.offsetY);
67
+ setHover(prev => (prev?.id === hit?.id ? prev : hit));
68
+ }, onMouseLeave: () => {
69
+ setHover(undefined);
70
+ }, onClick: event => {
71
+ model.treeOverviewClick(event.nativeEvent.offsetY);
72
+ } }));
73
+ });
74
+ export default TreeOverview;
75
+ //# sourceMappingURL=TreeOverview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TreeOverview.js","sourceRoot":"","sources":["../../../src/components/tree/TreeOverview.tsx"],"names":[],"mappings":"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"}
@@ -1,21 +1,17 @@
1
1
  import React from 'react';
2
2
  import { useTheme } from '@mui/material';
3
3
  import { observer } from 'mobx-react';
4
- import { scaleBarLength } from './scaleBar.js';
5
- const BAR_HEIGHT = 22;
6
- // The gutter above the tree panel. It spans the resize handle too, so whatever
7
- // follows it in the top row starts exactly where the alignment canvas does --
8
- // MainArea has TreePanel + VerticalResizeHandle before the alignment. A
9
- // phylogram fills it with a scale bar: without one the branch lengths are drawn
10
- // to a scale nothing states.
4
+ import { treeScaleBarHeight as h } from '../../constants.js';
5
+ // The gutter above the tree panel, the width of the tree area, so the strip
6
+ // headers beside it start where the strips do. A phylogram fills it with a
7
+ // scale bar: without one the branch lengths are drawn to a scale nothing
8
+ // states.
11
9
  const TreeRuler = observer(({ model }) => {
12
- const { treeAreaWidth, resizeHandleWidth, marginLeft, pxPerBranchLength } = model;
10
+ const { treeAreaWidth, marginLeft, treeScaleBar: bar } = model;
13
11
  const theme = useTheme();
14
- const width = treeAreaWidth + resizeHandleWidth;
15
- const bar = scaleBarLength(pxPerBranchLength, treeAreaWidth - marginLeft * 2);
16
- return (React.createElement("div", { style: { flexShrink: 0, width } }, bar ? (React.createElement("svg", { width: width, height: BAR_HEIGHT, style: { display: 'block' }, color: theme.palette.text.primary },
17
- React.createElement("text", { x: marginLeft, y: BAR_HEIGHT - 9, fontSize: 10, fill: "currentColor" }, bar.label),
18
- React.createElement("path", { d: `M${marginLeft} ${BAR_HEIGHT - 7} v6 h${bar.px} v-6`, fill: "none", stroke: "currentColor" }))) : null));
12
+ return (React.createElement("div", { style: { flexShrink: 0, width: treeAreaWidth } }, bar ? (React.createElement("svg", { width: treeAreaWidth, height: h, style: { display: 'block' }, color: theme.palette.text.primary },
13
+ React.createElement("text", { x: marginLeft, y: h - 9, fontSize: 10, fill: "currentColor" }, bar.label),
14
+ React.createElement("path", { d: `M${marginLeft} ${h - 7} v6 h${bar.px} v-6`, fill: "none", stroke: "currentColor" }))) : null));
19
15
  });
20
16
  export default TreeRuler;
21
17
  //# sourceMappingURL=TreeRuler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TreeRuler.js","sourceRoot":"","sources":["../../../src/components/tree/TreeRuler.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAI9C,MAAM,UAAU,GAAG,EAAE,CAAA;AAErB,+EAA+E;AAC/E,8EAA8E;AAC9E,wEAAwE;AACxE,gFAAgF;AAChF,6BAA6B;AAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,EAAE,KAAK,EAA2B,EAAE,EAAE;IAChE,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,GACvE,KAAK,CAAA;IACP,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IACxB,MAAM,KAAK,GAAG,aAAa,GAAG,iBAAiB,CAAA;IAC/C,MAAM,GAAG,GAAG,cAAc,CAAC,iBAAiB,EAAE,aAAa,GAAG,UAAU,GAAG,CAAC,CAAC,CAAA;IAE7E,OAAO,CACL,6BAAK,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,IACjC,GAAG,CAAC,CAAC,CAAC,CACL,6BACE,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAC3B,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO;QAEjC,8BACE,CAAC,EAAE,UAAU,EACb,CAAC,EAAE,UAAU,GAAG,CAAC,EACjB,QAAQ,EAAE,EAAE,EACZ,IAAI,EAAC,cAAc,IAElB,GAAG,CAAC,KAAK,CACL;QACP,8BACE,CAAC,EAAE,IAAI,UAAU,IAAI,UAAU,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,MAAM,EACvD,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,GACrB,CACE,CACP,CAAC,CAAC,CAAC,IAAI,CACJ,CACP,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"TreeRuler.js","sourceRoot":"","sources":["../../../src/components/tree/TreeRuler.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,OAAO,EAAE,kBAAkB,IAAI,CAAC,EAAE,MAAM,oBAAoB,CAAA;AAI5D,4EAA4E;AAC5E,2EAA2E;AAC3E,yEAAyE;AACzE,UAAU;AACV,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,EAAE,KAAK,EAA2B,EAAE,EAAE;IAChE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,KAAK,CAAA;IAC9D,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IAExB,OAAO,CACL,6BAAK,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,IAChD,GAAG,CAAC,CAAC,CAAC,CACL,6BACE,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAC3B,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO;QAEjC,8BAAM,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAC,cAAc,IAC7D,GAAG,CAAC,KAAK,CACL;QACP,8BACE,CAAC,EAAE,IAAI,UAAU,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE,MAAM,EAC9C,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,GACrB,CACE,CACP,CAAC,CAAC,CAAC,IAAI,CACJ,CACP,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,SAAS,CAAA"}
@@ -0,0 +1,25 @@
1
+ import type { ResolvedClade } from '../../types.ts';
2
+ export declare const bracketBarWidth = 3;
3
+ export declare const bracketGap = 4;
4
+ export declare const maxCladeGutterWidth = 140;
5
+ /** whether a clade draws in the gutter: a bracket, or a highlight with a label */
6
+ export declare function cladeInGutter(clade: ResolvedClade): boolean;
7
+ /** the pixel height of the rows a clade covers */
8
+ export declare function cladeHeight(clade: ResolvedClade, rowHeight: number): number;
9
+ /**
10
+ * Whether a label reads across the rows. It does where they are taller than the
11
+ * font, and runs up the bar where they are not.
12
+ */
13
+ export declare function cladeLabelHorizontal(clade: ResolvedClade, rowHeight: number, fontSize: number): boolean;
14
+ /** the px between the left edge of the gutter and the label's own column */
15
+ export declare function cladeLabelOffset(clade: ResolvedClade): number;
16
+ /**
17
+ * The gutter the bracket mark needs at the right of the tree area: the bar plus
18
+ * the widest label at the tree font, zero where no clade draws there, and at
19
+ * most maxCladeGutterWidth.
20
+ */
21
+ export declare function cladeGutterWidth({ clades, rowHeight, fontSize, }: {
22
+ clades: ResolvedClade[];
23
+ rowHeight: number;
24
+ fontSize: number;
25
+ }): number;
@@ -0,0 +1,51 @@
1
+ import { measureTextCanvas } from '../../measureTextCanvas.js';
2
+ // The bar of the bracket mark and the space around it, in px.
3
+ export const bracketBarWidth = 3;
4
+ export const bracketGap = 4;
5
+ // The widest gutter the bracket mark takes. A longer label is clipped, so one
6
+ // long name cannot squeeze the tree it annotates.
7
+ export const maxCladeGutterWidth = 140;
8
+ /** whether a clade draws in the gutter: a bracket, or a highlight with a label */
9
+ export function cladeInGutter(clade) {
10
+ return (clade.mark === 'bracket' || (clade.mark === 'highlight' && !!clade.label));
11
+ }
12
+ /** the pixel height of the rows a clade covers */
13
+ export function cladeHeight(clade, rowHeight) {
14
+ return (clade.rows[1] - clade.rows[0] + 1) * rowHeight;
15
+ }
16
+ /**
17
+ * Whether a label reads across the rows. It does where they are taller than the
18
+ * font, and runs up the bar where they are not.
19
+ */
20
+ export function cladeLabelHorizontal(clade, rowHeight, fontSize) {
21
+ return cladeHeight(clade, rowHeight) >= fontSize;
22
+ }
23
+ /** the px between the left edge of the gutter and the label's own column */
24
+ export function cladeLabelOffset(clade) {
25
+ return clade.mark === 'bracket'
26
+ ? bracketGap + bracketBarWidth + bracketGap
27
+ : bracketGap;
28
+ }
29
+ /**
30
+ * The gutter the bracket mark needs at the right of the tree area: the bar plus
31
+ * the widest label at the tree font, zero where no clade draws there, and at
32
+ * most maxCladeGutterWidth.
33
+ */
34
+ export function cladeGutterWidth({ clades, rowHeight, fontSize, }) {
35
+ let widest = 0;
36
+ for (const clade of clades) {
37
+ if (!cladeInGutter(clade)) {
38
+ continue;
39
+ }
40
+ const text = clade.label
41
+ ? cladeLabelHorizontal(clade, rowHeight, fontSize)
42
+ ? measureTextCanvas(clade.label, fontSize)
43
+ : fontSize
44
+ : 0;
45
+ widest = Math.max(widest, cladeLabelOffset(clade) + text + bracketGap);
46
+ }
47
+ // a whole pixel, so the room the renderers measure against covers the label
48
+ // the measurement here sized the gutter for
49
+ return Math.min(maxCladeGutterWidth, Math.ceil(widest));
50
+ }
51
+ //# sourceMappingURL=cladeBrackets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cladeBrackets.js","sourceRoot":"","sources":["../../../src/components/tree/cladeBrackets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAI9D,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAA;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAA;AAE3B,8EAA8E;AAC9E,kDAAkD;AAClD,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAA;AAEtC,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,KAAoB;IAChD,OAAO,CACL,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAC1E,CAAA;AACH,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,WAAW,CAAC,KAAoB,EAAE,SAAiB;IACjE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAA;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAoB,EACpB,SAAiB,EACjB,QAAgB;IAEhB,OAAO,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,QAAQ,CAAA;AAClD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB,CAAC,KAAoB;IACnD,OAAO,KAAK,CAAC,IAAI,KAAK,SAAS;QAC7B,CAAC,CAAC,UAAU,GAAG,eAAe,GAAG,UAAU;QAC3C,CAAC,CAAC,UAAU,CAAA;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,MAAM,EACN,SAAS,EACT,QAAQ,GAKT;IACC,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,SAAQ;QACV,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK;YACtB,CAAC,CAAC,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;gBAChD,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAC1C,CAAC,CAAC,QAAQ;YACZ,CAAC,CAAC,CAAC,CAAA;QACL,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,UAAU,CAAC,CAAA;IACxE,CAAC;IACD,4EAA4E;IAC5E,4CAA4C;IAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;AACzD,CAAC"}
@@ -6,8 +6,8 @@ import { DialogContent } from '@mui/material';
6
6
  import { observer } from 'mobx-react';
7
7
  import SequenceTextArea from '../../SequenceTextArea.js';
8
8
  const TreeNodeInfoDialog = observer(function ({ info, model, nodeName, onClose, }) {
9
- const { treeMetadata, rows } = model;
10
- const metadata = treeMetadata[nodeName];
9
+ const { rows } = model;
10
+ const metadata = model.rowDataOf(nodeName);
11
11
  const res = rows.find(f => f[0] === nodeName);
12
12
  return (React.createElement(Dialog, { onClose: () => {
13
13
  onClose();
@@ -1 +1 @@
1
- {"version":3,"file":"TreeNodeInfoDialog.js","sourceRoot":"","sources":["../../../../src/components/tree/dialogs/TreeNodeInfoDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,UAAU,MAAM,8DAA8D,CAAA;AACrF,OAAO,QAAQ,MAAM,4DAA4D,CAAA;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,OAAO,gBAAgB,MAAM,2BAA4B,CAAA;AAIzD,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,EAC5C,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,OAAO,GAMR;IACC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAA;IAC7C,OAAO,CACL,oBAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,EAAE,CAAA;QACX,CAAC,EACD,IAAI,QACJ,KAAK,EAAC,gBAAgB,EACtB,QAAQ,EAAC,IAAI;QAEb,oBAAC,aAAa;YACZ,oBAAC,QAAQ,IAAC,KAAK,EAAC,YAAY;gBAC1B,oBAAC,UAAU,IAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAI,CACxC;YACX,oBAAC,QAAQ,IAAC,KAAK,EAAC,UAAU,IACvB,GAAG,CAAC,CAAC,CAAC,CACL,oBAAC,gBAAgB,IAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAI,CACjC,CAAC,CAAC,CAAC,CACF,sDAA6B,CAC9B,CACQ;YACV,QAAQ,CAAC,CAAC,CAAC,CACV,oBAAC,QAAQ,IAAC,KAAK,EAAC,gBAAgB;gBAC9B,oBAAC,UAAU,IAAC,UAAU,EAAE,QAAQ,GAAI,CAC3B,CACZ,CAAC,CAAC,CAAC,IAAI,CACM,CACT,CACV,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,kBAAkB,CAAA"}
1
+ {"version":3,"file":"TreeNodeInfoDialog.js","sourceRoot":"","sources":["../../../../src/components/tree/dialogs/TreeNodeInfoDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,UAAU,MAAM,8DAA8D,CAAA;AACrF,OAAO,QAAQ,MAAM,4DAA4D,CAAA;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,OAAO,gBAAgB,MAAM,2BAA4B,CAAA;AAIzD,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,EAC5C,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,OAAO,GAMR;IACC,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAA;IAC7C,OAAO,CACL,oBAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,EAAE,CAAA;QACX,CAAC,EACD,IAAI,QACJ,KAAK,EAAC,gBAAgB,EACtB,QAAQ,EAAC,IAAI;QAEb,oBAAC,aAAa;YACZ,oBAAC,QAAQ,IAAC,KAAK,EAAC,YAAY;gBAC1B,oBAAC,UAAU,IAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAI,CACxC;YACX,oBAAC,QAAQ,IAAC,KAAK,EAAC,UAAU,IACvB,GAAG,CAAC,CAAC,CAAC,CACL,oBAAC,gBAAgB,IAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAI,CACjC,CAAC,CAAC,CAAC,CACF,sDAA6B,CAC9B,CACQ;YACV,QAAQ,CAAC,CAAC,CAAC,CACV,oBAAC,QAAQ,IAAC,KAAK,EAAC,gBAAgB;gBAC9B,oBAAC,UAAU,IAAC,UAAU,EAAE,QAAQ,GAAI,CAC3B,CACZ,CAAC,CAAC,CAAC,IAAI,CACM,CACT,CACV,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,kBAAkB,CAAA"}
@@ -1,7 +1,8 @@
1
- import { calcDepthToLeaf } from '../../hierarchy.js';
1
+ import { calcDepthToLeaf, nodeCoveringRows } from '../../hierarchy.js';
2
2
  import { setFontSize } from '../../setFontSize.js';
3
3
  import { getVisibleLeaves } from '../getVisibleLeaves.js';
4
4
  import { drawHighlightLabel, highlightLabelHeight, highlightRowFill, } from '../msa/renderHighlights.js';
5
+ import { bracketBarWidth, bracketGap } from './cladeBrackets.js';
5
6
  const radius = 2.5;
6
7
  const d = radius * 2;
7
8
  // How far outside a block a node's row-center can sit and still draw into it: a
@@ -17,12 +18,12 @@ function inYBlock(y, offsetY, by, pad) {
17
18
  }
18
19
  /**
19
20
  * Every node whose subtree reaches into the block, skipping the subtrees that
20
- * do not. A subtree's leaves are one contiguous run of rows -- clusterLayout
21
- * records the run as xMin/xMax -- so a block of a 200k-tip tree visits a few
22
- * dozen nodes instead of every one of them, three times over.
21
+ * do not. A subtree's leaves are one contiguous run of rows, recorded by
22
+ * clusterLayout as xMin/xMax, so a block of a 200k-tip tree visits a few dozen
23
+ * nodes.
23
24
  *
24
- * A link out of a visited node is still drawn even when the child it reaches is
25
- * pruned, which is what keeps a branch that crosses the block from vanishing.
25
+ * A link out of a visited node is drawn even when its child is pruned, so a
26
+ * branch crossing the block stays visible.
26
27
  */
27
28
  function forEachNodeInBlock(root, offsetY, by, pad, cb) {
28
29
  const top = offsetY - pad;
@@ -57,9 +58,10 @@ export function getNodeX(node, showBranchLen, tipX, maxDepthToLeaf) {
57
58
  return ((maxDepthToLeaf - depthToLeaf) / maxDepthToLeaf) * tipX;
58
59
  }
59
60
  function renderTree({ offsetY, ctx, model, theme, tipX, maxDepthToLeaf, blockSizeYOverride, }) {
60
- const { hierarchy, showBranchLenEffective: showBranchLen, blockSize } = model;
61
+ const { hierarchy, showBranchLenEffective: showBranchLen, blockSize, branchColors, } = model;
61
62
  const by = blockSizeYOverride ?? blockSize;
62
- ctx.strokeStyle = theme.palette.text.primary;
63
+ const defaultStroke = theme.palette.text.primary;
64
+ ctx.strokeStyle = defaultStroke;
63
65
  forEachNodeInBlock(hierarchy, offsetY, by, blockPad(model), source => {
64
66
  const sy = source.x;
65
67
  const sx = getNodeX(source, showBranchLen, tipX, maxDepthToLeaf);
@@ -78,6 +80,10 @@ function renderTree({ offsetY, ctx, model, theme, tipX, maxDepthToLeaf, blockSiz
78
80
  // optimization that allows us to skip drawing most tree links outside the
79
81
  // block
80
82
  if (offsetY + by >= y1 && y2 >= offsetY) {
83
+ // the edge belongs to the child, whose id the branch channel colors
84
+ if (branchColors) {
85
+ ctx.strokeStyle = branchColors.get(target.data.id) ?? defaultStroke;
86
+ }
81
87
  ctx.beginPath();
82
88
  ctx.moveTo(sx, sy);
83
89
  ctx.lineTo(sx, ty);
@@ -86,9 +92,10 @@ function renderTree({ offsetY, ctx, model, theme, tipX, maxDepthToLeaf, blockSiz
86
92
  }
87
93
  }
88
94
  });
95
+ ctx.strokeStyle = defaultStroke;
89
96
  }
90
97
  function renderCollapsedTriangles({ ctx, clickMap, offsetY, model, theme, tipX, maxDepthToLeaf, blockSizeYOverride, collapsedSet, }) {
91
- const { hierarchy, showBranchLenEffective: showBranchLen, blockSize, rowHeight, fontSize, marginLeft: ml, } = model;
98
+ const { hierarchy, showBranchLenEffective: showBranchLen, blockSize, rowHeight, fontSize, marginLeft: ml, branchColors, } = model;
92
99
  // nothing collapsed is the common case, and the traversal below visits every
93
100
  // node in the tree on every block of every redraw
94
101
  if (collapsedSet.size === 0) {
@@ -111,7 +118,7 @@ function renderCollapsedTriangles({ ctx, clickMap, offsetY, model, theme, tipX,
111
118
  ctx.lineTo(baseX, y - halfHeight);
112
119
  ctx.lineTo(baseX, y + halfHeight);
113
120
  ctx.closePath();
114
- ctx.fillStyle = theme.palette.action.disabled;
121
+ ctx.fillStyle = branchColors?.get(id) ?? theme.palette.action.disabled;
115
122
  ctx.fill();
116
123
  ctx.strokeStyle = theme.palette.text.primary;
117
124
  ctx.stroke();
@@ -141,7 +148,7 @@ function renderCollapsedTriangles({ ctx, clickMap, offsetY, model, theme, tipX,
141
148
  }
142
149
  // the bubbles are click targets whether or not they are painted, so this pass
143
150
  // always runs and `draw` only decides whether it also strokes the circles
144
- function renderNodeBubbles({ ctx, clickMap, offsetY, model, tipX, maxDepthToLeaf, blockSizeYOverride, collapsedSet, draw, }) {
151
+ function renderNodeBubbles({ ctx, theme, clickMap, offsetY, model, tipX, maxDepthToLeaf, blockSizeYOverride, collapsedSet, draw, }) {
145
152
  const { hierarchy, showBranchLenEffective: showBranchLen, blockSize, marginLeft: ml, } = model;
146
153
  const by = blockSizeYOverride ?? blockSize;
147
154
  forEachNodeInBlock(hierarchy, offsetY, by, blockPad(model), node => {
@@ -155,8 +162,10 @@ function renderNodeBubbles({ ctx, clickMap, offsetY, model, tipX, maxDepthToLeaf
155
162
  if (node.height >= 1 && inYBlock(y, offsetY, by, blockPad(model))) {
156
163
  const isCollapsed = collapsedSet.has(id);
157
164
  if (draw) {
158
- ctx.strokeStyle = 'black';
159
- ctx.fillStyle = isCollapsed ? 'black' : 'white';
165
+ ctx.strokeStyle = theme.palette.text.primary;
166
+ ctx.fillStyle = isCollapsed
167
+ ? theme.palette.text.primary
168
+ : theme.palette.background.default;
160
169
  ctx.beginPath();
161
170
  ctx.arc(x, y, radius, 0, 2 * Math.PI);
162
171
  ctx.fill();
@@ -178,8 +187,33 @@ function renderNodeBubbles({ ctx, clickMap, offsetY, model, tipX, maxDepthToLeaf
178
187
  }
179
188
  });
180
189
  }
190
+ // The label a newick file puts on an internal node, which is where a bootstrap
191
+ // or posterior support value lands: ((A,B)95,(C,D)80);. withId falls back to the
192
+ // path-derived id for an unnamed node, so a node whose name is its id has no
193
+ // label of its own and an ungated pass prints node-0-1-1 across the tree.
194
+ function renderNodeLabels({ ctx, theme, offsetY, model, tipX, maxDepthToLeaf, blockSizeYOverride, }) {
195
+ const { hierarchy, showBranchLenEffective: showBranchLen, blockSize, fontSize, } = model;
196
+ const by = blockSizeYOverride ?? blockSize;
197
+ const pad = blockPad(model);
198
+ setFontSize(ctx, Math.max(6, fontSize - 3));
199
+ ctx.fillStyle = theme.palette.text.primary;
200
+ ctx.textAlign = 'right';
201
+ forEachNodeInBlock(hierarchy, offsetY, by, pad, node => {
202
+ const { id, name } = node.data;
203
+ if (node.height < 1 || name === id) {
204
+ return;
205
+ }
206
+ const x = getNodeX(node, showBranchLen, tipX, maxDepthToLeaf);
207
+ const y = node.x;
208
+ if (x !== undefined && inYBlock(y, offsetY, by, pad)) {
209
+ ctx.fillText(name, x - radius - 1, y - radius - 1);
210
+ }
211
+ });
212
+ ctx.textAlign = 'start';
213
+ setFontSize(ctx, fontSize);
214
+ }
181
215
  function renderTreeLabels({ theme, model, offsetY, ctx, clickMap, tipX, maxDepthToLeaf, blockSizeYOverride, collapsedSet, }) {
182
- const { fontSize, showBranchLenEffective: showBranchLen, treeMetadata, blockSize, labelsAlignRight, drawTree, treeAreaWidthMinusMargin, marginLeft, noTree, labelWidthMap, labelWidthScale, } = model;
216
+ const { fontSize, showBranchLenEffective: showBranchLen, tipLabelColors, blockSize, labelsAlignRight, drawTree, treeAreaWidthMinusMargin, marginLeft, noTree, labelWidthMap, labelWidthScale, } = model;
183
217
  const by = blockSizeYOverride ?? blockSize;
184
218
  // labels only exist for leaves, which are laid out top to bottom, so take the
185
219
  // same slice the MSA renderer uses instead of walking every tip per block
@@ -197,7 +231,7 @@ function renderTreeLabels({ theme, model, offsetY, ctx, clickMap, tipX, maxDepth
197
231
  for (const node of visibleLeaves) {
198
232
  const { data: { name, id }, } = node;
199
233
  const y = node.x;
200
- const displayName = treeMetadata[name]?.genome || name;
234
+ const displayName = model.rowDataOf(name)?.genome || name;
201
235
  // a collapsed clade is drawn as a triangle + tip count; suppress its leaf
202
236
  // label when the "name" is just the auto-generated internal-node id
203
237
  const isAnonymousCollapsed = collapsedSet.has(id) && name === id;
@@ -212,7 +246,7 @@ function renderTreeLabels({ theme, model, offsetY, ctx, clickMap, tipX, maxDepth
212
246
  const width = measured === undefined
213
247
  ? ctx.measureText(displayName).width
214
248
  : measured * labelWidthScale;
215
- ctx.fillStyle = theme.palette.text.primary;
249
+ ctx.fillStyle = tipLabelColors?.get(name) ?? theme.palette.text.primary;
216
250
  if (labelsAlignRight) {
217
251
  const smallPadding = 2;
218
252
  const offset = treeAreaWidthMinusMargin - smallPadding;
@@ -254,22 +288,101 @@ function renderTreeLabels({ theme, model, offsetY, ctx, clickMap, tipX, maxDepth
254
288
  }
255
289
  ctx.setLineDash([]);
256
290
  }
257
- // the row sets of `highlights`, tinted across the tree area under the labels
258
- // with the label in the gutter at the first row of each set
291
+ // the first row of a set, as a loop: spreading into Math.min passes one
292
+ // argument per row, and the ~125k argument limit throws RangeError on a set
293
+ // covering the 230k-tip COVID tree
294
+ function firstRow(rowIndices) {
295
+ let min = Infinity;
296
+ for (const index of rowIndices) {
297
+ if (index < min) {
298
+ min = index;
299
+ }
300
+ }
301
+ return min;
302
+ }
303
+ // the highlight mark of the `clades` layer: a translucent rectangle from the
304
+ // clade's common ancestor to the right edge of the tree area, under the
305
+ // branches. A clade spanning hundreds of rows crosses several blocks, so each
306
+ // block draws the whole rectangle and the canvas takes the part that is its.
307
+ function renderCladeHighlights({ ctx, model, offsetY, tipX, maxDepthToLeaf, blockSizeYOverride, }) {
308
+ const { resolvedClades, hierarchy, showBranchLenEffective: showBranchLen, rowHeight, treeAreaWidth, marginLeft, blockSize, } = model;
309
+ const by = blockSizeYOverride ?? blockSize;
310
+ const right = treeAreaWidth - marginLeft;
311
+ for (const { rows, color, mark } of resolvedClades) {
312
+ if (mark !== 'highlight') {
313
+ continue;
314
+ }
315
+ const top = rows[0] * rowHeight;
316
+ const bottom = (rows[1] + 1) * rowHeight;
317
+ if (bottom < offsetY || top > offsetY + by) {
318
+ continue;
319
+ }
320
+ const node = nodeCoveringRows(hierarchy, top + rowHeight / 2, bottom - rowHeight / 2);
321
+ const x = getNodeX(node, showBranchLen, tipX, maxDepthToLeaf) ?? 0;
322
+ ctx.fillStyle = color;
323
+ ctx.fillRect(x, top, right - x, bottom - top);
324
+ }
325
+ }
326
+ // the bar of the bracket mark, in the gutter `cladeGutterWidth` reserves at the
327
+ // right of the tree area. The label beside it is DOM text on screen and a
328
+ // <text> in the export, since the canvas layer has no rotation.
329
+ function renderCladeBrackets({ ctx, model, theme, offsetY, blockSizeYOverride, }) {
330
+ const { resolvedClades, cladeGutterWidth, rowHeight, treeAreaWidth, marginLeft, blockSize, } = model;
331
+ if (cladeGutterWidth === 0) {
332
+ return;
333
+ }
334
+ const by = blockSizeYOverride ?? blockSize;
335
+ const x = treeAreaWidth -
336
+ marginLeft -
337
+ cladeGutterWidth +
338
+ bracketGap +
339
+ bracketBarWidth / 2;
340
+ ctx.lineWidth = bracketBarWidth;
341
+ for (const { rows, mark, markColor } of resolvedClades) {
342
+ const top = rows[0] * rowHeight + 1;
343
+ const bottom = (rows[1] + 1) * rowHeight - 1;
344
+ if (mark !== 'bracket' || bottom < offsetY || top > offsetY + by) {
345
+ continue;
346
+ }
347
+ ctx.strokeStyle = markColor ?? theme.palette.text.primary;
348
+ ctx.beginPath();
349
+ ctx.moveTo(x, top);
350
+ ctx.lineTo(x, bottom);
351
+ ctx.stroke();
352
+ }
353
+ ctx.lineWidth = 1;
354
+ ctx.strokeStyle = theme.palette.text.primary;
355
+ }
356
+ // the `rowTint` encoding and the row sets of `highlights`, washed across the
357
+ // tree area under the labels, with each set's label in the gutter at its first
358
+ // row
259
359
  function renderRowHighlights({ ctx, model, theme, offsetY, blockSizeYOverride, }) {
260
- const { resolvedHighlights, rowHeight, treeAreaWidth, marginLeft, blockSize, } = model;
360
+ const { resolvedHighlights, rowTints, rowHeight, treeAreaWidth, marginLeft, blockSize, } = model;
261
361
  const by = blockSizeYOverride ?? blockSize;
262
362
  const pad = blockPad(model);
263
363
  const placed = [];
364
+ const fillRow = (index) => {
365
+ ctx.fillRect(-marginLeft, index * rowHeight, treeAreaWidth, rowHeight);
366
+ };
367
+ if (rowTints) {
368
+ const top = Math.max(0, Math.floor((offsetY - pad) / rowHeight));
369
+ const bottom = Math.min(rowTints.length - 1, Math.ceil((offsetY + by + pad) / rowHeight));
370
+ for (let index = top; index <= bottom; index++) {
371
+ const color = rowTints[index];
372
+ if (color) {
373
+ ctx.fillStyle = color;
374
+ fillRow(index);
375
+ }
376
+ }
377
+ }
264
378
  for (const { rowIndices, label, color } of resolvedHighlights) {
265
379
  ctx.fillStyle = color ?? highlightRowFill;
266
380
  for (const index of rowIndices) {
267
- const y = index * rowHeight;
268
- if (inYBlock(y + rowHeight / 2, offsetY, by, pad)) {
269
- ctx.fillRect(-marginLeft, y, treeAreaWidth, rowHeight);
381
+ if (inYBlock(index * rowHeight + rowHeight / 2, offsetY, by, pad)) {
382
+ fillRow(index);
270
383
  }
271
384
  }
272
- const first = Math.min(...rowIndices);
385
+ const first = firstRow(rowIndices);
273
386
  if (label &&
274
387
  rowIndices.length &&
275
388
  inYBlock(first * rowHeight, offsetY, by, pad)) {
@@ -289,7 +402,7 @@ function renderRowHighlights({ ctx, model, theme, offsetY, blockSizeYOverride, }
289
402
  export function renderTreeCanvas({ model, clickMap, ctx, offsetY, theme, highResScaleFactorOverride, blockSizeYOverride, }) {
290
403
  clickMap?.clear();
291
404
  // Defer the finish call until after all inserts are done
292
- const { noTree, drawTree, drawNodeBubbles, highResScaleFactor, fontSize, showTreeText, marginLeft,
405
+ const { noTree, drawTree, drawNodeBubbles, drawNodeLabels, highResScaleFactor, fontSize, showTreeText, marginLeft,
293
406
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
294
407
  rowHeight: _rowHeight, // read so the draw autorun re-fires after a zoom change
295
408
  } = model;
@@ -310,6 +423,14 @@ export function renderTreeCanvas({ model, clickMap, ctx, offsetY, theme, highRes
310
423
  // built once for all three passes: each of them asks about a different node on
311
424
  // every block of every redraw, and `collapsed` is a list
312
425
  const collapsedSet = new Set(model.collapsed);
426
+ renderCladeHighlights({
427
+ ctx,
428
+ model,
429
+ offsetY,
430
+ tipX,
431
+ maxDepthToLeaf,
432
+ blockSizeYOverride,
433
+ });
313
434
  renderRowHighlights({ ctx, model, theme, offsetY, blockSizeYOverride });
314
435
  setFontSize(ctx, fontSize);
315
436
  if (!noTree && drawTree) {
@@ -335,6 +456,7 @@ export function renderTreeCanvas({ model, clickMap, ctx, offsetY, theme, highRes
335
456
  });
336
457
  renderNodeBubbles({
337
458
  ctx,
459
+ theme,
338
460
  offsetY,
339
461
  clickMap,
340
462
  model,
@@ -344,6 +466,17 @@ export function renderTreeCanvas({ model, clickMap, ctx, offsetY, theme, highRes
344
466
  collapsedSet,
345
467
  draw: drawNodeBubbles,
346
468
  });
469
+ if (drawNodeLabels) {
470
+ renderNodeLabels({
471
+ ctx,
472
+ theme,
473
+ offsetY,
474
+ model,
475
+ tipX,
476
+ maxDepthToLeaf,
477
+ blockSizeYOverride,
478
+ });
479
+ }
347
480
  }
348
481
  if (showTreeText) {
349
482
  renderTreeLabels({
@@ -358,6 +491,7 @@ export function renderTreeCanvas({ model, clickMap, ctx, offsetY, theme, highRes
358
491
  collapsedSet,
359
492
  });
360
493
  }
494
+ renderCladeBrackets({ ctx, model, theme, offsetY, blockSizeYOverride });
361
495
  // Finish the index so it's ready for queries
362
496
  clickMap?.finish();
363
497
  }