openlayers 绘图功能,编辑多边形,modify组件的使用(三)

前两篇介绍了 openlayers 中 draw 的使用,自定义了绘制中和绘制结束后的样式,绘制结束后可以获取到绘制图形的featue或者进一步获取轮廓坐标(如下),可以进行坐标保存或者将feature添加到其他层进一步自定义显示

draw.value.on("drawend", (e) => {
  console.log("feature",  e.feature);
  const coord = e.feature.getGeometry().getCoordinates();
  console.log("coord", coord);
});

本篇介绍一下编辑工具 modify

1 需求

使用 openlayers 绘图功能绘制多边形,绘制完成后可进行编辑

2 分析

主要是 openlayers 中 draw,modify 功能的使用

3 实现

为了方便,直接使用绘制功能

3.1 简单实现

<template>
  <div id="map" class="map"></div>
</template>

<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import { Draw, Modify } from 'ol/interaction.js';
import { Vector as VectorSource } from 'ol/source.js';
import { Vector as VectorLayer } from 'ol/layer.js';
import { Circle, Fill, Stroke } from 'ol/style.js';
import { LineString, Point, Polygon } from 'ol/geom';


const projection = get('EPSG:4326');
const source = new VectorSource({ wrapX: false });
const map = shallowRef();
const draw = shallowRef();
const modify = shallowRef();

onMounted(() => {
  initMap();
  initInteraction();
});

const initMap = () => {
  map.value = new Map({
    target: 'map',
    view: new View({
      center: [116.406393, 39.909006],
      projection: projection,
      zoom: 5
    }),
    layers: [
      new VectorLayer({
        source: source,
        style: styleFunc
      })
    ]
  });
};

const initInteraction = () => {
  draw.value = new Draw({
    source: source,
    type: 'Polygon',
    style: drawStyleFunc
  });
  draw.value.on('drawstart', e => {
    console.log('e', e);
  });
  draw.value.on('drawend', e => {
    console.log('coord', e.feature.getGeometry().getCoordinates());
  });
  map.value.addInteraction(draw.value);

  modify.value = new Modify({
    source: source
  });

  modify.value.on('modifystart',  (event) =>{});

  modify.value.on('modifyend',  (event)=> {
    // 获取编辑后的轮廓
    event.features.forEach(feature => {
       console.log(feature.getGeometry().getCoordinates())
    });
  });

  map.value.addInteraction(modify.value);
};

const drawStyleFunc = feature => {
  const styles = [];
  const type = feature.getGeometry().getType();
  const coord = feature.getGeometry().getCoordinates();
  for (let i = 0; i < coord.length - 1; i++) {
    styles.push(
      new Style({
        geometry: new Point(coord[i]),
        image: new Circle({
          radius: 4,
          fill: new Fill({
            color: '#ffff'
          }),
          stroke: new Stroke({
            color: 'orange',
            width: 2
          })
        })
      })
    );
  }
  if (type === 'LineString') {
    for (let i = 0; i < coord.length - 1; i++) {
      styles.push(
        new Style({
          geometry: new LineString([coord[i], coord[i + 1]]),
          stroke: new Stroke({
            color: 'orange',
            lineDash: coord.length > 2 && i < coord.length - 2 ? [] : [10],
            width: 2
          })
        })
      );
    }
  }
  return styles;
};

const styleFunc = feature => {
  const styles = [];
  const coord = feature.getGeometry().getCoordinates();

  for (let i = 0; i < coord[0].length - 1; i++) {
    styles.push(
      new Style({
        geometry: new Point(coord[0][i]),
        image: new Circle({
          radius: 4,
          fill: new Fill({
            color: '#ffff'
          }),
          stroke: new Stroke({
            color: 'orange',
            width: 2
          })
        })
      })
    );
  }
  styles.push(
    new Style({
      fill: new Fill({
        color: [128, 128, 255, 0.5]
      }),
      stroke: new Stroke({
        color: 'blue',
        width: 2
      })
    })
  );
  return styles;
};
</script>
<style scoped lang="scss">
.map {
  width: 100%;
  height: 100%;
  background: #000;
}
</style>

