vue3+openlayers 点击点自定义弹窗,不同类型不同样式,点击面跳转,点的聚类

<template>
  <div class="selectLocation">
    <div
      class="project_map"
      id="project_map"
      ref="container"
      style="width: 100%; height: 100%; z-index: 1"
    ></div>
    <div class="layerControl">
      <el-radio-group v-model="radio">
        <el-radio
          size="large"
          v-for="(item, index) in MapList.groundList"
          :label="index"
          @change="fly"
        >
          {{ item.name }}{{ index }}
        </el-radio>
      </el-radio-group>
    </div>
    <div
      id="popup"
      class="ol-popup"
      style="background-color: bisque"
      v-if="popshow"
    >
      <div class="pophead" style="width: 100%; height: 20px">
        <div
          id="popup-title"
          style="
            font: bold 15px sans-serif;
            align: left;
            position: absolute;
            top: 5px;
            left: 8px;
            color: #000000;
            height: 100px;
            border-radius: 10px;
            display: flex;
            justify-content: space-between;
          "
        >
          <div>信息</div>
          <div id="popup-closer">关闭</div>
        </div>

        <a id="popup-closer" class="ol-popup-closer" style="color: #8e908c"></a>
      </div>

      <div
        id="popup-content"
        style="padding: 10px; width: 500px; height: 100px"
      ></div>
    </div>
  </div>
</template>

script

<script setup>
import { onMounted, ref } 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 VectorSource from "ol/source/Vector";
import VectorLayer from "ol/layer/Vector";
import Point from "ol/geom/Point";
import Overlay from "ol/Overlay.js";
import { Circle, Geometry, LineString, Polygon } from "ol/geom";
import {
  Icon,
  Style,
  Stroke,
  Circle as CircleStyle,
  Fill,
  Text,
} from "ol/style";
import { useRvo } from "@/hook/useRvo";
import { useStore } from "vuex";
import API from "@/network/api";
import { Cluster, OSM } from "ol/source.js";
import { altKeyOnly, click, pointerMove } from "ol/events/condition";
import { boundingExtent } from "ol/extent";

