@vitessce/config 3.0.0 → 3.1.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/index.js +589 -83
- package/dist-tsc/VitessceAutoConfig.d.ts +13 -1
- package/dist-tsc/VitessceAutoConfig.d.ts.map +1 -1
- package/dist-tsc/VitessceAutoConfig.js +318 -87
- package/dist-tsc/VitessceAutoConfig.test.js +599 -71
- package/dist-tsc/VitessceConfig.d.ts +46 -0
- package/dist-tsc/VitessceConfig.d.ts.map +1 -1
- package/dist-tsc/VitessceConfig.js +353 -0
- package/dist-tsc/VitessceConfig.test.js +329 -1
- package/dist-tsc/constants.d.ts +247 -0
- package/dist-tsc/constants.d.ts.map +1 -0
- package/dist-tsc/constants.js +87 -0
- package/dist-tsc/index.d.ts +2 -1
- package/dist-tsc/index.js +2 -1
- package/package.json +4 -4
- package/src/VitessceAutoConfig.js +368 -99
- package/src/VitessceAutoConfig.test.js +626 -76
- package/src/VitessceConfig.js +393 -0
- package/src/VitessceConfig.test.js +339 -0
- package/src/constants.js +94 -0
- package/src/index.js +2 -1
package/src/VitessceConfig.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
1
2
|
import { CoordinationType } from '@vitessce/constants-internal';
|
|
2
3
|
import { fromEntries, getNextScope } from '@vitessce/utils';
|
|
3
4
|
|
|
@@ -101,6 +102,142 @@ export class VitessceConfigDataset {
|
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
function useComplexCoordinationHelper(scopes, coordinationScopes, coordinationScopesBy) {
|
|
106
|
+
// Set this.coordinationScopes and this.coordinationScopesBy by recursion on `scopes`.
|
|
107
|
+
/*
|
|
108
|
+
// Destructured, `scopes` might look like:
|
|
109
|
+
const {
|
|
110
|
+
[CoordinationType.SPATIAL_IMAGE_LAYER]: [
|
|
111
|
+
{
|
|
112
|
+
scope: imageLayerScope,
|
|
113
|
+
children: {
|
|
114
|
+
[CoordinationType.IMAGE]: { scope: imageScope },
|
|
115
|
+
[CoordinationType.SPATIAL_LAYER_VISIBLE]: { scope: imageVisibleScope },
|
|
116
|
+
[CoordinationType.SPATIAL_LAYER_OPACITY]: { scope: imageOpacityScope },
|
|
117
|
+
[CoordinationType.SPATIAL_IMAGE_CHANNEL]: [
|
|
118
|
+
{
|
|
119
|
+
scope: imageChannelScopeR,
|
|
120
|
+
children: {
|
|
121
|
+
[CoordinationType.SPATIAL_TARGET_C]: { scope: rTargetScope },
|
|
122
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: { scope: rColorScope },
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
scope: imageChannelScopeG,
|
|
127
|
+
children: {
|
|
128
|
+
[CoordinationType.SPATIAL_TARGET_C]: { scope: gTargetScope },
|
|
129
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: { scope: gColorScope },
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
// ...
|
|
137
|
+
} = scopes;
|
|
138
|
+
|
|
139
|
+
// This would set the values to:
|
|
140
|
+
this.coordinationScopes = {
|
|
141
|
+
// Add the top-level coordination types to `coordinationScopes`.
|
|
142
|
+
[CoordinationType.SPATIAL_IMAGE_LAYER]: [imageLayerScope.cScope],
|
|
143
|
+
};
|
|
144
|
+
this.coordinationScopesBy = {
|
|
145
|
+
[CoordinationType.SPATIAL_IMAGE_LAYER]: {
|
|
146
|
+
[CoordinationType.IMAGE]: {
|
|
147
|
+
[imageLayerScope.cScope]: imageScope.cScope,
|
|
148
|
+
},
|
|
149
|
+
[CoordinationType.SPATIAL_LAYER_VISIBLE]: {
|
|
150
|
+
[imageLayerScope.cScope]: imageVisibleScope.cScope,
|
|
151
|
+
},
|
|
152
|
+
[CoordinationType.SPATIAL_LAYER_OPACITY]: {
|
|
153
|
+
[imageLayerScope.cScope]: imageOpacityScope.cScope,
|
|
154
|
+
},
|
|
155
|
+
[CoordinationType.SPATIAL_IMAGE_CHANNEL]: {
|
|
156
|
+
[imageLayerScope.cScope]: [imageChannelScopeR.cScope, imageChannelScopeG.cScope],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
[CoordinationType.SPATIAL_IMAGE_CHANNEL]: {
|
|
160
|
+
[CoordinationType.SPATIAL_TARGET_C]: {
|
|
161
|
+
[imageChannelScopeR.cScope]: rTargetScope.cScope,
|
|
162
|
+
[imageChannelScopeG.cScope]: gTargetScope.cScope,
|
|
163
|
+
},
|
|
164
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: {
|
|
165
|
+
[imageChannelScopeR.cScope]: rColorScope.cScope,
|
|
166
|
+
[imageChannelScopeG.cScope]: gColorScope.cScope,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
*/
|
|
171
|
+
|
|
172
|
+
// Recursive inner function.
|
|
173
|
+
function processLevel(parentType, parentScope, levelType, levelVal) {
|
|
174
|
+
if (Array.isArray(levelVal)) {
|
|
175
|
+
// eslint-disable-next-line no-param-reassign
|
|
176
|
+
coordinationScopesBy[parentType] = {
|
|
177
|
+
...(coordinationScopesBy[parentType] || {}),
|
|
178
|
+
[levelType]: {
|
|
179
|
+
...(coordinationScopesBy[parentType]?.[levelType] || {}),
|
|
180
|
+
[parentScope.cScope]: levelVal.map(childVal => childVal.scope.cScope),
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
levelVal.forEach((childVal) => {
|
|
184
|
+
if (childVal.children) {
|
|
185
|
+
// Continue recursion.
|
|
186
|
+
Object.entries(childVal.children)
|
|
187
|
+
.forEach(([nextLevelType, nextLevelVal]) => processLevel(
|
|
188
|
+
levelType, childVal.scope, nextLevelType, nextLevelVal,
|
|
189
|
+
));
|
|
190
|
+
} // Else is the base case: no children
|
|
191
|
+
});
|
|
192
|
+
} else {
|
|
193
|
+
// eslint-disable-next-line no-param-reassign
|
|
194
|
+
coordinationScopesBy[parentType] = {
|
|
195
|
+
...(coordinationScopesBy[parentType] || {}),
|
|
196
|
+
[levelType]: {
|
|
197
|
+
...(coordinationScopesBy[parentType]?.[levelType] || {}),
|
|
198
|
+
[parentScope.cScope]: levelVal.scope.cScope,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
if (levelVal.children) {
|
|
203
|
+
// Continue recursion.
|
|
204
|
+
Object.entries(levelVal.children)
|
|
205
|
+
.forEach(([nextLevelType, nextLevelVal]) => processLevel(
|
|
206
|
+
levelType, levelVal.scope, nextLevelType, nextLevelVal,
|
|
207
|
+
));
|
|
208
|
+
} // Else is the base case: no children
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
Object.entries(scopes).forEach(([topLevelType, topLevelVal]) => {
|
|
213
|
+
if (Array.isArray(topLevelVal)) {
|
|
214
|
+
// eslint-disable-next-line no-param-reassign
|
|
215
|
+
coordinationScopes[topLevelType] = topLevelVal.map(levelVal => levelVal.scope.cScope);
|
|
216
|
+
|
|
217
|
+
topLevelVal.forEach((levelVal) => {
|
|
218
|
+
if (levelVal.children) {
|
|
219
|
+
// Begin recursion.
|
|
220
|
+
Object.entries(levelVal.children)
|
|
221
|
+
.forEach(([nextLevelType, nextLevelVal]) => processLevel(
|
|
222
|
+
topLevelType, levelVal.scope, nextLevelType, nextLevelVal,
|
|
223
|
+
));
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
// eslint-disable-next-line no-param-reassign
|
|
228
|
+
coordinationScopes[topLevelType] = topLevelVal.scope.cScope;
|
|
229
|
+
if (topLevelVal.children) {
|
|
230
|
+
// Begin recursion.
|
|
231
|
+
Object.entries(topLevelVal.children)
|
|
232
|
+
.forEach(([nextLevelType, nextLevelVal]) => processLevel(
|
|
233
|
+
topLevelType, topLevelVal.scope, nextLevelType, nextLevelVal,
|
|
234
|
+
));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
return [coordinationScopes, coordinationScopesBy];
|
|
239
|
+
}
|
|
240
|
+
|
|
104
241
|
/**
|
|
105
242
|
* Class representing a view within a Vitessce layout.
|
|
106
243
|
*/
|
|
@@ -119,6 +256,7 @@ export class VitessceConfigView {
|
|
|
119
256
|
this.view = {
|
|
120
257
|
component,
|
|
121
258
|
coordinationScopes,
|
|
259
|
+
coordinationScopesBy: undefined, // TODO: initialize from parameter?
|
|
122
260
|
x,
|
|
123
261
|
y,
|
|
124
262
|
w,
|
|
@@ -140,6 +278,43 @@ export class VitessceConfigView {
|
|
|
140
278
|
return this;
|
|
141
279
|
}
|
|
142
280
|
|
|
281
|
+
useComplexCoordination(scopes) {
|
|
282
|
+
if (!this.view.coordinationScopes) {
|
|
283
|
+
this.view.coordinationScopes = {};
|
|
284
|
+
}
|
|
285
|
+
if (!this.view.coordinationScopesBy) {
|
|
286
|
+
this.view.coordinationScopesBy = {};
|
|
287
|
+
}
|
|
288
|
+
const [nextCoordinationScopes, nextCoordinationScopesBy] = useComplexCoordinationHelper(
|
|
289
|
+
scopes,
|
|
290
|
+
this.view.coordinationScopes,
|
|
291
|
+
this.view.coordinationScopesBy,
|
|
292
|
+
);
|
|
293
|
+
this.view.coordinationScopes = nextCoordinationScopes;
|
|
294
|
+
this.view.coordinationScopesBy = nextCoordinationScopesBy;
|
|
295
|
+
return this;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Attach meta coordination scopes to this view.
|
|
300
|
+
* @param {VitessceConfigMetaCoordinationScope} metaScope A meta coordination scope instance.
|
|
301
|
+
* @returns {VitessceConfigView} This, to allow chaining.
|
|
302
|
+
*/
|
|
303
|
+
useMetaCoordination(metaScope) {
|
|
304
|
+
if (!this.view.coordinationScopes) {
|
|
305
|
+
this.view.coordinationScopes = {};
|
|
306
|
+
}
|
|
307
|
+
this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] = [
|
|
308
|
+
...(this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] || []),
|
|
309
|
+
metaScope.metaScope.cScope,
|
|
310
|
+
];
|
|
311
|
+
this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] = [
|
|
312
|
+
...(this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] || []),
|
|
313
|
+
metaScope.metaByScope.cScope,
|
|
314
|
+
];
|
|
315
|
+
return this;
|
|
316
|
+
}
|
|
317
|
+
|
|
143
318
|
/**
|
|
144
319
|
* Set the x, y, w, h values for this view.
|
|
145
320
|
* @param {number} x The x-coordinate of the view in the layout.
|
|
@@ -217,6 +392,17 @@ export function vconcat(...views) {
|
|
|
217
392
|
return vcvvc;
|
|
218
393
|
}
|
|
219
394
|
|
|
395
|
+
// would import as CL for convenience
|
|
396
|
+
class CoordinationLevel {
|
|
397
|
+
constructor(value) {
|
|
398
|
+
this.value = value;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export function CL(value) {
|
|
403
|
+
return new CoordinationLevel(value);
|
|
404
|
+
}
|
|
405
|
+
|
|
220
406
|
/**
|
|
221
407
|
* Class representing a coordination scope in the coordination space.
|
|
222
408
|
*/
|
|
@@ -243,6 +429,72 @@ export class VitessceConfigCoordinationScope {
|
|
|
243
429
|
}
|
|
244
430
|
}
|
|
245
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Class representing a pair of coordination scopes,
|
|
434
|
+
* for metaCoordinationScopes and metaCoordinationScopesBy,
|
|
435
|
+
* respectively, in the coordination space.
|
|
436
|
+
*/
|
|
437
|
+
export class VitessceConfigMetaCoordinationScope {
|
|
438
|
+
/**
|
|
439
|
+
* Construct a new coordination scope instance.
|
|
440
|
+
* @param {string} metaScope The name of the coordination scope for metaCoordinationScopes.
|
|
441
|
+
* @param {string} metaByScope The name of the coordination scope for metaCoordinationScopesBy.
|
|
442
|
+
*/
|
|
443
|
+
constructor(metaScope, metaByScope) {
|
|
444
|
+
this.metaScope = new VitessceConfigCoordinationScope(
|
|
445
|
+
CoordinationType.META_COORDINATION_SCOPES,
|
|
446
|
+
metaScope,
|
|
447
|
+
);
|
|
448
|
+
this.metaByScope = new VitessceConfigCoordinationScope(
|
|
449
|
+
CoordinationType.META_COORDINATION_SCOPES_BY,
|
|
450
|
+
metaByScope,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Attach coordination scopes to this meta scope.
|
|
456
|
+
* @param {...VitessceConfigCoordinationScope} args A variable number of
|
|
457
|
+
* coordination scope instances.
|
|
458
|
+
* @returns {VitessceConfigMetaCoordinationScope} This, to allow chaining.
|
|
459
|
+
*/
|
|
460
|
+
useCoordination(...args) {
|
|
461
|
+
const cScopes = args;
|
|
462
|
+
const metaScopesVal = this.metaScope.cValue;
|
|
463
|
+
cScopes.forEach((cScope) => {
|
|
464
|
+
metaScopesVal[cScope.cType] = cScope.cScope;
|
|
465
|
+
});
|
|
466
|
+
this.metaScope.setValue(metaScopesVal);
|
|
467
|
+
return this;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
useComplexCoordination(scopes) {
|
|
471
|
+
if (!this.metaScope.cValue) {
|
|
472
|
+
this.metaScope.setValue({});
|
|
473
|
+
}
|
|
474
|
+
if (!this.metaByScope.cValue) {
|
|
475
|
+
this.metaByScope.setValue({});
|
|
476
|
+
}
|
|
477
|
+
const [metaScopesVal, metaByScopesVal] = useComplexCoordinationHelper(
|
|
478
|
+
scopes,
|
|
479
|
+
this.metaScope.cValue,
|
|
480
|
+
this.metaByScope.cValue,
|
|
481
|
+
);
|
|
482
|
+
this.metaScope.setValue(metaScopesVal);
|
|
483
|
+
this.metaByScope.setValue(metaByScopesVal);
|
|
484
|
+
return this;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Set the coordination value of the coordination scope.
|
|
489
|
+
* @param {any} cValue The value to set.
|
|
490
|
+
* @returns {VitessceConfigCoordinationScope} This, to allow chaining.
|
|
491
|
+
*/
|
|
492
|
+
setValue(cValue) {
|
|
493
|
+
this.cValue = cValue;
|
|
494
|
+
return this;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
246
498
|
/**
|
|
247
499
|
* Class representing a Vitessce view config.
|
|
248
500
|
*/
|
|
@@ -383,6 +635,147 @@ export class VitessceConfig {
|
|
|
383
635
|
return result;
|
|
384
636
|
}
|
|
385
637
|
|
|
638
|
+
addMetaCoordination() {
|
|
639
|
+
const prevMetaScopes = (
|
|
640
|
+
this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES]
|
|
641
|
+
? Object.keys(this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES])
|
|
642
|
+
: []
|
|
643
|
+
);
|
|
644
|
+
const prevMetaByScopes = (
|
|
645
|
+
this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY]
|
|
646
|
+
? Object.keys(this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY])
|
|
647
|
+
: []
|
|
648
|
+
);
|
|
649
|
+
const metaContainer = new VitessceConfigMetaCoordinationScope(
|
|
650
|
+
getNextScope(prevMetaScopes),
|
|
651
|
+
getNextScope(prevMetaByScopes),
|
|
652
|
+
);
|
|
653
|
+
if (!this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES]) {
|
|
654
|
+
this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES] = {};
|
|
655
|
+
}
|
|
656
|
+
if (!this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY]) {
|
|
657
|
+
this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY] = {};
|
|
658
|
+
}
|
|
659
|
+
// eslint-disable-next-line max-len
|
|
660
|
+
this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES][metaContainer.metaScope.cScope] = metaContainer.metaScope;
|
|
661
|
+
// eslint-disable-next-line max-len
|
|
662
|
+
this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY][metaContainer.metaByScope.cScope] = metaContainer.metaByScope;
|
|
663
|
+
return metaContainer;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
addComplexCoordination(input) {
|
|
667
|
+
/*
|
|
668
|
+
// The value for `input` might look like:
|
|
669
|
+
{
|
|
670
|
+
[CoordinationType.SPATIAL_IMAGE_LAYER]: CL([
|
|
671
|
+
{
|
|
672
|
+
[CoordinationType.IMAGE]: 'S-1905-017737_bf',
|
|
673
|
+
[CoordinationType.SPATIAL_LAYER_VISIBLE]: true,
|
|
674
|
+
[CoordinationType.SPATIAL_LAYER_OPACITY]: 1,
|
|
675
|
+
[CoordinationType.SPATIAL_IMAGE_CHANNEL]: CL([
|
|
676
|
+
{
|
|
677
|
+
[CoordinationType.SPATIAL_TARGET_C]: 0,
|
|
678
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: [255, 0, 0],
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
[CoordinationType.SPATIAL_TARGET_C]: 1,
|
|
682
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: [0, 255, 0],
|
|
683
|
+
},
|
|
684
|
+
]),
|
|
685
|
+
},
|
|
686
|
+
]),
|
|
687
|
+
[CoordinationType.SPATIAL_SEGMENTATION_LAYER]: CL([
|
|
688
|
+
{
|
|
689
|
+
[CoordinationType.IMAGE]: 'S-1905-017737',
|
|
690
|
+
[CoordinationType.SPATIAL_LAYER_VISIBLE]: true,
|
|
691
|
+
[CoordinationType.SPATIAL_LAYER_OPACITY]: 1,
|
|
692
|
+
[CoordinationType.SPATIAL_SEGMENTATION_CHANNEL]: CL([
|
|
693
|
+
{
|
|
694
|
+
[CoordinationType.OBS_TYPE]: 'Cortical Interstitia',
|
|
695
|
+
[CoordinationType.SPATIAL_TARGET_C]: 0,
|
|
696
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: [255, 0, 0],
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
[CoordinationType.OBS_TYPE]: 'Non-Globally Sclerotic Glomeruli',
|
|
700
|
+
[CoordinationType.SPATIAL_TARGET_C]: 1,
|
|
701
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: [255, 0, 0],
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
[CoordinationType.OBS_TYPE]: 'Globally Sclerotic Glomeruli',
|
|
705
|
+
[CoordinationType.SPATIAL_TARGET_C]: 2,
|
|
706
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: [255, 0, 0],
|
|
707
|
+
},
|
|
708
|
+
]),
|
|
709
|
+
},
|
|
710
|
+
]),
|
|
711
|
+
}
|
|
712
|
+
// Which would correspond to this `output`,
|
|
713
|
+
// a valid input for `VitessceConfigMetaCoordinationScope.useComplexCoordination()`:
|
|
714
|
+
{
|
|
715
|
+
[CoordinationType.SPATIAL_IMAGE_LAYER]: [
|
|
716
|
+
{
|
|
717
|
+
scope: imageLayerScope,
|
|
718
|
+
children: {
|
|
719
|
+
[CoordinationType.IMAGE]: { scope: imageScope },
|
|
720
|
+
[CoordinationType.SPATIAL_LAYER_VISIBLE]: { scope: imageVisibleScope },
|
|
721
|
+
[CoordinationType.SPATIAL_LAYER_OPACITY]: { scope: imageOpacityScope },
|
|
722
|
+
[CoordinationType.SPATIAL_IMAGE_CHANNEL]: [
|
|
723
|
+
{
|
|
724
|
+
scope: imageChannelScopeR,
|
|
725
|
+
children: {
|
|
726
|
+
[CoordinationType.SPATIAL_TARGET_C]: { scope: rTargetScope },
|
|
727
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: { scope: rColorScope },
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
scope: imageChannelScopeG,
|
|
732
|
+
children: {
|
|
733
|
+
[CoordinationType.SPATIAL_TARGET_C]: { scope: gTargetScope },
|
|
734
|
+
[CoordinationType.SPATIAL_CHANNEL_COLOR]: { scope: gColorScope },
|
|
735
|
+
},
|
|
736
|
+
},
|
|
737
|
+
],
|
|
738
|
+
},
|
|
739
|
+
},
|
|
740
|
+
],
|
|
741
|
+
// ...
|
|
742
|
+
}
|
|
743
|
+
*/
|
|
744
|
+
const processLevel = (level) => {
|
|
745
|
+
const result = {};
|
|
746
|
+
Object.entries(level).forEach(([cType, nextLevelOrInitialValue]) => {
|
|
747
|
+
// Check if value of object is instanceof CoordinationLevel
|
|
748
|
+
// (otherwise assume it is the coordination value).
|
|
749
|
+
if (nextLevelOrInitialValue instanceof CoordinationLevel) {
|
|
750
|
+
const nextLevel = nextLevelOrInitialValue.value;
|
|
751
|
+
if (Array.isArray(nextLevel)) {
|
|
752
|
+
result[cType] = nextLevel.map((nextEl) => {
|
|
753
|
+
const [dummyScope] = this.addCoordination(cType);
|
|
754
|
+
// TODO: set a better initial value for dummy cases.
|
|
755
|
+
dummyScope.setValue('__dummy__');
|
|
756
|
+
return {
|
|
757
|
+
scope: dummyScope,
|
|
758
|
+
children: processLevel(nextEl),
|
|
759
|
+
};
|
|
760
|
+
});
|
|
761
|
+
} else {
|
|
762
|
+
throw new Error('Expected CoordinationLevel.value to be an array.');
|
|
763
|
+
}
|
|
764
|
+
} else {
|
|
765
|
+
// Base case.
|
|
766
|
+
const initialValue = nextLevelOrInitialValue;
|
|
767
|
+
const [scope] = this.addCoordination(cType);
|
|
768
|
+
scope.setValue(initialValue);
|
|
769
|
+
result[cType] = { scope };
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
return result;
|
|
773
|
+
};
|
|
774
|
+
// Begin recursion.
|
|
775
|
+
const output = processLevel(input);
|
|
776
|
+
return output;
|
|
777
|
+
}
|
|
778
|
+
|
|
386
779
|
/**
|
|
387
780
|
* A convenience function for setting up new coordination scopes across a set of views.
|
|
388
781
|
* @param {VitessceConfigView[]} views An array of view objects to link together.
|