react-msaview 6.5.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) hide show
  1. package/README.md +13 -11
  2. package/bundle/index.js +122 -112
  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 +2 -2
  13. package/dist/components/Loading.js.map +1 -1
  14. package/dist/components/MSAView.js +17 -6
  15. package/dist/components/MSAView.js.map +1 -1
  16. package/dist/components/MSAViewer.d.ts +69 -4
  17. package/dist/components/MSAViewer.js +201 -8
  18. package/dist/components/MSAViewer.js.map +1 -1
  19. package/dist/components/PortalTooltip.d.ts +11 -0
  20. package/dist/components/PortalTooltip.js +29 -0
  21. package/dist/components/PortalTooltip.js.map +1 -0
  22. package/dist/components/ResizeHandles.d.ts +3 -3
  23. package/dist/components/ResizeHandles.js +13 -24
  24. package/dist/components/ResizeHandles.js.map +1 -1
  25. package/dist/components/SequenceTextArea.js +3 -3
  26. package/dist/components/SequenceTextArea.js.map +1 -1
  27. package/dist/components/Track.js +41 -22
  28. package/dist/components/Track.js.map +1 -1
  29. package/dist/components/dialogs/{InterProScanDialog.d.ts → AnnotationFileDialog.d.ts} +2 -2
  30. package/dist/components/dialogs/AnnotationFileDialog.js +92 -0
  31. package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -0
  32. package/dist/components/dialogs/ExportSVGDialog.js +5 -3
  33. package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
  34. package/dist/components/dialogs/FeatureDialog.js +13 -9
  35. package/dist/components/dialogs/FeatureDialog.js.map +1 -1
  36. package/dist/components/dialogs/TrackInfoDialog.js +1 -1
  37. package/dist/components/dialogs/TrackInfoDialog.js.map +1 -1
  38. package/dist/components/header/GappynessSlider.js +6 -11
  39. package/dist/components/header/GappynessSlider.js.map +1 -1
  40. package/dist/components/header/Header.js +7 -0
  41. package/dist/components/header/Header.js.map +1 -1
  42. package/dist/components/header/HeaderStatusArea.js +0 -2
  43. package/dist/components/header/HeaderStatusArea.js.map +1 -1
  44. package/dist/components/header/LoadWarnings.d.ts +6 -0
  45. package/dist/components/header/LoadWarnings.js +35 -0
  46. package/dist/components/header/LoadWarnings.js.map +1 -0
  47. package/dist/components/header/MultiAlignmentSelector.js +0 -0
  48. package/dist/components/header/MultiAlignmentSelector.js.map +1 -1
  49. package/dist/components/header/ScrollZoomIcons.d.ts +6 -0
  50. package/dist/components/header/ScrollZoomIcons.js +35 -0
  51. package/dist/components/header/ScrollZoomIcons.js.map +1 -0
  52. package/dist/components/header/TreeSettingsMenu.js +7 -1
  53. package/dist/components/header/TreeSettingsMenu.js.map +1 -1
  54. package/dist/components/header/UnshareableDataWarning.d.ts +6 -0
  55. package/dist/components/header/UnshareableDataWarning.js +40 -0
  56. package/dist/components/header/UnshareableDataWarning.js.map +1 -0
  57. package/dist/components/header/ZoomControls.js +49 -6
  58. package/dist/components/header/ZoomControls.js.map +1 -1
  59. package/dist/components/header/getAnnotationsMenu.js +11 -14
  60. package/dist/components/header/getAnnotationsMenu.js.map +1 -1
  61. package/dist/components/header/settingsMenuItems.js +10 -7
  62. package/dist/components/header/settingsMenuItems.js.map +1 -1
  63. package/dist/components/import/ImportForm.js +1 -1
  64. package/dist/components/import/ImportForm.js.map +1 -1
  65. package/dist/components/import/ImportFormExamples.js +2 -6
  66. package/dist/components/import/ImportFormExamples.js.map +1 -1
  67. package/dist/components/import/util.js +2 -0
  68. package/dist/components/import/util.js.map +1 -1
  69. package/dist/components/minimap/Minimap.js +1 -2
  70. package/dist/components/minimap/Minimap.js.map +1 -1
  71. package/dist/components/msa/AnnotationLegend.js +27 -19
  72. package/dist/components/msa/AnnotationLegend.js.map +1 -1
  73. package/dist/components/msa/MSACanvas.js +1 -1
  74. package/dist/components/msa/MSACanvas.js.map +1 -1
  75. package/dist/components/msa/MSACanvasBlock.js +17 -20
  76. package/dist/components/msa/MSACanvasBlock.js.map +1 -1
  77. package/dist/components/msa/MSAMouseoverCanvas.js +2 -1
  78. package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
  79. package/dist/components/msa/domainBandCursor.d.ts +7 -11
  80. package/dist/components/msa/domainBandCursor.js +7 -11
  81. package/dist/components/msa/domainBandCursor.js.map +1 -1
  82. package/dist/components/msa/drawFeatureSpans.d.ts +53 -0
  83. package/dist/components/msa/drawFeatureSpans.js +78 -0
  84. package/dist/components/msa/drawFeatureSpans.js.map +1 -0
  85. package/dist/components/msa/legendRows.d.ts +8 -0
  86. package/dist/components/msa/legendRows.js +16 -0
  87. package/dist/components/msa/legendRows.js.map +1 -0
  88. package/dist/components/msa/msaRaster.d.ts +30 -27
  89. package/dist/components/msa/msaRaster.js +193 -90
  90. package/dist/components/msa/msaRaster.js.map +1 -1
  91. package/dist/components/msa/packDomainLanes.d.ts +20 -0
  92. package/dist/components/msa/packDomainLanes.js +33 -0
  93. package/dist/components/msa/packDomainLanes.js.map +1 -0
  94. package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +3 -1
  95. package/dist/components/msa/renderBoxFeatureCanvasBlock.js +51 -87
  96. package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
  97. package/dist/components/msa/renderHighlights.d.ts +44 -4
  98. package/dist/components/msa/renderHighlights.js +99 -11
  99. package/dist/components/msa/renderHighlights.js.map +1 -1
  100. package/dist/components/msa/renderMSABlock.d.ts +1 -2
  101. package/dist/components/msa/renderMSABlock.js +28 -31
  102. package/dist/components/msa/renderMSABlock.js.map +1 -1
  103. package/dist/components/msa/renderMSAMouseover.js +9 -30
  104. package/dist/components/msa/renderMSAMouseover.js.map +1 -1
  105. package/dist/components/msa/tileColor.js +4 -7
  106. package/dist/components/msa/tileColor.js.map +1 -1
  107. package/dist/components/msa/useMsaBlockMouse.d.ts +5 -3
  108. package/dist/components/msa/useMsaBlockMouse.js +6 -6
  109. package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
  110. package/dist/components/renderCtx.d.ts +1 -1
  111. package/dist/components/rowpanels/RowPanelBlock.d.ts +9 -0
  112. package/dist/components/rowpanels/RowPanelBlock.js +86 -0
  113. package/dist/components/rowpanels/RowPanelBlock.js.map +1 -0
  114. package/dist/components/rowpanels/RowPanelHeaders.d.ts +12 -0
  115. package/dist/components/rowpanels/RowPanelHeaders.js +38 -0
  116. package/dist/components/rowpanels/RowPanelHeaders.js.map +1 -0
  117. package/dist/components/{msa/ColumnStats.d.ts → rowpanels/RowPanels.d.ts} +2 -2
  118. package/dist/components/rowpanels/RowPanels.js +32 -0
  119. package/dist/components/rowpanels/RowPanels.js.map +1 -0
  120. package/dist/components/rowpanels/headerLayout.d.ts +1 -0
  121. package/dist/components/rowpanels/headerLayout.js +5 -0
  122. package/dist/components/rowpanels/headerLayout.js.map +1 -0
  123. package/dist/components/rowpanels/renderFeaturePanel.d.ts +21 -0
  124. package/dist/components/rowpanels/renderFeaturePanel.js +37 -0
  125. package/dist/components/rowpanels/renderFeaturePanel.js.map +1 -0
  126. package/dist/components/rowpanels/renderRowPanel.d.ts +23 -0
  127. package/dist/components/rowpanels/renderRowPanel.js +22 -0
  128. package/dist/components/rowpanels/renderRowPanel.js.map +1 -0
  129. package/dist/components/rowpanels/renderStrip.d.ts +20 -0
  130. package/dist/components/rowpanels/renderStrip.js +26 -0
  131. package/dist/components/rowpanels/renderStrip.js.map +1 -0
  132. package/dist/components/tracks/TrackBlocks.js +13 -16
  133. package/dist/components/tracks/TrackBlocks.js.map +1 -1
  134. package/dist/components/tracks/TrackTooltipContent.d.ts +15 -0
  135. package/dist/components/tracks/TrackTooltipContent.js +109 -0
  136. package/dist/components/tracks/TrackTooltipContent.js.map +1 -0
  137. package/dist/components/tracks/drawTracks.d.ts +30 -12
  138. package/dist/components/tracks/drawTracks.js +127 -34
  139. package/dist/components/tracks/drawTracks.js.map +1 -1
  140. package/dist/components/tracks/useTrackHover.d.ts +22 -0
  141. package/dist/components/tracks/useTrackHover.js +30 -0
  142. package/dist/components/tracks/useTrackHover.js.map +1 -0
  143. package/dist/components/tree/CladeLabels.d.ts +12 -0
  144. package/dist/components/tree/CladeLabels.js +48 -0
  145. package/dist/components/tree/CladeLabels.js.map +1 -0
  146. package/dist/components/tree/TreeCanvas.js +6 -4
  147. package/dist/components/tree/TreeCanvas.js.map +1 -1
  148. package/dist/components/tree/TreeCanvasBlock.js +6 -21
  149. package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
  150. package/dist/components/tree/TreeOverview.d.ts +14 -0
  151. package/dist/components/tree/TreeOverview.js +75 -0
  152. package/dist/components/tree/TreeOverview.js.map +1 -0
  153. package/dist/components/tree/TreeRuler.js +11 -5
  154. package/dist/components/tree/TreeRuler.js.map +1 -1
  155. package/dist/components/tree/cladeBrackets.d.ts +25 -0
  156. package/dist/components/tree/cladeBrackets.js +51 -0
  157. package/dist/components/tree/cladeBrackets.js.map +1 -0
  158. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +2 -2
  159. package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
  160. package/dist/components/tree/renderTreeCanvas.d.ts +0 -1
  161. package/dist/components/tree/renderTreeCanvas.js +221 -47
  162. package/dist/components/tree/renderTreeCanvas.js.map +1 -1
  163. package/dist/components/tree/renderTreeOverview.d.ts +52 -0
  164. package/dist/components/tree/renderTreeOverview.js +138 -0
  165. package/dist/components/tree/renderTreeOverview.js.map +1 -0
  166. package/dist/components/tree/scaleBar.d.ts +10 -0
  167. package/dist/components/tree/scaleBar.js +24 -0
  168. package/dist/components/tree/scaleBar.js.map +1 -0
  169. package/dist/components/tree/useTreeHover.js +2 -4
  170. package/dist/components/tree/useTreeHover.js.map +1 -1
  171. package/dist/constants.d.ts +18 -1
  172. package/dist/constants.js +51 -8
  173. package/dist/constants.js.map +1 -1
  174. package/dist/createPaletteMap.d.ts +7 -6
  175. package/dist/createPaletteMap.js +10 -9
  176. package/dist/createPaletteMap.js.map +1 -1
  177. package/dist/element.d.ts +13 -0
  178. package/dist/element.js +269 -0
  179. package/dist/element.js.map +1 -0
  180. package/dist/featureFields.d.ts +11 -0
  181. package/dist/featureFields.js +17 -0
  182. package/dist/featureFields.js.map +1 -0
  183. package/dist/fetchUtils.d.ts +7 -7
  184. package/dist/fetchUtils.js +4 -32
  185. package/dist/fetchUtils.js.map +1 -1
  186. package/dist/flatToTree.js +1 -2
  187. package/dist/flatToTree.js.map +1 -1
  188. package/dist/ggplotPalettes.d.ts +10 -0
  189. package/dist/ggplotPalettes.js +58 -0
  190. package/dist/ggplotPalettes.js.map +1 -1
  191. package/dist/hierarchy.d.ts +29 -1
  192. package/dist/hierarchy.js +82 -19
  193. package/dist/hierarchy.js.map +1 -1
  194. package/dist/index.d.ts +10 -1
  195. package/dist/index.js +10 -2
  196. package/dist/index.js.map +1 -1
  197. package/dist/model/DataModel.js +4 -4
  198. package/dist/model/DataModel.js.map +1 -1
  199. package/dist/model/msaModel.d.ts +3 -2
  200. package/dist/model/msaModel.js +3 -2
  201. package/dist/model/msaModel.js.map +1 -1
  202. package/dist/model/treeModel.d.ts +30 -0
  203. package/dist/model/treeModel.js +37 -1
  204. package/dist/model/treeModel.js.map +1 -1
  205. package/dist/model.d.ts +792 -259
  206. package/dist/model.js +2092 -675
  207. package/dist/model.js.map +1 -1
  208. package/dist/mount.d.ts +11 -0
  209. package/dist/mount.js +22 -0
  210. package/dist/mount.js.map +1 -0
  211. package/dist/neighborJoining.js +8 -32
  212. package/dist/neighborJoining.js.map +1 -1
  213. package/dist/renderToStaticMarkup.d.ts +15 -13
  214. package/dist/renderToStaticMarkup.js +37 -25
  215. package/dist/renderToStaticMarkup.js.map +1 -1
  216. package/dist/renderToSvg.js +198 -68
  217. package/dist/renderToSvg.js.map +1 -1
  218. package/dist/rowCoordinateCalculations.d.ts +26 -28
  219. package/dist/rowCoordinateCalculations.js +13 -39
  220. package/dist/rowCoordinateCalculations.js.map +1 -1
  221. package/dist/scales.d.ts +22 -0
  222. package/dist/scales.js +30 -0
  223. package/dist/scales.js.map +1 -0
  224. package/dist/seqPosToGlobalCol.d.ts +2 -3
  225. package/dist/seqPosToGlobalCol.js +5 -4
  226. package/dist/seqPosToGlobalCol.js.map +1 -1
  227. package/dist/sequenceLogo.d.ts +6 -11
  228. package/dist/sequenceLogo.js +6 -11
  229. package/dist/sequenceLogo.js.map +1 -1
  230. package/dist/stripDefault.d.ts +7 -14
  231. package/dist/stripDefault.js +7 -14
  232. package/dist/stripDefault.js.map +1 -1
  233. package/dist/svgTestUtil.d.ts +306 -124
  234. package/dist/types.d.ts +295 -3
  235. package/dist/umd.d.ts +2 -0
  236. package/dist/umd.js +4 -2
  237. package/dist/umd.js.map +1 -1
  238. package/dist/useCanvasAutorun.d.ts +5 -10
  239. package/dist/useCanvasAutorun.js +5 -10
  240. package/dist/useCanvasAutorun.js.map +1 -1
  241. package/dist/useMsaSvgFigure.d.ts +20 -0
  242. package/dist/useMsaSvgFigure.js +46 -0
  243. package/dist/useMsaSvgFigure.js.map +1 -0
  244. package/dist/util.d.ts +10 -4
  245. package/dist/util.js +37 -10
  246. package/dist/util.js.map +1 -1
  247. package/dist/version.d.ts +1 -1
  248. package/dist/version.js +1 -1
  249. package/dist/wuss.d.ts +14 -0
  250. package/dist/wuss.js +55 -0
  251. package/dist/wuss.js.map +1 -0
  252. package/package.json +23 -14
  253. package/src/colorSchemes.ts +1 -2
  254. package/src/columnStats.ts +58 -0
  255. package/src/components/DragHandle.tsx +18 -7
  256. package/src/components/Loading.tsx +14 -8
  257. package/src/components/MSAView.tsx +19 -5
  258. package/src/components/MSAViewer.tsx +326 -10
  259. package/src/components/PortalTooltip.tsx +47 -0
  260. package/src/components/ResizeHandles.tsx +21 -36
  261. package/src/components/SequenceTextArea.tsx +3 -3
  262. package/src/components/Track.tsx +55 -18
  263. package/src/components/dialogs/AnnotationFileDialog.tsx +162 -0
  264. package/src/components/dialogs/ExportSVGDialog.tsx +7 -2
  265. package/src/components/dialogs/FeatureDialog.tsx +13 -9
  266. package/src/components/dialogs/TrackInfoDialog.tsx +1 -1
  267. package/src/components/header/GappynessSlider.tsx +6 -11
  268. package/src/components/header/Header.tsx +10 -0
  269. package/src/components/header/HeaderStatusArea.tsx +0 -5
  270. package/src/components/header/LoadWarnings.tsx +48 -0
  271. package/src/components/header/MultiAlignmentSelector.tsx +0 -0
  272. package/src/components/header/ScrollZoomIcons.tsx +52 -0
  273. package/src/components/header/TreeSettingsMenu.tsx +7 -1
  274. package/src/components/header/UnshareableDataWarning.tsx +56 -0
  275. package/src/components/header/ZoomControls.tsx +74 -14
  276. package/src/components/header/getAnnotationsMenu.ts +13 -17
  277. package/src/components/header/settingsMenuItems.ts +11 -6
  278. package/src/components/import/ImportForm.tsx +2 -2
  279. package/src/components/import/ImportFormExamples.tsx +4 -8
  280. package/src/components/import/util.ts +2 -0
  281. package/src/components/minimap/Minimap.tsx +1 -2
  282. package/src/components/msa/AnnotationLegend.tsx +48 -38
  283. package/src/components/msa/MSACanvas.tsx +3 -5
  284. package/src/components/msa/MSACanvasBlock.tsx +17 -21
  285. package/src/components/msa/MSAMouseoverCanvas.tsx +2 -1
  286. package/src/components/msa/domainBandCursor.ts +7 -11
  287. package/src/components/msa/drawFeatureSpans.ts +150 -0
  288. package/src/components/msa/legendRows.ts +24 -0
  289. package/src/components/msa/msaRaster.ts +236 -88
  290. package/src/components/msa/packDomainLanes.ts +36 -0
  291. package/src/components/msa/renderBoxFeatureCanvasBlock.ts +69 -123
  292. package/src/components/msa/renderHighlights.ts +141 -10
  293. package/src/components/msa/renderMSABlock.ts +29 -38
  294. package/src/components/msa/renderMSAMouseover.ts +9 -39
  295. package/src/components/msa/tileColor.ts +4 -7
  296. package/src/components/msa/useMsaBlockMouse.ts +6 -6
  297. package/src/components/renderCtx.ts +1 -0
  298. package/src/components/rowpanels/RowPanelBlock.tsx +139 -0
  299. package/src/components/rowpanels/RowPanelHeaders.tsx +57 -0
  300. package/src/components/rowpanels/RowPanels.tsx +77 -0
  301. package/src/components/rowpanels/headerLayout.ts +5 -0
  302. package/src/components/rowpanels/renderFeaturePanel.ts +66 -0
  303. package/src/components/rowpanels/renderRowPanel.ts +41 -0
  304. package/src/components/rowpanels/renderStrip.ts +46 -0
  305. package/src/components/tracks/TrackBlocks.tsx +13 -18
  306. package/src/components/tracks/TrackTooltipContent.tsx +156 -0
  307. package/src/components/tracks/drawTracks.ts +169 -38
  308. package/src/components/tracks/useTrackHover.ts +42 -0
  309. package/src/components/tree/CladeLabels.tsx +77 -0
  310. package/src/components/tree/TreeCanvas.tsx +4 -3
  311. package/src/components/tree/TreeCanvasBlock.tsx +10 -32
  312. package/src/components/tree/TreeOverview.tsx +106 -0
  313. package/src/components/tree/TreeRuler.tsx +29 -5
  314. package/src/components/tree/cladeBrackets.ts +73 -0
  315. package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +2 -2
  316. package/src/components/tree/renderTreeCanvas.ts +312 -48
  317. package/src/components/tree/renderTreeOverview.ts +212 -0
  318. package/src/components/tree/scaleBar.ts +23 -0
  319. package/src/components/tree/useTreeHover.ts +2 -4
  320. package/src/constants.ts +61 -8
  321. package/src/createPaletteMap.ts +10 -9
  322. package/src/element.ts +321 -0
  323. package/src/featureFields.ts +19 -0
  324. package/src/fetchUtils.ts +7 -40
  325. package/src/flatToTree.ts +1 -2
  326. package/src/ggplotPalettes.ts +60 -0
  327. package/src/hierarchy.ts +97 -20
  328. package/src/index.ts +46 -6
  329. package/src/model/DataModel.ts +5 -4
  330. package/src/model/msaModel.ts +3 -2
  331. package/src/model/treeModel.ts +42 -0
  332. package/src/model.ts +2492 -793
  333. package/src/mount.tsx +32 -0
  334. package/src/neighborJoining.ts +8 -32
  335. package/src/rawImports.d.ts +9 -0
  336. package/src/renderToStaticMarkup.ts +41 -25
  337. package/src/renderToSvg.tsx +365 -92
  338. package/src/rowCoordinateCalculations.ts +16 -62
  339. package/src/scales.ts +47 -0
  340. package/src/seqPosToGlobalCol.ts +5 -4
  341. package/src/sequenceLogo.ts +6 -11
  342. package/src/stripDefault.ts +7 -14
  343. package/src/types.ts +352 -12
  344. package/src/umd.ts +4 -2
  345. package/src/useCanvasAutorun.ts +5 -10
  346. package/src/useMsaSvgFigure.ts +72 -0
  347. package/src/util.ts +40 -14
  348. package/src/version.ts +1 -1
  349. package/src/wuss.ts +62 -0
  350. package/dist/components/dialogs/InterProScanDialog.js +0 -137
  351. package/dist/components/dialogs/InterProScanDialog.js.map +0 -1
  352. package/dist/components/dialogs/InterProScanFileDialog.d.ts +0 -7
  353. package/dist/components/dialogs/InterProScanFileDialog.js +0 -64
  354. package/dist/components/dialogs/InterProScanFileDialog.js.map +0 -1
  355. package/dist/components/msa/ColumnStats.js +0 -42
  356. package/dist/components/msa/ColumnStats.js.map +0 -1
  357. package/dist/launchInterProScan.d.ts +0 -13
  358. package/dist/launchInterProScan.js +0 -110
  359. package/dist/launchInterProScan.js.map +0 -1
  360. package/dist/useColorContrast.d.ts +0 -10
  361. package/dist/useColorContrast.js +0 -13
  362. package/dist/useColorContrast.js.map +0 -1
  363. package/src/clustalX.test.ts +0 -74
  364. package/src/colSpace.test.ts +0 -67
  365. package/src/collapseLogic.test.ts +0 -115
  366. package/src/colorSchemes.docs.test.ts +0 -57
  367. package/src/columnCounts.test.ts +0 -73
  368. package/src/columnStats.test.ts +0 -94
  369. package/src/columnTracks.test.ts +0 -97
  370. package/src/components/dialogs/InterProScanDialog.tsx +0 -214
  371. package/src/components/dialogs/InterProScanFileDialog.tsx +0 -138
  372. package/src/components/minimap/minimapLayout.test.ts +0 -71
  373. package/src/components/msa/ColumnStats.tsx +0 -54
  374. package/src/components/msa/msaRaster.test.ts +0 -145
  375. package/src/components/msa/renderBoxFeatureCanvasBlock.test.ts +0 -51
  376. package/src/components/tree/renderTreeCanvas.test.ts +0 -296
  377. package/src/dataInitialized.test.ts +0 -42
  378. package/src/domainBands.test.ts +0 -122
  379. package/src/domainLetterColor.test.ts +0 -80
  380. package/src/exportFileName.test.ts +0 -40
  381. package/src/fetchUtils.test.ts +0 -83
  382. package/src/flatToTree.test.ts +0 -51
  383. package/src/hierarchy.test.ts +0 -228
  384. package/src/highlights.test.ts +0 -70
  385. package/src/impgRender.test.tsx +0 -68
  386. package/src/largeTree.test.ts +0 -67
  387. package/src/launchInterProScan.ts +0 -167
  388. package/src/loadErrorDisplay.test.tsx +0 -102
  389. package/src/modelFilehandleLoaders.test.ts +0 -137
  390. package/src/modelReset.test.ts +0 -120
  391. package/src/neighborJoining.test.ts +0 -164
  392. package/src/parseAsn1.test.ts +0 -36
  393. package/src/propertyConservation.test.ts +0 -36
  394. package/src/renderColumnTracksSvg.test.tsx +0 -108
  395. package/src/renderDomainsSvg.test.tsx +0 -118
  396. package/src/renderHighlightsSvg.test.tsx +0 -85
  397. package/src/renderMinimapSvg.test.tsx +0 -62
  398. package/src/renderRasterSvg.test.tsx +0 -144
  399. package/src/renderSequenceLogoSvg.test.tsx +0 -165
  400. package/src/renderToSvg.test.tsx +0 -65
  401. package/src/reset.test.ts +0 -61
  402. package/src/rowCoordinateCalculations.test.ts +0 -211
  403. package/src/rowSpace.test.ts +0 -46
  404. package/src/segmentOverlay.test.ts +0 -70
  405. package/src/seqPosToGlobalCol.test.ts +0 -59
  406. package/src/sequenceLogo.test.ts +0 -88
  407. package/src/setFontSize.test.ts +0 -33
  408. package/src/stripDefault.test.ts +0 -48
  409. package/src/stripDefaultSnapshot.test.ts +0 -87
  410. package/src/treeMetadata.test.ts +0 -39
  411. package/src/useCanvasAutorun.test.tsx +0 -98
  412. package/src/useColorContrast.ts +0 -18
  413. package/src/viewChrome.test.tsx +0 -134
  414. package/src/wheelZoom.test.ts +0 -46
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Assigns each of one row's bands a lane: the first lane whose last band ends
3
+ * before this one starts, so only bands that actually overlap stack. A row of
4
+ * adjacent exons packs into a single lane; a family with a domain nested inside
5
+ * it takes two.
6
+ *
7
+ * Packing runs left to right, but the result keeps the input's largest-first
8
+ * paint order. `laneCount` is the row's depth, which the renderer divides the
9
+ * row height by so a deep stack stays inside its own row.
10
+ *
11
+ * The coordinates are whatever the caller packs in: alignment columns for the
12
+ * overlay, residue positions for a `features` row panel.
13
+ */
14
+ export function packDomainLanes<T extends { startCol: number; endCol: number }>(
15
+ bands: T[],
16
+ ): (T & { lane: number; laneCount: number })[] {
17
+ const laneEnds: number[] = []
18
+ const lanes = new Array<number>(bands.length)
19
+ const byStart = bands
20
+ .map((_, i) => i)
21
+ .sort((a, b) => bands[a]!.startCol - bands[b]!.startCol)
22
+
23
+ for (const i of byStart) {
24
+ const { startCol, endCol } = bands[i]!
25
+ const found = laneEnds.findIndex(end => end <= startCol)
26
+ const lane = found === -1 ? laneEnds.length : found
27
+ laneEnds[lane] = endCol
28
+ lanes[i] = lane
29
+ }
30
+
31
+ return bands.map((band, i) => ({
32
+ ...band,
33
+ lane: lanes[i]!,
34
+ laneCount: laneEnds.length,
35
+ }))
36
+ }
@@ -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 { NodeWithIdsAndLength } from '../../types.ts'
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
- rowHeight,
63
- fillPalette,
64
- strokePalette,
37
+ featureColors,
38
+ featureLabels,
65
39
  segmentLabels,
