@vitessce/neuroglancer 3.9.7 → 3.9.9
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/{ReactNeuroglancer-pv4bM8Yp.js → ReactNeuroglancer-Bxe4YcLF.js} +64 -9
- package/dist/{index-BEPd2Tds.js → index-anGvS-pL.js} +120 -46
- package/dist/index.js +1 -1
- package/dist-tsc/Neuroglancer.d.ts.map +1 -1
- package/dist-tsc/Neuroglancer.js +2 -2
- package/dist-tsc/NeuroglancerSubscriber.d.ts.map +1 -1
- package/dist-tsc/NeuroglancerSubscriber.js +22 -6
- package/dist-tsc/ReactNeuroglancer.d.ts +11 -0
- package/dist-tsc/ReactNeuroglancer.d.ts.map +1 -1
- package/dist-tsc/ReactNeuroglancer.js +60 -5
- package/dist-tsc/data-hook-ng-utils.d.ts +1 -1
- package/dist-tsc/data-hook-ng-utils.d.ts.map +1 -1
- package/dist-tsc/data-hook-ng-utils.js +18 -4
- package/dist-tsc/shader-utils.d.ts +12 -12
- package/dist-tsc/shader-utils.d.ts.map +1 -1
- package/dist-tsc/shader-utils.js +51 -26
- package/dist-tsc/shader-utils.test.js +20 -0
- package/dist-tsc/use-memo-custom-comparison.d.ts.map +1 -1
- package/dist-tsc/use-memo-custom-comparison.js +5 -0
- package/package.json +9 -9
- package/src/Neuroglancer.js +2 -1
- package/src/NeuroglancerSubscriber.js +28 -4
- package/src/ReactNeuroglancer.js +67 -5
- package/src/data-hook-ng-utils.js +21 -2
- package/src/shader-utils.js +79 -26
- package/src/shader-utils.test.js +20 -0
- package/src/use-memo-custom-comparison.js +6 -0
package/dist-tsc/shader-utils.js
CHANGED
|
@@ -12,6 +12,16 @@ import { PALETTE, getDefaultColor } from '@vitessce/utils';
|
|
|
12
12
|
function normalizeColor(rgbColor) {
|
|
13
13
|
return rgbColor.map(c => c / 255);
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* GLSL call to set point marker border width.
|
|
17
|
+
* Set to 0.0 to remove the outline.
|
|
18
|
+
* @param {number} borderWidth
|
|
19
|
+
* @returns {string}
|
|
20
|
+
*/
|
|
21
|
+
function borderWidthGlsl(borderWidth = 0.0) {
|
|
22
|
+
// must be decimal/float value
|
|
23
|
+
return `setPointMarkerBorderWidth(${borderWidth.toFixed(1)});`;
|
|
24
|
+
}
|
|
15
25
|
/**
|
|
16
26
|
* Format a normalized color as a GLSL vec3 literal.
|
|
17
27
|
* @param {[number, number, number]} normalizedColor
|
|
@@ -39,12 +49,13 @@ function toVec4(normalizedColor, alpha) {
|
|
|
39
49
|
* @param {number} opacity Opacity (0-1).
|
|
40
50
|
* @returns {string} A GLSL shader string.
|
|
41
51
|
*/
|
|
42
|
-
export function getSpatialLayerColorShader(staticColor, opacity) {
|
|
52
|
+
export function getSpatialLayerColorShader(staticColor, opacity, borderWidth = 0.0) {
|
|
43
53
|
const norm = normalizeColor(staticColor);
|
|
44
54
|
// lang: glsl
|
|
45
55
|
return `
|
|
46
56
|
void main() {
|
|
47
57
|
setColor(${toVec4(norm, opacity)});
|
|
58
|
+
${borderWidthGlsl(borderWidth)}
|
|
48
59
|
}
|
|
49
60
|
`;
|
|
50
61
|
}
|
|
@@ -58,7 +69,7 @@ export function getSpatialLayerColorShader(staticColor, opacity) {
|
|
|
58
69
|
* @param {string} featureIndexProp The property name for the feature index in the shader.
|
|
59
70
|
* @returns {string} A GLSL shader string.
|
|
60
71
|
*/
|
|
61
|
-
export function getSpatialLayerColorWithSelectionShader(staticColor, opacity, featureIndices, defaultColor, featureIndexProp) {
|
|
72
|
+
export function getSpatialLayerColorWithSelectionShader(staticColor, opacity, featureIndices, defaultColor, featureIndexProp, borderWidth = 0.0) {
|
|
62
73
|
const normStatic = normalizeColor(staticColor);
|
|
63
74
|
const normDefault = normalizeColor(defaultColor);
|
|
64
75
|
const numFeatures = featureIndices.length;
|
|
@@ -76,8 +87,10 @@ export function getSpatialLayerColorWithSelectionShader(staticColor, opacity, fe
|
|
|
76
87
|
}
|
|
77
88
|
if (isSelected) {
|
|
78
89
|
setColor(${toVec4(normStatic, opacity)});
|
|
90
|
+
${borderWidthGlsl(borderWidth)}
|
|
79
91
|
} else {
|
|
80
92
|
setColor(${toVec4(normDefault, opacity)});
|
|
93
|
+
${borderWidthGlsl(borderWidth)}
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
`;
|
|
@@ -91,7 +104,7 @@ export function getSpatialLayerColorWithSelectionShader(staticColor, opacity, fe
|
|
|
91
104
|
* @param {string} featureIndexProp The property name for the feature index in the shader.
|
|
92
105
|
* @returns {string} A GLSL shader string.
|
|
93
106
|
*/
|
|
94
|
-
export function getSpatialLayerColorFilteredShader(staticColor, opacity, featureIndices, featureIndexProp) {
|
|
107
|
+
export function getSpatialLayerColorFilteredShader(staticColor, opacity, featureIndices, featureIndexProp, borderWidth = 0.0) {
|
|
95
108
|
const normStatic = normalizeColor(staticColor);
|
|
96
109
|
const numFeatures = featureIndices.length;
|
|
97
110
|
const indicesArr = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(', ')});`;
|
|
@@ -110,6 +123,7 @@ export function getSpatialLayerColorFilteredShader(staticColor, opacity, feature
|
|
|
110
123
|
discard;
|
|
111
124
|
}
|
|
112
125
|
setColor(${toVec4(normStatic, opacity)});
|
|
126
|
+
${borderWidthGlsl(borderWidth)}
|
|
113
127
|
}
|
|
114
128
|
`;
|
|
115
129
|
}
|
|
@@ -124,12 +138,13 @@ export function getSpatialLayerColorFilteredShader(staticColor, opacity, feature
|
|
|
124
138
|
* @param {number} opacity Opacity (0-1).
|
|
125
139
|
* @returns {string} A GLSL shader string.
|
|
126
140
|
*/
|
|
127
|
-
export function getGeneSelectionNoSelectionShader(staticColor, opacity) {
|
|
141
|
+
export function getGeneSelectionNoSelectionShader(staticColor, opacity, borderWidth = 0.0) {
|
|
128
142
|
const norm = normalizeColor(staticColor);
|
|
129
143
|
// lang: glsl
|
|
130
144
|
return `
|
|
131
145
|
void main() {
|
|
132
146
|
setColor(${toVec4(norm, opacity)});
|
|
147
|
+
${borderWidthGlsl(borderWidth)}
|
|
133
148
|
}
|
|
134
149
|
`;
|
|
135
150
|
}
|
|
@@ -148,7 +163,7 @@ export function getGeneSelectionNoSelectionShader(staticColor, opacity) {
|
|
|
148
163
|
* @param {string} featureIndexProp The property name for the feature index in the shader.
|
|
149
164
|
* @returns {string} A GLSL shader string.
|
|
150
165
|
*/
|
|
151
|
-
export function getGeneSelectionWithSelectionShader(featureIndices, featureColors, staticColor, defaultColor, opacity, featureIndexProp) {
|
|
166
|
+
export function getGeneSelectionWithSelectionShader(featureIndices, featureColors, staticColor, defaultColor, opacity, featureIndexProp, borderWidth = 0.0) {
|
|
152
167
|
const numFeatures = featureIndices.length;
|
|
153
168
|
const normDefault = normalizeColor(defaultColor);
|
|
154
169
|
const normColors = featureColors.map(c => normalizeColor(c));
|
|
@@ -169,6 +184,7 @@ export function getGeneSelectionWithSelectionShader(featureIndices, featureColor
|
|
|
169
184
|
}
|
|
170
185
|
}
|
|
171
186
|
setColor(color);
|
|
187
|
+
${borderWidthGlsl(borderWidth)}
|
|
172
188
|
}
|
|
173
189
|
`;
|
|
174
190
|
}
|
|
@@ -183,7 +199,7 @@ export function getGeneSelectionWithSelectionShader(featureIndices, featureColor
|
|
|
183
199
|
* @param {string} featureIndexProp The property name for the feature index in the shader.
|
|
184
200
|
* @returns {string} A GLSL shader string.
|
|
185
201
|
*/
|
|
186
|
-
export function getGeneSelectionFilteredShader(featureIndices, featureColors, staticColor, opacity, featureIndexProp) {
|
|
202
|
+
export function getGeneSelectionFilteredShader(featureIndices, featureColors, staticColor, opacity, featureIndexProp, borderWidth = 0.0) {
|
|
187
203
|
const numFeatures = featureIndices.length;
|
|
188
204
|
const normColors = featureColors.map(c => normalizeColor(c));
|
|
189
205
|
const normStatic = normalizeColor(staticColor);
|
|
@@ -208,6 +224,7 @@ export function getGeneSelectionFilteredShader(featureIndices, featureColors, st
|
|
|
208
224
|
discard;
|
|
209
225
|
}
|
|
210
226
|
setColor(vec4(matchedColor, ${opacity}));
|
|
227
|
+
${borderWidthGlsl(borderWidth)}
|
|
211
228
|
}
|
|
212
229
|
`;
|
|
213
230
|
}
|
|
@@ -221,7 +238,7 @@ export function getGeneSelectionFilteredShader(featureIndices, featureColors, st
|
|
|
221
238
|
* @param {string} featureIndexProp The property name for the feature index in the shader.
|
|
222
239
|
* @returns {string} A GLSL shader string.
|
|
223
240
|
*/
|
|
224
|
-
export function getRandomByFeatureShader(opacity, featureIndexProp) {
|
|
241
|
+
export function getRandomByFeatureShader(opacity, featureIndexProp, borderWidth = 0.0) {
|
|
225
242
|
const paletteSize = PALETTE.length;
|
|
226
243
|
const normPalette = PALETTE.map(c => normalizeColor(c));
|
|
227
244
|
const paletteDecl = `vec3 palette[${paletteSize}] = vec3[${paletteSize}](${normPalette.map(c => toVec3(c)).join(', ')});`;
|
|
@@ -234,6 +251,7 @@ export function getRandomByFeatureShader(opacity, featureIndexProp) {
|
|
|
234
251
|
if (colorIdx < 0) { colorIdx = -colorIdx; }
|
|
235
252
|
vec3 color = palette[colorIdx];
|
|
236
253
|
setColor(vec4(color, ${opacity}));
|
|
254
|
+
${borderWidthGlsl(borderWidth)}
|
|
237
255
|
}
|
|
238
256
|
`;
|
|
239
257
|
}
|
|
@@ -247,7 +265,7 @@ export function getRandomByFeatureShader(opacity, featureIndexProp) {
|
|
|
247
265
|
* @param {string} featureIndexProp The property name for the feature index in the shader.
|
|
248
266
|
* @returns {string} A GLSL shader string.
|
|
249
267
|
*/
|
|
250
|
-
export function getRandomByFeatureWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp) {
|
|
268
|
+
export function getRandomByFeatureWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp, borderWidth = 0.0) {
|
|
251
269
|
const paletteSize = PALETTE.length;
|
|
252
270
|
const normPalette = PALETTE.map(c => normalizeColor(c));
|
|
253
271
|
const normDefault = normalizeColor(defaultColor);
|
|
@@ -270,8 +288,10 @@ export function getRandomByFeatureWithSelectionShader(featureIndices, defaultCol
|
|
|
270
288
|
int colorIdx = geneIndex - (geneIndex / ${paletteSize}) * ${paletteSize};
|
|
271
289
|
if (colorIdx < 0) { colorIdx = -colorIdx; }
|
|
272
290
|
setColor(vec4(palette[colorIdx], ${opacity}));
|
|
291
|
+
${borderWidthGlsl(borderWidth)}
|
|
273
292
|
} else {
|
|
274
293
|
setColor(${toVec4(normDefault, opacity)});
|
|
294
|
+
${borderWidthGlsl(borderWidth)}
|
|
275
295
|
}
|
|
276
296
|
}
|
|
277
297
|
`;
|
|
@@ -284,7 +304,7 @@ export function getRandomByFeatureWithSelectionShader(featureIndices, defaultCol
|
|
|
284
304
|
* @param {string} featureIndexProp The property name for the feature index in the shader.
|
|
285
305
|
* @returns {string} A GLSL shader string.
|
|
286
306
|
*/
|
|
287
|
-
export function getRandomByFeatureFilteredShader(featureIndices, opacity, featureIndexProp) {
|
|
307
|
+
export function getRandomByFeatureFilteredShader(featureIndices, opacity, featureIndexProp, borderWidth = 0.0) {
|
|
288
308
|
const paletteSize = PALETTE.length;
|
|
289
309
|
const normPalette = PALETTE.map(c => normalizeColor(c));
|
|
290
310
|
const numFeatures = featureIndices.length;
|
|
@@ -308,6 +328,7 @@ export function getRandomByFeatureFilteredShader(featureIndices, opacity, featur
|
|
|
308
328
|
int colorIdx = geneIndex - (geneIndex / ${paletteSize}) * ${paletteSize};
|
|
309
329
|
if (colorIdx < 0) { colorIdx = -colorIdx; }
|
|
310
330
|
setColor(vec4(palette[colorIdx], ${opacity}));
|
|
331
|
+
${borderWidthGlsl(borderWidth)}
|
|
311
332
|
}
|
|
312
333
|
`;
|
|
313
334
|
}
|
|
@@ -338,7 +359,7 @@ function hashToFloatGlsl() {
|
|
|
338
359
|
* @param {string} pointIndexProp The property name for the point index in the shader.
|
|
339
360
|
* @returns {string} A GLSL shader string.
|
|
340
361
|
*/
|
|
341
|
-
export function getRandomPerPointShader(opacity, featureIndexProp, pointIndexProp) {
|
|
362
|
+
export function getRandomPerPointShader(opacity, featureIndexProp, pointIndexProp, borderWidth = 0.0) {
|
|
342
363
|
// lang: glsl
|
|
343
364
|
return `
|
|
344
365
|
${hashToFloatGlsl()}
|
|
@@ -349,6 +370,7 @@ export function getRandomPerPointShader(opacity, featureIndexProp, pointIndexPro
|
|
|
349
370
|
float g = hashToFloat(pointIndex, 1);
|
|
350
371
|
float b = hashToFloat(pointIndex, 2);
|
|
351
372
|
setColor(vec4(r, g, b, ${opacity}));
|
|
373
|
+
${borderWidthGlsl(borderWidth)}
|
|
352
374
|
}
|
|
353
375
|
`;
|
|
354
376
|
}
|
|
@@ -362,7 +384,7 @@ export function getRandomPerPointShader(opacity, featureIndexProp, pointIndexPro
|
|
|
362
384
|
* @param {string} pointIndexProp The property name for the point index in the shader.
|
|
363
385
|
* @returns {string} A GLSL shader string.
|
|
364
386
|
*/
|
|
365
|
-
export function getRandomPerPointWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp, pointIndexProp) {
|
|
387
|
+
export function getRandomPerPointWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp, pointIndexProp, borderWidth = 0.0) {
|
|
366
388
|
const normDefault = normalizeColor(defaultColor);
|
|
367
389
|
const numFeatures = featureIndices.length;
|
|
368
390
|
const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(', ')});`;
|
|
@@ -384,8 +406,10 @@ export function getRandomPerPointWithSelectionShader(featureIndices, defaultColo
|
|
|
384
406
|
float g = hashToFloat(pointIndex, 1);
|
|
385
407
|
float b = hashToFloat(pointIndex, 2);
|
|
386
408
|
setColor(vec4(r, g, b, ${opacity}));
|
|
409
|
+
${borderWidthGlsl(borderWidth)}
|
|
387
410
|
} else {
|
|
388
411
|
setColor(${toVec4(normDefault, opacity)});
|
|
412
|
+
${borderWidthGlsl(borderWidth)}
|
|
389
413
|
}
|
|
390
414
|
}
|
|
391
415
|
`;
|
|
@@ -399,7 +423,7 @@ export function getRandomPerPointWithSelectionShader(featureIndices, defaultColo
|
|
|
399
423
|
* @param {string} pointIndexProp The property name for the point index in the shader.
|
|
400
424
|
* @returns {string} A GLSL shader string.
|
|
401
425
|
*/
|
|
402
|
-
export function getRandomPerPointFilteredShader(featureIndices, opacity, featureIndexProp, pointIndexProp) {
|
|
426
|
+
export function getRandomPerPointFilteredShader(featureIndices, opacity, featureIndexProp, pointIndexProp, borderWidth = 0.0) {
|
|
403
427
|
const numFeatures = featureIndices.length;
|
|
404
428
|
const indicesDecl = `int selectedIndices[${numFeatures}] = int[${numFeatures}](${featureIndices.join(', ')});`;
|
|
405
429
|
// lang: glsl
|
|
@@ -422,11 +446,12 @@ export function getRandomPerPointFilteredShader(featureIndices, opacity, feature
|
|
|
422
446
|
float g = hashToFloat(pointIndex, 1);
|
|
423
447
|
float b = hashToFloat(pointIndex, 2);
|
|
424
448
|
setColor(vec4(r, g, b, ${opacity}));
|
|
449
|
+
${borderWidthGlsl(borderWidth)}
|
|
425
450
|
}
|
|
426
451
|
`;
|
|
427
452
|
}
|
|
428
453
|
export function getPointsShader(layerCoordination) {
|
|
429
|
-
const { theme, featureIndex, spatialLayerOpacity, obsColorEncoding, spatialLayerColor, featureSelection, featureFilterMode, featureColor, featureIndexProp, pointIndexProp, } = layerCoordination;
|
|
454
|
+
const { theme, featureIndex, spatialLayerOpacity, obsColorEncoding, spatialLayerColor, featureSelection, featureFilterMode, featureColor, pointMarkerBorderWidth = 0.0, featureIndexProp, pointIndexProp, } = layerCoordination;
|
|
430
455
|
const defaultColor = getDefaultColor(theme);
|
|
431
456
|
const opacity = spatialLayerOpacity ?? 1.0;
|
|
432
457
|
const staticColor = (Array.isArray(spatialLayerColor) && spatialLayerColor.length === 3
|
|
@@ -496,12 +521,12 @@ export function getPointsShader(layerCoordination) {
|
|
|
496
521
|
// ---- spatialLayerColor ----
|
|
497
522
|
if (obsColorEncoding === 'spatialLayerColor') {
|
|
498
523
|
if (!hasFeatureSelection || !hasResolvedIndices) {
|
|
499
|
-
return getSpatialLayerColorShader(staticColor, opacity);
|
|
524
|
+
return getSpatialLayerColorShader(staticColor, opacity, pointMarkerBorderWidth);
|
|
500
525
|
}
|
|
501
526
|
if (isFiltered) {
|
|
502
|
-
return getSpatialLayerColorFilteredShader(staticColor, opacity, featureIndices, featureIndexProp);
|
|
527
|
+
return getSpatialLayerColorFilteredShader(staticColor, opacity, featureIndices, featureIndexProp, pointMarkerBorderWidth);
|
|
503
528
|
}
|
|
504
|
-
return getSpatialLayerColorWithSelectionShader(staticColor, opacity, featureIndices, defaultColor, featureIndexProp);
|
|
529
|
+
return getSpatialLayerColorWithSelectionShader(staticColor, opacity, featureIndices, defaultColor, featureIndexProp, pointMarkerBorderWidth);
|
|
505
530
|
}
|
|
506
531
|
// ---- geneSelection ----
|
|
507
532
|
if (obsColorEncoding === 'geneSelection') {
|
|
@@ -509,12 +534,12 @@ export function getPointsShader(layerCoordination) {
|
|
|
509
534
|
throw new Error('In order to use gene-based color encoding for Neuroglancer Points, options.featureIndexProp must be specified for the obsPoints.ng-annotations fileType in the Vitessce configuration.');
|
|
510
535
|
}
|
|
511
536
|
if (!hasFeatureSelection || !hasResolvedIndices) {
|
|
512
|
-
return getGeneSelectionNoSelectionShader(staticColor, opacity);
|
|
537
|
+
return getGeneSelectionNoSelectionShader(staticColor, opacity, pointMarkerBorderWidth);
|
|
513
538
|
}
|
|
514
539
|
if (isFiltered) {
|
|
515
|
-
return getGeneSelectionFilteredShader(featureIndices, resolvedFeatureColors, staticColor, opacity, featureIndexProp);
|
|
540
|
+
return getGeneSelectionFilteredShader(featureIndices, resolvedFeatureColors, staticColor, opacity, featureIndexProp, pointMarkerBorderWidth);
|
|
516
541
|
}
|
|
517
|
-
return getGeneSelectionWithSelectionShader(featureIndices, resolvedFeatureColors, staticColor, defaultColor, opacity, featureIndexProp);
|
|
542
|
+
return getGeneSelectionWithSelectionShader(featureIndices, resolvedFeatureColors, staticColor, defaultColor, opacity, featureIndexProp, pointMarkerBorderWidth);
|
|
518
543
|
}
|
|
519
544
|
// ---- randomByFeature ----
|
|
520
545
|
if (obsColorEncoding === 'randomByFeature') {
|
|
@@ -522,12 +547,12 @@ export function getPointsShader(layerCoordination) {
|
|
|
522
547
|
throw new Error('In order to use gene-based color encoding for Neuroglancer Points, options.featureIndexProp must be specified for the obsPoints.ng-annotations fileType in the Vitessce configuration.');
|
|
523
548
|
}
|
|
524
549
|
if (!hasFeatureSelection || !hasResolvedIndices) {
|
|
525
|
-
return getRandomByFeatureShader(opacity, featureIndexProp);
|
|
550
|
+
return getRandomByFeatureShader(opacity, featureIndexProp, pointMarkerBorderWidth);
|
|
526
551
|
}
|
|
527
552
|
if (isFiltered) {
|
|
528
|
-
return getRandomByFeatureFilteredShader(featureIndices, opacity, featureIndexProp);
|
|
553
|
+
return getRandomByFeatureFilteredShader(featureIndices, opacity, featureIndexProp, pointMarkerBorderWidth);
|
|
529
554
|
}
|
|
530
|
-
return getRandomByFeatureWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp);
|
|
555
|
+
return getRandomByFeatureWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp, pointMarkerBorderWidth);
|
|
531
556
|
}
|
|
532
557
|
// ---- random (per point) ----
|
|
533
558
|
if (obsColorEncoding === 'random') {
|
|
@@ -535,13 +560,13 @@ export function getPointsShader(layerCoordination) {
|
|
|
535
560
|
throw new Error('In order to use per-point color encoding for Neuroglancer Points, options.pointIndexProp must be specified for the obsPoints.ng-annotations fileType in the Vitessce configuration.');
|
|
536
561
|
}
|
|
537
562
|
if (!hasFeatureSelection || !hasResolvedIndices) {
|
|
538
|
-
return getRandomPerPointShader(opacity, featureIndexProp, pointIndexProp);
|
|
563
|
+
return getRandomPerPointShader(opacity, featureIndexProp, pointIndexProp, pointMarkerBorderWidth);
|
|
539
564
|
}
|
|
540
565
|
if (isFiltered) {
|
|
541
|
-
return getRandomPerPointFilteredShader(featureIndices, opacity, featureIndexProp, pointIndexProp);
|
|
566
|
+
return getRandomPerPointFilteredShader(featureIndices, opacity, featureIndexProp, pointIndexProp, pointMarkerBorderWidth);
|
|
542
567
|
}
|
|
543
|
-
return getRandomPerPointWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp, pointIndexProp);
|
|
568
|
+
return getRandomPerPointWithSelectionShader(featureIndices, defaultColor, opacity, featureIndexProp, pointIndexProp, pointMarkerBorderWidth);
|
|
544
569
|
}
|
|
545
570
|
// Fallback: static color.
|
|
546
|
-
return getSpatialLayerColorShader(staticColor, opacity);
|
|
571
|
+
return getSpatialLayerColorShader(staticColor, opacity, pointMarkerBorderWidth);
|
|
547
572
|
}
|
|
@@ -29,6 +29,7 @@ describe('getSpatialLayerColorShader', () => {
|
|
|
29
29
|
const expected = `
|
|
30
30
|
void main() {
|
|
31
31
|
setColor(vec4(1, 0.5019607843137255, 0, 0.8));
|
|
32
|
+
setPointMarkerBorderWidth(0.0);
|
|
32
33
|
}
|
|
33
34
|
`;
|
|
34
35
|
expectShaderEqual(result, expected);
|
|
@@ -38,6 +39,7 @@ void main() {
|
|
|
38
39
|
const expected = `
|
|
39
40
|
void main() {
|
|
40
41
|
setColor(vec4(0, 0, 0, 0));
|
|
42
|
+
setPointMarkerBorderWidth(0.0);
|
|
41
43
|
}
|
|
42
44
|
`;
|
|
43
45
|
expectShaderEqual(result, expected);
|
|
@@ -47,6 +49,7 @@ void main() {
|
|
|
47
49
|
const expected = `
|
|
48
50
|
void main() {
|
|
49
51
|
setColor(vec4(1, 1, 1, 1));
|
|
52
|
+
setPointMarkerBorderWidth(0.0);
|
|
50
53
|
}
|
|
51
54
|
`;
|
|
52
55
|
expectShaderEqual(result, expected);
|
|
@@ -67,8 +70,10 @@ void main() {
|
|
|
67
70
|
}
|
|
68
71
|
if (isSelected) {
|
|
69
72
|
setColor(vec4(1, 0, 0, 0.5));
|
|
73
|
+
setPointMarkerBorderWidth(0.0);
|
|
70
74
|
} else {
|
|
71
75
|
setColor(vec4(0.5019607843137255, 0.5019607843137255, 0.5019607843137255, 0.5));
|
|
76
|
+
setPointMarkerBorderWidth(0.0);
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
`;
|
|
@@ -88,8 +93,10 @@ void main() {
|
|
|
88
93
|
}
|
|
89
94
|
if (isSelected) {
|
|
90
95
|
setColor(vec4(0, 1, 0, 1));
|
|
96
|
+
setPointMarkerBorderWidth(0.0);
|
|
91
97
|
} else {
|
|
92
98
|
setColor(vec4(0, 0, 0, 1));
|
|
99
|
+
setPointMarkerBorderWidth(0.0);
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
`;
|
|
@@ -113,6 +120,7 @@ void main() {
|
|
|
113
120
|
discard;
|
|
114
121
|
}
|
|
115
122
|
setColor(vec4(0, 0, 1, 0.9));
|
|
123
|
+
setPointMarkerBorderWidth(0.0);
|
|
116
124
|
}
|
|
117
125
|
`;
|
|
118
126
|
expectShaderEqual(result, expected);
|
|
@@ -127,6 +135,7 @@ describe('getGeneSelectionNoSelectionShader', () => {
|
|
|
127
135
|
const expected = `
|
|
128
136
|
void main() {
|
|
129
137
|
setColor(vec4(0.39215686274509803, 0.7843137254901961, 0.19607843137254902, 0.7));
|
|
138
|
+
setPointMarkerBorderWidth(0.0);
|
|
130
139
|
}
|
|
131
140
|
`;
|
|
132
141
|
expectShaderEqual(result, expected);
|
|
@@ -147,6 +156,7 @@ void main() {
|
|
|
147
156
|
}
|
|
148
157
|
}
|
|
149
158
|
setColor(color);
|
|
159
|
+
setPointMarkerBorderWidth(0.0);
|
|
150
160
|
}
|
|
151
161
|
`;
|
|
152
162
|
expectShaderEqual(result, expected);
|
|
@@ -169,6 +179,7 @@ void main() {
|
|
|
169
179
|
}
|
|
170
180
|
}
|
|
171
181
|
setColor(color);
|
|
182
|
+
setPointMarkerBorderWidth(0.0);
|
|
172
183
|
}
|
|
173
184
|
`;
|
|
174
185
|
expectShaderEqual(result, expected);
|
|
@@ -194,6 +205,7 @@ void main() {
|
|
|
194
205
|
discard;
|
|
195
206
|
}
|
|
196
207
|
setColor(vec4(matchedColor, 0.75));
|
|
208
|
+
setPointMarkerBorderWidth(0.0);
|
|
197
209
|
}
|
|
198
210
|
`;
|
|
199
211
|
expectShaderEqual(result, expected);
|
|
@@ -213,6 +225,7 @@ void main() {
|
|
|
213
225
|
if (colorIdx < 0) { colorIdx = -colorIdx; }
|
|
214
226
|
vec3 color = palette[colorIdx];
|
|
215
227
|
setColor(vec4(color, 0.5));
|
|
228
|
+
setPointMarkerBorderWidth(0.0);
|
|
216
229
|
}
|
|
217
230
|
`;
|
|
218
231
|
expectShaderEqual(result, expected);
|
|
@@ -236,8 +249,10 @@ void main() {
|
|
|
236
249
|
int colorIdx = geneIndex - (geneIndex / 3) * 3;
|
|
237
250
|
if (colorIdx < 0) { colorIdx = -colorIdx; }
|
|
238
251
|
setColor(vec4(palette[colorIdx], 0.8));
|
|
252
|
+
setPointMarkerBorderWidth(0.0);
|
|
239
253
|
} else {
|
|
240
254
|
setColor(vec4(0.19607843137254902, 0.19607843137254902, 0.19607843137254902, 0.8));
|
|
255
|
+
setPointMarkerBorderWidth(0.0);
|
|
241
256
|
}
|
|
242
257
|
}
|
|
243
258
|
`;
|
|
@@ -264,6 +279,7 @@ void main() {
|
|
|
264
279
|
int colorIdx = geneIndex - (geneIndex / 3) * 3;
|
|
265
280
|
if (colorIdx < 0) { colorIdx = -colorIdx; }
|
|
266
281
|
setColor(vec4(palette[colorIdx], 1));
|
|
282
|
+
setPointMarkerBorderWidth(0.0);
|
|
267
283
|
}
|
|
268
284
|
`;
|
|
269
285
|
expectShaderEqual(result, expected);
|
|
@@ -290,6 +306,7 @@ void main() {
|
|
|
290
306
|
float g = hashToFloat(pointIndex, 1);
|
|
291
307
|
float b = hashToFloat(pointIndex, 2);
|
|
292
308
|
setColor(vec4(r, g, b, 0.9));
|
|
309
|
+
setPointMarkerBorderWidth(0.0);
|
|
293
310
|
}
|
|
294
311
|
`;
|
|
295
312
|
expectShaderEqual(result, expected);
|
|
@@ -321,8 +338,10 @@ void main() {
|
|
|
321
338
|
float g = hashToFloat(pointIndex, 1);
|
|
322
339
|
float b = hashToFloat(pointIndex, 2);
|
|
323
340
|
setColor(vec4(r, g, b, 0.5));
|
|
341
|
+
setPointMarkerBorderWidth(0.0);
|
|
324
342
|
} else {
|
|
325
343
|
setColor(vec4(0.39215686274509803, 0.39215686274509803, 0.39215686274509803, 0.5));
|
|
344
|
+
setPointMarkerBorderWidth(0.0);
|
|
326
345
|
}
|
|
327
346
|
}
|
|
328
347
|
`;
|
|
@@ -357,6 +376,7 @@ void main() {
|
|
|
357
376
|
float g = hashToFloat(pointIndex, 1);
|
|
358
377
|
float b = hashToFloat(pointIndex, 2);
|
|
359
378
|
setColor(vec4(r, g, b, 1));
|
|
379
|
+
setPointMarkerBorderWidth(0.0);
|
|
360
380
|
}
|
|
361
381
|
`;
|
|
362
382
|
expectShaderEqual(result, expected);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-memo-custom-comparison.d.ts","sourceRoot":"","sources":["../src/use-memo-custom-comparison.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,wCAPa,CAAC,WACH,MAAM,CAAC,gBACP,GAAG,iBACH,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,GAEvC,CAAC,CAUb;AA6CD,
|
|
1
|
+
{"version":3,"file":"use-memo-custom-comparison.d.ts","sourceRoot":"","sources":["../src/use-memo-custom-comparison.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,wCAPa,CAAC,WACH,MAAM,CAAC,gBACP,GAAG,iBACH,CAAC,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,GAEvC,CAAC,CAUb;AA6CD,kFAgDC;AAED,0FA8EC"}
|
|
@@ -74,6 +74,7 @@ export function customIsEqualForCellColors(prevDeps, nextDeps) {
|
|
|
74
74
|
'obsSetSelection',
|
|
75
75
|
'additionalObsSets',
|
|
76
76
|
'spatialChannelColor',
|
|
77
|
+
'spatialChannelOpacity',
|
|
77
78
|
])) {
|
|
78
79
|
forceUpdate = true;
|
|
79
80
|
}
|
|
@@ -96,6 +97,9 @@ export function customIsEqualForInitialViewerState(prevDeps, nextDeps) {
|
|
|
96
97
|
const curriedShallowDiffByLayerCoordinationWithKeys = (depName, layerScope, keys) => shallowDiffByLayerCoordinationWithKeys(prevDeps, nextDeps, depName, layerScope, keys);
|
|
97
98
|
const curriedShallowDiffByChannelCoordination = (depName, layerScope, channelScope) => shallowDiffByChannelCoordination(prevDeps, nextDeps, depName, layerScope, channelScope);
|
|
98
99
|
const curriedShallowDiffByChannelCoordinationWithKeys = (depName, layerScope, channelScope, keys) => shallowDiffByChannelCoordinationWithKeys(prevDeps, nextDeps, depName, layerScope, channelScope, keys);
|
|
100
|
+
if (['theme', 'showAxisLines'].some(curriedShallowDiff)) {
|
|
101
|
+
forceUpdate = true;
|
|
102
|
+
}
|
|
99
103
|
// Segmentation layers/channels.
|
|
100
104
|
if (['segmentationLayerScopes', 'segmentationChannelScopesByLayer'].some(curriedShallowDiff)) {
|
|
101
105
|
// Force update for all layers since the layerScopes array changed.
|
|
@@ -136,6 +140,7 @@ export function customIsEqualForInitialViewerState(prevDeps, nextDeps) {
|
|
|
136
140
|
'featureSelection',
|
|
137
141
|
'featureFilterMode',
|
|
138
142
|
'featureColor',
|
|
143
|
+
'spatialPointStrokeWidth',
|
|
139
144
|
])
|
|
140
145
|
// For opacity, use an epsilon comparison to avoid too many re-renders, as it affects performance.
|
|
141
146
|
|| (Math.abs(prevDeps?.pointLayerCoordination?.[0]?.[layerScope]?.spatialLayerOpacity - nextDeps?.pointLayerCoordination?.[0]?.[layerScope]?.spatialLayerOpacity)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitessce/neuroglancer",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.9",
|
|
4
4
|
"author": "Gehlenborg Lab",
|
|
5
5
|
"homepage": "http://vitessce.io",
|
|
6
6
|
"repository": {
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"lodash-es": "^4.17.21",
|
|
21
21
|
"three": "^0.154.0",
|
|
22
22
|
"react": "18.3.1",
|
|
23
|
-
"@vitessce/
|
|
24
|
-
"@vitessce/
|
|
25
|
-
"@vitessce/
|
|
26
|
-
"@vitessce/utils": "3.9.
|
|
27
|
-
"@vitessce/
|
|
28
|
-
"@vitessce/
|
|
29
|
-
"@vitessce/tooltip": "3.9.
|
|
30
|
-
"@vitessce/legend": "3.9.
|
|
23
|
+
"@vitessce/constants-internal": "3.9.9",
|
|
24
|
+
"@vitessce/neuroglancer-workers": "3.9.9",
|
|
25
|
+
"@vitessce/styles": "3.9.9",
|
|
26
|
+
"@vitessce/sets-utils": "3.9.9",
|
|
27
|
+
"@vitessce/utils": "3.9.9",
|
|
28
|
+
"@vitessce/vit-s": "3.9.9",
|
|
29
|
+
"@vitessce/tooltip": "3.9.9",
|
|
30
|
+
"@vitessce/legend": "3.9.9"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@testing-library/jest-dom": "^6.6.3",
|
package/src/Neuroglancer.js
CHANGED
|
@@ -92,7 +92,7 @@ export class NeuroglancerComp extends PureComponent {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
render() {
|
|
95
|
-
const { classes, viewerState, cellColorMapping } = this.props;
|
|
95
|
+
const { classes, viewerState, cellColorMapping, onLayerLoadingChange } = this.props;
|
|
96
96
|
|
|
97
97
|
return (
|
|
98
98
|
<>
|
|
@@ -103,6 +103,7 @@ export class NeuroglancerComp extends PureComponent {
|
|
|
103
103
|
brainMapsClientId="NOT_A_VALID_ID"
|
|
104
104
|
viewerState={viewerState}
|
|
105
105
|
onViewerStateChanged={this.onViewerStateChanged}
|
|
106
|
+
onLayerLoadingChange={onLayerLoadingChange}
|
|
106
107
|
bundleRoot={this.bundleRoot}
|
|
107
108
|
cellColorMapping={cellColorMapping}
|
|
108
109
|
ref={this.onRef}
|
|
@@ -79,6 +79,7 @@ export function NeuroglancerSubscriber(props) {
|
|
|
79
79
|
downloadButtonVisible,
|
|
80
80
|
removeGridComponent,
|
|
81
81
|
theme,
|
|
82
|
+
showAxisLines = false,
|
|
82
83
|
title = 'Spatial',
|
|
83
84
|
subtitle = 'Powered by Neuroglancer',
|
|
84
85
|
helpText = ViewHelpMapping.NEUROGLANCER,
|
|
@@ -207,6 +208,7 @@ export function NeuroglancerSubscriber(props) {
|
|
|
207
208
|
CoordinationType.TOOLTIPS_VISIBLE,
|
|
208
209
|
CoordinationType.TOOLTIP_CROSSHAIRS_VISIBLE,
|
|
209
210
|
CoordinationType.LEGEND_VISIBLE,
|
|
211
|
+
CoordinationType.SPATIAL_POINT_STROKE_WIDTH,
|
|
210
212
|
],
|
|
211
213
|
coordinationScopes,
|
|
212
214
|
coordinationScopesBy,
|
|
@@ -289,8 +291,8 @@ export function NeuroglancerSubscriber(props) {
|
|
|
289
291
|
obsSetSelection,
|
|
290
292
|
additionalObsSets,
|
|
291
293
|
spatialChannelColor,
|
|
294
|
+
spatialChannelOpacity,
|
|
292
295
|
} = segmentationChannelCoordination[0][layerScope][channelScope];
|
|
293
|
-
|
|
294
296
|
if (obsColorEncoding === 'spatialChannelColor') {
|
|
295
297
|
// All segments get the same static channel color
|
|
296
298
|
if (layerIndex && spatialChannelColor) {
|
|
@@ -315,6 +317,7 @@ export function NeuroglancerSubscriber(props) {
|
|
|
315
317
|
});
|
|
316
318
|
}
|
|
317
319
|
result[layerScope][channelScope] = ngCellColors;
|
|
320
|
+
result[layerScope].opacity = spatialChannelOpacity ?? 1.0;
|
|
318
321
|
}
|
|
319
322
|
} else if (layerSets && layerIndex) {
|
|
320
323
|
const mergedCellSets = mergeObsSets(layerSets, additionalObsSets);
|
|
@@ -331,6 +334,7 @@ export function NeuroglancerSubscriber(props) {
|
|
|
331
334
|
ngCellColors[i] = rgbToHex(color);
|
|
332
335
|
});
|
|
333
336
|
result[layerScope][channelScope] = ngCellColors;
|
|
337
|
+
result[layerScope].opacity = spatialChannelOpacity ?? 1.0;
|
|
334
338
|
}
|
|
335
339
|
});
|
|
336
340
|
});
|
|
@@ -349,6 +353,7 @@ export function NeuroglancerSubscriber(props) {
|
|
|
349
353
|
// Obtain the Neuroglancer viewerState object.
|
|
350
354
|
const initalViewerState = useNeuroglancerViewerState(
|
|
351
355
|
theme,
|
|
356
|
+
showAxisLines,
|
|
352
357
|
segmentationLayerScopes,
|
|
353
358
|
segmentationChannelScopesByLayer,
|
|
354
359
|
segmentationLayerCoordination,
|
|
@@ -403,6 +408,9 @@ export function NeuroglancerSubscriber(props) {
|
|
|
403
408
|
orbit: spatialRotationOrbit,
|
|
404
409
|
});
|
|
405
410
|
|
|
411
|
+
// Track layer loading state for showing loading indicator
|
|
412
|
+
const [isLayersLoaded, setIsLayersLoaded] = useState(false);
|
|
413
|
+
|
|
406
414
|
// Track the last coord values we saw, and only mark "vitessce"
|
|
407
415
|
// when *those* actually change. This prevents cell set renders
|
|
408
416
|
// from spoofing the source.
|
|
@@ -566,7 +574,10 @@ export function NeuroglancerSubscriber(props) {
|
|
|
566
574
|
const result = {};
|
|
567
575
|
segmentationLayerScopes?.forEach((layerScope) => {
|
|
568
576
|
const channelScope = segmentationChannelScopesByLayer?.[layerScope]?.[0];
|
|
569
|
-
result[layerScope] =
|
|
577
|
+
result[layerScope] = {
|
|
578
|
+
colors: segmentationColorMapping?.[layerScope]?.[channelScope] ?? {},
|
|
579
|
+
opacity: segmentationColorMapping?.[layerScope]?.opacity ?? 1.0,
|
|
580
|
+
};
|
|
570
581
|
});
|
|
571
582
|
return result;
|
|
572
583
|
}, [segmentationColorMapping, segmentationLayerScopes, segmentationChannelScopesByLayer]);
|
|
@@ -720,12 +731,13 @@ export function NeuroglancerSubscriber(props) {
|
|
|
720
731
|
|
|
721
732
|
const updatedLayers = current?.layers?.map((layer, idx) => {
|
|
722
733
|
const layerScope = segmentationLayerScopes?.[idx];
|
|
723
|
-
const layerColorMapping = cellColorMappingByLayer?.[layerScope] ?? {};
|
|
734
|
+
const layerColorMapping = cellColorMappingByLayer?.[layerScope]?.colors ?? {};
|
|
724
735
|
const layerSegments = Object.keys(layerColorMapping);
|
|
725
736
|
return {
|
|
726
737
|
...layer,
|
|
727
738
|
segments: layerSegments,
|
|
728
739
|
segmentColors: layerColorMapping,
|
|
740
|
+
objectAlpha: cellColorMappingByLayer?.[layerScope]?.opacity ?? 1.0,
|
|
729
741
|
};
|
|
730
742
|
}) ?? [];
|
|
731
743
|
|
|
@@ -758,6 +770,10 @@ export function NeuroglancerSubscriber(props) {
|
|
|
758
770
|
setCellHighlight(String(obsId));
|
|
759
771
|
}, [setCellHighlight]);
|
|
760
772
|
|
|
773
|
+
const handleLayerLoadingChange = useCallback((isLoaded) => {
|
|
774
|
+
setIsLayersLoaded(isLoaded);
|
|
775
|
+
}, []);
|
|
776
|
+
|
|
761
777
|
// TODO: if all cells are deselected, a black view is shown, rather we want to show empty NG view?
|
|
762
778
|
// if (!cellColorMapping || Object.keys(cellColorMapping).length === 0) {
|
|
763
779
|
// return;
|
|
@@ -777,7 +793,7 @@ export function NeuroglancerSubscriber(props) {
|
|
|
777
793
|
closeButtonVisible={closeButtonVisible}
|
|
778
794
|
downloadButtonVisible={downloadButtonVisible}
|
|
779
795
|
removeGridComponent={removeGridComponent}
|
|
780
|
-
isReady={isReady}
|
|
796
|
+
isReady={isReady && isLayersLoaded}
|
|
781
797
|
errors={errors}
|
|
782
798
|
withPadding={false}
|
|
783
799
|
guideUrl={GUIDE_URL}
|
|
@@ -788,10 +804,17 @@ export function NeuroglancerSubscriber(props) {
|
|
|
788
804
|
<MultiLegend
|
|
789
805
|
theme="dark"
|
|
790
806
|
maxHeight={ngHeight}
|
|
807
|
+
|
|
808
|
+
// Segmentations
|
|
791
809
|
segmentationLayerScopes={segmentationLayerScopes}
|
|
792
810
|
segmentationLayerCoordination={segmentationLayerCoordination}
|
|
793
811
|
segmentationChannelScopesByLayer={segmentationChannelScopesByLayer}
|
|
794
812
|
segmentationChannelCoordination={segmentationChannelCoordination}
|
|
813
|
+
|
|
814
|
+
// Points
|
|
815
|
+
pointLayerScopes={pointLayerScopes}
|
|
816
|
+
pointLayerCoordination={pointLayerCoordination}
|
|
817
|
+
pointMultiIndicesData={pointMultiIndicesData}
|
|
795
818
|
/>
|
|
796
819
|
</div>
|
|
797
820
|
|
|
@@ -802,6 +825,7 @@ export function NeuroglancerSubscriber(props) {
|
|
|
802
825
|
viewerState={derivedViewerState}
|
|
803
826
|
cellColorMapping={cellColorMappingByLayer}
|
|
804
827
|
setViewerState={handleStateUpdate}
|
|
828
|
+
onLayerLoadingChange={handleLayerLoadingChange}
|
|
805
829
|
/>
|
|
806
830
|
</div>
|
|
807
831
|
) : null}
|