diff --git a/example/screens/cluster.tsx b/example/screens/cluster.tsx index f6e71a69..99ac7b1a 100644 --- a/example/screens/cluster.tsx +++ b/example/screens/cluster.tsx @@ -19,10 +19,7 @@ export default class Clustering extends Component { this.status = nativeEvent; this.cluster?.update(nativeEvent); }} - onLongPress={() => { - this.setState({ markers: generateMarkers() }); - setTimeout(() => this.cluster?.update(this.status!), 0); - }} + onLongPress={() => this.setState({ markers: generateMarkers() })} > { @@ -49,8 +46,8 @@ export default class Clustering extends Component { } } -function generateMarkers() { - return Array(1000) +function generateMarkers(count = 1000) { + return Array(count) .fill(0) .map((_, i) => ({ position: { latitude: 39.5 + Math.random(), longitude: 116 + Math.random() }, diff --git a/lib/src/cluster/index.tsx b/lib/src/cluster/index.tsx index 6a22fe9e..eabaf6e2 100644 --- a/lib/src/cluster/index.tsx +++ b/lib/src/cluster/index.tsx @@ -6,23 +6,65 @@ import { LatLng } from "../types"; import ClusterView from "./cluster-view"; export interface ClusterParams { + /** + * 唯一标识 + */ id: number; + + /** + * 包含的 Marker 数量 + */ count: number; + + /** + * 坐标 + */ position: LatLng; } interface MarkerItem { + /** + * 坐标 + */ position: LatLng; + + /** + * 携带的数据,可以是任意类型 + */ properties?: any; } interface Props { radius?: number; + + /** + * 聚合点样式 + */ clusterStyle?: ViewStyle; + + /** + * 聚合点文本样式 + */ clusterTextStyle?: ViewStyle; + + /** + * 坐标点列表 + */ points: MarkerItem[]; + + /** + * 渲染 Marker + */ renderMarker: (item: MarkerItem) => React.ReactNode; + + /** + * 渲染聚合点 + */ renderCluster?: (params: ClusterParams) => React.ComponentType; + + /** + * 聚合点点击事件 + */ onPress?: (params: ClusterParams) => void; } @@ -33,60 +75,66 @@ interface State { export default class Cluster extends React.PureComponent { static defaultProps = { radius: 200 }; state: State = { clusters: [] }; + status?: CameraEvent; cluster?: Supercluster; componentDidMount() { - this.init(this.props); + this.init(); } componentDidUpdate(props: Props) { if (props.points != this.props.points) { - this.init(props); + this.init(); } } - init(props: Props) { + async init() { + const { radius, points } = this.props; // 如果主线程占用太多计算资源,会导致 ios onLoad 事件无法触发,非常蛋疼 - // 暂时想到的解决办法是丢到下一个事件循环,但这可能会导致 update 失败 - setTimeout(() => { - const { radius } = props; - const options = { radius, minZoom: 3, maxZoom: 21 }; - this.cluster = new Supercluster(options).load( - props.points.map((marker) => ({ - type: "Feature", - geometry: { - type: "Point", - coordinates: [marker.position.longitude, marker.position.latitude], - }, - properties: marker.properties, - })) - ); - }, 0); + // 暂时想到的解决办法是等一个事件循环 + await new Promise((resolve) => setTimeout(resolve, 0)); + const options = { radius, minZoom: 3, maxZoom: 21 }; + this.cluster = new Supercluster(options).load( + points.map((marker) => ({ + type: "Feature", + geometry: { + type: "Point", + coordinates: [marker.position.longitude, marker.position.latitude], + }, + properties: marker.properties, + })) + ); + if (this.status) { + this.update(this.status); + } } /** * 需要在 MapView.onCameraIdle({ nativeEvent }) 回调里调用,参数为 nativeEvent */ - update({ cameraPosition, latLngBounds }: CameraEvent) { - setTimeout(() => { - const { southwest, northeast } = latLngBounds; - const clusters = this.cluster!.getClusters( - [southwest.longitude, southwest.latitude, northeast.longitude, northeast.latitude], - Math.round(cameraPosition.zoom!) - ); - this.setState({ clusters }); - }, 0); + async update(status: CameraEvent) { + this.status = status; + await new Promise((resolve) => setTimeout(resolve, 0)); + const { cameraPosition, latLngBounds } = status; + const { southwest, northeast } = latLngBounds; + const clusters = this.cluster!.getClusters( + [southwest.longitude, southwest.latitude, northeast.longitude, northeast.latitude], + Math.round(cameraPosition.zoom!) + ); + this.setState({ clusters }); } - renderCluster = (cluster: ClusterParams) => ( - - ); + renderCluster = (cluster: ClusterParams) => { + return ( + + ); + }; render() { const { renderCluster, renderMarker } = this.props;