@genome-spy/core 0.40.0 → 0.42.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 (104) hide show
  1. package/dist/bundle/index--cKb-dKG.js +615 -0
  2. package/dist/bundle/{index-gn8bhQ8w.js → index-d7k3kkin.js} +365 -366
  3. package/dist/bundle/index.es.js +4260 -3928
  4. package/dist/bundle/index.js +115 -80
  5. package/dist/schema.json +254 -52
  6. package/dist/src/data/sources/dynamic/axisGenomeSource.js +1 -1
  7. package/dist/src/data/sources/dynamic/axisTickSource.js +3 -3
  8. package/dist/src/data/sources/dynamic/bamSource.d.ts +3 -21
  9. package/dist/src/data/sources/dynamic/bamSource.d.ts.map +1 -1
  10. package/dist/src/data/sources/dynamic/bamSource.js +38 -55
  11. package/dist/src/data/sources/dynamic/bigBedSource.d.ts +2 -38
  12. package/dist/src/data/sources/dynamic/bigBedSource.d.ts.map +1 -1
  13. package/dist/src/data/sources/dynamic/bigBedSource.js +14 -71
  14. package/dist/src/data/sources/dynamic/bigWigSource.d.ts +4 -42
  15. package/dist/src/data/sources/dynamic/bigWigSource.d.ts.map +1 -1
  16. package/dist/src/data/sources/dynamic/bigWigSource.js +23 -60
  17. package/dist/src/data/sources/dynamic/gff3Source.d.ts.map +1 -1
  18. package/dist/src/data/sources/dynamic/gff3Source.js +1 -0
  19. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts +2 -20
  20. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts.map +1 -1
  21. package/dist/src/data/sources/dynamic/indexedFastaSource.js +23 -41
  22. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts +23 -4
  23. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts.map +1 -1
  24. package/dist/src/data/sources/dynamic/singleAxisLazySource.js +29 -4
  25. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts +60 -0
  26. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts.map +1 -0
  27. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.js +152 -0
  28. package/dist/src/data/sources/dynamic/tabixSource.d.ts +6 -40
  29. package/dist/src/data/sources/dynamic/tabixSource.d.ts.map +1 -1
  30. package/dist/src/data/sources/dynamic/tabixSource.js +29 -78
  31. package/dist/src/data/transforms/regexFold.d.ts.map +1 -1
  32. package/dist/src/data/transforms/regexFold.js +8 -0
  33. package/dist/src/data/transforms/regexFold.test.js +28 -0
  34. package/dist/src/encoder/accessor.js +4 -2
  35. package/dist/src/genomeSpy.d.ts +16 -0
  36. package/dist/src/genomeSpy.d.ts.map +1 -1
  37. package/dist/src/genomeSpy.js +119 -8
  38. package/dist/src/gl/link.vertex.glsl.js +1 -1
  39. package/dist/src/gl/point.common.glsl.js +2 -0
  40. package/dist/src/gl/point.fragment.glsl.js +1 -1
  41. package/dist/src/gl/point.vertex.glsl.js +1 -1
  42. package/dist/src/gl/rect.vertex.glsl.js +1 -1
  43. package/dist/src/gl/rule.common.glsl.js +2 -0
  44. package/dist/src/gl/rule.fragment.glsl.js +1 -1
  45. package/dist/src/gl/rule.vertex.glsl.js +1 -1
  46. package/dist/src/gl/text.common.glsl.js +2 -0
  47. package/dist/src/gl/text.fragment.glsl.js +1 -1
  48. package/dist/src/gl/text.vertex.glsl.js +1 -1
  49. package/dist/src/gl/webGLHelper.d.ts +6 -21
  50. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  51. package/dist/src/gl/webGLHelper.js +7 -38
  52. package/dist/src/img/90-ring-with-bg.svg +1 -0
  53. package/dist/src/img/README.md +5 -0
  54. package/dist/src/marks/link.d.ts +7 -0
  55. package/dist/src/marks/link.d.ts.map +1 -1
  56. package/dist/src/marks/link.js +99 -50
  57. package/dist/src/marks/mark.d.ts +34 -0
  58. package/dist/src/marks/mark.d.ts.map +1 -1
  59. package/dist/src/marks/mark.js +83 -1
  60. package/dist/src/marks/pointMark.d.ts.map +1 -1
  61. package/dist/src/marks/pointMark.js +21 -9
  62. package/dist/src/marks/rectMark.d.ts +1 -2
  63. package/dist/src/marks/rectMark.d.ts.map +1 -1
  64. package/dist/src/marks/rectMark.js +28 -17
  65. package/dist/src/marks/rule.d.ts.map +1 -1
  66. package/dist/src/marks/rule.js +17 -6
  67. package/dist/src/marks/text.d.ts.map +1 -1
  68. package/dist/src/marks/text.js +32 -18
  69. package/dist/src/paramBroker.d.ts +30 -0
  70. package/dist/src/paramBroker.d.ts.map +1 -0
  71. package/dist/src/paramBroker.js +102 -0
  72. package/dist/src/spec/data.d.ts +28 -13
  73. package/dist/src/spec/mark.d.ts +27 -26
  74. package/dist/src/spec/view.d.ts +2 -1
  75. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  76. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  77. package/dist/src/styles/genome-spy.css.js +33 -4
  78. package/dist/src/styles/genome-spy.scss +40 -4
  79. package/dist/src/types/viewContext.d.ts +11 -0
  80. package/dist/src/utils/binnedIndex.d.ts +2 -0
  81. package/dist/src/utils/binnedIndex.d.ts.map +1 -1
  82. package/dist/src/utils/binnedIndex.js +59 -10
  83. package/dist/src/utils/binnedIndex.test.js +46 -0
  84. package/dist/src/utils/expression.d.ts +12 -2
  85. package/dist/src/utils/expression.d.ts.map +1 -1
  86. package/dist/src/utils/expression.js +68 -9
  87. package/dist/src/utils/linearstep.d.ts +7 -0
  88. package/dist/src/utils/linearstep.d.ts.map +1 -0
  89. package/dist/src/utils/linearstep.js +10 -0
  90. package/dist/src/view/gridView.d.ts.map +1 -1
  91. package/dist/src/view/gridView.js +2 -0
  92. package/dist/src/view/layerView.d.ts.map +1 -1
  93. package/dist/src/view/layerView.js +2 -0
  94. package/dist/src/view/unitView.d.ts +0 -6
  95. package/dist/src/view/unitView.d.ts.map +1 -1
  96. package/dist/src/view/unitView.js +2 -9
  97. package/dist/src/view/view.d.ts +6 -0
  98. package/dist/src/view/view.d.ts.map +1 -1
  99. package/dist/src/view/view.js +17 -0
  100. package/package.json +3 -3
  101. package/dist/bundle/index-Cbz74kpR.js +0 -638
  102. package/dist/src/data/sources/dynamic/windowedMixin.d.ts +0 -32
  103. package/dist/src/data/sources/dynamic/windowedMixin.d.ts.map +0 -1
  104. package/dist/src/data/sources/dynamic/windowedMixin.js +0 -53
