openlayers 要素聚合(cluster)、icon聚合

64 阅读2分钟

本篇介绍一下使用openlayers 要素聚合(cluster),icon聚合

1 需求

  • 要素聚合(cluster),icon聚合

2 分析

使用cluster这个source

4 实现

26.gif

<template>
  <div id="map" class="map"></div>
  <div class="toolbar">
    <div>距离</div>
    <el-slider
      v-model="distance"
      :min="1"
      :max="300"
      :step="1"
      @change="handleChangeDistance"
    ></el-slider>
    <div>最小距离</div>
    <el-slider
      v-model="minDistance"
      :min="1"
      :max="300"
      :step="1"
      @change="handleChangeMinDistance"
    ></el-slider>
  </div>
</template>

<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { Point } from 'ol/geom';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { get } from 'ol/proj';
import { XYZ, Cluster, Vector as VectorSource } from 'ol/source';
import { Fill, Stroke, Circle, Style, Text } from 'ol/style';

const projection = get('EPSG:4326');

const layerTypeMap = {
  vector: ['vec', 'cva'], // [矢量底图, 矢量注记]
  image: ['img', 'cia'], // [影像底图, 影像注记]
  terrain: ['ter', 'cta'] // [地形晕渲, 地形注记]
};
const styleCache = {};
const map = shallowRef();
const clusterSource = shallowRef();
const distance = ref(1);
const minDistance = ref(1);

const count = 1000;
const features = new Array(count);
for (let i = 0; i < count; ++i) {
  const coordinates = [Math.random() + 120, Math.random() + 30];
  features[i] = new Feature(new Point(coordinates));
}

onMounted(() => {
  initMap('image');
});

const initMap = (layerType = 'image') => {
  const key = '替换为天地图key';
  // c: 经纬度投影 w: 墨卡托投影
  const matrixSet = 'c';
  clusterSource.value = new Cluster({
    distance: distance.value,
    minDistance: minDistance.value,
    source: new VectorSource({
      features: features
    })
  });
  map.value = new Map({
    target: 'map',
    view: new View({
      center: [116.406393, 39.909006],
      projection: projection,
      zoom: 5,
      maxZoom: 17,
      minZoom: 1
    }),
    layers: [
      // 底图
      new TileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][0]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection
        })
      }),
      // 注记
      new TileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][1]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection
        })
      }),
      new VectorLayer({
        source: clusterSource.value,
        style: styleFunc
      })
    ]
  });
};

const styleFunc = feature => {
	console.log('feature',feature)
	// 获取聚合数量(当source为cluster时,feature上会有一个features树形,数组,包括聚合的所有feature)
  const size = feature.get('features').length;
	// 缓存样式
  let style = styleCache[size];
  if (!style) {
    style = new Style({
      image: new Circle({
        radius: 10,
        stroke: new Stroke({
          color: '#fff'
        }),
        fill: new Fill({
          color: 'rgba(228, 147, 87,0.8)'
        })
      }),
      text: new Text({
        text: size.toString(),
        fill: new Fill({
          color: '#fff'
        })
      })
    });
    styleCache[size] = style;
  }
  return style;
};

const handleChangeDistance = () => {
  clusterSource.value.setDistance(distance.value);
};

const handleChangeMinDistance = () => {
  clusterSource.value.setMinDistance(minDistance.value);
};
</script>
<style scoped lang="scss">
.map {
  width: 100%;
  height: 100%;
}

.toolbar {
  position: absolute;
  top: 20px;
  left: 100px;
  width: 500px;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
  .el-slider {
    margin-right: 50px;
  }
  div {
    width: 100px;
    height: 30px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
</style>