jbrowse-plugin-graphgenomeviewer 7.1.0 → 7.1.2

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 (233) hide show
  1. package/README.md +17 -8
  2. package/dist/chunks/AddTrackWorkflow-RPH4ZFSX.js +2 -0
  3. package/dist/chunks/{AddTrackWorkflow-Q6RY23LF.js.map → AddTrackWorkflow-RPH4ZFSX.js.map} +2 -2
  4. package/dist/chunks/{ChooseSamplesDialog-BNVYBGJQ.js → ChooseSamplesDialog-JRN4YLBY.js} +2 -2
  5. package/dist/chunks/{ChooseWalksDialog-EN3C6AQA.js → ChooseWalksDialog-UXLFZTZJ.js} +2 -2
  6. package/dist/chunks/GbzBaseSyntenyAdapter-LRECKL74.js +2 -0
  7. package/dist/chunks/GbzBaseSyntenyAdapter-LRECKL74.js.map +7 -0
  8. package/dist/chunks/{GraphGenomeView-Z2WZKEEO.js → GraphGenomeView-NJ5XCREB.js} +2 -2
  9. package/dist/chunks/GraphTrackSettingsDialog-47PQ6LM7.js +6 -0
  10. package/dist/chunks/GraphTrackSettingsDialog-47PQ6LM7.js.map +7 -0
  11. package/dist/chunks/{HighlightColorDialog-EYBKFSJU.js → HighlightColorDialog-UK5VDDV6.js} +2 -2
  12. package/dist/chunks/{LinearGraphDisplay-WIBVWRQE.js → LinearGraphDisplay-TXTKAACH.js} +2 -2
  13. package/dist/chunks/MinigraphBubbleAdapter-HW7XQMAI.js +2 -0
  14. package/dist/chunks/MinigraphBubbleAdapter-HW7XQMAI.js.map +7 -0
  15. package/dist/chunks/RgfaTabixAdapter-PSKYWD2X.js +3 -0
  16. package/dist/chunks/RgfaTabixAdapter-PSKYWD2X.js.map +7 -0
  17. package/dist/chunks/{TrackWarningsDialog-QT4YEXGD.js → TrackWarningsDialog-TRYBOIHX.js} +2 -2
  18. package/dist/chunks/WalkTabixSyntenyAdapter-U53JLYVU.js +2 -0
  19. package/dist/chunks/WalkTabixSyntenyAdapter-U53JLYVU.js.map +7 -0
  20. package/dist/chunks/chunk-2MCOY3YG.js +3 -0
  21. package/dist/chunks/chunk-2MCOY3YG.js.map +7 -0
  22. package/dist/chunks/{chunk-EWFJBQDV.js → chunk-5O6YRJHL.js} +2 -2
  23. package/dist/chunks/{chunk-EWFJBQDV.js.map → chunk-5O6YRJHL.js.map} +1 -1
  24. package/dist/chunks/chunk-BUY2PV7D.js +2 -0
  25. package/dist/chunks/chunk-BUY2PV7D.js.map +7 -0
  26. package/dist/chunks/chunk-DVCZ3BOC.js +2 -0
  27. package/dist/chunks/chunk-DVCZ3BOC.js.map +7 -0
  28. package/dist/chunks/{chunk-SAMJE6GH.js → chunk-EGDLEQ47.js} +3 -3
  29. package/dist/chunks/{chunk-SAMJE6GH.js.map → chunk-EGDLEQ47.js.map} +4 -4
  30. package/dist/chunks/chunk-FHZXW7IG.js +2 -0
  31. package/dist/chunks/chunk-FHZXW7IG.js.map +7 -0
  32. package/dist/chunks/{chunk-DZ4OUKQV.js → chunk-FITPB5X6.js} +2 -2
  33. package/dist/chunks/{chunk-DZ4OUKQV.js.map → chunk-FITPB5X6.js.map} +1 -1
  34. package/dist/chunks/chunk-FVK2THE4.js +2 -0
  35. package/dist/chunks/chunk-FVK2THE4.js.map +7 -0
  36. package/dist/chunks/{chunk-AHFQHYJI.js → chunk-IBWORBGY.js} +2 -2
  37. package/dist/chunks/chunk-MND7GAOG.js +2 -0
  38. package/dist/chunks/chunk-MND7GAOG.js.map +7 -0
  39. package/dist/chunks/chunk-MURN3JPK.js +2 -0
  40. package/dist/chunks/chunk-MURN3JPK.js.map +7 -0
  41. package/dist/chunks/{chunk-3Q4RBDCL.js → chunk-N6PQZSAX.js} +1 -1
  42. package/dist/chunks/{chunk-3Q4RBDCL.js.map → chunk-N6PQZSAX.js.map} +1 -1
  43. package/dist/chunks/chunk-NWJYLP6Z.js +4 -0
  44. package/dist/chunks/chunk-NWJYLP6Z.js.map +7 -0
  45. package/dist/chunks/{chunk-YJHYBDYF.js → chunk-S75W27NT.js} +2 -2
  46. package/dist/chunks/{chunk-YJHYBDYF.js.map → chunk-S75W27NT.js.map} +1 -1
  47. package/dist/chunks/{chunk-IXQK7JAW.js → chunk-T4HOC6O3.js} +1 -1
  48. package/dist/chunks/{chunk-IXQK7JAW.js.map → chunk-T4HOC6O3.js.map} +1 -1
  49. package/dist/chunks/{chunk-AU73K7LX.js → chunk-TUKJRVBS.js} +1 -1
  50. package/dist/chunks/{chunk-AU73K7LX.js.map → chunk-TUKJRVBS.js.map} +1 -1
  51. package/dist/chunks/chunk-UGCNPRKC.js +2 -0
  52. package/dist/chunks/{chunk-E3WYW7Z6.js.map → chunk-UGCNPRKC.js.map} +2 -2
  53. package/dist/chunks/{chunk-YSTMDXXX.js → chunk-VJ3SO4CH.js} +1 -1
  54. package/dist/chunks/{chunk-YSTMDXXX.js.map → chunk-VJ3SO4CH.js.map} +1 -1
  55. package/dist/chunks/{chunk-XT766CZ5.js → chunk-W6EQLQ6H.js} +1 -1
  56. package/dist/chunks/{chunk-XT766CZ5.js.map → chunk-W6EQLQ6H.js.map} +1 -1
  57. package/dist/chunks/chunk-WAMBI7OX.js +2 -0
  58. package/dist/chunks/chunk-WAMBI7OX.js.map +7 -0
  59. package/dist/chunks/chunk-WCGVUZWP.js +2 -0
  60. package/dist/chunks/chunk-WCGVUZWP.js.map +7 -0
  61. package/dist/chunks/chunk-WEGWTC52.js +2 -0
  62. package/dist/chunks/chunk-WEGWTC52.js.map +7 -0
  63. package/dist/chunks/chunk-YU7T5WOQ.js +2 -0
  64. package/dist/chunks/{chunk-6OPB7FOJ.js.map → chunk-YU7T5WOQ.js.map} +2 -2
  65. package/dist/chunks/{chunk-446RWIA3.js → chunk-ZMOMFU2B.js} +1 -1
  66. package/dist/chunks/{chunk-446RWIA3.js.map → chunk-ZMOMFU2B.js.map} +1 -1
  67. package/dist/chunks/renderSvg-KSQI5DH6.js +2 -0
  68. package/dist/chunks/renderSvg-KSQI5DH6.js.map +7 -0
  69. package/dist/jbrowse-plugin-graphgenomeviewer.esm.js +4 -4
  70. package/dist/jbrowse-plugin-graphgenomeviewer.esm.js.map +4 -4
  71. package/package.json +8 -9
  72. package/src/GbzBaseSyntenyAdapter/GbzBaseSyntenyAdapter.test.ts +12 -10
  73. package/src/GbzBaseSyntenyAdapter/GbzBaseSyntenyAdapter.ts +31 -39
  74. package/src/GbzBaseSyntenyAdapter/configSchema.ts +5 -29
  75. package/src/GetGraphHaplotypes.ts +6 -15
  76. package/src/GetGraphReads.ts +7 -14
  77. package/src/GetSubgraph.ts +11 -20
  78. package/src/GraphAddTrackWorkflow/AddTrackWorkflow.test.tsx +73 -0
  79. package/src/GraphAddTrackWorkflow/AddTrackWorkflow.tsx +1 -0
  80. package/src/GraphAddTrackWorkflow/buildTrackConfig.test.ts +3 -2
  81. package/src/GraphAddTrackWorkflow/buildTrackConfig.ts +2 -11
  82. package/src/GraphAddTrackWorkflow/graphManifest.ts +15 -3
  83. package/src/GraphGenomeView/components/BubbleHalos.tsx +5 -24
  84. package/src/GraphGenomeView/components/ElTree.tsx +6 -1
  85. package/src/GraphGenomeView/components/FacetPanels.test.tsx +65 -0
  86. package/src/GraphGenomeView/components/FacetPanels.tsx +17 -12
  87. package/src/GraphGenomeView/components/GenePins.tsx +5 -22
  88. package/src/GraphGenomeView/components/GraphCanvas.tsx +40 -234
  89. package/src/GraphGenomeView/components/GraphSettingsDialog.tsx +102 -108
  90. package/src/GraphGenomeView/components/GraphToolbar.tsx +5 -6
  91. package/src/GraphGenomeView/components/HoverLayer.tsx +3 -7
  92. package/src/GraphGenomeView/components/HoverTooltip.test.tsx +39 -0
  93. package/src/GraphGenomeView/components/HoverTooltip.tsx +122 -0
  94. package/src/GraphGenomeView/components/LabelChip.tsx +3 -5
  95. package/src/GraphGenomeView/components/LabelLayer.tsx +4 -17
  96. package/src/GraphGenomeView/components/LabelledSelect.tsx +1 -1
  97. package/src/GraphGenomeView/components/Legend.tsx +14 -23
  98. package/src/GraphGenomeView/components/PaneContextMenu.test.tsx +48 -0
  99. package/src/GraphGenomeView/components/PaneContextMenu.tsx +144 -0
  100. package/src/GraphGenomeView/components/PaneLayer.tsx +91 -0
  101. package/src/GraphGenomeView/components/PaneSvg.tsx +32 -50
  102. package/src/GraphGenomeView/components/ReferenceStripOverlay.test.tsx +48 -0
  103. package/src/GraphGenomeView/components/ReferenceStripOverlay.tsx +13 -42
  104. package/src/GraphGenomeView/components/SettingsMenu.test.tsx +29 -0
  105. package/src/GraphGenomeView/components/SettingsMenu.tsx +56 -65
  106. package/src/GraphGenomeView/components/TubeMapOverlay.tsx +15 -46
  107. package/src/GraphGenomeView/components/WalkRowsOverlay.tsx +58 -132
  108. package/src/GraphGenomeView/components/WalkStrip.tsx +17 -20
  109. package/src/GraphGenomeView/components/WalkStripLocator.tsx +8 -15
  110. package/src/GraphGenomeView/components/usePaneGestures.test.tsx +35 -0
  111. package/src/GraphGenomeView/components/usePaneGestures.ts +88 -91
  112. package/src/GraphGenomeView/genes/geneFeatures.ts +27 -45
  113. package/src/GraphGenomeView/graphLayers.ts +4 -4
  114. package/src/GraphGenomeView/host.ts +1 -1
  115. package/src/GraphGenomeView/legendSections.test.ts +23 -1
  116. package/src/GraphGenomeView/legendSections.ts +68 -74
  117. package/src/GraphGenomeView/model.test.ts +373 -39
  118. package/src/GraphGenomeView/model.ts +67 -11
  119. package/src/GraphGenomeView/pane/fitViews.ts +57 -514
  120. package/src/GraphGenomeView/pane/graphViews.ts +219 -160
  121. package/src/GraphGenomeView/pane/hostViews.ts +2 -10
  122. package/src/GraphGenomeView/pane/keepInView.ts +5 -4
  123. package/src/GraphGenomeView/pane/launchActions.ts +117 -139
  124. package/src/GraphGenomeView/pane/launchViews.ts +8 -27
  125. package/src/GraphGenomeView/pane/loadActions.ts +208 -187
  126. package/src/GraphGenomeView/pane/morph.ts +3 -9
  127. package/src/GraphGenomeView/pane/paneBase.ts +22 -11
  128. package/src/GraphGenomeView/pane/renderingActions.ts +65 -11
  129. package/src/GraphGenomeView/pane/settingActions.ts +17 -42
  130. package/src/GraphGenomeView/pane/tubeMapViews.ts +445 -0
  131. package/src/GraphGenomeView/pane/walkRowViews.ts +29 -37
  132. package/src/GraphGenomeView/renderPipeline.test.ts +1 -1
  133. package/src/GraphGenomeView/repeats/repeatFeatures.test.ts +23 -0
  134. package/src/GraphGenomeView/repeats/repeatFeatures.ts +16 -23
  135. package/src/GraphGenomeView/repeats/walkCalls.test.ts +18 -0
  136. package/src/GraphGenomeView/repeats/walkCalls.ts +46 -38
  137. package/src/GraphGenomeView/subgraphLoad.test.ts +67 -3
  138. package/src/GraphGenomeView/trackFeatures.ts +24 -0
  139. package/src/GraphGenomeView/tubeMapPanels.ts +28 -36
  140. package/src/GraphGenomeView/viewModel.ts +8 -56
  141. package/src/GraphGenomeView/walkRowGroups.ts +104 -30
  142. package/src/GraphGenomeView/walkRowSpans.test.ts +6 -0
  143. package/src/GraphGenomeView/walkRowSpans.ts +22 -31
  144. package/src/GraphGenomeView/walkRowsCut.ts +8 -17
  145. package/src/LinearGraphDisplay/LinearGraphDisplay.test.ts +173 -26
  146. package/src/LinearGraphDisplay/components/SubgraphContextSelect.test.tsx +1 -1
  147. package/src/LinearGraphDisplay/components/SubgraphContextSelect.tsx +3 -3
  148. package/src/LinearGraphDisplay/components/SubgraphHaplotypesField.test.tsx +3 -3
  149. package/src/LinearGraphDisplay/components/SubgraphHaplotypesField.tsx +7 -10
  150. package/src/LinearGraphDisplay/configSchema.ts +0 -3
  151. package/src/LinearGraphDisplay/denseWindow.ts +8 -11
  152. package/src/LinearGraphDisplay/model.ts +89 -82
  153. package/src/MinigraphBubbleAdapter/MinigraphBubbleAdapter.test.ts +21 -0
  154. package/src/MinigraphBubbleAdapter/MinigraphBubbleAdapter.ts +6 -14
  155. package/src/MinigraphBubbleAdapter/configSchema.ts +3 -9
  156. package/src/MinigraphBubbleAdapter/index.ts +1 -2
  157. package/src/RgfaTabixAdapter/RgfaTabixAdapter.test.ts +45 -1
  158. package/src/RgfaTabixAdapter/RgfaTabixAdapter.ts +111 -276
  159. package/src/RgfaTabixAdapter/configSchema.ts +15 -49
  160. package/src/RgfaTabixAdapter/index.ts +1 -2
  161. package/src/RgfaTabixAdapter/rgfaBed.ts +25 -15
  162. package/src/RgfaTabixAdapter/rgfaCut.ts +139 -0
  163. package/src/RgfaTabixAdapter/test_data/walks2_twopart.GRCh38.walks.bed.gz +0 -0
  164. package/src/RgfaTabixAdapter/test_data/walks2_twopart.GRCh38.walks.bed.gz.tbi +0 -0
  165. package/src/RgfaTabixAdapter/walkFiles.test.ts +33 -0
  166. package/src/RgfaTabixAdapter/walkReader.ts +103 -27
  167. package/src/RgfaTabixAdapter/walkRowRuns.test.ts +53 -0
  168. package/src/RgfaTabixAdapter/walkRowRuns.ts +42 -24
  169. package/src/WalkTabixSyntenyAdapter/WalkTabixSyntenyAdapter.test.ts +37 -6
  170. package/src/WalkTabixSyntenyAdapter/WalkTabixSyntenyAdapter.ts +23 -45
  171. package/src/WalkTabixSyntenyAdapter/configSchema.ts +11 -24
  172. package/src/WalkTabixSyntenyAdapter/index.ts +1 -2
  173. package/src/WalkTabixSyntenyAdapter/walkLanes.ts +35 -43
  174. package/src/adapterImplementing.ts +27 -0
  175. package/src/graphTrackDefaults/index.ts +14 -20
  176. package/src/hoverSync/lgvHover.ts +2 -4
  177. package/src/launchFromGraph/contributors.ts +1 -5
  178. package/src/launchFromGraph/graphMenuItems.ts +3 -4
  179. package/src/launchFromGraph/launchFromGraph.test.ts +0 -1
  180. package/src/launchFromGraph/launchFromGraph.ts +8 -13
  181. package/src/panSNTabix.test.ts +1 -26
  182. package/src/panSNTabix.ts +54 -51
  183. package/src/synteny/lanePairs.ts +8 -0
  184. package/src/synteny/matchFeature.ts +52 -0
  185. package/src/tabixRange.ts +13 -10
  186. package/src/version.ts +1 -1
  187. package/dist/chunks/AddTrackWorkflow-Q6RY23LF.js +0 -2
  188. package/dist/chunks/GbzBaseSyntenyAdapter-TIXR4Y3J.js +0 -2
  189. package/dist/chunks/GbzBaseSyntenyAdapter-TIXR4Y3J.js.map +0 -7
  190. package/dist/chunks/GraphTrackSettingsDialog-TAM6PMXD.js +0 -6
  191. package/dist/chunks/GraphTrackSettingsDialog-TAM6PMXD.js.map +0 -7
  192. package/dist/chunks/MinigraphBubbleAdapter-AGI2UYQR.js +0 -2
  193. package/dist/chunks/MinigraphBubbleAdapter-AGI2UYQR.js.map +0 -7
  194. package/dist/chunks/RgfaTabixAdapter-2OL5X3HF.js +0 -3
  195. package/dist/chunks/RgfaTabixAdapter-2OL5X3HF.js.map +0 -7
  196. package/dist/chunks/WalkTabixSyntenyAdapter-UKFHCFOF.js +0 -2
  197. package/dist/chunks/WalkTabixSyntenyAdapter-UKFHCFOF.js.map +0 -7
  198. package/dist/chunks/chunk-5SFGHDQA.js +0 -2
  199. package/dist/chunks/chunk-5SFGHDQA.js.map +0 -7
  200. package/dist/chunks/chunk-6OPB7FOJ.js +0 -2
  201. package/dist/chunks/chunk-AMFIBQVR.js +0 -2
  202. package/dist/chunks/chunk-AMFIBQVR.js.map +0 -7
  203. package/dist/chunks/chunk-BJMRBVG3.js +0 -2
  204. package/dist/chunks/chunk-BJMRBVG3.js.map +0 -7
  205. package/dist/chunks/chunk-E3WYW7Z6.js +0 -2
  206. package/dist/chunks/chunk-EHCF6AXH.js +0 -2
  207. package/dist/chunks/chunk-EHCF6AXH.js.map +0 -7
  208. package/dist/chunks/chunk-GOFS7BXK.js +0 -3
  209. package/dist/chunks/chunk-GOFS7BXK.js.map +0 -7
  210. package/dist/chunks/chunk-IJQTSJGT.js +0 -4
  211. package/dist/chunks/chunk-IJQTSJGT.js.map +0 -7
  212. package/dist/chunks/chunk-J6NZIAZF.js +0 -2
  213. package/dist/chunks/chunk-J6NZIAZF.js.map +0 -7
  214. package/dist/chunks/chunk-LUTMKRXY.js +0 -2
  215. package/dist/chunks/chunk-LUTMKRXY.js.map +0 -7
  216. package/dist/chunks/chunk-MHPJB22Z.js +0 -2
  217. package/dist/chunks/chunk-MHPJB22Z.js.map +0 -7
  218. package/dist/chunks/chunk-TXI43PEN.js +0 -2
  219. package/dist/chunks/chunk-TXI43PEN.js.map +0 -7
  220. package/dist/chunks/chunk-WRH2EJKX.js +0 -2
  221. package/dist/chunks/chunk-WRH2EJKX.js.map +0 -7
  222. package/dist/chunks/chunk-WX26KTZM.js +0 -2
  223. package/dist/chunks/chunk-WX26KTZM.js.map +0 -7
  224. package/dist/chunks/renderSvg-ST2GBBOC.js +0 -2
  225. package/dist/chunks/renderSvg-ST2GBBOC.js.map +0 -7
  226. package/src/GraphGenomeView/components/WalkRowContextMenu.tsx +0 -105
  227. /package/dist/chunks/{ChooseSamplesDialog-BNVYBGJQ.js.map → ChooseSamplesDialog-JRN4YLBY.js.map} +0 -0
  228. /package/dist/chunks/{ChooseWalksDialog-EN3C6AQA.js.map → ChooseWalksDialog-UXLFZTZJ.js.map} +0 -0
  229. /package/dist/chunks/{GraphGenomeView-Z2WZKEEO.js.map → GraphGenomeView-NJ5XCREB.js.map} +0 -0
  230. /package/dist/chunks/{HighlightColorDialog-EYBKFSJU.js.map → HighlightColorDialog-UK5VDDV6.js.map} +0 -0
  231. /package/dist/chunks/{LinearGraphDisplay-WIBVWRQE.js.map → LinearGraphDisplay-TXTKAACH.js.map} +0 -0
  232. /package/dist/chunks/{TrackWarningsDialog-QT4YEXGD.js.map → TrackWarningsDialog-TRYBOIHX.js.map} +0 -0
  233. /package/dist/chunks/{chunk-AHFQHYJI.js.map → chunk-IBWORBGY.js.map} +0 -0
