@genome-spy/core 0.48.2 → 0.50.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 (244) hide show
  1. package/dist/bundle/index.es.js +7434 -7107
  2. package/dist/bundle/index.js +116 -103
  3. package/dist/schema.json +3975 -2819
  4. package/dist/src/data/collector.test.d.ts +2 -0
  5. package/dist/src/data/collector.test.d.ts.map +1 -0
  6. package/dist/src/data/dataFlow.test.d.ts +2 -0
  7. package/dist/src/data/dataFlow.test.d.ts.map +1 -0
  8. package/dist/src/data/flow.test.d.ts +2 -0
  9. package/dist/src/data/flow.test.d.ts.map +1 -0
  10. package/dist/src/data/flow.test.js +19 -14
  11. package/dist/src/data/flowNode.test.d.ts +2 -0
  12. package/dist/src/data/flowNode.test.d.ts.map +1 -0
  13. package/dist/src/data/flowOptimizer.test.d.ts +2 -0
  14. package/dist/src/data/flowOptimizer.test.d.ts.map +1 -0
  15. package/dist/src/data/flowOptimizer.test.js +9 -10
  16. package/dist/src/data/formats/fasta.test.d.ts +2 -0
  17. package/dist/src/data/formats/fasta.test.d.ts.map +1 -0
  18. package/dist/src/data/sources/inlineSource.test.d.ts +2 -0
  19. package/dist/src/data/sources/inlineSource.test.d.ts.map +1 -0
  20. package/dist/src/data/sources/inlineSource.test.js +23 -16
  21. package/dist/src/data/sources/sequenceSource.test.d.ts +2 -0
  22. package/dist/src/data/sources/sequenceSource.test.d.ts.map +1 -0
  23. package/dist/src/data/sources/sequenceSource.test.js +59 -42
  24. package/dist/src/data/transforms/clone.test.d.ts +2 -0
  25. package/dist/src/data/transforms/clone.test.d.ts.map +1 -0
  26. package/dist/src/data/transforms/coverage.test.d.ts +2 -0
  27. package/dist/src/data/transforms/coverage.test.d.ts.map +1 -0
  28. package/dist/src/data/transforms/coverage.test.js +1 -1
  29. package/dist/src/data/transforms/filter.d.ts +10 -0
  30. package/dist/src/data/transforms/filter.d.ts.map +1 -1
  31. package/dist/src/data/transforms/filter.js +30 -1
  32. package/dist/src/data/transforms/filter.test.d.ts +2 -0
  33. package/dist/src/data/transforms/filter.test.d.ts.map +1 -0
  34. package/dist/src/data/transforms/flatten.test.d.ts +2 -0
  35. package/dist/src/data/transforms/flatten.test.d.ts.map +1 -0
  36. package/dist/src/data/transforms/flatten.test.js +10 -7
  37. package/dist/src/data/transforms/flattenDelimited.test.d.ts +2 -0
  38. package/dist/src/data/transforms/flattenDelimited.test.d.ts.map +1 -0
  39. package/dist/src/data/transforms/flattenDelimited.test.js +16 -13
  40. package/dist/src/data/transforms/flattenSequence.test.d.ts +2 -0
  41. package/dist/src/data/transforms/flattenSequence.test.d.ts.map +1 -0
  42. package/dist/src/data/transforms/flattenSequence.test.js +1 -1
  43. package/dist/src/data/transforms/formula.test.d.ts +2 -0
  44. package/dist/src/data/transforms/formula.test.d.ts.map +1 -0
  45. package/dist/src/data/transforms/formula.test.js +1 -1
  46. package/dist/src/data/transforms/identifier.test.d.ts +2 -0
  47. package/dist/src/data/transforms/identifier.test.d.ts.map +1 -0
  48. package/dist/src/data/transforms/pileup.test.d.ts +2 -0
  49. package/dist/src/data/transforms/pileup.test.d.ts.map +1 -0
  50. package/dist/src/data/transforms/project.test.d.ts +2 -0
  51. package/dist/src/data/transforms/project.test.d.ts.map +1 -0
  52. package/dist/src/data/transforms/project.test.js +1 -1
  53. package/dist/src/data/transforms/regexExtract.test.d.ts +2 -0
  54. package/dist/src/data/transforms/regexExtract.test.d.ts.map +1 -0
  55. package/dist/src/data/transforms/regexExtract.test.js +6 -3
  56. package/dist/src/data/transforms/regexFold.test.d.ts +2 -0
  57. package/dist/src/data/transforms/regexFold.test.d.ts.map +1 -0
  58. package/dist/src/data/transforms/sample.test.d.ts +2 -0
  59. package/dist/src/data/transforms/sample.test.d.ts.map +1 -0
  60. package/dist/src/data/transforms/stack.test.d.ts +2 -0
  61. package/dist/src/data/transforms/stack.test.d.ts.map +1 -0
  62. package/dist/src/data/transforms/stack.test.js +8 -8
  63. package/dist/src/encoder/accessor.d.ts +17 -14
  64. package/dist/src/encoder/accessor.d.ts.map +1 -1
  65. package/dist/src/encoder/accessor.js +127 -56
  66. package/dist/src/encoder/accessor.test.d.ts +2 -0
  67. package/dist/src/encoder/accessor.test.d.ts.map +1 -0
  68. package/dist/src/encoder/accessor.test.js +145 -31
  69. package/dist/src/encoder/encoder.d.ts +26 -13
  70. package/dist/src/encoder/encoder.d.ts.map +1 -1
  71. package/dist/src/encoder/encoder.js +98 -114
  72. package/dist/src/encoder/encoder.test.d.ts +2 -0
  73. package/dist/src/encoder/encoder.test.d.ts.map +1 -0
  74. package/dist/src/encoder/encoder.test.js +85 -82
  75. package/dist/src/fonts/bmFontManager.d.ts.map +1 -1
  76. package/dist/src/fonts/bmFontManager.js +10 -4
  77. package/dist/src/genome/genome.test.d.ts +2 -0
  78. package/dist/src/genome/genome.test.d.ts.map +1 -0
  79. package/dist/src/genome/scaleIndex.test.d.ts +2 -0
  80. package/dist/src/genome/scaleIndex.test.d.ts.map +1 -0
  81. package/dist/src/genome/scaleLocus.test.d.ts +2 -0
  82. package/dist/src/genome/scaleLocus.test.d.ts.map +1 -0
  83. package/dist/src/genomeSpy.d.ts +3 -2
  84. package/dist/src/genomeSpy.d.ts.map +1 -1
  85. package/dist/src/genomeSpy.js +15 -6
  86. package/dist/src/gl/dataToVertices.d.ts +6 -8
  87. package/dist/src/gl/dataToVertices.d.ts.map +1 -1
  88. package/dist/src/gl/dataToVertices.js +42 -33
  89. package/dist/src/gl/glslScaleGenerator.d.ts +84 -15
  90. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
  91. package/dist/src/gl/glslScaleGenerator.js +260 -73
  92. package/dist/src/gl/includes/common.glsl.js +1 -1
  93. package/dist/src/marks/link.common.glsl.js +1 -1
  94. package/dist/src/marks/link.d.ts +8 -1
  95. package/dist/src/marks/link.d.ts.map +1 -1
  96. package/dist/src/marks/link.fragment.glsl.js +1 -1
  97. package/dist/src/marks/link.js +47 -31
  98. package/dist/src/marks/link.vertex.glsl.js +1 -1
  99. package/dist/src/marks/mark.d.ts +24 -25
  100. package/dist/src/marks/mark.d.ts.map +1 -1
  101. package/dist/src/marks/mark.js +246 -118
  102. package/dist/src/marks/markUtils.d.ts +25 -0
  103. package/dist/src/marks/markUtils.d.ts.map +1 -1
  104. package/dist/src/marks/markUtils.js +41 -1
  105. package/dist/src/marks/point.common.glsl.js +1 -1
  106. package/dist/src/marks/point.d.ts +8 -1
  107. package/dist/src/marks/point.d.ts.map +1 -1
  108. package/dist/src/marks/point.js +34 -25
  109. package/dist/src/marks/point.vertex.glsl.js +1 -1
  110. package/dist/src/marks/rect.d.ts +8 -1
  111. package/dist/src/marks/rect.d.ts.map +1 -1
  112. package/dist/src/marks/rect.js +28 -23
  113. package/dist/src/marks/rule.d.ts +8 -1
  114. package/dist/src/marks/rule.d.ts.map +1 -1
  115. package/dist/src/marks/rule.js +23 -16
  116. package/dist/src/marks/text.d.ts +10 -1
  117. package/dist/src/marks/text.d.ts.map +1 -1
  118. package/dist/src/marks/text.fragment.glsl.js +1 -1
  119. package/dist/src/marks/text.js +53 -47
  120. package/dist/src/marks/text.vertex.glsl.js +1 -1
  121. package/dist/src/scale/scale.test.d.ts +2 -0
  122. package/dist/src/scale/scale.test.d.ts.map +1 -0
  123. package/dist/src/scale/scale.test.js +2 -0
  124. package/dist/src/scale/ticks.test.d.ts +2 -0
  125. package/dist/src/scale/ticks.test.d.ts.map +1 -0
  126. package/dist/src/scale/ticks.test.js +6 -0
  127. package/dist/src/selection/selection.d.ts +39 -0
  128. package/dist/src/selection/selection.d.ts.map +1 -0
  129. package/dist/src/selection/selection.js +78 -0
  130. package/dist/src/spec/channel.d.ts +150 -83
  131. package/dist/src/spec/mark.d.ts +133 -78
  132. package/dist/src/spec/parameter.d.ts +112 -3
  133. package/dist/src/spec/root.d.ts +0 -1
  134. package/dist/src/spec/transform.d.ts +19 -1
  135. package/dist/src/spec/view.d.ts +5 -10
  136. package/dist/src/tooltip/dataTooltipHandler.d.ts +1 -1
  137. package/dist/src/tooltip/dataTooltipHandler.d.ts.map +1 -1
  138. package/dist/src/tooltip/dataTooltipHandler.js +1 -1
  139. package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts +1 -1
  140. package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts.map +1 -1
  141. package/dist/src/types/encoder.d.ts +80 -26
  142. package/dist/src/types/rendering.d.ts +1 -0
  143. package/dist/src/types/selectionTypes.d.ts +44 -0
  144. package/dist/src/types/viewContext.d.ts +1 -4
  145. package/dist/src/utils/addBaseUrl.test.d.ts +2 -0
  146. package/dist/src/utils/addBaseUrl.test.d.ts.map +1 -0
  147. package/dist/src/utils/binnedIndex.test.d.ts +2 -0
  148. package/dist/src/utils/binnedIndex.test.d.ts.map +1 -0
  149. package/dist/src/utils/cloner.test.d.ts +2 -0
  150. package/dist/src/utils/cloner.test.d.ts.map +1 -0
  151. package/dist/src/utils/coalesce.test.d.ts +2 -0
  152. package/dist/src/utils/coalesce.test.d.ts.map +1 -0
  153. package/dist/src/utils/concatIterables.test.d.ts +2 -0
  154. package/dist/src/utils/concatIterables.test.d.ts.map +1 -0
  155. package/dist/src/utils/domainArray.test.d.ts +2 -0
  156. package/dist/src/utils/domainArray.test.d.ts.map +1 -0
  157. package/dist/src/utils/expression.d.ts +2 -2
  158. package/dist/src/utils/expression.d.ts.map +1 -1
  159. package/dist/src/utils/expression.js +11 -2
  160. package/dist/src/utils/indexer.test.d.ts +2 -0
  161. package/dist/src/utils/indexer.test.d.ts.map +1 -0
  162. package/dist/src/utils/inputBinding.d.ts.map +1 -1
  163. package/dist/src/utils/inputBinding.js +4 -0
  164. package/dist/src/utils/iterateNestedMaps.test.d.ts +2 -0
  165. package/dist/src/utils/iterateNestedMaps.test.d.ts.map +1 -0
  166. package/dist/src/utils/kWayMerge.test.d.ts +2 -0
  167. package/dist/src/utils/kWayMerge.test.d.ts.map +1 -0
  168. package/dist/src/utils/mergeObjects.test.d.ts +2 -0
  169. package/dist/src/utils/mergeObjects.test.d.ts.map +1 -0
  170. package/dist/src/utils/numberExtractor.test.d.ts +2 -0
  171. package/dist/src/utils/numberExtractor.test.d.ts.map +1 -0
  172. package/dist/src/utils/propertyCacher.test.d.ts +2 -0
  173. package/dist/src/utils/propertyCacher.test.d.ts.map +1 -0
  174. package/dist/src/utils/propertyCoalescer.test.d.ts +2 -0
  175. package/dist/src/utils/propertyCoalescer.test.d.ts.map +1 -0
  176. package/dist/src/utils/propertyCoalescer.test.js +3 -0
  177. package/dist/src/utils/radixSort.test.d.ts +2 -0
  178. package/dist/src/utils/radixSort.test.d.ts.map +1 -0
  179. package/dist/src/utils/reservationMap.test.d.ts +2 -0
  180. package/dist/src/utils/reservationMap.test.d.ts.map +1 -0
  181. package/dist/src/utils/ringBuffer.test.d.ts +2 -0
  182. package/dist/src/utils/ringBuffer.test.d.ts.map +1 -0
  183. package/dist/src/utils/topK.test.d.ts +2 -0
  184. package/dist/src/utils/topK.test.d.ts.map +1 -0
  185. package/dist/src/utils/trees.test.d.ts +2 -0
  186. package/dist/src/utils/trees.test.d.ts.map +1 -0
  187. package/dist/src/utils/trees.test.js +8 -3
  188. package/dist/src/utils/variableTools.test.d.ts +2 -0
  189. package/dist/src/utils/variableTools.test.d.ts.map +1 -0
  190. package/dist/src/view/axisResolution.d.ts +19 -6
  191. package/dist/src/view/axisResolution.d.ts.map +1 -1
  192. package/dist/src/view/axisResolution.js +16 -7
  193. package/dist/src/view/axisResolution.test.d.ts +2 -0
  194. package/dist/src/view/axisResolution.test.d.ts.map +1 -0
  195. package/dist/src/view/axisResolution.test.js +16 -11
  196. package/dist/src/view/axisView.js +2 -2
  197. package/dist/src/view/facetView.d.ts +1 -1
  198. package/dist/src/view/facetView.d.ts.map +1 -1
  199. package/dist/src/view/flowBuilder.d.ts +1 -1
  200. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  201. package/dist/src/view/flowBuilder.js +34 -5
  202. package/dist/src/view/flowBuilder.test.d.ts +2 -0
  203. package/dist/src/view/flowBuilder.test.d.ts.map +1 -0
  204. package/dist/src/view/flowBuilder.test.js +1 -1
  205. package/dist/src/view/gridView.d.ts +0 -6
  206. package/dist/src/view/gridView.d.ts.map +1 -1
  207. package/dist/src/view/gridView.js +1 -1
  208. package/dist/src/view/layerView.d.ts +0 -6
  209. package/dist/src/view/layerView.d.ts.map +1 -1
  210. package/dist/src/view/layout/flexLayout.test.d.ts +2 -0
  211. package/dist/src/view/layout/flexLayout.test.d.ts.map +1 -0
  212. package/dist/src/view/layout/grid.test.d.ts +2 -0
  213. package/dist/src/view/layout/grid.test.d.ts.map +1 -0
  214. package/dist/src/view/layout/rectangle.test.d.ts +2 -0
  215. package/dist/src/view/layout/rectangle.test.d.ts.map +1 -0
  216. package/dist/src/view/paramMediator.d.ts +39 -5
  217. package/dist/src/view/paramMediator.d.ts.map +1 -1
  218. package/dist/src/view/paramMediator.js +120 -9
  219. package/dist/src/view/paramMediator.test.d.ts +2 -0
  220. package/dist/src/view/paramMediator.test.d.ts.map +1 -0
  221. package/dist/src/view/paramMediator.test.js +37 -1
  222. package/dist/src/view/scaleResolution.d.ts +17 -15
  223. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  224. package/dist/src/view/scaleResolution.js +70 -68
  225. package/dist/src/view/scaleResolution.test.d.ts +2 -0
  226. package/dist/src/view/scaleResolution.test.d.ts.map +1 -0
  227. package/dist/src/view/scaleResolution.test.js +2 -0
  228. package/dist/src/view/testUtils.d.ts.map +1 -1
  229. package/dist/src/view/testUtils.js +15 -3
  230. package/dist/src/view/unitView.d.ts +8 -20
  231. package/dist/src/view/unitView.d.ts.map +1 -1
  232. package/dist/src/view/unitView.js +100 -102
  233. package/dist/src/view/view.d.ts +1 -1
  234. package/dist/src/view/view.d.ts.map +1 -1
  235. package/dist/src/view/view.test.d.ts +2 -0
  236. package/dist/src/view/view.test.d.ts.map +1 -0
  237. package/dist/src/view/view.test.js +73 -55
  238. package/dist/src/view/viewFactory.test.d.ts +2 -0
  239. package/dist/src/view/viewFactory.test.d.ts.map +1 -0
  240. package/dist/src/view/viewFactory.test.js +2 -2
  241. package/dist/src/view/viewUtils.d.ts +1 -1
  242. package/dist/src/view/viewUtils.d.ts.map +1 -1
  243. package/dist/src/view/zoom.js +2 -2
  244. package/package.json +5 -2
