Clusters 聚类

使用 MapLibre 内置聚类高效渲染大量点数据。点在低缩放级别自动分组为聚类,随缩放展开。

MapClusterLayer 组件使用 MapLibre GL 的原生聚类功能。 自动将附近的点分组为聚类,点击聚类时放大展开。必须在 Map 内部使用。

基本用法

点击聚类放大,点击单个点查看详情弹窗:

ClusterExample.tsx
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
class="tk-string">"use client";

import { useState } from class="tk-string">"react";
import { Map, MapClusterLayer, MapPopup, MapControls } from class="tk-string">"@/components/ui/map";

interface EarthquakeProperties {
  mag: number;
  place: string;
  tsunami: number;
}

export function ClusterExample() {
  const [selectedPoint, setSelectedPoint] = useState<{
    coordinates: [number, number];
    properties: EarthquakeProperties;
  } | null>(null);

  return (
    <div className=class="tk-string">"h-[420px] w-full">
      <Map center={[-103.59, 40.66]} zoom={3.4} fadeDuration={0}>
        <MapClusterLayer<EarthquakeProperties>
          data=class="tk-string">"https:class="tk-commentclass="tk-string">">//maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson"
          clusterRadius={50}
          clusterMaxZoom={14}
          clusterColors={[class="tk-string">"#1d8cf8", class="tk-string">"#6d5dfc", class="tk-string">"#e23670"]}
          pointColor=class="tk-string">"#1d8cf8"
          onPointClick={(feature, coordinates) => {
            setSelectedPoint({
              coordinates,
              properties: feature.properties,
            });
          }}
        />

        {selectedPoint && (
          <MapPopup
            key={class="tk-string">`${selectedPoint.coordinates[0]}-${selectedPoint.coordinates[1]}`}
            longitude={selectedPoint.coordinates[0]}
            latitude={selectedPoint.coordinates[1]}
            onClose={() => setSelectedPoint(null)}
            closeOnClick={false}
            focusAfterOpen={false}
            closeButton
            className=class="tk-string">"w-34"
          >
            <div className=class="tk-string">"text-[13px]">
              <p className=class="tk-string">"text-muted-foreground">
                震级:{class="tk-string">" "}
                <span className=class="tk-string">"text-foreground font-medium">
                  {selectedPoint.properties.mag}
                </span>
              </p>
              <p className=class="tk-string">"text-muted-foreground">
                海啸:{class="tk-string">" "}
                <span className=class="tk-string">"text-foreground font-medium">
                  {selectedPoint.properties?.tsunami === 1 ? class="tk-string">"是" : class="tk-string">"否"}
                </span>
              </p>
            </div>
          </MapPopup>
        )}

        <MapControls />
      </Map>
    </div>
  );
}

自定义聚类颜色

clusterColors 定义三个级别的聚类颜色,clusterThresholds 定义点数阈值:

12345678910
<MapClusterLayer
  data={earthquakeData}
  clusterColors={[
    class="tk-string">"#22c55e",  class=class="tk-string">"tk-comment">// 小聚类(< 100 个点)
    class="tk-string">"#eab308",  class=class="tk-string">"tk-comment">// 中聚类(100-750 个点)
    class="tk-string">"#ef4444",  class=class="tk-string">"tk-comment">// 大聚类(> 750 个点)
  ]}
  clusterThresholds={[100, 750]}
  pointColor=class="tk-string">"#3b82f6"
/>

自定义聚类点击

默认点击聚类会放大展开。你也可以自定义点击行为:

1234567
<MapClusterLayer
  data={data}
  onClusterClick={(clusterId, coordinates, pointCount) => {
    console.log(class="tk-string">`聚类 ${clusterId} 包含 ${pointCount} 个点`);
    class=class="tk-string">"tk-comment">// 自定义逻辑,如显示聚类详情弹窗
  }}
/>

类型安全

使用泛型类型参数实现类型安全的属性访问:

1234567891011121314
interface StoreProperties {
  name: string;
  category: string;
  isOpen: boolean;
}

<MapClusterLayer<StoreProperties>
  data={storesGeoJSON}
  onPointClick={(feature, coordinates) => {
    class=class="tk-string">"tk-comment">// feature.properties 类型为 StoreProperties
    console.log(feature.properties.name);
    console.log(feature.properties.isOpen);
  }}
/>

属性

属性类型默认值描述
datastring | GeoJSON.FeatureCollectionGeoJSON 数据或获取数据的 URL
clusterMaxZoomnumber14聚类点的最大缩放级别
clusterRadiusnumber50聚类点半径(像素)
clusterColors[string, string, string]绿/黄/红聚类圆颜色:[小, 中, 大]
clusterThresholds[number, number][100, 750]颜色/大小阈值:[中, 大]
pointColorstring"#3b82f6"未聚类的单点颜色
onPointClick(feature, coordinates) => void单个点被点击时的回调
onClusterClick(clusterId, coordinates, pointCount) => void放大展开聚类被点击时的回调。未提供时自动放大

下一步

高级用法

useMap Hook