当前位置: 首页 > article >正文

Vue2+OpenLayers实现折线绘制、起始点标记和轨迹打点的完整功能(提供Gitee源码)

目录

一、案例截图

二、安装OpenLayers库

三、代码实现

3.1、HTML页面

3.2、初始化变量

3.3、创建起始点位

3.4、遍历轨迹点

3.5、画折线

3.6、初始化弹窗信息

3.7、初始化地图上标点的点击事件

3.8、完整代码

四、Gitee源码


一、案例截图

二、安装OpenLayers库

npm install ol

三、代码实现

整体的实现思路:

1、创建开始、结束点位。

2、遍历轨迹点信息

3、画出轨迹折线

4、初始化弹窗样式

5、初始化地图上标点的点击事件。

3.1、HTML页面

关键代码:

<template>
  <div>
    <div id="map-container"></div>
    <div id="popup-box" class="popup-box">
      <button id="close-button" class="close-button">&times;</button>
      <div id="popup-content" class="popup-content"></div>
    </div>
  </div>
</template>

3.2、初始化变量

关键代码:

data() {
  return {
    map:null,
    overLay:null,
    // 定义路径坐标
    pointList: [
      [120.430070,31.938140],
      [120.428570,31.939100],
      [120.429530,31.941680],
      [120.431240,31.943580],
      [120.432410,31.944820],
      [120.433600,31.943970],
    ],
    pointLayer: new VectorLayer({
      source: new VectorSource(),
      zIndex: 5
    }),
  }
},

3.3、创建起始点位

关键代码:

/**
 * 创建开始点位
 */
createStartPoint(){
  // 创建feature要素,一个feature就是一个点坐标信息
  let feature = new Feature({
    geometry: new Point(this.pointList[0]),
  });
  // 设置要素的图标
  feature.setStyle(
      new Style({
        // 设置图片效果
        image: new Icon({
          src: 'http://lbs.tianditu.gov.cn/images/bus/start.png',
          // anchor: [0.5, 0.5],
          scale: 1,
        }),
        zIndex: 10,
      }),

  );
  this.pointLayer.getSource().addFeature(feature);
},
//创建结束点位
createEndPoint(){
  // 创建feature要素,一个feature就是一个点坐标信息
  let feature = new Feature({
    geometry: new Point(this.pointList[this.pointList.length-1]),
  });
  // 设置要素的图标
  feature.setStyle(
      new Style({
        // 设置图片效果
        image: new Icon({
          src: 'http://lbs.tianditu.gov.cn/images/bus/end.png',
          // anchor: [0.5, 0.5],
          scale: 1,
        }),
        zIndex: 10
      }),

  );
  this.pointLayer.getSource().addFeature(feature);
},

3.4、遍历轨迹点

先封装一个创建轨迹点的方法:

关键代码:

//创建轨迹点位
addPoint(coordinate) {
  // 创建feature要素,一个feature就是一个点坐标信息
  let feature = new Feature({
    geometry: new Point(coordinate),
  });
  // 设置要素的图标
  feature.setStyle(
      new Style({
        // 使用 Circle 图形
        image: new Circle({
          radius: 10, // 圆的半径
          fill: new Fill({
            color: 'white', // 内部颜色
          }),
          stroke: new Stroke({
            color: 'blue', // 外部颜色
            width: 3, // 外圈线宽
          }),
        }),
        zIndex: 5
      }),
  );
  return feature;
},

遍历轨迹点:

关键代码:

/**
 * 遍历点位
 */
drawPoints(){
  this.createStartPoint();
  for(let i = 0 ; i < this.pointList.length ; i++){
    let feature = this.addPoint(this.pointList[i]);
    this.pointLayer.getSource().addFeature(feature);
  }
  this.createEndPoint();
  this.map.addLayer(this.pointLayer);
},

3.5、画折线

关键代码:

