Vue + Openlayers入门教程(六):实现信息弹窗功能

信息弹窗功能实现

一、技术栈

Vue 3 + Typescript +Openlayers 7 + Element plus
在这里插入图片描述

二、组件代码

  • OLPopup.vue
<template>
  <div id="popup" class="olPopup" v-show="selectState">
    <a href="#" id="popupCloser" class="olPopupCloser" @click="removePopup"></a>
    <div id="popupContent" v-show="featureAmount > -1">
      <table>
        <tr>
          <th>当前坐标:</th>
          <td>{{ lonAndLat }}</td>
        </tr>
      </table>
      <div v-show="featureAmount > 0">
        <table>
          <tr>
            <th>矢量类型:</th>
            <td>{{ type[layerIndex] }}</td>
          </tr>
          <tr>
            <th>图层名称:</th>
            <td>{{ name[layerIndex] }}</td>
          </tr>
        </table>
        <el-button v-show="featureAmount > 1" @click="changePopup"
          >切换</el-button
        >
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { Feature, Map } from "ol";
import { toLonLat } from "ol/proj";
import Overlay from "ol/Overlay.js";
import bus from "@/utils/bus.ts"; //定义声明文件再引入
import { Coordinate, toStringHDMS } from "ol/coordinate";
import { FeatureLike } from "ol/Feature";
import { Pixel } from "ol/pixel";

let mapCopy: Map;

let popupContainer: HTMLElement;
let popup: Overlay;
let lonAndLat = ref(""); //经纬度
const name = ref<string[]>([]); //图层名称
const type = ref<string[]>([]); //矢量类型
const selectState = ref<boolean>(false); //弹窗状态
let featureAmount = ref<number>(0); //选中矢量要素个数
let layerIndex = ref<number>(0); //图层显示索引

// 添加弹窗
const addPopup = (clickCrd: Coordinate, clickPixel: Pixel) => {
  //获取弹出框DOM
  popupContainer = document.getElementById("popup") as HTMLElement;
  //创建弹出层并绑定DOM
  popup = new Overlay({
    element: popupContainer as HTMLElement,
    autoPan: {
      animation: {
        duration: 250,
      },
    },
  });

  lonAndLat.value = toStringHDMS(toLonLat(clickCrd, "EPSG:4548")); //转换为经纬度坐标
  // 判断点击位置的要素
  let featuresVector: Feature[] = [];
  mapCopy.forEachFeatureAtPixel(clickPixel, (f: FeatureLike) => {
    featuresVector.push(f as Feature);
  });

  featureAmount.value = featuresVector.length; //获取到的元素的个数

  for (let i = 0; i < featureAmount.value; i++) {
    //循环获取元素名称与类型
    name.value.push(featuresVector[i].get("district"));
    type.value.push(featuresVector[i].getGeometry()?.getType() as string);
  }
  mapCopy.addOverlay(popup);
  //设置位置
  popup.setPosition(clickCrd);
};
//关闭弹窗
const removePopup = () => {
  popup.setPosition(undefined);
  selectState.value = false; //关闭弹窗状态
};
//切换要素信息弹窗
const changePopup = () => {
  if (layerIndex.value < featureAmount.value - 1) {
    layerIndex.value++;
  } else {
    alert("已经没有更多图层了");
  }
};

//监听map数据
bus.on("mapToChecked", (res: Map) => {
  // 传参由回调函数中的形参接受
  mapCopy = res;
  //监听click事件
  mapCopy.on("click", (event) => {
    //更新弹窗状态为开启
    selectState.value = true;
    //判断地图实例上是否存在绘制交互,如果存在,关闭弹窗
    mapCopy
      .getInteractions()
      .getArray()
      .some((item) => {
        if (item.getProperties().name === "Draw") {
          selectState.value = false;
        }
      });

    const clickCoordinate: Coordinate = event.coordinate; //获取点击坐标
    const clickPixel: Pixel = event.pixel; //获取点击位置
    featureAmount.value = 0; //每次点击都置空个数
    name.value = []; //置空名称数组
    type.value = []; //置空类型数组
    layerIndex.value = 0; //归零显示图层索引
    addPopup(clickCoordinate, clickPixel); //挂载添加弹窗函数
  });
});
</script>

<style>
.olPopup {
  position: absolute;
  background-color: white;
  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: 350px;
}

.olPopup:after,
.olPopup:before {
  top: 100%;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}

.olPopup:after {
  border-top-color: white;
  border-width: 10px;
  left: 48px;
  margin-left: -10px;
}

.olPopup:before {
  border-top-color: #cccccc;
  border-width: 11px;
  left: 48px;
  margin-left: -11px;
}

.olPopupCloser {
  text-decoration: none;
  position: absolute;
  top: 2px;
  right: 8px;
}

.olPopupCloser:after {
  content: "✖";
}
</style>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在 Vue 中使用 OpenLayers 实现图层控制控件,可以按照以下步骤进行操作: 1. 安装 OpenLayersVue: ``` npm install ol vue ``` 2. 在 Vue 中引入 OpenLayers: ```javascript import ol from 'ol' import 'ol/ol.css' ``` 3. 创建地图容器: ```html <template> <div ref="map" class="map"></div> </template> ``` 4. 在 Vue 的 mounted 钩子函数中创建地图: ```javascript mounted() { // 创建地图容器 const map = new ol.Map({ target: this.$refs.map, layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], view: new ol.View({ center: ol.proj.fromLonLat([116.3975, 39.9085]), zoom: 12 }) }); this.map = map; } ``` 5. 创建图层控制控件: ```html <template> <div ref="map" class="map"> <div class="ol-control ol-custom-control"> <div class="ol-custom-control-header">图层控制</div> <div class="ol-custom-control-body"> <div v-for="(layer, index) in layers" :key="index"> <input type="checkbox" :id="layer.name" v-model="layer.visible"> <label :for="layer.name">{{ layer.name }}</label> </div> </div> </div> </div> </template> ``` 6. 在 Vue 的 data 中定义图层数据和控件的状态: ```javascript data() { return { map: null, layers: [ { name: 'OSM', visible: true, layer: new ol.layer.Tile({ source: new ol.source.OSM() }) }, { name: 'Bing Maps', visible: false, layer: new ol.layer.Tile({ source: new ol.source.BingMaps({ key: 'your-bingmaps-api-key', imagerySet: 'Road' }) }) } ] } } ``` 7. 在 Vue 的 watch 中监听图层状态的变化并更新地图: ```javascript watch: { layers: { deep: true, handler(layers) { const map = this.map; map.getLayers().clear(); layers.forEach(layer => { if (layer.visible) { map.addLayer(layer.layer); } }); } } } ``` 通过以上步骤就可以在 Vue实现图层控制控件了。需要注意的是,在实际应用中,可以根据需要自定义控件的样式和布局。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值