@genome-spy/core 0.44.0 → 0.45.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.
- package/dist/bundle/index.es.js +6123 -5482
- package/dist/bundle/index.js +211 -148
- package/dist/schema.json +329 -79
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +4 -2
- package/dist/src/data/flowOptimizer.test.js +12 -3
- package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
- package/dist/src/data/sources/dataUtils.js +3 -1
- package/dist/src/data/sources/lazy/bigBedSource.d.ts +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.js +52 -20
- package/dist/src/data/sources/lazy/bigWigSource.d.ts +0 -1
- package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigWigSource.js +30 -4
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.js +0 -2
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +6 -2
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +38 -20
- package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
- package/dist/src/data/sources/sequenceSource.js +14 -5
- package/dist/src/data/sources/sequenceSource.test.js +23 -5
- package/dist/src/data/sources/urlSource.d.ts.map +1 -1
- package/dist/src/data/sources/urlSource.js +15 -2
- package/dist/src/data/transforms/aggregate.d.ts.map +1 -1
- package/dist/src/data/transforms/aggregate.js +5 -2
- package/dist/src/encoder/encoder.d.ts +2 -4
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +8 -8
- package/dist/src/encoder/encoder.test.js +3 -0
- package/dist/src/genomeSpy.d.ts +7 -5
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +109 -132
- package/dist/src/gl/glslScaleGenerator.js +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/marks/mark.d.ts +8 -5
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +56 -12
- package/dist/src/marks/point.common.glsl.js +1 -1
- package/dist/src/marks/point.d.ts +1 -4
- package/dist/src/marks/point.d.ts.map +1 -1
- package/dist/src/marks/point.js +31 -23
- package/dist/src/marks/point.vertex.glsl.js +1 -1
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.js +15 -7
- package/dist/src/spec/data.d.ts +11 -10
- package/dist/src/spec/mark.d.ts +11 -21
- package/dist/src/spec/parameter.d.ts +11 -7
- package/dist/src/spec/root.d.ts +0 -8
- package/dist/src/spec/title.d.ts +5 -4
- package/dist/src/spec/view.d.ts +19 -4
- package/dist/src/styles/genome-spy.css.d.ts +1 -1
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
- package/dist/src/styles/genome-spy.css.js +52 -5
- package/dist/src/styles/genome-spy.scss +63 -10
- package/dist/src/styles/update.sh +6 -0
- package/dist/src/tooltip/dataTooltipHandler.js +1 -1
- package/dist/src/tooltip/refseqGeneTooltipHandler.js +1 -1
- package/dist/src/tooltip/tooltipHandler.d.ts +1 -1
- package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
- package/dist/src/tooltip/tooltipHandler.ts +1 -1
- package/dist/src/types/embedApi.d.ts +6 -0
- package/dist/src/types/viewContext.d.ts +2 -3
- package/dist/src/utils/debounce.d.ts +2 -2
- package/dist/src/utils/debounce.d.ts.map +1 -1
- package/dist/src/utils/debounce.js +5 -2
- package/dist/src/utils/expression.d.ts +2 -2
- package/dist/src/utils/expression.d.ts.map +1 -1
- package/dist/src/utils/expression.js +1 -1
- package/dist/src/utils/formatObject.d.ts +2 -2
- package/dist/src/utils/formatObject.d.ts.map +1 -1
- package/dist/src/utils/formatObject.js +2 -2
- package/dist/src/utils/inputBinding.d.ts +5 -0
- package/dist/src/utils/inputBinding.d.ts.map +1 -0
- package/dist/src/utils/inputBinding.js +115 -0
- package/dist/src/utils/ui/tooltip.js +1 -1
- package/dist/src/view/paramMediator.d.ts +108 -0
- package/dist/src/view/paramMediator.d.ts.map +1 -0
- package/dist/src/view/paramMediator.js +337 -0
- package/dist/src/view/paramMediator.test.js +211 -0
- package/dist/src/view/scaleResolution.d.ts.map +1 -1
- package/dist/src/view/scaleResolution.js +11 -6
- package/dist/src/view/view.d.ts +4 -1
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +19 -5
- package/dist/src/view/viewFactory.d.ts.map +1 -1
- package/dist/src/view/viewFactory.js +45 -0
- package/dist/src/view/viewUtils.d.ts +5 -1
- package/dist/src/view/viewUtils.d.ts.map +1 -1
- package/dist/src/view/viewUtils.js +9 -4
- package/package.json +16 -17
- package/dist/src/paramBroker.d.ts +0 -46
- package/dist/src/paramBroker.d.ts.map +0 -1
- package/dist/src/paramBroker.js +0 -118
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewFactory.d.ts","sourceRoot":"","sources":["../../../src/view/viewFactory.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"viewFactory.d.ts","sourceRoot":"","sources":["../../../src/view/viewFactory.js"],"names":[],"mappings":"AAoPA;;;;GAIG;AACH,iHAEC;AAED;;;;GAIG;AACH,mHAEC;AAED;;;;GAIG;AACH,mHAOC;AAED;;;;GAIG;AACH,yIAMC;AAED;;;;GAIG;AACH,mCAHW,MAAM,gDAKhB;AAED;;;;GAIG;AACH,uHAEC;AAED;;;;GAIG;AACH,6FAEC;AAED;;;;GAIG;AACH,qHAEC;AAED;;;;GAIG;AACH,2HAOC;AAtUD,wCAAyC;AAEzC;;;;GAIG;AAEH;;GAEG;AACH;IAiBI;;OAEG;IACH,sBAFW,kBAAkB,EAoC5B;IAjCG,2CAA2C;IAC3C,SADW,SAAS,kBAAkB,CAAC,CAKtC;IA8BL;;;OAGG;IACH,qEAlDiC,OAAO,yHAC2B,OAAO,oBAAoB,EAAE,OAAO,eAAe,OAAO,WAAW,EAAE,OAAO,gBAAgB,MAAM,KAAK,IAAI,QAmD/K;IAED;;;;;;OAMG;IACH,wHAJW,OAAO,oBAAoB,EAAE,OAAO,eACpC,OAAO,WAAW,EAAE,OAAO,gBAC3B,MAAM,QAmBhB;IAED;;;;OAIG;IACH,iGAQC;IAED;;;;;;;;;;OAUG;IACH,uKALW,OAAO,oBAAoB,EAAE,OAAO,eACpC,OAAO,WAAW,EAAE,OAAO,gBAC3B,MAAM,4DACc,IAAI,iBA8DlC;;CACJ;;kBAxLa,OAAO;eACP,OAAO;;iBAfJ,WAAW"}
|
|
@@ -158,6 +158,8 @@ export class ViewFactory {
|
|
|
158
158
|
if (validator) {
|
|
159
159
|
validator(viewSpec);
|
|
160
160
|
}
|
|
161
|
+
|
|
162
|
+
applyParamsToImportedSpec(viewSpec, spec.import);
|
|
161
163
|
} else {
|
|
162
164
|
throw new ViewError(
|
|
163
165
|
"Importing views is not allowed!",
|
|
@@ -197,6 +199,49 @@ export class ViewFactory {
|
|
|
197
199
|
}
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
/**
|
|
203
|
+
*
|
|
204
|
+
* @param {ViewSpec} importedSpec
|
|
205
|
+
* @param {import("../spec/view.js").ImportParams} importParams
|
|
206
|
+
*/
|
|
207
|
+
function applyParamsToImportedSpec(importedSpec, importParams) {
|
|
208
|
+
if (importParams.name != null) {
|
|
209
|
+
importedSpec.name = importParams.name;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const params = isArray(importParams.params)
|
|
213
|
+
? importParams.params
|
|
214
|
+
: isObject(importParams.params)
|
|
215
|
+
? Object.entries(importParams.params).map(([name, value]) => ({
|
|
216
|
+
name,
|
|
217
|
+
value,
|
|
218
|
+
}))
|
|
219
|
+
: [];
|
|
220
|
+
|
|
221
|
+
if (!params.length) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
importedSpec.params ??= [];
|
|
226
|
+
|
|
227
|
+
// Replace overridden parameters
|
|
228
|
+
for (const param of params) {
|
|
229
|
+
const index = importedSpec.params.findIndex(
|
|
230
|
+
(p) => p.name == param.name
|
|
231
|
+
);
|
|
232
|
+
if (index >= 0) {
|
|
233
|
+
importedSpec.params[index] = param;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Add missing parameters
|
|
238
|
+
for (const param of params) {
|
|
239
|
+
if (!importedSpec.params.some((p) => p.name == param.name)) {
|
|
240
|
+
importedSpec.params.push(param);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
200
245
|
/**
|
|
201
246
|
*
|
|
202
247
|
* @param {ViewSpec} spec
|
|
@@ -82,7 +82,11 @@ export function findUniqueViewNames(root: View): Set<string>;
|
|
|
82
82
|
/**
|
|
83
83
|
* @param {View} viewRoot
|
|
84
84
|
*/
|
|
85
|
-
export function
|
|
85
|
+
export function calculateViewRootSize(viewRoot: View): import("./layout/flexLayout.js").FlexDimensions;
|
|
86
|
+
/**
|
|
87
|
+
* @param {import("./layout/flexLayout.js").FlexDimensions} viewRootSize
|
|
88
|
+
*/
|
|
89
|
+
export function calculateCanvasSize(viewRootSize: import("./layout/flexLayout.js").FlexDimensions): {
|
|
86
90
|
width: number;
|
|
87
91
|
height: number;
|
|
88
92
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewUtils.d.ts","sourceRoot":"","sources":["../../../src/view/viewUtils.js"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,qCAHW,OAAO,oBAAoB,EAAE,UAAU,GAAG,OAAO,iBAAiB,EAAE,YAAY,yBAK1F;AAED;;;;GAIG;AACH,oCAHW,OAAO,oBAAoB,EAAE,aAAa,GAAG,OAAO,iBAAiB,EAAE,YAAY,wBAQ7F;AAED;;;;GAIG;AACH,uCAHW,MAAM,0BAKhB;AAED;;;GAGG;AACH,+BAFW,IAAI,wCAMd;AAED;;;;GAIG;AACH,wCAFW,IAAI,UASd;AAED;;GAEG;AACH,kDAFW,IAAI,QAiBd;AAED;;;;;;;GAOG;AACH,4CAFW,IAAI,QAUd;AAED;;;;GAIG;AACH,qCAJW,IAAI,iBACJ,OAAO,qBAAqB,EAAE,OAAO,CAAC,IAAI,CAAC,wDAcrD;AAED;;;GAGG;AACH,wCAFW,IAAI;UAGO,QAAQ;aAAW,OAAO,oBAAoB,EAAE,OAAO;WAAS,OAAO,oBAAoB,EAAE,KAAK;UAAQ,OAAO,oBAAoB,EAAE,IAAI;IAqBhK;AAED;;;;GAIG;AACH,2CAJW,OAAO,iBAAiB,EAAE,UAAU,WACpC,MAAM,eACN,OAAO,yBAAyB,EAAE,OAAO,gBA8BnD;AAED;;GAEG;AACH,gDAFoB,IAAI,QAAE,IAAI,EAAE,KAAE,IAAI,+BAkBrC;AAED;;;;;;GAMG;AACH,4CAJW,IAAI,QACJ,MAAM,GACJ,IAAI,EAAE,CAalB;AAED;;;GAGG;AACH,0CAFW,IAAI,eAqBd;AAOD;;GAEG;AACH,
|
|
1
|
+
{"version":3,"file":"viewUtils.d.ts","sourceRoot":"","sources":["../../../src/view/viewUtils.js"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,qCAHW,OAAO,oBAAoB,EAAE,UAAU,GAAG,OAAO,iBAAiB,EAAE,YAAY,yBAK1F;AAED;;;;GAIG;AACH,oCAHW,OAAO,oBAAoB,EAAE,aAAa,GAAG,OAAO,iBAAiB,EAAE,YAAY,wBAQ7F;AAED;;;;GAIG;AACH,uCAHW,MAAM,0BAKhB;AAED;;;GAGG;AACH,+BAFW,IAAI,wCAMd;AAED;;;;GAIG;AACH,wCAFW,IAAI,UASd;AAED;;GAEG;AACH,kDAFW,IAAI,QAiBd;AAED;;;;;;;GAOG;AACH,4CAFW,IAAI,QAUd;AAED;;;;GAIG;AACH,qCAJW,IAAI,iBACJ,OAAO,qBAAqB,EAAE,OAAO,CAAC,IAAI,CAAC,wDAcrD;AAED;;;GAGG;AACH,wCAFW,IAAI;UAGO,QAAQ;aAAW,OAAO,oBAAoB,EAAE,OAAO;WAAS,OAAO,oBAAoB,EAAE,KAAK;UAAQ,OAAO,oBAAoB,EAAE,IAAI;IAqBhK;AAED;;;;GAIG;AACH,2CAJW,OAAO,iBAAiB,EAAE,UAAU,WACpC,MAAM,eACN,OAAO,yBAAyB,EAAE,OAAO,gBA8BnD;AAED;;GAEG;AACH,gDAFoB,IAAI,QAAE,IAAI,EAAE,KAAE,IAAI,+BAkBrC;AAED;;;;;;GAMG;AACH,4CAJW,IAAI,QACJ,MAAM,GACJ,IAAI,EAAE,CAalB;AAED;;;GAGG;AACH,0CAFW,IAAI,eAqBd;AAOD;;GAEG;AACH,gDAFW,IAAI,mDAId;AAED;;GAEG;AACH,kDAFW,OAAO,wBAAwB,EAAE,cAAc;;;EAczD;AAxBM,uCAFI,MAAM,WAE0D;iBAxP9B,WAAW;qBAFnC,eAAe"}
|
|
@@ -256,9 +256,14 @@ export const isCustomViewName = (name) => !/^(layer|concat)\d+$/.test(name);
|
|
|
256
256
|
/**
|
|
257
257
|
* @param {View} viewRoot
|
|
258
258
|
*/
|
|
259
|
-
export function
|
|
260
|
-
|
|
259
|
+
export function calculateViewRootSize(viewRoot) {
|
|
260
|
+
return viewRoot.getSize().addPadding(viewRoot.getOverhang());
|
|
261
|
+
}
|
|
261
262
|
|
|
263
|
+
/**
|
|
264
|
+
* @param {import("./layout/flexLayout.js").FlexDimensions} viewRootSize
|
|
265
|
+
*/
|
|
266
|
+
export function calculateCanvasSize(viewRootSize) {
|
|
262
267
|
// If a dimension has an absolutely specified size (in pixels), use it for the canvas size.
|
|
263
268
|
// However, if the dimension has a growing component, the canvas should be fit to the
|
|
264
269
|
// container.
|
|
@@ -267,7 +272,7 @@ export function calculateCanvasSize(viewRoot) {
|
|
|
267
272
|
/** @param {import("./layout/flexLayout.js").SizeDef} dim */
|
|
268
273
|
const f = (dim) => (dim.grow > 0 ? undefined : dim.px);
|
|
269
274
|
return {
|
|
270
|
-
width: f(
|
|
271
|
-
height: f(
|
|
275
|
+
width: f(viewRootSize.width),
|
|
276
|
+
height: f(viewRootSize.height),
|
|
272
277
|
};
|
|
273
278
|
}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"contributors": [],
|
|
9
9
|
"license": "MIT",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.45.0",
|
|
11
11
|
"jsdelivr": "dist/bundle/index.js",
|
|
12
12
|
"unpkg": "dist/bundle/index.js",
|
|
13
13
|
"browser": "dist/bundle/index.js",
|
|
@@ -43,27 +43,26 @@
|
|
|
43
43
|
"@gmod/gff": "^1.3.0",
|
|
44
44
|
"@gmod/indexedfasta": "^2.0.4",
|
|
45
45
|
"@gmod/tabix": "^1.5.13",
|
|
46
|
-
"@types/d3-array": "^3.
|
|
47
|
-
"@types/d3-dsv": "^3.0.
|
|
48
|
-
"@types/d3-ease": "^3.0.
|
|
49
|
-
"@types/d3-format": "^3.0.
|
|
50
|
-
"@types/d3-interpolate": "^3.0.
|
|
51
|
-
"@types/d3-scale": "^4.0.
|
|
46
|
+
"@types/d3-array": "^3.2.1",
|
|
47
|
+
"@types/d3-dsv": "^3.0.7",
|
|
48
|
+
"@types/d3-ease": "^3.0.2",
|
|
49
|
+
"@types/d3-format": "^3.0.4",
|
|
50
|
+
"@types/d3-interpolate": "^3.0.4",
|
|
51
|
+
"@types/d3-scale": "^4.0.8",
|
|
52
52
|
"buffer": "^6.0.3",
|
|
53
|
-
"d3-array": "^3.
|
|
54
|
-
"d3-color": "^3.0
|
|
53
|
+
"d3-array": "^3.2.4",
|
|
54
|
+
"d3-color": "^3.1.0",
|
|
55
55
|
"d3-ease": "^3.0.1",
|
|
56
|
-
"d3-format": "^3.0
|
|
56
|
+
"d3-format": "^3.1.0",
|
|
57
57
|
"events": "^3.3.0",
|
|
58
58
|
"flatqueue": "^2.0.3",
|
|
59
59
|
"internmap": "^2.0.3",
|
|
60
|
-
"lit": "^3.1.
|
|
61
|
-
"lit-html": "^3.0.2",
|
|
60
|
+
"lit": "^3.1.2",
|
|
62
61
|
"twgl.js": "^4.19.1",
|
|
63
|
-
"vega-expression": "^5.
|
|
64
|
-
"vega-loader": "^4.
|
|
65
|
-
"vega-scale": "^7.
|
|
66
|
-
"vega-util": "^1.
|
|
62
|
+
"vega-expression": "^5.1.0",
|
|
63
|
+
"vega-loader": "^4.5.1",
|
|
64
|
+
"vega-scale": "^7.3.1",
|
|
65
|
+
"vega-util": "^1.17.2"
|
|
67
66
|
},
|
|
68
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "7b6de39e856c85c755b2134bf451780c8b7922bb"
|
|
69
68
|
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A class that manages parameters and expressions. Still a work in progress.
|
|
3
|
-
*
|
|
4
|
-
* TODO: Write tests for this class.
|
|
5
|
-
*
|
|
6
|
-
* This should eventually handle the following:
|
|
7
|
-
* - Parameter registration
|
|
8
|
-
* - Dependency tracking
|
|
9
|
-
* - Calling observers when a parameter changes
|
|
10
|
-
* - Somehow saving parameter "state" (in bookmarks)
|
|
11
|
-
* - Maybe something else
|
|
12
|
-
*
|
|
13
|
-
* @typedef {import("./utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, invalidate: () => void}} ExprRefFunction
|
|
14
|
-
*/
|
|
15
|
-
export default class ParamBroker {
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* @param {string} paramName
|
|
19
|
-
* @returns {(value: any) => void}
|
|
20
|
-
*/
|
|
21
|
-
allocateSetter(paramName: string): (value: any) => void;
|
|
22
|
-
/**
|
|
23
|
-
* Parse expr and return a function that returns the value of the parameter.
|
|
24
|
-
*
|
|
25
|
-
* @param {string} expr
|
|
26
|
-
*/
|
|
27
|
-
createExpression(expr: string): ExprRefFunction;
|
|
28
|
-
#private;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* A class that manages parameters and expressions. Still a work in progress.
|
|
32
|
-
*
|
|
33
|
-
* TODO: Write tests for this class.
|
|
34
|
-
*
|
|
35
|
-
* This should eventually handle the following:
|
|
36
|
-
* - Parameter registration
|
|
37
|
-
* - Dependency tracking
|
|
38
|
-
* - Calling observers when a parameter changes
|
|
39
|
-
* - Somehow saving parameter "state" (in bookmarks)
|
|
40
|
-
* - Maybe something else
|
|
41
|
-
*/
|
|
42
|
-
export type ExprRefFunction = ((datum: object) => any) & import("./utils/expression.js").ExpressionProps & {
|
|
43
|
-
addListener: (listener: () => void) => void;
|
|
44
|
-
invalidate: () => void;
|
|
45
|
-
};
|
|
46
|
-
//# sourceMappingURL=paramBroker.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paramBroker.d.ts","sourceRoot":"","sources":["../../src/paramBroker.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH;IAyBI;;;;OAIG;IACH,0BAHW,MAAM,WACI,GAAG,KAAK,IAAI,CAqBhC;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBA2ChB;;CACJ;;;;;;;;;;;;;;4BAtG2F,MAAM,IAAI,KAAK,IAAI;gBAAc,MAAM,IAAI"}
|
package/dist/src/paramBroker.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { isString } from "vega-util";
|
|
2
|
-
import createFunction from "./utils/expression.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A class that manages parameters and expressions. Still a work in progress.
|
|
6
|
-
*
|
|
7
|
-
* TODO: Write tests for this class.
|
|
8
|
-
*
|
|
9
|
-
* This should eventually handle the following:
|
|
10
|
-
* - Parameter registration
|
|
11
|
-
* - Dependency tracking
|
|
12
|
-
* - Calling observers when a parameter changes
|
|
13
|
-
* - Somehow saving parameter "state" (in bookmarks)
|
|
14
|
-
* - Maybe something else
|
|
15
|
-
*
|
|
16
|
-
* @typedef {import("./utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, invalidate: () => void}} ExprRefFunction
|
|
17
|
-
*/
|
|
18
|
-
export default class ParamBroker {
|
|
19
|
-
/** @type {Map<string, any>} */
|
|
20
|
-
#params;
|
|
21
|
-
|
|
22
|
-
/** @type {Set<string>} */
|
|
23
|
-
#allocatedSetters;
|
|
24
|
-
|
|
25
|
-
/** @type {Record<string, any>} */
|
|
26
|
-
#proxy;
|
|
27
|
-
|
|
28
|
-
/** @type {Map<string, Set<() => void>>} */
|
|
29
|
-
#paramListeners;
|
|
30
|
-
|
|
31
|
-
constructor() {
|
|
32
|
-
this.#params = new Map();
|
|
33
|
-
this.#allocatedSetters = new Set();
|
|
34
|
-
this.#paramListeners = new Map();
|
|
35
|
-
|
|
36
|
-
this.#proxy = new Proxy(this.#params, {
|
|
37
|
-
get(target, prop) {
|
|
38
|
-
return isString(prop) ? target.get(prop) : undefined;
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
* @param {string} paramName
|
|
46
|
-
* @returns {(value: any) => void}
|
|
47
|
-
*/
|
|
48
|
-
allocateSetter(paramName) {
|
|
49
|
-
if (this.#allocatedSetters.has(paramName)) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
"Setter already allocated for parameter: " + paramName
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.#allocatedSetters.add(paramName);
|
|
56
|
-
|
|
57
|
-
return (value) => {
|
|
58
|
-
this.#params.set(paramName, value);
|
|
59
|
-
|
|
60
|
-
const listeners = this.#paramListeners.get(paramName);
|
|
61
|
-
if (listeners) {
|
|
62
|
-
for (const listener of listeners) {
|
|
63
|
-
listener();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// TODO: deallocateSetter
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Parse expr and return a function that returns the value of the parameter.
|
|
73
|
-
*
|
|
74
|
-
* @param {string} expr
|
|
75
|
-
*/
|
|
76
|
-
createExpression(expr) {
|
|
77
|
-
/** @type {ExprRefFunction} */
|
|
78
|
-
const fn = /** @type {any} */ (createFunction(expr, this.#proxy));
|
|
79
|
-
|
|
80
|
-
for (const g of fn.globals) {
|
|
81
|
-
if (!this.#allocatedSetters.has(g)) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`Unknown variable "${g}" in expression: ${expr}`
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Keep track of them so that they can be detached later
|
|
89
|
-
const myListeners = new Set();
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
*
|
|
93
|
-
* @param {() => void} listener
|
|
94
|
-
*/
|
|
95
|
-
fn.addListener = (listener) => {
|
|
96
|
-
for (const g of fn.globals) {
|
|
97
|
-
const listeners = this.#paramListeners.get(g) ?? new Set();
|
|
98
|
-
this.#paramListeners.set(g, listeners);
|
|
99
|
-
listeners.add(listener);
|
|
100
|
-
myListeners.add(listener);
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Detach listeners. This must be called if the expression is no longer used.
|
|
106
|
-
*/
|
|
107
|
-
fn.invalidate = () => {
|
|
108
|
-
for (const g of fn.globals) {
|
|
109
|
-
const listeners = this.#paramListeners.get(g);
|
|
110
|
-
for (const listener of myListeners) {
|
|
111
|
-
listeners.delete(listener);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
return fn;
|
|
117
|
-
}
|
|
118
|
-
}
|