Skip to content

聚类图层

展开代码
vue
<template>
  <div ref="mapContainer" id="map"></div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import Map from "ol/Map";
import View from "ol/View";
import { Cluster, Vector as VectorSource } from "ol/source";
import { Vector as VectorLayer, Tile as TileLayer } from "ol/layer";
import { Point } from "ol/geom";
import Feature from "ol/Feature";
import XYZ from "ol/source/XYZ";
import { Style, Circle, Text, Fill, Icon } from "ol/style";
import "ol/ol.css";

const mapContainer = ref(null);

// 1. 创建原始点数据源(模拟1000个随机点)
const rawSource = new VectorSource();
for (let i = 0; i < 1000; i++) {
  const point = new Point([
    116.3 + Math.random() * 1.0, // 经度范围:116.3~117.3
    39.8 + Math.random() * 0.8, // 纬度范围:39.8~40.6
  ]);
  rawSource.addFeature(new Feature(point));
}

// 2. 创建聚类数据源(核心)
const clusterSource = new Cluster({
  source: rawSource,
  distance: 40, // 像素距离,值越大聚类越少
});

// 3. 动态样式函数(根据聚类点数设置不同样式)
const clusterStyle = (feature) => {
  const size = feature.get("features").length;
  let color, radius, image;

  if (size === 1) {
    // color = "rgba(0, 150, 255, 0.8)";
    // radius = 6;
    // 实际情况这里更多的是logo
    return new Style({
      image: new Icon({
        anchor: [0.5, 1],
        src: "/src/assets/local.png", // 使用本地图片
        scale: 0.5, // 缩放图标大小
      }),
    });
  } else if (size < 20) {
    color = "rgba(50, 200, 100, 0.8)";
    radius = 10;
    image = new Circle({
      radius,
      fill: new Fill({ color }),
    });
  } else {
    color = "rgba(255, 70, 70, 0.8)";
    radius = 15 + Math.min(size / 10, 10);
    image = new Circle({
      radius,
      fill: new Fill({ color }),
    });
  }

  return new Style({
    image,
    text: new Text({
      text: size.toString(),
      fill: new Fill({ color: "#fff" }),
      font: "bold 12px sans-serif",
    }),
  });
};

onMounted(() => {
  new Map({
    target: mapContainer.value,
    layers: [
      new TileLayer({
        // 设置高德地图为数据源底图
        source: new XYZ({
          // 设置路网图层
          url: "https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}",
        }),
      }),
      new VectorLayer({
        source: clusterSource,
        style: clusterStyle, // 应用动态样式
      }),
    ],
    view: new View({
      center: [116.5, 40.0],
      zoom: 8,
      projection: "EPSG:4326",
    }),
  });
});
</script>
<style scoped>
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}
</style>