vue2+Ts中openLayer绘图工具组件封装

news2025/1/18 11:06:19

vue2+Ts中openLayer绘图工具组件封装

效果:
在这里插入图片描述
封装组件代码:

<!-- openLayer绘图工具 -->
<template>
  <a-button-group v-show="isShow">
    <a-button v-if="shouldShowButton('point')" @click="draw('Point')">
      绘点
      <a-icon type="dot-chart" />
    </a-button>
    <a-button v-if="shouldShowButton('line')" @click="draw('LineString')">
      绘线
      <a-icon type="line-chart" />
    </a-button>
    <a-button v-if="shouldShowButton('polygon')" @click="draw('Polygon')">
      绘面
      <a-icon type="border" />
    </a-button>
    <a-button v-if="shouldShowButton('edit')" @click="edit()">
      编辑
      <a-icon type="edit" />
    </a-button>
    <a-button v-if="shouldShowButton('undo')" @click="undo()">
      撤销
      <a-icon type="undo" />
    </a-button>
    <a-button v-if="shouldShowButton('redo')" @click="redo()">
      重做
      <a-icon type="redo" />
    </a-button>
    <a-button v-if="shouldShowButton('save')" @click="save()">
      保存
      <a-icon type="save" />
    </a-button>
  </a-button-group>
</template>

<script lang="ts">
import abpbase from '@/libs/abpbase';
import VectorSource from 'ol/source/Vector';
import Map from 'ol/Map';
import { Component, Emit, Prop } from 'vue-property-decorator';
import ol from 'ol';
import VectorLayer from 'ol/layer/Vector';
import Draw, { createRegularPolygon } from 'ol/interaction/Draw';
import Modify from 'ol/interaction/Modify';
import {
 singleClick, doubleClick, pointerMove, never,
} from 'ol/events/condition';
import Select from 'ol/interaction/Select';
import Translate from 'ol/interaction/Translate';
import Snap from 'ol/interaction/Snap';
// eslint-disable-next-line import/no-unresolved
import * as jsts_io from 'jsts/org/locationtech/jts/io';
import {
 Style, Fill, Stroke, Circle,
} from 'ol/style';
import {
  LinearRing,
  LineString,
  MultiLineString,
  MultiPoint,
  MultiPolygon,
  Point,
  Polygon,
} from 'ol/geom.js';
import MapBrowserEventType from 'ol/MapBrowserEventType';

@Component({
  name: 'OpenLayerDrawTool',
  components: {
  },
})
export default class OpenLayerDrawTool extends abpbase {
  /**
   * 最大可绘制要素数量
   */
  @Prop({type:Number, default:1})
  maxFeatures

  @Prop({ type: Array, default: () => ["point", "line", "polygon", "undo", "redo", "save", "edit"] })
  buttonsToShow: string[];

  /**
   * 编辑操作
   */
  editOperation: Modify;

  shouldShowButton(buttonName: string): boolean {
    return this.buttonsToShow.includes(buttonName);
  }

  /**
   * 绘制的矢量图层
   */
  drawVectorLayer: VectorLayer<any>;

  /**
   * 绘制的数据源
   */
  drawSource: VectorSource;

  /**
   * 传入的openLayer地图
   */
  map: Map = null;

  /**
   * 绘制操作
   */
  drawOperation: Draw;

  /**
   * 绘制的图形堆栈
   */
  drawStack = []

  /**
   * 重做的图形堆栈
   */
  redoStack = []

  selectOperation: Select

  translateOperation: Translate

  snapOperation: Snap

  get isShow() {
    return this.map != null;
  }

  /**
   * 初始化地图控件,需要在父组件调用;
   * @param map openLayer地图对象
   * @param requestDataId 请求的数据参数
   */
  initCtrl(map: Map) {
    this.map = map;
    this.drawSource = new VectorSource();

    const createCustomStyle = () => (feature) => {
        const geometryType = feature.getGeometry().getType();
        let style;
        switch (geometryType) {
          case 'Point':
            style = new Style({
              image: new Circle({
                radius: 6,
                fill: new Fill({ color: 'rgba(255, 0, 0, 0.5)' }),
                stroke: new Stroke({ color: 'red', width: 2 }),
              }),
            });
            break;
          case 'LineString':
            style = new Style({
              stroke: new Stroke({
                color: 'blue',
                width: 4,
              }),
            });
            break;
          case 'Polygon':
            style = new Style({
              fill: new Fill({ color: 'rgba(0, 255, 0, 0.2)' }),
              stroke: new Stroke({ color: 'green', width: 3 }),
            });
            break;
          default: {
            break;
          }
        }

        return style;
      };

    this.drawVectorLayer = new VectorLayer<any>({
      source: this.drawSource,
      style: createCustomStyle(),
      zIndex: 999,
    });
    this.map.addLayer(this.drawVectorLayer);
    this.$forceUpdate();
  }