@@ -52,6 +52,10 @@ import { computed } from 'mobx'
52
52
 
53
53
  import { TUBE_MAP_MODES, dependOn, geometryPainted, paneBase } from './paneBase'
54
54
  import { walkRowRuns, walkRowsOf } from '../../RgfaTabixAdapter/walkRowRuns.ts'
55
+ import {
56
+ canonicalAssemblyName,
57
+ trackAssemblies,
58
+ } from '../../launchFromGraph/launchFromGraph'
55
59
  import { locationIsSet } from '../../locationName.ts'
56
60
  import { trackAdapterConfig } from '../../panSNAliases/trackAdapterConfig'
57
61
  import {
@@ -77,6 +81,7 @@ import {
77
81
  } from '../tubeMapPanels'
78
82
  import { groupByOf, groupWalkRows, metadataColumns } from '../walkRowGroups'
79
83
 
84
+ import type { ScreenTransform } from './keepInView'
80
85
  import type { WalkCut } from '../../RgfaTabixAdapter/walkRowRuns.ts'
81
86
  import type { GraphLayers } from '../graphLayers'
82
87
  import type { HoverHighlight } from '../hoverHighlight'
@@ -93,7 +98,7 @@ import type { FacetInput, FacetSetting } from '@jbrowse/bandage-core/facetGrid'
93
98
  import type { LayoutModeValue } from '@jbrowse/bandage-core/layoutModes'
94
99
  import type { NodeWidth } from '@jbrowse/bandage-core/nodeWidths'
95
100
  import type { AssemblyNames } from '@jbrowse/bandage-core/reference'
96
- import type { GraphNode } from '@jbrowse/bandage-core/types'
101
+ import type { Graph, GraphNode } from '@jbrowse/bandage-core/types'
97
102
  import type { NodeInk } from '@jbrowse/bandage-core/util/hitDetection'
98
103
  import type { WalkLayer } from '@jbrowse/bandage-core/walkEncoding'
99
104
  import type { WalkLift } from '@jbrowse/bandage-core/walkHighlight'
@@ -110,6 +115,34 @@ function walkRowsFromCut(
110
115
  return runs ? walkRowsOf(runs, unit) : undefined
111
116
  }
112
117
 
118
+ // undefined for a pane outside any track or view, as a test makes one
119
+ function orUndefined<T>(get: () => T) {
120
+ try {
121
+ return get()
122
+ } catch {
123
+ return undefined
124
+ }
125
+ }
126
+
127
+ function nodeMapOf(graph: Graph) {
128
+ const m = new Map<string, GraphNode>()
129
+ for (const n of graph.nodes) {
130
+ m.set(n.id, n)
131
+ }
132
+ return m
133
+ }
134
+
135
+ // A node's reference interval, an allele's between its flanks
136
+ function spanIn(
137
+ nodeId: string,
138
+ nodeById: Map<string, GraphNode> | undefined,
139
+ neighbors: ReturnType<typeof buildNeighbors> | undefined,
140
+ ) {
141
+ return nodeById && neighbors
142
+ ? nodeReferenceSpan({ nodeId, nodeById, neighbors })
143
+ : undefined
144
+ }
145
+
113
146
  // The layout, node color and hover as a host stores them: a view of its own
114
147
  // as props, a track display in its config
115
148
  export interface GraphGrammar {
@@ -122,6 +155,8 @@ export interface GraphGrammar {
122
155
  hover?: HoverHighlight
123
156
  }
124
157
 
158
+ type TubeColorKind = 'value' | 'tinted' | 'role' | 'path'
159
+
125
160
  // The rows walk rows draw: `kept` names the samples whose walks show, by the
126
161
  // name before the haplotype number; unset shows every walk the cut holds
127
162
  export interface GraphRows {
@@ -133,11 +168,6 @@ export const withGraphViews = paneBase
133
168
  get grammar(): GraphGrammar {
134
169
  return {}
135
170
  },
136
- // Light paper even under a dark theme: Bandage's deletion edges, the
137
- // deletion labels and the gene ink are near-black, and vanish on dark
138
- get darkMode() {
139
- return false
140
- },
141
171
  // a source declared but not yet loaded
142
172
  get hasPendingSource() {
143
173
  return false
@@ -147,11 +177,10 @@ export const withGraphViews = paneBase
147
177
  },
148
178
  // the track the graph is cut from: the one the pane is a display of
149
179
  get sourceTrack(): AnyConfigurationModel | undefined {
150
- try {
151
- return getContainingTrack(self).configuration
152
- } catch {
153
- return undefined
154
- }
180
+ return orUndefined(() => getContainingTrack(self).configuration)
181
+ },
182
+ get containingView(): object | undefined {
183
+ return orUndefined(() => getContainingView(self))
155
184
  },
156
185
  }))
