@vitessce/gl 3.1.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{deflate-c9746f58.js → deflate-69c280fb.js} +1 -1
  2. package/dist/{index-72755d2f.js → index-2a7f1ae0.js} +21935 -5890
  3. package/dist/index.js +14 -13
  4. package/dist/{jpeg-cb74431a.js → jpeg-95f78026.js} +1 -1
  5. package/dist/{lerc-5dffa929.js → lerc-5320d7fa.js} +1 -1
  6. package/dist/{lzw-85fa08a9.js → lzw-8d3691e0.js} +1 -1
  7. package/dist/{packbits-6b8314bf.js → packbits-2846ed6b.js} +1 -1
  8. package/dist/{raw-f12c17bf.js → raw-b0ec4406.js} +1 -1
  9. package/dist/{webimage-99c1b585.js → webimage-a17e81f9.js} +1 -1
  10. package/dist-tsc/BitmaskLayerBeta.d.ts +152 -0
  11. package/dist-tsc/BitmaskLayerBeta.d.ts.map +1 -0
  12. package/dist-tsc/BitmaskLayerBeta.js +253 -0
  13. package/dist-tsc/SelectionLayer.d.ts +1 -0
  14. package/dist-tsc/SelectionLayer.d.ts.map +1 -1
  15. package/dist-tsc/SelectionLayer.js +45 -31
  16. package/dist-tsc/bitmask-layer-beta-shaders.d.ts +3 -0
  17. package/dist-tsc/bitmask-layer-beta-shaders.d.ts.map +1 -0
  18. package/dist-tsc/bitmask-layer-beta-shaders.js +212 -0
  19. package/dist-tsc/bitmask-utils.d.ts +12 -0
  20. package/dist-tsc/bitmask-utils.d.ts.map +1 -0
  21. package/dist-tsc/bitmask-utils.js +89 -0
  22. package/dist-tsc/bitmask-utils.test.d.ts +2 -0
  23. package/dist-tsc/bitmask-utils.test.d.ts.map +1 -0
  24. package/dist-tsc/bitmask-utils.test.js +72 -0
  25. package/dist-tsc/index.d.ts +2 -1
  26. package/dist-tsc/index.js +2 -1
  27. package/dist-tsc/selection-utils.d.ts +3 -3
  28. package/dist-tsc/selection-utils.d.ts.map +1 -1
  29. package/dist-tsc/selection-utils.js +26 -28
  30. package/dist-tsc/viv.d.ts +1 -1
  31. package/dist-tsc/viv.js +1 -1
  32. package/package.json +3 -2
  33. package/src/BitmaskLayerBeta.js +360 -0
  34. package/src/SelectionLayer.js +60 -42
  35. package/src/bitmask-layer-beta-shaders.js +214 -0
  36. package/src/bitmask-utils.js +99 -0
  37. package/src/bitmask-utils.test.js +91 -0
  38. package/src/index.js +3 -1
  39. package/src/selection-utils.js +13 -17
  40. package/src/viv.js +1 -0
