@genome-spy/core 0.68.0 → 0.69.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 (163) hide show
  1. package/dist/bundle/index.es.js +12108 -10682
  2. package/dist/bundle/index.js +119 -119
  3. package/dist/schema.json +6224 -6319
  4. package/dist/src/data/dataFlow.d.ts.map +1 -1
  5. package/dist/src/data/dataFlow.js +10 -0
  6. package/dist/src/data/flowNode.d.ts +25 -10
  7. package/dist/src/data/flowNode.d.ts.map +1 -1
  8. package/dist/src/data/flowNode.js +66 -13
  9. package/dist/src/data/flowTestUtils.d.ts +2 -2
  10. package/dist/src/data/flowTestUtils.d.ts.map +1 -1
  11. package/dist/src/data/flowTestUtils.js +5 -4
  12. package/dist/src/data/sources/dataSource.js +2 -2
  13. package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
  14. package/dist/src/data/sources/lazy/bigBedSource.js +11 -10
  15. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  16. package/dist/src/data/sources/lazy/bigWigSource.js +11 -10
  17. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +1 -1
  18. package/dist/src/data/sources/lazy/tabixSource.d.ts +0 -1
  19. package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
  20. package/dist/src/data/sources/lazy/tabixSource.js +41 -11
  21. package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
  22. package/dist/src/data/sources/sequenceSource.js +5 -3
  23. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  24. package/dist/src/data/sources/urlSource.js +7 -3
  25. package/dist/src/data/transforms/filter.d.ts +4 -4
  26. package/dist/src/data/transforms/filter.d.ts.map +1 -1
  27. package/dist/src/data/transforms/filter.js +13 -7
  28. package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
  29. package/dist/src/data/transforms/filterScoredLabels.js +11 -6
  30. package/dist/src/data/transforms/filterScoredLabels.test.d.ts +2 -0
  31. package/dist/src/data/transforms/filterScoredLabels.test.d.ts.map +1 -0
  32. package/dist/src/data/transforms/formula.d.ts +4 -4
  33. package/dist/src/data/transforms/formula.d.ts.map +1 -1
  34. package/dist/src/data/transforms/formula.js +12 -6
  35. package/dist/src/data/transforms/measureText.d.ts +2 -2
  36. package/dist/src/data/transforms/measureText.d.ts.map +1 -1
  37. package/dist/src/data/transforms/measureText.js +16 -12
  38. package/dist/src/data/transforms/transform.d.ts +2 -2
  39. package/dist/src/data/transforms/transform.d.ts.map +1 -1
  40. package/dist/src/data/transforms/transform.js +3 -3
  41. package/dist/src/encoder/accessor.d.ts +8 -4
  42. package/dist/src/encoder/accessor.d.ts.map +1 -1
  43. package/dist/src/encoder/accessor.js +10 -10
  44. package/dist/src/encoder/encoder.js +5 -5
  45. package/dist/src/genome/genome.d.ts +8 -0
  46. package/dist/src/genome/genome.d.ts.map +1 -1
  47. package/dist/src/genome/genome.js +16 -1
  48. package/dist/src/genomeSpy/inputBindingManager.js +1 -1
  49. package/dist/src/genomeSpy/interactionController.d.ts.map +1 -1
  50. package/dist/src/genomeSpy/interactionController.js +7 -1
  51. package/dist/src/genomeSpy.js +1 -1
  52. package/dist/src/gl/glslScaleGenerator.js +1 -1
  53. package/dist/src/marks/mark.d.ts.map +1 -1
  54. package/dist/src/marks/mark.js +22 -30
  55. package/dist/src/marks/point.d.ts.map +1 -1
  56. package/dist/src/marks/point.js +4 -6
  57. package/dist/src/paramRuntime/expressionCompiler.d.ts +7 -0
  58. package/dist/src/paramRuntime/expressionCompiler.d.ts.map +1 -0
  59. package/dist/src/paramRuntime/expressionCompiler.js +10 -0
  60. package/dist/src/paramRuntime/expressionRef.d.ts +20 -0
  61. package/dist/src/paramRuntime/expressionRef.d.ts.map +1 -0
  62. package/dist/src/paramRuntime/expressionRef.js +95 -0
  63. package/dist/src/paramRuntime/expressionRef.test.d.ts +2 -0
  64. package/dist/src/paramRuntime/expressionRef.test.d.ts.map +1 -0
  65. package/dist/src/paramRuntime/graphRuntime.d.ts +176 -0
  66. package/dist/src/paramRuntime/graphRuntime.d.ts.map +1 -0
  67. package/dist/src/paramRuntime/graphRuntime.js +628 -0
  68. package/dist/src/paramRuntime/graphRuntime.test.d.ts +2 -0
  69. package/dist/src/paramRuntime/graphRuntime.test.d.ts.map +1 -0
  70. package/dist/src/paramRuntime/index.d.ts +9 -0
  71. package/dist/src/paramRuntime/index.d.ts.map +1 -0
  72. package/dist/src/paramRuntime/index.js +8 -0
  73. package/dist/src/paramRuntime/lifecycleRegistry.d.ts +27 -0
  74. package/dist/src/paramRuntime/lifecycleRegistry.d.ts.map +1 -0
  75. package/dist/src/paramRuntime/lifecycleRegistry.js +54 -0
  76. package/dist/src/paramRuntime/paramRuntime.d.ts +165 -0
  77. package/dist/src/paramRuntime/paramRuntime.d.ts.map +1 -0
  78. package/dist/src/paramRuntime/paramRuntime.js +222 -0
  79. package/dist/src/paramRuntime/paramRuntime.test.d.ts +2 -0
  80. package/dist/src/paramRuntime/paramRuntime.test.d.ts.map +1 -0
  81. package/dist/src/paramRuntime/paramStore.d.ts +68 -0
  82. package/dist/src/paramRuntime/paramStore.d.ts.map +1 -0
  83. package/dist/src/paramRuntime/paramStore.js +148 -0
  84. package/dist/src/paramRuntime/paramStore.test.d.ts +2 -0
  85. package/dist/src/paramRuntime/paramStore.test.d.ts.map +1 -0
  86. package/dist/src/paramRuntime/paramUtils.d.ts +86 -0
  87. package/dist/src/paramRuntime/paramUtils.d.ts.map +1 -0
  88. package/dist/src/paramRuntime/paramUtils.js +272 -0
  89. package/dist/src/paramRuntime/selectionStore.d.ts +6 -0
  90. package/dist/src/paramRuntime/selectionStore.d.ts.map +1 -0
  91. package/dist/src/paramRuntime/selectionStore.js +13 -0
  92. package/dist/src/paramRuntime/types.d.ts +16 -0
  93. package/dist/src/paramRuntime/types.d.ts.map +1 -0
  94. package/dist/src/paramRuntime/types.js +25 -0
  95. package/dist/src/paramRuntime/viewParamRuntime.d.ts +164 -0
  96. package/dist/src/paramRuntime/viewParamRuntime.d.ts.map +1 -0
  97. package/dist/src/paramRuntime/viewParamRuntime.js +443 -0
  98. package/dist/src/scales/scaleInstanceManager.d.ts +6 -3
  99. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
  100. package/dist/src/scales/scaleInstanceManager.js +17 -11
  101. package/dist/src/scales/scaleResolution.d.ts +1 -0
  102. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  103. package/dist/src/scales/scaleResolution.js +7 -1
  104. package/dist/src/selection/selection.js +1 -1
  105. package/dist/src/spec/coreSchemaRoot.d.ts +53 -0
  106. package/dist/src/spec/root.d.ts +1 -1
  107. package/dist/src/spec/view.d.ts +114 -33
  108. package/dist/src/tooltip/dataTooltipHandler.d.ts +1 -1
  109. package/dist/src/tooltip/dataTooltipHandler.js +23 -32
  110. package/dist/src/tooltip/dataTooltipHandler.test.d.ts +2 -0
  111. package/dist/src/tooltip/dataTooltipHandler.test.d.ts.map +1 -0
  112. package/dist/src/tooltip/flattenDatumRows.d.ts +13 -0
  113. package/dist/src/tooltip/flattenDatumRows.d.ts.map +1 -0
  114. package/dist/src/tooltip/flattenDatumRows.js +47 -0
  115. package/dist/src/tooltip/flattenDatumRows.test.d.ts +2 -0
  116. package/dist/src/tooltip/flattenDatumRows.test.d.ts.map +1 -0
  117. package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts +1 -1
  118. package/dist/src/tooltip/refseqGeneTooltipHandler.js +7 -1
  119. package/dist/src/tooltip/tooltipContext.d.ts +13 -0
  120. package/dist/src/tooltip/tooltipContext.d.ts.map +1 -0
  121. package/dist/src/tooltip/tooltipContext.js +543 -0
  122. package/dist/src/tooltip/tooltipContext.test.d.ts +2 -0
  123. package/dist/src/tooltip/tooltipContext.test.d.ts.map +1 -0
  124. package/dist/src/tooltip/tooltipHandler.d.ts +40 -1
  125. package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
  126. package/dist/src/tooltip/tooltipHandler.ts +62 -1
  127. package/dist/src/types/encoder.d.ts +1 -1
  128. package/dist/src/utils/inputBinding.d.ts +10 -2
  129. package/dist/src/utils/inputBinding.d.ts.map +1 -1
  130. package/dist/src/utils/inputBinding.js +12 -3
  131. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  132. package/dist/src/view/flowBuilder.js +12 -3
  133. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  134. package/dist/src/view/gridView/gridChild.js +8 -3
  135. package/dist/src/view/gridView/selectionRect.d.ts +6 -10
  136. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  137. package/dist/src/view/gridView/selectionRect.js +3 -20
  138. package/dist/src/view/layerView.d.ts.map +1 -1
  139. package/dist/src/view/layerView.js +4 -2
  140. package/dist/src/view/multiscale.d.ts +35 -0
  141. package/dist/src/view/multiscale.d.ts.map +1 -0
  142. package/dist/src/view/multiscale.js +233 -0
  143. package/dist/src/view/multiscale.test.d.ts +2 -0
  144. package/dist/src/view/multiscale.test.d.ts.map +1 -0
  145. package/dist/src/view/unitView.d.ts.map +1 -1
  146. package/dist/src/view/unitView.js +10 -4
  147. package/dist/src/view/view.d.ts +5 -4
  148. package/dist/src/view/view.d.ts.map +1 -1
  149. package/dist/src/view/view.js +205 -28
  150. package/dist/src/view/viewFactory.d.ts +0 -12
  151. package/dist/src/view/viewFactory.d.ts.map +1 -1
  152. package/dist/src/view/viewFactory.js +35 -24
  153. package/dist/src/view/viewParamRuntime.test.d.ts +2 -0
  154. package/dist/src/view/viewParamRuntime.test.d.ts.map +1 -0
  155. package/dist/src/view/viewSelectors.d.ts.map +1 -1
  156. package/dist/src/view/viewSelectors.js +8 -5
  157. package/package.json +3 -3
  158. package/dist/src/spec/sampleView.d.ts +0 -197
  159. package/dist/src/view/paramMediator.d.ts +0 -168
  160. package/dist/src/view/paramMediator.d.ts.map +0 -1
  161. package/dist/src/view/paramMediator.js +0 -545
  162. package/dist/src/view/paramMediator.test.d.ts +0 -2
  163. package/dist/src/view/paramMediator.test.d.ts.map +0 -1
