higlass 1.13.6 → 2.0.1

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 (297) hide show
  1. package/app/scripts/AddTrackDialog.jsx +8 -1
  2. package/app/scripts/AddTrackPositionMenu.jsx +26 -5
  3. package/app/scripts/Annotations1dTrack.js +90 -251
  4. package/app/scripts/Annotations2dTrack.js +9 -2
  5. package/app/scripts/Autocomplete.jsx +1 -9
  6. package/app/scripts/BedLikeTrack.js +549 -441
  7. package/app/scripts/ContextMenuContainer.jsx +3 -0
  8. package/app/scripts/ContextMenuItem.jsx +13 -2
  9. package/app/scripts/FilledLine.js +349 -0
  10. package/app/scripts/GenomePositionSearchBox.jsx +178 -477
  11. package/app/scripts/HiGlassComponent.jsx +443 -349
  12. package/app/scripts/HiGlassComponentContext.js +5 -0
  13. package/app/scripts/SeriesListMenu.jsx +94 -44
  14. package/app/scripts/SeriesListSubmenuMixin.jsx +1 -0
  15. package/app/scripts/Tiled1DPixiTrack.js +0 -1
  16. package/app/scripts/TiledPixiTrack.js +72 -63
  17. package/app/scripts/TiledPlot.jsx +530 -77
  18. package/app/scripts/TrackRenderer.jsx +2 -2
  19. package/app/scripts/ViewContextMenu.jsx +50 -2
  20. package/app/scripts/ViewHeader.jsx +3 -2
  21. package/app/scripts/api.js +87 -6
  22. package/app/scripts/configs/index.js +6 -1
  23. package/app/scripts/configs/primitives.js +2 -0
  24. package/app/scripts/configs/tracks-info.js +1 -0
  25. package/app/scripts/data-fetchers/genbank-fetcher.js +9 -14
  26. package/app/scripts/data-fetchers/local-tile-fetcher.js +8 -2
  27. package/app/scripts/hglib.jsx +61 -70
  28. package/app/scripts/options-info.js +49 -11
  29. package/app/scripts/services/tile-proxy.js +0 -4
  30. package/app/scripts/services/worker.js +1 -0
  31. package/app/scripts/test-helpers/index.js +2 -1
  32. package/app/scripts/test-helpers/test-helpers.jsx +154 -66
  33. package/app/scripts/types.ts +68 -3
  34. package/app/scripts/utils/copy-text-to-clipboard.js +36 -0
  35. package/app/scripts/utils/decompress.js +33 -0
  36. package/app/scripts/utils/default-tracks.js +46 -0
  37. package/app/scripts/utils/get-default-track-for-datatype.js +2 -1
  38. package/app/scripts/utils/get-default-tracks-for-datatype.ts +46 -0
  39. package/app/scripts/utils/index.js +1 -0
  40. package/app/scripts/utils/positioned-tracks-to-all-tracks.js +55 -0
  41. package/app/scripts/utils/show-mouse-position.js +0 -16
  42. package/app/scripts/utils/visit-positioned-tracks.js +4 -1
  43. package/app/styles/AddTrackPositionMenu.module.scss +37 -0
  44. package/app/styles/HiGlass.module.scss +3 -1
  45. package/app/styles/TiledPlot.module.scss +20 -0
  46. package/dist/app/schema.json +525 -0
  47. package/dist/app/scripts/AddTrackDialog.d.ts +64 -0
  48. package/dist/app/scripts/AddTrackPositionMenu.d.ts +5 -0
  49. package/dist/app/scripts/Annotations1dTrack.d.ts +15 -0
  50. package/dist/app/scripts/Annotations2dTrack.d.ts +95 -0
  51. package/dist/app/scripts/ArrowheadDomainsTrack.d.ts +36 -0
  52. package/dist/app/scripts/Autocomplete.d.ts +102 -0
  53. package/dist/app/scripts/AxisPixi.d.ts +25 -0
  54. package/dist/app/scripts/BarTrack.d.ts +28 -0
  55. package/dist/app/scripts/BedLikeTrack.d.ts +84 -0
  56. package/dist/app/scripts/Button.d.ts +3 -0
  57. package/dist/app/scripts/CNVIntervalTrack.d.ts +12 -0
  58. package/dist/app/scripts/CenterTiledPlot.d.ts +3 -0
  59. package/dist/app/scripts/CenterTrack.d.ts +92 -0
  60. package/dist/app/scripts/Chromosome2DAnnotations.d.ts +10 -0
  61. package/dist/app/scripts/Chromosome2DLabels.d.ts +13 -0
  62. package/dist/app/scripts/ChromosomeGrid.d.ts +24 -0
  63. package/dist/app/scripts/ChromosomeInfo.d.ts +14 -0
  64. package/dist/app/scripts/CloseTrackMenu.d.ts +10 -0
  65. package/dist/app/scripts/CombinedTrack.d.ts +32 -0
  66. package/dist/app/scripts/ConfigTrackMenu.d.ts +10 -0
  67. package/dist/app/scripts/ConfigViewMenu.d.ts +34 -0
  68. package/dist/app/scripts/ConfigureSeriesMenu.d.ts +3 -0
  69. package/dist/app/scripts/ContextMenuContainer.d.ts +36 -0
  70. package/dist/app/scripts/ContextMenuItem.d.ts +34 -0
  71. package/dist/app/scripts/Cross.d.ts +3 -0
  72. package/dist/app/scripts/CrossRule.d.ts +24 -0
  73. package/dist/app/scripts/CustomTrackDialog.d.ts +17 -0
  74. package/dist/app/scripts/Dialog.d.ts +5 -0
  75. package/dist/app/scripts/DivergentBarTrack.d.ts +4 -0
  76. package/dist/app/scripts/DragListeningDiv.d.ts +32 -0
  77. package/dist/app/scripts/DraggableDiv.d.ts +63 -0
  78. package/dist/app/scripts/ExportLinkDialog.d.ts +21 -0
  79. package/dist/app/scripts/FilledLine.d.ts +5 -0
  80. package/dist/app/scripts/FixedTrack.d.ts +5 -0
  81. package/dist/app/scripts/GalleryTracks.d.ts +20 -0
  82. package/dist/app/scripts/GenomePositionSearchBox.d.ts +95 -0
  83. package/dist/app/scripts/HeatmapOptions.d.ts +30 -0
  84. package/dist/app/scripts/HeatmapTiledPixiTrack.d.ts +184 -0
  85. package/dist/app/scripts/HiGlassComponent.d.ts +762 -0
  86. package/dist/app/scripts/HiGlassComponentContext.d.ts +3 -0
  87. package/dist/app/scripts/HiGlassTrackComponent.d.ts +37 -0
  88. package/dist/app/scripts/Horizontal1dHeatmapTrack.d.ts +9 -0
  89. package/dist/app/scripts/Horizontal2DDomainsTrack.d.ts +21 -0
  90. package/dist/app/scripts/HorizontalChromosomeLabels.d.ts +47 -0
  91. package/dist/app/scripts/HorizontalGeneAnnotationsTrack.d.ts +25 -0
  92. package/dist/app/scripts/HorizontalHeatmapTrack.d.ts +12 -0
  93. package/dist/app/scripts/HorizontalItem.d.ts +3 -0
  94. package/dist/app/scripts/HorizontalLine1DPixiTrack.d.ts +23 -0
  95. package/dist/app/scripts/HorizontalMultivecTrack.d.ts +50 -0
  96. package/dist/app/scripts/HorizontalPoint1DPixiTrack.d.ts +5 -0
  97. package/dist/app/scripts/HorizontalRule.d.ts +22 -0
  98. package/dist/app/scripts/HorizontalTiled1DPixiTrack.d.ts +26 -0
  99. package/dist/app/scripts/HorizontalTiledPlot.d.ts +49 -0
  100. package/dist/app/scripts/HorizontalTrack.d.ts +6 -0
  101. package/dist/app/scripts/Id2DTiledPixiTrack.d.ts +10 -0
  102. package/dist/app/scripts/IdHorizontal1DTiledPixiTrack.d.ts +6 -0
  103. package/dist/app/scripts/IdVertical1DTiledPixiTrack.d.ts +7 -0
  104. package/dist/app/scripts/LeftAxisTrack.d.ts +9 -0
  105. package/dist/app/scripts/LeftTrackModifier.d.ts +29 -0
  106. package/dist/app/scripts/ListWrapper.d.ts +64 -0
  107. package/dist/app/scripts/MapboxTilesTrack.d.ts +9 -0
  108. package/dist/app/scripts/Modal.d.ts +5 -0
  109. package/dist/app/scripts/MoveableTrack.d.ts +18 -0
  110. package/dist/app/scripts/NestedContextMenu.d.ts +7 -0
  111. package/dist/app/scripts/OSMTileIdsTrack.d.ts +5 -0
  112. package/dist/app/scripts/OSMTilesTrack.d.ts +129 -0
  113. package/dist/app/scripts/OverlayTrack.d.ts +13 -0
  114. package/dist/app/scripts/PixiTrack.d.ts +174 -0
  115. package/dist/app/scripts/PlotTypeChooser.d.ts +25 -0
  116. package/dist/app/scripts/PopupMenu.d.ts +28 -0
  117. package/dist/app/scripts/RasterTilesTrack.d.ts +9 -0
  118. package/dist/app/scripts/RuleMixin.d.ts +2 -0
  119. package/dist/app/scripts/SVGTrack.d.ts +15 -0
  120. package/dist/app/scripts/SearchField.d.ts +13 -0
  121. package/dist/app/scripts/SeriesListItems.d.ts +2 -0
  122. package/dist/app/scripts/SeriesListMenu.d.ts +51 -0
  123. package/dist/app/scripts/SeriesListSubmenuMixin.d.ts +2 -0
  124. package/dist/app/scripts/SketchInlinePicker.d.ts +25 -0
  125. package/dist/app/scripts/SortableList.d.ts +22 -0
  126. package/dist/app/scripts/SquareMarkersTrack.d.ts +22 -0
  127. package/dist/app/scripts/Tiled1DPixiTrack.d.ts +60 -0
  128. package/dist/app/scripts/TiledPixiTrack.d.ts +369 -0
  129. package/dist/app/scripts/TiledPlot.d.ts +313 -0
  130. package/dist/app/scripts/TilesetFinder.d.ts +65 -0
  131. package/dist/app/scripts/TopAxisTrack.d.ts +9 -0
  132. package/dist/app/scripts/Track.d.ts +196 -0
  133. package/dist/app/scripts/TrackArea.d.ts +26 -0
  134. package/dist/app/scripts/TrackControl.d.ts +5 -0
  135. package/dist/app/scripts/TrackRenderer.d.ts +724 -0
  136. package/dist/app/scripts/UnknownPixiTrack.d.ts +7 -0
  137. package/dist/app/scripts/ValueIntervalTrack.d.ts +6 -0
  138. package/dist/app/scripts/VerticalItem.d.ts +3 -0
  139. package/dist/app/scripts/VerticalRule.d.ts +21 -0
  140. package/dist/app/scripts/VerticalTiled1DPixiTrack.d.ts +6 -0
  141. package/dist/app/scripts/VerticalTiledPlot.d.ts +50 -0
  142. package/dist/app/scripts/VerticalTrack.d.ts +6 -0
  143. package/dist/app/scripts/ViewConfigEditor.d.ts +53 -0
  144. package/dist/app/scripts/ViewContextMenu.d.ts +17 -0
  145. package/dist/app/scripts/ViewHeader.d.ts +75 -0
  146. package/dist/app/scripts/ViewportTracker2D.d.ts +17 -0
  147. package/dist/app/scripts/ViewportTracker2DPixi.d.ts +11 -0
  148. package/dist/app/scripts/ViewportTrackerHorizontal.d.ts +17 -0
  149. package/dist/app/scripts/ViewportTrackerVertical.d.ts +17 -0
  150. package/dist/app/scripts/api.d.ts +640 -0
  151. package/dist/app/scripts/configs/available-track-types.d.ts +2 -0
  152. package/dist/app/scripts/configs/colormaps.d.ts +2 -0
  153. package/dist/app/scripts/configs/datatype-to-track-type.d.ts +4 -0
  154. package/dist/app/scripts/configs/default-tracks-for-datatype.d.ts +38 -0
  155. package/dist/app/scripts/configs/dense-data-extrema-config.d.ts +2 -0
  156. package/dist/app/scripts/configs/globals.d.ts +5 -0
  157. package/dist/app/scripts/configs/index.d.ts +16 -0
  158. package/dist/app/scripts/configs/positions-by-datatype.d.ts +2 -0
  159. package/dist/app/scripts/configs/primitives.d.ts +20 -0
  160. package/dist/app/scripts/configs/themes.d.ts +3 -0
  161. package/dist/app/scripts/configs/tracks-info-by-type.d.ts +4 -0
  162. package/dist/app/scripts/configs/tracks-info.d.ts +24 -0
  163. package/dist/app/scripts/d3-context-menu.d.ts +2 -0
  164. package/dist/app/scripts/data-fetchers/DataFetcher.d.ts +151 -0
  165. package/dist/app/scripts/data-fetchers/genbank-fetcher.d.ts +86 -0
  166. package/dist/app/scripts/data-fetchers/index.d.ts +3 -0
  167. package/dist/app/scripts/data-fetchers/local-tile-fetcher.d.ts +47 -0
  168. package/dist/app/scripts/gosling-exports.d.ts +17 -0
  169. package/dist/app/scripts/hglib.d.ts +24 -0
  170. package/dist/app/scripts/hocs/with-modal.d.ts +19 -0
  171. package/dist/app/scripts/hocs/with-pub-sub.d.ts +22 -0
  172. package/dist/app/scripts/hocs/with-theme.d.ts +13 -0
  173. package/dist/app/scripts/icons.d.ts +161 -0
  174. package/dist/app/scripts/mixwith.d.ts +27 -0
  175. package/dist/app/scripts/options-info.d.ts +1355 -0
  176. package/dist/app/scripts/plugins/available-for-plugins.d.ts +2338 -0
  177. package/dist/app/scripts/plugins/get-data-fetcher.d.ts +2 -0
  178. package/dist/app/scripts/plugins/index.d.ts +2 -0
  179. package/dist/app/scripts/services/chrom-info.d.ts +10 -0
  180. package/dist/app/scripts/services/dom-event.d.ts +7 -0
  181. package/dist/app/scripts/services/element-resize-listener.d.ts +5 -0
  182. package/dist/app/scripts/services/index.d.ts +5 -0
  183. package/dist/app/scripts/services/tile-proxy.d.ts +180 -0
  184. package/dist/app/scripts/services/worker.d.ts +157 -0
  185. package/dist/app/scripts/symbol.d.ts +13 -0
  186. package/dist/app/scripts/test-helpers/index.d.ts +1 -0
  187. package/dist/app/scripts/test-helpers/test-helpers.d.ts +33 -0
  188. package/dist/app/scripts/track-utils.d.ts +73 -0
  189. package/dist/app/scripts/types.d.ts +199 -0
  190. package/dist/app/scripts/utils/DenseDataExtrema1D.d.ts +88 -0
  191. package/dist/app/scripts/utils/DenseDataExtrema2D.d.ts +97 -0
  192. package/dist/app/scripts/utils/LruCache.d.ts +44 -0
  193. package/dist/app/scripts/utils/abs-to-chr.d.ts +14 -0
  194. package/dist/app/scripts/utils/accessor-transposition.d.ts +14 -0
  195. package/dist/app/scripts/utils/add-arrays.d.ts +18 -0
  196. package/dist/app/scripts/utils/add-class.d.ts +8 -0
  197. package/dist/app/scripts/utils/add-event-listener-once.d.ts +11 -0
  198. package/dist/app/scripts/utils/assert.d.ts +17 -0
  199. package/dist/app/scripts/utils/background-task-scheduler.d.ts +47 -0
  200. package/dist/app/scripts/utils/base64-to-canvas.d.ts +9 -0
  201. package/dist/app/scripts/utils/chr-to-abs.d.ts +10 -0
  202. package/dist/app/scripts/utils/chrom-info-bisector.d.ts +4 -0
  203. package/dist/app/scripts/utils/clone-event.d.ts +12 -0
  204. package/dist/app/scripts/utils/color-domain-to-rgba-array.d.ts +13 -0
  205. package/dist/app/scripts/utils/color-to-hex.d.ts +9 -0
  206. package/dist/app/scripts/utils/color-to-rgba.d.ts +9 -0
  207. package/dist/app/scripts/utils/copy-text-to-clipboard.d.ts +2 -0
  208. package/dist/app/scripts/utils/data-to-genomic-loci.d.ts +11 -0
  209. package/dist/app/scripts/utils/debounce.d.ts +5 -0
  210. package/dist/app/scripts/utils/dec-to-hex-str.d.ts +8 -0
  211. package/dist/app/scripts/utils/decompress.d.ts +27 -0
  212. package/dist/app/scripts/utils/default-tracks.d.ts +3 -0
  213. package/dist/app/scripts/utils/dict-from-tuples.d.ts +11 -0
  214. package/dist/app/scripts/utils/dict-items.d.ts +18 -0
  215. package/dist/app/scripts/utils/dict-keys.d.ts +10 -0
  216. package/dist/app/scripts/utils/dict-values.d.ts +8 -0
  217. package/dist/app/scripts/utils/download.d.ts +7 -0
  218. package/dist/app/scripts/utils/expand-combined-tracks.d.ts +11 -0
  219. package/dist/app/scripts/utils/fake-pub-sub.d.ts +11 -0
  220. package/dist/app/scripts/utils/fill-in-min-widths.d.ts +44 -0
  221. package/dist/app/scripts/utils/flatten.d.ts +9 -0
  222. package/dist/app/scripts/utils/for-each.d.ts +9 -0
  223. package/dist/app/scripts/utils/forward-event.d.ts +7 -0
  224. package/dist/app/scripts/utils/genome-loci-to-pixels.d.ts +9 -0
  225. package/dist/app/scripts/utils/genomic-range-to-chromosome-chunks.d.ts +21 -0
  226. package/dist/app/scripts/utils/get-aggregation-function.d.ts +10 -0
  227. package/dist/app/scripts/utils/get-default-track-for-datatype.d.ts +21 -0
  228. package/dist/app/scripts/utils/get-default-tracks-for-datatype.d.ts +3 -0
  229. package/dist/app/scripts/utils/get-element-dim.d.ts +7 -0
  230. package/dist/app/scripts/utils/get-higlass-components.d.ts +7 -0
  231. package/dist/app/scripts/utils/get-track-by-uid.d.ts +7 -0
  232. package/dist/app/scripts/utils/get-track-conf-from-hgc.d.ts +10 -0
  233. package/dist/app/scripts/utils/get-track-obj-by-id.d.ts +2 -0
  234. package/dist/app/scripts/utils/get-track-position-by-uid.d.ts +13 -0
  235. package/dist/app/scripts/utils/get-xylofon.d.ts +2 -0
  236. package/dist/app/scripts/utils/gradient.d.ts +14 -0
  237. package/dist/app/scripts/utils/has-class.d.ts +8 -0
  238. package/dist/app/scripts/utils/has-parent.d.ts +9 -0
  239. package/dist/app/scripts/utils/hex-string-to-int.d.ts +14 -0
  240. package/dist/app/scripts/utils/index.d.ts +89 -0
  241. package/dist/app/scripts/utils/interval-tree.d.ts +109 -0
  242. package/dist/app/scripts/utils/into-the-void.d.ts +6 -0
  243. package/dist/app/scripts/utils/is-track-or-child-track.d.ts +7 -0
  244. package/dist/app/scripts/utils/is-track-range-selectable.d.ts +2 -0
  245. package/dist/app/scripts/utils/is-within.d.ts +12 -0
  246. package/dist/app/scripts/utils/lat-to-y.d.ts +9 -0
  247. package/dist/app/scripts/utils/lng-to-x.d.ts +8 -0
  248. package/dist/app/scripts/utils/load-chrom-infos.d.ts +8 -0
  249. package/dist/app/scripts/utils/map.d.ts +13 -0
  250. package/dist/app/scripts/utils/max-non-zero.d.ts +6 -0
  251. package/dist/app/scripts/utils/max.d.ts +10 -0
  252. package/dist/app/scripts/utils/min-non-zero.d.ts +6 -0
  253. package/dist/app/scripts/utils/min.d.ts +10 -0
  254. package/dist/app/scripts/utils/mod.d.ts +9 -0
  255. package/dist/app/scripts/utils/ndarray-assign.d.ts +2 -0
  256. package/dist/app/scripts/utils/ndarray-flatten.d.ts +2 -0
  257. package/dist/app/scripts/utils/ndarray-to-list.d.ts +2 -0
  258. package/dist/app/scripts/utils/numericify-version.d.ts +6 -0
  259. package/dist/app/scripts/utils/obj-vals.d.ts +8 -0
  260. package/dist/app/scripts/utils/or.d.ts +8 -0
  261. package/dist/app/scripts/utils/parse-chromsizes-rows.d.ts +34 -0
  262. package/dist/app/scripts/utils/pixi-text-to-svg.d.ts +2 -0
  263. package/dist/app/scripts/utils/positioned-tracks-to-all-tracks.d.ts +26 -0
  264. package/dist/app/scripts/utils/q.d.ts +18 -0
  265. package/dist/app/scripts/utils/rad-to-deg.d.ts +7 -0
  266. package/dist/app/scripts/utils/range-query-2d.d.ts +17 -0
  267. package/dist/app/scripts/utils/reduce.d.ts +14 -0
  268. package/dist/app/scripts/utils/rel-to-abs-chrom-pos.d.ts +10 -0
  269. package/dist/app/scripts/utils/remove-class.d.ts +7 -0
  270. package/dist/app/scripts/utils/reset-d3-brush-style.d.ts +10 -0
  271. package/dist/app/scripts/utils/rgb-to-hex.d.ts +8 -0
  272. package/dist/app/scripts/utils/scales-center-and-k.d.ts +12 -0
  273. package/dist/app/scripts/utils/scales-to-genome-loci.d.ts +3 -0
  274. package/dist/app/scripts/utils/segments-to-rows.d.ts +15 -0
  275. package/dist/app/scripts/utils/selected-items-to-cum-weights.d.ts +12 -0
  276. package/dist/app/scripts/utils/selected-items-to-size.d.ts +13 -0
  277. package/dist/app/scripts/utils/show-mouse-position.d.ts +54 -0
  278. package/dist/app/scripts/utils/some.d.ts +10 -0
  279. package/dist/app/scripts/utils/sum.d.ts +8 -0
  280. package/dist/app/scripts/utils/svg-line.d.ts +2 -0
  281. package/dist/app/scripts/utils/throttle-and-debounce.d.ts +33 -0
  282. package/dist/app/scripts/utils/tile-to-canvas.d.ts +9 -0
  283. package/dist/app/scripts/utils/timeout.d.ts +3 -0
  284. package/dist/app/scripts/utils/to-void.d.ts +3 -0
  285. package/dist/app/scripts/utils/total-track-pixel-height.d.ts +27 -0
  286. package/dist/app/scripts/utils/trim-trailing-slash.d.ts +7 -0
  287. package/dist/app/scripts/utils/type-guards.d.ts +36 -0
  288. package/dist/app/scripts/utils/value-to-color.d.ts +12 -0
  289. package/dist/app/scripts/utils/visit-positioned-tracks.d.ts +18 -0
  290. package/dist/app/scripts/utils/visit-tracks.d.ts +9 -0
  291. package/dist/esm.html +1 -3
  292. package/dist/hglib.js +65302 -79868
  293. package/dist/hglib.min.js +104 -112
  294. package/dist/higlass.mjs +64214 -78780
  295. package/dist/index.html +1 -3
  296. package/dist/package.json +134 -0
  297. package/package.json +13 -10