@@ -0,0 +1,214 @@
1
+ import { colormaps } from './glsl/index.js';
2
+
3
+ export const vs = `
4
+ #define SHADER_NAME bitmask-layer-vertex-shader
5
+
6
+ attribute vec2 texCoords;
7
+ attribute vec3 positions;
8
+ attribute vec3 positions64Low;
9
+ attribute vec3 instancePickingColors;
10
+
11
+ varying vec2 vTexCoord;
12
+
13
+ void main(void) {
14
+ geometry.worldPosition = positions;
15
+ geometry.uv = texCoords;
16
+ geometry.pickingColor = instancePickingColors;
17
+ gl_Position = project_position_to_clipspace(positions, positions64Low, vec3(0.0), geometry.position);
18
+ DECKGL_FILTER_GL_POSITION(gl_Position, geometry);
19
+ vTexCoord = texCoords;
20
+ vec4 color = vec4(0.0);
21
+ DECKGL_FILTER_COLOR(color, geometry);
22
+ }
23
+ `;
24
+
25
+ export const fs = `
26
+ #define SHADER_NAME bitmask-layer-fragment-shader
27
+ precision highp float;
28
+
29
+ ${colormaps}
30
+
31
+ // Note: can have a maximum of 16 textures in most browsers
32
+ // Reference: https://webglreport.com/
33
+
34
+ // Data (mask) texture
35
+ uniform sampler2D channel0;
36
+ uniform sampler2D channel1;
37
+ uniform sampler2D channel2;
38
+ uniform sampler2D channel3;
39
+ uniform sampler2D channel4;
40
+ uniform sampler2D channel5;
41
+ uniform sampler2D channel6;
42
+
43
+ // Color texture
44
+ uniform float hovered;
45
+
46
+ // Channel-specific properties
47
+ uniform bool channelsVisible[7];
48
+ uniform float channelOpacities[7];
49
+ uniform bool channelIsStaticColorMode[7]; // TODO: should this be a single float?
50
+ uniform bool channelIsSetColorMode[7]; // TODO: should this be a single float?
51
+
52
+ // TODO: can array of tuples/vec2 be used?
53
+ uniform float channelColormapRangeStarts[7];
54
+ uniform float channelColormapRangeEnds[7];
55
+
56
+ uniform float multiFeatureTexSize;
57
+
58
+ // Use one expressionTex for all channels, using an offset mechanism.
59
+ uniform sampler2D valueTex;
60
+ uniform float valueTexOffsets[7];
61
+ uniform float valueTexHeight;
62
+
63
+ // Textures for set colors, using the same offset mechanism.
64
+ uniform sampler2D colorTex;
65
+ uniform float colorTexOffsets[7];
66
+ uniform float colorTexHeight;
67
+
68
+
69
+ // Static colors
70
+ // TODO: For some reason I cannot use uniform vec3 colors[7]; and i cannot figure out why.
71
+ uniform vec3 color0;
72
+ uniform vec3 color1;
73
+ uniform vec3 color2;
74
+ uniform vec3 color3;
75
+ uniform vec3 color4;
76
+ uniform vec3 color5;
77
+ uniform vec3 color6;
78
+
79
+ // Info for edge-only mode
80
+ uniform float scaleFactor;
81
+ uniform bool channelsFilled[7];
82
+ uniform float channelStrokeWidths[7];
83
+
84
+ // opacity
85
+ uniform float opacity;
86
+
87
+ varying vec2 vTexCoord;
88
+
89
+ vec3 sampleAndGetData(sampler2D dataTex, vec2 coord, bool isFilled, float strokeWidth, bool isOn) {
90
+ float sampledData = texture(dataTex, coord).r;
91
+ float clampedSampledData = max(0., min(sampledData, 1.));
92
+
93
+ bool isEdge = true;
94
+
95
+ if(!isFilled) {
96
+ vec2 uTextureSize = vec2(2048.0, 2048.0);
97
+ vec2 onePixel = vec2(1.0, 1.0) / uTextureSize;
98
+
99
+ // Vary the edgeSize based on user-defined stroke width.
100
+ float edgeSize = 150.0 * strokeWidth * scaleFactor;
101
+
102
+ float pixN = texture(dataTex, coord + vec2(0.0, onePixel.y * edgeSize)).r;
103
+ float pixS = texture(dataTex, coord - vec2(0.0, onePixel.y * edgeSize)).r;
104
+ float pixW = texture(dataTex, coord + vec2(onePixel.x * edgeSize, 0.0)).r;
105
+ float pixE = texture(dataTex, coord - vec2(onePixel.x * edgeSize, 0.0)).r;
106
+
107
+ float pixNW = texture(dataTex, coord + vec2(onePixel.y * edgeSize, onePixel.y * edgeSize)).r;
108
+ float pixNE = texture(dataTex, coord + vec2(-1.0 * onePixel.x * edgeSize, onePixel.y * edgeSize)).r;
109
+ float pixSW = texture(dataTex, coord - vec2(onePixel.x * edgeSize, onePixel.y * edgeSize)).r;
110
+ float pixSE = texture(dataTex, coord - vec2(-1.0 * onePixel.x * edgeSize, onePixel.y * edgeSize)).r;
111
+
112
+ isEdge = (pixN != sampledData || pixS != sampledData || pixW != sampledData || pixE != sampledData || pixNW != sampledData || pixNE != sampledData || pixSW != sampledData || pixSE != sampledData);
113
+ }
114
+ // Return a tuple of (sampledData, isEdge)
115
+ return vec3(clampedSampledData * float(isOn), sampledData, float(isEdge));
116
+ }
117
+
118
+ vec4 dataToColor(vec3 sampledDataAndIsEdge, bool isStaticColorMode, vec3 channelColor, float channelOpacity, float valueOffset, float rangeStart, float rangeEnd, bool isSetColorMode, float setColorOffset) {
119
+ float clampedSampledDataAndIsOn = sampledDataAndIsEdge.x;
120
+ float sampledData = sampledDataAndIsEdge.y;
121
+ float isEdge = sampledDataAndIsEdge.z;
122
+
123
+
124
+ vec4 hoveredColor = float(sampledData == hovered && sampledData > 0. && hovered > 0.) * vec4(0., 0., 1., 1.);
125
+
126
+ // Colors are laid out corresponding to ids in row-major order in the texture. So if width of the texture is 10, and you want ID 25,
127
+ // you need coordinate (1, 4) (i.e 2 rows down, and 5 columns over indexed from 0 for a total of 25 units covered in row major order).
128
+ float offsetSampledData = sampledData + valueOffset - 1.0;
129
+ vec2 colorTexCoord = vec2(mod(offsetSampledData, multiFeatureTexSize) / multiFeatureTexSize, floor(offsetSampledData / multiFeatureTexSize) / (valueTexHeight - 1.));
130
+
131
+ // Get expression value
132
+ float expressionValue = texture(valueTex, colorTexCoord).r / 255.;
133
+ float scaledExpressionValue = (expressionValue - rangeStart) / max(0.005, (rangeEnd - rangeStart));
134
+
135
+
136
+ // Get set color index value
137
+ vec2 setIndicesTexCoord = vec2(mod(offsetSampledData, multiFeatureTexSize) / multiFeatureTexSize, floor(offsetSampledData / multiFeatureTexSize) / (valueTexHeight - 1.));
138
+ float setColorIndex = texture(valueTex, setIndicesTexCoord).r;
139
+
140
+ // Initialize to the default "null" color.
141
+ vec3 setColor = vec3(200. / 255., 200. / 255., 200. / 255.);
142
+ if(setColorIndex != 0.) {
143
+ // Subtract one from setColorIndex because we have already checked for the "null" value.
144
+ setColorIndex = setColorIndex - 1.;
145
+
146
+ float setColorOffsetR = (setColorIndex + setColorOffset) * 3.0 + 0.0;
147
+ vec2 setColorTexCoordR = vec2(mod(setColorOffsetR, multiFeatureTexSize) / multiFeatureTexSize, floor(setColorOffsetR / multiFeatureTexSize) / (colorTexHeight - 1.));
148
+ float setColorR = texture(colorTex, setColorTexCoordR).r / 255.;
149
+
150
+ float setColorOffsetG = (setColorIndex + setColorOffset) * 3.0 + 1.0;
151
+ vec2 setColorTexCoordG = vec2(mod(setColorOffsetG, multiFeatureTexSize) / multiFeatureTexSize, floor(setColorOffsetG / multiFeatureTexSize) / (colorTexHeight - 1.));
152
+ float setColorG = texture(colorTex, setColorTexCoordG).r / 255.;
153
+
154
+ float setColorOffsetB = (setColorIndex + setColorOffset) * 3.0 + 2.0;
155
+ vec2 setColorTexCoordB = vec2(mod(setColorOffsetB, multiFeatureTexSize) / multiFeatureTexSize, floor(setColorOffsetB / multiFeatureTexSize) / (colorTexHeight - 1.));
156
+ float setColorB = texture(colorTex, setColorTexCoordB).r / 255.;
157
+
158
+ setColor = vec3(setColorR, setColorG, setColorB);
159
+ }
160
+
161
+
162
+ vec4 sampledColor = (1. - (float(isStaticColorMode) + float(isSetColorMode))) * vec4(COLORMAP_FUNC(clamp(scaledExpressionValue, 0.0, 1.0)).rgb, channelOpacity) + float(isStaticColorMode) * vec4(channelColor.rgb, channelOpacity) + float(isSetColorMode) * vec4(setColor, channelOpacity);
163
+ // Only return a color if the data is non-zero.
164
+
165
+ return clampedSampledDataAndIsOn * isEdge * sampledColor;
166
+ }
167
+
168
+ void main() {
169
+
170
+ // Get the color and alpha value for each channel.
171
+ vec3 dat0 = sampleAndGetData(channel0, vTexCoord, channelsFilled[0], channelStrokeWidths[0], channelsVisible[0]);
172
+ vec3 dat1 = sampleAndGetData(channel1, vTexCoord, channelsFilled[1], channelStrokeWidths[1], channelsVisible[1]);
173
+ vec3 dat2 = sampleAndGetData(channel2, vTexCoord, channelsFilled[2], channelStrokeWidths[2], channelsVisible[2]);
174
+ vec3 dat3 = sampleAndGetData(channel3, vTexCoord, channelsFilled[3], channelStrokeWidths[3], channelsVisible[3]);
175
+ vec3 dat4 = sampleAndGetData(channel4, vTexCoord, channelsFilled[4], channelStrokeWidths[4], channelsVisible[4]);
176
+ vec3 dat5 = sampleAndGetData(channel5, vTexCoord, channelsFilled[5], channelStrokeWidths[5], channelsVisible[5]);
177
+ vec3 dat6 = sampleAndGetData(channel6, vTexCoord, channelsFilled[6], channelStrokeWidths[6], channelsVisible[6]);
178
+
179
+ vec4 val0 = dataToColor(dat0, channelIsStaticColorMode[0], color0, channelOpacities[0], valueTexOffsets[0], channelColormapRangeStarts[0], channelColormapRangeEnds[0], channelIsSetColorMode[0], colorTexOffsets[0]);
180
+ vec4 val1 = dataToColor(dat1, channelIsStaticColorMode[1], color1, channelOpacities[1], valueTexOffsets[1], channelColormapRangeStarts[1], channelColormapRangeEnds[1], channelIsSetColorMode[1], colorTexOffsets[1]);
181
+ vec4 val2 = dataToColor(dat2, channelIsStaticColorMode[2], color2, channelOpacities[2], valueTexOffsets[2], channelColormapRangeStarts[2], channelColormapRangeEnds[2], channelIsSetColorMode[2], colorTexOffsets[2]);
182
+ vec4 val3 = dataToColor(dat3, channelIsStaticColorMode[3], color3, channelOpacities[3], valueTexOffsets[3], channelColormapRangeStarts[3], channelColormapRangeEnds[3], channelIsSetColorMode[3], colorTexOffsets[3]);
183
+ vec4 val4 = dataToColor(dat4, channelIsStaticColorMode[4], color4, channelOpacities[4], valueTexOffsets[4], channelColormapRangeStarts[4], channelColormapRangeEnds[4], channelIsSetColorMode[4], colorTexOffsets[4]);
184
+ vec4 val5 = dataToColor(dat5, channelIsStaticColorMode[5], color5, channelOpacities[5], valueTexOffsets[5], channelColormapRangeStarts[5], channelColormapRangeEnds[5], channelIsSetColorMode[5], colorTexOffsets[5]);
185
+ vec4 val6 = dataToColor(dat6, channelIsStaticColorMode[6], color6, channelOpacities[6], valueTexOffsets[6], channelColormapRangeStarts[6], channelColormapRangeEnds[6], channelIsSetColorMode[6], colorTexOffsets[6]);
186
+
187
+ // If all of the channels are "empty", then discard this pixel so that it is not considered during picking.
188
+ float emptyDat = 0.;
189
+ if(dat0.x == emptyDat && dat1.x == emptyDat && dat2.x == emptyDat && dat3.x == emptyDat && dat4.x == emptyDat && dat5.x == emptyDat && dat6.x == emptyDat) {
190
+ discard;
191
+ }
192
+
193
+ // If the next channel color and the currently stored color (gl_FragColor) are identical,
194
+ // or the next channel color is transparent black,
195
+ // just use the currently stored color. Repeat this for all channels.
196
+
197
+ // Mix colors where necessary, using the alpha value of the next channel as the weight.
198
+ // Use the maximum alpha value as the resulting alpha value.
199
+ gl_FragColor = val0;
200
+ gl_FragColor = (val1 == gl_FragColor || val1 == vec4(0.)) ? gl_FragColor : vec4(mix(gl_FragColor, val1, val1.a).rgb, max(gl_FragColor.a, val1.a));
201
+ gl_FragColor = (val2 == gl_FragColor || val2 == vec4(0.)) ? gl_FragColor : vec4(mix(gl_FragColor, val2, val2.a).rgb, max(gl_FragColor.a, val2.a));
202
+ gl_FragColor = (val3 == gl_FragColor || val3 == vec4(0.)) ? gl_FragColor : vec4(mix(gl_FragColor, val3, val3.a).rgb, max(gl_FragColor.a, val3.a));
203
+ gl_FragColor = (val4 == gl_FragColor || val4 == vec4(0.)) ? gl_FragColor : vec4(mix(gl_FragColor, val4, val4.a).rgb, max(gl_FragColor.a, val4.a));
204
+ gl_FragColor = (val5 == gl_FragColor || val5 == vec4(0.)) ? gl_FragColor : vec4(mix(gl_FragColor, val5, val5.a).rgb, max(gl_FragColor.a, val5.a));
205
+ gl_FragColor = (val6 == gl_FragColor || val6 == vec4(0.)) ? gl_FragColor : vec4(mix(gl_FragColor, val6, val6.a).rgb, max(gl_FragColor.a, val6.a));
206
+
207
+
208
+
209
+ // TODO: multiply the resulting channel-level opacity value by the layer-level opacity value.
210
+
211
+ geometry.uv = vTexCoord;
212
+ DECKGL_FILTER_COLOR(gl_FragColor, geometry);
213
+ }
214
+ `;
@@ -0,0 +1,99 @@
1
+ import { extent } from 'd3-array';
2
+
3
+
4
+ function normalize(arr) {
5
+ const [min, max] = extent(arr);
6
+ const ratio = 255 / (max - min);
7
+ const data = new Uint8Array(
8
+ arr.map(i => Math.floor((i - min) * ratio)),
9
+ );
10
+ return data;
11
+ }
12
+
13
+ /**
14
+ *
15
+ * @param {array[]} multiFeatureValues One array per channel.
16
+ * @param {object[]} setColorValues One object per channel.
17
+ * @param {boolean[]} channelIsSetColorMode Whether the channel
18
+ * colors should use obsSet colors or quantitative feature values.
19
+ * @param {number} texSize The width of the texture; the height
20
+ * will be determined by the length of the concatenated values.
21
+ * @returns
22
+ */
23
+ export function multiSetsToTextureData(
24
+ multiFeatureValues, setColorValues, channelIsSetColorMode, texSize,
25
+ ) {
26
+ let totalValuesLength = 0;
27
+ let totalColorsLength = 0;
28
+
29
+ channelIsSetColorMode.forEach((isSetColorMode, channelIndex) => {
30
+ if (isSetColorMode) {
31
+ totalValuesLength += setColorValues[channelIndex]?.obsIndex?.length || 0;
32
+ totalColorsLength += (setColorValues[channelIndex]?.setColors?.length || 0) * 3;
33
+ } else {
34
+ totalValuesLength += multiFeatureValues[channelIndex]?.length || 0;
35
+ }
36
+ });
37
+
38
+ const valueTexHeight = Math.max(2, Math.ceil(totalValuesLength / texSize));
39
+ const colorTexHeight = Math.max(2, Math.ceil(totalColorsLength / texSize));
40
+
41
+ if (valueTexHeight > texSize) {
42
+ console.error('Error: length of concatenated quantitative feature values larger than maximum texture size');
43
+ }
44
+ if (colorTexHeight > texSize) {
45
+ console.error('Error: length of concatenated quantitative feature values larger than maximum texture size');
46
+ }
47
+ // Array for texture containing color indices.
48
+ const totalData = new Uint8Array(texSize * valueTexHeight);
49
+ // Array for texture containing color RGB values.
50
+ const totalColors = new Uint8Array(texSize * colorTexHeight);
51
+
52
+ // Per-channel offsets into the texture arrays.
53
+ const indicesOffsets = [];
54
+ const colorsOffsets = []; // Color offsets need to be multiplied by 3 in the shader.
55
+ let indexOffset = 0;
56
+ let colorOffset = 0;
57
+ // Iterate over the data for each channel.
58
+ channelIsSetColorMode.forEach((isSetColorMode, channelIndex) => {
59
+ if (isSetColorMode) {
60
+ const { setColorIndices, setColors, obsIndex } = setColorValues[channelIndex] || {};
61
+ if (setColorIndices && setColors && obsIndex) {
62
+ for (let i = 0; i < obsIndex.length; i++) {
63
+ // We add one here to account for i being 0-based but the pixel values being 1-based
64
+ // (to account for zero indicating the background of the segmentation bitmask).
65
+ const colorIndex = setColorIndices.get(String(i + 1));
66
+ // Add one to the color index, so that we can use zero to indicate a "null" set color.
67
+ totalData[indexOffset + i] = colorIndex === undefined ? 0 : colorIndex + 1;
68
+ }
69
+ for (let i = 0; i < setColors.length; i++) {
70
+ const { color: [r, g, b] } = setColors[i];
71
+ totalColors[(colorOffset + i) * 3 + 0] = r;
72
+ totalColors[(colorOffset + i) * 3 + 1] = g;
73
+ totalColors[(colorOffset + i) * 3 + 2] = b;
74
+ }
75
+ }
76
+ indicesOffsets.push(indexOffset);
77
+ colorsOffsets.push(colorOffset);
78
+ indexOffset += (obsIndex?.length || 0);
79
+ colorOffset += (setColors?.length || 0);
80
+ } else {
81
+ const featureArr = multiFeatureValues[channelIndex];
82
+ // TODO: are these values always already normalized?
83
+ totalData.set(normalize(featureArr), indexOffset);
84
+ indicesOffsets.push(indexOffset);
85
+ indexOffset += featureArr.length;
86
+ // Add a color offset so that the number of offsets still equals the number of channels.
87
+ colorsOffsets.push(colorOffset);
88
+ }
89
+ });
90
+
91
+ return [
92
+ totalData,
93
+ valueTexHeight,
94
+ indicesOffsets,
95
+ totalColors,
96
+ colorTexHeight,
97
+ colorsOffsets,
98
+ ];
99
+ }
@@ -0,0 +1,91 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ multiSetsToTextureData,
4
+ } from './bitmask-utils.js';
5
+
6
+ describe('bitmask utils', () => {
7
+ describe('multiSetsToTextureData', () => {
8
+ it('gets all scope names for a particular coordination type', () => {
9
+ const multiFeatureValues = [
10
+ [1, 2, 3, 255, 1000], // 5 expression values, one per cell
11
+ [10, 20, 30], // 3 expression values, one per glomerulus
12
+ ];
13
+
14
+ const setColorValues = [
15
+ {
16
+ setColorIndices: (new Map([
17
+ ['4', 0],
18
+ ['5', 1],
19
+ ['2', 1],
20
+ ['3', 2],
21
+ ])),
22
+ setColors: [
23
+ { color: [255, 0, 0] },
24
+ { color: [0, 255, 0] },
25
+ { color: [0, 0, 255] },
26
+ ],
27
+ obsIndex: ['1', '2', '3', '4', '5'],
28
+ },
29
+ {
30
+ setColorIndices: (new Map([
31
+ ['2', 0],
32
+ ['1', 1],
33
+ ['3', 0],
34
+ ])),
35
+ setColors: [
36
+ { color: [255, 255, 255] },
37
+ { color: [0, 0, 0] },
38
+ ],
39
+ obsIndex: ['1', '2', '3'],
40
+ },
41
+ ];
42
+
43
+ const channelIsSetColorMode = [
44
+ true,
45
+ false,
46
+ ];
47
+
48
+ const [
49
+ totalData,
50
+ valueTexHeight,
51
+ indicesOffsets,
52
+ totalColors,
53
+ colorTexHeight,
54
+ colorsOffsets,
55
+ ] = multiSetsToTextureData(
56
+ multiFeatureValues,
57
+ setColorValues,
58
+ channelIsSetColorMode,
59
+ 10,
60
+ );
61
+
62
+ expect(valueTexHeight).toEqual(2);
63
+ expect(colorTexHeight).toEqual(2);
64
+ expect(indicesOffsets).toEqual([0, 5]);
65
+ expect(colorsOffsets).toEqual([0, 3]);
66
+ expect(totalColors.length).toEqual(20);
67
+ expect(totalColors).toEqual(new Uint8Array([
68
+ // Expect colors to be present for only the channels with isSetColorMode.
69
+ 255, 0, 0,
70
+ 0, 255, 0,
71
+ 0, 0, 255,
72
+ // For isSetColorMode = false, expect all zeros.
73
+ 0, 0, 0,
74
+ 0, 0, 0,
75
+ // Extra values for padding.
76
+ 0, 0, 0, 0, 0,
77
+ ]));
78
+ expect(totalData.length).toEqual(20);
79
+ expect(totalData).toEqual(new Uint8Array([
80
+ // For the first channel, expect the indices to be present.
81
+ // Expect one to be added so that zero is the "null" color.
82
+ 0, 1 + 1, 1 + 2, 1 + 0, 1 + 1,
83
+ // For the second channel, expect the expression values to be present.
84
+ // Expect the values [10, 20, 30] to be normalized to [0, 127, 255].
85
+ 0, 127, 255,
86
+ // Extra values for padding.
87
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88
+ ]));
89
+ });
90
+ });
91
+ });
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Selection Layers
2
- export { getSelectionLayers } from './selection-utils.js';
2
+ export { getSelectionLayer } from './selection-utils.js';
3
3
 
