@vitessce/gl 2.0.3-beta.0 → 3.0.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/deflate-36830437.js +11 -0
- package/dist/index-d34ff949.js +120610 -0
- package/dist/index.js +33 -16
- package/dist/jpeg-a66190dc.js +838 -0
- package/dist/lerc-21af7ec8.js +2004 -0
- package/dist/lzw-76194936.js +126 -0
- package/dist/packbits-bf7850c4.js +28 -0
- package/dist/pako.esm-68f84e2a.js +4022 -0
- package/dist/raw-05d82ade.js +10 -0
- package/dist/webimage-1ceac06a.js +30 -0
- package/dist-tsc/BitmaskLayer.d.ts +74 -0
- package/dist-tsc/BitmaskLayer.d.ts.map +1 -0
- package/{dist → dist-tsc}/BitmaskLayer.js +14 -4
- package/dist-tsc/HeatmapBitmapLayer.d.ts +93 -0
- package/dist-tsc/HeatmapBitmapLayer.d.ts.map +1 -0
- package/{dist → dist-tsc}/HeatmapBitmapLayer.js +3 -3
- package/dist-tsc/HeatmapCompositeTextLayer.d.ts +11 -0
- package/dist-tsc/HeatmapCompositeTextLayer.d.ts.map +1 -0
- package/{dist → dist-tsc}/HeatmapCompositeTextLayer.js +1 -1
- package/dist-tsc/PaddedExpressionHeatmapBitmapLayer.d.ts +93 -0
- package/dist-tsc/PaddedExpressionHeatmapBitmapLayer.d.ts.map +1 -0
- package/{dist → dist-tsc}/PaddedExpressionHeatmapBitmapLayer.js +3 -3
- package/dist-tsc/PixelatedBitmapLayer.d.ts +10 -0
- package/dist-tsc/PixelatedBitmapLayer.d.ts.map +1 -0
- package/{dist → dist-tsc}/PixelatedBitmapLayer.js +1 -1
- package/dist-tsc/ScaledExpressionExtension/ScaledExpressionExtension.d.ts +62 -0
- package/dist-tsc/ScaledExpressionExtension/ScaledExpressionExtension.d.ts.map +1 -0
- package/{dist → dist-tsc}/ScaledExpressionExtension/ScaledExpressionExtension.js +2 -2
- package/dist-tsc/ScaledExpressionExtension/index.d.ts +3 -0
- package/dist-tsc/ScaledExpressionExtension/index.d.ts.map +1 -0
- package/{dist → dist-tsc}/ScaledExpressionExtension/index.js +1 -1
- package/dist-tsc/ScaledExpressionExtension/shader-module.d.ts +17 -0
- package/dist-tsc/ScaledExpressionExtension/shader-module.d.ts.map +1 -0
- package/{dist → dist-tsc}/ScaledExpressionExtension/shader-module.js +1 -1
- package/dist-tsc/SelectionExtension/SelectionExtension.d.ts +18 -0
- package/dist-tsc/SelectionExtension/SelectionExtension.d.ts.map +1 -0
- package/{dist → dist-tsc}/SelectionExtension/SelectionExtension.js +1 -1
- package/dist-tsc/SelectionExtension/index.d.ts +3 -0
- package/dist-tsc/SelectionExtension/index.d.ts.map +1 -0
- package/dist-tsc/SelectionExtension/index.js +2 -0
- package/dist-tsc/SelectionExtension/shader-module.d.ts +12 -0
- package/dist-tsc/SelectionExtension/shader-module.d.ts.map +1 -0
- package/dist-tsc/SelectionLayer.d.ts +15 -0
- package/dist-tsc/SelectionLayer.d.ts.map +1 -0
- package/{dist → dist-tsc}/SelectionLayer.js +1 -11
- package/dist-tsc/bitmask-layer-shaders.d.ts +3 -0
- package/dist-tsc/bitmask-layer-shaders.d.ts.map +1 -0
- package/{dist → dist-tsc}/bitmask-layer-shaders.js +1 -1
- package/dist-tsc/constants.d.ts +8 -0
- package/dist-tsc/constants.d.ts.map +1 -0
- package/dist-tsc/deck.d.ts +2 -0
- package/dist-tsc/deck.d.ts.map +1 -0
- package/dist-tsc/glsl/index.d.ts +2 -0
- package/dist-tsc/glsl/index.d.ts.map +1 -0
- package/dist-tsc/heatmap-bitmap-layer-shaders.d.ts +13 -0
- package/dist-tsc/heatmap-bitmap-layer-shaders.d.ts.map +1 -0
- package/{dist → dist-tsc}/heatmap-bitmap-layer-shaders.js +1 -1
- package/dist-tsc/heatmap-constants.d.ts +20 -0
- package/dist-tsc/heatmap-constants.d.ts.map +1 -0
- package/dist-tsc/index.d.ts +14 -0
- package/dist-tsc/index.d.ts.map +1 -0
- package/dist-tsc/index.js +19 -0
- package/dist-tsc/luma.d.ts +2 -0
- package/dist-tsc/luma.d.ts.map +1 -0
- package/dist-tsc/padded-expression-heatmap-bitmap-layer-shaders.d.ts +13 -0
- package/dist-tsc/padded-expression-heatmap-bitmap-layer-shaders.d.ts.map +1 -0
- package/{dist → dist-tsc}/padded-expression-heatmap-bitmap-layer-shaders.js +1 -1
- package/dist-tsc/selection-utils.d.ts +19 -0
- package/dist-tsc/selection-utils.d.ts.map +1 -0
- package/{dist → dist-tsc}/selection-utils.js +1 -1
- package/dist-tsc/viv.d.ts +2 -0
- package/dist-tsc/viv.d.ts.map +1 -0
- package/package.json +16 -7
- package/src/BitmaskLayer.js +175 -0
- package/src/HeatmapBitmapLayer.js +144 -0
- package/src/HeatmapCompositeTextLayer.js +156 -0
- package/src/PaddedExpressionHeatmapBitmapLayer.js +154 -0
- package/src/PixelatedBitmapLayer.js +30 -0
- package/src/ScaledExpressionExtension/ScaledExpressionExtension.js +117 -0
- package/src/ScaledExpressionExtension/index.js +3 -0
- package/src/ScaledExpressionExtension/shader-module.js +35 -0
- package/src/SelectionExtension/SelectionExtension.js +34 -0
- package/src/SelectionExtension/index.js +3 -0
- package/src/SelectionExtension/shader-module.js +22 -0
- package/src/SelectionLayer.js +187 -0
- package/src/bitmask-layer-shaders.js +92 -0
- package/src/constants.js +13 -0
- package/src/deck.js +4 -0
- package/src/glsl/README.md +8 -0
- package/src/glsl/colormaps.in.glsl +15 -0
- package/src/glsl/index.js +341 -0
- package/src/heatmap-bitmap-layer-shaders.js +111 -0
- package/src/heatmap-constants.js +30 -0
- package/src/index.js +36 -0
- package/src/luma.js +2 -0
- package/src/padded-expression-heatmap-bitmap-layer-shaders.js +145 -0
- package/src/selection-utils.js +109 -0
- package/src/viv.js +20 -0
- package/dist/SelectionExtension/index.js +0 -2
- package/dist/layer-controller.js +0 -109
- package/dist/spatial.js +0 -281
- package/dist/spatial.test.js +0 -8
- /package/{dist → dist-tsc}/SelectionExtension/shader-module.js +0 -0
- /package/{dist → dist-tsc}/constants.js +0 -0
- /package/{dist → dist-tsc}/deck.js +0 -0
- /package/{dist → dist-tsc}/glsl/index.js +0 -0
- /package/{dist → dist-tsc}/heatmap-constants.js +0 -0
- /package/{dist → dist-tsc}/luma.js +0 -0
- /package/{dist → dist-tsc}/viv.js +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import GL from '@luma.gl/constants'; // eslint-disable-line import/no-extraneous-dependencies
|
|
2
|
+
import { _mergeShaders, project32, picking } from '@deck.gl/core'; // eslint-disable-line import/no-extraneous-dependencies
|
|
3
|
+
import { BitmapLayer } from '@deck.gl/layers'; // eslint-disable-line import/no-extraneous-dependencies
|
|
4
|
+
import { Texture2D } from '@luma.gl/core';
|
|
5
|
+
import { PIXELATED_TEXTURE_PARAMETERS, TILE_SIZE } from './heatmap-constants.js';
|
|
6
|
+
import {
|
|
7
|
+
GLSL_COLORMAPS,
|
|
8
|
+
GLSL_COLORMAP_DEFAULT,
|
|
9
|
+
COLORMAP_SHADER_PLACEHOLDER,
|
|
10
|
+
} from './constants.js';
|
|
11
|
+
import { vertexShader, fragmentShader } from './heatmap-bitmap-layer-shaders.js';
|
|
12
|
+
|
|
13
|
+
const defaultProps = {
|
|
14
|
+
image: { type: 'object', value: null, async: true },
|
|
15
|
+
colormap: { type: 'string', value: GLSL_COLORMAP_DEFAULT, compare: true },
|
|
16
|
+
bounds: { type: 'array', value: [1, 0, 0, 1], compare: true },
|
|
17
|
+
aggSizeX: { type: 'number', value: 8.0, compare: true },
|
|
18
|
+
aggSizeY: { type: 'number', value: 8.0, compare: true },
|
|
19
|
+
colorScaleLo: { type: 'number', value: 0.0, compare: true },
|
|
20
|
+
colorScaleHi: { type: 'number', value: 1.0, compare: true },
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A BitmapLayer that performs aggregation in the fragment shader,
|
|
24
|
+
* and renders its texture from a Uint8Array rather than an ImageData.
|
|
25
|
+
*/
|
|
26
|
+
export default class HeatmapBitmapLayer extends BitmapLayer {
|
|
27
|
+
/**
|
|
28
|
+
* Copy of getShaders from Layer (grandparent, parent of BitmapLayer).
|
|
29
|
+
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/core/src/lib/layer.js#L302
|
|
30
|
+
* @param {object} shaders
|
|
31
|
+
* @returns {object} Merged shaders.
|
|
32
|
+
*/
|
|
33
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
34
|
+
_getShaders(shaders) {
|
|
35
|
+
this.props.extensions.forEach((extension) => {
|
|
36
|
+
// eslint-disable-next-line no-param-reassign
|
|
37
|
+
shaders = _mergeShaders(
|
|
38
|
+
shaders,
|
|
39
|
+
extension.getShaders.call(this, extension),
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
return shaders;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Need to override to provide custom shaders.
|
|
47
|
+
*/
|
|
48
|
+
getShaders() {
|
|
49
|
+
const { colormap } = this.props;
|
|
50
|
+
const fragmentShaderWithColormap = GLSL_COLORMAPS.includes(colormap)
|
|
51
|
+
? fragmentShader.replace(COLORMAP_SHADER_PLACEHOLDER, colormap)
|
|
52
|
+
: fragmentShader.replace(
|
|
53
|
+
COLORMAP_SHADER_PLACEHOLDER,
|
|
54
|
+
GLSL_COLORMAP_DEFAULT,
|
|
55
|
+
);
|
|
56
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
57
|
+
return this._getShaders({
|
|
58
|
+
vs: vertexShader,
|
|
59
|
+
fs: fragmentShaderWithColormap,
|
|
60
|
+
modules: [project32, picking],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
updateState(args) {
|
|
65
|
+
super.updateState(args);
|
|
66
|
+
this.loadTexture(this.props.image);
|
|
67
|
+
const { props, oldProps } = args;
|
|
68
|
+
if (props.colormap !== oldProps.colormap) {
|
|
69
|
+
const { gl } = this.context;
|
|
70
|
+
// eslint-disable-next-line no-unused-expressions
|
|
71
|
+
this.state.model?.delete();
|
|
72
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
73
|
+
this.state.model = this._getModel(gl);
|
|
74
|
+
this.getAttributeManager().invalidateAll();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Need to override to provide additional uniform values.
|
|
80
|
+
* Simplified by removing video-related code.
|
|
81
|
+
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/layers/src/bitmap-layer/bitmap-layer.js#L173
|
|
82
|
+
* @param {*} opts
|
|
83
|
+
*/
|
|
84
|
+
draw(opts) {
|
|
85
|
+
const { uniforms } = opts;
|
|
86
|
+
const { bitmapTexture, model } = this.state;
|
|
87
|
+
const {
|
|
88
|
+
aggSizeX, aggSizeY, colorScaleLo, colorScaleHi,
|
|
89
|
+
} = this.props;
|
|
90
|
+
|
|
91
|
+
// Render the image
|
|
92
|
+
if (bitmapTexture && model) {
|
|
93
|
+
model
|
|
94
|
+
.setUniforms(
|
|
95
|
+
Object.assign({}, uniforms, {
|
|
96
|
+
uBitmapTexture: bitmapTexture,
|
|
97
|
+
uTextureSize: [TILE_SIZE, TILE_SIZE],
|
|
98
|
+
uAggSize: [aggSizeX, aggSizeY],
|
|
99
|
+
uColorScaleRange: [colorScaleLo, colorScaleHi],
|
|
100
|
+
}),
|
|
101
|
+
)
|
|
102
|
+
.draw();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Need to override to provide the custom DEFAULT_TEXTURE_PARAMETERS
|
|
108
|
+
* object.
|
|
109
|
+
* Simplified by removing video-related code.
|
|
110
|
+
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/layers/src/bitmap-layer/bitmap-layer.js#L218
|
|
111
|
+
* @param {Uint8Array} image
|
|
112
|
+
*/
|
|
113
|
+
loadTexture(image) {
|
|
114
|
+
const { gl } = this.context;
|
|
115
|
+
|
|
116
|
+
if (this.state.bitmapTexture) {
|
|
117
|
+
this.state.bitmapTexture.delete();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (image instanceof Texture2D) {
|
|
121
|
+
this.setState({
|
|
122
|
+
bitmapTexture: image,
|
|
123
|
+
});
|
|
124
|
+
} else if (image) {
|
|
125
|
+
this.setState({
|
|
126
|
+
bitmapTexture: new Texture2D(gl, {
|
|
127
|
+
data: image,
|
|
128
|
+
mipmaps: false,
|
|
129
|
+
parameters: PIXELATED_TEXTURE_PARAMETERS,
|
|
130
|
+
// Each color contains a single luminance value.
|
|
131
|
+
// When sampled, rgb are all set to this luminance, alpha is 1.0.
|
|
132
|
+
// Reference: https://luma.gl/docs/api-reference/webgl/texture#texture-formats
|
|
133
|
+
format: GL.LUMINANCE,
|
|
134
|
+
dataFormat: GL.LUMINANCE,
|
|
135
|
+
type: GL.UNSIGNED_BYTE,
|
|
136
|
+
width: TILE_SIZE,
|
|
137
|
+
height: TILE_SIZE,
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
HeatmapBitmapLayer.layerName = 'HeatmapBitmapLayer';
|
|
144
|
+
HeatmapBitmapLayer.defaultProps = defaultProps;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
import { COORDINATE_SYSTEM, CompositeLayer } from '@deck.gl/core'; // eslint-disable-line import/no-extraneous-dependencies
|
|
3
|
+
import { TextLayer } from '@deck.gl/layers'; // eslint-disable-line import/no-extraneous-dependencies
|
|
4
|
+
import {
|
|
5
|
+
AXIS_LABEL_TEXT_SIZE,
|
|
6
|
+
AXIS_TITLE_TEXT_SIZE,
|
|
7
|
+
AXIS_MARGIN,
|
|
8
|
+
THEME_TO_TEXT_COLOR,
|
|
9
|
+
AXIS_FONT_FAMILY,
|
|
10
|
+
COLOR_BAR_SIZE,
|
|
11
|
+
} from './heatmap-constants.js';
|
|
12
|
+
|
|
13
|
+
export default class HeatmapCompositeTextLayer extends CompositeLayer {
|
|
14
|
+
_renderAxisTopLayers() {
|
|
15
|
+
const {
|
|
16
|
+
axisTopLabelData, matrixLeft, width, matrixWidth, viewWidth, theme,
|
|
17
|
+
targetX, targetY, axisTopTitle, cellWidth, axisOffsetTop, scaleFactor,
|
|
18
|
+
hideTopLabels,
|
|
19
|
+
} = this.props;
|
|
20
|
+
const showAxisTopLabels = cellWidth >= AXIS_LABEL_TEXT_SIZE;
|
|
21
|
+
const axisLabelTop = targetY + (axisOffsetTop - AXIS_MARGIN) / 2 / scaleFactor;
|
|
22
|
+
return hideTopLabels ? [] : [
|
|
23
|
+
new TextLayer({
|
|
24
|
+
id: 'axisTopLabels',
|
|
25
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
26
|
+
data: axisTopLabelData,
|
|
27
|
+
getText: d => d[1],
|
|
28
|
+
getPosition: d => [matrixLeft + ((d[0] + 0.5) / width) * matrixWidth, axisLabelTop],
|
|
29
|
+
getTextAnchor: 'start',
|
|
30
|
+
getColor: () => THEME_TO_TEXT_COLOR[theme],
|
|
31
|
+
getSize: (showAxisTopLabels ? AXIS_LABEL_TEXT_SIZE : 0),
|
|
32
|
+
getAngle: 75,
|
|
33
|
+
fontFamily: AXIS_FONT_FAMILY,
|
|
34
|
+
updateTriggers: {
|
|
35
|
+
getPosition: [axisLabelTop, matrixLeft, matrixWidth, viewWidth],
|
|
36
|
+
getSize: [showAxisTopLabels],
|
|
37
|
+
getColor: [theme],
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
new TextLayer({
|
|
41
|
+
id: 'axisTopTitle',
|
|
42
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
43
|
+
data: [{ title: axisTopTitle }],
|
|
44
|
+
getText: d => d.title,
|
|
45
|
+
getPosition: [targetX, targetY],
|
|
46
|
+
getTextAnchor: 'middle',
|
|
47
|
+
getColor: () => THEME_TO_TEXT_COLOR[theme],
|
|
48
|
+
getSize: (!showAxisTopLabels ? AXIS_TITLE_TEXT_SIZE : 0),
|
|
49
|
+
getAngle: 0,
|
|
50
|
+
fontFamily: AXIS_FONT_FAMILY,
|
|
51
|
+
updateTriggers: {
|
|
52
|
+
getSize: [showAxisTopLabels],
|
|
53
|
+
getColor: [theme],
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
_renderCornerLayers() {
|
|
60
|
+
const {
|
|
61
|
+
theme, targetX, targetY, axisOffsetTop, scaleFactor,
|
|
62
|
+
cellColorLabelsData, axisOffsetLeft, transpose,
|
|
63
|
+
} = this.props;
|
|
64
|
+
const axisLabelTop = targetY + (axisOffsetTop - AXIS_MARGIN) / 2 / scaleFactor;
|
|
65
|
+
const axisLabelLeft = targetX + (axisOffsetLeft - AXIS_MARGIN) / 2 / scaleFactor;
|
|
66
|
+
return cellColorLabelsData.map(data => (
|
|
67
|
+
new TextLayer({
|
|
68
|
+
id: `cellColorLabel-${data[0]}`,
|
|
69
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
70
|
+
data: [data],
|
|
71
|
+
getText: d => d[1],
|
|
72
|
+
getTextAnchor: (transpose ? 'end' : 'start'),
|
|
73
|
+
getAlignmentBaseline: 'top',
|
|
74
|
+
getColor: () => THEME_TO_TEXT_COLOR[theme],
|
|
75
|
+
getSize: AXIS_LABEL_TEXT_SIZE,
|
|
76
|
+
getPosition: d => [
|
|
77
|
+
(transpose
|
|
78
|
+
? axisLabelLeft
|
|
79
|
+
: targetX
|
|
80
|
+
+ ((-cellColorLabelsData.length + d[0] * 2) * COLOR_BAR_SIZE + AXIS_MARGIN)
|
|
81
|
+
/ 2 / scaleFactor
|
|
82
|
+
),
|
|
83
|
+
(transpose
|
|
84
|
+
? targetY
|
|
85
|
+
+ ((-cellColorLabelsData.length + d[0] * 2) * COLOR_BAR_SIZE + AXIS_MARGIN)
|
|
86
|
+
/ 2 / scaleFactor
|
|
87
|
+
: axisLabelTop
|
|
88
|
+
),
|
|
89
|
+
],
|
|
90
|
+
getAngle: (transpose ? 0 : 90),
|
|
91
|
+
fontFamily: AXIS_FONT_FAMILY,
|
|
92
|
+
})
|
|
93
|
+
));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_renderAxisLeftLayers() {
|
|
97
|
+
const {
|
|
98
|
+
axisLeftLabelData, matrixTop, height, matrixHeight,
|
|
99
|
+
viewHeight, theme, axisLeftTitle, targetX, targetY, cellHeight, axisOffsetLeft,
|
|
100
|
+
scaleFactor, hideLeftLabels,
|
|
101
|
+
} = this.props;
|
|
102
|
+
const showAxisLeftLabels = cellHeight >= AXIS_LABEL_TEXT_SIZE;
|
|
103
|
+
const axisLabelLeft = targetX + (axisOffsetLeft - AXIS_MARGIN) / 2 / scaleFactor;
|
|
104
|
+
return hideLeftLabels ? [] : [
|
|
105
|
+
new TextLayer({
|
|
106
|
+
id: 'axisLeftLabels',
|
|
107
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
108
|
+
data: axisLeftLabelData,
|
|
109
|
+
getText: d => d[1],
|
|
110
|
+
getPosition: d => [axisLabelLeft, matrixTop + ((d[0] + 0.5) / height) * matrixHeight],
|
|
111
|
+
getTextAnchor: 'end',
|
|
112
|
+
getColor: () => THEME_TO_TEXT_COLOR[theme],
|
|
113
|
+
getSize: (showAxisLeftLabels ? AXIS_LABEL_TEXT_SIZE : 0),
|
|
114
|
+
getAngle: 0,
|
|
115
|
+
fontFamily: AXIS_FONT_FAMILY,
|
|
116
|
+
updateTriggers: {
|
|
117
|
+
getPosition: [axisLabelLeft, matrixTop, matrixHeight, viewHeight],
|
|
118
|
+
getSize: [showAxisLeftLabels],
|
|
119
|
+
getColor: [theme],
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
new TextLayer({
|
|
123
|
+
id: 'axisLeftTitle',
|
|
124
|
+
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
125
|
+
data: [{ title: axisLeftTitle }],
|
|
126
|
+
getText: d => d.title,
|
|
127
|
+
getPosition: [targetX, targetY],
|
|
128
|
+
getTextAnchor: 'middle',
|
|
129
|
+
getColor: () => THEME_TO_TEXT_COLOR[theme],
|
|
130
|
+
getSize: (!showAxisLeftLabels ? AXIS_TITLE_TEXT_SIZE : 0),
|
|
131
|
+
getAngle: 90,
|
|
132
|
+
fontFamily: AXIS_FONT_FAMILY,
|
|
133
|
+
updateTriggers: {
|
|
134
|
+
getSize: [showAxisLeftLabels],
|
|
135
|
+
getColor: [theme],
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
renderLayers() {
|
|
142
|
+
const { axis } = this.props;
|
|
143
|
+
if (axis === 'left') {
|
|
144
|
+
return this._renderAxisLeftLayers();
|
|
145
|
+
}
|
|
146
|
+
if (axis === 'top') {
|
|
147
|
+
return this._renderAxisTopLayers();
|
|
148
|
+
}
|
|
149
|
+
if (axis === 'corner') {
|
|
150
|
+
return this._renderCornerLayers();
|
|
151
|
+
}
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
HeatmapCompositeTextLayer.layerName = 'HeatmapCompositeTextLayer';
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
import GL from '@luma.gl/constants'; // eslint-disable-line import/no-extraneous-dependencies
|
|
3
|
+
import { _mergeShaders, project32, picking } from '@deck.gl/core'; // eslint-disable-line import/no-extraneous-dependencies
|
|
4
|
+
import { BitmapLayer } from '@deck.gl/layers'; // eslint-disable-line import/no-extraneous-dependencies
|
|
5
|
+
import { Texture2D } from '@luma.gl/core';
|
|
6
|
+
import { PIXELATED_TEXTURE_PARAMETERS, TILE_SIZE, DATA_TEXTURE_SIZE } from './heatmap-constants.js';
|
|
7
|
+
import { GLSL_COLORMAPS, GLSL_COLORMAP_DEFAULT, COLORMAP_SHADER_PLACEHOLDER } from './constants.js';
|
|
8
|
+
import { vertexShader, fragmentShader } from './padded-expression-heatmap-bitmap-layer-shaders.js';
|
|
9
|
+
|
|
10
|
+
const defaultProps = {
|
|
11
|
+
image: { type: 'object', value: null, async: true },
|
|
12
|
+
colormap: { type: 'string', value: GLSL_COLORMAP_DEFAULT, compare: true },
|
|
13
|
+
bounds: { type: 'array', value: [1, 0, 0, 1], compare: true },
|
|
14
|
+
aggSizeX: { type: 'number', value: 8.0, compare: true },
|
|
15
|
+
aggSizeY: { type: 'number', value: 8.0, compare: true },
|
|
16
|
+
colorScaleLo: { type: 'number', value: 0.0, compare: true },
|
|
17
|
+
colorScaleHi: { type: 'number', value: 1.0, compare: true },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A BitmapLayer that performs aggregation in the fragment shader,
|
|
22
|
+
* and renders its texture from a Uint8Array rather than an ImageData.
|
|
23
|
+
*/
|
|
24
|
+
export default class PaddedExpressionHeatmapBitmapLayer extends BitmapLayer {
|
|
25
|
+
/**
|
|
26
|
+
* Copy of getShaders from Layer (grandparent, parent of BitmapLayer).
|
|
27
|
+
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/core/src/lib/layer.js#L302
|
|
28
|
+
* @param {object} shaders
|
|
29
|
+
* @returns {object} Merged shaders.
|
|
30
|
+
*/
|
|
31
|
+
_getShaders(shaders) {
|
|
32
|
+
this.props.extensions.forEach((extension) => {
|
|
33
|
+
// eslint-disable-next-line no-param-reassign
|
|
34
|
+
shaders = _mergeShaders(
|
|
35
|
+
shaders,
|
|
36
|
+
extension.getShaders.call(this, extension),
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
return shaders;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Need to override to provide custom shaders.
|
|
44
|
+
*/
|
|
45
|
+
getShaders() {
|
|
46
|
+
const { colormap } = this.props;
|
|
47
|
+
const fragmentShaderWithColormap = GLSL_COLORMAPS.includes(colormap)
|
|
48
|
+
? fragmentShader.replace(COLORMAP_SHADER_PLACEHOLDER, colormap)
|
|
49
|
+
: fragmentShader.replace(
|
|
50
|
+
COLORMAP_SHADER_PLACEHOLDER,
|
|
51
|
+
GLSL_COLORMAP_DEFAULT,
|
|
52
|
+
);
|
|
53
|
+
return this._getShaders({
|
|
54
|
+
vs: vertexShader,
|
|
55
|
+
fs: fragmentShaderWithColormap,
|
|
56
|
+
modules: [project32, picking],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
updateState(args) {
|
|
61
|
+
super.updateState(args);
|
|
62
|
+
const { props, oldProps } = args;
|
|
63
|
+
if (props.colormap !== oldProps.colormap) {
|
|
64
|
+
const { gl } = this.context;
|
|
65
|
+
// eslint-disable-next-line no-unused-expressions
|
|
66
|
+
this.state.model?.delete();
|
|
67
|
+
this.state.model = this._getModel(gl);
|
|
68
|
+
this.getAttributeManager().invalidateAll();
|
|
69
|
+
}
|
|
70
|
+
if (props.image !== oldProps.image) {
|
|
71
|
+
this.loadTexture(this.props.image);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Need to override to provide additional uniform values.
|
|
77
|
+
* Simplified by removing video-related code.
|
|
78
|
+
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/layers/src/bitmap-layer/bitmap-layer.js#L173
|
|
79
|
+
* @param {*} opts
|
|
80
|
+
*/
|
|
81
|
+
draw(opts) {
|
|
82
|
+
const { uniforms } = opts;
|
|
83
|
+
const { bitmapTexture, model } = this.state;
|
|
84
|
+
const {
|
|
85
|
+
aggSizeX,
|
|
86
|
+
aggSizeY,
|
|
87
|
+
colorScaleLo,
|
|
88
|
+
colorScaleHi,
|
|
89
|
+
origDataSize,
|
|
90
|
+
tileI,
|
|
91
|
+
tileJ,
|
|
92
|
+
numXTiles,
|
|
93
|
+
numYTiles,
|
|
94
|
+
} = this.props;
|
|
95
|
+
// Render the image
|
|
96
|
+
if (bitmapTexture && model) {
|
|
97
|
+
model
|
|
98
|
+
.setUniforms(
|
|
99
|
+
Object.assign({}, uniforms, {
|
|
100
|
+
uBitmapTexture: bitmapTexture,
|
|
101
|
+
uOrigDataSize: origDataSize,
|
|
102
|
+
uReshapedDataSize: [DATA_TEXTURE_SIZE, DATA_TEXTURE_SIZE],
|
|
103
|
+
uTextureSize: [TILE_SIZE, TILE_SIZE],
|
|
104
|
+
uAggSize: [aggSizeX, aggSizeY],
|
|
105
|
+
uColorScaleRange: [colorScaleLo, colorScaleHi],
|
|
106
|
+
tileIJ: [tileI, tileJ],
|
|
107
|
+
dataIJ: [0, 0],
|
|
108
|
+
numTiles: [numXTiles, numYTiles],
|
|
109
|
+
numData: [1, 1],
|
|
110
|
+
}),
|
|
111
|
+
)
|
|
112
|
+
.draw();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Need to override to provide the custom DEFAULT_TEXTURE_PARAMETERS
|
|
118
|
+
* object.
|
|
119
|
+
* Simplified by removing video-related code.
|
|
120
|
+
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/layers/src/bitmap-layer/bitmap-layer.js#L218
|
|
121
|
+
* @param {Array<Uint8Array>} images
|
|
122
|
+
*/
|
|
123
|
+
loadTexture(image) {
|
|
124
|
+
const { gl } = this.context;
|
|
125
|
+
|
|
126
|
+
if (this.state.bitmapTexture) {
|
|
127
|
+
this.state.bitmapTexture.delete();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (image && image instanceof Texture2D) {
|
|
131
|
+
this.setState({
|
|
132
|
+
bitmapTexture: image,
|
|
133
|
+
});
|
|
134
|
+
} else if (image) {
|
|
135
|
+
this.setState({
|
|
136
|
+
bitmapTexture: new Texture2D(gl, {
|
|
137
|
+
data: image,
|
|
138
|
+
mipmaps: false,
|
|
139
|
+
parameters: PIXELATED_TEXTURE_PARAMETERS,
|
|
140
|
+
// Each color contains a single luminance value.
|
|
141
|
+
// When sampled, rgb are all set to this luminance, alpha is 1.0.
|
|
142
|
+
// Reference: https://luma.gl/docs/api-reference/webgl/texture#texture-formats
|
|
143
|
+
format: GL.LUMINANCE,
|
|
144
|
+
dataFormat: GL.LUMINANCE,
|
|
145
|
+
type: GL.UNSIGNED_BYTE,
|
|
146
|
+
width: DATA_TEXTURE_SIZE,
|
|
147
|
+
height: DATA_TEXTURE_SIZE,
|
|
148
|
+
}),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
PaddedExpressionHeatmapBitmapLayer.layerName = 'PaddedExpressionHeatmapBitmapLayer';
|
|
154
|
+
PaddedExpressionHeatmapBitmapLayer.defaultProps = defaultProps;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BitmapLayer } from '@deck.gl/layers'; // eslint-disable-line import/no-extraneous-dependencies
|
|
2
|
+
import { CompositeLayer } from '@deck.gl/core'; // eslint-disable-line import/no-extraneous-dependencies
|
|
3
|
+
import { PIXELATED_TEXTURE_PARAMETERS } from './heatmap-constants.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
// These are the same defaultProps as for BitmapLayer.
|
|
7
|
+
const defaultProps = {
|
|
8
|
+
...BitmapLayer.defaultProps,
|
|
9
|
+
image: { type: 'object', value: null, async: true },
|
|
10
|
+
bounds: { type: 'array', value: [1, 0, 0, 1], compare: true },
|
|
11
|
+
desaturate: {
|
|
12
|
+
type: 'number', min: 0, max: 1, value: 0,
|
|
13
|
+
},
|
|
14
|
+
transparentColor: { type: 'color', value: [0, 0, 0, 0] },
|
|
15
|
+
tintColor: { type: 'color', value: [255, 255, 255] },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default class PixelatedBitmapLayer extends CompositeLayer {
|
|
19
|
+
renderLayers() {
|
|
20
|
+
const { image } = this.props;
|
|
21
|
+
return new BitmapLayer(this.props, {
|
|
22
|
+
id: `${this.props.id}-wrapped`,
|
|
23
|
+
image,
|
|
24
|
+
textureParameters: PIXELATED_TEXTURE_PARAMETERS,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
PixelatedBitmapLayer.layerName = 'PixelatedBitmapLayer';
|
|
30
|
+
PixelatedBitmapLayer.defaultProps = defaultProps;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
3
|
+
import GL from '@luma.gl/constants';
|
|
4
|
+
import { LayerExtension } from '@deck.gl/core';
|
|
5
|
+
import { GLSL_COLORMAPS, GLSL_COLORMAP_DEFAULT, COLORMAP_SHADER_PLACEHOLDER } from '../constants.js';
|
|
6
|
+
import module from './shader-module.js';
|
|
7
|
+
|
|
8
|
+
const defaultProps = {
|
|
9
|
+
colormap: { type: 'string', value: GLSL_COLORMAP_DEFAULT, compare: true },
|
|
10
|
+
colorScaleLo: { type: 'number', value: 0.0, compare: true },
|
|
11
|
+
colorScaleHi: { type: 'number', value: 1.0, compare: true },
|
|
12
|
+
isExpressionMode: false,
|
|
13
|
+
getExpressionValue: { type: 'accessor', value: 0 },
|
|
14
|
+
getSelectionState: { type: 'accessor', value: 0.0 },
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default class ScaledExpressionExtension extends LayerExtension {
|
|
18
|
+
getShaders() {
|
|
19
|
+
const { colormap } = this.props;
|
|
20
|
+
return {
|
|
21
|
+
modules: [module],
|
|
22
|
+
defines: {
|
|
23
|
+
[COLORMAP_SHADER_PLACEHOLDER]: GLSL_COLORMAPS.includes(colormap)
|
|
24
|
+
? colormap
|
|
25
|
+
: GLSL_COLORMAP_DEFAULT,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
updateState({ props, oldProps }) {
|
|
31
|
+
if (props.colormap !== oldProps.colormap) {
|
|
32
|
+
const { gl } = this.context;
|
|
33
|
+
// Normal single model layers, like ScatterplotLayer
|
|
34
|
+
if (this.state.model) {
|
|
35
|
+
// eslint-disable-next-line no-unused-expressions
|
|
36
|
+
this.state.model?.delete();
|
|
37
|
+
this.state.model = this._getModel(gl);
|
|
38
|
+
} else {
|
|
39
|
+
// Special handling for PolygonLayer sublayer models.
|
|
40
|
+
if (this.state.models) {
|
|
41
|
+
// eslint-disable-next-line no-unused-expressions
|
|
42
|
+
this.state.models?.forEach(model => model?.delete());
|
|
43
|
+
}
|
|
44
|
+
if (this.state.topModel) {
|
|
45
|
+
// eslint-disable-next-line no-unused-expressions
|
|
46
|
+
this.state.topModel?.delete();
|
|
47
|
+
}
|
|
48
|
+
if (this.state.sideModel) {
|
|
49
|
+
// eslint-disable-next-line no-unused-expressions
|
|
50
|
+
this.state.sideModel?.delete();
|
|
51
|
+
}
|
|
52
|
+
if (this._getModels) {
|
|
53
|
+
this.setState(this._getModels(this.context.gl));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const attributeManager = this.getAttributeManager();
|
|
57
|
+
if (attributeManager) {
|
|
58
|
+
this.getAttributeManager().invalidateAll();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
initializeState() {
|
|
64
|
+
const layer = this.getCurrentLayer();
|
|
65
|
+
// No need to run this on layers that don't have a `draw` call.
|
|
66
|
+
if (layer.isComposite) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const attributeManager = this.getAttributeManager();
|
|
70
|
+
if (attributeManager) {
|
|
71
|
+
// This attributes is the array of expression data needed for
|
|
72
|
+
// coloring cells against the colormap.
|
|
73
|
+
attributeManager.add({
|
|
74
|
+
expressionValue: {
|
|
75
|
+
type: GL.FLOAT,
|
|
76
|
+
size: 1,
|
|
77
|
+
transition: true,
|
|
78
|
+
accessor: 'getExpressionValue',
|
|
79
|
+
defaultValue: 1,
|
|
80
|
+
// PolygonLayer fill needs not-intsanced attribute but
|
|
81
|
+
// ScatterplotLayer and the PolygonLayer stroke needs instanced.
|
|
82
|
+
// So use another attribute's divisor property as a proxy for this divisor.
|
|
83
|
+
divisor: Object.values(attributeManager.attributes)[0].settings.divisor,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
draw() {
|
|
90
|
+
const {
|
|
91
|
+
colorScaleLo,
|
|
92
|
+
colorScaleHi,
|
|
93
|
+
isExpressionMode,
|
|
94
|
+
} = this.props;
|
|
95
|
+
const {
|
|
96
|
+
topModel, sideModel, models, model,
|
|
97
|
+
} = this.state;
|
|
98
|
+
const uniforms = {
|
|
99
|
+
uColorScaleRange: [colorScaleLo, colorScaleHi],
|
|
100
|
+
uIsExpressionMode: isExpressionMode,
|
|
101
|
+
};
|
|
102
|
+
// ScatterplotLayer model
|
|
103
|
+
// eslint-disable-next-line no-unused-expressions
|
|
104
|
+
model?.setUniforms(uniforms);
|
|
105
|
+
|
|
106
|
+
// PolygonLayer models from sublayers
|
|
107
|
+
// eslint-disable-next-line no-unused-expressions
|
|
108
|
+
models?.forEach(m => m.setUniforms(uniforms));
|
|
109
|
+
// eslint-disable-next-line no-unused-expressions
|
|
110
|
+
topModel?.setUniforms(uniforms);
|
|
111
|
+
// eslint-disable-next-line no-unused-expressions
|
|
112
|
+
sideModel?.setUniforms(uniforms);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
ScaledExpressionExtension.extensionName = 'ScaledExpressionExtension';
|
|
117
|
+
ScaledExpressionExtension.defaultProps = defaultProps;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { colormaps } from '../glsl/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Reference: https://github.com/visgl/deck.gl/blob/8.4-release/modules/layers/src/scatterplot-layer/scatterplot-layer-vertex.glsl.js
|
|
6
|
+
* Reference: https://observablehq.com/@rreusser/selecting-the-right-opacity-for-2d-point-clouds
|
|
7
|
+
* Reference: https://github.com/flekschas/regl-scatterplot/blob/5e3b03e/src/point.vs
|
|
8
|
+
*/
|
|
9
|
+
const vs = `
|
|
10
|
+
${colormaps}
|
|
11
|
+
|
|
12
|
+
// Custom attributes for Vitessce:
|
|
13
|
+
attribute float expressionValue;
|
|
14
|
+
|
|
15
|
+
// Custom uniforms for Vitessce:
|
|
16
|
+
uniform vec2 uColorScaleRange;
|
|
17
|
+
uniform bool uIsExpressionMode;
|
|
18
|
+
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const inject = {
|
|
22
|
+
'vs:DECKGL_FILTER_COLOR': `
|
|
23
|
+
if(uIsExpressionMode) {
|
|
24
|
+
float normalizedExpressionValue = expressionValue / 255.0;
|
|
25
|
+
float scaledExpressionValue = (normalizedExpressionValue - uColorScaleRange[0]) / max(0.005, (uColorScaleRange[1] - uColorScaleRange[0]));
|
|
26
|
+
color.rgb = COLORMAP_FUNC(clamp(scaledExpressionValue, 0.0, 1.0)).rgb;
|
|
27
|
+
}
|
|
28
|
+
`,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default {
|
|
32
|
+
name: 'scaled-expression',
|
|
33
|
+
vs,
|
|
34
|
+
inject,
|
|
35
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
3
|
+
import GL from '@luma.gl/constants';
|
|
4
|
+
import { LayerExtension } from '@deck.gl/core';
|
|
5
|
+
import module from './shader-module.js';
|
|
6
|
+
|
|
7
|
+
export default class SelectionExtension extends LayerExtension {
|
|
8
|
+
// eslint-disable-next-line class-methods-use-this
|
|
9
|
+
getShaders() {
|
|
10
|
+
return {
|
|
11
|
+
modules: [module],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
initializeState(context, extension) {
|
|
16
|
+
const attributeManager = this.getAttributeManager();
|
|
17
|
+
if (attributeManager) {
|
|
18
|
+
attributeManager.add({
|
|
19
|
+
isSelected: {
|
|
20
|
+
type: GL.FLOAT,
|
|
21
|
+
size: 1,
|
|
22
|
+
transition: true,
|
|
23
|
+
accessor: 'getCellIsSelected',
|
|
24
|
+
defaultValue: 1,
|
|
25
|
+
// PolygonLayer needs not-intsanced attribute but
|
|
26
|
+
// ScatterplotLayer needs instanced.
|
|
27
|
+
divisor: Number(extension.opts.instanced),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
SelectionExtension.extensionName = 'SelectionExtension';
|