@@ -1,4 +1,5 @@
1
1
  // @ts-nocheck
2
+
2
3
  import boxIntersect from 'box-intersect';
3
4
  import { median, range } from 'd3-array';
4
5
  import { scaleBand, scaleLinear } from 'd3-scale';
@@ -6,7 +7,6 @@ import { zoomIdentity } from 'd3-zoom';
6
7
  import classifyPoint from 'robust-point-in-polygon';
7
8
 
8
9
  import HorizontalTiled1DPixiTrack from './HorizontalTiled1DPixiTrack';
9
- import trackUtils from './track-utils';
10
10
 
11
11
  // Services
12
12
  import { tileProxy } from './services';
@@ -15,6 +15,7 @@ import {
15
15
  colorDomainToRgbaArray,
16
16
  colorToHex,
17
17
  segmentsToRows,
18
+ trackUtils,
18
19
  valueToColor,
19
20
  } from './utils';
20
21
 
@@ -29,6 +30,7 @@ const FONT_SIZE = 14;
29
30
  // the label text should have a white outline so that it's more
30
31
  // visible against a similar colored background
31
32
  const TEXT_STYLE = {
33
+ align: 'center',
32
34
  fontSize: `${FONT_SIZE}px`,
33
35
  fontFamily: 'Arial',
34
36
  stroke: 'white',
@@ -40,11 +42,245 @@ const TEXT_STYLE = {
40
42
  dropShadowBlur: 2,
41
43
  };
42
44
 
45
+ /** Scale a polygon * */
46
+ export const polyToPoly = (poly, kx, px, ky, py) => {
47
+ const newArr = [];
48
+
49
+ while (poly.length) {
50
+ const [x, y] = poly.splice(0, 2);
51
+ newArr.push([x * kx + px, y * ky + py]);
52
+ }
53
+
54
+ return newArr;
55
+ };
56
+
57
+ const hashFunc = (s) => {
58
+ let hash = 0;
59
+ if (s.length === 0) {
60
+ return hash;
61
+ }
62
+ for (let i = 0; i < s.length; i++) {
63
+ const char = s.charCodeAt(i);
64
+ hash = (hash << 5) - hash + char;
65
+ hash &= hash; // Convert to 32bit integer
66
+ }
67
+ return hash;
68
+ };
69
+
70
+ const scaleScalableGraphics = (graphics, xScale, drawnAtScale) => {
71
+ const tileK =
72
+ (drawnAtScale.domain()[1] - drawnAtScale.domain()[0]) /
73
+ (xScale.domain()[1] - xScale.domain()[0]);
74
+ const newRange = xScale.domain().map(drawnAtScale);
75
+
76
+ const posOffset = newRange[0];
77
+ graphics.scale.x = tileK;
78
+ graphics.position.x = -posOffset * tileK;
79
+ };
80
+
81
+ export const uniqueify = (elements) => {
82
+ const byUid = {};
83
+ for (let i = 0; i < elements.length; i++) {
84
+ byUid[elements[i].uid] = elements[i];
85
+ }
86
+
87
+ return Object.values(byUid);
88
+ };
89
+
90
+ export class TextManager {
91
+ constructor(track) {
92
+ this.track = track;
93
+ this.texts = {};
94
+
95
+ // store a list of already created texts so that we don't
96
+ // have to recreate new ones each time
97
+ this.textsList = [];
98
+
99
+ this.textWidths = {};
100
+ this.textHeights = {};
101
+
102
+ this.textGraphics = new GLOBALS.PIXI.Graphics();
103
+ this.track.pMain.addChild(this.textGraphics);
104
+
105
+ // Some default font size that will get overwriten when
106
+ // this.textWidths and this.textHeights are set
107
+ this.fontSize = 9;
108
+ }
109
+
110
+ hideOverlaps() {
111
+ const [allBoxes, allTexts] = [this.allBoxes, this.allTexts];
112
+ // Calculate overlaps from the bounding boxes of the texts
113
+
114
+ boxIntersect(allBoxes, (i, j) => {
115
+ if (allTexts[i].importance > allTexts[j].importance) {
116
+ if (allTexts[i].text.visible) {
117
+ allTexts[j].text.visible = false;
118
+ }
119
+ } else if (allTexts[j].text.visible) {
120
+ allTexts[i].text.visible = false;
121
+ }
122
+ });
123
+ }
124
+
125
+ startDraw() {
126
+ this.allBoxes = [];
127
+ this.allTexts = [];
128
+ }
129
+
130
+ lightUpdateSingleText(td, xMiddle, yMiddle, textInfo) {
131
+ if (!this.texts[td.uid]) return;
132
+ if (!this.track.options.showTexts) return;
133
+
134
+ const text = this.texts[td.uid];
135
+
136
+ const TEXT_MARGIN = 3;
137
+
138
+ text.position.x = xMiddle;
139
+ text.position.y = yMiddle;
140
+
141
+ text.visible = true;
142
+ this.allBoxes.push([
143
+ text.position.x - TEXT_MARGIN,
144
+ text.position.y - this.textHeights[td.uid] / 2,
145
+ text.position.x + this.textWidths[td.uid] + TEXT_MARGIN,
146
+ text.position.y + this.textHeights[td.uid] / 2,
147
+ ]);
148
+
149
+ this.allTexts.push({
150
+ text,
151
+ ...textInfo,
152
+ });
153
+ }
154
+
155
+ updateSingleText(td, xMiddle, yMiddle, textText) {
156
+ if (!this.texts[td.uid]) return;
157
+
158
+ const text = this.texts[td.uid];
159
+
160
+ text.position.x = xMiddle;
161
+ text.position.y = yMiddle;
162
+ text.nominalY = yMiddle;
163
+
164
+ const fontColor =
165
+ this.track.options.fontColor !== undefined
166
+ ? colorToHex(this.track.options.fontColor)
167
+ : 'black';
168
+
169
+ const newFontSize = +this.track.options.fontSize || TEXT_STYLE.fontSize;
170
+ if (newFontSize !== this.fontSize) {
171
+ // New font size means different text widths and heights
172
+ this.fontSize = newFontSize;
173
+ this.textWidths = {};
174
+ this.textHeights = {};
175
+ }
176
+
177
+ text.style = {
178
+ ...TEXT_STYLE,
179
+ fill: fontColor,
180
+ fontSize: this.fontSize,
181
+ };
182
+ text.text = textText;
183
+
184
+ if (!(td.uid in this.textWidths)) {
185
+ text.updateTransform();
186
+ const textWidth = text.getBounds().width;
187
+ const textHeight = text.getBounds().height;
188
+
189
+ // the text size adjustment compensates for the extra
190
+ // size that the show gives it
191
+ const TEXT_SIZE_ADJUSTMENT = 5;
192
+
193
+ this.textWidths[td.uid] = textWidth;
194
+ this.textHeights[td.uid] = textHeight - TEXT_SIZE_ADJUSTMENT;
195
+ }
196
+ }
197
+
198
+ updateTexts() {
199
+ if (this.track.options.showTexts) {
200
+ this.texts = {};
201
+
202
+ let yRange = [
203
+ (0 - this.track.vertY) / (this.track.vertK * this.track.prevK),
204
+ (this.track.dimensions[1] - this.track.vertY) /
205
+ (this.track.vertK * this.track.prevK),
206
+ ];
207
+
208
+ const yRangeWidth = yRange[1] - yRange[0];
209
+ yRange = [yRange[0] - yRangeWidth * 0.8, yRange[1] + yRangeWidth * 0.8];
210
+
211
+ const relevantSegments = this.track.uniqueSegments.filter(
212
+ (x) => !x.yMiddle || (x.yMiddle > yRange[0] && x.yMiddle < yRange[1]),
213
+ );
214
+
215
+ relevantSegments.forEach((td, i) => {
216
+ // don't draw too many texts so they don't bog down the frame rate
217
+ if (i >= (+this.track.options.maxTexts || MAX_TEXTS)) {
218
+ return;
219
+ }
220
+
221
+ let text = this.textsList[i];
222
+
223
+ if (!text) {
224
+ text = new GLOBALS.PIXI.Text();
225
+ this.textsList.push(text);
226
+ this.textGraphics.addChild(text);
227
+ }
228
+
229
+ text.style = {
230
+ ...TEXT_STYLE,
231
+ fontSize: +this.track.options.fontSize || TEXT_STYLE.fontSize,
232
+ };
233
+
234
+ // geneInfo[3] is the gene symbol
235
+
236
+ if (this.track.isLeftModified) {
237
+ text.scale.x = -1;
238
+ }
239
+
240
+ text.anchor.x = 0.5;
241
+ text.anchor.y = 0.5;
242
+
243
+ this.texts[td.uid] = text;
244
+ });
245
+
246
+ while (
247
+ this.textsList.length >
248
+ Math.min(
249
+ relevantSegments.length,
250
+ +this.track.options.maxTexts || MAX_TEXTS,
251
+ )
252
+ ) {
253
+ const text = this.textsList.pop();
254
+ this.textGraphics.removeChild(text);
255
+ }
256
+ }
257
+ }
258
+ }
259
+
43
260
  class BedLikeTrack extends HorizontalTiled1DPixiTrack {
44
261
  constructor(context, options) {
45
262
  super(context, options);
46
263
 
47
264
  this.valueScaleTransform = zoomIdentity;
265
+
266
+ this.textManager = new TextManager(this);
267
+
268
+ this.vertY = 1;
269
+ this.vertK = 0;
270
+ this.prevY = 0;
271
+ this.prevK = 1;
272
+
273
+ // we're setting these functions to null so that value scale
274
+ // locking doesn't try to get values from them
275
+ this.minRawValue = null;
276
+ this.maxRawValue = null;
277
+
278
+ this.rectGraphics = new GLOBALS.PIXI.Graphics();
279
+ this.pMain.addChild(this.rectGraphics);
280
+
281
+ this.selectedRect = null;
282
+
283
+ this.uniqueSegments = [];
48
284
  }
49
285
 
50
286
  /** Factor out some initialization code for the track. This is
@@ -71,118 +307,102 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
71
307
  this.initialized = true;
72
308
  }
73
309
 
74
- initTile(tile) {
75
- // create texts
76
- tile.texts = {};
77
-
78
- tile.rectGraphics = new GLOBALS.PIXI.Graphics();
79
- tile.textGraphics = new GLOBALS.PIXI.Graphics();
80
-
81
- tile.graphics.addChild(tile.rectGraphics);
82
- tile.graphics.addChild(tile.textGraphics);
310
+ updateExistingGraphics() {
311
+ const errors = this._checkForErrors();
83
312
 
84
313
  let plusStrandRows = [];
85
314
  let minusStrandRows = [];
86
315
 
87
- if (tile.tileData?.length) {
88
- tile.tileData.sort((a, b) => b.importance - a.importance);
89
- // tile.tileData = tile.tileData.slice(0, MAX_TILE_ENTRIES);
90
-
91
- if (!this.options || !this.options.valueColumn) {
92
- // no value column so we can break entries up into separate
93
- // plus and minus strand segments
94
- const segments = tile.tileData.map((x) => {
95
- const chrOffset = +x.chrOffset;
96
-
97
- return {
98
- from: +x.fields[1] + chrOffset,
99
- to: +x.fields[2] + chrOffset,
100
- value: x,
101
- text: x.fields[3],
102
- strand: x.fields.length >= 6 && x.fields[5] === '-' ? '-' : '+',
103
- };
104
- });
105
-
106
- plusStrandRows = segmentsToRows(
107
- segments.filter((x) => x.strand === '+'),
108
- );
109
- minusStrandRows = segmentsToRows(
110
- segments.filter((x) => x.strand === '-'),
111
- );
112
- } else {
113
- plusStrandRows = [tile.tileData.map((x) => ({ value: x }))];
316
+ if (errors.length > 0) {
317
+ this.draw();
318
+ return;
319
+ }
320
+
321
+ // Object.values(this.fetchedTiles
322
+
323
+ this.uniqueSegments = uniqueify(
324
+ Object.values(this.fetchedTiles)
325
+ .filter((x) => x.tileData.length)
326
+ .flatMap((x) => x.tileData),
327
+ );
328
+
329
+ this.uniqueSegments.forEach((td) => {
330
+ // A random importance helps with selective hiding
331
+ // of overlapping texts
332
+ if (!td.importance) {
333
+ td.importance = hashFunc(td.uid.toString());
114
334
  }
335
+ });
115
336
 
116
- tile.plusStrandRows = plusStrandRows;
117
- tile.minusStrandRows = minusStrandRows;
337
+ this.uniqueSegments.sort((a, b) => b.importance - a.importance);
118
338
 
119
- if (this.options.showTexts) {
120
- tile.tileData.forEach((td, i) => {
121
- const geneInfo = td.fields;
339
+ if (!this.options || !this.options.valueColumn) {
340
+ // no value column so we can break entries up into separate
341
+ // plus and minus strand segments
342
+ const segments = this.uniqueSegments.map((x) => {
343
+ const chrOffset = +x.chrOffset;
122
344
 
123
- // A random importance helps with selective hiding
124
- // of overlapping texts
125
- if (!td.importance) {
126
- td.importance = Math.random();
127
- }
128
- tile.textWidths = {};
129
- tile.textHeights = {};
345
+ return {
346
+ from: +x.fields[1] + chrOffset,
347
+ to: +x.fields[2] + chrOffset,
348
+ value: x,
349
+ text: x.fields[3],
350
+ strand: x.fields.length >= 6 && x.fields[5] === '-' ? '-' : '+',
351
+ };
352
+ });
130
353
 
131
- // don't draw too many texts so they don't bog down the frame rate
132
- if (i >= (+this.options.maxTexts || MAX_TEXTS)) {
133
- return;
134
- }
354
+ plusStrandRows = segmentsToRows(segments.filter((x) => x.strand === '+'));
355
+ minusStrandRows = segmentsToRows(
356
+ segments.filter((x) => x.strand === '-'),
357
+ );
358
+ } else {
359
+ plusStrandRows = [this.uniqueSegments.map((x) => ({ value: x }))];
360
+ }
135
361
 
136
- // geneInfo[3] is the gene symbol
137
- const text = new GLOBALS.PIXI.Text(geneInfo[3], {
138
- ...TEXT_STYLE,
139
- fontSize: +this.options.fontSize || TEXT_STYLE.fontSize,
140
- });
141
- if (this.flipText) {
142
- text.scale.x = -1;
143
- }
362
+ this.plusStrandRows = plusStrandRows;
363
+ this.minusStrandRows = minusStrandRows;
144
364
 
145
- text.anchor.x = 0.5;
146
- text.anchor.y = 0.5;
365
+ this.textManager.updateTexts();
366
+ this.render();
367
+ }
147
368
 
148
- tile.texts[td.uid] = text; // index by geneName
369
+ selectRect(uid) {
370
+ this.selectedRect = uid;
149
371
 
150
- tile.textGraphics.addChild(text);
151
- });
152
- }
153
- }
372
+ this.render();
373
+ this.animate();
374
+ }
154
375
 
155
- tile.initialized = true;
376
+ /** There was a click outside the track so unselect the
377
+ * the current selection */
378
+ clickOutside() {
379
+ this.selectRect(null);
156
380
  }
157
381
 
382
+ initTile(tile) {}
383
+
158
384
  /**
159
385
  * Remove the tile's rectangles from the list of drawnRects so that they
160
386
  * can be drawn again.
161
387
  */
162
- removeTileRects(tile) {
163
- const zoomLevel = +tile.tileId.split('.')[0];
164
- tile.rectGraphics.clear();
165
- tile.rendered = false;
166
-
167
- if (tile.tileData?.length) {
168
- tile.tileData.forEach((td, i) => {
169
- if (this.drawnRects[zoomLevel]?.[td.uid]) {
170
- if (this.drawnRects[zoomLevel][td.uid][2] === tile.tileId) {
171
- // this was the tile that drew that rectangle
172
- delete this.drawnRects[zoomLevel][td.uid];
173
- }
174
- }
175
- });
176
- }
177
- }
178
-
179
- destroyTile(tile) {
180
- // remove texts
181
- this.removeTileRects(tile);
182
-
183
- tile.graphics.removeChild(tile.textGraphics);
184
- tile.graphics.removeChild(tile.rectGraphics);
185
- }
388
+ // removeTileRects(tile) {
389
+ // const zoomLevel = +tile.tileId.split('.')[0];
390
+ // tile.rectGraphics.clear();
391
+ // tile.rendered = false;
392
+
393
+ // if (tile.tileData && tile.tileData.length) {
394
+ // tile.tileData.forEach((td, i) => {
395
+ // if (this.drawnRects[zoomLevel] && this.drawnRects[zoomLevel][td.uid]) {
396
+ // if (this.drawnRects[zoomLevel][td.uid][2] === tile.tileId) {
397
+ // // this was the tile that drew that rectangle
398
+ // delete this.drawnRects[zoomLevel][td.uid];
399
+ // }
400
+ // }
401
+ // });
402
+ // }
403
+ // }
404
+
405
+ destroyTile(tile) {}
186
406
 
187
407
  removeTiles(toRemoveIds) {
188
408
  super.removeTiles(toRemoveIds);
@@ -215,20 +435,16 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
215
435
  this.colorScale = HEATED_OBJECT_MAP;
216
436
  }
217
437
 
218
- for (const tile of this.visibleAndFetchedTiles()) {
219
- this.destroyTile(tile);
220
- this.initTile(tile);
221
- this.renderTile(tile);
222
- }
438
+ this.updateExistingGraphics();
223
439
  }
224
440
 
225
441
  updateTile(tile) {
226
442
  // this.destroyTile(tile);
227
- if (this.areAllVisibleTilesLoaded()) {
228
- // this.destroyTile(tile);
229
- // this.initTile(tile);
230
- this.renderTile(tile);
231
- }
443
+ // if (this.areAllVisibleTilesLoaded()) {
444
+ // this.destroyTile(tile);
445
+ // this.initTile(tile);
446
+ // this.renderTile(tile);
447
+ // }
232
448
  }
233
449
 
234
450
  /**
@@ -276,7 +492,7 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
276
492
  return allRects;
277
493
  }
278
494
 
279
- drawSegmentStyle(tile, xStartPos, xEndPos, rectY, rectHeight, strand) {
495
+ drawSegmentStyle(xStartPos, xEndPos, rectY, rectHeight, strand) {
280
496
  const hw = 0.1; // half width of the line
281
497
 
282
498
  const centerY = rectY + rectHeight / 2;
@@ -308,16 +524,15 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
308
524
  rectY + rectHeight,
309
525
  ];
310
526
 
311
- tile.rectGraphics.drawPolygon(poly);
527
+ this.rectGraphics.drawPolygon(poly);
312
528
  return poly;
313
529
  }
314
530
 
315
- drawPoly(tile, xStartPos, xEndPos, rectY, rectHeight, strand) {
531
+ drawPoly(xStartPos, xEndPos, rectY, rectHeight, strand) {
316
532
  let drawnPoly = null;
317
533
 
318
534
  if (this.options.annotationStyle === 'segment') {
319
535
  return this.drawSegmentStyle(
320
- tile,
321
536
  xStartPos,
322
537
  xEndPos,
323
538
  rectY,
@@ -341,7 +556,7 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
341
556
  ];
342
557
 
343
558
  if (strand === '+') {
344
- tile.rectGraphics.drawPolygon(drawnPoly);
559
+ this.rectGraphics.drawPolygon(drawnPoly);
345
560
  } else {
346
561
  drawnPoly = [
347
562
  xEndPos,
@@ -351,7 +566,7 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
351
566
  xEndPos,
352
567
  rectY + rectHeight, // bottom
353
568
  ];
354
- tile.rectGraphics.drawPolygon(drawnPoly);
569
+ this.rectGraphics.drawPolygon(drawnPoly);
355
570
  }
356
571
  } else {
357
572
  if (strand === '+') {
@@ -393,7 +608,7 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
393
608
  ];
394
609
  }
395
610
 
396
- tile.rectGraphics.drawPolygon(drawnPoly);
611
+ this.rectGraphics.drawPolygon(drawnPoly);
397
612
  }
398
613
 
399
614
  return drawnPoly;
@@ -445,16 +660,14 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
445
660
  }
446
661
  }
447
662
 
448
- renderRows(tile, rows, maxRows, startY, endY, fill) {
449
- const zoomLevel = +tile.tileId.split('.')[0];
663
+ renderRows(rows, maxRows, startY, endY, fill) {
450
664
  let maxValue = Number.MIN_SAFE_INTEGER;
451
665
 
452
666
  this.initialize();
453
667
 
454
- const rowScale = scaleBand()
455
- .domain(range(maxRows))
456
- .range([startY, endY])
457
- .paddingInner(0.3);
668
+ const rowScale = scaleBand().domain(range(maxRows)).range([startY, endY]);
669
+ // .paddingOuter(0.2);
670
+ // .paddingInner(0.3)
458
671
 
459
672
  this.allVisibleRects();
460
673
  let allRects = null;
@@ -469,15 +682,12 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
469
682
  const td = rows[j][i].value;
470
683
  const geneInfo = td.fields;
471
684
 
472
- // the returned positions are chromosome-based and they need to
473
- // be converted to genome-based
474
- const chrOffset = +td.chrOffset;
475
- const txStart = +geneInfo[1] + chrOffset;
476
- const txEnd = +geneInfo[2] + chrOffset;
685
+ const txStart = +td.xStart;
686
+ const txEnd = +td.xEnd;
477
687
  const txMiddle = (txStart + txEnd) / 2;
478
- let yMiddle = rowScale(j) + rowScale.step() / 2;
688
+ let yMiddle = rowScale(j) + rowScale.bandwidth() / 2;
479
689
 
480
- let rectHeight = this.options.annotationHeight || GENE_RECT_HEIGHT;
690
+ let rectHeight = this.options.annotationHeight || 'scaled';
481
691
 
482
692
  if (rectHeight === 'scaled') {
483
693
  rectHeight = rowScale.bandwidth();
@@ -495,7 +705,12 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
495
705
  this.options.colorEncoding === 'itemRgb' &&
496
706
  td.fields[8]
497
707
  ) {
498
- const parts = td.fields[8].split(',');
708
+ let parts = [];
709
+
710
+ try {
711
+ parts = td.fields[8].split(',');
712
+ // eslint-disable-next-line
713
+ } catch {}
499
714
 
500
715
  if (parts.length === 3) {
501
716
  const color = `rgb(${td.fields[8]})`;
@@ -510,6 +725,18 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
510
725
  -Number.MIN_VALUE,
511
726
  )(+geneInfo[+this.options.colorEncoding - 1]);
512
727
  fill = `rgba(${rgb.join(',')})`;
728
+ } else if (
729
+ this.options &&
730
+ this.options.colorEncoding === 'itemRgb' &&
731
+ td.fields[8]
732
+ ) {
733
+ const parts = td.fields[8].split(',');
734
+
735
+ if (parts.length === 3) {
736
+ const color = `rgb(${td.fields[8]})`;
737
+
738
+ fill = color;
739
+ }
513
740
  }
514
741
 
515
742
  if (this.valueScale) {
@@ -517,13 +744,18 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
517
744
  if (value > maxValue) {
518
745
  maxValue = value;
519
746
  }
520
-
521
747
  yMiddle = this.valueScale(value);
522
748
  }
523
749
 
524
750
  const opacity = this.options.fillOpacity || 0.3;
525
- tile.rectGraphics.lineStyle(1, colorToHex(fill), opacity);
526
- tile.rectGraphics.beginFill(colorToHex(fill), opacity);
751
+
752
+ if (this.selectedRect === td.uid) {
753
+ this.rectGraphics.lineStyle(3, 0, 0.75);
754
+ } else {
755
+ this.rectGraphics.lineStyle(1, colorToHex(fill), opacity);
756
+ }
757
+
758
+ this.rectGraphics.beginFill(colorToHex(fill), opacity);
527
759
 
528
760
  let rectY = yMiddle - rectHeight / 2;
529
761
  const xStartPos = this._xScale(txStart);
@@ -538,114 +770,58 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
538
770
  rectY += STAGGERED_OFFSET / 2;
539
771
  }
540
772
  }
773
+ const drawnPoly = this.drawPoly(
774
+ xStartPos,
775
+ xEndPos,
776
+ rectY * this.prevK,
777
+ rectHeight * this.prevK,
778
+ geneInfo[5],
779
+ );
541
780
 
542
- let alreadyDrawn = true;
543
-
544
- // don't draw anything that has already been drawn
545
- if (
546
- !(
547
- zoomLevel in this.drawnRects && td.uid in this.drawnRects[zoomLevel]
548
- )
549
- ) {
550
- alreadyDrawn = false;
551
-
552
- if (!this.drawnRects[zoomLevel]) this.drawnRects[zoomLevel] = {};
781
+ this.drawnRects[td.uid] = [
782
+ drawnPoly,
783
+ {
784
+ start: txStart,
785
+ end: txEnd,
786
+ value: td,
787
+ fill,
788
+ },
789
+ ];
553
790
 
554
- const drawnPoly = this.drawPoly(
555
- tile,
556
- xStartPos,
557
- xEndPos,
558
- rectY * this.prevK,
559
- rectHeight * this.prevK,
560
- geneInfo[5],
561
- );
791
+ td.yMiddle = yMiddle;
562
792
 
563
- this.drawnRects[zoomLevel][td.uid] = [
564
- drawnPoly,
565
- {
566
- start: txStart,
567
- end: txEnd,
568
- value: td,
569
- tile,
570
- fill,
571
- },
572
- tile.tileId,
573
- ];
793
+ if (!this.options.showTexts) {
794
+ continue;
574
795
  }
575
796
 
576
- if (!this.options.showTexts) continue;
577
-
578
- // tile probably hasn't been initialized yet
579
- if (!tile.texts) return;
580
-
581
797
  // don't draw too many texts so they don't bog down the frame rate
582
798
  if (i >= (+this.options.maxTexts || MAX_TEXTS)) continue;
583
799
 
584
- if (!tile.texts[td.uid]) continue;
585
-
586
- const text = tile.texts[td.uid];
587
-
588
- text.position.x = this._xScale(txMiddle);
589
- text.position.y = rectY + rectHeight / 2;
590
- text.nominalY = rectY + rectHeight / 2;
591
-
592
- if (alreadyDrawn) {
593
- text.alreadyDrawn = true;
594
- }
595
-
596
- const fontColor =
597
- this.options.fontColor !== undefined
598
- ? colorToHex(this.options.fontColor)
599
- : fill;
600
-
601
- text.style = {
602
- ...TEXT_STYLE,
603
- fill: fontColor,
604
- fontSize: +this.options.fontSize || TEXT_STYLE.fontSize,
605
- };
606
-
607
- if (!(geneInfo[3] in tile.textWidths)) {
608
- text.updateTransform();
609
- const textWidth = text.getBounds().width;
610
- const textHeight = text.getBounds().height;
611
-
612
- // the text size adjustment compensates for the extra
613
- // size that the show gives it
614
- const TEXT_SIZE_ADJUSTMENT = 5;
615
-
616
- tile.textWidths[geneInfo[3]] = textWidth;
617
- tile.textHeights[geneInfo[3]] = textHeight - TEXT_SIZE_ADJUSTMENT;
618
- }
800
+ this.textManager.updateSingleText(
801
+ td,
802
+ this._xScale(txMiddle),
803
+ rectY + rectHeight / 2,
804
+ td.fields[3],
805
+ );
619
806
  }
620
807
  }
621
- }
622
-
623
- renderTile(tile) {
624
- let maxPlusRows = tile.plusStrandRows ? tile.plusStrandRows.length : 1;
625
- let maxMinusRows = tile.minusStrandRows ? tile.minusStrandRows.length : 1;
626
808
 
627
- // const visibleAndFetchedTiles = this.visibleAndFetchedTiles();
809
+ this.textManager.updateTexts();
810
+ }
628
811
 
629
- // if (!visibleAndFetchedTiles.length) return;
812
+ render() {
813
+ const maxPlusRows = this.plusStrandRows ? this.plusStrandRows.length : 1;
814
+ const maxMinusRows = this.minusStrandRows ? this.minusStrandRows.length : 1;
630
815
 
631
- for (const otherTile of this.visibleAndFetchedTiles()) {
632
- if (!otherTile.initialized) return;
633
- if (!otherTile.plusStrandRows && !otherTile.minusStrandRows) continue;
816
+ this.prevVertY = this.vertY;
634
817
 
635
- maxPlusRows = Math.max(otherTile.plusStrandRows.length, maxPlusRows);
636
- maxMinusRows = Math.max(otherTile.minusStrandRows.length, maxMinusRows);
637
- }
818
+ const oldRectGraphics = this.rectGraphics;
819
+ this.rectGraphics = new GLOBALS.PIXI.Graphics();
638
820
 
639
821
  // store the scale at while the tile was drawn at so that
640
822
  // we only resize it when redrawing
641
823
 
642
- if (tile.rendered) {
643
- this.removeTileRects(tile);
644
- }
645
-
646
- tile.drawnAtScale = this._xScale.copy();
647
- tile.rendered = true;
648
-
824
+ this.drawnAtScale = this._xScale.copy();
649
825
  // configure vertical positioning of annotations if
650
826
  // this.options.valueColumn is set
651
827
  this.setValueScale();
@@ -654,44 +830,39 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
654
830
  // this.options.colorEncoding is set
655
831
  this.setColorValueScale();
656
832
 
657
- if (tile.tileData?.length) {
658
- const fill =
659
- this.options.plusStrandColor || this.options.fillColor || 'blue';
660
- const minusStrandFill =
661
- this.options.minusStrandColor || this.options.fillColor || 'purple';
662
-
663
- const MIDDLE_SPACE = 0;
664
- let plusHeight = 0;
833
+ const fill =
834
+ this.options.plusStrandColor || this.options.fillColor || 'blue';
835
+ const minusStrandFill =
836
+ this.options.minusStrandColor || this.options.fillColor || 'purple';
665
837
 
666
- if (this.options.separatePlusMinusStrands) {
667
- plusHeight =
668
- (maxPlusRows * this.dimensions[1]) / (maxPlusRows + maxMinusRows) -
669
- MIDDLE_SPACE / 2;
670
- } else {
671
- plusHeight = this.dimensions[1];
672
- }
838
+ const MIDDLE_SPACE = 0;
839
+ let plusHeight = 0;
673
840
 
674
- this.renderRows(
675
- tile,
676
- tile.plusStrandRows,
677
- maxPlusRows,
678
- 0,
679
- plusHeight,
680
- fill,
681
- );
682
- this.renderRows(
683
- tile,
684
- tile.minusStrandRows,
685
- maxMinusRows,
686
- this.options.separatePlusMinusStrands
687
- ? plusHeight + MIDDLE_SPACE / 2
688
- : 0,
689
- this.dimensions[1],
690
- minusStrandFill,
691
- );
841
+ if (this.options.separatePlusMinusStrands) {
842
+ plusHeight =
843
+ (maxPlusRows * this.dimensions[1]) / (maxPlusRows + maxMinusRows) -
844
+ MIDDLE_SPACE / 2;
845
+ } else {
846
+ plusHeight = this.dimensions[1];
692
847
  }
693
848
 
694
- trackUtils.stretchRects(this, [(x) => x.rectGraphics]);
849
+ this.renderRows(this.plusStrandRows, maxPlusRows, 0, plusHeight, fill);
850
+ this.renderRows(
851
+ this.minusStrandRows,
852
+ maxMinusRows,
853
+ this.options.separatePlusMinusStrands ? plusHeight + MIDDLE_SPACE / 2 : 0,
854
+ this.dimensions[1],
855
+ minusStrandFill,
856
+ );
857
+
858
+ this.pMain.removeChild(oldRectGraphics);
859
+ // this.pMain.removeChild(oldTextGraphics);
860
+
861
+ this.pMain.addChild(this.rectGraphics);
862
+ // this.pMain.addChild(this.textGraphics);
863
+
864
+ scaleScalableGraphics(this.rectGraphics, this._xScale, this.drawnAtScale);
865
+ // scaleScalableGraphics(this.textGraphics, this._xScale, this.drawnAtScale);
695
866
  }
696
867
 
697
868
  calculateZoomLevel() {
@@ -804,97 +975,45 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
804
975
  draw() {
805
976
  super.draw();
806
977
 
807
- this.allTexts = [];
808
- this.allBoxes = [];
809
-
810
- for (const fetchedTileId in this.fetchedTiles) {
811
- const tile = this.fetchedTiles[fetchedTileId];
812
-
813
- // these values control vertical scaling and they
814
- // need to be set in the draw method otherwise when
815
- // the window is resized, the zoomedY method won't
816
- // be called
817
- tile.rectGraphics.scale.y = this.vertK;
818
- tile.rectGraphics.position.y = this.vertY;
819
-
820
- // hasn't been rendered yet
821
- if (!tile.drawnAtScale) {
822
- return;
823
- }
824
-
825
- trackUtils.stretchRects(this, [(x) => x.rectGraphics]);
826
-
827
- // move the texts
828
-
829
- const parentInFetched = this.parentInFetched(tile);
978
+ this.textManager.startDraw();
830
979
 
831
- if (!tile.initialized) {
832
- continue;
833
- }
834
-
835
- if (tile.tileData?.length) {
836
- tile.tileData.forEach((td) => {
837
- if (!tile.texts) {
838
- // tile probably hasn't been initialized yet
839
- return;
840
- }
841
-
842
- const geneInfo = td.fields;
843
- const geneName = geneInfo[3];
844
- const text = tile.texts[td.uid];
980
+ // these values control vertical scaling and they
981
+ // need to be set in the draw method otherwise when
982
+ // the window is resized, the zoomedY method won't
983
+ // be called
984
+ this.rectGraphics.scale.y = this.vertK;
985
+ this.rectGraphics.position.y = this.vertY;
845
986
 
846
- if (!text) {
847
- return;
848
- }
849
-
850
- const chrOffset = +td.chrOffset;
851
- const txStart = +geneInfo[1] + chrOffset;
852
- const txEnd = +geneInfo[2] + chrOffset;
853
- const txMiddle = (txStart + txEnd) / 2;
854
-
855
- text.position.x = this._xScale(txMiddle);
856
- text.position.y =
857
- text.nominalY * (this.vertK * this.prevK) + this.vertY;
858
-
859
- if (!parentInFetched && !text.alreadyDrawn) {
860
- text.visible = true;
861
- // TODO, change the line below to true if texts are desired in the future
862
- // text.visible = false;
863
- const TEXT_MARGIN = 3;
864
- this.allBoxes.push([
865
- text.position.x - TEXT_MARGIN,
866
- text.position.y - tile.textHeights[geneInfo[3]] / 2,
867
- text.position.x + tile.textWidths[geneInfo[3]] + TEXT_MARGIN,
868
- text.position.y + tile.textHeights[geneInfo[3]] / 2,
869
- ]);
870
- this.allTexts.push({
871
- importance: td.importance,
872
- text,
873
- caption: geneName,
874
- strand: geneInfo[5],
875
- });
876
- } else {
877
- text.visible = false;
878
- }
879
- });
880
- }
987
+ // hasn't been rendered yet
988
+ if (!this.drawnAtScale) {
989
+ return;
881
990
  }
882
991
 
883
- this.hideOverlaps(this.allBoxes, this.allTexts);
884
- }
885
-
886
- hideOverlaps(allBoxes, allTexts) {
887
- // Calculate overlaps from the bounding boxes of the texts
992
+ scaleScalableGraphics(this.rectGraphics, this._xScale, this.drawnAtScale);
993
+ // scaleScalableGraphics(this.textGraphics, this._xScale, this.drawnAtScale);
888
994
 
889
- boxIntersect(allBoxes, (i, j) => {
890
- if (allTexts[i].importance > allTexts[j].importance) {
891
- if (allTexts[i].text.visible) {
892
- allTexts[j].text.visible = false;
995
+ if (this.uniqueSegments?.length) {
996
+ this.uniqueSegments.forEach((td) => {
997
+ const geneInfo = td.fields;
998
+ const geneName = geneInfo[3];
999
+
1000
+ const xMiddle = this._xScale((td.xStart + td.xEnd) / 2);
1001
+ if (this.textManager.texts[td.uid]) {
1002
+ const yMiddle =
1003
+ this.textManager.texts[td.uid].nominalY *
1004
+ (this.vertK * this.prevK) +
1005
+ this.vertY;
1006
+
1007
+ this.textManager.lightUpdateSingleText(td, xMiddle, yMiddle, {
1008
+ importance: td.importance,
1009
+ caption: geneName,
1010
+ strand: geneInfo[5],
1011
+ });
893
1012
  }
894
- } else if (allTexts[j].text.visible) {
895
- allTexts[i].text.visible = false;
896
- }
897
- });
1013
+ });
1014
+ }
1015
+
1016
+ this.textManager.hideOverlaps();
898
1017
  }
899
1018
 
900
1019
  setPosition(newPosition) {
@@ -939,101 +1058,93 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
939
1058
  output.appendChild(rectOutput);
940
1059
  output.appendChild(textOutput);
941
1060
 
942
- for (const tile of this.visibleAndFetchedTiles()) {
943
- if (!tile.tileData.length) {
944
- continue;
945
- }
946
-
947
- tile.tileData.forEach((td) => {
948
- const zoomLevel = +tile.tileId.split('.')[0];
1061
+ this.uniqueSegments.forEach((td) => {
1062
+ const gTile = document.createElement('g');
1063
+ gTile.setAttribute(
1064
+ 'transform',
1065
+ `translate(${this.rectGraphics.position.x},${this.rectGraphics.position.y})scale(${this.rectGraphics.scale.x},${this.rectGraphics.scale.y})`,
1066
+ );
1067
+ rectOutput.appendChild(gTile);
949
1068
 
950
- const gTile = document.createElement('g');
951
- gTile.setAttribute(
952
- 'transform',
953
- `translate(${tile.rectGraphics.position.x},${tile.rectGraphics.position.y})scale(${tile.rectGraphics.scale.x},${tile.rectGraphics.scale.y})`,
954
- );
955
- rectOutput.appendChild(gTile);
1069
+ if (this.drawnRects && td.uid in this.drawnRects) {
1070
+ const rect = this.drawnRects[td.uid][0];
1071
+ const r = document.createElement('path');
956
1072
 
957
- if (
958
- this.drawnRects[zoomLevel] &&
959
- td.uid in this.drawnRects[zoomLevel]
960
- ) {
961
- const rect = this.drawnRects[zoomLevel][td.uid][0];
962
- const r = document.createElement('path');
963
- let d = `M ${rect[0]} ${rect[1]}`;
1073
+ let d = `M ${rect[0]} ${rect[1]}`;
964
1074
 
965
- for (let i = 2; i < rect.length; i += 2) {
966
- d += ` L ${rect[i]} ${rect[i + 1]}`;
967
- }
1075
+ for (let i = 2; i < rect.length; i += 2) {
1076
+ d += ` L ${rect[i]} ${rect[i + 1]}`;
1077
+ }
968
1078
 
969
- const fill = this.drawnRects[zoomLevel][td.uid][1].fill;
970
- const fontColor =
971
- this.options.fontColor !== undefined
972
- ? colorToHex(this.options.fontColor)
973
- : fill;
1079
+ const fill = this.drawnRects[td.uid][1].fill;
1080
+ const fontColor =
1081
+ this.options.fontColor !== undefined
1082
+ ? colorToHex(this.options.fontColor)
1083
+ : fill;
974
1084
 
975
- r.setAttribute('d', d);
976
- r.setAttribute('fill', fill);
977
- r.setAttribute('opacity', 0.3);
1085
+ r.setAttribute('d', d);
1086
+ r.setAttribute('fill', fill);
1087
+ r.setAttribute('opacity', 0.3);
978
1088
 
979
- r.style.stroke = fill;
980
- r.style.strokeWidth = '1px';
1089
+ r.style.stroke = fill;
1090
+ r.style.strokeWidth = '1px';
981
1091
 
982
- gTile.appendChild(r);
1092
+ gTile.appendChild(r);
983
1093
 
984
- if (tile.texts[td.uid]) {
985
- const text = tile.texts[td.uid];
1094
+ if (this.textManager.texts[td.uid]) {
1095
+ const text = this.textManager.texts[td.uid];
986
1096
 
987
- if (!text.visible) {
988
- return;
989
- }
1097
+ if (!text.visible) {
1098
+ return;
1099
+ }
990
1100
 
991
- const g = document.createElement('g');
992
- const t = document.createElement('text');
1101
+ const g = document.createElement('g');
1102
+ const t = document.createElement('text');
993
1103
 
994
- textOutput.appendChild(g);
995
- g.appendChild(t);
996
- g.setAttribute(
997
- 'transform',
998
- `translate(${text.x},${text.y})scale(${text.scale.x},1)`,
999
- );
1104
+ textOutput.appendChild(g);
1105
+ g.appendChild(t);
1106
+ g.setAttribute(
1107
+ 'transform',
1108
+ `translate(${text.x},${text.y})scale(${text.scale.x},1)`,
1109
+ );
1000
1110
 
1001
- t.setAttribute('text-anchor', 'middle');
1002
- t.setAttribute('font-family', TEXT_STYLE.fontFamily);
1003
- t.setAttribute(
1004
- 'font-size',
1005
- +this.options.fontSize || TEXT_STYLE.fontSize,
1006
- );
1007
- t.setAttribute('font-weight', 'bold');
1008
- t.setAttribute('dy', '5px');
1009
- t.setAttribute('fill', fontColor);
1010
- t.setAttribute('stroke', TEXT_STYLE.stroke);
1011
- t.setAttribute('stroke-width', '0.4');
1012
- t.setAttribute('text-shadow', '0px 0px 2px grey');
1013
-
1014
- t.innerHTML = text.text;
1015
- }
1111
+ t.setAttribute('text-anchor', 'middle');
1112
+ t.setAttribute('font-family', TEXT_STYLE.fontFamily);
1113
+ t.setAttribute(
1114
+ 'font-size',
1115
+ +this.options.fontSize || TEXT_STYLE.fontSize,
1116
+ );
1117
+ t.setAttribute('font-weight', 'bold');
1118
+ t.setAttribute('dy', '5px');
1119
+ t.setAttribute('fill', fontColor);
1120
+ t.setAttribute('stroke', TEXT_STYLE.stroke);
1121
+ t.setAttribute('stroke-width', '0.4');
1122
+ t.setAttribute('text-shadow', '0px 0px 2px grey');
1123
+
1124
+ t.innerHTML = text.text;
1016
1125
  }
1017
- });
1018
- }
1126
+ }
1127
+ });
1019
1128
 
1020
1129
  return [base, base];
1021
1130
  }
1022
1131
 
1023
1132
  /** Move event for the y-axis */
1024
1133
  movedY(dY) {
1025
- Object.values(this.fetchedTiles).forEach((tile) => {
1026
- const vst = this.valueScaleTransform;
1027
- const { y, k } = vst;
1028
- const height = this.dimensions[1];
1029
- // clamp at the bottom and top
1030
- if (y + dY / k > -(k - 1) * height && y + dY / k < 0) {
1031
- this.valueScaleTransform = vst.translate(0, dY / k);
1032
- }
1033
- tile.rectGraphics.position.y = this.valueScaleTransform.y;
1034
- this.vertY = this.valueScaleTransform.y;
1035
- });
1134
+ const vst = this.valueScaleTransform;
1135
+ const { y, k } = vst;
1136
+ const height = this.dimensions[1];
1137
+ // clamp at the bottom and top
1138
+ if (y + dY / k > -(k - 1) * height && y + dY / k < 0) {
1139
+ this.valueScaleTransform = vst.translate(0, dY / k);
1140
+ }
1141
+ this.rectGraphics.position.y = this.valueScaleTransform.y;
1142
+ this.vertY = this.valueScaleTransform.y;
1036
1143
  this.animate();
1144
+
1145
+ if (this.vertY - this.prevVertY > this.dimensions[1] / 2) {
1146
+ this.render();
1147
+ }
1037
1148
  }
1038
1149
 
1039
1150
  /** Zoomed along the y-axis */
@@ -1065,13 +1176,14 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
1065
1176
  this.vertK = k1;
1066
1177
  this.vertY = t1;
1067
1178
 
1068
- Object.values(this.fetchedTiles).forEach((tile) => {
1069
- if (toStretch) this.renderTile(tile);
1070
-
1071
- tile.rectGraphics.scale.y = k1;
1072
- tile.rectGraphics.position.y = t1;
1073
- });
1179
+ if (toStretch) {
1180
+ this.render();
1181
+ }
1182
+ this.rectGraphics.scale.y = k1;
1183
+ this.rectGraphics.position.y = t1;
1074
1184
 
1185
+ // this.textGraphics.scale.y = k1;
1186
+ // this.textGraphics.position.y = t1;
1075
1187
  this.draw();
1076
1188
  this.animate();
1077
1189
  }