4
4
  // Heatmap Layers
5
5
  export { default as HeatmapBitmapLayer } from './HeatmapBitmapLayer.js';
@@ -15,6 +15,8 @@ export {
15
15
  export { default as ScaledExpressionExtension } from './ScaledExpressionExtension/index.js';
16
16
  export { default as SelectionExtension } from './SelectionExtension/index.js';
17
17
  export { default as BitmaskLayer } from './BitmaskLayer.js';
18
+ export { default as BitmaskLayerBeta } from './BitmaskLayerBeta.js';
19
+
18
20
 
19
21
  export {
20
22
  TILE_SIZE, MAX_ROW_AGG, MIN_ROW_AGG,
@@ -20,23 +20,23 @@ function getSelectedLayerId(layerId) {
20
20
  return `selected-${layerId}`;
21
21
  }
22
22
 
23
+ // eslint-disable-next-line no-unused-vars
24
+ const onSelectNoop = ({ pickingInfos }) => {};
25
+
23
26
  /**
24
27
  * Construct DeckGL selection layers.
25
28
  * @param {string} tool
26
29
  * @param {number} zoom
27
30
  * @param {string} cellBaseLayerId
28
- * @param {function} getCellCoords
29
- * @param {function} updateCellsSelection
31
+ * @param {object[]} obsLayers Objects with properties
32
+ * getObsCoords, obsIndex, obsQuadTree, onSelect.
30
33
  * @returns {object[]} The array of DeckGL selection layers.
31
34
  */
32
- export function getSelectionLayers(
35
+ export function getSelectionLayer(
33
36
  tool,
34
37
  zoom,
35
38
  layerId,
36
- getCellCoords,
37
- obsIndex,
38
- updateCellsSelection,
39
- cellsQuadTree,
39
+ obsLayers,
40
40
  flipY = false,
41
41
  ) {
42
42
  if (!tool) {
@@ -46,19 +46,15 @@ export function getSelectionLayers(
46
46
  const cellBaseLayerId = getBaseLayerId(layerId);
47
47
  const editHandlePointRadius = 5 / (zoom + 16);
48
48
 
49
- return [new SelectionLayer({
49
+ return new SelectionLayer({
50
50
  id: 'selection',
51
51
  flipY,
52
- cellsQuadTree,
53
- getCellCoords,
52
+ obsLayers,
54
53
  coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
55
54
  selectionType: tool,
56
- onSelect: ({ pickingInfos }) => {
57
- const cellIds = pickingInfos.map(i => obsIndex[i]);
58
- if (updateCellsSelection) {
59
- updateCellsSelection(cellIds);
60
- }
61
- },
55
+ // This onSelect is no longer used since
56
+ // the obsLayers each have their own onSelect.
57
+ onSelect: onSelectNoop,
62
58
  layerIds: [cellBaseLayerId],
63
59
  getTentativeFillColor: () => [255, 255, 255, 95],
64
60
  getTentativeLineColor: () => [143, 143, 143, 255],
@@ -70,7 +66,7 @@ export function getSelectionLayers(
70
66
  editHandlePointRadiusScale: 1,
71
67
  editHandlePointRadiusMinPixels: editHandlePointRadius,
72
68
  editHandlePointRadiusMaxPixels: 2 * editHandlePointRadius,
73
- })];
69
+ });
74
70
  }
75
71
 
76
72
  /**
package/src/viv.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export {
2
+ TiffPixelSource,
2
3
  ZarrPixelSource,
3
4
  loadOmeTiff,
4
5
  loadOmeZarr,