//画线
drawLine(){
  // 创建线特征
  const lineFeature = new Feature({
    geometry: new LineString(this.pointList),
  });

  // 设置线样式
  const lineStyle = new Style({
    stroke: new Stroke({
      color: '#25C2F2',
      width: 4,
      lineDash: [10, 8], // 使用点划线 数组的值来控制虚线的长度和间距
    }),

  });
  lineFeature.setStyle(lineStyle);

  // 创建矢量层并添加特征
  const vectorSource = new VectorSource({
    features: [lineFeature],
  });
  const vectorLayer = new VectorLayer({
    source: vectorSource,
    zIndex: 1
  });

  // 将矢量层添加到地图
  this.map.addLayer(vectorLayer);
  // 设置地图视图以适应路径
  this.map.getView().fit(lineFeature.getGeometry().getExtent(), {
    padding: [20, 20, 20, 20],
    maxZoom: 18,
  });
},

3.6、初始化弹窗信息

关键代码:

/**
 * 初始化弹窗信息
 */
initPointWindow() {
  let popupBox = document.getElementById('popup-box');
  let closeButton = document.getElementById('close-button');
  //用于显示详情页面的窗口(根据经纬度来的,位置不固定)
  this.overlay = new Overlay({
    element: popupBox,
    autoPan: {
      animation: {
        duration: 250,
      },
    },
    offset:[0,-20],
  });
  this.map.addOverlay(this.overlay);
  // 关闭弹出框的事件处理
  let _that = this;
  closeButton.addEventListener('click', () => {
    _that.overlay.setPosition(undefined); // 关闭弹出框
  });
},

3.7、初始化地图上标点的点击事件

关键代码:

/**
 * 初始化地图上标点的点击事件
 */
initPointEvent(){
  let _that = this;
  //给点初始化点击事件
  this.map.on("singleclick", (e) => {
    let pixel = this.map.getEventPixel(e.originalEvent);
    let feature = this.map.forEachFeatureAtPixel(pixel, function(feature) { return feature; });
    let coordinates = e.coordinate;
    if(feature){
      _that.overlay.setPosition(coordinates);
      let popupContent = document.getElementById('popup-content');
      popupContent.innerHTML = `<div>经度:${coordinates[0]}</div><div>纬度:${coordinates[1]}</div>`;
    }
  });
},

3.8、完整代码

<template>
  <div>
    <div id="map-container"></div>
    <div id="popup-box" class="popup-box">
      <button id="close-button" class="close-button">&times;</button>
      <div id="popup-content" class="popup-content"></div>
    </div>
  </div>
</template>
<script>
import { Map, View } from 'ol'
import {Tile as TileLayer} from 'ol/layer'
import Overlay from 'ol/Overlay';
import { get } from 'ol/proj';
import { getWidth, getTopLeft } from 'ol/extent'
import { WMTS } from 'ol/source'
import WMTSTileGrid from 'ol/tilegrid/WMTS'
import { defaults as defaultControls} from 'ol/control';
import 'ol/ol.css';
import OSM from 'ol/source/OSM';
import { Feature } from 'ol';
import LineString from 'ol/geom/LineString';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Style from 'ol/style/Style';
import Stroke from 'ol/style/Stroke';
import {Circle, Fill, Icon} from "ol/style";
import CircleStyle from "ol/style/Circle";
import {Point} from "ol/geom";

export const projection = get("EPSG:4326");
const projectionExtent = projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = [];
for (let z = 0; z < 19; ++z) {
  resolutions[z] = size / Math.pow(2, z);
}