@@ -14,6 +14,7 @@ import createEncoders, {
14
14
  isChannelDefWithScale,
15
15
  isChannelWithScale,
16
16
  isDatumDef,
17
+ isExprDef,
17
18
  isFieldDef,
18
19
  isValueDef,
19
20
  } from "../encoder/encoder.js";
@@ -25,9 +26,14 @@ import {
25
26
  toHighPrecisionDomainUniform,
26
27
  dedupeEncodingFields,
27
28
  generateDynamicValueGlslAndUniform,
28
- isLargeGenome,
29
29
  splitLargeHighPrecision,
30
30
  getRangeForGlsl,
31
+ getAttributeAndArrayTypes,
32
+ generateDataGlsl,
33
+ generateDatumGlslAndUniform,
34
+ generateConditionalEncoderGlsl,
35
+ PARAM_PREFIX,
36
+ ATTRIBUTE_PREFIX,
31
37
  } from "../gl/glslScaleGenerator.js";
32
38
  import GLSL_COMMON from "../gl/includes/common.glsl.js";
33
39
  import GLSL_SCALES from "../gl/includes/scales.glsl.js";
@@ -40,7 +46,9 @@ import coalesceProperties from "../utils/propertyCoalescer.js";
40
46
  import { isScalar } from "../utils/variableTools.js";