  draw(type) {
    this.map.removeInteraction(this.drawOperation);
    this.drawOperation = new Draw({
      source: this.drawSource,
      type,
      condition: (event) => event.type === MapBrowserEventType.POINTERDOWN && event.originalEvent.button === 0,
    });
    this.map.addInteraction(this.drawOperation);

    this.drawOperation.on('drawend', (e) => {
      // 为要素分配一个唯一的 ID
      e.feature.set('id', Date.now());

      this.drawStack.push(e.feature);
      // 如果绘制的图形数量超过最大限制,移除最早添加的图形
      if (this.drawStack.length > this.maxFeatures) {
        const firstFeature = this.drawStack.shift();
        this.drawSource.removeFeature(firstFeature);
      }
      this.map.removeInteraction(this.drawOperation);
    });
  }

  undo() {
    const lastFeature = this.drawStack.pop();
    if (lastFeature) {
      this.drawSource.removeFeature(lastFeature);
      this.redoStack.push(lastFeature);
    }
  }

  redo() {
    const lastFeature = this.redoStack.pop();
    if (lastFeature) {
      // 如果绘制的图形数量达到最大限制,移除最早添加的图形并将其从重做堆栈中移除
      if (this.drawStack.length >= this.maxFeatures) {
        const firstFeature = this.drawStack.shift();
        this.drawSource.removeFeature(firstFeature);
      }
      this.drawSource.addFeature(lastFeature);
      this.drawStack.push(lastFeature);
    }
  }

  save() {
    const parser = new jsts_io.OL3Parser();
    parser.inject(
        Point,
        LineString,
        LinearRing,
        Polygon,
        MultiPoint,
        MultiLineString,
        MultiPolygon,
    );

    const format = new jsts_io.WKTWriter();
    const features = this.drawSource.getFeatures();
    const wkts = features.map((feature) => {
      const olGeom = feature.getGeometry();
      const jstsGeom = parser.read(olGeom);
      return format.write(jstsGeom);
    });
    console.log(JSON.stringify(wkts));
  }

  mounted() {

  }

  edit() {
    // 移除 drawOperation 交互
    this.map.removeInteraction(this.drawOperation);

    // // 创建 selectOperation 交互对象
    this.selectOperation = new Select({
      condition: singleClick,
    });

    this.map.addInteraction(this.selectOperation);

    // 创建 translateOperation 交互对象
    this.translateOperation = new Translate({
      features: this.selectOperation.getFeatures(),
    });

    this.map.addInteraction(this.translateOperation);

    // 创建 modifyOperation 交互对象
    this.editOperation = new Modify({
      features: this.selectOperation.getFeatures(),
    });
    this.editOperation.setActive(false);

    this.map.addInteraction(this.editOperation);

    this.editOperation.on('modifyend', (e) => {
      // 更新 drawStack 中的要素
      const updatedFeature = e.features.getArray()[0];
      const featureIndex = this.drawStack.findIndex(
          (feature) => feature.get('id') === updatedFeature.get('id'),
      );
      if (featureIndex >= 0) {
        this.drawStack.splice(featureIndex, 1, updatedFeature);
      }
    });

    // 为地图添加双击事件侦听器
    this.map.on('dblclick', (event) => {
      const features = this.map.getFeaturesAtPixel(event.pixel);
      if (features && features.length > 0) {
        this.editOperation.setActive(true);
        this.snapOperation.setActive(true);
        this.translateOperation.setActive(false);
      } else {
        this.editOperation.setActive(false);
        this.snapOperation.setActive(false);
        this.translateOperation.setActive(true);
      }
    });

    // 为地图添加 pointermove 事件侦听器
    // this.map.on('pointermove', (event) => {
    //   const features = this.map.getFeaturesAtPixel(event.pixel);
    //   if (features && features.length > 0) {
    //     this.editOperation.setActive(true);
    //   } else {
    //     this.editOperation.setActive(false);
    //   }
    // });
  }

