@vitessce/gl 2.0.3-beta.0 → 2.0.3
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.04b04545.mjs +11 -0
- package/dist/index.9aaafdeb.mjs +118035 -0
- package/dist/index.mjs +33 -0
- package/dist/jpeg.060c9bc0.mjs +838 -0
- package/dist/lerc.62b02b29.mjs +1933 -0
- package/dist/lzw.19cdd4de.mjs +126 -0
- package/dist/packbits.03fc75de.mjs +28 -0
- package/dist/pako.esm.0e57f323.mjs +3940 -0
- package/dist/raw.739ce163.mjs +10 -0
- package/dist/webimage.4e868fb9.mjs +30 -0
- package/{dist → dist-tsc}/index.js +0 -0
- package/package.json +7 -7
- package/src/BitmaskLayer.js +165 -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/{dist → src}/ScaledExpressionExtension/index.js +1 -0
- package/{dist → src}/ScaledExpressionExtension/shader-module.js +7 -4
- package/src/SelectionExtension/SelectionExtension.js +34 -0
- package/{dist → src}/SelectionExtension/index.js +1 -0
- package/{dist → src}/SelectionExtension/shader-module.js +7 -5
- package/src/SelectionLayer.js +198 -0
- package/{dist → src}/bitmask-layer-shaders.js +2 -0
- package/{dist → src}/constants.js +5 -3
- package/{dist → src}/deck.js +0 -0
- package/src/glsl/README.md +8 -0
- package/src/glsl/colormaps.in.glsl +15 -0
- package/{dist → src}/glsl/index.js +1 -0
- package/{dist → src}/heatmap-bitmap-layer-shaders.js +2 -0
- package/{dist → src}/heatmap-constants.js +11 -8
- package/src/index.js +33 -0
- package/{dist → src}/luma.js +0 -0
- package/{dist → src}/padded-expression-heatmap-bitmap-layer-shaders.js +2 -0
- package/src/selection-utils.js +109 -0
- package/src/viv.js +20 -0
- package/dist/BitmaskLayer.js +0 -132
- package/dist/HeatmapBitmapLayer.js +0 -123
- package/dist/HeatmapCompositeTextLayer.js +0 -129
- package/dist/PaddedExpressionHeatmapBitmapLayer.js +0 -129
- package/dist/PixelatedBitmapLayer.js +0 -26
- package/dist/ScaledExpressionExtension/ScaledExpressionExtension.js +0 -105
- package/dist/SelectionExtension/SelectionExtension.js +0 -31
- package/dist/SelectionLayer.js +0 -167
- package/dist/layer-controller.js +0 -109
- package/dist/selection-utils.js +0 -92
- package/dist/spatial.js +0 -281
- package/dist/spatial.test.js +0 -8
- package/dist/viv.js +0 -3
|
@@ -1,129 +0,0 @@
|
|
|
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';
|
|
7
|
-
import { GLSL_COLORMAPS, GLSL_COLORMAP_DEFAULT, COLORMAP_SHADER_PLACEHOLDER } from './constants';
|
|
8
|
-
import { vertexShader, fragmentShader } from './padded-expression-heatmap-bitmap-layer-shaders';
|
|
9
|
-
const defaultProps = {
|
|
10
|
-
image: { type: 'object', value: null, async: true },
|
|
11
|
-
colormap: { type: 'string', value: GLSL_COLORMAP_DEFAULT, compare: true },
|
|
12
|
-
bounds: { type: 'array', value: [1, 0, 0, 1], compare: true },
|
|
13
|
-
aggSizeX: { type: 'number', value: 8.0, compare: true },
|
|
14
|
-
aggSizeY: { type: 'number', value: 8.0, compare: true },
|
|
15
|
-
colorScaleLo: { type: 'number', value: 0.0, compare: true },
|
|
16
|
-
colorScaleHi: { type: 'number', value: 1.0, compare: true },
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* A BitmapLayer that performs aggregation in the fragment shader,
|
|
20
|
-
* and renders its texture from a Uint8Array rather than an ImageData.
|
|
21
|
-
*/
|
|
22
|
-
export default class PaddedExpressionHeatmapBitmapLayer extends BitmapLayer {
|
|
23
|
-
/**
|
|
24
|
-
* Copy of getShaders from Layer (grandparent, parent of BitmapLayer).
|
|
25
|
-
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/core/src/lib/layer.js#L302
|
|
26
|
-
* @param {object} shaders
|
|
27
|
-
* @returns {object} Merged shaders.
|
|
28
|
-
*/
|
|
29
|
-
_getShaders(shaders) {
|
|
30
|
-
this.props.extensions.forEach((extension) => {
|
|
31
|
-
// eslint-disable-next-line no-param-reassign
|
|
32
|
-
shaders = _mergeShaders(shaders, extension.getShaders.call(this, extension));
|
|
33
|
-
});
|
|
34
|
-
return shaders;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Need to override to provide custom shaders.
|
|
38
|
-
*/
|
|
39
|
-
getShaders() {
|
|
40
|
-
const { colormap } = this.props;
|
|
41
|
-
const fragmentShaderWithColormap = GLSL_COLORMAPS.includes(colormap)
|
|
42
|
-
? fragmentShader.replace(COLORMAP_SHADER_PLACEHOLDER, colormap)
|
|
43
|
-
: fragmentShader.replace(COLORMAP_SHADER_PLACEHOLDER, GLSL_COLORMAP_DEFAULT);
|
|
44
|
-
return this._getShaders({
|
|
45
|
-
vs: vertexShader,
|
|
46
|
-
fs: fragmentShaderWithColormap,
|
|
47
|
-
modules: [project32, picking],
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
updateState(args) {
|
|
51
|
-
super.updateState(args);
|
|
52
|
-
const { props, oldProps } = args;
|
|
53
|
-
if (props.colormap !== oldProps.colormap) {
|
|
54
|
-
const { gl } = this.context;
|
|
55
|
-
// eslint-disable-next-line no-unused-expressions
|
|
56
|
-
this.state.model?.delete();
|
|
57
|
-
this.state.model = this._getModel(gl);
|
|
58
|
-
this.getAttributeManager().invalidateAll();
|
|
59
|
-
}
|
|
60
|
-
if (props.image !== oldProps.image) {
|
|
61
|
-
this.loadTexture(this.props.image);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Need to override to provide additional uniform values.
|
|
66
|
-
* Simplified by removing video-related code.
|
|
67
|
-
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/layers/src/bitmap-layer/bitmap-layer.js#L173
|
|
68
|
-
* @param {*} opts
|
|
69
|
-
*/
|
|
70
|
-
draw(opts) {
|
|
71
|
-
const { uniforms } = opts;
|
|
72
|
-
const { bitmapTexture, model } = this.state;
|
|
73
|
-
const { aggSizeX, aggSizeY, colorScaleLo, colorScaleHi, origDataSize, tileI, tileJ, numXTiles, numYTiles, } = this.props;
|
|
74
|
-
// Render the image
|
|
75
|
-
if (bitmapTexture && model) {
|
|
76
|
-
model
|
|
77
|
-
.setUniforms(Object.assign({}, uniforms, {
|
|
78
|
-
uBitmapTexture: bitmapTexture,
|
|
79
|
-
uOrigDataSize: origDataSize,
|
|
80
|
-
uReshapedDataSize: [DATA_TEXTURE_SIZE, DATA_TEXTURE_SIZE],
|
|
81
|
-
uTextureSize: [TILE_SIZE, TILE_SIZE],
|
|
82
|
-
uAggSize: [aggSizeX, aggSizeY],
|
|
83
|
-
uColorScaleRange: [colorScaleLo, colorScaleHi],
|
|
84
|
-
tileIJ: [tileI, tileJ],
|
|
85
|
-
dataIJ: [0, 0],
|
|
86
|
-
numTiles: [numXTiles, numYTiles],
|
|
87
|
-
numData: [1, 1],
|
|
88
|
-
}))
|
|
89
|
-
.draw();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Need to override to provide the custom DEFAULT_TEXTURE_PARAMETERS
|
|
94
|
-
* object.
|
|
95
|
-
* Simplified by removing video-related code.
|
|
96
|
-
* Reference: https://github.com/visgl/deck.gl/blob/0afd4e99a6199aeec979989e0c361c97e6c17a16/modules/layers/src/bitmap-layer/bitmap-layer.js#L218
|
|
97
|
-
* @param {Array<Uint8Array>} images
|
|
98
|
-
*/
|
|
99
|
-
loadTexture(image) {
|
|
100
|
-
const { gl } = this.context;
|
|
101
|
-
if (this.state.bitmapTexture) {
|
|
102
|
-
this.state.bitmapTexture.delete();
|
|
103
|
-
}
|
|
104
|
-
if (image && image instanceof Texture2D) {
|
|
105
|
-
this.setState({
|
|
106
|
-
bitmapTexture: image,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
else if (image) {
|
|
110
|
-
this.setState({
|
|
111
|
-
bitmapTexture: new Texture2D(gl, {
|
|
112
|
-
data: image,
|
|
113
|
-
mipmaps: false,
|
|
114
|
-
parameters: PIXELATED_TEXTURE_PARAMETERS,
|
|
115
|
-
// Each color contains a single luminance value.
|
|
116
|
-
// When sampled, rgb are all set to this luminance, alpha is 1.0.
|
|
117
|
-
// Reference: https://luma.gl/docs/api-reference/webgl/texture#texture-formats
|
|
118
|
-
format: GL.LUMINANCE,
|
|
119
|
-
dataFormat: GL.LUMINANCE,
|
|
120
|
-
type: GL.UNSIGNED_BYTE,
|
|
121
|
-
width: DATA_TEXTURE_SIZE,
|
|
122
|
-
height: DATA_TEXTURE_SIZE,
|
|
123
|
-
}),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
PaddedExpressionHeatmapBitmapLayer.layerName = 'PaddedExpressionHeatmapBitmapLayer';
|
|
129
|
-
PaddedExpressionHeatmapBitmapLayer.defaultProps = defaultProps;
|
|
@@ -1,26 +0,0 @@
|
|
|
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';
|
|
4
|
-
// These are the same defaultProps as for BitmapLayer.
|
|
5
|
-
const defaultProps = {
|
|
6
|
-
...BitmapLayer.defaultProps,
|
|
7
|
-
image: { type: 'object', value: null, async: true },
|
|
8
|
-
bounds: { type: 'array', value: [1, 0, 0, 1], compare: true },
|
|
9
|
-
desaturate: {
|
|
10
|
-
type: 'number', min: 0, max: 1, value: 0,
|
|
11
|
-
},
|
|
12
|
-
transparentColor: { type: 'color', value: [0, 0, 0, 0] },
|
|
13
|
-
tintColor: { type: 'color', value: [255, 255, 255] },
|
|
14
|
-
};
|
|
15
|
-
export default class PixelatedBitmapLayer extends CompositeLayer {
|
|
16
|
-
renderLayers() {
|
|
17
|
-
const { image } = this.props;
|
|
18
|
-
return new BitmapLayer(this.props, {
|
|
19
|
-
id: `${this.props.id}-wrapped`,
|
|
20
|
-
image,
|
|
21
|
-
textureParameters: PIXELATED_TEXTURE_PARAMETERS,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
PixelatedBitmapLayer.layerName = 'PixelatedBitmapLayer';
|
|
26
|
-
PixelatedBitmapLayer.defaultProps = defaultProps;
|
|
@@ -1,105 +0,0 @@
|
|
|
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';
|
|
6
|
-
import module from './shader-module';
|
|
7
|
-
const defaultProps = {
|
|
8
|
-
colormap: { type: 'string', value: GLSL_COLORMAP_DEFAULT, compare: true },
|
|
9
|
-
colorScaleLo: { type: 'number', value: 0.0, compare: true },
|
|
10
|
-
colorScaleHi: { type: 'number', value: 1.0, compare: true },
|
|
11
|
-
isExpressionMode: false,
|
|
12
|
-
getExpressionValue: { type: 'accessor', value: 0 },
|
|
13
|
-
getSelectionState: { type: 'accessor', value: 0.0 },
|
|
14
|
-
};
|
|
15
|
-
export default class ScaledExpressionExtension extends LayerExtension {
|
|
16
|
-
getShaders() {
|
|
17
|
-
const { colormap } = this.props;
|
|
18
|
-
return {
|
|
19
|
-
modules: [module],
|
|
20
|
-
defines: {
|
|
21
|
-
[COLORMAP_SHADER_PLACEHOLDER]: GLSL_COLORMAPS.includes(colormap)
|
|
22
|
-
? colormap
|
|
23
|
-
: GLSL_COLORMAP_DEFAULT,
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
updateState({ props, oldProps }) {
|
|
28
|
-
if (props.colormap !== oldProps.colormap) {
|
|
29
|
-
const { gl } = this.context;
|
|
30
|
-
// Normal single model layers, like ScatterplotLayer
|
|
31
|
-
if (this.state.model) {
|
|
32
|
-
// eslint-disable-next-line no-unused-expressions
|
|
33
|
-
this.state.model?.delete();
|
|
34
|
-
this.state.model = this._getModel(gl);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
// Special handling for PolygonLayer sublayer models.
|
|
38
|
-
if (this.state.models) {
|
|
39
|
-
// eslint-disable-next-line no-unused-expressions
|
|
40
|
-
this.state.models?.forEach(model => model?.delete());
|
|
41
|
-
}
|
|
42
|
-
if (this.state.topModel) {
|
|
43
|
-
// eslint-disable-next-line no-unused-expressions
|
|
44
|
-
this.state.topModel?.delete();
|
|
45
|
-
}
|
|
46
|
-
if (this.state.sideModel) {
|
|
47
|
-
// eslint-disable-next-line no-unused-expressions
|
|
48
|
-
this.state.sideModel?.delete();
|
|
49
|
-
}
|
|
50
|
-
if (this._getModels) {
|
|
51
|
-
this.setState(this._getModels(this.context.gl));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const attributeManager = this.getAttributeManager();
|
|
55
|
-
if (attributeManager) {
|
|
56
|
-
this.getAttributeManager().invalidateAll();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
initializeState() {
|
|
61
|
-
const layer = this.getCurrentLayer();
|
|
62
|
-
// No need to run this on layers that don't have a `draw` call.
|
|
63
|
-
if (layer.isComposite) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const attributeManager = this.getAttributeManager();
|
|
67
|
-
if (attributeManager) {
|
|
68
|
-
// This attributes is the array of expression data needed for
|
|
69
|
-
// coloring cells against the colormap.
|
|
70
|
-
attributeManager.add({
|
|
71
|
-
expressionValue: {
|
|
72
|
-
type: GL.FLOAT,
|
|
73
|
-
size: 1,
|
|
74
|
-
transition: true,
|
|
75
|
-
accessor: 'getExpressionValue',
|
|
76
|
-
defaultValue: 1,
|
|
77
|
-
// PolygonLayer fill needs not-intsanced attribute but
|
|
78
|
-
// ScatterplotLayer and the PolygonLayer stroke needs instanced.
|
|
79
|
-
// So use another attribute's divisor property as a proxy for this divisor.
|
|
80
|
-
divisor: Object.values(attributeManager.attributes)[0].settings.divisor,
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
draw() {
|
|
86
|
-
const { colorScaleLo, colorScaleHi, isExpressionMode, } = this.props;
|
|
87
|
-
const { topModel, sideModel, models, model, } = this.state;
|
|
88
|
-
const uniforms = {
|
|
89
|
-
uColorScaleRange: [colorScaleLo, colorScaleHi],
|
|
90
|
-
uIsExpressionMode: isExpressionMode,
|
|
91
|
-
};
|
|
92
|
-
// ScatterplotLayer model
|
|
93
|
-
// eslint-disable-next-line no-unused-expressions
|
|
94
|
-
model?.setUniforms(uniforms);
|
|
95
|
-
// PolygonLayer models from sublayers
|
|
96
|
-
// eslint-disable-next-line no-unused-expressions
|
|
97
|
-
models?.forEach(m => m.setUniforms(uniforms));
|
|
98
|
-
// eslint-disable-next-line no-unused-expressions
|
|
99
|
-
topModel?.setUniforms(uniforms);
|
|
100
|
-
// eslint-disable-next-line no-unused-expressions
|
|
101
|
-
sideModel?.setUniforms(uniforms);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
ScaledExpressionExtension.extensionName = 'ScaledExpressionExtension';
|
|
105
|
-
ScaledExpressionExtension.defaultProps = defaultProps;
|
|
@@ -1,31 +0,0 @@
|
|
|
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';
|
|
6
|
-
export default class SelectionExtension extends LayerExtension {
|
|
7
|
-
// eslint-disable-next-line class-methods-use-this
|
|
8
|
-
getShaders() {
|
|
9
|
-
return {
|
|
10
|
-
modules: [module],
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
initializeState(context, extension) {
|
|
14
|
-
const attributeManager = this.getAttributeManager();
|
|
15
|
-
if (attributeManager) {
|
|
16
|
-
attributeManager.add({
|
|
17
|
-
isSelected: {
|
|
18
|
-
type: GL.FLOAT,
|
|
19
|
-
size: 1,
|
|
20
|
-
transition: true,
|
|
21
|
-
accessor: 'getCellIsSelected',
|
|
22
|
-
defaultValue: 1,
|
|
23
|
-
// PolygonLayer needs not-intsanced attribute but
|
|
24
|
-
// ScatterplotLayer needs instanced.
|
|
25
|
-
divisor: Number(extension.opts.instanced),
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
SelectionExtension.extensionName = 'SelectionExtension';
|
package/dist/SelectionLayer.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
|
-
/* eslint-disable no-underscore-dangle */
|
|
3
|
-
// File adopted from nebula.gl's SelectionLayer
|
|
4
|
-
// https://github.com/uber/nebula.gl/blob/8e9c2ec8d7cf4ca7050909ed826eb847d5e2cd9c/modules/layers/src/layers/selection-layer.js
|
|
5
|
-
import { CompositeLayer } from 'deck.gl';
|
|
6
|
-
import { polygon as turfPolygon, point as turfPoint } from '@turf/helpers';
|
|
7
|
-
import booleanWithin from '@turf/boolean-within';
|
|
8
|
-
import booleanContains from '@turf/boolean-contains';
|
|
9
|
-
import booleanOverlap from '@turf/boolean-overlap';
|
|
10
|
-
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
|
|
11
|
-
import { ScatterplotLayer } from '@deck.gl/layers';
|
|
12
|
-
import { SELECTION_TYPE } from 'nebula.gl';
|
|
13
|
-
import { EditableGeoJsonLayer } from '@nebula.gl/layers';
|
|
14
|
-
import { DrawRectangleMode, DrawPolygonByDraggingMode, ViewMode } from '@nebula.gl/edit-modes';
|
|
15
|
-
const EDIT_TYPE_ADD = 'addFeature';
|
|
16
|
-
const EDIT_TYPE_CLEAR = 'clearFeatures';
|
|
17
|
-
// Customize the click handlers for the rectangle and polygon tools,
|
|
18
|
-
// so that clicking triggers the `onEdit` callback.
|
|
19
|
-
class ClickableDrawRectangleMode extends DrawRectangleMode {
|
|
20
|
-
// eslint-disable-next-line class-methods-use-this
|
|
21
|
-
handleClick(event, props) {
|
|
22
|
-
props.onEdit({ editType: EDIT_TYPE_CLEAR });
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
class ClickableDrawPolygonByDraggingMode extends DrawPolygonByDraggingMode {
|
|
26
|
-
// eslint-disable-next-line class-methods-use-this
|
|
27
|
-
handleClick(event, props) {
|
|
28
|
-
props.onEdit({ editType: EDIT_TYPE_CLEAR });
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
const MODE_MAP = {
|
|
32
|
-
[SELECTION_TYPE.RECTANGLE]: ClickableDrawRectangleMode,
|
|
33
|
-
[SELECTION_TYPE.POLYGON]: ClickableDrawPolygonByDraggingMode,
|
|
34
|
-
};
|
|
35
|
-
const defaultProps = {
|
|
36
|
-
selectionType: SELECTION_TYPE.RECTANGLE,
|
|
37
|
-
layerIds: [],
|
|
38
|
-
onSelect: () => { },
|
|
39
|
-
};
|
|
40
|
-
const EMPTY_DATA = {
|
|
41
|
-
type: 'FeatureCollection',
|
|
42
|
-
features: [],
|
|
43
|
-
};
|
|
44
|
-
const LAYER_ID_GEOJSON = 'selection-geojson';
|
|
45
|
-
const PASS_THROUGH_PROPS = [
|
|
46
|
-
'lineWidthScale',
|
|
47
|
-
'lineWidthMinPixels',
|
|
48
|
-
'lineWidthMaxPixels',
|
|
49
|
-
'lineWidthUnits',
|
|
50
|
-
'lineJointRounded',
|
|
51
|
-
'lineMiterLimit',
|
|
52
|
-
'pointRadiusScale',
|
|
53
|
-
'pointRadiusMinPixels',
|
|
54
|
-
'pointRadiusMaxPixels',
|
|
55
|
-
'lineDashJustified',
|
|
56
|
-
'getLineColor',
|
|
57
|
-
'getFillColor',
|
|
58
|
-
'getPointRadius',
|
|
59
|
-
'getLineWidth',
|
|
60
|
-
'getLineDashArray',
|
|
61
|
-
'getTentativeLineDashArray',
|
|
62
|
-
'getTentativeLineColor',
|
|
63
|
-
'getTentativeFillColor',
|
|
64
|
-
'getTentativeLineWidth',
|
|
65
|
-
'editHandlePointRadiusScale',
|
|
66
|
-
'editHandlePointRadiusMinPixels',
|
|
67
|
-
'editHandlePointRadiusMaxPixels',
|
|
68
|
-
'getEditHandlePointColor',
|
|
69
|
-
'getEditHandlePointRadius',
|
|
70
|
-
'modeHandlers',
|
|
71
|
-
];
|
|
72
|
-
export default class SelectionLayer extends CompositeLayer {
|
|
73
|
-
_selectPolygonObjects(coordinates) {
|
|
74
|
-
const { onSelect, getCellCoords, cellsQuadTree, flipY, } = this.props;
|
|
75
|
-
const flippedCoordinates = (flipY
|
|
76
|
-
? coordinates.map(poly => poly.map(p => ([p[0], -p[1]])))
|
|
77
|
-
: coordinates);
|
|
78
|
-
// Convert the selection to a turf polygon object.
|
|
79
|
-
const selectedPolygon = turfPolygon(flippedCoordinates);
|
|
80
|
-
// Create an array to store the results.
|
|
81
|
-
const pickingInfos = [];
|
|
82
|
-
// quadtree.visit() takes a callback that returns a boolean:
|
|
83
|
-
// If true returned, then the children of the node are _not_ visited.
|
|
84
|
-
// If false returned, then the children of the node are visited.
|
|
85
|
-
// Reference: https://github.com/d3/d3-quadtree#quadtree_visit
|
|
86
|
-
cellsQuadTree.visit((node, x0, y0, x1, y1) => {
|
|
87
|
-
const nodePoints = [[[x0, y0], [x1, y0], [x1, y1], [x0, y1], [x0, y0]]];
|
|
88
|
-
const nodePolygon = turfPolygon(nodePoints);
|
|
89
|
-
const nodePolygonContainsSelectedPolygon = booleanContains(nodePolygon, selectedPolygon);
|
|
90
|
-
const nodePolygonWithinSelectedPolygon = booleanWithin(nodePolygon, selectedPolygon);
|
|
91
|
-
const nodePolygonOverlapsSelectedPolgyon = booleanOverlap(nodePolygon, selectedPolygon);
|
|
92
|
-
if (!nodePolygonContainsSelectedPolygon
|
|
93
|
-
&& !nodePolygonWithinSelectedPolygon
|
|
94
|
-
&& !nodePolygonOverlapsSelectedPolgyon) {
|
|
95
|
-
// We are not interested in anything below this node,
|
|
96
|
-
// so return true because we are done with this node.
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
// This node made it past the above return statement, so it must either
|
|
100
|
-
// contain, be within, or overlap with the selected polygon.
|
|
101
|
-
// Check if this is a leaf node.
|
|
102
|
-
if (node.data
|
|
103
|
-
&& booleanPointInPolygon(turfPoint([].slice.call(getCellCoords(node.data))), selectedPolygon)) {
|
|
104
|
-
// This node has data, so it is a leaf node representing one data point,
|
|
105
|
-
// and we have verified that the point is in the selected polygon.
|
|
106
|
-
pickingInfos.push(node.data);
|
|
107
|
-
}
|
|
108
|
-
// Return false because we are not done.
|
|
109
|
-
// We want to visit the children of this node.
|
|
110
|
-
return false;
|
|
111
|
-
});
|
|
112
|
-
onSelect({ pickingInfos });
|
|
113
|
-
}
|
|
114
|
-
renderLayers() {
|
|
115
|
-
const { onSelect } = this.props;
|
|
116
|
-
const mode = MODE_MAP[this.props.selectionType] || ViewMode;
|
|
117
|
-
const inheritedProps = {};
|
|
118
|
-
PASS_THROUGH_PROPS.forEach((p) => {
|
|
119
|
-
if (this.props[p] !== undefined)
|
|
120
|
-
inheritedProps[p] = this.props[p];
|
|
121
|
-
});
|
|
122
|
-
const layers = [
|
|
123
|
-
new EditableGeoJsonLayer(this.getSubLayerProps({
|
|
124
|
-
id: LAYER_ID_GEOJSON,
|
|
125
|
-
pickable: true,
|
|
126
|
-
mode,
|
|
127
|
-
modeConfig: {
|
|
128
|
-
dragToDraw: true,
|
|
129
|
-
},
|
|
130
|
-
selectedFeatureIndexes: [],
|
|
131
|
-
data: EMPTY_DATA,
|
|
132
|
-
onEdit: ({ updatedData, editType }) => {
|
|
133
|
-
if (editType === EDIT_TYPE_ADD) {
|
|
134
|
-
const { coordinates } = updatedData.features[0].geometry;
|
|
135
|
-
this._selectPolygonObjects(coordinates);
|
|
136
|
-
}
|
|
137
|
-
else if (editType === EDIT_TYPE_CLEAR) {
|
|
138
|
-
// We want to select an empty array to clear any previous selection.
|
|
139
|
-
onSelect({ pickingInfos: [] });
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
_subLayerProps: {
|
|
143
|
-
guides: {
|
|
144
|
-
pointType: 'circle',
|
|
145
|
-
_subLayerProps: {
|
|
146
|
-
'points-circle': {
|
|
147
|
-
// Styling for editHandles goes here.
|
|
148
|
-
// Reference: https://github.com/uber/nebula.gl/issues/618#issuecomment-898466319
|
|
149
|
-
type: ScatterplotLayer,
|
|
150
|
-
radiusScale: 1,
|
|
151
|
-
stroked: true,
|
|
152
|
-
getLineWidth: 1,
|
|
153
|
-
radiusMinPixels: 1,
|
|
154
|
-
radiusMaxPixels: 3,
|
|
155
|
-
getPointRadius: 2,
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
...inheritedProps,
|
|
161
|
-
})),
|
|
162
|
-
];
|
|
163
|
-
return layers;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
SelectionLayer.layerName = 'SelectionLayer';
|
|
167
|
-
SelectionLayer.defaultProps = defaultProps;
|
package/dist/layer-controller.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { Matrix4 } from 'math.gl';
|
|
2
|
-
import { getChannelStats } from './viv';
|
|
3
|
-
async function getSingleSelectionStats2D({ loader, selection }) {
|
|
4
|
-
const data = Array.isArray(loader) ? loader[loader.length - 1] : loader;
|
|
5
|
-
const raster = await data.getRaster({ selection });
|
|
6
|
-
const selectionStats = getChannelStats(raster.data);
|
|
7
|
-
const { domain, contrastLimits: slider } = selectionStats;
|
|
8
|
-
return { domain, slider };
|
|
9
|
-
}
|
|
10
|
-
async function getSingleSelectionStats3D({ loader, selection }) {
|
|
11
|
-
const lowResSource = loader[loader.length - 1];
|
|
12
|
-
const { shape, labels } = lowResSource;
|
|
13
|
-
// eslint-disable-next-line no-bitwise
|
|
14
|
-
const sizeZ = shape[labels.indexOf('z')] >> (loader.length - 1);
|
|
15
|
-
const raster0 = await lowResSource.getRaster({
|
|
16
|
-
selection: { ...selection, z: 0 },
|
|
17
|
-
});
|
|
18
|
-
const rasterMid = await lowResSource.getRaster({
|
|
19
|
-
selection: { ...selection, z: Math.floor(sizeZ / 2) },
|
|
20
|
-
});
|
|
21
|
-
const rasterTop = await lowResSource.getRaster({
|
|
22
|
-
selection: { ...selection, z: Math.max(0, sizeZ - 1) },
|
|
23
|
-
});
|
|
24
|
-
const stats0 = getChannelStats(raster0.data);
|
|
25
|
-
const statsMid = getChannelStats(rasterMid.data);
|
|
26
|
-
const statsTop = getChannelStats(rasterTop.data);
|
|
27
|
-
return {
|
|
28
|
-
domain: [
|
|
29
|
-
Math.min(stats0.domain[0], statsMid.domain[0], statsTop.domain[0]),
|
|
30
|
-
Math.max(stats0.domain[1], statsMid.domain[1], statsTop.domain[1]),
|
|
31
|
-
],
|
|
32
|
-
slider: [
|
|
33
|
-
Math.min(stats0.contrastLimits[0], statsMid.contrastLimits[0], statsTop.contrastLimits[0]),
|
|
34
|
-
Math.max(stats0.contrastLimits[1], statsMid.contrastLimits[1], statsTop.contrastLimits[1]),
|
|
35
|
-
],
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Get bounding cube for a given loader i.e [[0, width], [0, height], [0, depth]]
|
|
40
|
-
* @param {Object} loader PixelSource|PixelSource[]
|
|
41
|
-
* @param {[]} selection Selection for stats.
|
|
42
|
-
* @param {boolean} use3d Whether or not to get 3d stats.
|
|
43
|
-
* @returns {Object} { domains, sliders }
|
|
44
|
-
*/
|
|
45
|
-
export const getSingleSelectionStats = async ({ loader, selection, use3d }) => {
|
|
46
|
-
const getStats = use3d
|
|
47
|
-
? getSingleSelectionStats3D
|
|
48
|
-
: getSingleSelectionStats2D;
|
|
49
|
-
return getStats({ loader, selection });
|
|
50
|
-
};
|
|
51
|
-
export const getMultiSelectionStats = async ({ loader, selections, use3d }) => {
|
|
52
|
-
const stats = await Promise.all(selections.map(selection => getSingleSelectionStats({ loader, selection, use3d })));
|
|
53
|
-
const domains = stats.map(stat => stat.domain);
|
|
54
|
-
const sliders = stats.map(stat => stat.slider);
|
|
55
|
-
return { domains, sliders };
|
|
56
|
-
};
|
|
57
|
-
/**
|
|
58
|
-
* Get physical size scaling Matrix4
|
|
59
|
-
* @param {Object} loader PixelSource
|
|
60
|
-
* @returns {Object} matrix
|
|
61
|
-
*/
|
|
62
|
-
export function getPhysicalSizeScalingMatrix(loader) {
|
|
63
|
-
const { x, y, z } = loader?.meta?.physicalSizes ?? {};
|
|
64
|
-
if (x?.size && y?.size && z?.size) {
|
|
65
|
-
const min = Math.min(z.size, x.size, y.size);
|
|
66
|
-
const ratio = [x.size / min, y.size / min, z.size / min];
|
|
67
|
-
return new Matrix4().scale(ratio);
|
|
68
|
-
}
|
|
69
|
-
return new Matrix4().identity();
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Get bounding cube for a given loader
|
|
73
|
-
* @param {Object} loader PixelSource|PixelSource[]
|
|
74
|
-
* @returns {Array} [0, width], [0, height], [0, depth]]
|
|
75
|
-
*/
|
|
76
|
-
export function getBoundingCube(loader) {
|
|
77
|
-
const source = Array.isArray(loader) ? loader[0] : loader;
|
|
78
|
-
const { shape, labels } = source;
|
|
79
|
-
const physicalSizeScalingMatrix = getPhysicalSizeScalingMatrix(source);
|
|
80
|
-
const xSlice = [0, physicalSizeScalingMatrix[0] * shape[labels.indexOf('x')]];
|
|
81
|
-
const ySlice = [0, physicalSizeScalingMatrix[5] * shape[labels.indexOf('y')]];
|
|
82
|
-
const zSlice = [
|
|
83
|
-
0,
|
|
84
|
-
physicalSizeScalingMatrix[10] * shape[labels.indexOf('z')],
|
|
85
|
-
];
|
|
86
|
-
return [xSlice, ySlice, zSlice];
|
|
87
|
-
}
|
|
88
|
-
export function abbreviateNumber(value) {
|
|
89
|
-
// Return an abbreviated representation of value, in 5 characters or less.
|
|
90
|
-
const maxLength = 5;
|
|
91
|
-
let maxNaiveDigits = maxLength;
|
|
92
|
-
/* eslint-disable no-plusplus */
|
|
93
|
-
if (!Number.isInteger(value)) {
|
|
94
|
-
--maxNaiveDigits;
|
|
95
|
-
} // Wasted on "."
|
|
96
|
-
if (value < 1) {
|
|
97
|
-
--maxNaiveDigits;
|
|
98
|
-
} // Wasted on "0."
|
|
99
|
-
/* eslint-disable no-plusplus */
|
|
100
|
-
const naive = Intl.NumberFormat('en-US', {
|
|
101
|
-
maximumSignificantDigits: maxNaiveDigits,
|
|
102
|
-
useGrouping: false,
|
|
103
|
-
}).format(value);
|
|
104
|
-
if (naive.length <= maxLength)
|
|
105
|
-
return naive;
|
|
106
|
-
// "e+9" consumes 3 characters, so if we even had two significant digits,
|
|
107
|
-
// it would take take us to six characters, including the decimal point.
|
|
108
|
-
return value.toExponential(0);
|
|
109
|
-
}
|
package/dist/selection-utils.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { COORDINATE_SYSTEM } from '@deck.gl/core'; // eslint-disable-line import/no-extraneous-dependencies
|
|
2
|
-
import { DataFilterExtension } from '@deck.gl/extensions'; // eslint-disable-line import/no-extraneous-dependencies
|
|
3
|
-
import SelectionLayer from './SelectionLayer';
|
|
4
|
-
/**
|
|
5
|
-
* Convert a DeckGL layer ID to a "base" layer ID for selection.
|
|
6
|
-
* @param {string} layerId The layer ID to convert.
|
|
7
|
-
* @returns {string} The base layer ID.
|
|
8
|
-
*/
|
|
9
|
-
function getBaseLayerId(layerId) {
|
|
10
|
-
return `base-${layerId}`;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Convert a DeckGL layer ID to a "selected" layer ID for selection.
|
|
14
|
-
* @param {string} layerId The layer ID to convert.
|
|
15
|
-
* @returns {string} The base layer ID.
|
|
16
|
-
*/
|
|
17
|
-
function getSelectedLayerId(layerId) {
|
|
18
|
-
return `selected-${layerId}`;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Construct DeckGL selection layers.
|
|
22
|
-
* @param {string} tool
|
|
23
|
-
* @param {number} zoom
|
|
24
|
-
* @param {string} cellBaseLayerId
|
|
25
|
-
* @param {function} getCellCoords
|
|
26
|
-
* @param {function} updateCellsSelection
|
|
27
|
-
* @returns {object[]} The array of DeckGL selection layers.
|
|
28
|
-
*/
|
|
29
|
-
export function getSelectionLayers(tool, zoom, layerId, getCellCoords, obsIndex, updateCellsSelection, cellsQuadTree, flipY = false) {
|
|
30
|
-
if (!tool) {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
const cellBaseLayerId = getBaseLayerId(layerId);
|
|
34
|
-
const editHandlePointRadius = 5 / (zoom + 16);
|
|
35
|
-
return [new SelectionLayer({
|
|
36
|
-
id: 'selection',
|
|
37
|
-
flipY,
|
|
38
|
-
cellsQuadTree,
|
|
39
|
-
getCellCoords,
|
|
40
|
-
coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
|
|
41
|
-
selectionType: tool,
|
|
42
|
-
onSelect: ({ pickingInfos }) => {
|
|
43
|
-
const cellIds = pickingInfos.map(i => obsIndex[i]);
|
|
44
|
-
if (updateCellsSelection) {
|
|
45
|
-
updateCellsSelection(cellIds);
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
layerIds: [cellBaseLayerId],
|
|
49
|
-
getTentativeFillColor: () => [255, 255, 255, 95],
|
|
50
|
-
getTentativeLineColor: () => [143, 143, 143, 255],
|
|
51
|
-
getTentativeLineDashArray: () => [7, 4],
|
|
52
|
-
lineWidthMinPixels: 2,
|
|
53
|
-
lineWidthMaxPixels: 2,
|
|
54
|
-
getEditHandlePointColor: () => [0xff, 0xff, 0xff, 0xff],
|
|
55
|
-
getEditHandlePointRadius: () => editHandlePointRadius,
|
|
56
|
-
editHandlePointRadiusScale: 1,
|
|
57
|
-
editHandlePointRadiusMinPixels: editHandlePointRadius,
|
|
58
|
-
editHandlePointRadiusMaxPixels: 2 * editHandlePointRadius,
|
|
59
|
-
})];
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Get deck.gl layer props for selection overlays.
|
|
63
|
-
* @param {object} props
|
|
64
|
-
* @returns {object} Object with two properties,
|
|
65
|
-
* overlay: overlayProps, base: baseProps,
|
|
66
|
-
* where the values are deck.gl layer props.
|
|
67
|
-
*/
|
|
68
|
-
export function overlayBaseProps(props) {
|
|
69
|
-
const { id, getColor, data, isSelected, ...rest } = props;
|
|
70
|
-
return {
|
|
71
|
-
overlay: {
|
|
72
|
-
id: getSelectedLayerId(id),
|
|
73
|
-
getFillColor: getColor,
|
|
74
|
-
getLineColor: getColor,
|
|
75
|
-
data,
|
|
76
|
-
getFilterValue: isSelected,
|
|
77
|
-
extensions: [new DataFilterExtension({ filterSize: 1 })],
|
|
78
|
-
filterRange: [1, 1],
|
|
79
|
-
...rest,
|
|
80
|
-
},
|
|
81
|
-
base: {
|
|
82
|
-
id: getBaseLayerId(id),
|
|
83
|
-
getLineColor: getColor,
|
|
84
|
-
getFillColor: getColor,
|
|
85
|
-
// Alternatively: contrast outlines with solids:
|
|
86
|
-
// getLineColor: getColor,
|
|
87
|
-
// getFillColor: [255, 255, 255],
|
|
88
|
-
data: data.slice(),
|
|
89
|
-
...rest,
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
}
|