@@ -1,4 +1,4 @@
1
- import { drawBufferInfo, setBuffersAndAttributes, setUniforms } from "twgl.js";
1
+ import { setBuffersAndAttributes } from "twgl.js";
2
2
  import VERTEX_SHADER from "../gl/link.vertex.glsl.js";
3
3
  import FRAGMENT_SHADER from "../gl/link.fragment.glsl.js";
4
4
  import { LinkVertexBuilder } from "../gl/dataToVertices.js";
@@ -39,6 +39,16 @@ export default class LinkMark extends Mark {
39
39
  orient: "vertical",
40
40
  })
41
41
  );
42
+
43
+ /**
44
+ * Only available if "WebGL Draft Extensions" is enabled in chrome://flags
45
+ * But seems to work.
46
+ *
47
+ * @private
48
+ */
49
+ this._baseInstanceExt = this.gl.getExtension(
50
+ "WEBGL_draw_instanced_base_vertex_base_instance"
51
+ );
42
52
  }
43
53
 
44
54
  getAttributes() {
@@ -97,17 +107,22 @@ export default class LinkMark extends Mark {
97
107
 
98
108
  const props = this.properties;
99
109
 
100
- // TODO: Use uniform block.
101
- setUniforms(this.programInfo, {
102
- uArcHeightFactor: props.arcHeightFactor,
103
- uMinArcHeight: props.minArcHeight,
104
- uMinPickingSize: props.minPickingSize,
105
- uShape: LINK_SHAPES.indexOf(props.linkShape),
106
- uOrient: ORIENTS.indexOf(props.orient),
107
- uClampApex: !!props.clampApex,
108
- uMaxChordLength: props.maxChordLength,
109
- uArcFadingDistance: props.arcFadingDistance || [0, 0],
110
- });
110
+ this.registerMarkUniform(
111
+ "uArcFadingDistance",
112
+ props.arcFadingDistance,
113
+ (x) => x || /** @type {[number, number]} */ ([0, 0])
114
+ );
115
+ this.registerMarkUniform("uArcHeightFactor", props.arcHeightFactor);
116
+ this.registerMarkUniform("uMinArcHeight", props.minArcHeight);
117
+ this.registerMarkUniform("uMinPickingSize", props.minPickingSize);
118
+ this.registerMarkUniform("uShape", props.linkShape, (linkShape) =>
119
+ LINK_SHAPES.indexOf(linkShape)
120
+ );
121
+ this.registerMarkUniform("uOrient", props.orient, (orient) =>
122
+ ORIENTS.indexOf(orient)
123
+ );
124
+ this.registerMarkUniform("uClampApex", props.clampApex, (x) => !!x);
125
+ this.registerMarkUniform("uMaxChordLength", props.maxChordLength);
111
126
  }
112
127
 
113
128
  updateGraphicsData() {
@@ -141,50 +156,84 @@ export default class LinkMark extends Mark {
141
156
  this.updateBufferInfo(vertexData);
142
157
  }
143
158
 
159
+ /**
160
+ * @param {import("../types/rendering.js").GlobalRenderingOptions} options
161
+ */
162
+ prepareRender(options) {
163
+ const ops = super.prepareRender(options);
164
+
165
+ ops.push(() => this.bindOrSetMarkUniformBlock());
166
+
167
+ if (this._baseInstanceExt) {
168
+ ops.push(() =>
169
+ setBuffersAndAttributes(
170
+ this.gl,
171
+ this.programInfo,
172
+ this.vertexArrayInfo
173
+ )
174
+ );
175
+ } else {
176
+ ops.push(() => this.gl.bindVertexArray(null));
177
+ }
178
+
179
+ return ops;
180
+ }
181
+
144
182
  /**
145
183
  * @param {import("./mark.js").MarkRenderingOptions} options
146
184
  */
147
185
  render(options) {
148
186
  const gl = this.gl;
149
187
 
150
- // TODO: Vertical clipping in faceted view
151
-
152
- return this.createRenderCallback((offset, count) => {
153
- // We are using instanced drawing here.
154
- // However, WebGL does not provide glDrawArraysInstancedBaseInstance and thus,
155
- // we have to hack with offsets in vertexAttribPointer
156
- // TODO: Use VAOs more intelligently to reduce WebGL calls
157
- // TODO: Explore multiDrawArraysInstancedWEBGL
158
- // There's also a promising extension draft:
159
- // https://www.khronos.org/registry/webgl/extensions/WEBGL_draw_instanced_base_vertex_base_instance/
160
- // (and https://www.khronos.org/registry/webgl/extensions/WEBGL_multi_draw_instanced_base_vertex_base_instance/)
161
-
162
- this.gl.bindVertexArray(this.vertexArrayInfo.vertexArrayObject);
163
-
164
- for (const attribInfoObject of Object.entries(
165
- this.bufferInfo.attribs
166
- )) {
167
- const [attribute, attribInfo] = attribInfoObject;
168
- if (
169
- attribInfo.buffer &&
170
- attribInfo.numComponents &&
171
- attribInfo.divisor
172
- ) {
173
- attribInfo.offset =
174
- offset * this.arrays[attribute].numComponents * 4; // gl.FLOAT in bytes
175
- }
176
- }
177
- setBuffersAndAttributes(gl, this.programInfo, this.bufferInfo);
178
-
179
- drawBufferInfo(
180
- gl,
181
- this.bufferInfo,
182
- gl.TRIANGLE_STRIP,
183
- (this.properties.segments + 1) * 2, // number of vertices in a triangle strip
184
- 0,
185
- count
186
- );
187
- }, options);
188
+ const arcVertexCount = (this.properties.segments + 1) * 2;
189
+
190
+ return this._baseInstanceExt
191
+ ? this.createRenderCallback((offset, count) => {
192
+ // Using the following extension, which, however, is only a draft and
193
+ // available if "WebGL Draft Extensions" is enabled in chrome://flags
194
+ // https://www.khronos.org/registry/webgl/extensions/WEBGL_draw_instanced_base_vertex_base_instance/
195
+
196
+ this._baseInstanceExt.drawArraysInstancedBaseInstanceWEBGL(
197
+ gl.TRIANGLE_STRIP,
198
+ 0,
199
+ arcVertexCount,
200
+ count,
201
+ offset
202
+ );
203
+ }, options)
204
+ : this.createRenderCallback((offset, count) => {
205
+ // Because vanilla WebGL 2 does not provide glDrawArraysInstancedBaseInstance,
206
+ // we have to hack with offsets in vertexAttribPointer
207
+ //
208
+ // TODO: Use VAOs more intelligently to reduce WebGL calls. In other words,
209
+ // reserve one VAO for each facet/sample.
210
+
211
+ for (const attribInfoObject of Object.entries(
212
+ this.bufferInfo.attribs
213
+ )) {
214
+ const [attribute, attribInfo] = attribInfoObject;
215
+ if (
216
+ attribInfo.buffer &&
217
+ attribInfo.numComponents &&
218
+ attribInfo.divisor
219
+ ) {
220
+ attribInfo.offset =
221
+ offset * this.arrays[attribute].numComponents * 4; // gl.FLOAT in bytes
222
+ }
223
+ }
224
+ setBuffersAndAttributes(
225
+ gl,
226
+ this.programInfo,
227
+ this.bufferInfo
228
+ );
229
+
230
+ gl.drawArraysInstanced(
231
+ gl.TRIANGLE_STRIP,
232
+ 0,
233
+ arcVertexCount,
234
+ count
235
+ );
236
+ }, options);
188
237
  }
189
238
  }
190
239
 
@@ -1,4 +1,9 @@
1
1
  /// <reference types="external-typings/internmap.js" />
2
+ /**
3
+ * @param {any} x
4
+ * @returns {x is import("../spec/mark.js").ExprRef}
5
+ */
6
+ export function isExprRef(x: any): x is import("../spec/mark.js").ExprRef;
2
7
  export const SAMPLE_FACET_UNIFORM: "SAMPLE_FACET_UNIFORM";
3
8
  export const SAMPLE_FACET_TEXTURE: "SAMPLE_FACET_TEXTURE";
4
9
  /**
@@ -20,6 +25,7 @@ export default class Mark {
20
25
  * @typedef {import("../spec/channel.js").Channel} Channel
21
26
  * @typedef {import("../spec/channel.js").Encoding} Encoding
22
27
  * @typedef {import("../spec/channel.js").ValueDef} ValueDef
28
+ * @typedef {import("../spec/mark.js").ExprRef} ExprRef
23
29
  */
24
30
  /**
25
31
  * @param {import("../view/unitView.js").default} unitView
@@ -40,6 +46,18 @@ export default class Mark {
40
46
  domainUniformInfo: import("twgl.js").UniformBlockInfo;
41
47
  /** @type {import("twgl.js").UniformBlockInfo} WebGL buffers */
42
48
  viewUniformInfo: import("twgl.js").UniformBlockInfo;
49
+ /**
50
+ * Uniforms related to the specific mark type.
51
+ * @type {import("twgl.js").UniformBlockInfo}
52
+ */
53
+ markUniformInfo: import("twgl.js").UniformBlockInfo;
54
+ /**
55
+ * Indicates whether the mark's uniforms have been altered since the last rendering.
56
+ * If set to true, the uniforms will be sent to the GPU before rendering the next frame.
57
+
58
+ * @protected
59
+ */
60
+ protected markUniformsAltered: boolean;
43
61
  /** @type {RangeMap<any>} keep track of facet locations within the vertex array */
44
62
  rangeMap: RangeMap<any>;
45
63
  /** @type {MarkConfig} */
@@ -123,6 +141,18 @@ export default class Mark {
123
141
  * initialization.
124
142
  */
125
143
  finalizeGraphicsInitialization(): void;
144
+ /**
145
+ * Set a uniform based on a mark property. If the property is an expression,
146
+ * register a listener to update the uniform when the params referenced by the
147
+ * expression change.
148
+ *
149
+ * @protected
150
+ * @template T
151
+ * @param {string} uniformName
152
+ * @param {T} propValue
153
+ * @param {(x: Exclude<T, ExprRef>) => any} adjuster
154
+ */
155
+ protected registerMarkUniform<T>(uniformName: string, propValue: T, adjuster?: (x: Exclude<T, import("../spec/mark.js").ExprRef>) => any): void;
126
156
  _setDatums(): void;
127
157
  /**
128
158
  * Delete WebGL buffers etc.
@@ -147,6 +177,10 @@ export default class Mark {
147
177
  * TODO: Check if selection (when it's implemented) is enabled
148
178
  */
149
179
  isPickingParticipant(): boolean;
180
+ /**
181
+ * @protected
182
+ */
183
+ protected bindOrSetMarkUniformBlock(): void;
150
184
  /**
151
185
  * Configures the WebGL state for rendering the mark instances.
152
186
  * A separate preparation stage allows for efficient rendering of faceted
@@ -1 +1 @@
1
- {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":";AAwCA,0DAA2D;AAC3D,0DAA2D;AAE3D;;;;;;;;;;;;GAYG;AACH;IACI;;;;;OAKG;IAEH;;OAEG;IACH,sBAFW,OAAO,qBAAqB,EAAE,OAAO,EAoE/C;IAjEG,gDAAwB;IAExB,oEAAoE;IACpE,UADW,OAAO,MAAM,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAC,CACvC;IAIzB,0FAA0F;IAC1F,YADW,OAAO,SAAS,EAAE,UAAU,GAAG;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAC7C;IAE3B,0DAA0D;IAC1D,aADW,OAAO,SAAS,EAAE,WAAW,CACZ;IAE5B,8DAA8D;IAC9D,iBADW,OAAO,SAAS,EAAE,eAAe,CACZ;IAEhC,+DAA+D;IAC/D,mBADW,OAAO,SAAS,EAAE,gBAAgB,CACX;IAElC,+DAA+D;IAC/D,iBADW,OAAO,SAAS,EAAE,gBAAgB,CACb;IAEhC,kFAAkF;IAClF,UADW,SAAS,GAAG,CAAC,CACM;IAG9B,yBAAyB;IACzB,wDAqBC;IAED;;;;;;;;OAQG;IACH,mEAKC;IAGL,sBAEC;IAED;;;;;;;OAOG;IACH,iBAFa,MAAM,EAAE,CAKpB;IAED;;OAEG;IACH,+DAWC;IAED;;OAEG;IACH,oEAcC;IAED;;;;;OAKG;IACH,oHAEC;IAED;;;;OAIG;IACH,8DAyCC;IAED,wDAEC;IAED,8CAEC;IAED,uBAEC;IAED;;;OAGG;IACH,2BAEC;IAED;;OAEG;IACH,oCAEC;IAED;;OAEG;IACH,2BAEC;IAED,sEAeC;IAED;;;;;OAKG;IACH,mCAJW,MAAM,kBACN,MAAM,iBACN,MAAM,EAAE,QA+FlB;IAtFG,uBAAuB;IACvB,gBADW,MAAM,EAAE,CACK;IAgFxB;;;;;;MAIC;IAGL;;;OAGG;IACH,uCA4CC;IAED,mBAgBC;IAED;;OAEG;IACH,2BAiBC;IAED;;;OAGG;IACH,6BAFW,GAAG,QAoCb;IAED,yBAAyB;IACzB,uDAEC;IAED,yBAAyB;IACzB,iCAEC;IAED,gCAEC;IAED,+BAEC;IAED,yCAEC;IAED;;;;;OAKG;IACH,gCAcC;IAED;;;;;;;;OAQG;IAEH,uBAJW,OAAO,uBAAuB,EAAE,sBAAsB,GACpD,CAAC,MAAM,IAAI,CAAC,EAAE,CA+H1B;IAED;;;;;;OAMG;IACH,qCAJW,oBAAoB,GAClB,OAAO,CAqCnB;IAED;;;;;;;OAOG;IACH,gBAJW,oBAAoB,SACP,IAAI,CAM3B;IAED;;;OAGG;IACH,2BAHW,YAAY,WACZ,OAAO,WAAW,EAAE,oBAAoB,cAiElD;IAED;;;;;;OAMG;IACH,oBAJW,OAAO,6BAA6B,EAAE,OAAO,aAC7C,OAAO,6BAA6B,EAAE,OAAO,GAC3C,OAAO,CAuHnB;IAED;;;;;;;;;OASG;IACH,qBAJW,MAAM,KACN,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAIf;CACJ;+BA95BY,OAAO,uBAAuB,EAAE,gBAAgB;;;;;;wBAEnD,OAAO;;mCAEJ,gBAAgB,GAAG,qBAAqB;oCAG1C,MAAM,SACN,MAAM;AAw5BjB;;;GAGG;AACH;IACI,cAEC;IAkBD;;;OAGG;IACH,2BAFW,IAAI,CAAC,EAAE,OAAO,yBAAyB,EAAE,UAAU,CAAC,QAM9D;CACJ;0BA38ByB,WAAW"}
1
+ {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import {
2
+ bindUniformBlock,
2
3
  createBufferInfoFromArrays,
3
4
  createProgramInfoFromProgram,
4
5
  createUniformBlockInfo,
@@ -37,6 +38,7 @@ import { isScalar } from "../utils/variableTools.js";
37
38
  import { InternMap } from "internmap";
38
39
  import scaleNull from "../utils/scaleNull.js";
39
40
  import ViewError from "../view/viewError.js";
41
+ import { isString } from "vega-util";
40
42
 
41
43
  export const SAMPLE_FACET_UNIFORM = "SAMPLE_FACET_UNIFORM";
42
44
  export const SAMPLE_FACET_TEXTURE = "SAMPLE_FACET_TEXTURE";
@@ -60,6 +62,7 @@ export default class Mark {
60
62
  * @typedef {import("../spec/channel.js").Channel} Channel
61
63
  * @typedef {import("../spec/channel.js").Encoding} Encoding
62
64
  * @typedef {import("../spec/channel.js").ValueDef} ValueDef
65
+ * @typedef {import("../spec/mark.js").ExprRef} ExprRef
63
66
  */
64
67
 
65
68
  /**
@@ -88,6 +91,20 @@ export default class Mark {
88
91
  /** @type {import("twgl.js").UniformBlockInfo} WebGL buffers */
89
92
  this.viewUniformInfo = undefined;
90
93
 
94
+ /**
95
+ * Uniforms related to the specific mark type.
96
+ * @type {import("twgl.js").UniformBlockInfo}
97
+ */
98
+ this.markUniformInfo = undefined;
99
+
100
+ /**
101
+ * Indicates whether the mark's uniforms have been altered since the last rendering.
102
+ * If set to true, the uniforms will be sent to the GPU before rendering the next frame.
103
+
104
+ * @protected
105
+ */
106
+ this.markUniformsAltered = true;
107
+
91
108
  /** @type {RangeMap<any>} keep track of facet locations within the vertex array */
92
109
  this.rangeMap = new RangeMap();
93
110
 
@@ -304,7 +321,7 @@ export default class Mark {
304
321
  const attributes = this.getAttributes();
305
322
 
306
323
  // For debugging
307
- extraHeaders.push("// view: " + this.unitView.getPathString());
324
+ const debugHeader = "// view: " + this.unitView.getPathString();
308
325
 
309
326
  // TODO: This is a temporary variable, don't store it in the mark object
310
327
  /** @type {string[]} */
@@ -366,6 +383,7 @@ export default class Mark {
366
383
 
367
384
  const vertexParts = [
368
385
  vertexPrecision,
386
+ debugHeader,
369
387
  ...extraHeaders,
370
388
  GLSL_COMMON,
371
389
  GLSL_SCALES,
@@ -377,6 +395,7 @@ export default class Mark {
377
395
  ];
378
396
 
379
397
  const fragmentParts = [
398
+ debugHeader,
380
399
  ...extraHeaders,
381
400
  GLSL_COMMON,
382
401
  GLSL_PICKING_FRAGMENT,
@@ -433,6 +452,12 @@ export default class Mark {
433
452
  "View"
434
453
  );
435
454
 
455
+ this.markUniformInfo = createUniformBlockInfo(
456
+ this.gl,
457
+ this.programInfo,
458
+ "Mark"
459
+ );
460
+
436
461
  this.gl.useProgram(this.programInfo.program);
437
462
 
438
463
  this._setDatums();
@@ -445,6 +470,42 @@ export default class Mark {
445
470
  });
446
471
  }
447
472
 
473
+ /**
474
+ * Set a uniform based on a mark property. If the property is an expression,
475
+ * register a listener to update the uniform when the params referenced by the
476
+ * expression change.
477
+ *
478
+ * @protected
479
+ * @template T
480
+ * @param {string} uniformName
481
+ * @param {T} propValue
482
+ * @param {(x: Exclude<T, ExprRef>) => any} adjuster
483
+ */
484
+ registerMarkUniform(uniformName, propValue, adjuster = (x) => x) {
485
+ const uniformSetter = this.markUniformInfo.setters[uniformName];
486
+
487
+ if (isExprRef(propValue)) {
488
+ const fn = this.unitView.context.paramBroker.createExpression(
489
+ propValue.expr
490
+ );
491
+
492
+ const set = () => {
493
+ uniformSetter(adjuster(fn(null)));
494
+ this.markUniformsAltered = true;
495
+ };
496
+
497
+ // Register a listener ...
498
+ fn.addListener(set);
499
+ // ... and set the initial value
500
+ set();
501
+ } else {
502
+ uniformSetter(
503
+ adjuster(/** @type {Exclude<T, ExprRef>} */ (propValue))
504
+ );
505
+ this.markUniformsAltered = true;
506
+ }
507
+ }
508
+
448
509
  _setDatums() {
449
510
  for (const [channel, channelDef] of Object.entries(this.encoding)) {
450
511
  if (isDatumDef(channelDef)) {
@@ -569,6 +630,18 @@ export default class Mark {
569
630
  return true;
570
631
  }
571
632
 
633
+ /**
634
+ * @protected
635
+ */
636
+ bindOrSetMarkUniformBlock() {
637
+ if (this.markUniformsAltered) {
638
+ setUniformBlock(this.gl, this.programInfo, this.markUniformInfo);
639
+ this.markUniformsAltered = false;
640
+ } else {
641
+ bindUniformBlock(this.gl, this.programInfo, this.markUniformInfo);
642
+ }
643
+ }
644
+
572
645
  /**
573
646
  * Configures the WebGL state for rendering the mark instances.
574
647
  * A separate preparation stage allows for efficient rendering of faceted
@@ -1006,3 +1079,12 @@ class RangeMap extends InternMap {
1006
1079
  }
1007
1080
  }
1008
1081
  }
1082
+
1083
+ // TODO: Find a better place for this function
1084
+ /**
1085
+ * @param {any} x
1086
+ * @returns {x is import("../spec/mark.js").ExprRef}
1087
+ */
1088
+ export function isExprRef(x) {
1089
+ return typeof x === "object" && "expr" in x && isString(x.expr);
1090
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"pointMark.d.ts","sourceRoot":"","sources":["../../../src/marks/pointMark.js"],"names":[],"mappings":"AAaA;IAsGY,oCAMC;IAwCT,mCAQC;IAED;;OAEG;IACH,wDASC;IAED,+BAoBC;CA6CJ;iBApPgB,WAAW"}
1
+ {"version":3,"file":"pointMark.d.ts","sourceRoot":"","sources":["../../../src/marks/pointMark.js"],"names":[],"mappings":"AAkBA;IAsGY,oCAMC;IA2CT,mCAQC;IAED;;OAEG;IACH,wDASC;IAED,+BAoBC;CAiDJ;iBA3PgB,WAAW"}
@@ -1,8 +1,13 @@
1
- import { drawBufferInfo, setBuffersAndAttributes, setUniforms } from "twgl.js";
1
+ import {
2
+ drawBufferInfo,
3
+ setBlockUniforms,
4
+ setBuffersAndAttributes,
5
+ } from "twgl.js";
2
6
  import { quantileSorted } from "d3-array";
3
7
  import { PointVertexBuilder } from "../gl/dataToVertices.js";
4
8
  import VERTEX_SHADER from "../gl/point.vertex.glsl.js";
5
9
  import FRAGMENT_SHADER from "../gl/point.fragment.glsl.js";
10
+ import COMMON_SHADER from "../gl/point.common.glsl.js";
6
11
 
7
12
  import Mark from "./mark.js";
8
13
  import { sampleIterable } from "../data/transforms/sample.js";
@@ -126,7 +131,9 @@ export default class PointMark extends Mark {
126
131
 
127
132
  async initializeGraphics() {
128
133
  await super.initializeGraphics();
129
- this.createAndLinkShaders(VERTEX_SHADER, FRAGMENT_SHADER);
134
+ this.createAndLinkShaders(VERTEX_SHADER, FRAGMENT_SHADER, [
135
+ COMMON_SHADER,
136
+ ]);
130
137
  }
131
138
 
132
139
  finalizeGraphicsInitialization() {
@@ -135,9 +142,10 @@ export default class PointMark extends Mark {
135
142
  this.gl.useProgram(this.programInfo.program);
136
143
 
137
144
  const props = this.properties;
138
- setUniforms(this.programInfo, {
139
- uInwardStroke: props.inwardStroke,
140
- uGradientStrength: props.fillGradientStrength,
145
+
146
+ setBlockUniforms(this.markUniformInfo, {
147
+ uInwardStroke: !!props.inwardStroke,
148
+ uGradientStrength: +props.fillGradientStrength,
141
149
  uMaxRelativePointDiameter: 1 - 2 * props.sampleFacetPadding,
142
150
  });
143
151
  }
@@ -211,13 +219,17 @@ export default class PointMark extends Mark {
211
219
  prepareRender(options) {
212
220
  const ops = super.prepareRender(options);
213
221
 
214
- ops.push(() =>
215
- setUniforms(this.programInfo, {
222
+ ops.push(() => {
223
+ // TODO: Use bindUniformBlock if none of the uniform has changed
224
+ setBlockUniforms(this.markUniformInfo, {
216
225
  uMaxPointSize: this._getMaxPointSize(),
217
226
  uScaleFactor: this._getGeometricScaleFactor(),
218
227
  uSemanticThreshold: this.getSemanticThreshold(),
219
- })
220
- );
228
+ });
229
+ this.markUniformsAltered = true;
230
+ });
231
+
232
+ ops.push(() => this.bindOrSetMarkUniformBlock());
221
233
 
222
234
  ops.push(() =>
223
235
  setBuffersAndAttributes(
@@ -1,6 +1,4 @@
1
1
  export default class RectMark extends Mark {
2
- _isRoundedCorners(): number;
3
- _isStroked(): boolean;
4
2
  /**
5
3
  * Finds a datum that overlaps the given value on the x domain.
6
4
  * The result is unspecified if multiple data are found.
@@ -13,6 +11,7 @@ export default class RectMark extends Mark {
13
11
  * @override
14
12
  */
15
13
  override findDatumAt(facetId: any, x: import("../spec/channel.js").Scalar): any;
14
+ #private;
16
15
  }
17
16
  import Mark from "./mark.js";
18
17
  //# sourceMappingURL=rectMark.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rectMark.d.ts","sourceRoot":"","sources":["../../../src/marks/rectMark.js"],"names":[],"mappings":"AAYA;IAsGI,4BASC;IAED,sBAGC;IA4FD;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;CACJ;iBAzPgB,WAAW"}
1
+ {"version":3,"file":"rectMark.d.ts","sourceRoot":"","sources":["../../../src/marks/rectMark.js"],"names":[],"mappings":"AAYA;IA2NI;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBApQgB,WAAW"}
@@ -1,4 +1,4 @@
1
- import { drawBufferInfo, setBuffersAndAttributes, setUniforms } from "twgl.js";
1
+ import { drawBufferInfo, setBuffersAndAttributes } from "twgl.js";
2
2
  import VERTEX_SHADER from "../gl/rect.vertex.glsl.js";
3
3
  import FRAGMENT_SHADER from "../gl/rect.fragment.glsl.js";
4
4
  import { RectVertexBuilder } from "../gl/dataToVertices.js";
@@ -76,8 +76,8 @@ export default class RectMark extends Mark {
76
76
  this,
77
77
  "opaque",
78
78
  () =>
79
- !this._isRoundedCorners() &&
80
- !this._isStroked() &&
79
+ !this.#isRoundedCorners() &&
80
+ !this.#isStroked() &&
81
81
  isValueDef(this.encoding.fillOpacity) &&
82
82
  this.encoding.fillOpacity.value == 1.0 &&
83
83
  this.properties.minOpacity == 1.0
@@ -112,7 +112,7 @@ export default class RectMark extends Mark {
112
112
  // TODO: Pop the previous buffers
113
113
  }
114
114
 
115
- _isRoundedCorners() {
115
+ #isRoundedCorners() {
116
116
  const p = this.properties;
117
117
  return (
118
118
  p.cornerRadius ||
@@ -123,7 +123,7 @@ export default class RectMark extends Mark {
123
123
  );
124
124
  }
125
125
 
126
- _isStroked() {
126
+ #isStroked() {
127
127
  const sw = this.encoding.strokeWidth;
128
128
  return !(isValueDef(sw) && !sw.value);
129
129
  }
@@ -133,10 +133,10 @@ export default class RectMark extends Mark {
133
133
 
134
134
  /** @type {string[]} */
135
135
  const defines = [];
136
- if (this._isRoundedCorners()) {
136
+ if (this.#isRoundedCorners()) {
137
137
  defines.push("ROUNDED_CORNERS");
138
138
  }
139
- if (this._isStroked()) {
139
+ if (this.#isStroked()) {
140
140
  defines.push("STROKED");
141
141
  }
142
142
 
@@ -154,16 +154,25 @@ export default class RectMark extends Mark {
154
154
 
155
155
  const props = this.properties;
156
156
 
157
- setUniforms(this.programInfo, {
158
- uMinSize: [props.minWidth, props.minHeight], // in pixels
159
- uMinOpacity: props.minOpacity,
160
- uCornerRadii: [
161
- props.cornerRadiusTopRight ?? props.cornerRadius,
162
- props.cornerRadiusBottomRight ?? props.cornerRadius,
163
- props.cornerRadiusTopLeft ?? props.cornerRadius,
164
- props.cornerRadiusBottomLeft ?? props.cornerRadius,
165
- ],
166
- });
157
+ this.registerMarkUniform("uMinWidth", props.minWidth);
158
+ this.registerMarkUniform("uMinHeight", props.minHeight);
159
+ this.registerMarkUniform("uMinOpacity", props.minOpacity);
160
+ this.registerMarkUniform(
161
+ "uCornerRadiusTopRight",
162
+ props.cornerRadiusTopRight ?? props.cornerRadius ?? 0
163
+ );
164
+ this.registerMarkUniform(
165
+ "uCornerRadiusBottomRight",
166
+ props.cornerRadiusBottomRight ?? props.cornerRadius ?? 0
167
+ );
168
+ this.registerMarkUniform(
169
+ "uCornerRadiusTopLeft",
170
+ props.cornerRadiusTopLeft ?? props.cornerRadius ?? 0
171
+ );
172
+ this.registerMarkUniform(
173
+ "uCornerRadiusBottomLeft",
174
+ props.cornerRadiusBottomLeft ?? props.cornerRadius ?? 0
175
+ );
167
176
  }
168
177
 
169
178
  updateGraphicsData() {
@@ -190,6 +199,8 @@ export default class RectMark extends Mark {
190
199
  prepareRender(options) {
191
200
  const ops = super.prepareRender(options);
192
201
 
202
+ ops.push(() => this.bindOrSetMarkUniformBlock());
203
+
193
204
  ops.push(() =>
194
205
  setBuffersAndAttributes(
195
206
  this.gl,
@@ -1 +1 @@
1
- {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/marks/rule.js"],"names":[],"mappings":"AAYA;IAOQ,wBAAwB;IA4GpB,0BAOE;CAmFb;iBAzNgB,WAAW"}
1
+ {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/marks/rule.js"],"names":[],"mappings":"AAcA;IAOQ,wBAAwB;IA4GpB,0BAOE;CA4Fb;iBApOgB,WAAW"}
@@ -2,11 +2,13 @@ import Mark from "./mark.js";
2
2
  import {
3
3
  createTexture,
4
4
  drawBufferInfo,
5
+ setBlockUniforms,
5
6
  setBuffersAndAttributes,
6
7
  setUniforms,
7
8
  } from "twgl.js";
8
9
  import VERTEX_SHADER from "../gl/rule.vertex.glsl.js";
9
10
  import FRAGMENT_SHADER from "../gl/rule.fragment.glsl.js";
11
+ import COMMON_SHADER from "../gl/rule.common.glsl.js";
10
12
  import { RuleVertexBuilder } from "../gl/dataToVertices.js";
11
13
  import { isChannelDefWithScale } from "../encoder/encoder.js";
12
14
 
@@ -136,7 +138,9 @@ export default class RuleMark extends Mark {
136
138
  this.dashTextureSize = textureData.length; // Not needed with WebGL2
137
139
  }
138
140
 
139
- this.createAndLinkShaders(VERTEX_SHADER, FRAGMENT_SHADER);
141
+ this.createAndLinkShaders(VERTEX_SHADER, FRAGMENT_SHADER, [
142
+ COMMON_SHADER,
143
+ ]);
140
144
  }
141
145
 
142
146
  finalizeGraphicsInitialization() {
@@ -146,11 +150,17 @@ export default class RuleMark extends Mark {
146
150
 
147
151
  const props = this.properties;
148
152
 
149
- setUniforms(this.programInfo, {
150
- uMinLength: props.minLength,
151
- uDashTextureSize: this.dashTextureSize,
152
- uStrokeCap: ["butt", "square", "round"].indexOf(props.strokeCap),
153
+ this.registerMarkUniform("uMinLength", props.minLength);
154
+ this.registerMarkUniform(
155
+ "uStrokeCap",
156
+ props.strokeCap ?? "butt",
157
+ (cap) => ["butt", "square", "round"].indexOf(cap)
158
+ );
159
+
160
+ setBlockUniforms(this.markUniformInfo, {
161
+ uDashTextureSize: +this.dashTextureSize,
153
162
  });
163
+ this.markUniformsAltered = true;
154
164
  }
155
165
 
156
166
  updateGraphicsData() {
@@ -177,11 +187,12 @@ export default class RuleMark extends Mark {
177
187
  prepareRender(options) {
178
188
  const ops = super.prepareRender(options);
179
189
 
190
+ ops.push(() => this.bindOrSetMarkUniformBlock());
191
+
180
192
  if (this.dashTexture) {
181
193
  ops.push(() =>
182
194
  setUniforms(this.programInfo, {
183
195
  uDashTexture: this.dashTexture,
184
- uStrokeDashOffset: this.properties.strokeDashOffset,
185
196
  })
186
197
  );
187
198
  }
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AA0BA;;;;;;;GAOG;AACH;IAsDQ,oDAMmD;CAwL1D;iBA/QgB,WAAW"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAsDQ,oDAMmD;CAgM1D;iBAvRgB,WAAW"}