openlayers 点击多边形弹框,高亮多边形,自定义属性传递,鼠标悬浮多边形上动态修改鼠标样式

本篇介绍一下使用openlayers点击多边形弹框,高亮多边形,自定义属性传递,鼠标悬浮多边形上动态修改鼠标样式

1 需求

  • 加载天地图,polygon
  • 传递自定义属性
  • 标悬浮在polygon上,根据自定义属性,动态修改鼠标样式为pointer
  • 点击polygon,根据自定义属性,高亮,弹框

2 分析

主要是 openlayers 中 地图事件,overlay等功能的使用

  • 为vectorSource填充features,有两种方法:

    1. features: [new Feature()]
    2. features: new GeoJSON().readFeatures(geoJSON)
  • 为vectorLayer填充style,有两种写法:

    1. style:new Style()
    2. style:{‘stroke-color’: ‘rgba(255, 128, 100, 1)’}
  • 获取鼠标点击活悬浮时的features,有两种写法:

    1. map.value.forEachFeatureAtPixel()
    2. map.value.getFeaturesAtPixel()

3 实现


没有录上鼠标样式改变,复制代码查看

<template>
  <div id="map" class="map"></div>
  <div id="popup" class="ol-popup" ref="container">
    <a href="#" id="popup-closer" class="ol-popup-closer" ref="closer"></a>
    <div id="popup-content" ref="content"></div>
  </div>
</template>

<script setup lang="ts">
import { Feature, Map, Overlay, View } from 'ol';
import { GeoJSON } from 'ol/format';
import { Polygon } from 'ol/geom';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { get, toLonLat } from 'ol/proj';
import { Vector, XYZ } from 'ol/source';
import { Fill, Stroke, Style } from 'ol/style';
import { toStringHDMS } from 'ol/coordinate.js';

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

const layerTypeMap = {
  vector: ['vec', 'cva'], // [矢量底图, 矢量注记]
  image: ['img', 'cia'], // [影像底图, 影像注记]
  terrain: ['ter', 'cta'] // [地形晕渲, 地形注记]
};

const map = ref();
const container = ref();
const content = ref();
const closer = ref();
const overlay = shallowRef();
const feature = ref();
const geoJSON = {
  type: 'FeatureCollection',
  crs: {
    type: 'name',
    properties: {
      name: 'EPSG:4326'
    }
  },
  features: [
    {
      type: 'Feature',
      geometry: {
        type: 'Polygon',
        coordinates: [
          [
            [112, 31],
            [113, 32.2],
            [114, 30.5],
            [112, 31]
          ]
        ]
      },
      properties: {
        //自定义属性
        pointer: true
      }
    }
  ]
};

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