3.2 需求更新 1

新需求:

  • 点击边的时候不自动增加新顶点
  • 不允许调整边,只允许调整点
  • 自定义鼠标悬浮顶点时的样式
  • 鼠标悬浮在顶点附近,吸附距离自定义

分析:

这里主要是pixelTolerance,insertVertexCondition和styleFunction的灵活使用

实现:

<template>
  <div id="map" class="map"></div>
</template>

<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import { Draw, Modify } from 'ol/interaction.js';
import { Vector as VectorSource } from 'ol/source.js';
import { Vector as VectorLayer } from 'ol/layer.js';
import { Circle, Fill, Stroke } from 'ol/style.js';
import { LineString, Point, Polygon } from 'ol/geom';

const projection = get('EPSG:4326');
const source = new VectorSource({ wrapX: false });
const map = shallowRef();
const draw = shallowRef();
const modify = shallowRef();

onMounted(() => {
  initMap();
  initInteraction();
});

const initMap = () => {
  map.value = new Map({
    target: 'map',
    view: new View({
      center: [116.406393, 39.909006],
      projection: projection,
      zoom: 5
    }),
    layers: [
      new VectorLayer({
        source: source,
        style: styleFunc
      })
    ]
  });
};

const initInteraction = () => {
  draw.value = new Draw({
    source: source,
    type: 'Polygon',
    style: drawStyleFunc
  });
  draw.value.on('drawstart', e => {
    console.log('e', e);
  });
  draw.value.on('drawend', e => {
    console.log('coord', e.feature.getGeometry().getCoordinates());
  });
  map.value.addInteraction(draw.value);

  modify.value = new Modify({
    source: source,
    pixelTolerance: 10, //设置吸附像素值
    insertVertexCondition: handleInsertVertexCondition,
    style: modifyStyleFunc
  });

  modify.value.on('modifystart', event => {});

  modify.value.on('modifyend', event => {
    event.features.forEach(feature => {
      console.log(feature.getGeometry().getCoordinates());
    });
  });

  map.value.addInteraction(modify.value);
};

const drawStyleFunc = feature => {
  const styles = [];
  const type = feature.getGeometry().getType();
  const coord = feature.getGeometry().getCoordinates();
  for (let i = 0; i < coord.length - 1; i++) {
    styles.push(
      new Style({
        geometry: new Point(coord[i]),
        image: new Circle({
          radius: 4,
          fill: new Fill({
            color: '#ffff'
          }),
          stroke: new Stroke({
            color: 'orange',
            width: 2
          })
        })
      })
    );
  }
  if (type === 'LineString') {
    for (let i = 0; i < coord.length - 1; i++) {
      styles.push(
        new Style({
          geometry: new LineString([coord[i], coord[i + 1]]),
          stroke: new Stroke({
            color: 'orange',
            lineDash: coord.length > 2 && i < coord.length - 2 ? [] : [10],
            width: 2
          })
        })
      );
    }
  }
  return styles;
};

const modifyStyleFunc = feature => {
  const coord = feature.getGeometry().getCoordinates();
  const layer = map.value.getLayers().item(0);
  const features = layer.getSource().getFeatures();
  const coords = features.map(feature => feature.getGeometry().getCoordinates()).flat(2);
  let style = undefined;
	// 只有鼠标在顶点时才能触发编辑功能
  if (coords.find(c => c.toString() === coord.toString())) {
    style = new Style({
      geometry: new Point(coord),
      image: new Circle({
        radius: 6,
        fill: new Fill({
          color: '#ffff'
        }),
        stroke: new Stroke({
          color: 'red',
          width: 2
        })
      })
    });
  }

  return style;
};
const handleInsertVertexCondition = e => {
	// 点击或者拖动边时不插入新顶点
  return false;
};
const styleFunc = feature => {
  const styles = [];
  const coord = feature.getGeometry().getCoordinates();

  for (let i = 0; i < coord[0].length - 1; i++) {
    styles.push(
      new Style({
        geometry: new Point(coord[0][i]),
        image: new Circle({
          radius: 4,
          fill: new Fill({
            color: '#ffff'
          }),
          stroke: new Stroke({
            color: 'orange',
            width: 2
          })
        })
      })
    );
  }
  styles.push(
    new Style({
      fill: new Fill({
        color: [128, 128, 255, 0.5]
      }),
      stroke: new Stroke({
        color: 'blue',
        width: 2
      })
    })
  );
  return styles;
};
</script>
<style scoped lang="scss">
.map {
  width: 100%;
  height: 100%;
  background: #000;
}
</style>


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

