@genome-spy/core 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (523) hide show
  1. package/README.md +1 -0
  2. package/dist/{index.es.js → bundled/index.es.js} +4227 -4085
  3. package/dist/{index.js → bundled/index.js} +191 -55
  4. package/dist/src/data/collector.d.ts +36 -0
  5. package/dist/src/data/collector.d.ts.map +1 -0
  6. package/dist/src/data/collector.js +184 -0
  7. package/dist/src/data/collector.test.js +84 -0
  8. package/dist/src/data/dataFlow.d.ts +65 -0
  9. package/dist/src/data/dataFlow.d.ts.map +1 -0
  10. package/dist/src/data/dataFlow.js +142 -0
  11. package/dist/src/data/dataFlow.test.js +5 -0
  12. package/dist/src/data/facetNode.d.ts +17 -0
  13. package/dist/src/data/facetNode.d.ts.map +1 -0
  14. package/dist/src/data/facetNode.js +17 -0
  15. package/dist/src/data/flow.test.js +72 -0
  16. package/dist/src/data/flowNode.d.ts +136 -0
  17. package/dist/src/data/flowNode.d.ts.map +1 -0
  18. package/dist/src/data/flowNode.js +286 -0
  19. package/dist/src/data/flowNode.test.js +50 -0
  20. package/dist/src/data/flowOptimizer.d.ts +27 -0
  21. package/dist/src/data/flowOptimizer.d.ts.map +1 -0
  22. package/dist/src/data/flowOptimizer.js +133 -0
  23. package/dist/src/data/flowOptimizer.test.js +193 -0
  24. package/dist/src/data/flowTestUtils.d.ts +30 -0
  25. package/dist/src/data/flowTestUtils.d.ts.map +1 -0
  26. package/dist/src/data/flowTestUtils.js +63 -0
  27. package/dist/src/data/formats/fasta.d.ts +20 -0
  28. package/dist/src/data/formats/fasta.d.ts.map +1 -0
  29. package/dist/src/data/formats/fasta.js +32 -0
  30. package/dist/src/data/formats/fasta.test.js +27 -0
  31. package/dist/src/data/sources/dataSource.d.ts +12 -0
  32. package/dist/src/data/sources/dataSource.d.ts.map +1 -0
  33. package/dist/src/data/sources/dataSource.js +25 -0
  34. package/dist/src/data/sources/dataSourceFactory.d.ts +16 -0
  35. package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -0
  36. package/dist/src/data/sources/dataSourceFactory.js +127 -0
  37. package/dist/src/data/sources/dataUtils.d.ts +50 -0
  38. package/dist/src/data/sources/dataUtils.d.ts.map +1 -0
  39. package/dist/src/data/sources/dataUtils.js +83 -0
  40. package/dist/src/data/sources/dynamic/README.md +3 -0
  41. package/dist/src/data/sources/dynamic/axisGenomeSource.d.ts +13 -0
  42. package/dist/src/data/sources/dynamic/axisGenomeSource.d.ts.map +1 -0
  43. package/dist/src/data/sources/dynamic/axisGenomeSource.js +19 -0
  44. package/dist/src/data/sources/dynamic/axisTickSource.d.ts +18 -0
  45. package/dist/src/data/sources/dynamic/axisTickSource.d.ts.map +1 -0
  46. package/dist/src/data/sources/dynamic/axisTickSource.js +73 -0
  47. package/dist/src/data/sources/dynamic/bamSource.d.ts +46 -0
  48. package/dist/src/data/sources/dynamic/bamSource.d.ts.map +1 -0
  49. package/dist/src/data/sources/dynamic/bamSource.js +115 -0
  50. package/dist/src/data/sources/dynamic/bigBedSource.d.ts +51 -0
  51. package/dist/src/data/sources/dynamic/bigBedSource.d.ts.map +1 -0
  52. package/dist/src/data/sources/dynamic/bigBedSource.js +128 -0
  53. package/dist/src/data/sources/dynamic/bigWigSource.d.ts +58 -0
  54. package/dist/src/data/sources/dynamic/bigWigSource.d.ts.map +1 -0
  55. package/dist/src/data/sources/dynamic/bigWigSource.js +166 -0
  56. package/dist/src/data/sources/dynamic/gff3Source.d.ts +8 -0
  57. package/dist/src/data/sources/dynamic/gff3Source.d.ts.map +1 -0
  58. package/dist/src/data/sources/dynamic/gff3Source.js +19 -0
  59. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts +30 -0
  60. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts.map +1 -0
  61. package/dist/src/data/sources/dynamic/indexedFastaSource.js +86 -0
  62. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts +42 -0
  63. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts.map +1 -0
  64. package/dist/src/data/sources/dynamic/singleAxisLazySource.js +129 -0
  65. package/dist/src/data/sources/dynamic/tabixSource.d.ts +54 -0
  66. package/dist/src/data/sources/dynamic/tabixSource.d.ts.map +1 -0
  67. package/dist/src/data/sources/dynamic/tabixSource.js +140 -0
  68. package/dist/src/data/sources/dynamic/windowedMixin.d.ts +32 -0
  69. package/dist/src/data/sources/dynamic/windowedMixin.d.ts.map +1 -0
  70. package/dist/src/data/sources/dynamic/windowedMixin.js +53 -0
  71. package/dist/src/data/sources/inlineSource.d.ts +16 -0
  72. package/dist/src/data/sources/inlineSource.d.ts.map +1 -0
  73. package/dist/src/data/sources/inlineSource.js +68 -0
  74. package/dist/src/data/sources/inlineSource.test.js +56 -0
  75. package/dist/src/data/sources/namedSource.d.ts +25 -0
  76. package/dist/src/data/sources/namedSource.d.ts.map +1 -0
  77. package/dist/src/data/sources/namedSource.js +80 -0
  78. package/dist/src/data/sources/sequenceSource.d.ts +17 -0
  79. package/dist/src/data/sources/sequenceSource.d.ts.map +1 -0
  80. package/dist/src/data/sources/sequenceSource.js +47 -0
  81. package/dist/src/data/sources/sequenceSource.test.js +46 -0
  82. package/dist/src/data/sources/urlSource.d.ts +16 -0
  83. package/dist/src/data/sources/urlSource.d.ts.map +1 -0
  84. package/dist/src/data/sources/urlSource.js +74 -0
  85. package/dist/src/data/transforms/aggregate.d.ts +18 -0
  86. package/dist/src/data/transforms/aggregate.d.ts.map +1 -0
  87. package/dist/src/data/transforms/aggregate.js +67 -0
  88. package/dist/src/data/transforms/clone.d.ts +15 -0
  89. package/dist/src/data/transforms/clone.d.ts.map +1 -0
  90. package/dist/src/data/transforms/clone.js +40 -0
  91. package/dist/src/data/transforms/clone.test.js +11 -0
  92. package/dist/src/data/transforms/coverage.d.ts +30 -0
  93. package/dist/src/data/transforms/coverage.d.ts.map +1 -0
  94. package/dist/src/data/transforms/coverage.js +183 -0
  95. package/dist/src/data/transforms/coverage.test.js +123 -0
  96. package/dist/src/data/transforms/filter.d.ts +12 -0
  97. package/dist/src/data/transforms/filter.d.ts.map +1 -0
  98. package/dist/src/data/transforms/filter.js +33 -0
  99. package/dist/src/data/transforms/filter.test.js +18 -0
  100. package/dist/src/data/transforms/filterScoredLabels.d.ts +29 -0
  101. package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -0
  102. package/dist/src/data/transforms/filterScoredLabels.js +134 -0
  103. package/dist/src/data/transforms/flatten.d.ts +10 -0
  104. package/dist/src/data/transforms/flatten.d.ts.map +1 -0
  105. package/dist/src/data/transforms/flatten.js +68 -0
  106. package/dist/src/data/transforms/flatten.test.js +93 -0
  107. package/dist/src/data/transforms/flattenCompressedExons.d.ts +19 -0
  108. package/dist/src/data/transforms/flattenCompressedExons.d.ts.map +1 -0
  109. package/dist/src/data/transforms/flattenCompressedExons.js +53 -0
  110. package/dist/src/data/transforms/flattenDelimited.d.ts +10 -0
  111. package/dist/src/data/transforms/flattenDelimited.d.ts.map +1 -0
  112. package/dist/src/data/transforms/flattenDelimited.js +66 -0
  113. package/dist/src/data/transforms/flattenDelimited.test.js +87 -0
  114. package/dist/src/data/transforms/flattenSequence.d.ts +11 -0
  115. package/dist/src/data/transforms/flattenSequence.d.ts.map +1 -0
  116. package/dist/src/data/transforms/flattenSequence.js +35 -0
  117. package/dist/src/data/transforms/flattenSequence.test.js +34 -0
  118. package/dist/src/data/transforms/formula.d.ts +13 -0
  119. package/dist/src/data/transforms/formula.d.ts.map +1 -0
  120. package/dist/src/data/transforms/formula.js +35 -0
  121. package/dist/src/data/transforms/formula.test.js +19 -0
  122. package/dist/src/data/transforms/identifier.d.ts +40 -0
  123. package/dist/src/data/transforms/identifier.d.ts.map +1 -0
  124. package/dist/src/data/transforms/identifier.js +106 -0
  125. package/dist/src/data/transforms/identifier.test.js +83 -0
  126. package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts +10 -0
  127. package/dist/src/data/transforms/linearizeGenomicCoordinate.d.ts.map +1 -0
  128. package/dist/src/data/transforms/linearizeGenomicCoordinate.js +97 -0
  129. package/dist/src/data/transforms/measureText.d.ts +18 -0
  130. package/dist/src/data/transforms/measureText.d.ts.map +1 -0
  131. package/dist/src/data/transforms/measureText.js +42 -0
  132. package/dist/src/data/transforms/pileup.d.ts +10 -0
  133. package/dist/src/data/transforms/pileup.d.ts.map +1 -0
  134. package/dist/src/data/transforms/pileup.js +126 -0
  135. package/dist/src/data/transforms/pileup.test.js +70 -0
  136. package/dist/src/data/transforms/project.d.ts +13 -0
  137. package/dist/src/data/transforms/project.d.ts.map +1 -0
  138. package/dist/src/data/transforms/project.js +38 -0
  139. package/dist/src/data/transforms/project.test.js +32 -0
  140. package/dist/src/data/transforms/regexExtract.d.ts +13 -0
  141. package/dist/src/data/transforms/regexExtract.d.ts.map +1 -0
  142. package/dist/src/data/transforms/regexExtract.js +57 -0
  143. package/dist/src/data/transforms/regexExtract.test.js +67 -0
  144. package/dist/src/data/transforms/regexFold.d.ts +14 -0
  145. package/dist/src/data/transforms/regexFold.d.ts.map +1 -0
  146. package/dist/src/data/transforms/regexFold.js +139 -0
  147. package/dist/src/data/transforms/regexFold.test.js +160 -0
  148. package/dist/src/data/transforms/sample.d.ts +42 -0
  149. package/dist/src/data/transforms/sample.d.ts.map +1 -0
  150. package/dist/src/data/transforms/sample.js +99 -0
  151. package/dist/src/data/transforms/sample.test.js +38 -0
  152. package/dist/src/data/transforms/stack.d.ts +11 -0
  153. package/dist/src/data/transforms/stack.d.ts.map +1 -0
  154. package/dist/src/data/transforms/stack.js +134 -0
  155. package/dist/src/data/transforms/stack.test.js +91 -0
  156. package/dist/src/data/transforms/transformFactory.d.ts +12 -0
  157. package/dist/src/data/transforms/transformFactory.d.ts.map +1 -0
  158. package/dist/src/data/transforms/transformFactory.js +59 -0
  159. package/dist/src/encoder/accessor.d.ts +15 -0
  160. package/dist/src/encoder/accessor.d.ts.map +1 -0
  161. package/dist/src/encoder/accessor.js +76 -0
  162. package/dist/src/encoder/accessor.test.js +47 -0
  163. package/dist/src/encoder/encoder.d.ts +144 -0
  164. package/dist/src/encoder/encoder.d.ts.map +1 -0
  165. package/dist/src/encoder/encoder.js +400 -0
  166. package/dist/src/encoder/encoder.test.js +98 -0
  167. package/dist/src/fonts/Lato-Regular.json +1267 -0
  168. package/dist/src/fonts/Lato-Regular.png +0 -0
  169. package/dist/src/fonts/OFL.txt +93 -0
  170. package/dist/src/fonts/README.md +3 -0
  171. package/dist/src/fonts/bmFontManager.d.ts +182 -0
  172. package/dist/src/fonts/bmFontManager.d.ts.map +1 -0
  173. package/dist/src/fonts/bmFontManager.js +359 -0
  174. package/dist/src/fonts/bmFontMetrics.d.ts +45 -0
  175. package/dist/src/fonts/bmFontMetrics.d.ts.map +1 -0
  176. package/dist/src/fonts/bmFontMetrics.js +108 -0
  177. package/dist/src/genome/genome.d.ts +172 -0
  178. package/dist/src/genome/genome.d.ts.map +1 -0
  179. package/dist/src/genome/genome.js +379 -0
  180. package/dist/src/genome/genome.test.js +226 -0
  181. package/dist/src/genome/genomeStore.d.ts +20 -0
  182. package/dist/src/genome/genomeStore.d.ts.map +1 -0
  183. package/dist/src/genome/genomeStore.js +54 -0
  184. package/dist/src/genome/locusFormat.d.ts +14 -0
  185. package/dist/src/genome/locusFormat.d.ts.map +1 -0
  186. package/dist/src/genome/locusFormat.js +37 -0
  187. package/dist/src/genome/scaleIndex.d.ts +6 -0
  188. package/dist/src/genome/scaleIndex.d.ts.map +1 -0
  189. package/dist/src/genome/scaleIndex.js +165 -0
  190. package/dist/src/genome/scaleIndex.test.js +78 -0
  191. package/dist/src/genome/scaleLocus.d.ts +3 -0
  192. package/dist/src/genome/scaleLocus.d.ts.map +1 -0
  193. package/dist/src/genome/scaleLocus.js +101 -0
  194. package/dist/src/genome/scaleLocus.test.js +4 -0
  195. package/dist/src/genomeSpy.d.ts +141 -0
  196. package/dist/src/genomeSpy.d.ts.map +1 -0
  197. package/dist/src/genomeSpy.js +788 -0
  198. package/dist/src/gl/arrayBuilder.d.ts +71 -0
  199. package/dist/src/gl/arrayBuilder.d.ts.map +1 -0
  200. package/dist/src/gl/arrayBuilder.js +199 -0
  201. package/dist/src/gl/dataToVertices.d.ts +194 -0
  202. package/dist/src/gl/dataToVertices.d.ts.map +1 -0
  203. package/dist/src/gl/dataToVertices.js +639 -0
  204. package/dist/src/gl/includes/common.glsl.js +2 -0
  205. package/dist/src/gl/includes/picking.fragment.glsl.js +2 -0
  206. package/dist/src/gl/includes/picking.vertex.glsl.js +2 -0
  207. package/dist/src/gl/includes/sampleFacet.glsl.js +2 -0
  208. package/dist/src/gl/includes/scales.glsl.js +2 -0
  209. package/dist/src/gl/link.fragment.glsl.js +2 -0
  210. package/dist/src/gl/link.vertex.glsl.js +2 -0
  211. package/dist/src/gl/point.fragment.glsl.js +2 -0
  212. package/dist/src/gl/point.vertex.glsl.js +2 -0
  213. package/dist/src/gl/rect.fragment.glsl.js +2 -0
  214. package/dist/src/gl/rect.vertex.glsl.js +2 -0
  215. package/dist/src/gl/rule.fragment.glsl.js +2 -0
  216. package/dist/src/gl/rule.vertex.glsl.js +2 -0
  217. package/dist/src/gl/text.fragment.glsl.js +2 -0
  218. package/dist/src/gl/text.vertex.glsl.js +2 -0
  219. package/dist/src/gl/webGLHelper.d.ts +118 -0
  220. package/dist/src/gl/webGLHelper.d.ts.map +1 -0
  221. package/dist/src/gl/webGLHelper.js +513 -0
  222. package/dist/src/img/bowtie.svg +1 -0
  223. package/dist/src/img/genomespy-favicon.svg +34 -0
  224. package/dist/src/index.d.ts +15 -0
  225. package/dist/src/index.d.ts.map +1 -0
  226. package/dist/src/index.html +11 -0
  227. package/dist/src/index.js +129 -0
  228. package/dist/src/marks/link.d.ts +11 -0
  229. package/dist/src/marks/link.d.ts.map +1 -0
  230. package/dist/src/marks/link.js +175 -0
  231. package/dist/src/marks/mark.d.ts +226 -0
  232. package/dist/src/marks/mark.d.ts.map +1 -0
  233. package/dist/src/marks/mark.js +1004 -0
  234. package/dist/src/marks/markUtils.d.ts +23 -0
  235. package/dist/src/marks/markUtils.d.ts.map +1 -0
  236. package/dist/src/marks/markUtils.js +125 -0
  237. package/dist/src/marks/pointMark.d.ts +11 -0
  238. package/dist/src/marks/pointMark.d.ts.map +1 -0
  239. package/dist/src/marks/pointMark.js +251 -0
  240. package/dist/src/marks/rectMark.d.ts +18 -0
  241. package/dist/src/marks/rectMark.d.ts.map +1 -0
  242. package/dist/src/marks/rectMark.js +255 -0
  243. package/dist/src/marks/rule.d.ts +6 -0
  244. package/dist/src/marks/rule.d.ts.map +1 -0
  245. package/dist/src/marks/rule.js +250 -0
  246. package/dist/src/marks/text.d.ts +13 -0
  247. package/dist/src/marks/text.d.ts.map +1 -0
  248. package/dist/src/marks/text.js +279 -0
  249. package/dist/src/scale/colorUtils.d.ts +34 -0
  250. package/dist/src/scale/colorUtils.d.ts.map +1 -0
  251. package/dist/src/scale/colorUtils.js +184 -0
  252. package/dist/src/scale/glslScaleGenerator.d.ts +45 -0
  253. package/dist/src/scale/glslScaleGenerator.d.ts.map +1 -0
  254. package/dist/src/scale/glslScaleGenerator.js +506 -0
  255. package/dist/src/scale/scale.d.ts +10 -0
  256. package/dist/src/scale/scale.d.ts.map +1 -0
  257. package/dist/src/scale/scale.js +456 -0
  258. package/dist/src/scale/scale.test.js +324 -0
  259. package/dist/src/scale/ticks.d.ts +47 -0
  260. package/dist/src/scale/ticks.d.ts.map +1 -0
  261. package/dist/src/scale/ticks.js +203 -0
  262. package/dist/src/scale/ticks.test.js +40 -0
  263. package/dist/src/singlePageApp.d.ts +2 -0
  264. package/dist/src/singlePageApp.d.ts.map +1 -0
  265. package/dist/src/singlePageApp.js +13 -0
  266. package/dist/src/spec/axis.d.ts +402 -0
  267. package/dist/src/spec/channel.d.ts +440 -0
  268. package/dist/src/spec/data.d.ts +370 -0
  269. package/dist/src/spec/font.d.ts +15 -0
  270. package/dist/src/spec/genome.d.ts +35 -0
  271. package/dist/src/spec/mark.d.ts +435 -0
  272. package/dist/src/spec/root.d.ts +22 -0
  273. package/dist/src/spec/sampleView.d.ts +185 -0
  274. package/dist/src/spec/scale.d.ts +273 -0
  275. package/dist/src/spec/title.d.ts +102 -0
  276. package/dist/src/spec/tooltip.d.ts +9 -0
  277. package/dist/src/spec/transform.d.ts +504 -0
  278. package/dist/src/spec/view.d.ts +214 -0
  279. package/dist/src/styles/genome-spy.css.d.ts +3 -0
  280. package/dist/src/styles/genome-spy.css.d.ts.map +1 -0
  281. package/dist/src/styles/genome-spy.css.js +114 -0
  282. package/dist/src/styles/genome-spy.scss +153 -0
  283. package/dist/src/tooltip/dataTooltipHandler.d.ts +2 -0
  284. package/dist/src/tooltip/dataTooltipHandler.d.ts.map +1 -0
  285. package/dist/src/tooltip/dataTooltipHandler.js +64 -0
  286. package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts +2 -0
  287. package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts.map +1 -0
  288. package/dist/src/tooltip/refseqGeneTooltipHandler.js +78 -0
  289. package/dist/src/tooltip/tooltipHandler.d.ts +9 -0
  290. package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -0
  291. package/dist/src/tooltip/tooltipHandler.ts +12 -0
  292. package/dist/src/types/bmFont.d.ts +58 -0
  293. package/dist/src/types/embedApi.d.ts +67 -0
  294. package/dist/src/types/encoder.d.ts +84 -0
  295. package/dist/src/types/flowBatch.d.ts +40 -0
  296. package/dist/src/types/rendering.d.ts +65 -0
  297. package/dist/src/types/scaleResolutionApi.d.ts +40 -0
  298. package/dist/src/types/viewContext.d.ts +85 -0
  299. package/dist/src/utils/addBaseUrl.d.ts +6 -0
  300. package/dist/src/utils/addBaseUrl.d.ts.map +1 -0
  301. package/dist/src/utils/addBaseUrl.js +19 -0
  302. package/dist/src/utils/addBaseUrl.test.js +22 -0
  303. package/dist/src/utils/animator.d.ts +41 -0
  304. package/dist/src/utils/animator.d.ts.map +1 -0
  305. package/dist/src/utils/animator.js +83 -0
  306. package/dist/src/utils/arrayUtils.d.ts +34 -0
  307. package/dist/src/utils/arrayUtils.d.ts.map +1 -0
  308. package/dist/src/utils/arrayUtils.js +61 -0
  309. package/dist/src/utils/binnedIndex.d.ts +23 -0
  310. package/dist/src/utils/binnedIndex.d.ts.map +1 -0
  311. package/dist/src/utils/binnedIndex.js +167 -0
  312. package/dist/src/utils/binnedIndex.test.js +155 -0
  313. package/dist/src/utils/clamp.d.ts +7 -0
  314. package/dist/src/utils/clamp.d.ts.map +1 -0
  315. package/dist/src/utils/clamp.js +8 -0
  316. package/dist/src/utils/cloner.d.ts +16 -0
  317. package/dist/src/utils/cloner.d.ts.map +1 -0
  318. package/dist/src/utils/cloner.js +34 -0
  319. package/dist/src/utils/cloner.test.js +24 -0
  320. package/dist/src/utils/coalesce.d.ts +6 -0
  321. package/dist/src/utils/coalesce.d.ts.map +1 -0
  322. package/dist/src/utils/coalesce.js +11 -0
  323. package/dist/src/utils/coalesce.test.js +16 -0
  324. package/dist/src/utils/concatIterables.d.ts +8 -0
  325. package/dist/src/utils/concatIterables.d.ts.map +1 -0
  326. package/dist/src/utils/concatIterables.js +26 -0
  327. package/dist/src/utils/concatIterables.test.js +8 -0
  328. package/dist/src/utils/debounce.d.ts +8 -0
  329. package/dist/src/utils/debounce.d.ts.map +1 -0
  330. package/dist/src/utils/debounce.js +37 -0
  331. package/dist/src/utils/domainArray.d.ts +61 -0
  332. package/dist/src/utils/domainArray.d.ts.map +1 -0
  333. package/dist/src/utils/domainArray.js +216 -0
  334. package/dist/src/utils/domainArray.test.js +130 -0
  335. package/dist/src/utils/eerp.d.ts +12 -0
  336. package/dist/src/utils/eerp.d.ts.map +1 -0
  337. package/dist/src/utils/eerp.js +13 -0
  338. package/dist/src/utils/expression.d.ts +9 -0
  339. package/dist/src/utils/expression.d.ts.map +1 -0
  340. package/dist/src/utils/expression.js +32 -0
  341. package/dist/src/utils/field.d.ts +17 -0
  342. package/dist/src/utils/field.d.ts.map +1 -0
  343. package/dist/src/utils/field.js +28 -0
  344. package/dist/src/utils/formatObject.d.ts +7 -0
  345. package/dist/src/utils/formatObject.d.ts.map +1 -0
  346. package/dist/src/utils/formatObject.js +37 -0
  347. package/dist/src/utils/indexer.d.ts +16 -0
  348. package/dist/src/utils/indexer.d.ts.map +1 -0
  349. package/dist/src/utils/indexer.js +43 -0
  350. package/dist/src/utils/indexer.test.js +47 -0
  351. package/dist/src/utils/inertia.d.ts +42 -0
  352. package/dist/src/utils/inertia.d.ts.map +1 -0
  353. package/dist/src/utils/inertia.js +124 -0
  354. package/dist/src/utils/interactionEvent.d.ts +26 -0
  355. package/dist/src/utils/interactionEvent.d.ts.map +1 -0
  356. package/dist/src/utils/interactionEvent.js +33 -0
  357. package/dist/src/utils/iterateNestedMaps.d.ts +11 -0
  358. package/dist/src/utils/iterateNestedMaps.d.ts.map +1 -0
  359. package/dist/src/utils/iterateNestedMaps.js +21 -0
  360. package/dist/src/utils/iterateNestedMaps.test.js +33 -0
  361. package/dist/src/utils/kWayMerge.d.ts +9 -0
  362. package/dist/src/utils/kWayMerge.d.ts.map +1 -0
  363. package/dist/src/utils/kWayMerge.js +42 -0
  364. package/dist/src/utils/kWayMerge.test.js +26 -0
  365. package/dist/src/utils/layout/flexLayout.d.ts +182 -0
  366. package/dist/src/utils/layout/flexLayout.d.ts.map +1 -0
  367. package/dist/src/utils/layout/flexLayout.js +381 -0
  368. package/dist/src/utils/layout/flexLayout.test.js +323 -0
  369. package/dist/src/utils/layout/grid.d.ts +29 -0
  370. package/dist/src/utils/layout/grid.d.ts.map +1 -0
  371. package/dist/src/utils/layout/grid.js +95 -0
  372. package/dist/src/utils/layout/grid.test.js +71 -0
  373. package/dist/src/utils/layout/padding.d.ts +83 -0
  374. package/dist/src/utils/layout/padding.d.ts.map +1 -0
  375. package/dist/src/utils/layout/padding.js +155 -0
  376. package/dist/src/utils/layout/point.d.ts +16 -0
  377. package/dist/src/utils/layout/point.d.ts.map +1 -0
  378. package/dist/src/utils/layout/point.js +23 -0
  379. package/dist/src/utils/layout/rectangle.d.ts +142 -0
  380. package/dist/src/utils/layout/rectangle.d.ts.map +1 -0
  381. package/dist/src/utils/layout/rectangle.js +296 -0
  382. package/dist/src/utils/layout/rectangle.test.js +172 -0
  383. package/dist/src/utils/mergeObjects.d.ts +15 -0
  384. package/dist/src/utils/mergeObjects.d.ts.map +1 -0
  385. package/dist/src/utils/mergeObjects.js +99 -0
  386. package/dist/src/utils/mergeObjects.test.js +42 -0
  387. package/dist/src/utils/numberExtractor.d.ts +9 -0
  388. package/dist/src/utils/numberExtractor.d.ts.map +1 -0
  389. package/dist/src/utils/numberExtractor.js +24 -0
  390. package/dist/src/utils/numberExtractor.test.js +6 -0
  391. package/dist/src/utils/point.d.ts +9 -0
  392. package/dist/src/utils/point.d.ts.map +1 -0
  393. package/dist/src/utils/point.js +14 -0
  394. package/dist/src/utils/propertyCacher.d.ts +30 -0
  395. package/dist/src/utils/propertyCacher.d.ts.map +1 -0
  396. package/dist/src/utils/propertyCacher.js +70 -0
  397. package/dist/src/utils/propertyCacher.test.js +85 -0
  398. package/dist/src/utils/propertyCoalescer.d.ts +15 -0
  399. package/dist/src/utils/propertyCoalescer.d.ts.map +1 -0
  400. package/dist/src/utils/propertyCoalescer.js +42 -0
  401. package/dist/src/utils/propertyCoalescer.test.js +22 -0
  402. package/dist/src/utils/reservationMap.d.ts +42 -0
  403. package/dist/src/utils/reservationMap.d.ts.map +1 -0
  404. package/dist/src/utils/reservationMap.js +103 -0
  405. package/dist/src/utils/reservationMap.test.js +20 -0
  406. package/dist/src/utils/scaleNull.d.ts +13 -0
  407. package/dist/src/utils/scaleNull.d.ts.map +1 -0
  408. package/dist/src/utils/scaleNull.js +21 -0
  409. package/dist/src/utils/setOperations.d.ts +31 -0
  410. package/dist/src/utils/setOperations.d.ts.map +1 -0
  411. package/dist/src/utils/setOperations.js +75 -0
  412. package/dist/src/utils/smoothstep.d.ts +7 -0
  413. package/dist/src/utils/smoothstep.d.ts.map +1 -0
  414. package/dist/src/utils/smoothstep.js +10 -0
  415. package/dist/src/utils/throttle.d.ts +8 -0
  416. package/dist/src/utils/throttle.d.ts.map +1 -0
  417. package/dist/src/utils/throttle.js +34 -0
  418. package/dist/src/utils/topK.d.ts +22 -0
  419. package/dist/src/utils/topK.d.ts.map +1 -0
  420. package/dist/src/utils/topK.js +76 -0
  421. package/dist/src/utils/topK.test.js +64 -0
  422. package/dist/src/utils/transition.d.ts +44 -0
  423. package/dist/src/utils/transition.d.ts.map +1 -0
  424. package/dist/src/utils/transition.js +74 -0
  425. package/dist/src/utils/trees.d.ts +56 -0
  426. package/dist/src/utils/trees.d.ts.map +1 -0
  427. package/dist/src/utils/trees.js +92 -0
  428. package/dist/src/utils/trees.test.js +130 -0
  429. package/dist/src/utils/ui/tooltip.d.ts +50 -0
  430. package/dist/src/utils/ui/tooltip.d.ts.map +1 -0
  431. package/dist/src/utils/ui/tooltip.js +189 -0
  432. package/dist/src/utils/url.d.ts +9 -0
  433. package/dist/src/utils/url.d.ts.map +1 -0
  434. package/dist/src/utils/url.js +22 -0
  435. package/dist/src/utils/variableTools.d.ts +14 -0
  436. package/dist/src/utils/variableTools.d.ts.map +1 -0
  437. package/dist/src/utils/variableTools.js +24 -0
  438. package/dist/src/utils/variableTools.test.js +13 -0
  439. package/dist/src/view/axisGridView.d.ts +39 -0
  440. package/dist/src/view/axisGridView.d.ts.map +1 -0
  441. package/dist/src/view/axisGridView.js +246 -0
  442. package/dist/src/view/axisResolution.d.ts +24 -0
  443. package/dist/src/view/axisResolution.d.ts.map +1 -0
  444. package/dist/src/view/axisResolution.js +141 -0
  445. package/dist/src/view/axisResolution.test.js +201 -0
  446. package/dist/src/view/axisView.d.ts +49 -0
  447. package/dist/src/view/axisView.d.ts.map +1 -0
  448. package/dist/src/view/axisView.js +629 -0
  449. package/dist/src/view/concatView.d.ts +16 -0
  450. package/dist/src/view/concatView.d.ts.map +1 -0
  451. package/dist/src/view/concatView.js +84 -0
  452. package/dist/src/view/containerView.d.ts +43 -0
  453. package/dist/src/view/containerView.d.ts.map +1 -0
  454. package/dist/src/view/containerView.js +137 -0
  455. package/dist/src/view/facetView.d.ts +71 -0
  456. package/dist/src/view/facetView.d.ts.map +1 -0
  457. package/dist/src/view/facetView.js +492 -0
  458. package/dist/src/view/flowBuilder.d.ts +37 -0
  459. package/dist/src/view/flowBuilder.d.ts.map +1 -0
  460. package/dist/src/view/flowBuilder.js +383 -0
  461. package/dist/src/view/flowBuilder.test.js +125 -0
  462. package/dist/src/view/gridView.d.ts +111 -0
  463. package/dist/src/view/gridView.d.ts.map +1 -0
  464. package/dist/src/view/gridView.js +1086 -0
  465. package/dist/src/view/implicitRootView.d.ts +9 -0
  466. package/dist/src/view/implicitRootView.d.ts.map +1 -0
  467. package/dist/src/view/implicitRootView.js +23 -0
  468. package/dist/src/view/importView.d.ts +17 -0
  469. package/dist/src/view/importView.d.ts.map +1 -0
  470. package/dist/src/view/importView.js +22 -0
  471. package/dist/src/view/layerView.d.ts +25 -0
  472. package/dist/src/view/layerView.d.ts.map +1 -0
  473. package/dist/src/view/layerView.js +77 -0
  474. package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts +30 -0
  475. package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts.map +1 -0
  476. package/dist/src/view/renderingContext/bufferedViewRenderingContext.js +175 -0
  477. package/dist/src/view/renderingContext/compositeViewRenderingContext.d.ts +14 -0
  478. package/dist/src/view/renderingContext/compositeViewRenderingContext.d.ts.map +1 -0
  479. package/dist/src/view/renderingContext/compositeViewRenderingContext.js +51 -0
  480. package/dist/src/view/renderingContext/debuggingViewRenderingContext.d.ts +51 -0
  481. package/dist/src/view/renderingContext/debuggingViewRenderingContext.d.ts.map +1 -0
  482. package/dist/src/view/renderingContext/debuggingViewRenderingContext.js +94 -0
  483. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts +60 -0
  484. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts.map +1 -0
  485. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.js +128 -0
  486. package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts +19 -0
  487. package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts.map +1 -0
  488. package/dist/src/view/renderingContext/simpleViewRenderingContext.js +64 -0
  489. package/dist/src/view/renderingContext/svgViewRenderingContext.d.ts +22 -0
  490. package/dist/src/view/renderingContext/svgViewRenderingContext.d.ts.map +1 -0
  491. package/dist/src/view/renderingContext/svgViewRenderingContext.js +125 -0
  492. package/dist/src/view/renderingContext/viewRenderingContext.d.ts +33 -0
  493. package/dist/src/view/renderingContext/viewRenderingContext.d.ts.map +1 -0
  494. package/dist/src/view/renderingContext/viewRenderingContext.js +41 -0
  495. package/dist/src/view/scaleResolution.d.ts +170 -0
  496. package/dist/src/view/scaleResolution.d.ts.map +1 -0
  497. package/dist/src/view/scaleResolution.js +874 -0
  498. package/dist/src/view/scaleResolution.test.js +658 -0
  499. package/dist/src/view/testUtils.d.ts +30 -0
  500. package/dist/src/view/testUtils.d.ts.map +1 -0
  501. package/dist/src/view/testUtils.js +101 -0
  502. package/dist/src/view/title.d.ts +6 -0
  503. package/dist/src/view/title.d.ts.map +1 -0
  504. package/dist/src/view/title.js +165 -0
  505. package/dist/src/view/unitView.d.ts +93 -0
  506. package/dist/src/view/unitView.d.ts.map +1 -0
  507. package/dist/src/view/unitView.js +345 -0
  508. package/dist/src/view/view.d.ts +291 -0
  509. package/dist/src/view/view.d.ts.map +1 -0
  510. package/dist/src/view/view.js +691 -0
  511. package/dist/src/view/view.test.js +214 -0
  512. package/dist/src/view/viewFactory.d.ts +76 -0
  513. package/dist/src/view/viewFactory.d.ts.map +1 -0
  514. package/dist/src/view/viewFactory.js +178 -0
  515. package/dist/src/view/viewFactory.test.js +17 -0
  516. package/dist/src/view/viewUtils.d.ts +90 -0
  517. package/dist/src/view/viewUtils.d.ts.map +1 -0
  518. package/dist/src/view/viewUtils.js +326 -0
  519. package/dist/src/view/zoom.d.ts +23 -0
  520. package/dist/src/view/zoom.d.ts.map +1 -0
  521. package/dist/src/view/zoom.js +89 -0
  522. package/package.json +15 -12
  523. package/dist/style.css +0 -1
