@deck.gl/carto 9.0.17 → 9.0.18
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/cartoRasterTile-worker.js +1 -1
- package/dist/cartoSpatialTile-worker.js +1 -1
- package/dist/cartoVectorTile-worker.js +1 -1
- package/dist/dist.dev.js +440 -531
- package/dist/index.cjs +492 -422
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/layers/heatmap-tile-layer.d.ts +36 -0
- package/dist/layers/heatmap-tile-layer.d.ts.map +1 -0
- package/dist/layers/heatmap-tile-layer.js +165 -0
- package/dist/layers/heatmap.d.ts +5 -0
- package/dist/layers/heatmap.d.ts.map +1 -1
- package/dist/layers/heatmap.js +17 -15
- package/dist/layers/schema/carto-raster-tile-loader.js +1 -1
- package/dist/layers/schema/carto-spatial-tile-loader.js +1 -1
- package/dist/layers/schema/carto-vector-tile-loader.js +1 -1
- package/dist/layers/vector-tile-layer.d.ts +1 -1
- package/dist/layers/vector-tile-layer.d.ts.map +1 -1
- package/dist/layers/vector-tile-layer.js +5 -10
- package/dist.min.js +37 -31
- package/package.json +2 -2
- package/src/index.ts +3 -3
- package/src/layers/heatmap-tile-layer.ts +236 -0
- package/src/layers/heatmap.ts +31 -18
- package/src/layers/vector-tile-layer.ts +4 -14
- package/dist/layers/quadbin-heatmap-tile-layer.d.ts +0 -24
- package/dist/layers/quadbin-heatmap-tile-layer.d.ts.map +0 -1
- package/dist/layers/quadbin-heatmap-tile-layer.js +0 -84
- package/src/layers/quadbin-heatmap-tile-layer.ts +0 -135
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "CARTO official integration with Deck.gl. Build geospatial applications using CARTO and Deck.gl.",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"version": "9.0.
|
|
6
|
+
"version": "9.0.18",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"@deck.gl/layers": "^9.0.0",
|
|
74
74
|
"@loaders.gl/core": "^4.2.0"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "32f7e51eb96319739a18a3ca22092e60948fcbdb"
|
|
77
77
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import {default as H3TileLayer} from './layers/h3-tile-layer';
|
|
2
|
+
import {default as HeatmapTileLayer} from './layers/heatmap-tile-layer';
|
|
2
3
|
import {default as _PointLabelLayer} from './layers/point-label-layer';
|
|
3
4
|
import {default as QuadbinTileLayer} from './layers/quadbin-tile-layer';
|
|
4
|
-
import {default as QuadbinHeatmapTileLayer} from './layers/quadbin-heatmap-tile-layer';
|
|
5
5
|
import {default as RasterTileLayer} from './layers/raster-tile-layer';
|
|
6
6
|
import {default as VectorTileLayer} from './layers/vector-tile-layer';
|
|
7
7
|
const CARTO_LAYERS = {
|
|
8
8
|
H3TileLayer,
|
|
9
|
+
HeatmapTileLayer,
|
|
9
10
|
_PointLabelLayer,
|
|
10
11
|
QuadbinTileLayer,
|
|
11
|
-
QuadbinHeatmapTileLayer,
|
|
12
12
|
RasterTileLayer,
|
|
13
13
|
VectorTileLayer
|
|
14
14
|
};
|
|
15
15
|
export {
|
|
16
16
|
CARTO_LAYERS,
|
|
17
17
|
H3TileLayer,
|
|
18
|
+
HeatmapTileLayer,
|
|
18
19
|
_PointLabelLayer,
|
|
19
20
|
QuadbinTileLayer,
|
|
20
|
-
QuadbinHeatmapTileLayer,
|
|
21
21
|
RasterTileLayer,
|
|
22
22
|
VectorTileLayer
|
|
23
23
|
};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {getResolution} from 'quadbin';
|
|
2
|
+
|
|
3
|
+
import {Accessor, CompositeLayer, CompositeLayerProps, DefaultProps, Layer} from '@deck.gl/core';
|
|
4
|
+
import {SolidPolygonLayer} from '@deck.gl/layers';
|
|
5
|
+
|
|
6
|
+
import {HeatmapProps, heatmap} from './heatmap';
|
|
7
|
+
import {RTTModifier, PostProcessModifier} from './post-process-utils';
|
|
8
|
+
import QuadbinTileLayer, {QuadbinTileLayerProps} from './quadbin-tile-layer';
|
|
9
|
+
import {TilejsonPropType} from './utils';
|
|
10
|
+
import {TilejsonResult} from '../sources';
|
|
11
|
+
import {_Tile2DHeader as Tile2DHeader} from '@deck.gl/geo-layers';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Computes the unit density (inverse of cell area)
|
|
15
|
+
*/
|
|
16
|
+
function unitDensityForCell(cell: bigint) {
|
|
17
|
+
const cellResolution = Number(getResolution(cell));
|
|
18
|
+
return Math.pow(4.0, cellResolution);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Modified polygon layer to draw offscreen and output value expected by heatmap
|
|
22
|
+
class RTTSolidPolygonLayer extends RTTModifier(SolidPolygonLayer) {
|
|
23
|
+
static layerName = 'RTTSolidPolygonLayer';
|
|
24
|
+
|
|
25
|
+
getShaders(type) {
|
|
26
|
+
const shaders = super.getShaders(type);
|
|
27
|
+
shaders.inject = {
|
|
28
|
+
'vs:#decl': `
|
|
29
|
+
uniform float densityFactor;
|
|
30
|
+
`,
|
|
31
|
+
'vs:#main-end': `
|
|
32
|
+
// Value from getWeight accessor
|
|
33
|
+
float weight = elevations;
|
|
34
|
+
|
|
35
|
+
// Keep "power" delivered to screen constant when tiles update
|
|
36
|
+
// by outputting normalized density
|
|
37
|
+
weight *= densityFactor;
|
|
38
|
+
|
|
39
|
+
// Pack float into 3 channels to pass to heatmap shader
|
|
40
|
+
// SCALE value important, as we don't want to saturate
|
|
41
|
+
// but also want enough definition to avoid banding
|
|
42
|
+
const vec3 SHIFT = vec3(1.0, 256.0, 256.0 * 256.0);
|
|
43
|
+
const float MAX_VAL = SHIFT.z * 255.0;
|
|
44
|
+
const float SCALE = MAX_VAL / 8.0;
|
|
45
|
+
weight *= SCALE;
|
|
46
|
+
weight = clamp(weight, 0.0, MAX_VAL);
|
|
47
|
+
vColor = vec4(mod(vec3(weight, floor(weight / SHIFT.yz)), 256.0), 255.0) / 255.0;
|
|
48
|
+
`
|
|
49
|
+
};
|
|
50
|
+
return shaders;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
draw(this, opts: any) {
|
|
54
|
+
const cell = this.props!.data[0];
|
|
55
|
+
const maxDensity = this.props.elevationScale;
|
|
56
|
+
const densityFactor = unitDensityForCell(cell.id) / maxDensity;
|
|
57
|
+
for (const model of this.state.models) {
|
|
58
|
+
model.setUniforms({densityFactor});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
super.draw(opts);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Modify QuadbinTileLayer to apply heatmap post process effect
|
|
66
|
+
const PostProcessQuadbinTileLayer = PostProcessModifier(QuadbinTileLayer, heatmap);
|
|
67
|
+
|
|
68
|
+
const defaultProps: DefaultProps<HeatmapTileLayerProps> = {
|
|
69
|
+
data: TilejsonPropType,
|
|
70
|
+
getWeight: {type: 'accessor', value: 1},
|
|
71
|
+
onMaxDensityChange: {type: 'function', optional: true, value: null},
|
|
72
|
+
colorDomain: {type: 'array', value: [0, 1]},
|
|
73
|
+
intensity: {type: 'number', value: 1},
|
|
74
|
+
radiusPixels: {type: 'number', min: 0, max: 100, value: 20}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/** All properties supported by HeatmapTileLayer. */
|
|
78
|
+
export type HeatmapTileLayerProps<DataT = unknown> = _HeatmapTileLayerProps<DataT> &
|
|
79
|
+
CompositeLayerProps & {
|
|
80
|
+
data: null | TilejsonResult | Promise<TilejsonResult>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** Properties added by HeatmapTileLayer. */
|
|
84
|
+
type _HeatmapTileLayerProps<DataT> = QuadbinTileLayerProps<DataT> &
|
|
85
|
+
HeatmapProps & {
|
|
86
|
+
/**
|
|
87
|
+
* The weight of each object.
|
|
88
|
+
*
|
|
89
|
+
* @default 1
|
|
90
|
+
*/
|
|
91
|
+
getWeight?: Accessor<DataT, number>;
|
|
92
|
+
|
|
93
|
+
/** Called when maximum density in displayed tiles changes. */
|
|
94
|
+
onMaxDensityChange?: ((maxDensity: number) => void) | null;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
class HeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends CompositeLayer<
|
|
98
|
+
ExtraProps & Required<_HeatmapTileLayerProps<DataT>>
|
|
99
|
+
> {
|
|
100
|
+
static layerName = 'HeatmapTileLayer';
|
|
101
|
+
static defaultProps = defaultProps;
|
|
102
|
+
|
|
103
|
+
state!: {
|
|
104
|
+
isLoaded: boolean;
|
|
105
|
+
tiles: Set<Tile2DHeader>;
|
|
106
|
+
viewportChanged?: boolean;
|
|
107
|
+
};
|
|
108
|
+
initializeState() {
|
|
109
|
+
this.state = {
|
|
110
|
+
isLoaded: false,
|
|
111
|
+
tiles: new Set(),
|
|
112
|
+
viewportChanged: false
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
shouldUpdateState({changeFlags}): boolean {
|
|
117
|
+
const {viewportChanged} = changeFlags;
|
|
118
|
+
this.setState({viewportChanged});
|
|
119
|
+
return changeFlags.somethingChanged;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
renderLayers(): Layer {
|
|
123
|
+
const {
|
|
124
|
+
data,
|
|
125
|
+
getWeight,
|
|
126
|
+
colorDomain,
|
|
127
|
+
colorRange,
|
|
128
|
+
intensity,
|
|
129
|
+
radiusPixels,
|
|
130
|
+
_subLayerProps,
|
|
131
|
+
updateTriggers,
|
|
132
|
+
onMaxDensityChange,
|
|
133
|
+
onViewportLoad,
|
|
134
|
+
onTileLoad,
|
|
135
|
+
onTileUnload,
|
|
136
|
+
...tileLayerProps
|
|
137
|
+
} = this.props;
|
|
138
|
+
|
|
139
|
+
// Inject modified polygon layer as sublayer into TileLayer
|
|
140
|
+
const subLayerProps = {
|
|
141
|
+
..._subLayerProps,
|
|
142
|
+
cell: {
|
|
143
|
+
..._subLayerProps?.cell,
|
|
144
|
+
_subLayerProps: {
|
|
145
|
+
..._subLayerProps?.cell?._subLayerProps,
|
|
146
|
+
fill: {
|
|
147
|
+
..._subLayerProps?.cell?._subLayerProps?.fill,
|
|
148
|
+
type: RTTSolidPolygonLayer
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
let tileZ = 0;
|
|
155
|
+
let maxDensity = 0;
|
|
156
|
+
const tiles = [...this.state.tiles].filter(t => t.isVisible && t.data);
|
|
157
|
+
for (const tile of tiles) {
|
|
158
|
+
const cell = tile.data[0];
|
|
159
|
+
const unitDensity = unitDensityForCell(cell.id);
|
|
160
|
+
maxDensity = Math.max(tile.userData!.maxWeight * unitDensity, maxDensity);
|
|
161
|
+
tileZ = Math.max(tile.zoom, tileZ);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Between zoom levels the max density will change, but it isn't possible to know by what factor. Uniform data distributions lead to a factor of 4, while very localized data gives 1. As a heurstic estimate with a value inbetween (2) to make the transitions less obvious.
|
|
165
|
+
const overzoom = this.context.viewport.zoom - tileZ;
|
|
166
|
+
const estimatedMaxDensity = maxDensity * Math.pow(2, overzoom);
|
|
167
|
+
|
|
168
|
+
maxDensity = estimatedMaxDensity;
|
|
169
|
+
if (typeof onMaxDensityChange === 'function') {
|
|
170
|
+
onMaxDensityChange(maxDensity);
|
|
171
|
+
}
|
|
172
|
+
return new PostProcessQuadbinTileLayer(
|
|
173
|
+
tileLayerProps as Omit<QuadbinTileLayerProps, 'data'>,
|
|
174
|
+
this.getSubLayerProps({
|
|
175
|
+
id: 'heatmap',
|
|
176
|
+
data,
|
|
177
|
+
|
|
178
|
+
// Re-use existing props to pass down values to sublayer
|
|
179
|
+
// TODO replace with custom layer
|
|
180
|
+
getFillColor: 0,
|
|
181
|
+
getElevation: getWeight,
|
|
182
|
+
elevationScale: maxDensity,
|
|
183
|
+
|
|
184
|
+
colorDomain,
|
|
185
|
+
|
|
186
|
+
colorRange,
|
|
187
|
+
radiusPixels,
|
|
188
|
+
intensity,
|
|
189
|
+
_subLayerProps: subLayerProps,
|
|
190
|
+
refinementStrategy: 'no-overlap',
|
|
191
|
+
|
|
192
|
+
// Disable line rendering
|
|
193
|
+
extruded: false,
|
|
194
|
+
stroked: false,
|
|
195
|
+
|
|
196
|
+
updateTriggers: {
|
|
197
|
+
getElevation: updateTriggers.getWeight
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// Tile stats
|
|
201
|
+
onViewportLoad: tiles => {
|
|
202
|
+
this.setState({isLoaded: true});
|
|
203
|
+
if (typeof onViewportLoad === 'function') {
|
|
204
|
+
onViewportLoad(tiles);
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
onTileLoad: (tile: Tile2DHeader) => {
|
|
208
|
+
let maxWeight = -Infinity;
|
|
209
|
+
if (typeof getWeight !== 'function') {
|
|
210
|
+
maxWeight = getWeight;
|
|
211
|
+
} else if (tile.content) {
|
|
212
|
+
for (const d of tile.content) {
|
|
213
|
+
maxWeight = Math.max(getWeight(d, {} as any), maxWeight);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
tile.userData = {maxWeight};
|
|
217
|
+
|
|
218
|
+
this.state.tiles.add(tile);
|
|
219
|
+
|
|
220
|
+
if (typeof onTileLoad === 'function') {
|
|
221
|
+
onTileLoad(tile);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
onTileUnload: (tile: Tile2DHeader) => {
|
|
225
|
+
this.state.tiles.delete(tile);
|
|
226
|
+
if (typeof onTileUnload === 'function') {
|
|
227
|
+
onTileUnload(tile);
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
transitions: {elevationScale: {type: 'spring', stiffness: 0.3, damping: 0.5}}
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export default HeatmapTileLayer;
|
package/src/layers/heatmap.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {ShaderPass} from '@luma.gl/shadertools';
|
|
2
|
-
import {random} from '@luma.gl/shadertools';
|
|
3
2
|
import {Color} from '@deck.gl/core';
|
|
4
3
|
const glsl = (s: TemplateStringsArray) => `${s}`;
|
|
5
4
|
|
|
@@ -21,11 +20,10 @@ uniform heatmapUniforms {
|
|
|
21
20
|
vec3 color4;
|
|
22
21
|
vec3 color5;
|
|
23
22
|
vec3 color6;
|
|
23
|
+
float intensity;
|
|
24
24
|
float opacity;
|
|
25
25
|
} heatmap;
|
|
26
26
|
|
|
27
|
-
// Controls quality of heatmap, larger values increase quality at expense of performance
|
|
28
|
-
const float SUPPORT = 8.0;
|
|
29
27
|
const vec4 STOPS = vec4(0.2, 0.4, 0.6, 0.8);
|
|
30
28
|
|
|
31
29
|
vec3 colorGradient(float value) {
|
|
@@ -44,20 +42,18 @@ vec3 colorGradient(float value) {
|
|
|
44
42
|
} else if (value < STOPS.w) {
|
|
45
43
|
range = STOPS.zw;
|
|
46
44
|
c1 = heatmap.color4; c2 = heatmap.color5;
|
|
47
|
-
} else
|
|
45
|
+
} else {
|
|
48
46
|
range = vec2(STOPS.w, 1.0);
|
|
49
47
|
c1 = heatmap.color5; c2 = heatmap.color6;
|
|
50
|
-
} else {
|
|
51
|
-
// Fade out to white
|
|
52
|
-
range = vec2(1.0, 10.0);
|
|
53
|
-
c1 = heatmap.color6; c2 = vec3(255.0);
|
|
54
48
|
}
|
|
55
49
|
|
|
56
|
-
float f = (value - range.x) / (range.y - range.x);
|
|
50
|
+
float f = (clamp(value, 0.0, 1.0) - range.x) / (range.y - range.x);
|
|
57
51
|
return mix(c1, c2, f) / 255.0;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
54
|
const vec3 SHIFT = vec3(1.0, 256.0, 256.0 * 256.0);
|
|
55
|
+
const float MAX_VAL = SHIFT.z * 255.0;
|
|
56
|
+
const float SCALE = MAX_VAL / 8.0;
|
|
61
57
|
vec4 pack(float value) {
|
|
62
58
|
return vec4(mod(vec3(value, floor(value / SHIFT.yz)), 256.0), 255.0) / 255.0;
|
|
63
59
|
}
|
|
@@ -69,16 +65,15 @@ vec4 heatmap_sampleColor(sampler2D source, vec2 texSize, vec2 texCoord) {
|
|
|
69
65
|
bool firstPass = (heatmap.delta.y < 0.5);
|
|
70
66
|
float accumulator = 0.0;
|
|
71
67
|
|
|
72
|
-
//
|
|
73
|
-
float
|
|
68
|
+
// Controls quality of heatmap, larger values increase quality at expense of performance
|
|
69
|
+
float SUPPORT = clamp(heatmap.radiusPixels / 2.0, 8.0, 32.0);
|
|
74
70
|
|
|
75
71
|
// Gaussian normalization parameters
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
float sigma = SUPPORT / 3.0;
|
|
73
|
+
float a = -0.5 / (sigma * sigma);
|
|
74
|
+
float w0 = 0.3989422804014327 / sigma; // 1D normalization
|
|
80
75
|
for (float t = -SUPPORT; t <= SUPPORT; t++) {
|
|
81
|
-
vec2 percent = (t * heatmap.delta
|
|
76
|
+
vec2 percent = (t * heatmap.delta - 0.5) / SUPPORT;
|
|
82
77
|
vec2 delta = percent * heatmap.radiusPixels / texSize;
|
|
83
78
|
vec4 offsetColor = texture(source, texCoord + delta);
|
|
84
79
|
|
|
@@ -95,8 +90,18 @@ vec4 heatmap_sampleColor(sampler2D source, vec2 texSize, vec2 texCoord) {
|
|
|
95
90
|
return pack(accumulator);
|
|
96
91
|
}
|
|
97
92
|
|
|
93
|
+
// Undo scaling to obtain normalized density
|
|
94
|
+
float density = 10.0 * heatmap.intensity * accumulator / SCALE;
|
|
95
|
+
|
|
96
|
+
// Domain also in normalized density units
|
|
97
|
+
vec2 domain = heatmap.colorDomain;
|
|
98
|
+
|
|
98
99
|
// Apply domain
|
|
99
|
-
float f = (
|
|
100
|
+
float f = (density - domain[0]) / (domain[1] - domain[0]);
|
|
101
|
+
|
|
102
|
+
// sqrt/log scaling??
|
|
103
|
+
// float f = (log(density) - log(domain[0] + 1.0)) / (log(domain[1] + 1.0) - log(domain[0] + 1.0));
|
|
104
|
+
// f = sqrt(f);
|
|
100
105
|
|
|
101
106
|
// Color map
|
|
102
107
|
vec4 color = vec4(0.0);
|
|
@@ -138,6 +143,10 @@ export type HeatmapProps = {
|
|
|
138
143
|
* @default `6-class YlOrRd` - [colorbrewer](http://colorbrewer2.org/#type=sequential&scheme=YlOrRd&n=6)
|
|
139
144
|
*/
|
|
140
145
|
colorRange: Color[];
|
|
146
|
+
/**
|
|
147
|
+
* Value that is multiplied with the total weight at a pixel to obtain the final weight. A value larger than 1 biases the output color towards the higher end of the spectrum, and a value less than 1 biases the output color towards the lower end of the spectrum.
|
|
148
|
+
*/
|
|
149
|
+
intensity?: number;
|
|
141
150
|
opacity: number;
|
|
142
151
|
};
|
|
143
152
|
|
|
@@ -151,6 +160,7 @@ export type HeatmapUniforms = {
|
|
|
151
160
|
color4?: [number, number, number];
|
|
152
161
|
color5?: [number, number, number];
|
|
153
162
|
color6?: [number, number, number];
|
|
163
|
+
intensity: number;
|
|
154
164
|
opacity?: number;
|
|
155
165
|
};
|
|
156
166
|
|
|
@@ -166,6 +176,7 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
|
|
|
166
176
|
color4: {value: [0, 0, 0]},
|
|
167
177
|
color5: {value: [0, 0, 0]},
|
|
168
178
|
color6: {value: [0, 0, 0]},
|
|
179
|
+
intensity: {value: 1, min: 0.1, max: 10},
|
|
169
180
|
opacity: {value: 1, min: 0, max: 1}
|
|
170
181
|
},
|
|
171
182
|
uniformTypes: {
|
|
@@ -178,6 +189,7 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
|
|
|
178
189
|
color4: 'vec3<f32>',
|
|
179
190
|
color5: 'vec3<f32>',
|
|
180
191
|
color6: 'vec3<f32>',
|
|
192
|
+
intensity: 'f32',
|
|
181
193
|
opacity: 'f32'
|
|
182
194
|
},
|
|
183
195
|
getUniforms: opts => {
|
|
@@ -186,6 +198,7 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
|
|
|
186
198
|
colorRange = defaultColorRange,
|
|
187
199
|
radiusPixels = 20,
|
|
188
200
|
colorDomain = [0, 1],
|
|
201
|
+
intensity = 1,
|
|
189
202
|
opacity = 1
|
|
190
203
|
} = opts as HeatmapProps & {delta: [number, number]};
|
|
191
204
|
const [color1, color2, color3, color4, color5, color6] = colorRange;
|
|
@@ -199,10 +212,10 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
|
|
|
199
212
|
color6,
|
|
200
213
|
radiusPixels,
|
|
201
214
|
colorDomain,
|
|
215
|
+
intensity,
|
|
202
216
|
opacity
|
|
203
217
|
};
|
|
204
218
|
},
|
|
205
|
-
dependencies: [random],
|
|
206
219
|
fs,
|
|
207
220
|
passes: [
|
|
208
221
|
{sampler: true, uniforms: {delta: [1, 0]}},
|
|
@@ -14,9 +14,6 @@ import {
|
|
|
14
14
|
_TileLoadProps as TileLoadProps
|
|
15
15
|
} from '@deck.gl/geo-layers';
|
|
16
16
|
import {GeoJsonLayer} from '@deck.gl/layers';
|
|
17
|
-
import {binaryToGeojson} from '@loaders.gl/gis';
|
|
18
|
-
import type {BinaryFeatureCollection} from '@loaders.gl/schema';
|
|
19
|
-
import type {Feature, Geometry} from 'geojson';
|
|
20
17
|
|
|
21
18
|
import type {TilejsonResult} from '../sources/types';
|
|
22
19
|
import {TilejsonPropType, injectAccessToken, mergeBoundaryData} from './utils';
|
|
@@ -148,16 +145,9 @@ export default class VectorTileLayer<
|
|
|
148
145
|
return subLayer;
|
|
149
146
|
}
|
|
150
147
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const {data} = params.sourceLayer!.props;
|
|
156
|
-
info.object = binaryToGeojson(data as BinaryFeatureCollection, {
|
|
157
|
-
globalFeatureId: info.index
|
|
158
|
-
}) as Feature<Geometry, FeaturePropertiesT>;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return info;
|
|
148
|
+
protected override _isWGS84(): boolean {
|
|
149
|
+
// CARTO binary tile coordinates are [lng, lat], not tile-relative like MVT.
|
|
150
|
+
if (this.state.mvt) return super._isWGS84();
|
|
151
|
+
return true;
|
|
162
152
|
}
|
|
163
153
|
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Accessor, CompositeLayer, CompositeLayerProps, DefaultProps, Layer } from '@deck.gl/core';
|
|
2
|
-
import { HeatmapProps } from "./heatmap.js";
|
|
3
|
-
import { QuadbinTileLayerProps } from "./quadbin-tile-layer.js";
|
|
4
|
-
import { TilejsonResult } from "../sources.js";
|
|
5
|
-
/** All properties supported by QuadbinHeatmapTileLayer. */
|
|
6
|
-
export type QuadbinHeatmapTileLayerProps<DataT = unknown> = _QuadbinHeatmapTileLayerProps<DataT> & CompositeLayerProps & {
|
|
7
|
-
data: null | TilejsonResult | Promise<TilejsonResult>;
|
|
8
|
-
};
|
|
9
|
-
/** Properties added by QuadbinHeatmapTileLayer. */
|
|
10
|
-
type _QuadbinHeatmapTileLayerProps<DataT> = QuadbinTileLayerProps<DataT> & HeatmapProps & {
|
|
11
|
-
/**
|
|
12
|
-
* The weight of each object.
|
|
13
|
-
*
|
|
14
|
-
* @default 1
|
|
15
|
-
*/
|
|
16
|
-
getWeight?: Accessor<DataT, number>;
|
|
17
|
-
};
|
|
18
|
-
declare class QuadbinHeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends CompositeLayer<ExtraProps & Required<_QuadbinHeatmapTileLayerProps<DataT>>> {
|
|
19
|
-
static layerName: string;
|
|
20
|
-
static defaultProps: DefaultProps<QuadbinHeatmapTileLayerProps<unknown>>;
|
|
21
|
-
renderLayers(): Layer;
|
|
22
|
-
}
|
|
23
|
-
export default QuadbinHeatmapTileLayer;
|
|
24
|
-
//# sourceMappingURL=quadbin-heatmap-tile-layer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"quadbin-heatmap-tile-layer.d.ts","sourceRoot":"","sources":["../../src/layers/quadbin-heatmap-tile-layer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAE,mBAAmB,EAAE,YAAY,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AAGjG,OAAO,EAAC,YAAY,EAAU,qBAAkB;AAEhD,OAAyB,EAAC,qBAAqB,EAAC,gCAA6B;AAE7E,OAAO,EAAC,cAAc,EAAC,sBAAmB;AAiD1C,2DAA2D;AAC3D,MAAM,MAAM,4BAA4B,CAAC,KAAK,GAAG,OAAO,IAAI,6BAA6B,CAAC,KAAK,CAAC,GAC9F,mBAAmB,GAAG;IACpB,IAAI,EAAE,IAAI,GAAG,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACvD,CAAC;AAEJ,mDAAmD;AACnD,KAAK,6BAA6B,CAAC,KAAK,IAAI,qBAAqB,CAAC,KAAK,CAAC,GACtE,YAAY,GAAG;IACb;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;CACrC,CAAC;AAEJ,cAAM,uBAAuB,CAAC,KAAK,GAAG,GAAG,EAAE,UAAU,SAAS,EAAE,GAAG,EAAE,CAAE,SAAQ,cAAc,CAC3F,UAAU,GAAG,QAAQ,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAC5D;IACC,MAAM,CAAC,SAAS,SAA6B;IAC7C,MAAM,CAAC,YAAY,sDAAgB;IAEnC,YAAY,IAAI,KAAK;CAmDtB;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { getResolution } from 'quadbin';
|
|
2
|
-
import { CompositeLayer } from '@deck.gl/core';
|
|
3
|
-
import { SolidPolygonLayer } from '@deck.gl/layers';
|
|
4
|
-
import { heatmap } from "./heatmap.js";
|
|
5
|
-
import { RTTModifier, PostProcessModifier } from "./post-process-utils.js";
|
|
6
|
-
import QuadbinTileLayer from "./quadbin-tile-layer.js";
|
|
7
|
-
import { TilejsonPropType } from "./utils.js";
|
|
8
|
-
// Modified polygon layer to draw offscreen and output value expected by heatmap
|
|
9
|
-
class RTTSolidPolygonLayer extends RTTModifier(SolidPolygonLayer) {
|
|
10
|
-
static { this.layerName = 'RTTSolidPolygonLayer'; }
|
|
11
|
-
getShaders(type) {
|
|
12
|
-
const shaders = super.getShaders(type);
|
|
13
|
-
shaders.inject = {
|
|
14
|
-
'vs:#decl': 'uniform float cellResolution;',
|
|
15
|
-
'vs:DECKGL_FILTER_COLOR': `
|
|
16
|
-
const vec3 SHIFT = vec3(1.0, 256.0, 256.0 * 256.0);
|
|
17
|
-
float value = 255.0 * dot(SHIFT, color.rgb);
|
|
18
|
-
|
|
19
|
-
// Keep "power" delivered to screen constant when tiles update
|
|
20
|
-
float relativeZoom = log2(project_uScale) - cellResolution + 3.5; // range 0-1
|
|
21
|
-
float relativeArea = pow(2.0, -2.0 * relativeZoom); // range 0.25-1
|
|
22
|
-
value *= relativeArea;
|
|
23
|
-
|
|
24
|
-
// Pack float into 3 channels to pass to heatmap shader
|
|
25
|
-
color = vec4(mod(vec3(value, floor(value / SHIFT.yz)), 256.0), 255.0) / 255.0;
|
|
26
|
-
`
|
|
27
|
-
};
|
|
28
|
-
return shaders;
|
|
29
|
-
}
|
|
30
|
-
draw(opts) {
|
|
31
|
-
const cell0 = this.props.data[0];
|
|
32
|
-
const cellResolution = Number(getResolution(cell0.id));
|
|
33
|
-
for (const model of this.state.models) {
|
|
34
|
-
model.setUniforms({ cellResolution });
|
|
35
|
-
}
|
|
36
|
-
super.draw(opts);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
// Modify QuadbinTileLayer to apply heatmap post process effect
|
|
40
|
-
const PostProcessQuadbinTileLayer = PostProcessModifier(QuadbinTileLayer, heatmap);
|
|
41
|
-
function encodeWeight(w) {
|
|
42
|
-
return [w % 256, Math.floor(w / 256), Math.floor(w / (256 * 256))];
|
|
43
|
-
}
|
|
44
|
-
const defaultProps = {
|
|
45
|
-
data: TilejsonPropType,
|
|
46
|
-
getWeight: { type: 'accessor', value: 1 }
|
|
47
|
-
};
|
|
48
|
-
class QuadbinHeatmapTileLayer extends CompositeLayer {
|
|
49
|
-
static { this.layerName = 'QuadbinHeatmapTileLayer'; }
|
|
50
|
-
static { this.defaultProps = defaultProps; }
|
|
51
|
-
renderLayers() {
|
|
52
|
-
const { data, getWeight, colorDomain, colorRange, radiusPixels, _subLayerProps, updateTriggers, ...tileLayerProps } = this.props;
|
|
53
|
-
// Inject modified polygon layer as sublayer into TileLayer
|
|
54
|
-
const subLayerProps = {
|
|
55
|
-
..._subLayerProps,
|
|
56
|
-
cell: {
|
|
57
|
-
..._subLayerProps?.cell,
|
|
58
|
-
_subLayerProps: {
|
|
59
|
-
..._subLayerProps?.cell?._subLayerProps,
|
|
60
|
-
fill: {
|
|
61
|
-
..._subLayerProps?.cell?._subLayerProps?.fill,
|
|
62
|
-
type: RTTSolidPolygonLayer
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
const getFillColor = typeof getWeight === 'function'
|
|
68
|
-
? (d, info) => encodeWeight(getWeight(d, info))
|
|
69
|
-
: encodeWeight(getWeight);
|
|
70
|
-
return new PostProcessQuadbinTileLayer(tileLayerProps, this.getSubLayerProps({
|
|
71
|
-
id: 'heatmap',
|
|
72
|
-
data,
|
|
73
|
-
getFillColor,
|
|
74
|
-
colorDomain,
|
|
75
|
-
colorRange,
|
|
76
|
-
radiusPixels,
|
|
77
|
-
_subLayerProps: subLayerProps,
|
|
78
|
-
updateTriggers: {
|
|
79
|
-
getPosition: updateTriggers.getWeight
|
|
80
|
-
}
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
export default QuadbinHeatmapTileLayer;
|