arxiv提交报错解决指南

- 编译时无错误 - 所有文件和图片文件都在同一目录下 - 生成.bbl文件 overleaf将参考文献格式bib转bbl&#xff08;bibitem&#xff09;_overleaf bbl文件-CSDN博客 - .tex文件、.bib文件、.bbl文件 的文件名要一致&#xff0c;修改.bib文件名记得在.tex文件中修改bibliograp…

如何导出数据库中数据表或查询结果的数据:支持大数据量(以MySQL和SQLynx为例)

MySQL的数据导出是一个操作非常频繁的任务&#xff0c;也是数据的存储和传输比较重要的一种方式&#xff0c;本文主要以SQLynx为例来介绍MySQL的数据如何导出。 目录 1 操作步骤 步骤 1&#xff1a;登录SQLynx 步骤 2&#xff1a;选择数据库和表 步骤 3&#xff1a;执行查询…

BL104钡铼多协议采集网关助力企业智能化转型

BL104钡铼多协议采集网关&#xff08;PLC物联网关BL104&#xff09;是为满足工业环境需求而设计的专业工业级协议转换网关。它在企业智能化转型过程中扮演着关键角色&#xff0c;为企业提供了高效、稳定的通信解决方案&#xff0c;助力企业实现智能化转型。 首先&#xff0c;P…

【Linux】运维-Kubernetes(k8s)应用介绍及使用-了解

一、介绍 Kubernetes&#xff0c;也被称为K8s或Kube&#xff0c;是谷歌推出的业界最受欢迎的容器编排器。 K8s是一个架构良好的分布式系统的例子。它将集群中的所有机器都视为单个资源池的一部分。 K8s与其他成熟的分布式系统一样&#xff0c;有两层&#xff1a;头节点和工作节…

opencv-python(八)