const initMap = (layerType = 'image') => {
  const key = '替换为天地图key';

  overlay.value = new Overlay({
    element: container.value,
    autoPan: {
      animation: {
        duration: 250
      }
    }
  });

  // c: 经纬度投影 w: 墨卡托投影
  const matrixSet = 'c';
  map.value = new Map({
    target: 'map',
    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: new Vector({
          features: [
            new Feature({
              geometry: new Polygon([
                [
                  [116, 31],
                  [118, 32.2],
                  [119, 30.5],
                  [116, 31]
                ]
              ]),
              pointer: true //自定义属性,可用于修改鼠标样式、单击轮廓弹框,改变feature样式
            })
          ]
        }),
        style: new Style({
          fill: new Fill({
            color: 'rgba(228, 147, 87, 0.4)'
          }),
          stroke: new Stroke({
            color: 'rgba(228, 147, 87, 1)',
            width: 3
          })
        })
      }),
      new VectorLayer({
        source: new Vector({
          features: [
            new Feature({
              geometry: new Polygon([
                [
                  [114, 31],
                  [115, 32.2],
                  [116, 30.5],
                  [114, 31]
                ]
              ])
            })
          ]
        }),
        style: {
          //layer样式可以这样写
          'stroke-color': 'rgba(255, 255, 100, 1)',
          'stroke-width': 1.5,
          'fill-color': 'rgba(255, 255, 100, 0.5)',
          'circle-radius': 6,
          'circle-fill-color': 'rgba(255, 255, 100, 1)'
        }
      }),
      new VectorLayer({
        source: new Vector({
          features: new GeoJSON().readFeatures(geoJSON) //读取geojson格式数据
        }),
        style: {
          //layer样式可以这样写
          'stroke-color': 'rgba(255, 128, 100, 1)',
          'stroke-width': 1.5,
          'fill-color': 'rgba(255, 128, 100, 0.5)',
          'circle-radius': 6,
          'circle-fill-color': 'rgba(255, 128, 100, 1)'
        }
      })
    ],
    overlays: [overlay.value],
    view: new View({
      center: [116.406393, 39.909006],
      projection: projection,
      zoom: 5,
      maxZoom: 17,
      minZoom: 1
    })
  });
  map.value.on('pointermove', (e: any) => {
    // 根据自定义属性改变鼠标样式

    // 方法一
		// map.value.getTargetElement().style.cursor = 'auto';
    // let pixel = map.value.getEventPixel(e.originalEvent);
    // map.value.forEachFeatureAtPixel(pixel, (feature: any) => {
    //   const property = feature.getProperties();
    //   if (property.pointer) {
    //     map.value.getTargetElement().style.cursor = 'pointer'; //设置鼠标样式
    //   } else {
    //     map.value.getTargetElement().style.cursor = 'auto';
    //   }
    // });

    // 方法二
		map.value.getTargetElement().style.cursor = 'auto';
    const features = map.value.getFeaturesAtPixel(e.pixel);
    features.forEach(feature => {
      const property = feature.getProperties();
      if (property.pointer) {
        map.value.getTargetElement().style.cursor = 'pointer'; //设置鼠标样式
      } else {
        map.value.getTargetElement().style.cursor = 'auto';
      }
    });
  });
  map.value.on('click', e => {
    // 根据自定义属性改变轮廓样式,也可以进行弹框
    if (feature.value) {
      feature.value.setStyle();
			closer.value.onclick();
    }
    const features = map.value.getFeaturesAtPixel(e.pixel);
    const f = features.find(f => f.getProperties().pointer);
    if (f) {
      feature.value = f;
      f.setStyle(
        new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 100, 0.5)'
          }),
          stroke: new Stroke({
            color: 'rgba(255, 255, 100, 1)',
            width: 3
          })
        })
      );
      const coordinate = e.coordinate;
      const hdms = toStringHDMS(toLonLat(coordinate));
      content.value.innerHTML = '<p>当前经纬度:</p><code>' + hdms + '</code>';
      overlay.value.setPosition(coordinate);
    }
  });

  closer.value.onclick = function () {
    overlay.value.setPosition(undefined);
    closer.value.blur();
    if (feature.value) {
      feature.value.setStyle();
    }
    return false;
  };
};
</script>
<style scoped lang="scss">
.map {
  width: 100%;
  height: 100%;
}
.ol-popup {
  position: absolute;
  background-color: rgba(255, 255, 255, 0.7);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  padding: 15px;
  border-radius: 10px;
  border: 1px solid #cccccc;
  bottom: 12px;
  left: -50px;
  min-width: 280px;
}
.ol-popup:after,
.ol-popup:before {
  top: 100%;
  border: solid transparent;
  content: ' ';
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}
.ol-popup:after {
  border-top-color: rgba(255, 255, 255, 0.7);
  border-width: 10px;
  left: 48px;
  margin-left: -10px;
}
.ol-popup:before {
  border-top-color: #cccccc;
  border-width: 11px;
  left: 48px;
  margin-left: -11px;
}
.ol-popup-closer {
  text-decoration: none;
  position: absolute;
  top: 2px;
  right: 8px;
}
.ol-popup-closer:after {
  content: '✖';
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值