This article documents the system that deck.gl offers to provide extra type annotations for layer properties.
A number of deck.gl features are enabled by rich descriptions of the types of the properties in a layer:
A layer class may supply a static member defaultProps
that defines its default property types and values:
import {Layer} from 'deck.gl';
class MyLayer extends Layer {
// implementation
}
MyLayer.defaultProps = {
texture: {type: 'object', value: null, async: true},
strokeOpacity: {type: 'number', value: 1, min: 0, max: 1},
strokeColor: {type: 'color', value: [255, 0, 0]},
getRadius: {type: 'accessor', value: d => d.radius}
};
When the user construct this layer, the props are resolved as such:
const layer = new MyLayer({id: 'my-layer', strokeOpacity: 0.5})
/**
layer.props:
{
texture: null,
strokeOpacity: 0.5,
strokeColor: [255, 0, 0],
getRadius: d => d.radius,
// other default base Layer props
}
*/
The property types system enables layers to opt-in to specifying types, and also allows a certain amount of type auto-deduction to happen based on existing default values for layers that do not opt in.
Each prop in defaultProps
may be an object in the following shape:
type
(string, required)value
(any, required) - the default value if this prop is not suppliedasync
(boolean, optional) - if true
, the prop can either be a Promise that resolves to its actual value, or an url string (loaded using the base Layer's fetch prop).transform
(function, optional) - transforms an asynchronously loaded value and returns a new form. Receives the following arguments:value
- the new value of this proppropType
- this prop type definitionlayer
- the owner of this proprelease
(function, optional) - release a transformed value when it's no longer in use. Receives the following arguments:value
- the old value of this proppropType
- this prop type definitionlayer
- the owner of this propvalidate
(function, optional) - returns true
if the value is valid. Validation of layer props is only invoked in debug mode. This function is automatically populated if the prop has a built-in type. Receives the following arguments:value
- the value to be validatedpropType
- this prop type definitionequal
(function, optional) - returns true
if the two prop values should be considered equal. Comparison of layer props is invoked during layer update and the result is passed to changeFlags.propsChanged
. This function is automatically populated if the prop has a built-in type. Receives the following arguments:value
- the new value of this propoldValue
- the previous value of this proppropType
- this prop type definitiondeprecatedFor
(string|array, optional) - mark this prop as deprecated. The value is the new prop name(s) that this prop has been deprecated for. If the old prop is supplied instead of the new one, its value will be transferred to the new prop. The user will get a warning about the deprecation.boolean
Any value.
validate
: always passequal
: compared by truthinessMyLayerClass.defaultProps = {
// explicit
fill: {type: 'boolean', value: false}
// inferred
fill: false
}
number
A numeric value.
min
(number, optional) - the minimum allowed valuemax
(number, optional) - the maximum allowed valuevalidate
: value is finite and within bounds (if specified)equal
: strict equalMyLayerClass.defaultProps = {
// explicit, with bounds
radiusScale: {type: 'number', value: 1, min: 0}
// inferred, no bounds
radiusScale: 1
}
color
A RGBA color.
validate
: value is an array of 3 or 4 elementsequal
: deep equalMyLayerClass.defaultProps = {
// must be explicit
fillColor: {type: 'color', value: [255, 204, 0]}
}
image
One of: URL string, Texture2D object, Image
, HTMLCanvasElement
, HTMLVideoElement
, ImageBitmap
or ImageData
.
transform
: converts to a Texture2D
objectarray
An array of objects.
optional
(boolean, optional) - accept null
or undefined
. Default false
.compare
(boolean, optional) - compare deeply during prop comparison. Default false
.validate
: value is an array of 3 or 4 elementsequal
: shallow equal if compare: false
, otherwise deep equalMyLayerClass.defaultProps = {
// explicit
coordinateOrigin: {type: 'array', value: [0, 0, 0], compare: true}
// inferred
coordinateOrigin: [0, 0, 0]
}
accessor
An accessor used to update shader attributes.
validate
: value is either a function or the same type as the default valueequal
: true
if function, otherwise deep equalMyLayerClass.defaultProps = {
// must be explicit
getColor: {type: 'accessor', value: [255, 255, 255]}
}
function
A function.
optional
(boolean, optional) - accept null
or undefined
. Default false
.compare
(boolean, optional) - compare strictly during prop comparison. Default true
.validate
: value is a functionequal
: true
if compare: false
, otherwise strict equalMyLayerClass.defaultProps = {
// explicit
sizeScale: {type: 'function', value: x => Math.sqrt(x), compare: false}
// inferred
sizeScale: x => Math.sqrt(x)
}
The performance of a deck.gl application can be greatly improved by limiting the frequency of layer updates. Consider the following app:
import React from 'react';
function App() {
const layers = [
new GeoJsonLayer({
id: 'geojson',
data: DATA_URL,
extruded: true,
wireframe: true,
getElevation: f => ELEVATION_SCALE(f.properties.population),
getFillColor: f => COLOR_SCALE(f.properties.income),
getLineColor: [255, 255, 255]
})
];
return (
<DeckGL
layers={layers}
initialViewState={{
latitude: 49.254,
longitude: -123.13,
zoom: 11
}}
controller={true}
/>
);
}
Each time the user interacts with the viewport, the app state is updated, and render()
is called. Because getElevation
, getFillColor
and getLineColor
are functions and arrays defined inline, they have changed from the previous render.
Usually, any prop change results in updating a layer, that is, recomputing its internal states. Updating a layer could be expensive. In GeoJsonLayer's case, it creates ScatterplotLayer, PolygonLayer and PathLayer, and those layers also need to be updated recursively.
In reality, we do not want to update GeoJsonLayer, because no layer props changed from the user's perspective. In GeoJsonLayer, these props are declared as such:
const defaultProps = {
...
getElevation: {type: 'accessor', value: 1000},
getFillColor: {type: 'accessor', value: [0, 0, 0, 255]},
getLineColor: {type: 'accessor', value: [0, 0, 0, 255]}
}
The default comparator of the access
prop type ignores shallow changes in functions. As a result, deck.gl decides that no props have changed between the two renders, and the GeoJsonLayer does not need to be updated.