openlayers关于clusters介绍

效果展示

初始化地图

Javascript 复制代码
<template>
  <div id="map" class="map"></div>
</template>

<script>
import Map from "ol/Map.js";
import View from "ol/View.js";
import { centerPoint } from "@/utils/showPage.js";
import { gaodeMapLayer } from "@/utils/MapLayer.js";
import { clusters, clusterCircleStyle, clusterCircles } from "@/utils/cluster";
import { createEmpty, extend, getHeight, getWidth } from "ol/extent.js";
export default {
  name: "cluster",
  data() {
    return {
      map: null
    };
  },
  mounted() {
    const map = new Map({
      layers: [gaodeMapLayer, clusters, clusterCircles],
      target: "map",
      view: new View({
        center: centerPoint,
        zoom: 11,
        minZoom: 2,
        maxZoom: 30,
        projection: "EPSG:4326",
        rotation: 0,
      }),
    });
  },
};
</script>

<style scoped>
.map {
  width: 100%;
  height: 900px;
}
</style>

图层详解

  • 公共方法和样式

    Javascript 复制代码
     function gasPointType() {
       let customPoint = config.CUSTOM_POINT.val,
         GAS_POINT_TYPE = config.GAS_POINT_TYPE.children;
       GAS_POINT_TYPE.forEach((item) => {
         item.type = item.val.typeId.value;
       });
       return [
         ...GAS_POINT_TYPE,
         { type: customPoint.typeId.value, val: customPoint },
       ];
     }
     function getICon(properties) {
       let typeId = properties.typeId || "1",
         allPoint = gasPointType();
       return allPoint.find((i) => i.type == typeId).val;
     }
     function clusterMemberStyle(clusterMember) {
       let properties = clusterMember.getProperties();
       let item = getICon(properties);
       return new Style({
         geometry: clusterMember.getGeometry(),
         image: new Icon({
           rotation: 0,
           src: item.iconUrl.value,
           anchorXUnits: "fraction",
           imgSize: [item.width.value, item.height.value],
         }),
       });
     }
     function generatePointsCircle(count, clusterCenter, resolution) {
       const circumference =
         circleDistanceMultiplier * circleFootSeparation * (2 + count);
       let legLength = circumference / (Math.PI * 2); 
       const angleStep = (Math.PI * 2) / count;
       const res = [];
       let angle;
       legLength = Math.max(legLength, 35) * resolution;
       for (let i = 0; i < count; ++i) {
    
         angle = circleStartAngle + i * angleStep;
         res.push([
           clusterCenter[0] + legLength * Math.cos(angle),
           clusterCenter[1] + legLength * Math.sin(angle),
         ]);
       }
    
       return res;
     }
  • clusters图层

    Javascript 复制代码
      const vectorSource = new VectorSource({
        features: new GeoJSON().readFeatures({
          type: devList.type,
          features: _devList,
        }),
      });
    
      const clusterSource = new Cluster({
        distance: 35,
        source: vectorSource,
      });
      }
      function clusterStyle(feature) {
        const size = feature.get("features").length;
        if (size > 1) {
          return [
            new Style({
              image: outerCircle,
            }),
            new Style({
              image: innerCircle,
              text: new Text({
                text: size.toString(),
                fill: textFill,
                stroke: textStroke,
              }),
            }),
          ];
        }
        const originalFeature = feature.get("features")[0];
        return clusterMemberStyle(originalFeature);
      }
    
      const clusters = new VectorLayer({
        source: clusterSource,
        style: clusterStyle,
      });
  • clusterCircles图层

    Javascript 复制代码
       const clusterCircles = new VectorLayer({
         source: clusterSource,
         style: clusterCircleStyle,
       });
    
       function clusterCircleStyle(
         cluster,
         resolution,
         clickFeature,
         clickResolution
       ) {
         if (cluster !== clickFeature || resolution !== clickResolution) {
           return null;
         }
         const clusterMembers = cluster.get("features");
         const centerCoordinates = cluster.getGeometry().getCoordinates();
         return generatePointsCircle(
           clusterMembers.length,
           cluster.getGeometry().getCoordinates(),
           resolution
         ).reduce((styles, coordinates, i) => {
           const point = new Point(coordinates);
           const line = new LineString([centerCoordinates, coordinates]);
           styles.unshift(
             new Style({
               geometry: line,
               stroke: convexHullStroke,
             })
           );
           styles.push(
             clusterMemberStyle(
               new Feature({
                 ...clusterMembers[i].getProperties(),
                 geometry: point,
               })
             )
           );
           return styles;
         }, []);
       }

地图pointermove和click

Javascript 复制代码
  map.on("pointermove", (event) => {
      clusters.getFeatures(event.pixel).then((features) => {
        map.getTargetElement().style.cursor =
          features[0] && features[0].get("features").length > 1
            ? "pointer"
            : "";
      });
    });

    map.on("click", (event) => {
      clusters.getFeatures(event.pixel).then((features) => {
        if (features.length > 0) {
          const clusterMembers = features[0].get("features");
          if (clusterMembers.length > 1) {
            // Calculate the extent of the cluster members.
            const extent = createEmpty();
            clusterMembers.forEach((feature) =>
              extend(extent, feature.getGeometry().getExtent())
            );
            const view = map.getView();
            const resolution = map.getView().getResolution();
            if (
              view.getZoom() === view.getMaxZoom() ||
              (getWidth(extent) < resolution && getHeight(extent) < resolution)
            ) {
              // Show an expanded view of the cluster members.
              let clickFeature = features[0];
              let clickResolution = resolution;
              clusterCircles.setStyle((cluster, resolution) => {
                clusterCircleStyle(
                  cluster,
                  resolution,
                  clickFeature,
                  clickResolution
                );
              });
            } else {
              // Zoom to the extent of the cluster members.
              view.fit(extent, { duration: 500, padding: [50, 50, 50, 50] });
            }
          }
        }
      });
    });
相关推荐
lbh2 小时前
当我开始像写代码一样和AI对话,一切都变了
前端·openai·ai编程
We་ct3 小时前
LeetCode 918. 环形子数组的最大和:两种解法详解
前端·数据结构·算法·leetcode·typescript·动态规划·取反
wefly20173 小时前
m3u8live.cn 在线M3U8播放器,免安装高效验流排错
前端·后端·python·音视频·前端开发工具
C澒4 小时前
微前端容器标准化 —— 公共能力篇:通用打印
前端·架构
德育处主任Pro4 小时前
前端元素转图片,dom-to-image-more入门教程
前端·javascript·vue.js
木斯佳4 小时前
前端八股文面经大全:小红书前端一二面OC(下)·(2026-03-17)·面经深度解析
前端·vue3·proxy·八股·响应式
陈天伟教授4 小时前
人工智能应用- 预测新冠病毒传染性:04. 中国:强力措施遏制疫情
前端·人工智能·安全·xss·csrf
zayzy5 小时前
前端八股总结
开发语言·前端·javascript
今天减肥吗5 小时前
前端面试题
开发语言·前端·javascript
Rabbit_QL5 小时前
【前端UI行话】前端 UI 术语速查表
前端·ui·状态模式