@@ -0,0 +1,443 @@
1
+ import { isString } from "vega-util";
2
+ import ParamRuntime from "./paramRuntime.js";
3
+ import {
4
+ getDefaultParamValue,
5
+ isSelectionParameter,
6
+ validateParameterName,
7
+ } from "./paramUtils.js";
8
+
9
+ export {
10
+ activateExprRefProps,
11
+ getDefaultParamValue,
12
+ isExprRef,
13
+ isSelectionParameter,
14
+ isVariableParameter,
15
+ makeConstantExprRef,
16
+ validateParameterName,
17
+ withoutExprRef,
18
+ } from "./paramUtils.js";
19
+
20
+ /**
21
+ * A class that manages parameters and expressions.
22
+ * Supports nesting and scoped parameters through a shared runtime graph.
23
+ * The architecture follows signal-graph ideas (explicit dependencies, batched
24
+ * propagation, deterministic scheduling) while keeping GenomeSpy-specific
25
+ * parameter and expression semantics.
26
+ *
27
+ * @typedef {import("../utils/expression.js").ExpressionFunction & { subscribe: (listener: () => void) => () => void, invalidate: () => void, identifier: () => string}} ExprRefFunction
28
+ */
29
+ export default class ViewParamRuntime {
30
+ /**
31
+ * @typedef {import("../spec/parameter.js").Parameter} Parameter
32
+ * @typedef {(value: any) => void} ParameterSetter
33
+ *
34
+ * @typedef {object} WatchExpressionOptions
35
+ * @prop {boolean} [scopeOwned=true]
36
+ * Whether the subscription lifecycle is owned by this runtime scope.
37
+ * When true, the listener is unsubscribed automatically during
38
+ * `dispose()` via scope disposal. Set to false when another owner
39
+ * (for example a `View` disposer registry) controls teardown.
40
+ * @prop {(disposer: () => void) => void} [registerDisposer]
41
+ * Optional external disposer registration hook. When provided, the
42
+ * unsubscribe callback is passed to this hook in addition to any
43
+ * scope-owned registration.
44
+ */
45
+
46
+ /** @type {ParamRuntime} */
47
+ #runtime;
48
+
49
+ /** @type {string} */
50
+ #scopeId;
51
+
52
+ /** @type {Map<string, (value: any) => void>} */
53
+ #allocatedSetters = new Map();
54
+
55
+ /** @type {Map<string, import("./types.js").ParamRef<any>>} */
56
+ #localRefs = new Map();
57
+
58
+ /** @type {Map<string, Parameter>} */
59
+ #paramConfigs = new Map();
60
+
61
+ /** @type {() => ViewParamRuntime} */
62
+ #parentFinder;
63
+
64
+ #disposed = false;
65
+
66
+ /**
67
+ * @param {() => ViewParamRuntime} [parentFinder]
68
+ * An optional function that returns the parent runtime.
69
+ * N.B. The function must always return the same runtime for the same parent,
70
+ * i.e., the changing the structure of the hierarchy is NOT supported.
71
+ */
72
+ constructor(parentFinder) {
73
+ this.#parentFinder = parentFinder ?? (() => undefined);
74
+
75
+ const parent = this.#parentFinder();
76
+ if (parent) {
77
+ this.#runtime = parent.#runtime;
78
+ this.#scopeId = this.#runtime.createScope(parent.#scopeId);
79
+ } else {
80
+ this.#runtime = new ParamRuntime();
81
+ this.#scopeId = this.#runtime.createScope();
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Registers a parameter definition into this runtime scope.
87
+ *
88
+ * Returns a writable setter for writable parameters (`value`, `select`,
89
+ * `push: "outer"`). For derived (`expr`) parameters, the returned setter
90
+ * throws.
91
+ *
92
+ * A parameter name can be registered only once per runtime scope.
93
+ *
94
+ * @param {Parameter} param
95
+ * @returns {ParameterSetter}
96
+ */
97
+ registerParam(param) {
98
+ const name = param.name;
99
+ validateParameterName(name);
100
+
101
+ if (this.#paramConfigs.has(name)) {
102
+ throw new Error(
103
+ 'Parameter "' + name + '" already registered in this scope.'
104
+ );
105
+ }
106
+
107
+ if ("value" in param && "expr" in param) {
108
+ throw new Error(
109
+ `The parameter "${name}" must not have both value and expr properties!`
110
+ );
111
+ }
112
+
113
+ /** @type {ParameterSetter} */
114
+ let setter;
115
+ let defaultValue;
116
+
117
+ if (param.push == "outer") {
118
+ const outerRuntime = this.findRuntimeForParam(name);
119
+ if (!outerRuntime) {
120
+ throw new Error(
121
+ `Parameter "${name}" not found in outer scope!`
122
+ );
123
+ }
124
+
125
+ const outerProps = outerRuntime.paramConfigs.get(name);
126
+ if (!outerProps) {
127
+ throw new Error(
128
+ `Outer parameter "${name}" exists as a value but has no registered config.`
129
+ );
130
+ }
131
+ if ("expr" in outerProps || "select" in outerProps) {
132
+ throw new Error(
133
+ `The outer parameter "${name}" must not have expr or select properties!`
134
+ );
135
+ }
136
+ setter = (
137
+ /** @type {any} */
138
+ value
139
+ ) => {
140
+ outerRuntime.setValue(name, value);
141
+ };
142
+ // The following will become a bit fragile if the view hierarchy is going to
143
+ // support mutation (i.e. adding/removing children) in future.
144
+ this.#allocatedSetters.set(name, setter);
145
+ } else if ("value" in param) {
146
+ defaultValue = getDefaultParamValue(param, this);
147
+ setter = this.#registerBaseSetter(name, defaultValue);
148
+ } else if ("expr" in param) {
149
+ const ref = this.#runtime.registerDerived(
150
+ this.#scopeId,
151
+ name,
152
+ param.expr
153
+ );
154
+ this.#localRefs.set(name, ref);
155
+ setter = () => {
156
+ throw new Error('Cannot set derived parameter "' + name + '".');
157
+ };
158
+ } else {
159
+ defaultValue = getDefaultParamValue(param, this);
160
+ setter = this.#registerBaseSetter(name, defaultValue);
161
+ }
162
+
163
+ if ("select" in param) {
164
+ defaultValue ??= getDefaultParamValue(param, this);
165
+ if (!this.#allocatedSetters.has(name)) {
166
+ const ref = this.#runtime.registerSelection(
167
+ this.#scopeId,
168
+ name,
169
+ defaultValue
170
+ );
171
+ this.#localRefs.set(name, ref);
172
+ this.#allocatedSetters.set(name, (value) => {
173
+ ref.set(value);
174
+ this.#runtime.flushNow();
175
+ });
176
+ setter = this.#allocatedSetters.get(name);
177
+ }
178
+ // Set initial value so that production rules in shaders can be generated, etc.
179
+ setter(defaultValue);
180
+ }
181
+
182
+ this.#paramConfigs.set(name, param);
183
+
184
+ return setter;
185
+ }
186
+
187
+ /**
188
+ *
189
+ * @param {string} paramName
190
+ * @param {T} initialValue
191
+ * @param {boolean} [passive] If true, the setter will not notify listeners when the value changes.
192
+ * @returns {(value: T) => void}
193
+ * @template T
194
+ */
195
+ allocateSetter(paramName, initialValue, passive = false) {
196
+ validateParameterName(paramName);
197
+
198
+ if (this.#allocatedSetters.has(paramName)) {
199
+ throw new Error(
200
+ "Setter already allocated for parameter: " + paramName
201
+ );
202
+ }
203
+
204
+ const ref = this.#runtime.registerBase(
205
+ this.#scopeId,
206
+ paramName,
207
+ initialValue,
208
+ {
209
+ notify: !passive,
210
+ }
211
+ );
212
+ this.#localRefs.set(paramName, ref);
213
+ const setter = (
214
+ /** @type {T} */
215
+ value
216
+ ) => {
217
+ ref.set(value);
218
+ this.#runtime.flushNow();
219
+ };
220
+
221
+ this.#allocatedSetters.set(paramName, setter);
222
+
223
+ return setter;
224
+ }
225
+
226
+ /**
227
+ * Sets a writable parameter value in this runtime scope.
228
+ *
229
+ * Only parameters with locally registered writable setters are supported.
230
+ * This method does not resolve through ancestors.
231
+ *
232
+ * @param {string} paramName
233
+ * @param {any} value
234
+ */
235
+ setValue(paramName, value) {
236
+ validateParameterName(paramName);
237
+ const setter = this.#allocatedSetters.get(paramName);
238
+ if (!setter) {
239
+ throw new Error(
240
+ "Writable parameter not found in this scope: " + paramName
241
+ );
242
+ }
243
+ setter(value);
244
+ }
245
+
246
+ /**
247
+ * Get the value of a parameter from this runtime.
248
+ * @param {string} paramName
249
+ */
250
+ getValue(paramName) {
251
+ return this.#localRefs.get(paramName)?.get();
252
+ }
253
+
254
+ /**
255
+ * Subscribe to changes of a parameter's value. The listener is called only
256
+ * when the stored value changes. For expression parameters, the listener is
257
+ * called when upstream changes re-evaluate to a different value.
258
+ *
259
+ * @param {string} paramName
260
+ * @param {() => void} listener
261
+ * @returns {() => void}
262
+ */
263
+ subscribe(paramName, listener) {
264
+ validateParameterName(paramName);
265
+ const runtime = this.findRuntimeForParam(paramName);
266
+ if (!runtime) {
267
+ throw new Error("Parameter not found: " + paramName);
268
+ }
269
+
270
+ const ref = runtime.#localRefs.get(paramName);
271
+ if (!ref) {
272
+ throw new Error(
273
+ "Parameter found without local reference: " + paramName
274
+ );
275
+ }
276
+
277
+ return ref.subscribe(listener);
278
+ }
279
+
280
+ /**
281
+ * Get the value of a parameter from this runtime or its ancestors.
282
+ * @param {string} paramName
283
+ */
284
+ findValue(paramName) {
285
+ const runtime = this.findRuntimeForParam(paramName);
286
+ return runtime?.getValue(paramName);
287
+ }
288
+
289
+ /**
290
+ * Returns configs for all parameters that have been registered using `registerParam`.
291
+ */
292
+ get paramConfigs() {
293
+ return /** @type {ReadonlyMap<string, Parameter>} */ (
294
+ this.#paramConfigs
295
+ );
296
+ }
297
+
298
+ /**
299
+ *
300
+ * @param {string} paramName
301
+ * @returns {ViewParamRuntime}
302
+ */
303
+ findRuntimeForParam(paramName) {
304
+ if (this.#localRefs.has(paramName)) {
305
+ return this;
306
+ } else {
307
+ return this.#parentFinder()?.findRuntimeForParam(paramName);
308
+ }
309
+ }
310
+
311
+ // Setter lifecycle is scope-owned: setters are dropped when the runtime scope
312
+ // is disposed. A standalone deallocation API is intentionally not exposed.
313
+
314
+ /**
315
+ * Parse expr and return a function that returns the value of the parameter.
316
+ *
317
+ * @param {string} expr
318
+ */
319
+ createExpression(expr) {
320
+ return this.#runtime.createExpression(this.#scopeId, expr);
321
+ }
322
+
323
+ /**
324
+ * Creates an expression and subscribes a listener that is automatically
325
+ * removed according to `options` lifecycle ownership.
326
+ *
327
+ * Lifecycle semantics:
328
+ * 1. `scopeOwned: true` (default): unsubscribe is bound to runtime scope
329
+ * disposal (`ViewParamRuntime.dispose()`).
330
+ * 2. `scopeOwned: false`: caller must own teardown, typically via
331
+ * `registerDisposer` or by storing and calling the returned unsubscribe.
332
+ * 3. `registerDisposer` can be used regardless of `scopeOwned` to bind the
333
+ * same unsubscribe to another lifecycle owner.
334
+ *
335
+ * @param {string} expr
336
+ * @param {() => void} listener
337
+ * @param {WatchExpressionOptions} [options]
338
+ * @returns {ExprRefFunction}
339
+ */
340
+ watchExpression(expr, listener, options = {}) {
341
+ const fn = this.createExpression(expr);
342
+ const dispose = fn.subscribe(listener);
343
+
344
+ if (options.scopeOwned ?? true) {
345
+ this.#runtime.addScopeDisposer(this.#scopeId, dispose);
346
+ }
347
+ options.registerDisposer?.(dispose);
348
+
349
+ return fn;
350
+ }
351
+
352
+ /**
353
+ * @template T
354
+ * @param {string} name
355
+ * @param {T} defaultValue
356
+ * @returns {(value: T) => void}
357
+ */
358
+ #registerBaseSetter(name, defaultValue) {
359
+ const ref = this.#runtime.registerBase(
360
+ this.#scopeId,
361
+ name,
362
+ defaultValue
363
+ );
364
+ this.#localRefs.set(name, ref);
365
+ const setter = (
366
+ /** @type {T} */
367
+ value
368
+ ) => {
369
+ ref.set(value);
370
+ this.#runtime.flushNow();
371
+ };
372
+ this.#allocatedSetters.set(name, setter);
373
+ return setter;
374
+ }
375
+
376
+ /**
377
+ * A convenience method for evaluating an expression.
378
+ *
379
+ * @param {string} expr
380
+ */
381
+ evaluateAndGet(expr) {
382
+ const fn = this.createExpression(expr);
383
+ return fn();
384
+ }
385
+
386
+ /**
387
+ * @template T
388
+ * @param {() => T} fn
389
+ * @returns {T}
390
+ */
391
+ runInTransaction(fn) {
392
+ return this.#runtime.runInTransaction(fn);
393
+ }
394
+
395
+ flushNow() {
396
+ this.#runtime.flushNow();
397
+ }
398
+
399
+ /**
400
+ * Sync barrier only: resolves when DAG propagation/effects have flushed.
401
+ * Must not be broadened to temporal/animation convergence semantics.
402
+ *
403
+ * @param {{ signal?: AbortSignal, timeoutMs?: number }} [options]
404
+ */
405
+ whenPropagated(options) {
406
+ return this.#runtime.whenPropagated(options);
407
+ }
408
+
409
+ dispose() {
410
+ if (this.#disposed) {
411
+ return;
412
+ }
413
+
414
+ this.#disposed = true;
415
+ this.#runtime.disposeScope(this.#scopeId);
416
+ this.#allocatedSetters.clear();
417
+ this.#localRefs.clear();
418
+ this.#paramConfigs.clear();
419
+ }
420
+
421
+ /**
422
+ * Returns true if this runtime has any parameters that are point selections.
423
+ * Point selections necessitate the use of uniqueIds in the data.
424
+ *
425
+ * @returns {boolean}
426
+ */
427
+ hasPointSelections() {
428
+ for (const param of this.#paramConfigs.values()) {
429
+ if (isSelectionParameter(param)) {
430
+ const select = param.select;
431
+ if (isString(select)) {
432
+ if (select == "point") {
433
+ return true;
434
+ }
435
+ } else if (select.type == "point") {
436
+ return true;
437
+ }
438
+ }
439
+ }
440
+
441
+ return false;
442
+ }
443
+ }
@@ -1,13 +1,15 @@
1
1
  export default class ScaleInstanceManager {
2
2
  /**
3
3
  * @param {object} options
4
- * @param {() => import("../view/paramMediator.js").default} options.getParamMediator
4
+ * @param {() => { createExpression: (expr: string) => import("../paramRuntime/types.js").ExprRefFunction }} options.getParamRuntime
5
5
  * @param {() => void} options.onRangeChange
6
6
  * @param {() => void} [options.onDomainChange]
7
7
  * @param {() => import("../genome/genomeStore.js").default | undefined} [options.getGenomeStore]
8
8
  */
9
- constructor({ getParamMediator, onRangeChange, onDomainChange, getGenomeStore, }: {
10
- getParamMediator: () => import("../view/paramMediator.js").default;
9
+ constructor({ getParamRuntime, onRangeChange, onDomainChange, getGenomeStore, }: {
10
+ getParamRuntime: () => {
11
+ createExpression: (expr: string) => import("../paramRuntime/types.js").ExprRefFunction;
12
+ };
11
13
  onRangeChange: () => void;
12
14
  onDomainChange?: () => void;
13
15
  getGenomeStore?: () => import("../genome/genomeStore.js").default | undefined;
@@ -35,6 +37,7 @@ export default class ScaleInstanceManager {
35
37
  * @returns {void}
36
38
  */
37
39
  withDomainNotificationsSuppressed(callback: () => void): void;
40
+ dispose(): void;
38
41
  #private;
39
42
  }
40
43
  //# sourceMappingURL=scaleInstanceManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scaleInstanceManager.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInstanceManager.js"],"names":[],"mappings":"AAMA;IA0BI;;;;;;OAMG;IACH,kFALG;QAAkE,gBAAgB,EAA1E,MAAM,OAAO,0BAA0B,EAAE,OAAO;QAC5B,aAAa,EAAjC,MAAM,IAAI;QACW,cAAc,GAAnC,MAAM,IAAI;QAC6D,cAAc,GAArF,MAAM,OAAO,0BAA0B,EAAE,OAAO,GAAG,SAAS;KAA0B,EAYhG;IAED;eA1CkC,OAAO,kBAAkB,EAAE,KAAK;MA4CjE;IAED;;OAEG;IACH,kBAFa,OAAO,qBAAqB,EAAE,OAAO,CASjD;IAED;;;OAGG;IACH,mBAHW,OAAO,kBAAkB,EAAE,KAAK;eA3DT,OAAO,kBAAkB,EAAE,KAAK;MAgFjE;IAoBD;;OAEG;IACH,wBAFW,OAAO,kBAAkB,EAAE,KAAK,QAc1C;IAED;;;OAGG;IACH,4CAHW,MAAM,IAAI,GACR,IAAI,CAShB;;CAiFJ"}
1
+ {"version":3,"file":"scaleInstanceManager.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInstanceManager.js"],"names":[],"mappings":"AAMA;IA0BI;;;;;;OAMG;IACH,iFALG;QAAkH,eAAe,EAAzH,MAAM;YAAE,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,0BAA0B,EAAE,eAAe,CAAA;SAAE;QAC5E,aAAa,EAAjC,MAAM,IAAI;QACW,cAAc,GAAnC,MAAM,IAAI;QAC6D,cAAc,GAArF,MAAM,OAAO,0BAA0B,EAAE,OAAO,GAAG,SAAS;KAA0B,EAYhG;IAED;eA1CkC,OAAO,kBAAkB,EAAE,KAAK;MA4CjE;IAED;;OAEG;IACH,kBAFa,OAAO,qBAAqB,EAAE,OAAO,CASjD;IAED;;;OAGG;IACH,mBAHW,OAAO,kBAAkB,EAAE,KAAK;eA3DT,OAAO,kBAAkB,EAAE,KAAK;MAgFjE;IAoBD;;OAEG;IACH,wBAFW,OAAO,kBAAkB,EAAE,KAAK,QAc1C;IAED;;;OAGG;IACH,4CAHW,MAAM,IAAI,GACR,IAAI,CAShB;IAmFD,gBAGC;;CACJ"}
@@ -1,7 +1,7 @@
1
1
  import { isArray } from "vega-util";
2
2
 
3
3
  import createScale, { configureScale } from "../scale/scale.js";
4
- import { isExprRef } from "../view/paramMediator.js";
4
+ import { isExprRef } from "../paramRuntime/paramUtils.js";
5
5
  import { isScaleLocus } from "../genome/scaleLocus.js";
6
6
 
7
7
  export default class ScaleInstanceManager {
@@ -13,11 +13,11 @@ export default class ScaleInstanceManager {
13
13
  /** @type {ScaleWithProps | undefined} */
14
14
  #scale;
15
15
 
16
- /** @type {Set<import("../view/paramMediator.js").ExprRefFunction>} */
16
+ /** @type {Set<import("../paramRuntime/types.js").ExprRefFunction>} */
17
17
  #rangeExprRefListeners = new Set();
18
18
 
19
- /** @type {() => import("../view/paramMediator.js").default} */
20
- #getParamMediator;
19
+ /** @type {() => { createExpression: (expr: string) => import("../paramRuntime/types.js").ExprRefFunction }} */
20
+ #getParamRuntime;
21
21
 
22
22
  /** @type {() => void} */
23
23
  #onRangeChange;
@@ -32,18 +32,18 @@ export default class ScaleInstanceManager {
32
32
 
33
33
  /**
34
34
  * @param {object} options
35
- * @param {() => import("../view/paramMediator.js").default} options.getParamMediator
35
+ * @param {() => { createExpression: (expr: string) => import("../paramRuntime/types.js").ExprRefFunction }} options.getParamRuntime
36
36
  * @param {() => void} options.onRangeChange
37
37
  * @param {() => void} [options.onDomainChange]
38
38
  * @param {() => import("../genome/genomeStore.js").default | undefined} [options.getGenomeStore]
39
39
  */
40
40
  constructor({
41
- getParamMediator,
41
+ getParamRuntime,
42
42
  onRangeChange,
43
43
  onDomainChange,
44
44
  getGenomeStore,
45
45
  }) {
46
- this.#getParamMediator = getParamMediator;
46
+ this.#getParamRuntime = getParamRuntime;
47
47
  this.#onRangeChange = onRangeChange;
48
48
  this.#onDomainChange = onDomainChange;
49
49
  this.#getGenomeStore = getGenomeStore;
@@ -167,12 +167,13 @@ export default class ScaleInstanceManager {
167
167
 
168
168
  const props = scale.props;
169
169
  this.#rangeExprRefListeners.forEach((fn) => fn.invalidate());
170
+ this.#rangeExprRefListeners.clear();
170
171
 
171
172
  const resolved = resolveRange({
172
173
  range: props.range,
173
174
  reverse: props.reverse,
174
175
  createExpression: (expr) =>
175
- this.#getParamMediator().createExpression(expr),
176
+ this.#getParamRuntime().createExpression(expr),
176
177
  registerExpr: (fn) => this.#rangeExprRefListeners.add(fn),
177
178
  });
178
179
 
@@ -216,6 +217,11 @@ export default class ScaleInstanceManager {
216
217
 
217
218
  notifyRange();
218
219
  }
220
+
221
+ dispose() {
222
+ this.#rangeExprRefListeners.forEach((fn) => fn.invalidate());
223
+ this.#rangeExprRefListeners.clear();
224
+ }
219
225
  }
220
226
 
221
227
  /**
@@ -261,8 +267,8 @@ function withScaleInterceptors(
261
267
  * @param {object} options
262
268
  * @param {import("../spec/scale.js").Scale["range"]} options.range
263
269
  * @param {boolean | undefined} options.reverse
264
- * @param {(expr: string) => import("../view/paramMediator.js").ExprRefFunction} options.createExpression
265
- * @param {(fn: import("../view/paramMediator.js").ExprRefFunction) => void} options.registerExpr
270
+ * @param {(expr: string) => import("../paramRuntime/types.js").ExprRefFunction} options.createExpression
271
+ * @param {(fn: import("../paramRuntime/types.js").ExprRefFunction) => void} options.registerExpr
266
272
  * @returns {{
267
273
  * dynamic: true,
268
274
  * evaluate: () => any[],
@@ -299,7 +305,7 @@ function resolveRange({ range, reverse, createExpression, registerExpr }) {
299
305
  expressions = range.map((elem) => {
300
306
  if (isExprRef(elem)) {
301
307
  const fn = createExpression(elem.expr);
302
- fn.addListener(listener);
308
+ fn.subscribe(listener);
303
309
  registerExpr(fn);
304
310
  return () => fn(null);
305
311
  }
@@ -56,6 +56,7 @@ export default class ScaleResolution implements ScaleResolutionApi {
56
56
  * @returns {() => boolean}
57
57
  */
58
58
  registerMember(member: ScaleResolutionMember): () => boolean;
59
+ dispose(): void;
59
60
  /**
60
61
  * @param {import("../data/collector.js").default} collector
61
62
  * @param {Iterable<import("../types/encoder.js").ScaleAccessor>} accessors
@@ -1 +1 @@
1
- {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleResolution.js"],"names":[],"mappings":"AAuCA;;;;;;;;GAQG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH;IA8CI;;OAEG;IACH,2DAkCC;IAjCG,8CAAsB;IACtB,0FAA0F;IAC1F,MADW,OAAO,oBAAoB,EAAE,IAAI,CAC5B;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IAoEzB,2BASC;IAqBD;;;;;;;OAOG;IACH,4KAEC;IAED;;;OAGG;IACH,+KAEC;IA6ED;;;OAGG;IACH,uBAHW,qBAAqB,GACnB,MAAM,OAAO,CAYzB;IAWD;;;;OAIG;IACH,0CAJW,OAAO,sBAAsB,EAAE,OAAO,aACtC,QAAQ,CAAC,OAAO,qBAAqB,EAAE,aAAa,CAAC,GACnD,MAAM,IAAI,CAkCtB;IA4HD;;;;;OAKG;IACH,oBAUC;IAED;;;;;OAKG;IACH,0BAuBC;IAuGD;;OAEG;IACH;eA5jBkC,OAAO,kBAAkB,EAAE,KAAK;MAmkBjE;IAED;;;;;;OAMG;IACH;eA5kBkC,OAAO,kBAAkB,EAAE,KAAK;MA8kBjE;IAED;;;;OAIG;IACH;eArlBkC,OAAO,kBAAkB,EAAE,KAAK;MA8lBjE;IAED,mBAEC;IAED;;;;OAIG;IACH,+DAEC;IAED;;OAEG;IACH,oBAFa,mFAA6B,CAMzC;IAED;;;;OAIG;IACH,oBAEC;IAED;;OAEG;IACH,sBAGC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CAInB;IAED;;;;;;OAMG;IACH,eAJW,mFAA6B,aAC7B,OAAO,GAAG,MAAM,iBAK1B;IAED;;;;OAIG;IACH,qBAEC;IAED;;;;;OAKG;IACH,uBAEC;IAED;;;;;;;OAOG;IACH,wBAoBC;IAED;;;;;OAKG;IACH,uBAFW,MAAM,yDAUhB;IAED;;OAEG;IACH,iBAFW,MAAM,yDAIhB;IAED;;;OAGG;IACH,qBAHW,MAAM,+CAAmB,GACvB,MAAM,CAIlB;IAED;;;OAGG;IACH,8BAHW,kFAA4B,GAC1B,MAAM,EAAE,CAOpB;;CACJ;kCAlyB+B,CAAC,SAApB,6CAAkB;;;;UAGrB,OAAO,qBAAqB,EAAE,OAAO;aACrC,CAAC;gBACD,OAAO,oBAAoB,EAAE,mBAAmB;yBAChD,OAAO;;sBAvBV,+BAA+B;sBAA/B,+BAA+B;wBAA/B,+BAA+B;wBAA/B,+BAA+B;6BAA/B,+BAA+B"}
1
+ {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleResolution.js"],"names":[],"mappings":"AAuCA;;;;;;;;GAQG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH;IA8CI;;OAEG;IACH,2DAkCC;IAjCG,8CAAsB;IACtB,0FAA0F;IAC1F,MADW,OAAO,oBAAoB,EAAE,IAAI,CAC5B;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IAoEzB,2BASC;IAqBD;;;;;;;OAOG;IACH,4KAEC;IAED;;;OAGG;IACH,+KAEC;IA6ED;;;OAGG;IACH,uBAHW,qBAAqB,GACnB,MAAM,OAAO,CAYzB;IAED,gBAIC;IAWD;;;;OAIG;IACH,0CAJW,OAAO,sBAAsB,EAAE,OAAO,aACtC,QAAQ,CAAC,OAAO,qBAAqB,EAAE,aAAa,CAAC,GACnD,MAAM,IAAI,CAkCtB;IA4HD;;;;;OAKG;IACH,oBAUC;IAED;;;;;OAKG;IACH,0BAuBC;IAuGD;;OAEG;IACH;eAlkBkC,OAAO,kBAAkB,EAAE,KAAK;MAykBjE;IAED;;;;;;OAMG;IACH;eAllBkC,OAAO,kBAAkB,EAAE,KAAK;MAolBjE;IAED;;;;OAIG;IACH;eA3lBkC,OAAO,kBAAkB,EAAE,KAAK;MAomBjE;IAED,mBAEC;IAED;;;;OAIG;IACH,+DAEC;IAED;;OAEG;IACH,oBAFa,mFAA6B,CAMzC;IAED;;;;OAIG;IACH,oBAEC;IAED;;OAEG;IACH,sBAGC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CAInB;IAED;;;;;;OAMG;IACH,eAJW,mFAA6B,aAC7B,OAAO,GAAG,MAAM,iBAK1B;IAED;;;;OAIG;IACH,qBAEC;IAED;;;;;OAKG;IACH,uBAEC;IAED;;;;;;;OAOG;IACH,wBAoBC;IAED;;;;;OAKG;IACH,uBAFW,MAAM,yDAUhB;IAED;;OAEG;IACH,iBAFW,MAAM,yDAIhB;IAED;;;OAGG;IACH,qBAHW,MAAM,+CAAmB,GACvB,MAAM,CAIlB;IAED;;;OAGG;IACH,8BAHW,kFAA4B,GAC1B,MAAM,EAAE,CAOpB;;CACJ;kCAxyB+B,CAAC,SAApB,6CAAkB;;;;UAGrB,OAAO,qBAAqB,EAAE,OAAO;aACrC,CAAC;gBACD,OAAO,oBAAoB,EAAE,mBAAmB;yBAChD,OAAO;;sBAvBV,+BAA+B;sBAA/B,+BAA+B;wBAA/B,+BAA+B;wBAA/B,+BAA+B;6BAA/B,+BAA+B"}
@@ -132,7 +132,7 @@ export default class ScaleResolution {
132
132
  });
133
133
 
134
134
  this.#scaleManager = new ScaleInstanceManager({
135
- getParamMediator: () => this.#firstMemberView.paramMediator,
135
+ getParamRuntime: () => this.#firstMemberView.paramRuntime,
136
136
  onRangeChange: () => this.#notifyListeners("range"),
137
137
  onDomainChange: () => this.#notifyListeners("domain"),
138
138
  getGenomeStore: () => this.#viewContext.genomeStore,
@@ -329,6 +329,12 @@ export default class ScaleResolution {
329
329
  };
330
330
  }
331
331
 
332
+ dispose() {
333
+ this.#listeners.domain.clear();
334
+ this.#listeners.range.clear();
335
+ this.#scaleManager.dispose();
336
+ }
337
+
332
338
  #hasRenderedMember() {
333
339
  for (const member of this.#members) {
334
340
  if (member.view.hasRendered()) {
@@ -3,7 +3,7 @@ import {
3
3
  getSecondaryChannel,
4
4
  isPrimaryPositionalChannel,
5
5
  } from "../encoder/encoder.js";
6
- import { validateParameterName } from "../view/paramMediator.js";
6
+ import { validateParameterName } from "../paramRuntime/paramUtils.js";
7
7
  import { field } from "../utils/field.js";
8
8
 
9
9
  /**
@@ -0,0 +1,53 @@
1
+ import { RootConfig } from "./root.js";
2
+ import {
3
+ ConcatSpec as CoreConcatSpec,
4
+ HConcatSpec as CoreHConcatSpec,
5
+ ImportSpec,
6
+ LayerSpec as CoreLayerSpec,
7
+ MultiscaleSpec as CoreMultiscaleSpec,
8
+ UnitSpec as CoreUnitSpec,
9
+ VConcatSpec as CoreVConcatSpec,
10
+ } from "./view.js";
11
+
12
+ interface SchemaViewConfig {
13
+ templates?: Record<string, ViewSpec>;
14
+ }
15
+
16
+ interface UnitSpec extends Omit<CoreUnitSpec, "templates">, SchemaViewConfig {}
17
+
18
+ interface LayerSpec
19
+ extends Omit<CoreLayerSpec, "templates" | "layer">, SchemaViewConfig {
20
+ layer: (LayerSpec | UnitSpec | MultiscaleSpec | ImportSpec)[];
21
+ }
22
+
23
+ interface MultiscaleSpec
24
+ extends
25
+ Omit<CoreMultiscaleSpec, "templates" | "multiscale">,
26
+ SchemaViewConfig {
27
+ multiscale: (LayerSpec | UnitSpec | MultiscaleSpec | ImportSpec)[];
28
+ }
29
+
30
+ interface VConcatSpec
31
+ extends Omit<CoreVConcatSpec, "templates" | "vconcat">, SchemaViewConfig {
32
+ vconcat: (ViewSpec | ImportSpec)[];
33
+ }
34
+
35
+ interface HConcatSpec
36
+ extends Omit<CoreHConcatSpec, "templates" | "hconcat">, SchemaViewConfig {
37
+ hconcat: (ViewSpec | ImportSpec)[];
38
+ }
39
+
40
+ interface ConcatSpec
41
+ extends Omit<CoreConcatSpec, "templates" | "concat">, SchemaViewConfig {
42
+ concat: (ViewSpec | ImportSpec)[];
43
+ }
44
+
45
+ type ViewSpec =
46
+ | UnitSpec
47
+ | LayerSpec
48
+ | MultiscaleSpec
49
+ | VConcatSpec
50
+ | HConcatSpec
51
+ | ConcatSpec;
52
+
53
+ export type CoreRootSpec = ViewSpec & RootConfig;
@@ -1,7 +1,7 @@
1
1
  import { GenomeConfig } from "./genome.js";
2
2
  import { ViewSpec } from "./view.js";
3
3
 
4
- interface RootConfig {
4
+ export interface RootConfig {
5
5
  $schema?: string;
6
6
 
7
7
  genome?: GenomeConfig;