@@ -1081,40 +1193,36 @@ class BedLikeTrack extends HorizontalTiled1DPixiTrack {
1081
1193
  return '';
1082
1194
  }
1083
1195
 
1084
- const zoomLevel = this.calculateZoomLevel();
1085
- const point = [trackX, trackY];
1086
-
1087
- if (this.drawnRects[zoomLevel]) {
1088
- const visibleRects = Object.values(this.drawnRects[zoomLevel]);
1089
-
1090
- for (let i = 0; i < visibleRects.length; i++) {
1091
- const rect = visibleRects[i][0].slice(0);
1196
+ if (!this.drawnRects) {
1197
+ return '';
1198
+ }
1092
1199
 
1093
- // graphics have been scaled so we need to scale the points themselves
1094
- const tileKx = visibleRects[i][1].tile.rectGraphics.scale.x;
1095
- const tilePx = visibleRects[i][1].tile.rectGraphics.position.x;
1200
+ const closestText = '';
1201
+ const point = [trackX, trackY];
1096
1202
 
1097
- const tileKy = visibleRects[i][1].tile.rectGraphics.scale.y;
1098
- const tilePy = visibleRects[i][1].tile.rectGraphics.position.y;
1203
+ const visibleRects = Object.values(this.drawnRects);
1099
1204
 
1100
- const newArr = [];
1205
+ for (let i = 0; i < visibleRects.length; i++) {
1206
+ const rect = visibleRects[i][0].slice(0);
1101
1207
 
1102
- while (rect.length) {
1103
- const [x, y] = rect.splice(0, 2);
1104
- newArr.push([x * tileKx + tilePx, y * tileKy + tilePy]);
1105
- }
1208
+ const newArr = polyToPoly(
1209
+ rect,
1210
+ this.rectGraphics.scale.x,
1211
+ this.rectGraphics.position.x,
1212
+ this.rectGraphics.scale.y,
1213
+ this.rectGraphics.position.y,
1214
+ );
1106
1215
 
1107
- const pc = classifyPoint(newArr, point);
1216
+ const pc = classifyPoint(newArr, point);
1108
1217
 
1109
- if (pc === -1) {
1110
- const parts = visibleRects[i][1].value.fields;
1218
+ if (pc === -1) {
1219
+ const parts = visibleRects[i][1].value.fields;
1111
1220
 
1112
- return parts.join(' ');
1113
- }
1221
+ return parts.join(' ');
1114
1222
  }
1115
1223
  }
1116
1224
 
1117
- return '';
1225
+ return closestText;
1118
1226
  }
1119
1227
  }
1120
1228