import cv2 import numpy as npheight 160 width 280 image np.zeros((height, width),np.uint8) cv2.imshow(image,image) cv2.waitKeyEx(0) cv2.destroyAllWindows() 二维数组代表一幅灰度图像。 import cv2 import numpy as npheight 160 width 280 image np.zeros((he…

什么是无头浏览器以及其工作原理?

如果您对这个概念还不熟悉&#xff0c;那么使用无头网络浏览器的想法可能会让您感到不知所措。无头浏览器本质上与您熟悉的网络浏览器相同&#xff0c;但有一个关键区别&#xff1a;它们没有图形用户界面 (GUI)。这意味着没有按钮、选项卡、地址栏或视觉显示。 相反&#xff0c…

译译交友项目介绍

一、 项目背景 随着社会的进步&#xff0c;英语作为一种国际语言&#xff0c;很多人都在学习英语&#xff0c;然而现在很多人都会因为学习英语而烦恼&#xff0c;有时还会因为是一个人学习而感到枯燥。面对情绪的低落&#xff0c;往往会使学习更困难。因此&#xff0c;我打造了…

2024 AI智算产业趋势,数据智能时代的到来(免费下载)

【1】关注公众号<方案驿站> 【2】私信发送 2024AI智算产业趋势展望 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT/WORD原格式&#xff0c;诚挚邀请您微信扫描以下二维码加入方案驿站知识星球&#xff0c;获取上万份PPT/WORD解决方案&…

Ubuntu系统中网易云音乐编译安装

项目地址&#xff1a; netease-cloud-music-gtk: Linux 平台下基于 Rust GTK 开发的网易云音乐播放器 目录 1.README.md中按照步骤来 2.安装git 3.报错 sudo apt install cmake sudo apt-get install libdbus-1-dev sudo apt install dnf sudo dnf install gettext 继…

2024年山西泵管阀展览会11月8日开展

2024中国&#xff08;山西&#xff09;国际水务科技博览会 暨水处理技术设备与泵管阀展览会 时间&#xff1a;2024年11月8-10日 地点&#xff1a;山西潇河国际会展中心 经研究&#xff0c;由山西省水处理行业协会、山西省水暖阀门商会、山西省固废产业协会联合主办的2024…

防火墙安全管理

大多数企业通过互联网传输关键数据&#xff0c;因此部署适当的网络安全措施是必要的&#xff0c;拥有足够的网络安全措施可以为网络基础设施提供大量的保护&#xff0c;防止黑客、恶意用户、病毒攻击和数据盗窃。 网络安全结合了多层保护来限制恶意用户&#xff0c;并仅允许授…

教你一段代码激活计算机系统

方法简单粗暴&#xff0c;再也不用遭受未激活的烦恼了&#xff01; 新建文本 输入代码&#xff0c;把文件后缀.txt改.bat slmgr /skms kms.03k.org slmgr /ato

m4a怎么转换成m4r格式?

之前给大家分享过“m4a转mp3”教程文章&#xff0c;今天继续分享有关m4a的格式转换方法。想必大家对m4a格式已经了解的差不多了&#xff0c;苹果手机的专属格式。那么大家知道m4r格式吗? 从名字就可以看出来&#xff0c;它和m4a格式肯定有着密切的联系和相似点。m4r是iPhone铃…

GUI编程03-事件监听

事件监听是指当某个事件发生的时候干一些什么。 例如之前在关闭frame窗口时就写过一个window窗口监听&#xff0c;当点击左上角❌时调用System.exit进行程序关闭。 1.按钮监听 下面的例子是监听按钮Button被点击时触发的事件 同时我们将窗口关闭监听事件进行了优化&#xff…

每日一练:攻防世界:base64stego

base64stego&#xff1a; 打开压缩包发现被加密&#xff0c;用winhex查看&#xff0c;发现是伪加密&#xff0c;修改文件目录区的全局方式位标记&#xff0c;成功打开压缩包&#xff0c;得到一个文本 这里我想的有三种情况&#xff1a;1.直接base64解码&#xff0c;然后看解码…

美业SaaS收银系统拓客系统源码分享-预约管理功能的作用和重要性

美业收银管理系统对于美容、美发、医美行业的门店来说至关重要&#xff0c;它不仅可以帮助提高管理效率和降低成本&#xff0c;还可以改善客户体验并促进业务增长。 &#xff08;私信获取源码/演示视频&#xff09; ▶ 美业系统中的【预约管理】有多种作用&#xff0c;包括&…

css display:grid布局,实现任意行、列合并后展示,自适应大小屏幕

现有6X7列的一个布局&#xff0c;如下图所示 想要用户能组成任意矩形盒子&#xff0c;并展示内容&#xff0c;具体效果如下&#xff08;仅为一个示例&#xff0c;其实可以任意组合矩形&#xff09;&#xff1a; html代码&#xff1a; <div class"grid-container"…

微信小程序毕业设计-驾校管理系统项目开发实战(附源码+论文)

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

Spring Security实现用户认证四:使用JWT与Redis实现无状态认证

Spring Security实现用户认证四&#xff1a;使用JWT与Redis实现无状态认证 1 什么是无状态认证&#xff1f;2 什么是JWT&#xff1f;2.1 需要注意的事项2.2 JWT构成 3 Spring Security JWT实现无状态认证3.1 创建一个Spring Boot项目3.1.1 依赖3.1.2 Main3.1.3 application.ym…

CMS与AI的融合:构建万能表单小程序系统

引言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;MyCMS作为一款功能强大的内容管理系统&#xff0c;通过集成AI技术&#xff0c;进一步拓展了其应用范围和智能化水平。本文将探讨如何利用MyCMS结合AI技术&#xff0c;构建一个能够将用户提交的万能表单数据转化为智能提…