  // 初始化
  // init() {
  // }

  // created() {
  // }
}
</script>

<style lang="less" scoped>
.home-wrap {
  min-width: 1280px;
  overflow: auto;
}
</style>

父组件使用:

<div class="absolute right-4 top-4">
   <open-layer-draw-tool ref="drawTool"></open-layer-draw-tool>
</div>

initDrawTool() {
     this.$nextTick(() => {
       (this.$refs.drawTool as any).initCtrl(this.map);
     });
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1674554.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Axure10_win安装教程(安装、汉化、授权码,去弹窗)

1.下载Axure10 链接&#xff1a;https://pan.baidu.com/s/1fc8Bgyic8Ct__1IOv-afUg 提取码&#xff1a;9qew 2.安装Axure10 因为我的电脑是Windows操作系统&#xff0c;所以我下载的AxureRP-Setup-Beta v10.0.0.3816 (Win).exe 一直点下一步就行 3.Axure10中文 打开Axure…

(python)cryptography-安全的加密

前言 cryptography 是一个广泛使用的 Python 加密库&#xff0c;提供了各种加密、哈希和签名算法的实现。它支持多种加密算法&#xff0c;如 AES、RSA、ECC 等&#xff0c;以及哈希函数&#xff08;如 SHA-256、SHA-384 等&#xff09;和数字签名算法(如 DSA、ECDSA 等). 目录 …

Linux下Code_Aster源码编译安装及使用

目录 软件介绍 基本依赖 其它依赖 一、源码下载 二、解压缩 三、编译安装 四、算例运行 软件介绍 Code_aster为法国电力集团&#xff08;EDF&#xff09;自1989年起开始研发的通用结构和热力耦合有限元仿真软件。Code_aster可用于力学、热学和声学等物理现象的仿真分析&…

诺基亚3210复古风再起:情怀与现实的碰撞

在数字科技日新月异的今天&#xff0c;诺基亚的复古风潮却意外地掀起了波澜。这款曾经风靡一时的诺基亚3210&#xff0c;在时隔二十五年后&#xff0c;以全新的面貌再次回归市场&#xff0c;引发了无数人的怀旧与好奇。 诺基亚的这次“千禧回归”策略&#xff0c;无疑是对Y2K潮…

Java——类和对象第二节——封装

1.什么是封装 封装是面向对象程序的三大特性之一&#xff0c;面向对象程序的三大特性分别是封装&#xff0c;继承&#xff0c;多态 而封装简单来说就是套壳隐藏细节 打个比方&#xff1a; 在一些电脑厂商生产电脑时&#xff0c;仅对用户提供开关机键&#xff0c;键盘输入&a…

鸿蒙布局Column/Row/Stack

鸿蒙布局Column/Row/Stack 简介我们以Column为例进行讲解1. Column({space: 10}) 这里的space: 10&#xff0c;表示Column里面每个元素之间的间距为102. width(100%)&#xff0c;height(100%) 表示宽高占比3. backgroundColor(0xffeeeeee) 设置背景颜色4. padding({top: 50}) 设…

基于Springboot+Vue的Java项目-农产品直卖平台系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

【docker】SpringBoot应用容器镜像日志挂载

启动镜像时候使用 -v 挂载 首先得在宿主机创建目录&#xff1a;/workspace/java/demo/logs mkdir -pv /workspace/java/demo/logs 启动镜像 docker run -p 8080:8080 -itd -v /workspace/java/demo/logs/:/logs/ 192.168.2.1:5000/demo:0.0.1-SNAPSHOT -v /workspace/ja…

VMware虚拟机没有网,无法设置网络为桥接状态

今天需要使用Ubuntu18但现有虚拟机是Ubuntu20&#xff0c;由于硬盘空间不够大&#xff0c;所以删除了原来的虚拟机并重新搭建Ubuntu18的环境&#xff0c;然后发现虚拟机没有网络&#xff0c;而我之前的虚拟机这一切都是正常的。 在网络设置里勾选的是桥接模式但无法联网&#x…

如何基于可靠事件模式实现最终一致性?

今天我们一起来探讨一个分布式环境下的常见问题,这个问题与数据的一致性有关。那么,什么是数据一致性呢?要回答这个问题,需要我们回顾一下单块系统和分布式系统中对于数据处理的不同需求。 我们知道,传统的单块系统通常都只与一个数据库进行交互,所有的数据处理过程都位于…

前端连续发送同一个请求时,终止上一次请求

场景&#xff1a;几个tab页之间快速的切换&#xff08;tab页只是参数不同&#xff0c;下边的数据渲染给同一个data&#xff09;就会导致如果我在1,2,3&#xff0c;tab页按照顺序快速点击&#xff0c;发送三个请求&#xff0c;我想要展示的是3但是如果1或者2请求响应的时间比3长…

广汽原车控制系统CAN协议控制汽车基本信息获取及数据应用

在现代汽车工业的迅速发展中&#xff0c;车辆控制系统的智能化和网络化已成为提升汽车性能的关键。广汽作为中国汽车行业的佼佼者&#xff0c;其在原车通信网络方面也取得了显著的成就。特别是广汽原车CAN&#xff08;Controller Area Network&#xff09;协议的应用&#xff0…

unordered_map、unordered_set底层封装

文章目录 一、先实现哈希桶1.1哈希桶的实现方法1.2日常普遍的哈希桶存放的数据有两种&#xff1a;字符串和整形1.3哈希桶的实现代码详解1.3.1哈希桶的两种仿函数&#xff08;int和string&#xff09;1.3.2哈希桶的节点&#xff08;如果桶非常深&#xff0c;这里考虑挂红黑树&am…

k8s 网络组件详细 介绍

目录 一 k8s 有哪些网络组件 二 k8s 网络概念 1&#xff0c; k8s 三种网络 2&#xff0c;K8S 中 Pod 网络通信 2.1 Pod 内容器与容器之间的通信 2.2 同一个 Node 内 Pod 之间的通信 2.3 不同 Node 上 Pod 之间的通信 三 Flannel 网络组件 1&#xff0c;Flannel …

leetcode.所有可能的路径(python)

找到从节点0到n-1的所有路径&#xff0c;肯定是用dfs算法&#xff0c;不过有两种思考方式&#xff1a; 一种是&#xff1a;从后往前考虑。如果这条路能到n-1节点&#xff0c;那么dfs返回一个rec列表&#xff0c;里面存路径。 class Solution:def allPathsSourceTarget(self, …

C语言数据结构(超详细讲解)| 栈和队列的实现

栈和队列的实现 引言 在计算机科学的世界里&#xff0c;数据结构是我们构建各种复杂算法和解决问题的基石。其中&#xff0c;栈&#xff08;Stack&#xff09;和队列&#xff08;Queue&#xff09;作为两种经典的数据结构&#xff0c;在解决实际问题时发挥着不可或缺的作用。…

【回溯 代数系统】679. 24 点游戏

本文涉及知识点 回溯 代数系统 LeetCode679. 24 点游戏 给定一个长度为4的整数数组 cards 。你有 4 张卡片&#xff0c;每张卡片上都包含一个范围在 [1,9] 的数字。您应该使用运算符 [‘’, ‘-’, ‘*’, ‘/’] 和括号 ‘(’ 和 ‘)’ 将这些卡片上的数字排列成数学表达式…

【C#】WPF加载浏览器

结果展示 下载SDK 前端代码 红色框住的为添加代码 <Window x:Class"WPFwebview.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://…

TCP四次挥手——断开连接 滑动窗口-流量控制

四次挥手 在TCP的四次挥手中&#xff0c;其重要作用就是释放客户端和服务器的连接。 这里的一些参数非常重要&#xff0c;因为这些参数的作用是为了表达TCP四次挥手断开连接的过程。 其中的参数如下 1.FIN&#xff1a;FIN (Finish) 是TCP协议中的一个标志位&#xff0c;用于…

推荐网站(9)pixabay免费可商用的图片、视频、插画、矢量图、音乐

今天推荐一款可以免费可商用的图片、视频、插画、矢量图、音乐的资源网站&#xff0c;这里面的所以东西都是免费的&#xff0c;并且可以商用。对那些做视频剪辑的人来说帮助非常大。它里面的资源非常的丰富&#xff0c;质量也高。 比如搜索下雨 链接直达&#xff1a;https://pi…