export default {
  data() {
    return {
      map:null,
      overLay:null,
      // 定义路径坐标
      pointList: [
        [120.430070,31.938140],
        [120.428570,31.939100],
        [120.429530,31.941680],
        [120.431240,31.943580],
        [120.432410,31.944820],
        [120.433600,31.943970],
      ],
      pointLayer: new VectorLayer({
        source: new VectorSource(),
        zIndex: 5
      }),
    }
  },
  mounted(){
    this.initMap() // 加载矢量底图
  },
  methods:{
    initMap() {
      const KEY = '你申请的KEY'

      this.map = new Map({
        target: 'map-container',
        layers: [
          // 底图
          new TileLayer({
            source: new WMTS({
              url: `http://t{0-6}.tianditu.com/vec_c/wmts?tk=${KEY}`,
              layer: 'vec', // 矢量底图
              matrixSet: 'c', // c: 经纬度投影 w: 球面墨卡托投影
              style: "default",
              crossOrigin: 'anonymous', // 解决跨域问题 如无该需求可不添加
              format: "tiles", //请求的图层格式,这里指定为瓦片格式
              wrapX: true, // 允许地图在 X 方向重复(环绕)
              tileGrid: new WMTSTileGrid({
                origin: getTopLeft(projectionExtent),
                resolutions: resolutions,
                matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
              })
            })
          }),
          // 标注
          new TileLayer({
            source: new WMTS({
              url: `http://t{0-6}.tianditu.com/cva_c/wmts?tk=${KEY}`,
              layer: 'cva', //矢量注记
              matrixSet: 'c',
              style: "default",
              crossOrigin: 'anonymous',
              format: "tiles",
              wrapX: true,
              tileGrid: new WMTSTileGrid({
                origin: getTopLeft(projectionExtent),
                resolutions: resolutions,
                matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
              })
            })
          })
        ],
        view: new View({
          center: [119.975000,31.809701],
          projection: projection,
          zoom: 12,
          maxZoom: 17,
          minZoom: 1
        }),
        //加载控件到地图容器中
        controls: defaultControls({
          zoom: false,
          rotate: false,
          attribution: false
        })
      });
      //画点
      this.drawPoints();
      //画线
      this.drawLine();
      //初始化窗体
      this.initPointWindow();
      //初始化标点点击事件
      this.initPointEvent();
    },
    /**
     * 创建开始点位
     */
    createStartPoint(){
      // 创建feature要素,一个feature就是一个点坐标信息
      let feature = new Feature({
        geometry: new Point(this.pointList[0]),
      });
      // 设置要素的图标
      feature.setStyle(
          new Style({
            // 设置图片效果
            image: new Icon({
              src: 'http://lbs.tianditu.gov.cn/images/bus/start.png',
              // anchor: [0.5, 0.5],
              scale: 1,
            }),
            zIndex: 10,
          }),

      );
      this.pointLayer.getSource().addFeature(feature);
    },
    //创建结束点位
    createEndPoint(){
      // 创建feature要素,一个feature就是一个点坐标信息
      let feature = new Feature({
        geometry: new Point(this.pointList[this.pointList.length-1]),
      });
      // 设置要素的图标
      feature.setStyle(
          new Style({
            // 设置图片效果
            image: new Icon({
              src: 'http://lbs.tianditu.gov.cn/images/bus/end.png',
              // anchor: [0.5, 0.5],
              scale: 1,
            }),
            zIndex: 10
          }),

      );
      this.pointLayer.getSource().addFeature(feature);
    },
    //创建轨迹点位
    addPoint(coordinate) {
      // 创建feature要素,一个feature就是一个点坐标信息
      let feature = new Feature({
        geometry: new Point(coordinate),
      });
      // 设置要素的图标
      feature.setStyle(
          new Style({
            // 使用 Circle 图形
            image: new Circle({
              radius: 10, // 圆的半径
              fill: new Fill({
                color: 'white', // 内部颜色
              }),
              stroke: new Stroke({
                color: 'blue', // 外部颜色
                width: 3, // 外圈线宽
              }),
            }),
            zIndex: 5
          }),
      );
      return feature;
    },
    /**
     * 遍历点位
     */
    drawPoints(){
      this.createStartPoint();
      for(let i = 0 ; i < this.pointList.length ; i++){
        let feature = this.addPoint(this.pointList[i]);
        this.pointLayer.getSource().addFeature(feature);
      }
      this.createEndPoint();
      this.map.addLayer(this.pointLayer);
    },
    //画线
    drawLine(){
      // 创建线特征
      const lineFeature = new Feature({
        geometry: new LineString(this.pointList),
      });

      // 设置线样式
      const lineStyle = new Style({
        stroke: new Stroke({
          color: '#25C2F2',
          width: 4,
          lineDash: [10, 8], // 使用点划线 数组的值来控制虚线的长度和间距
        }),

      });
      lineFeature.setStyle(lineStyle);

      // 创建矢量层并添加特征
      const vectorSource = new VectorSource({
        features: [lineFeature],
      });
      const vectorLayer = new VectorLayer({
        source: vectorSource,
        zIndex: 1
      });

      // 将矢量层添加到地图
      this.map.addLayer(vectorLayer);
      // 设置地图视图以适应路径
      this.map.getView().fit(lineFeature.getGeometry().getExtent(), {
        padding: [20, 20, 20, 20],
        maxZoom: 18,
      });
    },
    /**
     * 初始化地图上标点的点击事件
     */
    initPointEvent(){
      let _that = this;
      //给点初始化点击事件
      this.map.on("singleclick", (e) => {
        let pixel = this.map.getEventPixel(e.originalEvent);
        let feature = this.map.forEachFeatureAtPixel(pixel, function(feature) { return feature; });
        let coordinates = e.coordinate;
        if(feature){
          _that.overlay.setPosition(coordinates);
          let popupContent = document.getElementById('popup-content');
          popupContent.innerHTML = `<div>经度:${coordinates[0]}</div><div>纬度:${coordinates[1]}</div>`;
        }
      });
    },
    /**
     * 初始化弹窗信息
     */
    initPointWindow() {
      let popupBox = document.getElementById('popup-box');
      let closeButton = document.getElementById('close-button');
      //用于显示详情页面的窗口(根据经纬度来的,位置不固定)
      this.overlay = new Overlay({
        element: popupBox,
        autoPan: {
          animation: {
            duration: 250,
          },
        },
        offset:[0,-20],
      });
      this.map.addOverlay(this.overlay);
      // 关闭弹出框的事件处理
      let _that = this;
      closeButton.addEventListener('click', () => {
        _that.overlay.setPosition(undefined); // 关闭弹出框
      });
    },
  }
}
</script>
<style scoped>
#map-container {
  width: 100%;
  height: 100vh;
}
.popup-box {
  background: rgba(255, 255, 255, 0.95);
  border: 1px solid #ccc;
  border-radius: 8px;
  padding: 20px;
  z-index: 1000;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  transition: all 0.3s ease;
  max-width: 300px;
  font-family: 'Arial', sans-serif;
  position: absolute;
  transform: translate(-50%, -100%); /* 使弹出框上移并居中 */
}