157
186
  .views(self => {
@@ -254,14 +283,7 @@ export const withGraphViews = paneBase
254
283
  }))
255
284
  .views(self => ({
256
285
  get nodeById() {
257
- if (self.drawnGraph) {
258
- const m = new Map<string, GraphNode>()
259
- for (const n of self.drawnGraph.nodes) {
260
- m.set(n.id, n)
261
- }
262
- return m
263
- }
264
- return undefined
286
+ return self.drawnGraph && nodeMapOf(self.drawnGraph)
265
287
  },
266
288
  // bp per node id, which is all the label overlay needs of a GraphNode.
267
289
  // Held here rather than rebuilt in the component: that render runs on
@@ -356,13 +378,21 @@ export const withGraphViews = paneBase
356
378
  ? { start: open.start, end: open.end }
357
379
  : (self.statedColorDomain ?? self.graphRegion)
358
380
  },
359
- // The ramp a lane coloured by reference position reads, computed only
360
- // when a layer asks for one: it is a neighbour walk per node
381
+ // Every node's midpoint on the reference plus the interval the hue ramps
382
+ // over, on the drawn graph, whose ids a folded tube map's boxes carry.
383
+ // Deriving it is a bounded neighbour walk per node (referenceMidpoints):
384
+ // 1.6 ms at 1.5k nodes, 45 ms at 30k. It depends on nothing the
385
+ // transform touches, so a pan or drag frame reuses it, and the nodes and
386
+ // the lanes share it. Read only behind walkRamp's and referenceRamp's
387
+ // gates, so a colouring that ignores it never runs the walk.
388
+ get drawnReferenceRamp() {
389
+ const graph = self.drawnGraph
390
+ return graph ? computeReferenceRamp(graph, this.rampDomain) : undefined
391
+ },
392
+ // the ramp a lane coloured by reference position reads
361
393
  get walkRamp() {
362
- const { graph } = self
363
- return graph &&
364
- self.walkLayers.some(layer => layer.color?.field === 'reference')
365
- ? computeReferenceRamp(graph, this.rampDomain)
394
+ return self.walkLayers.some(layer => layer.color?.field === 'reference')
395
+ ? this.drawnReferenceRamp
366
396
  : undefined
367
397
  },
368
398
  // Whether the chosen layout draws the graph's nodes, which a facet
@@ -470,8 +500,13 @@ export const withGraphViews = paneBase
470
500
  ? 'uniform'
471
501
  : resolveColorScheme(self.chosenColorScheme, self.graph)
472
502
  },
503
+ // Panels lay their walks out without the reads
473
504
  get tubeMapReads() {
474
- return (self.layoutResult?.tubeMap?.layout.reads.length ?? 0) > 0
505
+ const layout = self.layoutResult
506
+ return (
507
+ !layout?.tubeMapPanels &&
508
+ (layout?.tubeMap?.layout.reads.length ?? 0) > 0
509
+ )
475
510
  },
476
511
  // Why no node scheme is on screen to pick, for every control that
477
512
  // offers one: lifted walks colour their own lanes and grey the rest,
@@ -496,14 +531,9 @@ export const withGraphViews = paneBase
496
531
  get labelsNodeSizes() {
497
532
  return !self.layoutResult?.tubeMap && !this.walkLift
498
533
  },
499
- // Empty rather than undefined: every consumer maps over it, and a layout
500
- // with no row structure (FMMM) is a normal state, not a missing one.
501
- get rowLabels() {
502
- return self.layoutResult?.rowLabels ?? []
503
- },
504
- // Deletions the layout found inside an allele, empty for the same reason
505
- // rowLabels is: a layout drawn at sequence scale states none, because
506
- // there a node's drawn extent already IS its length. `deletions` beside
534
+ // Deletions the layout found inside an allele, empty rather than
535
+ // undefined: a layout drawn at sequence scale states none, because there
536
+ // a node's drawn extent already IS its length. `deletions` beside
507
537
  // this one is the bare-edge kind, which every layout has.
508
538
  get alleleDeletions() {
509
539
  return self.layoutResult?.alleleDeletions ?? []
@@ -634,22 +664,26 @@ export const withGraphViews = paneBase
634
664
  const track = self.sourceTrack
635
665
  return track ? (readConfObject(track, 'trackId') as string) : undefined
636
666
  },
667
+ // The session's tracks, each with the assemblies it covers by canonical
668
+ // name, since a track may name one by an alias
669
+ get sessionTracks() {
670
+ const session = getSession(self)
671
+ return session.tracks.map(t => ({
672
+ trackId: t.trackId as string,
673
+ name: readConfObject(t, 'name') as string,
674
+ adapterType: (readConfObject(t, 'adapter') as { type: string }).type,
675
+ assemblies: trackAssemblies(session, t),
676
+ }))
677
+ },
678
+ }))
679
+ .views(self => ({
637
680
  get assemblyTrackChoices() {
638
681
  const region = self.graphRegion
639
- if (!region) {
640
- return []
641
- }
642
- return getSession(self)
643
- .tracks.filter(t =>
644
- (readConfObject(t, 'assemblyNames') as string[]).includes(
645
- region.assemblyName,
646
- ),
647
- )
648
- .map(t => ({
649
- trackId: t.trackId as string,
650
- name: readConfObject(t, 'name') as string,
651
- adapterType: (readConfObject(t, 'adapter') as { type: string }).type,
652
- }))
682
+ const assembly =
683
+ region && canonicalAssemblyName(getSession(self), region.assemblyName)
684
+ return assembly
685
+ ? self.sessionTracks.filter(t => t.assemblies.includes(assembly))
686
+ : []
653
687
  },
654
688
  }))