@@ -0,0 +1,1086 @@
1
+ /* eslint-disable max-depth */
2
+ import { primaryPositionalChannels } from "../encoder/encoder";
3
+ import {
4
+ FlexDimensions,
5
+ getLargestSize,
6
+ mapToPixelCoords,
7
+ parseSizeDef,
8
+ ZERO_SIZEDEF,
9
+ } from "../utils/layout/flexLayout";
10
+ import Grid from "../utils/layout/grid";
11
+ import Padding from "../utils/layout/padding";
12
+ import Rectangle from "../utils/layout/rectangle";
13
+ import AxisGridView from "./axisGridView";
14
+ import AxisView, { CHANNEL_ORIENTS, ORIENT_CHANNELS } from "./axisView";
15
+ import ContainerView from "./containerView";
16
+ import LayerView from "./layerView";
17
+ import createTitle from "./title";
18
+ import UnitView from "./unitView";
19
+ import interactionToZoom from "./zoom";
20
+
21
+ /**
22
+ * Modeled after: https://vega.github.io/vega/docs/layout/
23
+ *
24
+ * This should take care of the following:
25
+ * - Composition: [hv]concat / facet / repeat
26
+ * - Views
27
+ * - Axes
28
+ * - Grid lines
29
+ * - View background
30
+ * - View titles
31
+ * - Facet (column / row) titles
32
+ * - Header / footer
33
+ * - Zoom / pan
34
+ * - And later on, brushing, legend(?)
35
+ */
36
+ export default class GridView extends ContainerView {
37
+ /**
38
+ * @typedef {"row" | "column"} Direction
39
+ *
40
+ * @typedef {import("./view").default} View
41
+ */
42
+
43
+ /** */
44
+ #columns = Infinity;
45
+
46
+ #spacing = 10;
47
+
48
+ /**
49
+ * @type { GridChild[] }
50
+ */
51
+ #children = [];
52
+
53
+ /**
54
+ * Note: shared axes are not included in #children because we have to handle
55
+ * toggleable view visibilities. For example, if the bottom view is suddenly hidden,
56
+ * the axis should be shown in the view that takes its place as the new bottom view.
57
+ *
58
+ * @type { Partial<Record<import("../spec/channel").PrimaryPositionalChannel, AxisView>> } }
59
+ */
60
+ #sharedAxes = {};
61
+
62
+ #childSerial = 0;
63
+
64
+ /**
65
+ *
66
+ * @param {import("../spec/view").AnyConcatSpec} spec
67
+ * @param {import("../types/viewContext").default} context
68
+ * @param {ContainerView} layoutParent
69
+ * @param {View} dataParent
70
+ * @param {string} name
71
+ * @param {number} columns
72
+ */
73
+ constructor(spec, context, layoutParent, dataParent, name, columns) {
74
+ super(spec, context, layoutParent, dataParent, name);
75
+ this.spec = spec;
76
+
77
+ this.#spacing = spec.spacing ?? 10;
78
+ this.#columns = columns;
79
+
80
+ this.#children = [];
81
+
82
+ this.wrappingFacet = false;
83
+
84
+ this._createChildren();
85
+ }
86
+
87
+ /**
88
+ * @protected
89
+ */
90
+ _createChildren() {
91
+ // Override
92
+ }
93
+
94
+ /**
95
+ * @param {View} view
96
+ */
97
+ appendChild(view) {
98
+ view.layoutParent ??= this;
99
+ this.#children.push(new GridChild(view, this, this.#childSerial));
100
+ this.#childSerial++;
101
+ }
102
+
103
+ get #visibleChildren() {
104
+ return this.#children.filter((gridChild) =>
105
+ gridChild.view.isConfiguredVisible()
106
+ );
107
+ }
108
+
109
+ get #grid() {
110
+ return new Grid(
111
+ this.#visibleChildren.length,
112
+ this.#columns ?? Infinity
113
+ );
114
+ }
115
+
116
+ /**
117
+ * @param {View[]} views
118
+ */
119
+ setChildren(views) {
120
+ this.#children = [];
121
+ for (const view of views) {
122
+ this.appendChild(view);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * @param {View} child
128
+ * @param {View} replacement
129
+ */
130
+ replaceChild(child, replacement) {
131
+ const i = this.#children.findIndex(
132
+ (gridChild) => gridChild.view == child
133
+ );
134
+ if (i >= 0) {
135
+ this.#children[i] = new GridChild(
136
+ replacement,
137
+ this,
138
+ this.#childSerial
139
+ );
140
+ } else {
141
+ throw new Error("Not my child view!");
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Read-only view to children
147
+ */
148
+ get children() {
149
+ return this.#children.map((gridChild) => gridChild.view);
150
+ }
151
+
152
+ get childCount() {
153
+ return this.#children.length;
154
+ }
155
+
156
+ onScalesResolved() {
157
+ super.onScalesResolved();
158
+
159
+ this.#createAxes();
160
+ }
161
+
162
+ #createAxes() {
163
+ // Axis ticks, labels, etc. They should be created only if this view has caught
164
+ // the scale resolution for the channel.
165
+ for (const channel of primaryPositionalChannels) {
166
+ const r = this.resolutions.axis[channel];
167
+ if (r) {
168
+ const props = r.getAxisProps();
169
+ if (props) {
170
+ const propsWithDefaults = {
171
+ title: r.getTitle(),
172
+ orient: CHANNEL_ORIENTS[channel][0],
173
+ ...props,
174
+ };
175
+ // TODO: Validate that channel and orient are compatible
176
+ const v = new AxisView(
177
+ propsWithDefaults,
178
+ r.scaleResolution.type,
179
+ this.context,
180
+ this,
181
+ this
182
+ );
183
+ this.#sharedAxes[channel] = v;
184
+
185
+ // Axes are created after scales are resolved, so we need to resolve possible new scales here
186
+ v.visit((view) => {
187
+ if (view instanceof UnitView) {
188
+ view.resolve("scale");
189
+ }
190
+ });
191
+ }
192
+ }
193
+ }
194
+
195
+ // Create view decorations, grid lines, and independent axes for each child
196
+ for (const gridChild of this.#children) {
197
+ gridChild.createAxes();
198
+ }
199
+ }
200
+
201
+ /**
202
+ * @returns {IterableIterator<View>}
203
+ */
204
+ *[Symbol.iterator]() {
205
+ for (const gridChild of this.#children) {
206
+ yield* gridChild.getChildren();
207
+ }
208
+
209
+ for (const axisView of Object.values(this.#sharedAxes)) {
210
+ yield axisView;
211
+ }
212
+ }
213
+
214
+ /**
215
+ * @param {Direction} direction
216
+ */
217
+ #getSizes(direction) {
218
+ const dim = direction == "column" ? "width" : "height";
219
+
220
+ /**
221
+ * @type {(indices: number[], side: 0 | 1) => number}
222
+ */
223
+ const getMaxAxisSize = (indices, side) =>
224
+ indices
225
+ .map((index) => {
226
+ const child = this.#visibleChildren[index];
227
+ const overhang = child.getOverhangAndPadding();
228
+
229
+ return direction == "column"
230
+ ? side
231
+ ? overhang.right
232
+ : overhang.left
233
+ : side
234
+ ? overhang.bottom
235
+ : overhang.top;
236
+ })
237
+ .reduce((a, b) => Math.max(a, b), 0);
238
+
239
+ return this._cache(`size/directionSizes/${direction}`, () =>
240
+ this.#grid[direction == "column" ? "colIndices" : "rowIndices"].map(
241
+ (col) => ({
242
+ axisBefore: getMaxAxisSize(col, 0),
243
+ axisAfter: getMaxAxisSize(col, 1),
244
+ view: getLargestSize(
245
+ col.map(
246
+ (rowIndex) =>
247
+ this.#visibleChildren[rowIndex].view.getSize()[
248
+ dim
249
+ ]
250
+ )
251
+ ),
252
+ })
253
+ )
254
+ );
255
+ }
256
+
257
+ /**
258
+ * An example layout with two children, either column or row-based direction:
259
+ *
260
+ * 0. title
261
+ * 1. header
262
+ * 2. axis/padding
263
+ * 3. view
264
+ * 4. axis/padding
265
+ * 5. footer (if column and wrapping)
266
+ * 5. spacing
267
+ * 6. header (if column and wrapping)
268
+ * 7. axis/padding
269
+ * 8. view
270
+ * 9. axis/padding
271
+ * 10. footer
272
+ *
273
+ * @param {Direction} direction
274
+ */
275
+ #makeFlexItems(direction) {
276
+ const sizes = this.#getSizes(direction);
277
+
278
+ /** @type {import("../utils/layout/flexLayout").SizeDef[]} */
279
+ const items = [];
280
+
281
+ // Title
282
+ items.push(ZERO_SIZEDEF);
283
+
284
+ for (const [i, size] of sizes.entries()) {
285
+ if (i > 0) {
286
+ // Spacing
287
+ items.push({ px: this.#spacing, grow: 0 });
288
+ }
289
+
290
+ if (i == 0 || this.wrappingFacet) {
291
+ // Header
292
+ items.push(ZERO_SIZEDEF);
293
+ }
294
+
295
+ // Axis/padding
296
+ items.push({ px: size.axisBefore, grow: 0 });
297
+
298
+ // View
299
+ items.push(size.view);
300
+
301
+ // Axis/padding
302
+ items.push({ px: size.axisAfter, grow: 0 });
303
+
304
+ if (i == sizes.length - 1 || this.wrappingFacet) {
305
+ //Footer
306
+ items.push(ZERO_SIZEDEF);
307
+ }
308
+ }
309
+
310
+ return items;
311
+ }
312
+
313
+ /**
314
+ * @param {Direction} direction
315
+ * @return {import("../utils/layout/flexLayout").SizeDef}
316
+ */
317
+ #getFlexSize(direction) {
318
+ let grow = 0;
319
+ let px = 0;
320
+
321
+ const explicitSize =
322
+ (direction == "row" && this.spec.height) ??
323
+ (direction == "column" && this.spec.width);
324
+ if (explicitSize || explicitSize === 0) {
325
+ return parseSizeDef(explicitSize);
326
+ }
327
+
328
+ const sizes = this.#getSizes(direction);
329
+
330
+ for (const [i, size] of sizes.entries()) {
331
+ if (i > 0) {
332
+ // Spacing
333
+ px += this.#spacing;
334
+ }
335
+
336
+ if (i == 0 || this.wrappingFacet) {
337
+ // Header
338
+ px += 0;
339
+ }
340
+
341
+ // Axis/padding
342
+ px += size.axisBefore;
343
+
344
+ // View
345
+ px += size.view.px ?? 0;
346
+ grow += size.view.grow ?? 0;
347
+
348
+ // Axis/padding
349
+ px += size.axisAfter;
350
+
351
+ if (i == sizes.length - 1 || this.wrappingFacet) {
352
+ //Footer
353
+ px += 0;
354
+ }
355
+ }
356
+
357
+ return { px, grow };
358
+ }
359
+
360
+ /**
361
+ * Locates a view slot in FlexLayout
362
+ *
363
+ * @param {Direction} direction
364
+ * @param {number} index column/row number
365
+ */
366
+ #getViewSlot(direction, index) {
367
+ return direction == "row" && this.wrappingFacet
368
+ ? // Views have header/footer on every row
369
+ 1 + 6 * index + 2
370
+ : // Only first row has header, last row has footer.
371
+ 2 + 4 * index + 1;
372
+ }
373
+
374
+ /**
375
+ * @return {Padding}
376
+ */
377
+ getOverhang() {
378
+ return this.#getGridOverhang().union(this.#getSharedAxisOverhang());
379
+ }
380
+
381
+ #getGridOverhang() {
382
+ const cols = this.#getSizes("column");
383
+ const rows = this.#getSizes("row");
384
+
385
+ if (!cols.length || !rows.length) {
386
+ return Padding.zero();
387
+ }
388
+
389
+ return new Padding(
390
+ rows.at(0).axisBefore,
391
+ cols.at(-1).axisAfter,
392
+ rows.at(-1).axisAfter,
393
+ cols.at(0).axisBefore
394
+ );
395
+ }
396
+
397
+ #getSharedAxisOverhang() {
398
+ /**
399
+ * @param {import("../spec/axis").AxisOrient} orient
400
+ */
401
+ const getSharedAxisSize = (orient) => {
402
+ const channel = ORIENT_CHANNELS[orient];
403
+ const axisView = this.#sharedAxes[channel];
404
+ if (axisView?.axisProps.orient !== orient) {
405
+ return 0;
406
+ }
407
+
408
+ return Math.max(
409
+ axisView.getPerpendicularSize() + axisView.axisProps.offset ??
410
+ 0,
411
+ 0
412
+ );
413
+ };
414
+
415
+ return new Padding(
416
+ getSharedAxisSize("top"),
417
+ getSharedAxisSize("right"),
418
+ getSharedAxisSize("bottom"),
419
+ getSharedAxisSize("left")
420
+ );
421
+ }
422
+
423
+ /**
424
+ * @returns {FlexDimensions}
425
+ */
426
+ getSize() {
427
+ return this._cache("size", () =>
428
+ new FlexDimensions(
429
+ this.#getFlexSize("column"),
430
+ this.#getFlexSize("row")
431
+ ).addPadding(this.#getSharedAxisOverhang())
432
+ );
433
+ }
434
+
435
+ /**
436
+ * @param {import("./renderingContext/viewRenderingContext").default} context
437
+ * @param {import("../utils/layout/rectangle").default} coords
438
+ * @param {import("../types/rendering").RenderingOptions} [options]
439
+ */
440
+ // eslint-disable-next-line complexity
441
+ render(context, coords, options = {}) {
442
+ if (!this.isConfiguredVisible()) {
443
+ return;
444
+ }
445
+
446
+ if (!this.layoutParent) {
447
+ // Usually padding is applied by the parent GridView, but if this is the root view, we need to apply it here
448
+ coords = coords.shrink(this.getPadding());
449
+ }
450
+ coords = coords.shrink(this.#getSharedAxisOverhang());
451
+
452
+ context.pushView(this, coords);
453
+
454
+ const flexOpts = {
455
+ devicePixelRatio: this.context.devicePixelRatio,
456
+ };
457
+ const columnFlexCoords = mapToPixelCoords(
458
+ this.#makeFlexItems("column"),
459
+ coords.width,
460
+ flexOpts
461
+ );
462
+
463
+ const rowFlexCoords = mapToPixelCoords(
464
+ this.#makeFlexItems("row"),
465
+ coords.height,
466
+ flexOpts
467
+ );
468
+
469
+ const grid = new Grid(
470
+ this.#visibleChildren.length,
471
+ this.#columns ?? Infinity
472
+ );
473
+
474
+ for (const [i, gridChild] of this.#visibleChildren.entries()) {
475
+ const {
476
+ view,
477
+ axes,
478
+ gridLines,
479
+ background,
480
+ backgroundStroke,
481
+ title,
482
+ } = gridChild;
483
+
484
+ const [col, row] = grid.getCellCoords(i);
485
+ const colLocSize =
486
+ columnFlexCoords[this.#getViewSlot("column", col)];
487
+ const rowLocSize = rowFlexCoords[this.#getViewSlot("row", row)];
488
+
489
+ const size = view.getSize();
490
+ const overhang = view.getOverhang();
491
+
492
+ const x = colLocSize.location - overhang.left;
493
+ const y = rowLocSize.location - overhang.top;
494
+
495
+ const width =
496
+ (size.width.grow ? colLocSize.size : size.width.px) +
497
+ overhang.width;
498
+ const height =
499
+ (size.height.grow ? rowLocSize.size : size.height.px) +
500
+ overhang.height;
501
+
502
+ const childCoords = new Rectangle(
503
+ () => coords.x + x,
504
+ () => coords.y + y,
505
+ () => width,
506
+ () => height
507
+ );
508
+
509
+ gridChild.coords = childCoords;
510
+
511
+ const clippedChildCoords = options.clipRect
512
+ ? childCoords.intersect(options.clipRect)
513
+ : childCoords;
514
+
515
+ background?.render(context, clippedChildCoords, {
516
+ ...options,
517
+ clipRect: undefined,
518
+ });
519
+
520
+ for (const gridLineView of Object.values(gridLines)) {
521
+ gridLineView.render(context, childCoords, options);
522
+ }
523
+
524
+ // If clipped, the axes should be drawn on top of the marks (because clipping may not be pixel-perfect)
525
+ const clipped = isClippedChildren(view);
526
+ if (clipped) {
527
+ view.render(context, childCoords, options);
528
+ }
529
+
530
+ backgroundStroke?.render(context, clippedChildCoords, {
531
+ ...options,
532
+ clipRect: undefined,
533
+ });
534
+
535
+ // Independent axes
536
+ for (const [orient, axisView] of Object.entries(axes)) {
537
+ axisView.render(
538
+ context,
539
+ translateAxisCoords(childCoords, orient, axisView),
540
+ options
541
+ );
542
+ }
543
+
544
+ // Axes shared between children
545
+ for (const axisView of Object.values(this.#sharedAxes)) {
546
+ const props = axisView.axisProps;
547
+ const orient = props.orient;
548
+ if (
549
+ (orient == "left" && col == 0) ||
550
+ (orient == "right" && col == grid.nCols - 1) ||
551
+ (orient == "top" && row == 0) ||
552
+ (orient == "bottom" && row == grid.nRows - 1)
553
+ ) {
554
+ axisView.render(
555
+ context,
556
+ translateAxisCoords(
557
+ childCoords.shrink(gridChild.view.getOverhang()),
558
+ orient,
559
+ axisView
560
+ ),
561
+ options
562
+ );
563
+ }
564
+ }
565
+
566
+ if (!clipped) {
567
+ view.render(context, childCoords, options);
568
+ }
569
+
570
+ title?.render(context, childCoords, options);
571
+ }
572
+
573
+ context.popView(this);
574
+ }
575
+
576
+ /**
577
+ * @param {import("../utils/interactionEvent").default} event
578
+ */
579
+ propagateInteractionEvent(event) {
580
+ this.handleInteractionEvent(undefined, event, true);
581
+
582
+ if (event.stopped) {
583
+ return;
584
+ }
585
+
586
+ const pointedChild = this.#visibleChildren.find((gridChild) =>
587
+ gridChild.coords.containsPoint(event.point.x, event.point.y)
588
+ );
589
+ const pointedView = pointedChild?.view;
590
+ if (pointedView) {
591
+ pointedView.propagateInteractionEvent(event);
592
+
593
+ if (
594
+ pointedView instanceof UnitView ||
595
+ pointedView instanceof LayerView
596
+ ) {
597
+ interactionToZoom(
598
+ event,
599
+ pointedChild.coords,
600
+ (zoomEvent) =>
601
+ this.#handleZoom(
602
+ pointedChild.coords,
603
+ pointedChild.view,
604
+ zoomEvent
605
+ ),
606
+ this.context.getCurrentHover()
607
+ );
608
+ }
609
+ }
610
+
611
+ if (event.stopped) {
612
+ return;
613
+ }
614
+
615
+ this.handleInteractionEvent(undefined, event, false);
616
+ }
617
+
618
+ /**
619
+ *
620
+ * @param {import("../utils/layout/rectangle").default} coords Coordinates
621
+ * @param {View} view
622
+ * @param {import("./zoom").ZoomEvent} zoomEvent
623
+ */
624
+ #handleZoom(coords, view, zoomEvent) {
625
+ for (const [channel, resolutionSet] of Object.entries(
626
+ getZoomableResolutions(view)
627
+ )) {
628
+ if (resolutionSet.size <= 0) {
629
+ continue;
630
+ }
631
+
632
+ const p = coords.normalizePoint(zoomEvent.x, zoomEvent.y);
633
+ const tp = coords.normalizePoint(
634
+ zoomEvent.x + zoomEvent.xDelta,
635
+ zoomEvent.y + zoomEvent.yDelta
636
+ );
637
+
638
+ const delta = {
639
+ x: tp.x - p.x,
640
+ y: tp.y - p.y,
641
+ };
642
+
643
+ for (const resolution of resolutionSet) {
644
+ resolution.zoom(
645
+ 2 ** zoomEvent.zDelta,
646
+ channel == "y" ? 1 - p[channel] : p[channel],
647
+ channel == "x" ? delta.x : -delta.y
648
+ );
649
+ }
650
+ }
651
+
652
+ this.context.animator.requestRender();
653
+ }
654
+
655
+ /**
656
+ * @param {import("../spec/channel").Channel} channel
657
+ * @param {import("../spec/view").ResolutionTarget} resolutionType
658
+ * @returns {import("../spec/view").ResolutionBehavior}
659
+ */
660
+ getDefaultResolution(channel, resolutionType) {
661
+ return "independent";
662
+ }
663
+ }
664
+
665
+ /**
666
+ * @param {import("../spec/view").ViewBackground} viewBackground
667
+ * @returns {import("../spec/view").UnitSpec}
668
+ */
669
+ export function createBackground(viewBackground) {
670
+ if (
671
+ !viewBackground ||
672
+ !viewBackground.fill ||
673
+ viewBackground.fillOpacity === 0
674
+ ) {
675
+ return;
676
+ }
677
+
678
+ return {
679
+ configurableVisibility: false,
680
+ data: { values: [{}] },
681
+ mark: {
682
+ color: viewBackground.fill,
683
+ opacity: viewBackground.fillOpacity ?? 1.0,
684
+ type: "rect",
685
+ clip: false, // Shouldn't be needed
686
+ tooltip: null,
687
+ minHeight: 1,
688
+ minOpacity: 0,
689
+ },
690
+ };
691
+ }
692
+
693
+ /**
694
+ * @param {import("../spec/view").ViewBackground} viewBackground
695
+ * @returns {import("../spec/view").UnitSpec}
696
+ */
697
+ export function createBackgroundStroke(viewBackground) {
698
+ if (
699
+ !viewBackground ||
700
+ !viewBackground.stroke ||
701
+ viewBackground.strokeWidth === 0 ||
702
+ viewBackground.strokeOpacity === 0
703
+ ) {
704
+ return;
705
+ }
706
+
707
+ // Using rules to draw a non-filled rectangle.
708
+ // We are not using a rect mark because it is not optimized for outlines.
709
+ // TODO: Implement "hollow" mesh for non-filled rectangles
710
+ return {
711
+ configurableVisibility: false,
712
+ resolve: {
713
+ scale: { x: "excluded", y: "excluded" },
714
+ axis: { x: "excluded", y: "excluded" },
715
+ },
716
+ data: {
717
+ values: [
718
+ { x: 0, y: 0, x2: 1, y2: 0 },
719
+ { x: 1, y: 0, x2: 1, y2: 1 },
720
+ { x: 1, y: 1, x2: 0, y2: 1 },
721
+ { x: 0, y: 1, x2: 0, y2: 0 },
722
+ ],
723
+ },
724
+ mark: {
725
+ size: viewBackground.strokeWidth ?? 1.0,
726
+ color: viewBackground.stroke ?? "lightgray",
727
+ strokeCap: "square",
728
+ strokeOpacity: viewBackground.strokeOpacity ?? 1.0,
729
+ type: "rule",
730
+ clip: false,
731
+ tooltip: null,
732
+ },
733
+ encoding: {
734
+ x: { field: "x", type: "quantitative", scale: null },
735
+ y: { field: "y", type: "quantitative", scale: null },
736
+ x2: { field: "x2" },
737
+ y2: { field: "y2" },
738
+ },
739
+ };
740
+ }
741
+
742
+ /**
743
+ *
744
+ * @param {View} view
745
+ * @returns
746
+ */
747
+ function getZoomableResolutions(view) {
748
+ /** @type {Record<import("../spec/channel").PrimaryPositionalChannel, Set<import("./scaleResolution").default>>} */
749
+ const resolutions = {
750
+ x: new Set(),
751
+ y: new Set(),
752
+ };
753
+
754
+ // Find all resolutions (scales) that are candidates for zooming
755
+ view.visit((v) => {
756
+ for (const [channel, resolutionSet] of Object.entries(resolutions)) {
757
+ const resolution = v.getScaleResolution(channel);
758
+ if (resolution && resolution.isZoomable()) {
759
+ resolutionSet.add(resolution);
760
+ }
761
+ }
762
+ });
763
+
764
+ return resolutions;
765
+ }
766
+
767
+ /**
768
+ * @param {View} view
769
+ */
770
+ export function isClippedChildren(view) {
771
+ let clipped = true;
772
+
773
+ view.visit((v) => {
774
+ if (v instanceof UnitView) {
775
+ clipped &&= v.mark.properties.clip === true;
776
+ }
777
+ });
778
+
779
+ return clipped;
780
+ }
781
+
782
+ /**
783
+ *
784
+ * @param {import("../utils/layout/rectangle").default} coords
785
+ * @param {import("../spec/axis").AxisOrient} orient
786
+ * @param {AxisView} axisView
787
+ */
788
+ export function translateAxisCoords(coords, orient, axisView) {
789
+ const props = axisView.axisProps;
790
+ const ps = axisView.getPerpendicularSize();
791
+
792
+ if (orient == "bottom") {
793
+ return coords
794
+ .translate(0, coords.height + props.offset)
795
+ .modify({ height: ps });
796
+ } else if (orient == "top") {
797
+ return coords.translate(0, -ps - props.offset).modify({ height: ps });
798
+ } else if (orient == "left") {
799
+ return coords.translate(-ps - props.offset, 0).modify({ width: ps });
800
+ } else if (orient == "right") {
801
+ return coords
802
+ .translate(coords.width + props.offset, 0)
803
+ .modify({ width: ps });
804
+ }
805
+ }
806
+
807
+ export class GridChild {
808
+ /**
809
+ * @param {View} view
810
+ * @param {ContainerView} layoutParent
811
+ * @param {number} serial
812
+ */
813
+ constructor(view, layoutParent, serial) {
814
+ this.layoutParent = layoutParent;
815
+ this.view = view;
816
+ this.serial = serial;
817
+
818
+ /** @type {UnitView} */
819
+ this.background = undefined;
820
+
821
+ /** @type {UnitView} */
822
+ this.backgroundStroke = undefined;
823
+
824
+ /** @type {Partial<Record<import("../spec/axis").AxisOrient, AxisView>>} axes */
825
+ this.axes = {};
826
+
827
+ /** @type {Partial<Record<import("../spec/axis").AxisOrient, AxisGridView>>} gridLines */
828
+ this.gridLines = {};
829
+
830
+ /** @type {UnitView} */
831
+ this.title = undefined;
832
+
833
+ /** @type {Rectangle} */
834
+ this.coords = Rectangle.ZERO;
835
+
836
+ if (view.needsAxes.x || view.needsAxes.y) {
837
+ const spec = view.spec;
838
+ const viewBackground = "view" in spec ? spec?.view : undefined;
839
+
840
+ const backgroundSpec = createBackground(viewBackground);
841
+ if (backgroundSpec) {
842
+ this.background = new UnitView(
843
+ backgroundSpec,
844
+ layoutParent.context,
845
+ layoutParent,
846
+ view,
847
+ "background" + serial
848
+ );
849
+ // TODO: Make configurable through spec:
850
+ this.background.blockEncodingInheritance = true;
851
+ }
852
+
853
+ const backgroundStrokeSpec = createBackgroundStroke(viewBackground);
854
+ if (backgroundStrokeSpec) {
855
+ this.backgroundStroke = new UnitView(
856
+ backgroundStrokeSpec,
857
+ layoutParent.context,
858
+ layoutParent,
859
+ view,
860
+ "backgroundStroke" + serial
861
+ );
862
+ // TODO: Make configurable through spec:
863
+ this.backgroundStroke.blockEncodingInheritance = true;
864
+ }
865
+
866
+ const title = createTitle(view.spec.title);
867
+ if (title) {
868
+ const unitView = new UnitView(
869
+ title,
870
+ layoutParent.context,
871
+ layoutParent,
872
+ view,
873
+ "title" + serial
874
+ );
875
+ // TODO: Make configurable through spec:
876
+ unitView.blockEncodingInheritance = true;
877
+ this.title = unitView;
878
+ }
879
+ }
880
+ }
881
+
882
+ *getChildren() {
883
+ if (this.background) {
884
+ yield this.background;
885
+ }
886
+ if (this.backgroundStroke) {
887
+ yield this.backgroundStroke;
888
+ }
889
+ if (this.title) {
890
+ yield this.title;
891
+ }
892
+ yield* Object.values(this.axes);
893
+ yield* Object.values(this.gridLines);
894
+ yield this.view;
895
+ }
896
+
897
+ /**
898
+ * Create view decorations, grid lines, axes, etc.
899
+ */
900
+ createAxes() {
901
+ const { view, axes, gridLines } = this;
902
+
903
+ /**
904
+ * @param {import("./axisResolution").default} r
905
+ * @param {import("../spec/channel").PrimaryPositionalChannel} channel
906
+ */
907
+ const getAxisPropsWithDefaults = (r, channel) => {
908
+ const propsWithoutDefaults = r.getAxisProps();
909
+ if (propsWithoutDefaults === null) {
910
+ return;
911
+ }
912
+
913
+ const props = propsWithoutDefaults
914
+ ? { ...propsWithoutDefaults }
915
+ : {};
916
+
917
+ // Pick a default orient based on what is available.
918
+ // This logic is needed for layer views that have independent axes.
919
+ if (!props.orient) {
920
+ for (const orient of CHANNEL_ORIENTS[channel]) {
921
+ if (!axes[orient]) {
922
+ props.orient = orient;
923
+ break;
924
+ }
925
+ }
926
+ if (!props.orient) {
927
+ throw new Error(
928
+ "No slots available for an axis! Perhaps a LayerView has more than two children?"
929
+ );
930
+ }
931
+ }
932
+
933
+ props.title ??= r.getTitle();
934
+
935
+ if (!CHANNEL_ORIENTS[channel].includes(props.orient)) {
936
+ throw new Error(
937
+ `Invalid axis orientation "${props.orient}" on channel "${channel}"!`
938
+ );
939
+ }
940
+
941
+ return props;
942
+ };
943
+
944
+ /**
945
+ * @param {import("./axisResolution").default} r
946
+ * @param {import("../spec/channel").PrimaryPositionalChannel} channel
947
+ * @param {View} axisParent
948
+ */
949
+ const createAxis = (r, channel, axisParent) => {
950
+ const props = getAxisPropsWithDefaults(r, channel);
951
+
952
+ if (props) {
953
+ if (axes[props.orient]) {
954
+ throw new Error(
955
+ `An axis with the orient "${props.orient}" already exists!`
956
+ );
957
+ }
958
+
959
+ axes[props.orient] = new AxisView(
960
+ props,
961
+ r.scaleResolution.type,
962
+ this.layoutParent.context,
963
+ this.layoutParent,
964
+ axisParent
965
+ );
966
+ }
967
+ };
968
+
969
+ /**
970
+ * @param {import("./axisResolution").default} r
971
+ * @param {import("../spec/channel").PrimaryPositionalChannel} channel
972
+ * @param {View} axisParent
973
+ */
974
+ const createAxisGrid = (r, channel, axisParent) => {
975
+ const props = getAxisPropsWithDefaults(r, channel);
976
+
977
+ if (props && (props.grid || props.chromGrid)) {
978
+ gridLines[props.orient] = new AxisGridView(
979
+ props,
980
+ r.scaleResolution.type,
981
+ this.layoutParent.context,
982
+ this.layoutParent,
983
+ axisParent
984
+ );
985
+ }
986
+ };
987
+
988
+ // Handle children that have caught axis resolutions. Create axes for them.
989
+ for (const channel of /** @type {import("../spec/channel").PrimaryPositionalChannel[]} */ ([
990
+ "x",
991
+ "y",
992
+ ])) {
993
+ if (view.needsAxes[channel]) {
994
+ const r = view.resolutions.axis[channel];
995
+ if (!r) {
996
+ continue;
997
+ }
998
+
999
+ createAxis(r, channel, view);
1000
+ }
1001
+ }
1002
+
1003
+ // Handle gridlines of children. Note: children's axis resolution may be caught by
1004
+ // this view or some of this view's ancestors.
1005
+ for (const channel of /** @type {import("../spec/channel").PrimaryPositionalChannel[]} */ ([
1006
+ "x",
1007
+ "y",
1008
+ ])) {
1009
+ if (view.needsAxes[channel]) {
1010
+ const r = view.getAxisResolution(channel);
1011
+ if (!r) {
1012
+ continue;
1013
+ }
1014
+
1015
+ // TODO: Optimization: the same grid view could be reused for all children
1016
+ // because they share the axis and scale resolutions anyway.
1017
+ createAxisGrid(r, channel, view);
1018
+ }
1019
+ }
1020
+
1021
+ // Handle LayerView's possible independent axes
1022
+ if (view instanceof LayerView) {
1023
+ // First create axes that have an orient preference
1024
+ for (const layerChild of view.children) {
1025
+ for (const [channel, r] of Object.entries(
1026
+ layerChild.resolutions.axis
1027
+ )) {
1028
+ const props = r.getAxisProps();
1029
+ if (props && props.orient) {
1030
+ createAxis(r, channel, layerChild);
1031
+ }
1032
+ }
1033
+ }
1034
+
1035
+ // Then create axes in a priority order
1036
+ for (const layerChild of view.children) {
1037
+ for (const [channel, r] of Object.entries(
1038
+ layerChild.resolutions.axis
1039
+ )) {
1040
+ const props = r.getAxisProps();
1041
+ if (props && !props.orient) {
1042
+ createAxis(r, channel, layerChild);
1043
+ }
1044
+ }
1045
+ }
1046
+
1047
+ // TODO: Axis grid
1048
+ }
1049
+
1050
+ // Axes are created after scales are resolved, so we need to resolve possible new scales here
1051
+ [...Object.values(axes), ...Object.values(gridLines)].forEach((v) =>
1052
+ v.visit((view) => {
1053
+ if (view instanceof UnitView) {
1054
+ view.resolve("scale");
1055
+ }
1056
+ })
1057
+ );
1058
+ }
1059
+
1060
+ getOverhang() {
1061
+ const calculate = (
1062
+ /** @type {import("../spec/axis").AxisOrient} */ orient
1063
+ ) => {
1064
+ const axisView = this.axes[orient];
1065
+ return axisView
1066
+ ? Math.max(
1067
+ axisView.getPerpendicularSize() +
1068
+ axisView.axisProps.offset ?? 0,
1069
+ 0
1070
+ )
1071
+ : 0;
1072
+ };
1073
+
1074
+ // Axes and overhang should be mutually exclusive, so we can just add them together
1075
+ return new Padding(
1076
+ calculate("top"),
1077
+ calculate("right"),
1078
+ calculate("bottom"),
1079
+ calculate("left")
1080
+ ).add(this.view.getOverhang());
1081
+ }
1082
+
1083
+ getOverhangAndPadding() {
1084
+ return this.getOverhang().add(this.view.getPadding());
1085
+ }
1086
+ }