@genome-spy/core 0.48.2 → 0.49.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 (221) hide show
  1. package/dist/bundle/index.es.js +7226 -6923
  2. package/dist/bundle/index.js +121 -108
  3. package/dist/schema.json +838 -344
  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/marks/link.common.glsl.js +1 -1
  93. package/dist/src/marks/link.d.ts.map +1 -1
  94. package/dist/src/marks/link.js +10 -0
  95. package/dist/src/marks/link.vertex.glsl.js +1 -1
  96. package/dist/src/marks/mark.d.ts +6 -9
  97. package/dist/src/marks/mark.d.ts.map +1 -1
  98. package/dist/src/marks/mark.js +212 -95
  99. package/dist/src/marks/point.d.ts.map +1 -1
  100. package/dist/src/marks/point.js +5 -1
  101. package/dist/src/marks/rect.d.ts.map +1 -1
  102. package/dist/src/marks/rect.js +9 -4
  103. package/dist/src/marks/rule.d.ts.map +1 -1
  104. package/dist/src/marks/rule.js +4 -0
  105. package/dist/src/marks/text.d.ts.map +1 -1
  106. package/dist/src/marks/text.js +5 -1
  107. package/dist/src/scale/scale.test.d.ts +2 -0
  108. package/dist/src/scale/scale.test.d.ts.map +1 -0
  109. package/dist/src/scale/scale.test.js +2 -0
  110. package/dist/src/scale/ticks.test.d.ts +2 -0
  111. package/dist/src/scale/ticks.test.d.ts.map +1 -0
  112. package/dist/src/scale/ticks.test.js +6 -0
  113. package/dist/src/selection/selection.d.ts +39 -0
  114. package/dist/src/selection/selection.d.ts.map +1 -0
  115. package/dist/src/selection/selection.js +78 -0
  116. package/dist/src/spec/channel.d.ts +137 -83
  117. package/dist/src/spec/mark.d.ts +9 -0
  118. package/dist/src/spec/parameter.d.ts +112 -3
  119. package/dist/src/spec/root.d.ts +0 -1
  120. package/dist/src/spec/transform.d.ts +19 -1
  121. package/dist/src/spec/view.d.ts +3 -3
  122. package/dist/src/tooltip/dataTooltipHandler.js +1 -1
  123. package/dist/src/types/encoder.d.ts +80 -26
  124. package/dist/src/types/rendering.d.ts +1 -0
  125. package/dist/src/types/selectionTypes.d.ts +44 -0
  126. package/dist/src/types/viewContext.d.ts +1 -4
  127. package/dist/src/utils/addBaseUrl.test.d.ts +2 -0
  128. package/dist/src/utils/addBaseUrl.test.d.ts.map +1 -0
  129. package/dist/src/utils/binnedIndex.test.d.ts +2 -0
  130. package/dist/src/utils/binnedIndex.test.d.ts.map +1 -0
  131. package/dist/src/utils/cloner.test.d.ts +2 -0
  132. package/dist/src/utils/cloner.test.d.ts.map +1 -0
  133. package/dist/src/utils/coalesce.test.d.ts +2 -0
  134. package/dist/src/utils/coalesce.test.d.ts.map +1 -0
  135. package/dist/src/utils/concatIterables.test.d.ts +2 -0
  136. package/dist/src/utils/concatIterables.test.d.ts.map +1 -0
  137. package/dist/src/utils/domainArray.test.d.ts +2 -0
  138. package/dist/src/utils/domainArray.test.d.ts.map +1 -0
  139. package/dist/src/utils/expression.d.ts +2 -2
  140. package/dist/src/utils/expression.d.ts.map +1 -1
  141. package/dist/src/utils/expression.js +11 -2
  142. package/dist/src/utils/indexer.test.d.ts +2 -0
  143. package/dist/src/utils/indexer.test.d.ts.map +1 -0
  144. package/dist/src/utils/inputBinding.d.ts.map +1 -1
  145. package/dist/src/utils/inputBinding.js +4 -0
  146. package/dist/src/utils/iterateNestedMaps.test.d.ts +2 -0
  147. package/dist/src/utils/iterateNestedMaps.test.d.ts.map +1 -0
  148. package/dist/src/utils/kWayMerge.test.d.ts +2 -0
  149. package/dist/src/utils/kWayMerge.test.d.ts.map +1 -0
  150. package/dist/src/utils/mergeObjects.test.d.ts +2 -0
  151. package/dist/src/utils/mergeObjects.test.d.ts.map +1 -0
  152. package/dist/src/utils/numberExtractor.test.d.ts +2 -0
  153. package/dist/src/utils/numberExtractor.test.d.ts.map +1 -0
  154. package/dist/src/utils/propertyCacher.test.d.ts +2 -0
  155. package/dist/src/utils/propertyCacher.test.d.ts.map +1 -0
  156. package/dist/src/utils/propertyCoalescer.test.d.ts +2 -0
  157. package/dist/src/utils/propertyCoalescer.test.d.ts.map +1 -0
  158. package/dist/src/utils/propertyCoalescer.test.js +3 -0
  159. package/dist/src/utils/radixSort.test.d.ts +2 -0
  160. package/dist/src/utils/radixSort.test.d.ts.map +1 -0
  161. package/dist/src/utils/reservationMap.test.d.ts +2 -0
  162. package/dist/src/utils/reservationMap.test.d.ts.map +1 -0
  163. package/dist/src/utils/ringBuffer.test.d.ts +2 -0
  164. package/dist/src/utils/ringBuffer.test.d.ts.map +1 -0
  165. package/dist/src/utils/topK.test.d.ts +2 -0
  166. package/dist/src/utils/topK.test.d.ts.map +1 -0
  167. package/dist/src/utils/trees.test.d.ts +2 -0
  168. package/dist/src/utils/trees.test.d.ts.map +1 -0
  169. package/dist/src/utils/trees.test.js +8 -3
  170. package/dist/src/utils/variableTools.test.d.ts +2 -0
  171. package/dist/src/utils/variableTools.test.d.ts.map +1 -0
  172. package/dist/src/view/axisResolution.d.ts +19 -6
  173. package/dist/src/view/axisResolution.d.ts.map +1 -1
  174. package/dist/src/view/axisResolution.js +16 -7
  175. package/dist/src/view/axisResolution.test.d.ts +2 -0
  176. package/dist/src/view/axisResolution.test.d.ts.map +1 -0
  177. package/dist/src/view/axisResolution.test.js +16 -11
  178. package/dist/src/view/facetView.d.ts +1 -1
  179. package/dist/src/view/facetView.d.ts.map +1 -1
  180. package/dist/src/view/flowBuilder.d.ts +1 -1
  181. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  182. package/dist/src/view/flowBuilder.js +34 -5
  183. package/dist/src/view/flowBuilder.test.d.ts +2 -0
  184. package/dist/src/view/flowBuilder.test.d.ts.map +1 -0
  185. package/dist/src/view/gridView.d.ts +0 -6
  186. package/dist/src/view/gridView.d.ts.map +1 -1
  187. package/dist/src/view/layerView.d.ts +0 -6
  188. package/dist/src/view/layerView.d.ts.map +1 -1
  189. package/dist/src/view/layout/flexLayout.test.d.ts +2 -0
  190. package/dist/src/view/layout/flexLayout.test.d.ts.map +1 -0
  191. package/dist/src/view/layout/grid.test.d.ts +2 -0
  192. package/dist/src/view/layout/grid.test.d.ts.map +1 -0
  193. package/dist/src/view/layout/rectangle.test.d.ts +2 -0
  194. package/dist/src/view/layout/rectangle.test.d.ts.map +1 -0
  195. package/dist/src/view/paramMediator.d.ts +32 -5
  196. package/dist/src/view/paramMediator.d.ts.map +1 -1
  197. package/dist/src/view/paramMediator.js +97 -9
  198. package/dist/src/view/paramMediator.test.d.ts +2 -0
  199. package/dist/src/view/paramMediator.test.d.ts.map +1 -0
  200. package/dist/src/view/paramMediator.test.js +17 -1
  201. package/dist/src/view/scaleResolution.d.ts +17 -9
  202. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  203. package/dist/src/view/scaleResolution.js +51 -34
  204. package/dist/src/view/scaleResolution.test.d.ts +2 -0
  205. package/dist/src/view/scaleResolution.test.d.ts.map +1 -0
  206. package/dist/src/view/scaleResolution.test.js +2 -0
  207. package/dist/src/view/testUtils.d.ts.map +1 -1
  208. package/dist/src/view/testUtils.js +15 -3
  209. package/dist/src/view/unitView.d.ts +5 -15
  210. package/dist/src/view/unitView.d.ts.map +1 -1
  211. package/dist/src/view/unitView.js +81 -101
  212. package/dist/src/view/view.d.ts +1 -1
  213. package/dist/src/view/view.d.ts.map +1 -1
  214. package/dist/src/view/view.test.d.ts +2 -0
  215. package/dist/src/view/view.test.d.ts.map +1 -0
  216. package/dist/src/view/view.test.js +73 -55
  217. package/dist/src/view/viewFactory.test.d.ts +2 -0
  218. package/dist/src/view/viewFactory.test.d.ts.map +1 -0
  219. package/dist/src/view/viewFactory.test.js +2 -2
  220. package/dist/src/view/zoom.js +2 -2
  221. 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";