/* 添加箭头样式 */
.popup-box::after {
  content: "";
  position: absolute;
  top: 100%; /* 箭头位于弹出框的底部 */
  left: 50%; /* 箭头横向居中 */
  margin-left: -6px; /* 调整箭头与弹出框的间距 */
  border-width: 6px; /* 箭头的大小 */
  border-style: solid;
  border-color: rgba(255, 255, 255, 0.95) transparent transparent transparent; /* 箭头的颜色 */
}

.close-button {
  background: none;
  color: gray;
  border: none;
  font-size: 20px;
  position: absolute;
  top: 10px;
  right: 10px;
  cursor: pointer;
}

.popup-content {
  width: 240px;
  margin-top: 10px;
  font-size: 16px;
  line-height: 1.5;
}
</style>

四、Gitee源码

地址:Vue2+OpenLayers实现折线绘制起始点标记和轨迹打点的完整功能


http://www.kler.cn/a/503287.html

相关文章:

  • 【容器逃逸实践】挂载/dev方法
  • MySQL:索引
  • TensorFlow Quantum快速编程(基本篇)
  • 细说STM32F407单片机以DMA方式读写外部SRAM的方法
  • Julia语言的数据结构
  • 网络应用技术 实验七:实现无线局域网
  • Spring MVC简单数据绑定
  • 通过高效的侦察发现关键漏洞接管整个IT基础设施
  • MATLAB中rescale函数用法
  • 【Uniapp-Vue3】响应式单位rpx及搭配使用UI产品工具
  • 力扣56. 合并区间
  • API接口技术开发小红书笔记详情api采集笔记图片视频参数解析
  • 【STM32】HAL库USB实现软件升级DFU的功能操作及配置
  • 开发人员学习书籍推荐(C#、Python方向)
  • IDEA编译器集成Maven环境以及项目的创建(2)
  • centos修改/etc/resolv.conf 重启network后又恢复到原来的状态
  • 微服务之松耦合
  • 微信小程序:实现首页权限菜单效果
  • Java-数据结构-栈与队列(常考面试题与单调栈)
  • 自动化办公|xlwings简介
  • 在移动端开发图表,uniapp+echarts,需要特殊处理,使用renderjs
  • 思科 Java 开发人员面试记录 2024(Java、Spring-Boot、Hibernate)
  • Kali之环境变量技巧(Kali‘s Environmental Variable Skills)
  • docker 与K8s的恩怨情仇
  • 【Vue】mouted、created、computed区别
  • HTTP详解——HTTP基础