Published
Edited
Feb 4, 2021
4 forks
20 stars
Insert cell
Insert cell
container = html `<div style="height:450px;"></div>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
defaultProps = {
const {GeoJsonLayer} = deck;

return {
// Inherit all of GeoJsonLayer's props
...GeoJsonLayer.defaultProps,
// Label for each feature
getLabel: {type: 'accessor', value: x => x.text},
// Label size for each feature
getLabelSize: {type: 'accessor', value: 32},
// Label color for each feature
getLabelColor: {type: 'accessor', value: [0, 0, 0, 255]},
// Label always facing the camera
billboard: true,
// Label size units
labelSizeUnits: 'pixels',
// Label background color
labelBackground: {type: 'color', value: null, optional: true},
// Label font
fontFamily: 'Monaco, monospace'
}
}
Insert cell
layer0 = {
const {CompositeLayer} = deck;
// Our custom layer class
class LabeledGeoJsonLayer extends CompositeLayer {
updateState() {
// TODO
}
renderLayers() {
// TODO
}
}
LabeledGeoJsonLayer.layerName = 'LabeledGeoJsonLayer';
LabeledGeoJsonLayer.defaultProps = defaultProps;

return new LabeledGeoJsonLayer({
id: `countries-${Date.now()}`,
data,
filled: false,
getLineColor: [180, 180, 180],
getLabel: f => f.properties.name,
getLabelSize: 32,
lineWidthMinPixels: 1
});
}
Insert cell
Insert cell
layer0.props.labelSizeUnits
Insert cell
Insert cell
layer1 = {
const {CompositeLayer, GeoJsonLayer} = deck;
// Our custom layer class
class LabeledGeoJsonLayer extends CompositeLayer {
updateState() {
// TODO
}
renderLayers() {
return [
new GeoJsonLayer(this.props, this.getSubLayerProps({id: 'geojson'}), {
data: this.props.data
})
];
}
}
LabeledGeoJsonLayer.layerName = 'LabeledGeoJsonLayer';
LabeledGeoJsonLayer.defaultProps = defaultProps;

return new LabeledGeoJsonLayer({
id: `countries-${Date.now()}`,
data,
filled: false,
getLineColor: [180, 180, 180],
getLabel: f => f.properties.name,
getLabelSize: 32,
lineWidthMinPixels: 1
});
}
Insert cell
Insert cell
Insert cell
getLabelAnchors = {
// Extract anchor positions from features. We will be placing labels at these positions.
return function(feature) {
const {type, coordinates} = feature.geometry;
switch (type) {
case 'Point':
return [coordinates];
case 'MultiPoint':
return coordinates;
case 'Polygon':
return [turf.centerOfMass(feature).geometry.coordinates];
case 'MultiPolygon':
let polygons = coordinates.map(rings => turf.polygon(rings));
const areas = polygons.map(turf.area);
const maxArea = Math.max.apply(null, areas);
// Filter out the areas that are too small
return polygons.filter((f, index) => areas[index] > maxArea * 0.5)
.map(f => turf.centerOfMass(f).geometry.coordinates);
default:
return [];
}
}
}
Insert cell
layer2 = {
const {CompositeLayer, GeoJsonLayer, TextLayer} = deck;

class LabeledGeoJsonLayer extends CompositeLayer {
updateState({changeFlags}) {
const {data} = this.props;
if (changeFlags.dataChanged && data) {
const labelData = (data.features || data)
.flatMap((feature, index) => {
const labelAnchors = getLabelAnchors(feature);
return labelAnchors.map(p => this.getSubLayerRow({position: p}, feature, index));
});

this.setState({labelData});
}
}
renderLayers() {
const {
getLabel,
getLabelSize,
getLabelColor,
labelSizeUnits,
labelBackground,
billboard,
fontFamily
} = this.props;
return [
new GeoJsonLayer(this.props, this.getSubLayerProps({id: 'geojson'}), {
data: this.props.data
}),
new TextLayer(this.getSubLayerProps({id: 'text'}), {
data: this.state.labelData,
billboard,
sizeUnits: labelSizeUnits,
backgroundColor: labelBackground,
getPosition: d => d.position,
getText: this.getSubLayerAccessor(getLabel),
getSize: this.getSubLayerAccessor(getLabelSize),
getColor: this.getSubLayerAccessor(getLabelColor)
})
];
}
}
LabeledGeoJsonLayer.layerName = 'LabeledGeoJsonLayer';
LabeledGeoJsonLayer.defaultProps = defaultProps;

const layer = new LabeledGeoJsonLayer({
id: `countries-${Date.now()}`,
data,
filled: false,
billboard: false,
getLineColor: [180, 180, 180],
getLabel: f => f.properties.name,
getLabelSize: f => Math.pow(2, Math.log10(turf.area(f))) * 20,
getLabelColor: [0, 64, 128],
labelSizeUnits: 'meters',
lineWidthMinPixels: 1
});
deckgl.setProps({layers: [layer]});
return layer;
}
Insert cell
Insert cell
layer2.state.labelData;
Insert cell
Insert cell
layer2.getSubLayers();
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more