41
47
  import { InternMap } from "internmap";
42
48
  import ViewError from "../view/viewError.js";
43
- import { isExprRef } from "../view/paramMediator.js";
49
+ import { isExprRef, validateParameterName } from "../view/paramMediator.js";
50
+ import { UNIQUE_ID_KEY } from "../data/transforms/identifier.js";
51
+ import { isSinglePointSelection } from "../selection/selection.js";
44
52
 
45
53
  export const SAMPLE_FACET_UNIFORM = "SAMPLE_FACET_UNIFORM";
46
54
  export const SAMPLE_FACET_TEXTURE = "SAMPLE_FACET_TEXTURE";
@@ -56,7 +64,10 @@ export const SAMPLE_FACET_TEXTURE = "SAMPLE_FACET_TEXTURE";
56
64
  * @callback DrawFunction
57
65
  * @param {number} offset
58
66
  * @param {number} count
59
- *
67
+ */
68
+
69
+ /**
70
+ * @template {MarkProps} [P=MarkProps]
60
71
  */
61
72
  export default class Mark {
62
73
  /**
@@ -80,7 +91,7 @@ export default class Mark {
80
91
  constructor(unitView) {
81
92
  this.unitView = unitView;
82
93
 
83
- /** @type {Record<string, import("../types/encoder.js").Encoder>} */
94
+ /** @type {Partial<Record<Channel, import("../types/encoder.js").Encoder>>} */
84
95
  this.encoders = undefined;
85
96
 
86
97
  // TODO: Consolidate the following webgl stuff into a single object
@@ -138,9 +149,8 @@ export default class Mark {
138
149
  /** @type {RangeMap<any>} keep track of facet locations within the vertex array */
139
150
  this.rangeMap = new RangeMap();
140
151
 
141
- // TODO: Implement https://vega.github.io/vega-lite/docs/config.html
142
- /** @type {MarkProps} */
143
- this.defaultProperties = {
152
+ // TODO: Implement config: https://vega.github.io/vega-lite/docs/config.html
153
+ this.defaultProperties = /** @type {P} */ ({
144
154
  get clip() {
145
155
  // TODO: Cache once the scales have been resolved
146
156
  // TODO: Only check channels that are used
@@ -161,25 +171,34 @@ export default class Mark {
161
171
  * This property is intended for internal usage.
162
172
  */
163
173
  minBufferSize: 0,
164
- };
174
+ });
165
175
 
166
176
  /**
167
177
  * A properties object that contains the configured mark properties or
168
178
  * default values as fallback.
169
179
  *
170
- * TODO: Proper and comprehensive typings for mark properties
171
- *
172
- * @type {Partial<MarkProps>}
180
+ * @type {P}
173
181
  * @readonly
174
182
  */
175
183
  this.properties = coalesceProperties(
176
184
  typeof this.unitView.spec.mark == "object"
177
- ? () => /** @type {MarkProps} */ (this.unitView.spec.mark)
178
- : () => /** @type {MarkProps} */ ({}),
185
+ ? () => /** @type {P} */ (this.unitView.spec.mark)
186
+ : () => /** @type {P} */ ({}),
179
187
  () => this.defaultProperties
180
188
  );
181
189
  }
182
190
 
191
+ /**
192
+ * @param {Partial<P>} props
193
+ * @protected
194
+ */
195
+ augmentDefaultProperties(props) {
196
+ Object.defineProperties(
197
+ this.defaultProperties,
198
+ Object.getOwnPropertyDescriptors(props)
199
+ );
200
+ }
201
+
183
202
  get opaque() {
184
203
  return false;
185
204
  }
@@ -187,10 +206,8 @@ export default class Mark {
187
206
  /**
188
207
  * Returns attribute info for WebGL attributes that match visual channels.
189
208
  *
190
- * Note: attributes and channels do not necessarily match.
191
- * For example, rectangles have x, y, x2, and y2 channels but only x and y as attributes.
192
- *
193
- * @returns {string[]}
209
+ * @returns {import("../spec/channel.js").Channel[]}
210
+ * @protected
194
211
  */
195
212
  getAttributes() {
196
213
  // override
@@ -225,7 +242,7 @@ export default class Mark {
225
242
 
226
243
  if (this.isPickingParticipant()) {
227
244
  encoding.uniqueId = {
228
- field: "_uniqueId", // TODO: Use constant
245
+ field: UNIQUE_ID_KEY,
229
246
  };
230
247
  }
231
248
 
@@ -246,7 +263,7 @@ export default class Mark {
246
263
  * Handles dynamic properties that are not bound to uniforms but need
247
264
  * to trigger a graphics update, i.e., rebuild the vertex buffer.
248
265
  *
249
- * @param {(keyof MarkProps)[]} props
266
+ * @param {(keyof P)[]} props
250
267
  * @protected
251
268
  */
252
269
  setupExprRefsNeedingGraphicsUpdate(props) {
@@ -358,7 +375,7 @@ export default class Mark {
358
375
  * the ranges of the visual channels.
359
376
  */
360
377
  initializeEncoders() {
361
- this.encoders = createEncoders(this);
378
+ this.encoders = createEncoders(this.unitView, this.encoding);
362
379
  }
363
380
 
364
381
  /**
@@ -401,7 +418,12 @@ export default class Mark {
401
418
  */
402
419
  // eslint-disable-next-line complexity
403
420
  createAndLinkShaders(vertexShader, fragmentShader, extraHeaders = []) {
404
- const attributes = this.getAttributes();
421
+ const shaderChannels = this.getAttributes();
422
+ const encoders = this.encoders;
423
+ const sampleFacetMode = this.getSampleFacetMode();
424
+ if (sampleFacetMode) {
425
+ extraHeaders.push(`#define ${sampleFacetMode}`);
426
+ }
405
427
 
406
428
  // For debugging
407
429
  const debugHeader = "// view: " + this.unitView.getPathString();
@@ -416,36 +438,83 @@ export default class Mark {
416
438
  */
417
439
  const attributeCode = new Set();
418
440
 
419
- const dedupedEncodingFields = dedupeEncodingFields(this.encoders);
420
-
421
- const sampleFacetMode = this.getSampleFacetMode();
422
- if (sampleFacetMode) {
423
- extraHeaders.push(`#define ${sampleFacetMode}`);
424
- }
441
+ const dedupedEncodingFields = dedupeEncodingFields(encoders);
425
442
 
426
443
  /** @type {string[]} */
427
444
  const dynamicMarkUniforms = [];
428
445
 
429
- for (const attribute of attributes) {
430
- /** @type {Channel} */
431
- let channel;
432
- if (attribute in this.encoding) {
433
- channel = /** @type {Channel} */ (attribute);
434
- } else {
435
- continue;
446
+ const paramPredicates = Object.values(encoders)
447
+ .flatMap((e) => e.accessors)
448
+ .map((a) => a.predicate)
449
+ .filter((p) => p.param);
450
+
451
+ /**
452
+ * Prevent duplicate registration.
453
+ * @type {Map<string, "single" | "multi" | "range">}
454
+ */
455
+ const selectionParameterUniforms = new Map();
456
+
457
+ for (const predicate of paramPredicates) {
458
+ const param = predicate.param;
459
+ const selection = this.unitView.paramMediator.getValue(param);
460
+
461
+ // The selection is supposed to have an empty value at this point
462
+ // so that we can figure out the type of the selection.
463
+ if (!selection) {
464
+ throw new Error(
465
+ `Cannot infer selection type as the parameter "${param}" has no value. Please ensure that the parameter is properly defined!`
466
+ );
436
467
  }
437
468
 
438
- const channelDef = this.encoding[channel];
439
- if (!channelDef) {
440
- continue;
469
+ if (isSinglePointSelection(selection)) {
470
+ // Register a mark uniform for each param. The uniform will have
471
+ // the value of uniqueId of the selected datum.
472
+ if (!selectionParameterUniforms.has(param)) {
473
+ const uniformName =
474
+ PARAM_PREFIX + validateParameterName(param);
475
+ selectionParameterUniforms.set(param, "single");
476
+
477
+ dynamicMarkUniforms.push(` // Selection parameter`);
478
+ dynamicMarkUniforms.push(
479
+ ` uniform highp uint ${uniformName};`
480
+ );
481
+ this.#callAfterShaderCompilation.push(() => {
482
+ this.registerMarkUniformValue(
483
+ uniformName,
484
+ { expr: param },
485
+ (
486
+ /** @type {import("../types/selectionTypes.js").SinglePointSelection} */ selection
487
+ ) => selection.uniqueId ?? 0
488
+ );
489
+ });
490
+ }
491
+ } else {
492
+ throw new Error(
493
+ `Unsupported selection (${param}) in condition: ${JSON.stringify(
494
+ selection
495
+ )}`
496
+ );
441
497
  }
498
+ }
499
+
500
+ /**
501
+ * @param {Channel} channel
502
+ * @param {import("../types/encoder.js").Accessor} accessor
503
+ * @param {number} conditionNumber
504
+ * @param {import("../types/encoder.js").VegaScale} scale
505
+ */
506
+ const addAccessor = (channel, accessor, conditionNumber, scale) => {
507
+ const channelDef = accessor.channelDef;
442
508
 
443
509
  if (isValueDef(channelDef)) {
444
510
  if (isExprRef(channelDef.value)) {
445
511
  // An expression that evaluates to a value
446
- const { uniformName, uniformGlsl, scaleGlsl, adjuster } =
447
- generateDynamicValueGlslAndUniform(channel);
448
- scaleCode.push(scaleGlsl);
512
+ const { uniformName, uniformGlsl, accessorGlsl, adjuster } =
513
+ generateDynamicValueGlslAndUniform(
514
+ channel,
515
+ conditionNumber
516
+ );
517
+ scaleCode.push(accessorGlsl);
449
518
  dynamicMarkUniforms.push(uniformGlsl);
450
519
 
451
520
  this.#callAfterShaderCompilation.push(() => {
@@ -458,50 +527,127 @@ export default class Mark {
458
527
  } else {
459
528
  // A constant value
460
529
  scaleCode.push(
461
- generateConstantValueGlsl(channel, channelDef.value)
530
+ generateConstantValueGlsl(
531
+ channel,
532
+ conditionNumber,
533
+ channelDef.value
534
+ ).accessorGlsl
462
535
  );
463
536
  }
537
+ } else if (isDatumDef(channelDef)) {
538
+ const { uniformName, uniformGlsl, accessorGlsl } =
539
+ generateDatumGlslAndUniform(
540
+ channel,
541
+ scale,
542
+ conditionNumber
543
+ );
544
+
545
+ dynamicMarkUniforms.push(uniformGlsl);
546
+ scaleCode.push(accessorGlsl);
547
+
548
+ const { largeHp, discrete } = getAttributeAndArrayTypes(
549
+ scale,
550
+ channel
551
+ );
552
+
553
+ /**
554
+ * Discrete variables both numeric and strings must be "indexed",
555
+ * 64 bit floats must be converted to vec2.
556
+ * 32 bit continuous variables go to GPU as is.
557
+ *
558
+ * @type {function(import("../spec/channel.js").Scalar):(number | number[])}
559
+ */
560
+ const adjuster =
561
+ discrete && "domain" in scale
562
+ ? (d) => scale.domain().indexOf(d)
563
+ : largeHp
564
+ ? splitLargeHighPrecision
565
+ : (d) => +d;
566
+
567
+ this.#callAfterShaderCompilation.push(() => {
568
+ this.registerMarkUniformValue(
569
+ uniformName,
570
+ channelDef.datum,
571
+ adjuster
572
+ );
573
+ });
574
+ } else if (isFieldDef(channelDef)) {
575
+ const fields = dedupedEncodingFields.get([
576
+ channelDef.field,
577
+ true,
578
+ ]);
579
+ const { attributeGlsl, accessorGlsl } = generateDataGlsl(
580
+ channel,
581
+ scale,
582
+ conditionNumber,
583
+ fields?.includes(channel) ? fields : undefined
584
+ );
585
+ attributeCode.add(attributeGlsl);
586
+ scaleCode.push(accessorGlsl);
587
+ } else if (isExprDef(channelDef)) {
588
+ const { attributeGlsl, accessorGlsl } = generateDataGlsl(
589
+ channel,
590
+ scale,
591
+ conditionNumber
592
+ );
593
+ attributeCode.add(attributeGlsl);
594
+ scaleCode.push(accessorGlsl);
464
595
  } else {
596
+ throw new ViewError(
597
+ `Unsupported channel definition: ${JSON.stringify(
598
+ channelDef
599
+ )}`,
600
+ this.unitView
601
+ );
602
+ }
603
+ };
604
+
605
+ for (const [channel, encoder] of Object.entries(encoders)) {
606
+ if (!shaderChannels.includes(channel)) {
607
+ continue;
608
+ }
609
+
610
+ const { channelDef, accessors, scale } = encoder;
611
+
612
+ // Generate accessors, one for each condition -------------
613
+
614
+ for (let i = 0; i < accessors.length; i++) {
615
+ addAccessor(channel, accessors[i], i, scale);
616
+ }
617
+
618
+ // Generate scale if needed -------------------------------
619
+
620
+ if (scale) {
465
621
  const resolutionChannel =
466
622
  (isChannelDefWithScale(channelDef) &&
467
623
  channelDef.resolutionChannel) ||
468
624
  channel;
469
625
 
626
+ // TODO: The event listener should be in the scale, not the resolution
470
627
  const scaleResolution = isChannelWithScale(resolutionChannel)
471
628
  ? this.unitView.getScaleResolution(resolutionChannel)
472
629
  : null;
473
630
 
474
- // Channels that share the same quantitative field
475
- // TODO: It should be ok to share a categorical field if the channels
476
- // share the same scale, e.g., primary and secondary positional channels
477
- const sharedChannels = isFieldDef(channelDef)
478
- ? dedupedEncodingFields.get([channelDef.field, true])
479
- : [channel];
480
-
481
- const generated = generateScaleGlsl(
482
- channel,
483
- scaleResolution,
484
- channelDef,
485
- sharedChannels?.includes(channel)
486
- ? sharedChannels
487
- : [channel]
488
- );
631
+ const {
632
+ glsl,
633
+ domainUniform,
634
+ domainUniformName,
635
+ rangeUniform,
636
+ rangeUniformName,
637
+ } = generateScaleGlsl(channel, scale, channelDef);
489
638
 
490
- scaleCode.push(generated.glsl);
491
- dynamicMarkUniforms.push(generated.domainUniform);
492
- dynamicMarkUniforms.push(generated.rangeUniform);
493
- attributeCode.add(generated.attributeGlsl);
639
+ scaleCode.push(glsl);
640
+ dynamicMarkUniforms.push(domainUniform);
641
+ dynamicMarkUniforms.push(rangeUniform);
494
642
 
495
- if (generated.rangeUniform) {
643
+ if (rangeUniform) {
496
644
  this.#callAfterShaderCompilation.push(() => {
497
- const rangeSetter = this.createMarkUniformSetter(
498
- generated.rangeName
499
- );
645
+ const rangeSetter =
646
+ this.createMarkUniformSetter(rangeUniformName);
500
647
 
501
648
  const set = () =>
502
- rangeSetter(
503
- getRangeForGlsl(scaleResolution.scale, channel)
504
- );
649
+ rangeSetter(getRangeForGlsl(scale, channel));
650
+ // TODO: The event listener should be in the scale, not the resolution
505
651
  scaleResolution.addEventListener("range", set);
506
652
 
507
653
  // Initial value
@@ -509,47 +655,10 @@ export default class Mark {
509
655
  });
510
656
  }
511
657
 
512
- if (generated.markUniformGlsl) {
513
- if (!isDatumDef(channelDef)) {
514
- throw new Error("Bug!");
515
- }
516
-
517
- const encoder = this.encoders[channel];
518
-
519
- const indexer = encoder.indexer;
520
- const hp = isHighPrecisionScale(encoder.scale.type);
521
- const largeHp = hp && isLargeGenome(encoder.scale.domain());
522
-
523
- /**
524
- * Discrete variables both numeric and strings must be "indexed",
525
- * 64 bit floats must be converted to vec2.
526
- * 32 bit continuous variables go to GPU as is.
527
- *
528
- * @type {function(import("../spec/channel.js").Scalar):(number | number[])}
529
- */
530
- const adjuster = indexer
531
- ? indexer
532
- : largeHp
533
- ? splitLargeHighPrecision
534
- : (d) => +d;
535
-
536
- dynamicMarkUniforms.push(generated.markUniformGlsl);
537
-
538
- this.#callAfterShaderCompilation.push(() => {
539
- this.registerMarkUniformValue(
540
- generated.attributeName,
541
- channelDef.datum,
542
- adjuster
543
- );
544
- });
545
- }
546
-
547
- if (generated.domainUniform) {
658
+ if (domainUniform) {
548
659
  this.#callAfterShaderCompilation.push(() => {
549
- const domainSetter = this.createMarkUniformSetter(
550
- generated.domainUniformName
551
- );
552
- const scale = scaleResolution.scale;
660
+ const domainSetter =
661
+ this.createMarkUniformSetter(domainUniformName);
553
662
  const set = () => {
554
663
  const domain = isDiscrete(scale.type)
555
664
  ? [0, scale.domain().length]
@@ -562,6 +671,7 @@ export default class Mark {
562
671
  );
563
672
  };
564
673
 
674
+ // TODO: The event listener should be in the scale, not the resolution
565
675
  scaleResolution.addEventListener("domain", set);
566
676
 
567
677
  // Initial value
@@ -569,8 +679,27 @@ export default class Mark {
569
679
  });
570
680
  }
571
681
  }
682
+
683
+ // Generate conditional encoder -------------------------------
684
+
685
+ scaleCode.push(generateConditionalEncoderGlsl(channel, accessors));
572
686
  }
573
687
 
688
+ // Generate a function that checks if the datum is subject to any point selection
689
+ const conditions = [...selectionParameterUniforms.entries()]
690
+ .filter(([, v]) => v == "single")
691
+ .map(
692
+ ([param]) =>
693
+ `${PARAM_PREFIX}${param} == ${ATTRIBUTE_PREFIX}uniqueId`
694
+ );
695
+ scaleCode.push(
696
+ "bool isPointSelected() {",
697
+ this.encoders.uniqueId && conditions.length > 0
698
+ ? ` return ${conditions.join(" || ")};`
699
+ : " return false;",
700
+ "}"
701
+ );
702
+
574
703
  const vertexPrecision = "precision highp float;\nprecision highp int;";
575
704
 
576
705
  /**
@@ -834,13 +963,12 @@ export default class Mark {
834
963
 
835
964
  /**
836
965
  * Returns true if this mark instance participates in picking.
837
- *
838
- * TODO: Check if tooltip is enabled,
839
- * TODO: Check if selection (when it's implemented) is enabled
840
966
  */
841
967
  isPickingParticipant() {
842
- // TODO: Should check encoding instead
843
- if (this.properties.tooltip === null) {
968
+ if (
969
+ this.properties.tooltip === null &&
970
+ !this.unitView.paramMediator.hasPointSelections()
971
+ ) {
844
972
  // Disabled
845
973
  return false;
846
974
  }
@@ -1153,14 +1281,14 @@ export default class Mark {
1153
1281
  // Because glViewport accepts only integers, we subtract the rounding
1154
1282
  // errors from xyOffsets to guarantee that graphics in clipped
1155
1283
  // and non-clipped viewports align correctly
1156
- const roundedCoords = physicalGlCoords.map((x) => Math.round(x));
1157
- const [xError, yError] = physicalGlCoords.map(
1158
- (x, i) => x - roundedCoords[i]
1159
- );
1284
+ const roundedCoords =
1285
+ /** @type {[number, number, number, number]} */ (
1286
+ physicalGlCoords.map((x) => Math.floor(x))
1287
+ );
1288
+ const xError = physicalGlCoords[0] - roundedCoords[0];
1289
+ const yError = physicalGlCoords[1] - roundedCoords[1];
1160
1290
 
1161
- // @ts-ignore
1162
1291
  gl.viewport(...roundedCoords);
1163
- // @ts-ignore
1164
1292
  gl.scissor(...roundedCoords);
1165
1293
  gl.enable(gl.SCISSOR_TEST);
1166
1294
 
@@ -18,6 +18,31 @@ export function fixStroke(encoding: import("../spec/channel.js").Encoding, fille
18
18
  * @param {boolean} filled
19
19
  */
20
20
  export function fixFill(encoding: import("../spec/channel.js").Encoding, filled: boolean): void;
21
+ /**
22
+ * @param {import("../spec/mark.js").MarkProps} props
23
+ * @returns {props is import("../spec/mark.js").PointProps}
24
+ */
25
+ export function isPointProps(props: import("../spec/mark.js").MarkProps): props is import("../spec/mark.js").PointProps;
26
+ /**
27
+ * @param {import("../spec/mark.js").MarkProps} props
28
+ * @returns {props is import("../spec/mark.js").RectProps}
29
+ */
30
+ export function isRectProps(props: import("../spec/mark.js").MarkProps): props is import("../spec/mark.js").RectProps;
31
+ /**
32
+ * @param {import("../spec/mark.js").MarkProps} props
33
+ * @returns {props is import("../spec/mark.js").RuleProps}
34
+ */
35
+ export function isRuleProps(props: import("../spec/mark.js").MarkProps): props is import("../spec/mark.js").RuleProps;
36
+ /**
37
+ * @param {import("../spec/mark.js").MarkProps} props
38
+ * @returns {props is import("../spec/mark.js").TextProps}
39
+ */
40
+ export function isTextProps(props: import("../spec/mark.js").MarkProps): props is import("../spec/mark.js").TextProps;
41
+ /**
42
+ * @param {import("../spec/mark.js").MarkProps} props
43
+ * @returns {props is import("../spec/mark.js").LinkProps}
44
+ */
45
+ export function isLinkProps(props: import("../spec/mark.js").MarkProps): props is import("../spec/mark.js").LinkProps;
21
46
  export type Encoding = import("../spec/channel.js").Encoding;
22
47
  export type Channel = import("../spec/channel.js").Channel;
23
48
  //# sourceMappingURL=markUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markUtils.d.ts","sourceRoot":"","sources":["../../../src/marks/markUtils.js"],"names":[],"mappings":"AAMA;;;;GAIG;AAEH;;;GAGG;AACH,wCAHW,QAAQ,WACR,OAAO,oBAAoB,EAAE,wBAAwB,QAoD/D;AAED;;;GAGG;AACH,oCAHW,OAAO,oBAAoB,EAAE,QAAQ,UACrC,OAAO,QAyBjB;AAED;;;GAGG;AACH,kCAHW,OAAO,oBAAoB,EAAE,QAAQ,UACrC,OAAO,QAyBjB;uBApHY,OAAO,oBAAoB,EAAE,QAAQ;sBACrC,OAAO,oBAAoB,EAAE,OAAO"}
1
+ {"version":3,"file":"markUtils.d.ts","sourceRoot":"","sources":["../../../src/marks/markUtils.js"],"names":[],"mappings":"AAMA;;;;GAIG;AAEH;;;GAGG;AACH,wCAHW,QAAQ,WACR,OAAO,oBAAoB,EAAE,wBAAwB,QAoD/D;AAED;;;GAGG;AACH,oCAHW,OAAO,oBAAoB,EAAE,QAAQ,UACrC,OAAO,QAyBjB;AAED;;;GAGG;AACH,kCAHW,OAAO,oBAAoB,EAAE,QAAQ,UACrC,OAAO,QAyBjB;AAED;;;GAGG;AACH,oCAHW,OAAO,iBAAiB,EAAE,SAAS,iDAK7C;AAED;;;GAGG;AACH,mCAHW,OAAO,iBAAiB,EAAE,SAAS,gDAK7C;AAED;;;GAGG;AACH,mCAHW,OAAO,iBAAiB,EAAE,SAAS,gDAK7C;AAED;;;GAGG;AACH,mCAHW,OAAO,iBAAiB,EAAE,SAAS,gDAK7C;AAED;;;GAGG;AACH,mCAHW,OAAO,iBAAiB,EAAE,SAAS,gDAK7C;uBA5JY,OAAO,oBAAoB,EAAE,QAAQ;sBACrC,OAAO,oBAAoB,EAAE,OAAO"}
@@ -37,7 +37,7 @@ export function fixPositional(encoding, channel) {
37
37
  if (!secondary) {
38
38
  if (primary.type == "quantitative") {
39
39
  // Bar plot, anchor the other end to zero
40
- secondary = { datum: 0 };
40
+ secondary = { datum: 0, contributesToScaleDomain: false };
41
41
  } else {
42
42
  secondary = { ...primary };
43
43
 
@@ -123,3 +123,43 @@ export function fixFill(encoding, filled) {
123
123
  }
124
124
  }
125
125
  }
126
+
127
+ /**
128
+ * @param {import("../spec/mark.js").MarkProps} props
129
+ * @returns {props is import("../spec/mark.js").PointProps}
130
+ */
131
+ export function isPointProps(props) {
132
+ return props.type === "point";
133
+ }
134
+
135
+ /**
136
+ * @param {import("../spec/mark.js").MarkProps} props
137
+ * @returns {props is import("../spec/mark.js").RectProps}
138
+ */
139
+ export function isRectProps(props) {
140
+ return props.type === "point";
141
+ }
142
+
143
+ /**
144
+ * @param {import("../spec/mark.js").MarkProps} props
145
+ * @returns {props is import("../spec/mark.js").RuleProps}
146
+ */
147
+ export function isRuleProps(props) {
148
+ return props.type === "point";
149
+ }
150
+
151
+ /**
152
+ * @param {import("../spec/mark.js").MarkProps} props
153
+ * @returns {props is import("../spec/mark.js").TextProps}
154
+ */
155
+ export function isTextProps(props) {
156
+ return props.type === "point";
157
+ }
158
+
159
+ /**
160
+ * @param {import("../spec/mark.js").MarkProps} props
161
+ * @returns {props is import("../spec/mark.js").LinkProps}
162
+ */
163
+ export function isLinkProps(props) {
164
+ return props.type === "point";
165
+ }
@@ -1,2 +1,2 @@
1
- const shader = "layout(std140)uniform Mark{/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform mediump float uScaleFactor;uniform mediump float uZoomLevel;uniform highp float uSemanticThreshold;uniform mediump float uGradientStrength;\n#pragma markUniforms\n};";
1
+ const shader = "layout(std140)uniform Mark{/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform float uMinPickingSize;uniform mediump float uScaleFactor;uniform mediump float uZoomLevel;uniform highp float uSemanticThreshold;uniform mediump float uGradientStrength;\n#pragma markUniforms\n};";
2
2
  export default shader;
@@ -1,4 +1,11 @@
1
- export default class PointMark extends Mark {
1
+ /**
2
+ * @extends {Mark<import("../spec/mark.js").PointProps>}
3
+ */
4
+ export default class PointMark extends Mark<import("../spec/mark.js").PointProps> {
5
+ /**
6
+ * @param {import("../view/unitView.js").default} unitView
7
+ */
8
+ constructor(unitView: import("../view/unitView.js").default);
2
9
  sampledSemanticScores: Float32Array;
3
10
  getSemanticThreshold(): number;
4
11
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../src/marks/point.js"],"names":[],"mappings":"AAmBA;IA0HY,oCAMC;IA6DT,+BAkBC;;CAgDJ;iBAvQgB,WAAW"}
1
+ {"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../src/marks/point.js"],"names":[],"mappings":"AAmBA;;GAEG;AACH;IAGI;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EA6C/C;IA0EO,oCAMC;IAkET,+BAkBC;;CAgDJ;iBAhRgB,WAAW"}