let choseLocation = ref("");
let choseCoordinates = ref("");
const radio = ref("");
//地图容器
let map;
//矢量地图
let baseMapLayer;
//中文标记
let annotateMapLayer;
//加载资源类
let vectorSource;
//加载的资源图层
let polygonsource;
let polygonterLayer;
let vectorLayer;
let chosePositionSource;
let chosePositionLayer;
const store = useStore();
//弹窗
let popshow = ref("false");
let container = document.getElementById("popup");
let content = document.getElementById("popup-content");
const fly = (e) => {
  let features = [];
  for (let item in polygonsource.featuresRtree_.items_) {
    features.push(polygonsource.featuresRtree_.items_[item]);
  }
  let a = features[e];
  Views.setCenter([(a.minX + a.maxX) / 2, (a.minY + a.maxY) / 2]);
  Views.setZoom(18);
};
let overlay1 = new Overlay({
  //设置弹出框的容器
  element: container,
  //是否自动平移,即假如标记在屏幕边缘,弹出时自动平移地图使弹出框完全可见
  autoPan: true,
  autoPanAnimation: {
    duration: 250,
    //当Popup超出地图边界时,为了Popup全部可见,地图移动的速度.
  },
});
const emit = defineEmits(["choseLocation"]);
// 提交位置信息
const confirmLocation = () => {
  emit(
    "choseLocation",
    choseLocation.value,
    projectArea,
    choseCoordinates.value
  );
};
let clusters = ref("");
let MapList = ref("");
const Views = new View({
  projection: "EPSG:4326", //使用这个坐标系
  center: [114.280485, 30.280073],
  zoom: 5,
  maxZoom: 23,
  minZoom: 1,
  // //1.设置缩放级别为整数
  // constrainResolution: false,
  // //2.关闭无级缩放地图
  // smoothResolutionConstraint: false,
});
onMounted(async () => {
  //获取访问者IP
  overlay1.setPosition(undefined);

  let IP = localStorage.getItem("Ip");
  map = new Map({
    target: "project_map",
    view: Views,
  });
  //     // 天地图  标注
  let url = "http://t{0-5}.tianditu.com/DataServer?x={x}&y={y}&l={z}";
  url = `${url}&T=vec_c&tk={{自己的token}}`
  const source = new XYZ({
    url: url,
    projection: "EPSG:4326",
  });
  baseMapLayer = new TileLayer({
    source: source,
  });
  url = "http://t{0-5}.tianditu.com/DataServer?x={x}&y={y}&l={z}";
  url = `${url}&T=cva_c&tk={{自己的token}}`;
  const sourceCVA = new XYZ({
    url: url,
    projection: "EPSG:4326",
  });

  annotateMapLayer = new TileLayer({
    source: sourceCVA,
  });
  //添加底图
  map.addLayer(baseMapLayer);
  let idRvo = useRvo().idRvo;
  map.addLayer(annotateMapLayer);
  // 请求数据
  const getmaplist = async () => {
    MapList.value = res.data;
    createPoint(MapList.value);
    createPolygon(MapList.value);
  };
  getmaplist();
  // 加 聚合点
  const createPoint = (list) => {
    const features = new Array(list.holeList.length);
    //遍历点,EPSG4326
    for (let i = 0; i < list.holeList.length; ++i) {
      let lan = list.holeList[i].geom
        .slice(6, list.holeList[i].geom.length - 1)
        .split(/\s+/)[0];
      let lon = list.holeList[i].geom
        .slice(6, list.holeList[i].geom.length - 1)
        .split(/\s+/)[1];
      let lanNum = Number(lan);
      let lonNum = Number(lon);
      const coordinates = [lanNum, lonNum];
      features[i] = new Feature({
        geometry: new Point(coordinates),
        zkCode: list.holeList[i].zkCode,
        warning: list.holeList[i].ewDrillholeInfos ? false : true,
      });

      features[i].setProperties(list.holeList[i].ewDrillholeInfos);
    }
    // 添加feature到source//添加点
    const pointsource = new VectorSource({
      features: features,
    });
    // 添加feature到source//添加到cluster
    const clusterSource = new Cluster({
      distance: 20,
      minDistance: 5,
      source: pointsource,
    });
    ///添加到适量层
    const pointerLayer = new VectorLayer({
      source: pointsource,
    });
    ///添加到clusters层
    clusters = new VectorLayer({
      source: clusterSource,
      style: stylefunction,
    });

    //添加点到map
    // map.addLayer(pointerLayer);
    //添加点到clusters
    map.addLayer(clusters);
    // 设置图层高度
    pointerLayer.setZIndex(100);
  };
  // 加面
  const createPolygon = (list) => {
    const features = new Array(list.groundList.length);

    for (let i = 0; i < list.groundList.length; ++i) {
      let onePolygon = [];
      let polygoninfo = list.groundList[i]?.geo
        .slice(9, list.groundList[i].geo.length - 2)
        .split(",");
      for (let index = 0; index < polygoninfo.length; index++) {
        let lon = Number(polygoninfo[index].split(/\s+/)[0]);
        let lan = Number(polygoninfo[index].split(/\s+/)[1]);
        let point = [lon, lan];
        onePolygon.push(point);
      }
      let finalArr = [];
      finalArr.push(onePolygon);

      features[i] = new Feature({
        geometry: new Polygon(finalArr),
      });
    }
    polygonsource = new VectorSource({
      features: features,
    });
    polygonterLayer = new VectorLayer({
      source: polygonsource,
      // style: polugonstyles,
    });
    map.addLayer(polygonterLayer);
    polygonterLayer.setZIndex(200);
  };
  //设置点样式
  const stylefunction = (feature) => {
    const styleCache = {};
    const size = feature.get("features").length;
    let style = styleCache[size];
    if (!style) {
      if (size == 1) {
        if (feature.values_.features[0].values_.warning) {
          style = new Style({
            image: new Icon({
              src: "src/assets/image/gisIco/icon_hover.png",
              scale: map.getView().getZoom() / 14,
            }),
            text: new Text({
              //对齐方式
              textAlign: "center",
              //文本基线
              textBaseline: "middle",
              //字体样式
              font: "normal 10px 微软雅黑",
              //文本内容
              text: feature.values_.features[0].values_.zkCode,
              //填充样式
              fill: new Fill({
                color: "#aa3300",
              }),
              offsetY: (20 * map.getView().getZoom()) / 7,
              //笔触
              stroke: new Stroke({
                color: "#ffcc33",
                width: 2,
              }),
              scale: map.getView().getZoom() / 7,
            }),
          });
        } else {
          style = new Style({
            image: new Icon({
              src: "src/assets/image/gisIco/icon.png",
              scale: map.getView().getZoom() / 14,
            }),
            text: new Text({
              //对齐方式
              textAlign: "center",
              //文本基线
              textBaseline: "middle",
              //字体样式
              font: "normal 10px 微软雅黑",
              //文本内容
              text: feature.values_.features[0].values_.zkCode,
              //填充样式
              fill: new Fill({
                color: "#aa3300",
              }),
              offsetY: (20 * map.getView().getZoom()) / 7,
              //笔触
              stroke: new Stroke({
                color: "#ffcc33",
                width: 2,
              }),
              scale: map.getView().getZoom() / 7,
            }),
          });
        }
      } else {
        style = new Style({
          image: new CircleStyle({
            radius: 10,
            stroke: new Stroke({
              color: "#fff",
            }),
            fill: new Fill({
              color: "#3399CC",
            }),
          }),
          text: new Text({
            text: size.toString(),
            fill: new Fill({
              color: "#fff",
            }),
          }),
        });
        styleCache[size] = style;
      }
    }
    return style;
  };

  map.on("click", (e) => {
    //cluster要到外部申明
    clusters.getFeatures(e.pixel).then((clickedFeatures) => {
      if (clickedFeatures.length) {
        const features = clickedFeatures[0].get("features");
        if (features.length > 1) {
          const extent = boundingExtent(
            features.map((r) => r.getGeometry().getCoordinates())
          );
          map
            .getView()
            .fit(extent, { duration: 1000, padding: [50, 50, 50, 50] });
        } else {
          let attr = features[0].values_[0];
          let keyID = features[0].values_.zkCode;
          let coodinate = e.coordinate;
          let container = document.getElementById("popup");
          let content = document.getElementById("popup-content");
          let popupCloser = document.getElementById("popup-closer");
          let overlay1 = new Overlay({
            //设置弹出框的容器
            element: container,
            //是否自动平移,即假如标记在屏幕边缘,弹出时自动平移地图使弹出框完全可见
            autoPan: true,
            autoPanAnimation: {
              duration: 250,
              //当Popup超出地图边界时,为了Popup全部可见,地图移动的速度.
            },
          });
          if (features[0].values_[0]) {
            content.innerHTML =
              "<ul>" +
              "<li>设备id: " +
              keyID +
              "</li>" +
              "<li>设备描述:" +
              attr.info +
              "</li>" +
              "<li>设备类型: " +
              attr.type +
              "</li>" +
              "</ul>";
          } else {
            content.innerHTML =
              "<ul>" + "<li>" + "警告" + "</li>" + "</ul>";
          }

          overlay1.setPosition(coodinate);
          map.addOverlay(overlay1);
          //关闭隐藏
          popupCloser.addEventListener("click", function () {
            overlay1.setPosition(undefined);
          });
        }
      }
    });
  });
});
</script>
<style scoped lang="scss">
.selectLocation {
  width: 100%;
  height: 100%;
  position: relative;
  // float: right;
}
.layerControl {
  overflow: auto;
  width: 200px;
  height: 300px;
  background-color: rgb(255, 249, 249);
  z-index: 100;
  position: absolute;
  top: 10px;
  left: 50px;
}
.popup {
  // width: 200px;
  // height: 100px;
}
#popup-closer {
  border-radius: 5px;
  text-align: center;
  width: 40px;
  margin: 5px;
  left: 380px;
  height: 20px;
  background-color: rgb(230, 114, 20);
}
.ol-popup {
  position: absolute;
  background-color: #eeeeee;
  -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
  filter: drop-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;
}
</style>