655
689
  .views(self => ({
@@ -733,10 +767,8 @@ export const withGraphViews = paneBase
733
767
  },
734
768
  // the filter of the gene track's lane in the view the pane draws in
735
769
  get geneLaneFilter() {
736
- let view: object
737
- try {
738
- view = getContainingView(self)
739
- } catch {
770
+ const view = self.containingView
771
+ if (!view) {
740
772
  return undefined
741
773
  }
742
774
  const filters = laneFilters(view, self.geneTrack?.trackId)
@@ -755,14 +787,13 @@ export const withGraphViews = paneBase
755
787
  ? geneModelsFrom(lane ? features.filter(f => lane.passes(f)) : features)
756
788
  : undefined
757
789
  },
758
- }))
759
- .views(self => ({
760
790
  // The genes on the drawn backbone under its own refNames. The track's
761
791
  // config puts its reference on the cut's assembly, whatever the walk's
762
792
  // name. After "Draw x along" another walk, the backbone takes the genes
763
793
  // only where its PanSN prefix names their assembly.
764
794
  get backboneGenes() {
765
- const { backbone, geneAssembly, geneFeatures } = self
795
+ const { backbone } = self
796
+ const { geneAssembly, geneFeatures } = this
766
797
  const binds =
767
798
  self.drawsLoadedReference ||
768
799
  (geneAssembly !== undefined &&
@@ -858,46 +889,47 @@ export const withGraphViews = paneBase
858
889
  unvalued: walks.some(w => valueOf(w) === ''),
859
890
  }
860
891
  },
892
+ // The grouping by a sample table column, once the table is read and
893
+ // has that column
894
+ get tableGroupBy() {
895
+ const groupBy = self.walkRowGroupBy
896
+ const table = self.walkRowSampleTable
897
+ return groupBy && table && this.walkRowGroupFields.includes(groupBy.field)
898
+ ? { groupBy, table }
899
+ : undefined
900
+ },
861
901
  // How a tube map splits into panels: by sample or walk, or by a sample
862
- // table column once the table is read
902
+ // table column
863
903
  get tubeMapPanelSplit(): TubeMapPanelSplit | undefined {
864
904
  const { field, domain } = self.facetSetting
865
- const groupBy = self.walkRowGroupBy
866
- const table = self.walkRowSampleTable
905
+ const grouped = this.tableGroupBy
867
906
  return field !== ''
868
907
  ? { by: field, domain }
869
- : groupBy && table && this.walkRowGroupFields.includes(groupBy.field)
870
- ? { by: 'column', ...groupBy, table }
908
+ : grouped
909
+ ? { by: 'column', ...grouped.groupBy, table: grouped.table }
871
910
  : undefined
872
911
  },
873
- // The filtered rows in a section per value of the grouped column, or
912
+ // the cohort's rows the sample filter keeps
913
+ get keptCohortRows() {
914
+ const bars = this.cohortWalkRows
915
+ return bars && filterSamples(bars.rows, self.walkRowSamples)
916
+ },
917
+ // The kept rows in a section per value of the grouped column, or
874
918
  // undefined while ungrouped or the table lacks that column
875
919
  get walkRowGroups() {
876
- const bars = this.cohortWalkRows
877
- const table = self.walkRowSampleTable
878
- const groupBy = self.walkRowGroupBy
879
- return bars &&
880
- table &&
881
- groupBy &&
882
- this.walkRowGroupFields.includes(groupBy.field)
883
- ? groupWalkRows(
884
- filterSamples(bars.rows, self.walkRowSamples),
885
- table,
886
- groupBy,
887
- )
920
+ const rows = this.keptCohortRows
921
+ const grouped = this.tableGroupBy
922
+ return rows && grouped
923
+ ? groupWalkRows(rows, grouped.table, grouped.groupBy)
888
924
  : undefined
889
925
  },
890
926
  // The bars the overlay draws: the cohort's, narrowed by the sample
891
927
  // filter, and stacked section by section while grouped
892
928
  get walkRowBars() {
893
929
  const bars = this.cohortWalkRows
894
- return bars
895
- ? {
896
- ...bars,
897
- rows:
898
- this.walkRowGroups?.rows ??
899
- filterSamples(bars.rows, self.walkRowSamples),
900
- }
930
+ const rows = this.keptCohortRows
931
+ return bars && rows
932
+ ? { ...bars, rows: this.walkRowGroups?.rows ?? rows }
901
933
  : undefined
902
934
  },
903
935
  // Whether the canvas draws the graph's nodes. A tube map and walk rows
@@ -933,23 +965,11 @@ export const withGraphViews = paneBase
933
965
  }
934
966
  return bubbleHalos(self.graph, self.bubbles, positions, self.repeatArrays)
935
967
  },
936
- // Every node's midpoint on the reference plus the interval the hue ramps
937
- // over — what `reference-position` paints from, and undefined under every
938
- // other scheme so the walk is never run for a colouring that ignores it.
939
- //
940
- // Here for the same reason `deletions` is, only more so: deriving it is a
941
- // bounded neighbour walk PER NODE (referenceMidpoints), it depends on
942
- // nothing the transform touches, and it was being redone inside every
943
- // geometry rebuild — 1.6 ms at 1.5k nodes, 45 ms at 30k, on a pass that
944
- // reruns on each debounced pan and each drag frame. `reference-position`
945
- // is also what `auto` resolves to on any anchored graph, so this was the
946
- // default path rather than an opt-in one.
947
- //
948
- // On the drawn graph, whose ids a folded tube map's boxes carry
968
+ // What `reference-position` paints from, which is also what `auto`
969
+ // resolves to on any anchored graph
949
970
  get referenceRamp() {
950
- return self.effectiveColorScheme === 'reference-position' &&
951
- self.drawnGraph
952
- ? computeReferenceRamp(self.drawnGraph, self.rampDomain)
971
+ return self.effectiveColorScheme === 'reference-position'
972
+ ? self.drawnReferenceRamp
953
973
  : undefined
954
974
  },
955
975
  // The assemblies this view is showing, which is the interface every
@@ -979,12 +999,7 @@ export const withGraphViews = paneBase
979
999
  //
980
1000
  // Everything that mixes the two axes takes their ratio as `yToX`
981
1001
  // (scaleY / scaleX) — see computeEdgeCurves.
982
- get scaleX() {
983
- return axisScaleOf(self.scale, self.pixelRows).scaleX
984
- },
985
- get scaleY() {
986
- return axisScaleOf(self.scale, self.pixelRows).scaleY
987
- },
1002
+ //
988
1003
  // The pair, for everything that draws or hit-tests. Handed over as one
989
1004
  // value on purpose: every consumer needs both, and passing them separately
990
1005
  // let a caller supply the x scale and default y, which compiles and draws
@@ -992,8 +1007,29 @@ export const withGraphViews = paneBase
992
1007
  get axisScale() {
993
1008
  return axisScaleOf(self.scale, self.pixelRows)
994
1009
  },
1010
+ get scaleX() {
1011
+ return this.axisScale.scaleX
1012
+ },
1013
+ get scaleY() {
1014
+ return this.axisScale.scaleY
1015
+ },
995
1016
  }))
