openlayers实现地图锚点和点击弹窗

背景介绍

这次使用openlayers实现的地图锚点和点击弹窗的功能,参考了网上别人的一些经验,简化了代码,后续实现点击弹窗插入数据的能力。使用的技术栈是vue3 + vite。

地图初始化以及属性介绍

由于OSM国内访问不到,这次使用的天地图的数据,token自己去天地图上注册获取就可以了

const map = new Map({
  layers: [
    new TileLayer({
      source: new XYZ({
        url: 'http://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=你的token'
      })
    }),
  ],
  target: 'map',
  view: new View({
    projection: "EPSG:4326",
    center: [128, 31.5],
    zoom: 5,
  })
})

layers

图层,是整个地图功能的基础,value为一个数组

TileLayer

平铺图层,展示的是大而全的地图数据,后续的锚点和弹窗视图都是落在平铺图层上的

target

容器,值为一个字符串,目标容器的id

view

视图,包含中心点和放大层级等属性

锚点功能

画点

想要在图层上画点,需要使用一个新的图层 VectorImageLayer,包含source属性默认为 VectorSourceVectorSource里面有features就是我们想要添加的锚点的列表

const feature = new Feature({
  geometry: new Point([119,36]) // 注册在什么坐标点添加
})

const vectorLayer = new VectorImageLayer({
  source: new VectorSource({
    features: [
      feature
    ]
  }),
})

feature.setStyle(new Style({
  image: new Icon({
    src: aicon
  })
}));

这样我就在经度119,维度36的地方画了一个点,大概在宇宙中心曹县一带

点击

点击功能代码分为两步

  • 监听地图点击事件

  • 捕获点击的经纬度坐标,捕获附近的锚点

    map.on('singleclick', (e) => {
      const coordinate = e.coordinate
      console.log(feature)
      const feature = map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
        return feature;
      })
      // 弹出popup
    })
    

弹窗

定义

使用vue3的 teleport 标签,把目标弹窗插入到 body 里面

<template>
  <teleport to="body">
    <div id="popup" class="ol-popup">
      <a href="#" id="popup-closer" class="ol-popup-closer"></a>
      <div id="popup-content">我是一个锚点</div>
    </div>
  </teleport>
</template>

注册

创建overLayer弹窗图层

// 创建弹窗图层
const popup = new Overlay({
  element: document.getElementById('popup')
})
map.addOverlay(popup)

const closer = document.getElementById('popup-closer')

closer.onclick = function () {
  popup.setPosition(undefined);
  closer.blur();
  return false;
};

使用

放到刚才的点击事件里面,就大功告成

map.on('singleclick', (e) => {
  const coordinate = e.coordinate
  console.log(feature)
  const feature = map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
    return feature;
  })
  if (feature) {
    // 弹出popup
    popup.setPosition(coordinate)
  }
})

源码

<script setup>
import { ref, reactive, onMounted } from 'vue'
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import Feature from 'ol/Feature'
import { Point } from 'ol/geom'
import VectorSource from 'ol/source/Vector'
import Overlay from 'ol/Overlay'
import Interaction from 'ol/interaction/Interaction'
import VectorImageLayer from 'ol/layer/VectorImage'
import Style from 'ol/style/Style'
import Icon from 'ol/style/Icon'
import aicon from '../assets/aicon.svg'
import MapDialog from './MapDialog.vue'
import 'ol/ol.css'


function generateLayer () {
  const vectorSource = new VectorSource({
    features: []
  })

  const vectorLayer = new VectorImageLayer({
    source: vectorSource,
  })
  return vectorLayer
}

function dataHandler (msg) {
  const data = msg.slice(15, -3)
  return data.split(',')
}

onMounted(async () => {
  const coors = ['119.36 35.07', '119.03 34', '119.36 33', '119.36 36']

  const layer = generateLayer() // 创建锚点图层
  const map = new Map({
    layers: [
      new TileLayer({
        source: new XYZ({
          url: 'http://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk='
        })
      }),
      layer
    ],
    target: 'map',
    view: new View({
      projection: "EPSG:4326",
      center: [128, 31.5],
      zoom: 5,
    })
  })

  const anchors = coors.map(item => {
    const coor = item.split(' ')
    const anchor = new Feature({
      geometry: new Point(coor)
    })
    anchor.setStyle(new Style({
      image: new Icon({
        src: aicon
      })
    }));
    layer.getSource().addFeature(anchor)
    return anchor
  })

  map.getView().on('change:resolution', function () {
    anchors.forEach(anchor => {
      const style = anchor.getStyle();
      // 重新设置图标的缩放率,基于层级20来做缩放
      style.getImage().setScale(this.getZoom() / 5);
      anchor.setStyle(style);
    })

  })

  // 创建弹窗图层
  const popup = new Overlay({
    element: document.getElementById('popup')
  })
  map.addOverlay(popup)

  const closer = document.getElementById('popup-closer')

  closer.onclick = function () {
    popup.setPosition(undefined);
    closer.blur();
    return false;
  };

  map.on('singleclick', (e) => {
    const coordinate = e.coordinate
    const feature = map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
      return feature;
    })
    if (feature) {
      // 弹出popup
      popup.setPosition(coordinate)
    }
  })

})
</script>

<template>
  <div id="map"></div>
  <map-dialog></map-dialog>
</template>

<style lang="less">
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
}
</style>
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值