效果图

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Vue 3 中结合 Ant Design Vue 和 TypeScript 实现点击文字出现弹窗的功能,你可以按照以下步骤进行操作: 1. 确保你已经按照官方文档的指引正确安装和配置了 Vue 3、Ant Design Vue 和 TypeScript。 2. 创建一个 Vue 组件,例如 `MyComponent.vue`,并在其中引入必要的组件和样式: ```vue <template> <div> <p @click="showModal">点击这里弹出弹窗</p> <a-modal v-model:visible="visible" title="弹窗标题"> <p>弹窗内容</p> </a-modal> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; import { Modal } from 'ant-design-vue'; export default defineComponent({ components: { 'a-modal': Modal, }, data() { return { visible: false, }; }, methods: { showModal() { this.visible = true; }, }, }); </script> <style scoped> /* 样式可以根据实际需求进行修改和定制 */ p { cursor: pointer; } </style> ``` 在这个示例中,我们创建了一个段落元素,并通过 `@click` 监听点击事件,当点击文字时调用 `showModal` 方法来显示弹窗。Modal 组件的使用方式与之前提到的示例相似。 3. 在需要使用该组件的地方引入并使用它: ```vue <template> <div> <my-component></my-component> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; import MyComponent from './MyComponent.vue'; export default defineComponent({ components: { 'my-component': MyComponent, }, }); </script> ``` 通过在需要使用的地方引入 `MyComponent`,你就可以在页上展示并使用点击文字弹窗的功能了。 请注意,这只是一个简单的示例,你可以根据自己的需求进行进一步的定制和扩展。希望这对你有帮助!如果你还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值