996
1017
  .views(self => ({
1018
+ // layout units to pane px
1019
+ get screenTransform(): ScreenTransform {
1020
+ return {
1021
+ scaleX: self.scaleX,
1022
+ scaleY: self.scaleY,
1023
+ translateX: self.translateX,
1024
+ translateY: self.translateY,
1025
+ }
1026
+ },
1027
+ toScreen(p: { x: number; y: number }) {
1028
+ return {
1029
+ x: p.x * self.scaleX + self.translateX,
1030
+ y: p.y * self.scaleY + self.translateY,
1031
+ }
1032
+ },
997
1033
  get deletionDrawing() {
998
1034
  return self.graph
999
1035
  ? deletionDrawing(self.graph, self.allDeletions, self.showDeletionEdges)
@@ -1060,43 +1096,79 @@ export const withGraphViews = paneBase
1060
1096
  )
1061
1097
  : undefined
1062
1098
  },
1063
- // Beside tinted boxes, and past the walks a key can name, the tubes take
1064
- // their roles' colours: a hue per walk would either share a box's or
1065
- // identify nothing
1066
- get tubeMapTubeColors() {
1067
- const drawing = self.layoutResult?.tubeMap
1068
- const colors = drawing?.pathColors
1069
- const paths = self.drawnGraph?.paths
1099
+ // How a tube map colours its tubes: a hue per value of the column
1100
+ // picked; grey by role beside tinted boxes, which a hue per walk would
1101
+ // share; the reference charcoal and the haplotypes blue in a panel, whose
1102
+ // title names its walks, and past the walks a key can name; else a hue
1103
+ // per walk. Beside reads, which take the reds and blues, that hue is grey.
1104
+ get tubeColorKind(): TubeColorKind | undefined {
1105
+ const layout = self.layoutResult
1106
+ const paths = self.drawnGraph?.paths ?? []
1107
+ const reads = self.tubeMapReads
1108
+ return !layout?.tubeMap
1109
+ ? undefined
1110
+ : self.tubeMapColoring && !reads
1111
+ ? 'value'
1112
+ : layout.tubeMapPanels
1113
+ ? 'role'
1114
+ : this.tubeMapNodeColors
1115
+ ? 'tinted'
1116
+ : !reads &&
1117
+ (!pathColorsLegible(paths.length) ||
1118
+ paths.some(p => p.members))
1119
+ ? 'role'
1120
+ : 'path'
1121
+ },
1122
+ // `graph`'s tubes as tubeColorKind colours them, `pathColors` being
1123
+ // its drawing's hue per walk
1124
+ tubeColorsOf(graph: Graph, pathColors: readonly string[]) {
1125
+ const paths = graph.paths ?? []
1126
+ const kind = this.tubeColorKind
1070
1127
  const coloring = self.tubeMapColoring
1071
- const tubes =
1072
- colors && paths && coloring && drawing.layout.reads.length === 0
1073
- ? valueTubeColors(
1074
- paths,
1075
- self.drawnGraph.referencePath,
1076
- coloring.valueOf,
1077
- coloring.palette,
1078
- )
1079
- : colors && paths && this.tubeMapNodeColors
1080
- ? roleTubeColors(paths, self.drawnGraph.referencePath, TINTED_TUBES)
1081
- : colors &&
1082
- paths &&
1083
- drawing.layout.reads.length === 0 &&
1084
- (!pathColorsLegible(paths.length) || paths.some(p => p.members))
1085
- ? roleTubeColors(paths, self.drawnGraph.referencePath)
1086
- : colors
1128
+ return kind === 'value' && coloring
1129
+ ? valueTubeColors(
1130
+ paths,
1131
+ graph.referencePath,
1132
+ coloring.valueOf,
1133
+ coloring.palette,
1134
+ )
1135
+ : kind === 'tinted'
1136
+ ? roleTubeColors(paths, graph.referencePath, TINTED_TUBES)
1137
+ : kind === 'role'
1138
+ ? roleTubeColors(paths, graph.referencePath)
1139
+ : pathColors
1140
+ },
1141
+ // While a lane row is hovered, every tube but its walks' and `kept`'s
1142
+ // fades. A panel keeps its reference to compare against; the unsplit map
1143
+ // fades it with the rest.
1144
+ fadeUnhovered(
1145
+ colors: readonly string[],
1146
+ paths: readonly { name: string }[],
1147
+ kept?: string,
1148
+ ) {
1087
1149
  const hovered = new Set(self.hoveredRowWalks)
1088
- return tubes && paths && hovered.size > 0
1089
- ? tubes.map((color, i) =>
1090
- hovered.has(paths[i]?.name ?? '') ? color : LIFT_BACKDROP_CSS,
1150
+ return hovered.size > 0
1151
+ ? colors.map((color, i) => {
1152
+ const name = paths[i]?.name ?? ''
1153
+ return hovered.has(name) ||
1154
+ (kept !== undefined && pathOrigin(name).name === kept)
1155
+ ? color
1156
+ : LIFT_BACKDROP_CSS
1157
+ })
1158
+ : colors
1159
+ },
1160
+ get tubeMapTubeColors() {
1161
+ const drawing = self.layoutResult?.tubeMap
1162
+ const graph = self.drawnGraph
1163
+ return drawing && graph
1164
+ ? this.fadeUnhovered(
1165
+ this.tubeColorsOf(graph, drawing.pathColors),
1166
+ graph.paths ?? [],
1091
1167
  )
1092
- : tubes
1168
+ : undefined
1093
1169
  },
1094
- // A node's reference interval, an allele's between its flanks
1095
1170
  nodeSpan(nodeId: string) {
1096
- const { nodeById, nodeNeighbors: neighbors } = self
1097
- return nodeById && neighbors
1098
- ? nodeReferenceSpan({ nodeId, nodeById, neighbors })
1099
- : undefined
1171
+ return spanIn(nodeId, self.nodeById, self.nodeNeighbors)
1100
1172
  },
1101
1173
  // The drawing the pointer is over: its panel's while a tube map is split,
1102
1174
  // each panel laid out alone and merging its own runs
@@ -1109,22 +1181,18 @@ export const withGraphViews = paneBase
1109
1181
  self.layoutResult?.tubeMap
1110
1182
  )
1111
1183
  },
1112
- }))
1113
- .views(self => ({
1114
1184
  // the graph whose ids the hover names
1115
1185
  get hoverGraph() {
1116
- return self.hoverDrawing?.graph ?? self.drawnGraph
1186
+ return this.hoverDrawing?.graph ?? self.drawnGraph
1117
1187
  },
1118
- }))
1119
- .views(self => ({
1120
1188
  get hoverNodeById() {
1121
- const graph = self.hoverGraph
1189
+ const graph = this.hoverGraph
1122
1190
  return graph === self.drawnGraph
1123
1191
  ? self.nodeById
1124
- : graph && new Map(graph.nodes.map(n => [n.id, n]))
1192
+ : graph && nodeMapOf(graph)
1125
1193
  },
1126
1194
  get hoverNeighbors() {
1127
- const graph = self.hoverGraph
1195
+ const graph = this.hoverGraph
1128
1196
  return graph === self.drawnGraph
1129
1197
  ? self.nodeNeighbors
1130
1198
  : graph && buildNeighbors(graph)
@@ -1137,20 +1205,17 @@ export const withGraphViews = paneBase
1137
1205
  // Empty unless the ribbons are actually on: a colour key beside a drawing
1138
1206
  // with no colours in it is a legend for nothing.
1139
1207
  // The tube map colours its tubes whether or not paths are drawn on the
1140
- // nodes, so under it the key follows the tubes, and names the colours
1141
- // the tubes were drawn in.
1208
+ // nodes, so under it the key follows the tubes: walk by walk where each
1209
+ // has a hue, and otherwise the tube map's own key names the colours.
1142
1210
  get pathLegend() {
1143
1211
  const paths = self.drawnGraph?.paths
1144
- const tubeMap = self.layoutResult?.tubeMap
1145
- const colouring = self.drawPaths || tubeMap
1146
- // tubes coloured by role or by a column take the tube map's role or value key
1147
- return colouring &&
1212
+ const keyed = self.layoutResult?.tubeMap
1213
+ ? self.tubeColorKind === 'path'
1214
+ : self.drawPaths
1215
+ return keyed &&
1148
1216
  paths &&
1149
1217
  pathColorsLegible(paths.length) &&
1150
- !self.layoutResult?.tubeMapPanels &&
1151
- !self.tubeMapNodeColors &&
1152
- !paths.some(p => p.members) &&
1153
- !self.tubeMapColoring
1218
+ !paths.some(p => p.members)
1154
1219
  ? pathLegend(paths, self.tubeMapTubeColors)
1155
1220
  : []
1156
1221
  },
@@ -1159,24 +1224,18 @@ export const withGraphViews = paneBase
1159
1224
  get hoveredSpan() {
1160
1225
  const nodeId = self.hoveredNode
1161
1226
  const bubble = self.hoveredBubble
1162
- const nodeById = self.hoverNodeById
1163
- const neighbors = self.hoverNeighbors
1164
1227
  return nodeId !== null
1165
- ? nodeById && neighbors
1166
- ? nodeReferenceSpan({ nodeId, nodeById, neighbors })
1167
- : undefined
1228
+ ? spanIn(nodeId, self.hoverNodeById, self.hoverNeighbors)
1168
1229
  : bubble && !bubble.offReference
1169
1230
  ? { start: bubble.start, end: bubble.end }
1170
1231
  : undefined
1171
1232
  },
1172
- }))
1173
- .views(self => ({
1174
1233
  // The hovered span, for a connected linear view to highlight. Only a
1175
1234
  // graph cut from a track has one: a whole-file import has no region, and
1176
1235
  // its stable names need not name anything in a loaded assembly.
1177
1236
  get hoverHighlight() {
1178
1237
  const region = self.graphRegion
1179
- const span = self.hoveredSpan
1238
+ const span = this.hoveredSpan
1180
1239
  return region && span && self.chosenHover !== 'off'
1181
1240
  ? {
1182
1241
  refName: region.refName,
@@ -14,7 +14,6 @@ import { tubeMapPicture } from '@jbrowse/bandage-core/tubeMap/draw'
14
14
  import { tubeMapGenes } from '@jbrowse/bandage-core/tubeMap/genes'
15
15
 
16
16
  import { hostFrame } from '../host'
17
- import { PAPER_DARK, PAPER_LIGHT, paperCss } from './paneBase'
18
17
  import { withWalkRowViews } from './walkRowViews'
19
18
 
20
19
  export const withHostViews = withWalkRowViews
@@ -166,17 +165,13 @@ export const withHostViews = withWalkRowViews
166
165
  if (!self.referenceStripShown) {
167
166
  return undefined
168
167
  }
169
- const toScreen = (p: { x: number; y: number }) => ({
170
- x: p.x * self.scaleX + self.translateX,
171
- y: p.y * self.scaleY + self.translateY,
172
- })
173
168
  const bubble = self.hoveredNode === null ? self.hoveredBubble : null
174
169
  if (bubble && !bubble.offReference) {
175
170
  const halo = self.bubbleHalos.find(h => sameBubble(h.bubble, bubble))
176
171
  return {
177
172
  start: bubble.start,
178
173
  end: bubble.end,
179
- anchor: halo ? toScreen(halo.labelAt) : undefined,
174
+ anchor: halo ? self.toScreen(halo.labelAt) : undefined,
180
175
  }
181
176
  }
182
177
  const nodeId = self.hoveredNode ?? self.selectedNode
@@ -184,7 +179,7 @@ export const withHostViews = withWalkRowViews
184
179
  return span && nodeId !== null
185
180
  ? {
186
181
  ...span,
187
- anchor: nodeAnchor(self.nodePositions?.[nodeId], toScreen),
182
+ anchor: nodeAnchor(self.nodePositions?.[nodeId], self.toScreen),
188
183
  }
189
184
  : undefined
190
185
  },
@@ -194,9 +189,6 @@ export const withHostViews = withWalkRowViews
194
189
  ? stripBlockAt(self.referenceStripBlocks, frame, sx, sy)
195
190
  : undefined
196
191
  },
197
- get paperCss() {
198
- return paperCss(self.darkMode ? PAPER_DARK : PAPER_LIGHT)
199
- },
200
192
  // the strip, and the gap the fit leaves under it
201
193
  get referenceStripZonePx() {
202
194
  return self.referenceStripShown ? REFERENCE_STRIP_ZONE_PX : 0
@@ -1,6 +1,6 @@
1
1
  // How much of the drawing a pan or zoom leaves on screen in each axis, or
2
2
  // all of it when it is smaller
3
- export const KEEP_IN_VIEW_PX = 48
3
+ const KEEP_IN_VIEW_PX = 48
4
4
 
5
5
  // The shift that brings a span starting at `lo`, `size` px long, back to
6
6
  // overlapping [0, extent] by `margin` px
@@ -16,7 +16,8 @@ interface DrawingBox {
16
16
  h: number
17
17
  }
18
18
 
19
- interface Placement {
19
+ // layout units to pane px, per axis
20
+ export interface ScreenTransform {
20
21
  scaleX: number
21
22
  scaleY: number
22
23
  translateX: number
@@ -25,7 +26,7 @@ interface Placement {
25
26
 
26
27
  export function keepInView(
27
28
  bounds: DrawingBox,
28
- t: Placement,
29
+ t: ScreenTransform,
29
30
  view: { width: number; height: number },
30
31
  ) {
31
32
  return {
@@ -48,7 +49,7 @@ export function keepInView(
48
49
 
49
50
  export function onScreen(
50
51
  bounds: DrawingBox,
51
- t: Placement,
52
+ t: ScreenTransform,
52
53
  view: { width: number; height: number },
53
54
  ) {
54
55
  const left = bounds.minX * t.scaleX + t.translateX