66
40
  showMsaLetters,
41
+ domainUnderline,
67
42
  domainBands,
68
43
  } = model
69
- const h = subFeatureRows ? subFeatureRowHeight : rowHeight
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
- const drawSegmentLabels = !showMsaLetters && !subFeatureRows && h >= 9
74
- // gene arrow heads stick out one row-height past the band, so pad the cull
75
- // window enough that a band just outside the block still draws its head
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
- for (const node of visibleLeaves) {
87
- const y = node.x!
88
- const bands = domainBands.get(node.data.name)
89
-
90
- if (bands) {
91
- for (const { annotation, startCol, endCol, stackIndex } of bands) {
92
- const { accession, strand } = annotation
93
- const x = startCol * colWidth
94
- const lw = colWidth * (endCol - startCol)
95
- if (x + lw >= xMin && x <= xMax) {
96
- const t = y - rowHeight + (subFeatureRows ? stackIndex * h : 0)
97
- ctx.fillStyle = fillPalette[accession]!
98
- ctx.strokeStyle = strokePalette[accession]!
99
- if (strand === undefined) {
100
- ctx.fillRect(x, t, lw, h)
101
- ctx.strokeRect(x, t, lw, h)
102
- const label =
103
- labelled && !labelled.has(accession)
104
- ? segmentLabels.get(accession)
105
- : undefined
106
- if (label !== undefined) {
107
- const fontSize = Math.min(h - 2, 11)
108
- ctx.font = `${fontSize}px sans-serif`
109
- if (ctx.measureText(label).width + 2 <= lw) {
110
- labelled!.add(accession)
111
- ctx.fillStyle = '#222'
112
- ctx.textAlign = 'center'
113
- ctx.textBaseline = 'middle'
114
- ctx.fillText(label, x + lw / 2, t + h / 2)
115
- }
116
- }
117
- } else {
118
- drawGeneArrow({ ctx, x, t, w: lw, h, strand })
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
  }
@@ -1,16 +1,37 @@
1
1
  import { setFontSize } from '../../setFontSize.ts'
2
+ import { referenceColor } from '../overlayColors.ts'
2
3
 
3
4
  import type { MsaViewModel } from '../../model.ts'
4
5
  import type { RenderCtx } from '../renderCtx.ts'
5
6
  import type { Theme } from '@mui/material'
6
7
 
8
+ // a fill plus a solid border; the hover wash alone is invisible over clustalx
9
+ // coloring
7
10
  export const highlightFill = 'rgba(255,140,0,0.28)'
8
11
  export const highlightBorder = 'rgba(210,90,0,0.95)'
9
12
  export const highlightRowFill = 'rgba(255,140,0,0.18)'
10
13
 
11
14
  export const labelFontSize = 11
12
15
  const labelPad = 3
16
+ // the label box above a highlight band; tree blocks also check rows this far
17
+ // outside themselves
18
+ export const highlightLabelHeight = labelFontSize + labelPad * 2
13
19
 
20
+ export interface LabelBox {
21
+ left: number
22
+ right: number
23
+ top: number
24
+ bottom: number
25
+ }
26
+
27
+ /**
28
+ * A highlight's label, over its band where it fits and beside it where it does
29
+ * not, kept inside `bounds` and out of the way of the labels already placed.
30
+ *
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.
34
+ */
14
35
  export function drawHighlightLabel({
15
36
  ctx,
16
37
  theme,
@@ -18,6 +39,8 @@ export function drawHighlightLabel({
18
39
  x,
19
40
  y,
20
41
  spanWidth,
42
+ bounds,
43
+ placed,
21
44
  }: {
22
45
  ctx: RenderCtx
23
46
  theme: Theme
@@ -25,24 +48,46 @@ export function drawHighlightLabel({
25
48
  x: number
26
49
  y: number
27
50
  spanWidth: number
51
+ bounds?: { min: number; max: number }
52
+ placed?: LabelBox[]
28
53
  }) {
29
54
  setFontSize(ctx, labelFontSize)
30
55
  ctx.textAlign = 'start'
31
56
  const boxWidth = ctx.measureText(label).width + labelPad * 2
32
- const boxHeight = labelFontSize + labelPad * 2
33
- const left = boxWidth <= spanWidth ? x : x + spanWidth + 2
57
+ const boxHeight = highlightLabelHeight
58
+ let left = boxWidth <= spanWidth ? x : x + spanWidth + 2
59
+ if (bounds) {
60
+ left = Math.max(bounds.min, Math.min(left, bounds.max - boxWidth))
61
+ }
62
+ let top = y
63
+ if (placed) {
64
+ const overlaps = (box: LabelBox) =>
65
+ box.left < left + boxWidth &&
66
+ box.right > left &&
67
+ box.top < top + boxHeight &&
68
+ box.bottom > top
69
+ while (placed.some(overlaps)) {
70
+ top += boxHeight
71
+ }
72
+ placed.push({ left, right: left + boxWidth, top, bottom: top + boxHeight })
73
+ }
34
74
  ctx.fillStyle = theme.palette.background.paper
35
- ctx.fillRect(left, y, boxWidth, boxHeight)
75
+ ctx.fillRect(left, top, boxWidth, boxHeight)
36
76
  ctx.fillStyle = theme.palette.text.primary
37
- ctx.fillText(label, left + labelPad, y + labelPad + labelFontSize - 2)
77
+ ctx.fillText(label, left + labelPad, top + labelPad + labelFontSize - 2)
38
78
  }
39
79
 
40
80
  /**
41
- * The persistent `highlights` overlay on the alignment: row tints, bordered
42
- * column bands, and a label above each band. `offsetX`/`offsetY` are the
43
- * content coordinates at the canvas origin, the convention renderMSABlock
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
44
85
  * uses, so the live overlay passes -scrollX/-scrollY and the export passes its
45
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.
46
91
  */
47
92
  export function renderHighlights({
48
93
  ctx,
@@ -61,12 +106,45 @@ export function renderHighlights({
61
106
  width: number
62
107
  height: number
63
108
  }) {
64
- const { resolvedHighlights, colWidth, rowHeight } = model
109
+ const { resolvedClades, resolvedHighlights, rowTints, colWidth, rowHeight } =
110
+ model
111
+ const placed: LabelBox[] = []
65
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
+ }
66
142
  for (const { rowIndices, color } of resolvedHighlights) {
67
143
  ctx.fillStyle = color ?? highlightRowFill
68
144
  for (const index of rowIndices) {
69
- ctx.fillRect(0, index * rowHeight - offsetY, width, rowHeight)
145
+ if (index >= firstRow && index <= lastRow) {
146
+ fillRow(index)
147
+ }
70
148
  }
71
149
  }
72
150
  for (const { startCol, endCol, label, color } of resolvedHighlights) {
@@ -80,7 +158,60 @@ export function renderHighlights({
80
158
  ctx.strokeStyle = color ?? highlightBorder
81
159
  ctx.strokeRect(x, 0, spanWidth, height)
82
160
  if (label) {
83
- drawHighlightLabel({ ctx, theme, label, x, y: 0, spanWidth })
161
+ drawHighlightLabel({
162
+ ctx,
163
+ theme,
164
+ label,
165
+ x,
166
+ y: 0,
167
+ spanWidth,
168
+ bounds: { min: 0, max: width },
169
+ placed,
170
+ })
84
171
  }
85
172
  }
86
173
  }
174
+
175
+ /**
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.
180
+ */
181
+ export function renderPersistentHighlights({
182
+ ctx,
183
+ model,
184
+ theme,
185
+ offsetX,
186
+ offsetY,
187
+ width,
188
+ height,
189
+ }: {
190
+ ctx: RenderCtx
191
+ model: MsaViewModel
192
+ theme: Theme
193
+ offsetX: number
194
+ offsetY: number
195
+ width: number
196
+ height: number
197
+ }) {
198
+ const { colWidth, rowHeight, referenceRowIndex, highlightedColumnRuns } =
199
+ model
200
+
201
+ if (referenceRowIndex !== undefined) {
202
+ ctx.fillStyle = referenceColor
203
+ ctx.fillRect(0, referenceRowIndex * rowHeight - offsetY, width, rowHeight)
204
+ }
205
+
206
+ ctx.lineWidth = 2
207
+ for (const { start, end } of highlightedColumnRuns) {
208
+ const x = start * colWidth - offsetX
209
+ const w = (end - start + 1) * colWidth
210
+ ctx.fillStyle = highlightFill
211
+ ctx.fillRect(x, 0, w, height)
212
+ ctx.strokeStyle = highlightBorder
213
+ ctx.strokeRect(x, 0, w, height)
214
+ }
215
+
216
+ renderHighlights({ ctx, model, theme, offsetX, offsetY, width, height })
217
+ }
@@ -1,5 +1,5 @@
1
1
  import { setFontSize } from '../../setFontSize.ts'
2
- import { adjustColorForContrast } from '../../util.ts'
2
+ import { adjustColorForContrast, contrastTextFn } from '../../util.ts'
3
3
  import { getVisibleLeaves } from '../getVisibleLeaves.ts'
4
4
  import { domainBandCursor } from './domainBandCursor.ts'
5
5
  import { tileColorFn } from './tileColor.ts'
@@ -15,7 +15,6 @@ export function renderMSABlock({
15
15
  model,
16
16
  offsetX,
17
17
  offsetY,
18
- contrastScheme,
19
18
  ctx,
20
19
  theme,
21
20
  highResScaleFactorOverride,
@@ -27,7 +26,6 @@ export function renderMSABlock({
27
26
  offsetY: number
28
27
  theme: Theme
29
28
  model: MsaViewModel
30
- contrastScheme: Record<string, string>
31
29
  ctx: RenderCtx
32
30
  highResScaleFactorOverride?: number
33
31
  blockSizeXOverride?: number
@@ -68,7 +66,6 @@ export function renderMSABlock({
68
66
  model,
69
67
  ctx,
70
68
  theme,
71
- contrastScheme,
72
69
  xStart,
73
70
  xEnd,
74
71
  visibleLeaves,
@@ -90,23 +87,10 @@ export function renderMSABlock({
90
87
  ctx.resetTransform()
91
88
  }
92
89
 
93
- // Letter color to use over a domain box, keyed by accession. Domain fills come
94
- // from a categorical palette that has no fixed lightness, so ask the theme for a
95
- // readable text color per fill instead of assuming dark-on-light.
96
- function domainLetterColors(model: MsaViewModel, theme: Theme) {
97
- return new Map(
98
- Object.entries(model.fillPalette).map(([accession, fill]) => [
99
- accession,
100
- theme.palette.getContrastText(fill),
101
- ]),
102
- )
103
- }
104
-
105
90
  function drawTilesAndText({
106
91
  model,
107
92
  ctx,
108
93
  theme,
109
- contrastScheme,
110
94
  visibleLeaves,
111
95
  xStart,
112
96
  xEnd,
@@ -117,7 +101,6 @@ function drawTilesAndText({
117
101
  model: MsaViewModel
118
102
  theme: Theme
119
103
  ctx: RenderCtx
120
- contrastScheme: Record<string, string>
121
104
  visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
122
105
  xStart: number
123
106
  xEnd: number
@@ -133,27 +116,30 @@ function drawTilesAndText({
133
116
  relativeTo,
134
117
  showMsaLetters,
135
118
  subFeatureRows,
119
+ domainUnderline,
136
120
  domainBandsByStart,
137
121
  } = model
138
122
 
139
123
  const tiles = drawTiles && bgColor
140
124
  const paintTiles = tiles && !rasterTiles
141
125
  if (paintTiles || showMsaLetters) {
142
- // over raster tiles the letters take their color from contrastScheme, so
143
- // the scheme lookup per cell is pure waste
144
- const needsColor = paintTiles || !tiles
126
+ // a letter takes its color from the cell it lands on, so the scheme lookup
127
+ // is only waste when nothing draws letters
128
+ const needsColor = paintTiles || showMsaLetters
145
129
  const tileColor = tileColorFn(model)
130
+ // Domain fills come from a categorical palette with no fixed lightness, and
131
+ // a dynamic scheme colors a cell from its column, so a readable letter color
132
+ // is a question about the cell's own color rather than about its letter.
133
+ const contrastText = contrastTextFn(theme)
146
134
  const offsetXAligned = xStart * colWidth
147
135
  const halfColWidth = colWidth / 2
148
136
  // note: -rowHeight/4 matches +rowHeight/4 in tree
149
137
  const quarterRowHeight = rowHeight / 4
150
138
  // with the tiles coming from the domain overlay instead, letters sit either
151
139
  // on a domain box or on the plain background; sub-row layout stacks the boxes
152
- // above the letters, so those rows are all plain background
153
- const overDomains = !drawTiles && !subFeatureRows
154
- const domainColors = overDomains
155
- ? domainLetterColors(model, theme)
156
- : undefined
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
157
143
 
158
144
  for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
159
145
  const node = visibleLeaves[i]!
@@ -186,18 +172,23 @@ function drawTilesAndText({
186
172
  const covering = bandAt(col)
187
173
  ctx.fillStyle = covering
188
174
  ? // on top of a domain box: contrast against the box fill
189
- domainColors!.get(covering.annotation.accession)!
190
- : tiles
191
- ? // on top of a colored tile
192
- (contrastScheme[letter] ?? 'black')
193
- : !drawTiles || !color
194
- ? // plain background, uncolored letters
195
- theme.palette.text.primary
196
- : // letter-color mode: darken/lighten to stay readable
197
- adjustColorForContrast(
198
- color,
199
- theme.palette.background.default,
200
- )
175
+ contrastText(model.fillPalette[covering.annotation.accession])
176
+ : isMatchingReference
177
+ ? // the dot sits on the faint reference-match wash, which is
178
+ // the theme's background with a little of its text color in it
179
+ theme.palette.text.primary
180
+ : tiles
181
+ ? // on top of a colored tile, or on the background where the
182
+ // scheme gives that cell no color
183
+ contrastText(color)
184
+ : bgColor || !color
185
+ ? // plain background, uncolored letters
186
+ theme.palette.text.primary
187
+ : // letter-color mode: darken/lighten to stay readable
188
+ adjustColorForContrast(
189
+ color,
190
+ theme.palette.background.default,
191
+ )
201
192
  ctx.fillText(
202
193
  isMatchingReference ? '.' : letter,
203
194
  x + halfColWidth,
@@ -1,20 +1,9 @@
1
- import {
2
- clickColor,
3
- hoverColor,
4
- multiRowHoverColor,
5
- referenceColor,
6
- } from '../overlayColors.ts'
7
- import { renderHighlights } from './renderHighlights.ts'
1
+ import { clickColor, hoverColor, multiRowHoverColor } from '../overlayColors.ts'
2
+ import { renderPersistentHighlights } from './renderHighlights.ts'
8
3
 
9
4
  import type { MsaViewModel } from '../../model.ts'
10
5
  import type { Theme } from '@mui/material'
11
6
 
12
- // the persistent highlightColumns overlay: a stronger fill plus a solid border
13
- // so a domain/motif band reads clearly over the colored alignment cells (the
14
- // faint hover-style wash alone is invisible against clustalx coloring)
15
- const highlightColumnsFill = 'rgba(255,140,0,0.28)'
16
- const highlightColumnsBorder = 'rgba(210,90,0,0.95)'
17
-
18
7
  export function renderMouseover({
19
8
  ctx,
20
9
  model,
@@ -36,9 +25,7 @@ export function renderMouseover({
36
25
  mouseClickRow,
37
26
  mouseClickCol,
38
27
  highResScaleFactor,
39
- referenceRowIndex,
40
28
  hoveredRowIndices,
41
- highlightedColumnRuns,
42
29
  } = model
43
30
  ctx.resetTransform()
44
31
  ctx.clearRect(0, 0, width * highResScaleFactor, height * highResScaleFactor)
@@ -53,30 +40,7 @@ export function renderMouseover({
53
40
  ctx.fillRect(index * colWidth + scrollX, 0, colWidth, height)
54
41
  }
55
42
 
56
- // the reference row (relativeTo) stays lit, as does every tip under a hovered
57
- // tree node
58
- if (referenceRowIndex !== undefined) {
59
- ctx.fillStyle = referenceColor
60
- rowBand(referenceRowIndex)
61
- }
62
- ctx.fillStyle = multiRowHoverColor
63
- for (const rowIndex of hoveredRowIndices) {
64
- rowBand(rowIndex)
65
- }
66
-
67
- // each contiguous run of highlighted columns draws as one filled, bordered
68
- // band, so a domain/motif highlight stays visible over the alignment
69
- ctx.lineWidth = 2
70
- for (const { start, end } of highlightedColumnRuns) {
71
- const x = start * colWidth + scrollX
72
- const w = (end - start + 1) * colWidth
73
- ctx.fillStyle = highlightColumnsFill
74
- ctx.fillRect(x, 0, w, height)
75
- ctx.strokeStyle = highlightColumnsBorder
76
- ctx.strokeRect(x, 0, w, height)
77
- }
78
-
79
- renderHighlights({
43
+ renderPersistentHighlights({
80
44
  ctx,
81
45
  model,
82
46
  theme,
@@ -86,6 +50,12 @@ export function renderMouseover({
86
50
  height,
87
51
  })
88
52
 
53
+ // every tip under a hovered tree node stays lit
54
+ ctx.fillStyle = multiRowHoverColor
55
+ for (const rowIndex of hoveredRowIndices) {
56
+ rowBand(rowIndex)
57
+ }
58
+
89
59
  ctx.fillStyle = hoverColor
90
60
  if (mouseCol !== undefined) {
91
61
  colBand(mouseCol)