@wayz/react-gl
Version:
React Component for DeckGL, Base on AMap, Mapbox GL
106 lines (105 loc) • 4.31 kB
JavaScript
import { GeoJsonLayer } from '@deck.gl/layers';
import { CompositeLayer } from '@deck.gl/core';
import { polygon } from '@turf/helpers';
import centerOfMass from '@turf/center-of-mass';
import area from '@turf/area';
import TextmapLayer from '../textmap-layer/textmap-layer';
const defaultProps = {
// 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] },
// Whether to render background for the text blocks
background: false,
// Label background color
getLabelBackground: { type: 'accessor', value: [255, 255, 255, 255] },
// Label not facing the camera
billboard: true,
// Label size units
labelSizeUnits: 'pixels',
// Label font
fontFamily: 'Monaco, monospace',
};
// Extract anchor positions from features. We will be placing labels at these positions.
function getLabelAnchors(feature) {
const { type, coordinates } = feature.geometry;
switch (type) {
case 'Point':
return [coordinates];
case 'MultiPoint':
return coordinates;
case 'Polygon':
return [centerOfMass(feature).geometry.coordinates];
case 'MultiPolygon':
let polygons = coordinates.map((rings) => polygon(rings));
const areas = polygons.map(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) => centerOfMass(f).geometry.coordinates);
default:
return [];
}
}
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 });
}
}
// set characterSet
setCharacterSet(f, characterSet) {
let { getLabel } = this.props;
getLabel = getLabel ? getLabel : (f) => f.text;
getLabel(f)
.split('')
.forEach((s) => characterSet.add(s));
}
renderLayers() {
const { data } = this.props;
const { fontFamily, billboard, labelSizeUnits, background, characterSet, getLabel, getLabelColor, getLabelSize, getLabelBackground, } = this.props;
// Accessor props for underlying layers
const { updateTriggers } = this.props;
return [
new GeoJsonLayer(this.props, this.getSubLayerProps({ id: 'labeled-geojson' }), {
data,
}),
new TextmapLayer({
data: this.state.labelData,
characterSet: characterSet ? characterSet : this.state.characterSet,
sizeUnits: labelSizeUnits,
background,
fontFamily,
billboard,
}, this.getSubLayerProps({
id: 'textamap',
updateTriggers: {
getPosition: updateTriggers.getPosition,
getText: updateTriggers.getLabel,
getSize: updateTriggers.getLabelSize,
getColor: updateTriggers.getLabelColor,
getBackgroundColor: updateTriggers.getLabelBackground,
},
}), {
getPosition: (d) => d.position,
getText: this.getSubLayerAccessor(getLabel),
getSize: this.getSubLayerAccessor(getLabelSize),
getColor: this.getSubLayerAccessor(getLabelColor),
getBackgroundColor: this.getSubLayerAccessor(getLabelBackground),
}),
];
}
}
LabeledGeoJsonLayer.layerName = 'LabeledGeoJsonLayer';
LabeledGeoJsonLayer.defaultProps = defaultProps;
export default LabeledGeoJsonLayer;