UNPKG

@wayz/react-gl

Version:

React Component for DeckGL, Base on AMap, Mapbox GL

106 lines (105 loc) 4.31 kB
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;