@genome-spy/core 0.66.1 → 0.68.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 +7669 -6115
- package/dist/bundle/index.js +114 -133
- package/dist/schema.json +534 -132
- package/dist/src/data/collector.d.ts +20 -0
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +148 -0
- package/dist/src/data/dataFlow.d.ts +6 -0
- package/dist/src/data/dataFlow.d.ts.map +1 -1
- package/dist/src/data/dataFlow.js +10 -0
- package/dist/src/data/flowHandle.d.ts +2 -0
- package/dist/src/data/flowHandle.d.ts.map +1 -1
- package/dist/src/data/flowHandle.js +1 -0
- package/dist/src/data/flowInit.d.ts +12 -4
- package/dist/src/data/flowInit.d.ts.map +1 -1
- package/dist/src/data/flowInit.js +115 -17
- package/dist/src/data/flowNode.d.ts +8 -0
- package/dist/src/data/flowNode.d.ts.map +1 -1
- package/dist/src/data/flowNode.js +18 -0
- package/dist/src/data/keyIndex.d.ts +18 -0
- package/dist/src/data/keyIndex.d.ts.map +1 -0
- package/dist/src/data/keyIndex.js +241 -0
- package/dist/src/data/keyIndex.test.d.ts +2 -0
- package/dist/src/data/keyIndex.test.d.ts.map +1 -0
- package/dist/src/data/sources/dataSource.d.ts.map +1 -1
- package/dist/src/data/sources/dataSource.js +5 -1
- package/dist/src/data/sources/dataSourceFactory.d.ts +14 -12
- package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -1
- package/dist/src/data/sources/dataSourceFactory.js +52 -16
- package/dist/src/data/sources/lazy/mockLazySource.d.ts +29 -0
- package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -0
- package/dist/src/data/sources/lazy/mockLazySource.js +44 -0
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +22 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.js +34 -2
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +15 -0
- package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/tabixSource.js +15 -5
- package/dist/src/data/transforms/stack.d.ts.map +1 -1
- package/dist/src/data/transforms/stack.js +1 -0
- package/dist/src/encoder/accessor.d.ts +43 -0
- package/dist/src/encoder/accessor.d.ts.map +1 -1
- package/dist/src/encoder/accessor.js +164 -0
- package/dist/src/encoder/encoder.d.ts +11 -2
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +24 -4
- package/dist/src/encoder/metadataChannels.d.ts +15 -0
- package/dist/src/encoder/metadataChannels.d.ts.map +1 -0
- package/dist/src/encoder/metadataChannels.js +65 -0
- package/dist/src/encoder/metadataChannels.test.d.ts +2 -0
- package/dist/src/encoder/metadataChannels.test.d.ts.map +1 -0
- package/dist/src/genome/scaleLocus.d.ts.map +1 -1
- package/dist/src/genome/scaleLocus.js +14 -1
- package/dist/src/genomeSpy/containerUi.d.ts +0 -1
- package/dist/src/genomeSpy/containerUi.d.ts.map +1 -1
- package/dist/src/genomeSpy/containerUi.js +0 -14
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts +3 -7
- package/dist/src/genomeSpy/loadingIndicatorManager.d.ts.map +1 -1
- package/dist/src/genomeSpy/loadingIndicatorManager.js +68 -20
- package/dist/src/genomeSpy/loadingStatusRegistry.d.ts +52 -0
- package/dist/src/genomeSpy/loadingStatusRegistry.d.ts.map +1 -0
- package/dist/src/genomeSpy/loadingStatusRegistry.js +86 -0
- package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewContextFactory.js +0 -1
- package/dist/src/genomeSpy/viewDataInit.d.ts +10 -0
- package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
- package/dist/src/genomeSpy/viewDataInit.js +166 -2
- package/dist/src/genomeSpy/viewDataInit.test.d.ts +2 -0
- package/dist/src/genomeSpy/viewDataInit.test.d.ts.map +1 -0
- package/dist/src/genomeSpy.d.ts +1 -2
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +69 -27
- package/dist/src/gl/dataToVertices.d.ts.map +1 -1
- package/dist/src/gl/dataToVertices.js +16 -4
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +18 -11
- package/dist/src/marks/markUtils.js +1 -1
- package/dist/src/scale/scale.d.ts +6 -1
- package/dist/src/scale/scale.d.ts.map +1 -1
- package/dist/src/scale/scale.js +83 -23
- package/dist/src/scales/axisResolution.d.ts.map +1 -1
- package/dist/src/scales/axisResolution.js +10 -0
- package/dist/src/scales/{scaleDomainAggregator.d.ts → domainPlanner.d.ts} +8 -5
- package/dist/src/scales/domainPlanner.d.ts.map +1 -0
- package/dist/src/scales/domainPlanner.js +285 -0
- package/dist/src/scales/domainPlanner.test.d.ts +2 -0
- package/dist/src/scales/domainPlanner.test.d.ts.map +1 -0
- package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
- package/dist/src/scales/scaleInstanceManager.js +8 -4
- package/dist/src/scales/scaleInteractionController.d.ts +6 -0
- package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
- package/dist/src/scales/scaleInteractionController.js +41 -3
- package/dist/src/scales/scaleResolution.d.ts +19 -16
- package/dist/src/scales/scaleResolution.d.ts.map +1 -1
- package/dist/src/scales/scaleResolution.js +255 -70
- package/dist/src/scales/scaleResolution.test.d.ts.map +1 -1
- package/dist/src/selection/selection.d.ts +21 -0
- package/dist/src/selection/selection.d.ts.map +1 -1
- package/dist/src/selection/selection.js +82 -0
- package/dist/src/spec/channel.d.ts +52 -15
- package/dist/src/spec/data.d.ts +4 -0
- package/dist/src/spec/parameter.d.ts +16 -11
- package/dist/src/spec/testing.d.ts +12 -0
- package/dist/src/spec/testing.d.ts.map +1 -0
- package/dist/src/spec/testing.js +20 -0
- package/dist/src/spec/view.d.ts +45 -10
- package/dist/src/styles/genome-spy.css +3 -31
- 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 +0 -29
- package/dist/src/types/encoder.d.ts +37 -2
- package/dist/src/types/rendering.d.ts +4 -3
- package/dist/src/types/viewContext.d.ts +0 -14
- package/dist/src/utils/domainArray.d.ts.map +1 -1
- package/dist/src/utils/domainArray.js +3 -0
- package/dist/src/utils/indexer.d.ts +3 -0
- package/dist/src/utils/indexer.d.ts.map +1 -1
- package/dist/src/utils/indexer.js +3 -0
- package/dist/src/utils/throttle.d.ts +4 -1
- package/dist/src/utils/throttle.d.ts.map +1 -1
- package/dist/src/utils/throttle.js +54 -23
- package/dist/src/utils/throttle.test.d.ts +2 -0
- package/dist/src/utils/throttle.test.d.ts.map +1 -0
- package/dist/src/utils/transition.d.ts +21 -0
- package/dist/src/utils/transition.d.ts.map +1 -1
- package/dist/src/utils/transition.js +28 -0
- package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
- package/dist/src/utils/ui/tooltip.js +7 -1
- package/dist/src/utils/ui/tooltip.test.d.ts +2 -0
- package/dist/src/utils/ui/tooltip.test.d.ts.map +1 -0
- package/dist/src/view/axisGridView.d.ts.map +1 -1
- package/dist/src/view/axisGridView.js +22 -5
- package/dist/src/view/axisView.d.ts.map +1 -1
- package/dist/src/view/axisView.js +20 -5
- package/dist/src/view/concatView.js +3 -3
- package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
- package/dist/src/view/containerMutationHelper.js +6 -2
- package/dist/src/view/containerView.d.ts +9 -5
- package/dist/src/view/containerView.d.ts.map +1 -1
- package/dist/src/view/containerView.js +34 -9
- package/dist/src/view/dataReadiness.d.ts +46 -0
- package/dist/src/view/dataReadiness.d.ts.map +1 -0
- package/dist/src/view/dataReadiness.js +267 -0
- package/dist/src/view/dataReadiness.test.d.ts +2 -0
- package/dist/src/view/dataReadiness.test.d.ts.map +1 -0
- package/dist/src/view/facetView.d.ts.map +1 -1
- package/dist/src/view/facetView.js +7 -5
- package/dist/src/view/flowBuilder.d.ts +5 -3
- package/dist/src/view/flowBuilder.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.js +74 -7
- package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
- package/dist/src/view/gridView/gridChild.js +8 -0
- package/dist/src/view/gridView/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView/gridView.js +119 -2
- package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
- package/dist/src/view/gridView/scrollbar.js +3 -0
- package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
- package/dist/src/view/gridView/selectionRect.js +20 -5
- package/dist/src/view/gridView/separatorView.d.ts +51 -0
- package/dist/src/view/gridView/separatorView.d.ts.map +1 -0
- package/dist/src/view/gridView/separatorView.js +275 -0
- package/dist/src/view/layerView.js +3 -3
- package/dist/src/view/layout/flexLayout.d.ts +0 -30
- package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
- package/dist/src/view/layout/flexLayout.js +0 -86
- package/dist/src/view/paramMediator.d.ts +19 -0
- package/dist/src/view/paramMediator.d.ts.map +1 -1
- package/dist/src/view/paramMediator.js +86 -19
- package/dist/src/view/testUtils.d.ts.map +1 -1
- package/dist/src/view/testUtils.js +11 -1
- package/dist/src/view/unitView.d.ts +8 -13
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +127 -43
- package/dist/src/view/view.d.ts +34 -14
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +119 -9
- package/dist/src/view/viewFactory.d.ts.map +1 -1
- package/dist/src/view/viewFactory.js +20 -1
- package/dist/src/view/viewSelectors.d.ts +148 -0
- package/dist/src/view/viewSelectors.d.ts.map +1 -0
- package/dist/src/view/viewSelectors.js +773 -0
- package/dist/src/view/viewSelectors.test.d.ts +2 -0
- package/dist/src/view/viewSelectors.test.d.ts.map +1 -0
- package/dist/src/view/viewUtils.d.ts +0 -8
- package/dist/src/view/viewUtils.d.ts.map +1 -1
- package/dist/src/view/viewUtils.js +1 -21
- package/package.json +3 -3
- package/dist/src/scales/scaleDomainAggregator.d.ts.map +0 -1
- package/dist/src/scales/scaleDomainAggregator.js +0 -162
- package/dist/src/scales/scaleDomainAggregator.test.d.ts +0 -2
- package/dist/src/scales/scaleDomainAggregator.test.d.ts.map +0 -1
|
@@ -302,89 +302,3 @@ export function parseSizeDef(size) {
|
|
|
302
302
|
|
|
303
303
|
throw new Error(`Invalid sizeDef: ${size}`);
|
|
304
304
|
}
|
|
305
|
-
|
|
306
|
-
// TODO: Find a better place for the following utilities: ////////////////////////////////////
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Interpolates between two LocSizes
|
|
310
|
-
*
|
|
311
|
-
* @param {LocSize} from
|
|
312
|
-
* @param {LocSize} to
|
|
313
|
-
* @param {function():number} ratio
|
|
314
|
-
* @returns {LocSize}
|
|
315
|
-
*/
|
|
316
|
-
export function interpolateLocSizes(from, to, ratio) {
|
|
317
|
-
return {
|
|
318
|
-
get location() {
|
|
319
|
-
const r = ratio();
|
|
320
|
-
switch (r) {
|
|
321
|
-
case 0:
|
|
322
|
-
return from.location;
|
|
323
|
-
case 1:
|
|
324
|
-
return to.location;
|
|
325
|
-
default:
|
|
326
|
-
return r * to.location + (1 - r) * from.location;
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
|
|
330
|
-
get size() {
|
|
331
|
-
const r = ratio();
|
|
332
|
-
switch (r) {
|
|
333
|
-
case 0:
|
|
334
|
-
return from.size;
|
|
335
|
-
case 1:
|
|
336
|
-
return to.size;
|
|
337
|
-
default:
|
|
338
|
-
return r * to.size + (1 - r) * from.size;
|
|
339
|
-
}
|
|
340
|
-
},
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Wraps a LocSize and allows scrolling.
|
|
346
|
-
*
|
|
347
|
-
* @param {LocSize} locSize
|
|
348
|
-
* @param {number | function():number} offset
|
|
349
|
-
* @returns {LocSize}
|
|
350
|
-
*/
|
|
351
|
-
export function translateLocSize(locSize, offset) {
|
|
352
|
-
const fn = isNumber(offset) ? () => offset : offset;
|
|
353
|
-
return {
|
|
354
|
-
get location() {
|
|
355
|
-
return locSize.location + fn();
|
|
356
|
-
},
|
|
357
|
-
|
|
358
|
-
get size() {
|
|
359
|
-
return locSize.size;
|
|
360
|
-
},
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Wraps a LocSize and allows scaling.
|
|
366
|
-
*
|
|
367
|
-
* @param {LocSize} locSize
|
|
368
|
-
* @param {number | function():number} factor
|
|
369
|
-
* @returns {LocSize}
|
|
370
|
-
*/
|
|
371
|
-
export function scaleLocSize(locSize, factor) {
|
|
372
|
-
const fn = isNumber(factor) ? () => factor : factor;
|
|
373
|
-
return {
|
|
374
|
-
get location() {
|
|
375
|
-
return locSize.location * fn();
|
|
376
|
-
},
|
|
377
|
-
|
|
378
|
-
get size() {
|
|
379
|
-
return locSize.size * fn();
|
|
380
|
-
},
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* @param {LocSize} locSize
|
|
386
|
-
* @param {number} value
|
|
387
|
-
*/
|
|
388
|
-
export function locSizeEncloses(locSize, value) {
|
|
389
|
-
return value >= locSize.location && value < locSize.location + locSize.size;
|
|
390
|
-
}
|
|
@@ -22,6 +22,15 @@ export function isVariableParameter(param: import("../spec/parameter.js").Parame
|
|
|
22
22
|
* @returns {param is import("../spec/parameter.js").SelectionParameter}
|
|
23
23
|
*/
|
|
24
24
|
export function isSelectionParameter(param: import("../spec/parameter.js").Parameter): param is import("../spec/parameter.js").SelectionParameter;
|
|
25
|
+
/**
|
|
26
|
+
* Computes the default value for a parameter specification.
|
|
27
|
+
*
|
|
28
|
+
* @param {Parameter} param
|
|
29
|
+
* @param {ParamMediator} [paramMediator]
|
|
30
|
+
* @param {ExprRefFunction} [exprFn]
|
|
31
|
+
* @returns {any}
|
|
32
|
+
*/
|
|
33
|
+
export function getDefaultParamValue(param: import("../spec/parameter.js").Parameter, paramMediator?: ParamMediator, exprFn?: ExprRefFunction): any;
|
|
25
34
|
/**
|
|
26
35
|
* Takes a record of properties that may have ExprRefs as values. Converts the
|
|
27
36
|
* ExprRefs to getters and setups a listener that is called when any of the
|
|
@@ -97,6 +106,16 @@ export default class ParamMediator {
|
|
|
97
106
|
* @param {string} paramName
|
|
98
107
|
*/
|
|
99
108
|
getValue(paramName: string): any;
|
|
109
|
+
/**
|
|
110
|
+
* Subscribe to changes of a parameter's value. The listener is called only
|
|
111
|
+
* when the stored value changes. For expression parameters, the listener is
|
|
112
|
+
* called when upstream changes re-evaluate to a different value.
|
|
113
|
+
*
|
|
114
|
+
* @param {string} paramName
|
|
115
|
+
* @param {() => void} listener
|
|
116
|
+
* @returns {() => void}
|
|
117
|
+
*/
|
|
118
|
+
subscribe(paramName: string, listener: () => void): () => void;
|
|
100
119
|
/**
|
|
101
120
|
* Get the value of a parameter from this mediator or the ancestors.
|
|
102
121
|
* @param {string} paramName
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"paramMediator.d.ts","sourceRoot":"","sources":["../../../src/view/paramMediator.js"],"names":[],"mappings":"AAiXA;;;GAGG;AACH,6BAHW,GAAG,GACD,CAAC,IAAI,OAAO,sBAAsB,EAAE,OAAO,CAIvD;AAED;;;;;;;GAOG;AACH,+BAHa,CAAC,KADH,CAAC,GAAG,OAAO,sBAAsB,EAAE,OAAO,GAExC,CAAC,CAWb;AAED;;;GAGG;AACH,sFAFa,KAAK,IAAI,OAAO,sBAAsB,EAAE,iBAAiB,CAIrE;AAED;;;GAGG;AACH,uFAFa,KAAK,IAAI,OAAO,sBAAsB,EAAE,kBAAkB,CAItE;AAED;;;;;;;GAOG;AACH,sGAJW,aAAa,WACb,eAAe,GACb,GAAG,CAwCf;AAED;;;;;;;;;;GAUG;AACH,qCAF4E,CAAC,SAA/D,MAAM,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,sBAAsB,EAAE,OAAO,CAAE,iBAJhE,aAAa,SACb,CAAC,aACD,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI,GAuCjB,CAAC,CACtB;AAED;;;;;;GAMG;AACH,4CAHW,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;;GAOG;AACH,2CAHW,GAAG,GACD,eAAe,CAY3B;AArhBD;;;;;;;;GAQG;AACH;IA2BI;;;;;OAKG;IACH,2BALW,MAAM,aAAa,EAU7B;IA7BD;;;OAGG;IACH,0BAHU,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAGvB;IA2Bf;;;OAGG;IACH,wEAzCqB,GAAG,KAAK,IAAI,CAkGhC;IAED;;;;;;;OAOG;IACH,eAFa,CAAC,aAJH,MAAM,gBACN,CAAC,YACD,OAAO,GACL,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAgC9B;IAED;;;OAGG;IACH,qBAFW,MAAM,WAjIc,GAAG,KAAK,IAAI,CAyI1C;IAED;;;OAGG;IACH,oBAFW,MAAM,OAIhB;IAED;;;;;;;;OAQG;IACH,qBAJW,MAAM,YACN,MAAM,IAAI,GACR,MAAM,IAAI,CAmBtB;IAED;;;OAGG;IACH,qBAFW,MAAM,OAKhB;IAED;;OAEG;IACH,oBACsB,WAAW,CAAC,MAAM,2CAAY,CAGnD;IAED;;;;OAIG;IACH,gCAHW,MAAM,GACJ,aAAa,CAQzB;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBAuFhB;IAED;;;;OAIG;IACH,qBAFW,MAAM,OAKhB;IAED;;;;;OAKG;IACH,sBAFa,OAAO,CAiBnB;;CACJ;;;;;;;;8BA7VY,OAAO,wBAAwB,EAAE,kBAAkB,GAAG;IAAE,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,MAAM,CAAA;CAAC"}
|
|
@@ -73,6 +73,7 @@ export default class ParamMediator {
|
|
|
73
73
|
|
|
74
74
|
/** @type {ParameterSetter} */
|
|
75
75
|
let setter;
|
|
76
|
+
let defaultValue;
|
|
76
77
|
|
|
77
78
|
if (param.push == "outer") {
|
|
78
79
|
const outerMediator = this.findMediatorForParam(name);
|
|
@@ -93,36 +94,26 @@ export default class ParamMediator {
|
|
|
93
94
|
// support mutation (i.e. adding/removing children) in future.
|
|
94
95
|
this.#allocatedSetters.set(name, setter);
|
|
95
96
|
} else if ("value" in param) {
|
|
96
|
-
|
|
97
|
+
defaultValue = getDefaultParamValue(param, this);
|
|
98
|
+
setter = this.allocateSetter(name, defaultValue);
|
|
97
99
|
} else if ("expr" in param) {
|
|
98
100
|
const expr = this.createExpression(param.expr);
|
|
99
101
|
// TODO: getSetter(param) should return a setter that throws if
|
|
100
102
|
// modifying the value is attempted.
|
|
101
|
-
|
|
103
|
+
defaultValue = getDefaultParamValue(param, this, expr);
|
|
104
|
+
const realSetter = this.allocateSetter(name, defaultValue);
|
|
102
105
|
expr.addListener(() => realSetter(expr(null)));
|
|
103
106
|
// NOP
|
|
104
107
|
setter = (_) => undefined;
|
|
105
108
|
} else {
|
|
106
|
-
|
|
109
|
+
defaultValue = getDefaultParamValue(param, this);
|
|
110
|
+
setter = this.allocateSetter(name, defaultValue);
|
|
107
111
|
}
|
|
108
112
|
|
|
109
113
|
if ("select" in param) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
setter(
|
|
114
|
-
select.toggle
|
|
115
|
-
? createMultiPointSelection()
|
|
116
|
-
: createSinglePointSelection(null)
|
|
117
|
-
);
|
|
118
|
-
} else if (isIntervalSelectionConfig(select)) {
|
|
119
|
-
if (!select.encodings) {
|
|
120
|
-
throw new Error(
|
|
121
|
-
`Interval selection "${name}" must have encodings defined!`
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
setter(createIntervalSelection(select.encodings));
|
|
125
|
-
}
|
|
114
|
+
defaultValue ??= getDefaultParamValue(param, this);
|
|
115
|
+
// Set initial value so that production rules in shaders can be generated, etc.
|
|
116
|
+
setter(defaultValue);
|
|
126
117
|
}
|
|
127
118
|
|
|
128
119
|
this.#paramConfigs.set(name, param);
|
|
@@ -189,6 +180,34 @@ export default class ParamMediator {
|
|
|
189
180
|
return this.#paramValues.get(paramName);
|
|
190
181
|
}
|
|
191
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Subscribe to changes of a parameter's value. The listener is called only
|
|
185
|
+
* when the stored value changes. For expression parameters, the listener is
|
|
186
|
+
* called when upstream changes re-evaluate to a different value.
|
|
187
|
+
*
|
|
188
|
+
* @param {string} paramName
|
|
189
|
+
* @param {() => void} listener
|
|
190
|
+
* @returns {() => void}
|
|
191
|
+
*/
|
|
192
|
+
subscribe(paramName, listener) {
|
|
193
|
+
validateParameterName(paramName);
|
|
194
|
+
const mediator = this.findMediatorForParam(paramName);
|
|
195
|
+
if (!mediator) {
|
|
196
|
+
throw new Error("Parameter not found: " + paramName);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const listeners = mediator.paramListeners.get(paramName) ?? new Set();
|
|
200
|
+
mediator.paramListeners.set(paramName, listeners);
|
|
201
|
+
listeners.add(listener);
|
|
202
|
+
|
|
203
|
+
return () => {
|
|
204
|
+
listeners.delete(listener);
|
|
205
|
+
if (!listeners.size) {
|
|
206
|
+
mediator.paramListeners.delete(paramName);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
192
211
|
/**
|
|
193
212
|
* Get the value of a parameter from this mediator or the ancestors.
|
|
194
213
|
* @param {string} paramName
|
|
@@ -391,6 +410,54 @@ export function isSelectionParameter(param) {
|
|
|
391
410
|
return !("expr" in param || "bind" in param) && "select" in param;
|
|
392
411
|
}
|
|
393
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Computes the default value for a parameter specification.
|
|
415
|
+
*
|
|
416
|
+
* @param {Parameter} param
|
|
417
|
+
* @param {ParamMediator} [paramMediator]
|
|
418
|
+
* @param {ExprRefFunction} [exprFn]
|
|
419
|
+
* @returns {any}
|
|
420
|
+
*/
|
|
421
|
+
export function getDefaultParamValue(param, paramMediator, exprFn) {
|
|
422
|
+
if ("select" in param) {
|
|
423
|
+
const select = asSelectionConfig(param.select);
|
|
424
|
+
if (isPointSelectionConfig(select)) {
|
|
425
|
+
return select.toggle
|
|
426
|
+
? createMultiPointSelection()
|
|
427
|
+
: createSinglePointSelection(null);
|
|
428
|
+
}
|
|
429
|
+
if (isIntervalSelectionConfig(select)) {
|
|
430
|
+
if (!select.encodings) {
|
|
431
|
+
throw new Error(
|
|
432
|
+
`Interval selection "${param.name}" must have encodings defined!`
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
return createIntervalSelection(select.encodings);
|
|
436
|
+
}
|
|
437
|
+
throw new Error(
|
|
438
|
+
`Unknown selection config for parameter "${param.name}".`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if ("expr" in param) {
|
|
443
|
+
const expr =
|
|
444
|
+
exprFn ??
|
|
445
|
+
paramMediator?.createExpression(/** @type {string} */ (param.expr));
|
|
446
|
+
if (!expr) {
|
|
447
|
+
throw new Error(
|
|
448
|
+
`Cannot evaluate expression for parameter "${param.name}".`
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
return expr(null);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if ("value" in param) {
|
|
455
|
+
return param.value;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
|
|
394
461
|
/**
|
|
395
462
|
* Takes a record of properties that may have ExprRefs as values. Converts the
|
|
396
463
|
* ExprRefs to getters and setups a listener that is called when any of the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../../src/view/testUtils.js"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,2DAHW,OAAO,kBAAkB,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"testUtils.d.ts","sourceRoot":"","sources":["../../../src/view/testUtils.js"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,2DAHW,OAAO,kBAAkB,EAAE,kBAAkB,6CAoEvD;AAGS,uBAAC,CAAC,SAAS,OAAO,WAAW,EAAE,OAAO,QAAQ,QAAQ,aAAa;IAAE,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,uBAAuB,OAAO,kBAAkB,EAAE,kBAAkB,GAAK,OAAO,CAAC,CAAC,CAAC,CAAA;AAgBhL,oCAAC,CAAC,SAAS,OAAO,WAAW,EAAE,OAAO,QAAQ,QAAQ,aAAa;IAAE,KAAI,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;CAAE,YAAY,WAAW,YAAY;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAC,GAAK,OAAO,CAAC,CAAC,CAAC,CAAA;;;;;uBAxGpL,OAAO,iBAAiB,EAAE,QAAQ;;;;;0BAClC,OAAO,yBAAyB,EAAE,OAAO"}
|
|
@@ -38,6 +38,8 @@ export function createTestViewContext(viewFactoryOptions = {}) {
|
|
|
38
38
|
],
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
const dataFlow = new DataFlow();
|
|
42
|
+
|
|
41
43
|
// @ts-expect-error
|
|
42
44
|
const c = /** @type {ViewContext} */ ({
|
|
43
45
|
createOrImportView: async function (
|
|
@@ -55,7 +57,7 @@ export function createTestViewContext(viewFactoryOptions = {}) {
|
|
|
55
57
|
);
|
|
56
58
|
},
|
|
57
59
|
|
|
58
|
-
dataFlow
|
|
60
|
+
dataFlow,
|
|
59
61
|
genomeStore,
|
|
60
62
|
|
|
61
63
|
fontManager: new BmFontManager(),
|
|
@@ -66,6 +68,11 @@ export function createTestViewContext(viewFactoryOptions = {}) {
|
|
|
66
68
|
/** @type {(callback: () => void) => void} */ (
|
|
67
69
|
(callback) => callback()
|
|
68
70
|
),
|
|
71
|
+
transition: (/** @type {any} */ options) => {
|
|
72
|
+
const to = typeof options.to === "number" ? options.to : 1;
|
|
73
|
+
options.onUpdate(to);
|
|
74
|
+
return Promise.resolve();
|
|
75
|
+
},
|
|
69
76
|
})
|
|
70
77
|
),
|
|
71
78
|
|
|
@@ -73,6 +80,9 @@ export function createTestViewContext(viewFactoryOptions = {}) {
|
|
|
73
80
|
|
|
74
81
|
isViewConfiguredVisible: () => true,
|
|
75
82
|
|
|
83
|
+
addBroadcastListener: () => undefined,
|
|
84
|
+
removeBroadcastListener: () => undefined,
|
|
85
|
+
|
|
76
86
|
//...partialContext,
|
|
77
87
|
});
|
|
78
88
|
|
|
@@ -33,25 +33,20 @@ export default class UnitView extends View {
|
|
|
33
33
|
* @param {Channel} channel
|
|
34
34
|
*/
|
|
35
35
|
getDataAccessor(channel: import("../spec/channel.js").Channel): import("../types/encoder.js").Accessor<import("../spec/channel.js").Scalar>;
|
|
36
|
+
/**
|
|
37
|
+
* Returns data accessors configured for the `search` channel.
|
|
38
|
+
*
|
|
39
|
+
* @returns {import("vega-util").AccessorFn[]}
|
|
40
|
+
*/
|
|
41
|
+
getSearchAccessors(): import("vega-util").AccessorFn[];
|
|
36
42
|
/**
|
|
37
43
|
* Returns a collector that is associated with this view.
|
|
38
44
|
*/
|
|
39
45
|
getCollector(): import("../data/collector.js").default;
|
|
40
46
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* TODO: Optimize! Now this performs redundant work if multiple views share the same collector.
|
|
44
|
-
* Also, all relevant fields should be processed in one iteration: https://jsbench.me/y5kkqy52jo/1
|
|
45
|
-
* In fact, domain extraction could be a responsibility of the collector: As it handles data items,
|
|
46
|
-
* it extracts domains for all fields (and data types) that need extracted domains.
|
|
47
|
-
* Alternatively, extractor nodes could be added to the data flow, just like Vega does
|
|
48
|
-
* (with aggregate and extent).
|
|
49
|
-
*
|
|
50
|
-
* @param {Channel} channel
|
|
51
|
-
* @param {import("../spec/channel.js").Type} type
|
|
52
|
-
* @returns {DomainArray}
|
|
47
|
+
* Registers collector subscriptions that keep scale domains up to date.
|
|
53
48
|
*/
|
|
54
|
-
|
|
49
|
+
registerDomainSubscriptions(): void;
|
|
55
50
|
getZoomLevel(): number;
|
|
56
51
|
/**
|
|
57
52
|
* @param {string} channel
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unitView.d.ts","sourceRoot":"","sources":["../../../src/view/unitView.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"unitView.d.ts","sourceRoot":"","sources":["../../../src/view/unitView.js"],"names":[],"mappings":"AA+BA;;;;GAIG;AACH,wBAHU,MAAM,CAAC,OAAO,iBAAiB,EAAE,QAAQ,EAAE,cAAc,kBAAkB,EAAE,OAAO,CAAC,CAc7F;AAEF;IAwBI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,QAAQ,WAClC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAyCzC;IApCG,yCAAgB;IAIZ,iDAAiD;IACjD,MADW,OAAO,kBAAkB,EAAE,OAAO,CACnB;IAoKlC,2DAIC;IAoBD;;;;;OAKG;IAEH,iEAoJC;IAUD;;;;;OAKG;IACH,4IAMC;IAED;;;;OAIG;IACH,sBAFa,OAAO,WAAW,EAAE,UAAU,EAAE,CAS5C;IAkBD;;OAEG;IACH,uDAEC;IAED;;OAEG;IACH,oCA0EC;IAED,uBAQC;IAgBD;;;;OAIG;IACH,8BAJW,MAAM,+DAEJ,OAAO,iBAAiB,EAAE,kBAAkB,CAKxD;;CACJ;iBA5kBgB,WAAW"}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
isPrimaryPositionalChannel,
|
|
15
15
|
isValueDefWithCondition,
|
|
16
16
|
} from "../encoder/encoder.js";
|
|
17
|
-
import
|
|
17
|
+
import { isScaleAccessor } from "../encoder/accessor.js";
|
|
18
18
|
import AxisResolution from "../scales/axisResolution.js";
|
|
19
19
|
import View from "./view.js";
|
|
20
20
|
import {
|
|
@@ -24,8 +24,10 @@ import {
|
|
|
24
24
|
isPointSelectionConfig,
|
|
25
25
|
updateMultiPointSelection,
|
|
26
26
|
} from "../selection/selection.js";
|
|
27
|
+
import { getEncodingSearchFields } from "../encoder/metadataChannels.js";
|
|
27
28
|
import { UNIQUE_ID_KEY } from "../data/transforms/identifier.js";
|
|
28
29
|
import { createEventFilterFunction } from "../utils/expression.js";
|
|
30
|
+
import { field } from "../utils/field.js";
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
33
|
*
|
|
@@ -48,7 +50,6 @@ export const markTypes = {
|
|
|
48
50
|
export default class UnitView extends View {
|
|
49
51
|
/**
|
|
50
52
|
* @typedef {import("../spec/channel.js").Channel} Channel
|
|
51
|
-
* @typedef {import("../utils/domainArray.js").DomainArray} DomainArray
|
|
52
53
|
* @typedef {import("../spec/view.js").ResolutionTarget} ResolutionTarget
|
|
53
54
|
* @typedef {((datum: import("../data/flowNode.js").Datum) => import("../spec/channel.js").Scalar) & { fieldDef: import("../spec/channel.js").FieldDef}} FieldAccessor
|
|
54
55
|
*
|
|
@@ -60,6 +61,16 @@ export default class UnitView extends View {
|
|
|
60
61
|
*/
|
|
61
62
|
#zoomLevelSetter;
|
|
62
63
|
|
|
64
|
+
/**
|
|
65
|
+
* @type {boolean}
|
|
66
|
+
*/
|
|
67
|
+
#domainSubscriptionsRegistered = false;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @type {import("vega-util").AccessorFn[] | null}
|
|
71
|
+
*/
|
|
72
|
+
#searchAccessors = null;
|
|
73
|
+
|
|
63
74
|
/**
|
|
64
75
|
*
|
|
65
76
|
* @param {import("../spec/view.js").UnitSpec} spec
|
|
@@ -253,6 +264,10 @@ export default class UnitView extends View {
|
|
|
253
264
|
const encoding = super.getEncoding();
|
|
254
265
|
const supportedChannels = this.mark.getSupportedChannels();
|
|
255
266
|
for (const channel of Object.keys(encoding)) {
|
|
267
|
+
if (channel === "key") {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
256
271
|
if (!supportedChannels.includes(channel)) {
|
|
257
272
|
delete encoding[channel];
|
|
258
273
|
}
|
|
@@ -284,6 +299,10 @@ export default class UnitView extends View {
|
|
|
284
299
|
continue;
|
|
285
300
|
}
|
|
286
301
|
|
|
302
|
+
if (Array.isArray(channelDef)) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
|
|
287
306
|
/** @type {import("../spec/channel.js").ChannelDefWithScale} */
|
|
288
307
|
let channelDefWithScale;
|
|
289
308
|
|
|
@@ -368,32 +387,38 @@ export default class UnitView extends View {
|
|
|
368
387
|
const resolution = new ScaleResolution(targetChannel);
|
|
369
388
|
view.resolutions[type][targetChannel] = resolution;
|
|
370
389
|
|
|
371
|
-
|
|
372
|
-
|
|
390
|
+
const updateRangeTexture = (
|
|
391
|
+
/** @type {import("../types/scaleResolutionApi.js").ScaleResolutionEvent} */ event
|
|
392
|
+
) => {
|
|
393
|
+
// Create if WebGLHelper is available, i.e., if not running in headless mode.
|
|
394
|
+
// Domain changes can alter discrete texture sizes as well.
|
|
373
395
|
this.context.glHelper?.createRangeTexture(
|
|
374
396
|
event.scaleResolution,
|
|
375
397
|
true
|
|
376
398
|
);
|
|
399
|
+
};
|
|
400
|
+
resolution.addEventListener("range", updateRangeTexture);
|
|
401
|
+
resolution.addEventListener("domain", updateRangeTexture);
|
|
402
|
+
this.registerDisposer(() => {
|
|
403
|
+
resolution.removeEventListener(
|
|
404
|
+
"range",
|
|
405
|
+
updateRangeTexture
|
|
406
|
+
);
|
|
407
|
+
resolution.removeEventListener(
|
|
408
|
+
"domain",
|
|
409
|
+
updateRangeTexture
|
|
410
|
+
);
|
|
377
411
|
});
|
|
378
412
|
}
|
|
379
413
|
|
|
380
|
-
const
|
|
381
|
-
this.getLayoutAncestors()
|
|
382
|
-
// TODO: Should check until the resolved scale resolution
|
|
383
|
-
.some(
|
|
384
|
-
(view) => !view.options.contributesToScaleDomain
|
|
385
|
-
) ||
|
|
386
|
-
(isChannelDefWithScale(channelDefWithScale) &&
|
|
387
|
-
channelDefWithScale.contributesToScaleDomain === false)
|
|
388
|
-
? undefined
|
|
389
|
-
: this.extractDataDomain.bind(this);
|
|
414
|
+
const contributesToDomain = !this.isDomainInert();
|
|
390
415
|
|
|
391
416
|
const resolution = view.resolutions[type][targetChannel];
|
|
392
417
|
const unregister = resolution.registerMember({
|
|
393
418
|
view: this,
|
|
394
419
|
channel,
|
|
395
420
|
channelDef: channelDefWithScale,
|
|
396
|
-
|
|
421
|
+
contributesToDomain,
|
|
397
422
|
});
|
|
398
423
|
this.registerDisposer(() => {
|
|
399
424
|
// Unregister returns true when it removed the last member.
|
|
@@ -430,6 +455,20 @@ export default class UnitView extends View {
|
|
|
430
455
|
return encoders[channel]?.dataAccessor;
|
|
431
456
|
}
|
|
432
457
|
|
|
458
|
+
/**
|
|
459
|
+
* Returns data accessors configured for the `search` channel.
|
|
460
|
+
*
|
|
461
|
+
* @returns {import("vega-util").AccessorFn[]}
|
|
462
|
+
*/
|
|
463
|
+
getSearchAccessors() {
|
|
464
|
+
if (!this.#searchAccessors) {
|
|
465
|
+
const fields = getEncodingSearchFields(this.getEncoding()) ?? [];
|
|
466
|
+
this.#searchAccessors = fields.map((fieldName) => field(fieldName));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return this.#searchAccessors;
|
|
470
|
+
}
|
|
471
|
+
|
|
433
472
|
/**
|
|
434
473
|
* Returns an accessor that returns a (composite) key for partitioning the data
|
|
435
474
|
*
|
|
@@ -454,37 +493,82 @@ export default class UnitView extends View {
|
|
|
454
493
|
}
|
|
455
494
|
|
|
456
495
|
/**
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
* TODO: Optimize! Now this performs redundant work if multiple views share the same collector.
|
|
460
|
-
* Also, all relevant fields should be processed in one iteration: https://jsbench.me/y5kkqy52jo/1
|
|
461
|
-
* In fact, domain extraction could be a responsibility of the collector: As it handles data items,
|
|
462
|
-
* it extracts domains for all fields (and data types) that need extracted domains.
|
|
463
|
-
* Alternatively, extractor nodes could be added to the data flow, just like Vega does
|
|
464
|
-
* (with aggregate and extent).
|
|
465
|
-
*
|
|
466
|
-
* @param {Channel} channel
|
|
467
|
-
* @param {import("../spec/channel.js").Type} type
|
|
468
|
-
* @returns {DomainArray}
|
|
496
|
+
* Registers collector subscriptions that keep scale domains up to date.
|
|
469
497
|
*/
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
498
|
+
registerDomainSubscriptions() {
|
|
499
|
+
if (this.#domainSubscriptionsRegistered) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (this.isDomainInert()) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const collector = this.getCollector();
|
|
508
|
+
if (!collector) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const encoders = this.mark.encoders;
|
|
513
|
+
if (!encoders) {
|
|
514
|
+
throw new Error("Encoders are not initialized!");
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
this.#domainSubscriptionsRegistered = true;
|
|
518
|
+
|
|
519
|
+
/** @type {Map<import("../scales/scaleResolution.js").default, Set<import("../types/encoder.js").ScaleAccessor>>} */
|
|
520
|
+
const accessorsByResolution = new Map();
|
|
521
|
+
|
|
522
|
+
for (const encoder of Object.values(encoders)) {
|
|
523
|
+
if (!encoder) {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const accessors = encoder.accessors ?? [];
|
|
528
|
+
if (accessors.length === 0) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
for (const accessor of accessors) {
|
|
533
|
+
if (!isScaleAccessor(accessor)) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (accessor.channelDef.domainInert) {
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
const resolution = this.getScaleResolution(
|
|
540
|
+
accessor.scaleChannel
|
|
541
|
+
);
|
|
542
|
+
if (!resolution) {
|
|
543
|
+
throw new Error(
|
|
544
|
+
"Missing scale resolution for channel: " +
|
|
545
|
+
accessor.scaleChannel
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
let accessorsForResolution =
|
|
550
|
+
accessorsByResolution.get(resolution);
|
|
551
|
+
if (!accessorsForResolution) {
|
|
552
|
+
accessorsForResolution = new Set();
|
|
553
|
+
accessorsByResolution.set(
|
|
554
|
+
resolution,
|
|
555
|
+
accessorsForResolution
|
|
556
|
+
);
|
|
484
557
|
}
|
|
485
|
-
|
|
558
|
+
accessorsForResolution.add(accessor);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
486
561
|
|
|
487
|
-
|
|
562
|
+
for (const [resolution, accessors] of accessorsByResolution) {
|
|
563
|
+
if (accessors.size === 0) {
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
const unregister = resolution.registerCollectorSubscriptions(
|
|
567
|
+
collector,
|
|
568
|
+
accessors
|
|
569
|
+
);
|
|
570
|
+
this.registerDisposer(unregister);
|
|
571
|
+
}
|
|
488
572
|
}
|
|
489
573
|
|
|
490
574
|
getZoomLevel() {
|