@@ -80,7 +88,7 @@ export default class Mark {
80
88
  constructor(unitView) {
81
89
  this.unitView = unitView;
82
90
 
83
- /** @type {Record<string, import("../types/encoder.js").Encoder>} */
91
+ /** @type {Partial<Record<Channel, import("../types/encoder.js").Encoder>>} */
84
92
  this.encoders = undefined;
85
93
 
86
94
  // TODO: Consolidate the following webgl stuff into a single object
@@ -187,9 +195,6 @@ export default class Mark {
187
195
  /**
188
196
  * Returns attribute info for WebGL attributes that match visual channels.
189
197
  *
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
198
  * @returns {string[]}
194
199
  */
195
200
  getAttributes() {
@@ -225,7 +230,7 @@ export default class Mark {
225
230
 
226
231
  if (this.isPickingParticipant()) {
227
232
  encoding.uniqueId = {
228
- field: "_uniqueId", // TODO: Use constant
233
+ field: UNIQUE_ID_KEY,
229
234
  };
230
235
  }
231
236
 
@@ -358,7 +363,7 @@ export default class Mark {
358
363
  * the ranges of the visual channels.
359
364
  */
360
365
  initializeEncoders() {
361
- this.encoders = createEncoders(this);
366
+ this.encoders = createEncoders(this.unitView, this.encoding);
362
367
  }
363
368
 
364
369
  /**
@@ -401,7 +406,12 @@ export default class Mark {
401
406
  */
402
407
  // eslint-disable-next-line complexity
403
408
  createAndLinkShaders(vertexShader, fragmentShader, extraHeaders = []) {
404
- const attributes = this.getAttributes();
409
+ const shaderChannels = this.getAttributes();
410
+ const encoders = this.encoders;
411
+ const sampleFacetMode = this.getSampleFacetMode();
412
+ if (sampleFacetMode) {
413
+ extraHeaders.push(`#define ${sampleFacetMode}`);
414
+ }
405
415
 
406
416
  // For debugging
407
417
  const debugHeader = "// view: " + this.unitView.getPathString();
@@ -416,36 +426,83 @@ export default class Mark {
416
426
  */
417
427
  const attributeCode = new Set();
418
428
 
419
- const dedupedEncodingFields = dedupeEncodingFields(this.encoders);
420
-
421
- const sampleFacetMode = this.getSampleFacetMode();
422
- if (sampleFacetMode) {
423
- extraHeaders.push(`#define ${sampleFacetMode}`);
424
- }
429
+ const dedupedEncodingFields = dedupeEncodingFields(encoders);
425
430
 
426
431
  /** @type {string[]} */
427
432
  const dynamicMarkUniforms = [];
428
433
 
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;
434
+ const paramPredicates = Object.values(encoders)
435
+ .flatMap((e) => e.accessors)
436
+ .map((a) => a.predicate)
437
+ .filter((p) => p.param);
438
+
439
+ /**
440
+ * Prevent duplicate registration.
441
+ * @type {Map<string, "single" | "multi" | "range">}
442
+ */
443
+ const selectionParameterUniforms = new Map();
444
+
445
+ for (const predicate of paramPredicates) {
446
+ const param = predicate.param;
447
+ const selection = this.unitView.paramMediator.getValue(param);
448
+
449
+ // The selection is supposed to have an empty value at this point
450
+ // so that we can figure out the type of the selection.
451
+ if (!selection) {
452
+ throw new Error(
453
+ `Cannot infer selection type as the parameter "${param}" has no value. Please ensure that the parameter is properly defined!`
454
+ );
436
455
  }
437
456
 
438
- const channelDef = this.encoding[channel];
439
- if (!channelDef) {
440
- continue;
457
+ if (isSinglePointSelection(selection)) {
458
+ // Register a mark uniform for each param. The uniform will have
459
+ // the value of uniqueId of the selected datum.
460
+ if (!selectionParameterUniforms.has(param)) {
461
+ const uniformName =
462
+ PARAM_PREFIX + validateParameterName(param);
463
+ selectionParameterUniforms.set(param, "single");
464
+
465
+ dynamicMarkUniforms.push(` // Selection parameter`);
466
+ dynamicMarkUniforms.push(
467
+ ` uniform highp uint ${uniformName};`
468
+ );
469
+ this.#callAfterShaderCompilation.push(() => {
470
+ this.registerMarkUniformValue(
471
+ uniformName,
472
+ { expr: param },
473
+ (
474
+ /** @type {import("../types/selectionTypes.js").SinglePointSelection} */ selection
475
+ ) => selection.uniqueId ?? 0
476
+ );
477
+ });
478
+ }
479
+ } else {
480
+ throw new Error(
481
+ `Unsupported selection (${param}) in condition: ${JSON.stringify(
482
+ selection
483
+ )}`
484
+ );
441
485
  }
486
+ }
487
+
488
+ /**
489
+ * @param {Channel} channel
490
+ * @param {import("../types/encoder.js").Accessor} accessor
491
+ * @param {number} conditionNumber
492
+ * @param {import("../types/encoder.js").VegaScale} scale
493
+ */
494
+ const addAccessor = (channel, accessor, conditionNumber, scale) => {
495
+ const channelDef = accessor.channelDef;
442
496
 
443
497
  if (isValueDef(channelDef)) {
444
498
  if (isExprRef(channelDef.value)) {
445
499
  // An expression that evaluates to a value
446
- const { uniformName, uniformGlsl, scaleGlsl, adjuster } =
447
- generateDynamicValueGlslAndUniform(channel);
448
- scaleCode.push(scaleGlsl);
500
+ const { uniformName, uniformGlsl, accessorGlsl, adjuster } =
501
+ generateDynamicValueGlslAndUniform(
502
+ channel,
503
+ conditionNumber
504
+ );
505
+ scaleCode.push(accessorGlsl);
449
506
  dynamicMarkUniforms.push(uniformGlsl);
450
507
 
451
508
  this.#callAfterShaderCompilation.push(() => {
@@ -458,50 +515,127 @@ export default class Mark {
458
515
  } else {
459
516
  // A constant value
460
517
  scaleCode.push(
461
- generateConstantValueGlsl(channel, channelDef.value)
518
+ generateConstantValueGlsl(
519
+ channel,
520
+ conditionNumber,
521
+ channelDef.value
522
+ ).accessorGlsl
462
523
  );
463
524
  }
525
+ } else if (isDatumDef(channelDef)) {
526
+ const { uniformName, uniformGlsl, accessorGlsl } =
527
+ generateDatumGlslAndUniform(
528
+ channel,
529
+ scale,
530
+ conditionNumber
531
+ );
532
+
533
+ dynamicMarkUniforms.push(uniformGlsl);
534
+ scaleCode.push(accessorGlsl);
535
+
536
+ const { largeHp, discrete } = getAttributeAndArrayTypes(
537
+ scale,
538
+ channel
539
+ );
540
+
541
+ /**
542
+ * Discrete variables both numeric and strings must be "indexed",
543
+ * 64 bit floats must be converted to vec2.
544
+ * 32 bit continuous variables go to GPU as is.
545
+ *
546
+ * @type {function(import("../spec/channel.js").Scalar):(number | number[])}
547
+ */
548
+ const adjuster =
549
+ discrete && "domain" in scale
550
+ ? (d) => scale.domain().indexOf(d)
551
+ : largeHp
552
+ ? splitLargeHighPrecision
553
+ : (d) => +d;
554
+
555
+ this.#callAfterShaderCompilation.push(() => {
556
+ this.registerMarkUniformValue(
557
+ uniformName,
558
+ channelDef.datum,
559
+ adjuster
560
+ );
561
+ });
562
+ } else if (isFieldDef(channelDef)) {
563
+ const fields = dedupedEncodingFields.get([
564
+ channelDef.field,
565
+ true,
566
+ ]);
567
+ const { attributeGlsl, accessorGlsl } = generateDataGlsl(
568
+ channel,
569
+ scale,
570
+ conditionNumber,
571
+ fields?.includes(channel) ? fields : undefined
572
+ );
573
+ attributeCode.add(attributeGlsl);
574
+ scaleCode.push(accessorGlsl);
575
+ } else if (isExprDef(channelDef)) {
576
+ const { attributeGlsl, accessorGlsl } = generateDataGlsl(
577
+ channel,
578
+ scale,
579
+ conditionNumber
580
+ );
581
+ attributeCode.add(attributeGlsl);
582
+ scaleCode.push(accessorGlsl);
464
583
  } else {
584
+ throw new ViewError(
585
+ `Unsupported channel definition: ${JSON.stringify(
586
+ channelDef
587
+ )}`,
588
+ this.unitView
589
+ );
590
+ }
591
+ };
592
+
593
+ for (const [channel, encoder] of Object.entries(encoders)) {
594
+ if (!shaderChannels.includes(channel)) {
595
+ continue;
596
+ }
597
+
598
+ const { channelDef, accessors, scale } = encoder;
599
+
600
+ // Generate accessors, one for each condition -------------
601
+
602
+ for (let i = 0; i < accessors.length; i++) {
603
+ addAccessor(channel, accessors[i], i, scale);
604
+ }
605
+
606
+ // Generate scale if needed -------------------------------
607
+
608
+ if (scale) {
465
609
  const resolutionChannel =
466
610
  (isChannelDefWithScale(channelDef) &&
467
611
  channelDef.resolutionChannel) ||
468
612
  channel;
469
613
 
614
+ // TODO: The event listener should be in the scale, not the resolution
470
615
  const scaleResolution = isChannelWithScale(resolutionChannel)
471
616
  ? this.unitView.getScaleResolution(resolutionChannel)
472
617
  : null;
473
618
 
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];
619
+ const {
620
+ glsl,
621
+ domainUniform,
622
+ domainUniformName,
623
+ rangeUniform,
624
+ rangeUniformName,
625
+ } = generateScaleGlsl(channel, scale, channelDef);
480
626
 
481
- const generated = generateScaleGlsl(
482
- channel,
483
- scaleResolution,
484
- channelDef,
485
- sharedChannels?.includes(channel)
486
- ? sharedChannels
487
- : [channel]
488
- );
627
+ scaleCode.push(glsl);
628
+ dynamicMarkUniforms.push(domainUniform);
629
+ dynamicMarkUniforms.push(rangeUniform);
489
630
 
490
- scaleCode.push(generated.glsl);
491
- dynamicMarkUniforms.push(generated.domainUniform);
492
- dynamicMarkUniforms.push(generated.rangeUniform);
493
- attributeCode.add(generated.attributeGlsl);
494
-
495
- if (generated.rangeUniform) {
631
+ if (rangeUniform) {
496
632
  this.#callAfterShaderCompilation.push(() => {
497
- const rangeSetter = this.createMarkUniformSetter(
498
- generated.rangeName
499
- );
633
+ const rangeSetter =
634
+ this.createMarkUniformSetter(rangeUniformName);
500
635
 
501
636
  const set = () =>
502
- rangeSetter(
503
- getRangeForGlsl(scaleResolution.scale, channel)
504
- );
637
+ rangeSetter(getRangeForGlsl(scale, channel));
638
+ // TODO: The event listener should be in the scale, not the resolution
505
639
  scaleResolution.addEventListener("range", set);
506
640
 
507
641
  // Initial value
@@ -509,47 +643,10 @@ export default class Mark {
509
643
  });
510
644
  }
511
645
 
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
-
646
+ if (domainUniform) {
538
647
  this.#callAfterShaderCompilation.push(() => {
539
- this.registerMarkUniformValue(
540
- generated.attributeName,
541
- channelDef.datum,
542
- adjuster
543
- );
544
- });
545
- }
546
-
547
- if (generated.domainUniform) {
548
- this.#callAfterShaderCompilation.push(() => {
549
- const domainSetter = this.createMarkUniformSetter(
550
- generated.domainUniformName
551
- );
552
- const scale = scaleResolution.scale;
648
+ const domainSetter =
649
+ this.createMarkUniformSetter(domainUniformName);
553
650
  const set = () => {
554
651
  const domain = isDiscrete(scale.type)
555
652
  ? [0, scale.domain().length]
@@ -562,6 +659,7 @@ export default class Mark {
562
659
  );
563
660
  };
564
661
 
662
+ // TODO: The event listener should be in the scale, not the resolution
565
663
  scaleResolution.addEventListener("domain", set);
566
664
 
567
665
  // Initial value
@@ -569,8 +667,27 @@ export default class Mark {
569
667
  });
570
668
  }
571
669
  }
670
+
671
+ // Generate conditional encoder -------------------------------
672
+
673
+ scaleCode.push(generateConditionalEncoderGlsl(channel, accessors));
572
674
  }
573
675
 
676
+ // Generate a function that checks if the datum is subject to any point selection
677
+ const conditions = [...selectionParameterUniforms.entries()]
678
+ .filter(([, v]) => v == "single")
679
+ .map(
680
+ ([param]) =>
681
+ `${PARAM_PREFIX}${param} == ${ATTRIBUTE_PREFIX}uniqueId`
682
+ );
683
+ scaleCode.push(
684
+ "bool isPointSelected() {",
685
+ this.encoders.uniqueId && conditions.length > 0
686
+ ? ` return ${conditions.join(" || ")};`
687
+ : " return false;",
688
+ "}"
689
+ );
690
+
574
691
  const vertexPrecision = "precision highp float;\nprecision highp int;";
575
692
 
576
693
  /**
@@ -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;IA0HY,oCAMC;IAiET,+BAkBC;;CAgDJ;iBA3QgB,WAAW"}
@@ -135,7 +135,7 @@ export default class PointMark extends Mark {
135
135
  // Semantic zooming is currently solely a feature of point mark.
136
136
  // Build a sorted sample that allows for computing p-quantiles
137
137
  const semanticScoreAccessor =
138
- this.unitView.getAccessor("semanticScore");
138
+ this.encoders["semanticScore"]?.dataAccessor?.asNumberAccessor();
139
139
  if (semanticScoreAccessor) {
140
140
  // n chosen using Stetson-Harrison
141
141
  // TODO: Throw on missing scores
@@ -177,6 +177,10 @@ export default class PointMark extends Mark {
177
177
 
178
178
  updateGraphicsData() {
179
179
  const collector = this.unitView.getCollector();
180
+ if (!collector) {
181
+ console.debug("No collector");
182
+ return;
183
+ }
180
184
  const itemCount = collector.getItemCount();
181
185
 
182
186
  const builder = new PointVertexBuilder({
@@ -1 +1 @@
1
- {"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AAaA;IAyNI;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBAlQgB,WAAW"}
1
+ {"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AAaA;IA8NI;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBAvQgB,WAAW"}
@@ -126,7 +126,8 @@ export default class RectMark extends Mark {
126
126
 
127
127
  #isStroked() {
128
128
  const sw = this.encoding.strokeWidth;
129
- return !(isValueDef(sw) && !sw.value);
129
+ // True if there's any chance for a stroke to be drawn
130
+ return !(isValueDef(sw) && !sw.value) || "condition" in sw;
130
131
  }
131
132
 
132
133
  async initializeGraphics() {
@@ -177,6 +178,10 @@ export default class RectMark extends Mark {
177
178
 
178
179
  updateGraphicsData() {
179
180
  const collector = this.unitView.getCollector();
181
+ if (!collector) {
182
+ console.debug("No collector");
183
+ return;
184
+ }
180
185
  const numItems = collector.getItemCount();
181
186
 
182
187
  const builder = new RectVertexBuilder({
@@ -251,13 +256,13 @@ export default class RectMark extends Mark {
251
256
  const scaleType = e.x.scale.type;
252
257
 
253
258
  if (isDiscrete(scaleType)) {
254
- const a = e.x.accessor;
259
+ const a = e.x.dataAccessor;
255
260
  // TODO: Binary search
256
261
  return data.find((d) => x == a(d));
257
262
  } else {
258
263
  // TODO: Handle point features on locus/index scales
259
- const a = e.x.accessor;
260
- const a2 = e.x2.accessor;
264
+ const a = e.x.dataAccessor;
265
+ const a2 = e.x2.dataAccessor;
261
266
  // TODO: Binary search
262
267
  return data.find((d) => x >= a(d) && x < a2(d));
263
268
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/marks/rule.js"],"names":[],"mappings":"AAcA;IAOQ,wBAAwB;IA4GpB,0BAOE;CA4Fb;iBApOgB,WAAW"}
1
+ {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/marks/rule.js"],"names":[],"mappings":"AAcA;IAOQ,wBAAwB;IA4GpB,0BAOE;CAgGb;iBAxOgB,WAAW"}
@@ -165,6 +165,10 @@ export default class RuleMark extends Mark {
165
165
 
166
166
  updateGraphicsData() {
167
167
  const collector = this.unitView.getCollector();
168
+ if (!collector) {
169
+ console.debug("No collector");
170
+ return;
171
+ }
168
172
  const itemCount = collector.getItemCount();
169
173
 
170
174
  const builder = new RuleVertexBuilder({
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAyDQ,oDAMmD;CAwM1D;iBAlSgB,WAAW"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAyDQ,oDAMmD;CA4M1D;iBAtSgB,WAAW"}
@@ -216,11 +216,15 @@ export default class TextMark extends Mark {
216
216
 
217
217
  updateGraphicsData() {
218
218
  const collector = this.unitView.getCollector();
219
+ if (!collector) {
220
+ console.debug("No collector");
221
+ return;
222
+ }
219
223
  const data = collector.getData();
220
224
  const encoding = this.encoding;
221
225
 
222
226
  // Count the total number of characters to that we can pre-allocate a typed array
223
- const accessor = this.encoders.text.accessor || this.encoders.text; // accessor or constant value
227
+ const accessor = this.encoders.text; // accessor or constant value
224
228
  let charCount = 0;
225
229
  /** @type {function(any):any} */
226
230
  const numberFormat =
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scale.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scale.test.d.ts","sourceRoot":"","sources":["../../../src/scale/scale.test.js"],"names":[],"mappings":""}
@@ -1,3 +1,5 @@
1
+ // @ts-nocheck
2
+
1
3
  import { expect, test } from "vitest";
2
4
  /*!
3
5
  * Adapted from vega-encode:
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ticks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ticks.test.d.ts","sourceRoot":"","sources":["../../../src/scale/ticks.test.js"],"names":[],"mappings":""}
@@ -16,6 +16,12 @@ import { validTicks } from "./ticks.js";
16
16
  test("validTicks uses count correctly", function () {
17
17
  var data = [0, 1, 2, 3, 4, 5, 6, 7];
18
18
 
19
+ /**
20
+ *
21
+ * @param {T} x
22
+ * @returns {T}
23
+ * @template T
24
+ */
19
25
  var identity = function (x) {
20
26
  return x;
21
27
  };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @param {import("../data/flowNode.js").Datum} datum
3
+ * @returns {import("../types/selectionTypes.js").SinglePointSelection}
4
+ */
5
+ export function createSinglePointSelection(datum: import("../data/flowNode.js").Datum): import("../types/selectionTypes.js").SinglePointSelection;
6
+ /**
7
+ * @param {import("../types/selectionTypes.js").Selection} selection
8
+ * @param {import("../data/flowNode.js").Datum} datum
9
+ * @param {boolean} [empty] evaluate to true if the selection is empty
10
+ */
11
+ export function selectionTest(selection: import("../types/selectionTypes.js").Selection, datum: import("../data/flowNode.js").Datum, empty?: boolean): boolean;
12
+ /**
13
+ * @param {{param: string, empty?: boolean}} params
14
+ */
15
+ export function makeSelectionTestExpression(params: {
16
+ param: string;
17
+ empty?: boolean;
18
+ }): string;
19
+ /**
20
+ * @param {import("../types/selectionTypes.js").Selection} selection
21
+ * @returns {selection is import("../types/selectionTypes.js").RangeSelection}
22
+ */
23
+ export function isRangeSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").RangeSelection;
24
+ /**
25
+ * @param {import("../types/selectionTypes.js").Selection} selection
26
+ * @returns {selection is import("../types/selectionTypes.js").SinglePointSelection}
27
+ */
28
+ export function isSinglePointSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").SinglePointSelection;
29
+ /**
30
+ * @param {import("../types/selectionTypes.js").Selection} selection
31
+ * @returns {selection is import("../types/selectionTypes.js").MultiPointSelection}
32
+ */
33
+ export function isMultiPointSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").MultiPointSelection;
34
+ /**
35
+ * @param {import("../types/selectionTypes.js").Selection} selection
36
+ * @returns {selection is import("../types/selectionTypes.js").ProjectedSelection}
37
+ */
38
+ export function isProjectedSelection(selection: import("../types/selectionTypes.js").Selection): selection is import("../types/selectionTypes.js").ProjectedSelection;
39
+ //# sourceMappingURL=selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/selection/selection.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,kDAHW,OAAO,qBAAqB,EAAE,KAAK,GACjC,OAAO,4BAA4B,EAAE,oBAAoB,CAQrE;AAED;;;;GAIG;AACH,yCAJW,OAAO,4BAA4B,EAAE,SAAS,SAC9C,OAAO,qBAAqB,EAAE,KAAK,UACnC,OAAO,WAkBjB;AAED;;GAEG;AACH,oDAFW;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,UAM1C;AAED;;;GAGG;AACH,4CAHW,OAAO,4BAA4B,EAAE,SAAS,oEAKxD;AAED;;;GAGG;AACH,kDAHW,OAAO,4BAA4B,EAAE,SAAS,0EAKxD;AAED;;;GAGG;AACH,iDAHW,OAAO,4BAA4B,EAAE,SAAS,yEAKxD;AAED;;;GAGG;AACH,gDAHW,OAAO,4BAA4B,EAAE,SAAS,wEAKxD"}