Openlayers6 图形绘制和修改功能(结合React)

news2024/9/21 19:08:06

Openlayers常用的API了解的差不多了,就开始进入实战了,首先从绘制基本的图形开始,这里主要介绍一下绘制圆形、矩形和多边形。

通过使用openlayers的ol.interaction.Drawol.interaction.Modify模块实现地图上绘制圆形、矩形、多边形并修改编辑。在这里插入图片描述
首先我们需要创建一个地图容器,并添加地图和矢量图层。底图我这里使用了高德图层,矢量图层用于显示用户绘制结果。然后我们通过添加Draw交互控件来实现绘制功能。每个绘制按钮都有一个点击事件处理函数,调用addInteraction方法来添加相应类型的绘制控件。通过添加Modify交互控件实现修改功能。

一、创建地图

在Openlayers中创建一个简单的地图可以通过一下步骤完成:

  1. 引入Openlayers库。
  2. 创建地图视图ol/View实例,并设置初始中心点和缩放级别。
  3. 创建地图层ol/layer/Tile,通常使用瓦片图层ol/source/OSM
  4. 创建地图实例ol/Map,并将之前创建的视图和图层添加进去。
  5. 获取DOM元素并将地图实例挂载到该元素上。
// 引入OpenLayers库
import { Map, View } from 'ol';
import { Tile as TileLayer } from 'ol/layer';
import * as Proj from 'ol/proj';

const [map, setMap] = useState(null); // 地图
const [view, setView] = useState(null); // 地图视图

useEffect(() => {
    // 监听地图视图并创建地图实例
    if (view) {
        // 创建一个高德图层
        const tileLayer = new TileLayer({
            source: new XYZ({
                url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&scl=1&size=1&style=7&x={x}&y={y}&z={z}'
            })
        });
        // 创建实例
        const _map = new Map({
            target: 'map',
            layers: [tileLayer], // 使用高德图层
            view: view
        });
        setMap(_map);
    }
}, [view]);

useEffect(() => {
    // 创建一个地图视图
    const viewObj = new View({
        center: Proj.transform([104.06403453968424, 30.597419070782898], 'EPSG:4326', 'EPSG:3857'), // 使用'EPSG:3857'投影
        zoom: 16
    });
    setView(viewObj);
}, []);

return <div id='map' style={{ width: '100%', height: '100%' }}></div>

二、绘制图形

可以使用VectorLayerVectorSource添加一个矢量图层,该图层可以用来绘制图形。

import { Vector as VectorLayer } from 'ol/layer';
import { Vector as VectorSource } from 'ol/source';
import { Style, Stroke, Fill } from 'ol/style';

let drawSource = null;
let drawLayer = null;

 useEffect(() => {
    if (map) {
        drawSource = new VectorSource();
        // 添加画板layer
        drawLayer = new VectorLayer({
            source: drawSource,
            style: new Style({
                fill: new Fill({
                    color: 'rgba(237, 57, 47, 0.35)'
                }),
                stroke: new Stroke({
                    color: '#ED392F',
                    width: 4,
                    lineDash: [10]
                })
            })
        });
        map.addLayer(drawLayer);
    }
}, [map]);

三、添加地图交互操作

添加DrawModify交互操作,允许用户在地图上绘图并编辑。

ol.interaction.Draw简述

使用 ol.interaction.Draw 绘制图形,Draw控件需要指定一个矢量源和绘制类型。当用户在地图上进行绘制时,绘制结果会被添加到矢量源中。可调用removeInteraction方法取消绘制。

常用属性
  • type:绘制的几何图形的几何类型,包括Point单点、LineString线、Circle圆、Polygon多边形四种类型。
  • features:表示绘制的图形将添加在指定的要素上。
  • source:绘制时指定的数据来源。表示绘制的图形将添加在指定的图层上。
  • geometryFunction:用于指定geometry,包括两参数,分别是coordinatesgeometry,返回geometry。通过该方法可以重新构建图形,比如将圆形构造成五角星。
  • style:指定绘制图形的样式。
  • freehand:手绘线、面等图形。设置属性为true开启手绘模式(随意绘制曲线或者直线)。
  • maxPoints:最多可以绘制多少个点,比如设置成5,在绘制多边形时,如果超过了5个点就不能绘制了。
  • minPoints:在完成多边形环或线时,必须指定绘制的点数。多边形的默认值为3,线段的默认值为2。
常用方法
  • createBox:当typeCircle时将geometryFunction设置成该方法,可以绘制矩形。
  • createRegularPolygon:当typeCircle时将geometryFunction设置成该方法,可以正多边形。
  • appendCoordinates:当在绘制完线或者多边形后,还可以通过该方法往图形中添加坐标。
  • extend:扩展图片,可以往图形上再添加一个图形,仅限于线条。
  • finishDrawing:结束绘制。
  • removeLastPoint:删除最后一个坐标点。
常用事件
  • drawend:绘制结束时触发。
  • drawstart:绘制开始时触发。
Draw实例
import { Draw } from 'ol/interaction';
import { Style, Stroke, Fill, Circle as CircleStyle } from 'ol/style';

let draw = null;

// 添加Draw交互操作
draw = new Draw({
    source: drawSource,
    type: 'Polygon',
    style: new Style({
        fill: new Fill({
            color: 'rgba(237, 57, 47, 0.35)'
        }),
        stroke: new Stroke({
            color: '#ED392F',
            width: 4,
            lineDash: [10]
        }),
        image: new CircleStyle({
            radius: 7,
            fill: new Fill({
                color: '#ED392F'
            })
        })
    })
});
// 添加Draw交互
map.addInteraction(draw);

draw.on('drawend',function() {
    // 绘制结束时触发
});
draw.on('drawstart',function() {
    // 绘制开始时触发
});
ol.interaction.Modify简述

使用 ol.interaction.Modify 编辑图形。只要将它初始化作为交互控件加入Map对象,就可以对几何图形进行动态编辑。
将鼠标移动到已经绘制好的线条或点上面,再移动鼠标,可以对图形进行修改。
按住Alt键时,再点击鼠标,可以删除选中的点。

常用属性
  • condition:设置一个函数,在修改时监听点击事件,返回一个布尔值表示是否处理该点击事件。比如返回false时,选中点后,点击选中的点再移动鼠标时将不处理移动事件。
  • deleteCondition:设置一个函数,返回一个布尔值是否执行删除的操作。
  • insertVertexCondition:设置一个函数,返回一个布尔值表示是否添加新的点。比如我们在编辑多边形时,点击多边形上的线条时,默认是可以在点击的位置添加一个点。如果返回值为false,不会添加新的坐标点。
  • pixelTolerance:设置捕捉点的像素差,如果设置的很大,离坐标点很远也能捕捉到点,默认值 为10px。
  • style:用于修改点或顶点的样式。对于LineString和Polygon类,style将影响它们的顶点;对于Circle类,style将影响沿着圆的点;对于Point,style影响的就是实际的点。如果没有配置的话,就会使用默认的配置,默认配置是蓝色的。
  • source:要修改的数据源。如果未提供数据源,则必须提供要修改的Feature。
  • features:要修改的Feature。如果未提供Feature,则必须提供数据源。
常用方法
  • removePoint:删除当前正在编辑的点。
常用事件
  • modifystart:编辑开始时触发
  • modifyend:编辑接触时触发
Modify实例
import { Collection } from 'ol';
import { Modify } from 'ol/interaction';
import { Style, Stroke, Fill, Circle as CircleStyle } from 'ol/style';

let modify = null;

let features = new Collection();
features.push(event.feature);
modify = new Modify({
    features: features // 选中的要素
});
// 添加Modify交互
map.addInteraction(modify);

modify.on('modifystart', () => {
    // 编辑开始时触发
});
modify.on('modifyend', () => {
    // 编辑接触时触发
});

四、完整代码示例

import React, { useState, useEffect } from 'react';
import { Map, View, Collection } from 'ol'; // 地图Collection
import * as Proj from 'ol/proj'; // 转化
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'; // 图层
import { XYZ, Vector as VectorSource } from 'ol/source'; // 资源
import Draw, { createBox } from 'ol/interaction/Draw';
import { Modify } from 'ol/interaction';
import { Style, Stroke, Fill, Circle as CircleStyle } from 'ol/style'; // 样式

let drawSource = null;
let drawLayer = null;
let draw = null;
let modify = null;

const OpenlayerInteraction = () => {
    const [map, setMap] = useState(null); // 地图
    const [view, setView] = useState(null); // 地图视图
    const [drawType, setDrawType] = useState(null); // 画板类型 1圆形 2矩形 3多边形

    // 设置绘制类型
    function setDraw(type) {
        let kind = null;
        let geometryFunction = null;
        if (type === 1) {
            kind = 'Circle';
        } else if (type === 2) {
            kind = 'Circle';
            geometryFunction = createBox();
        } else if (type === 3) {
            kind = 'Polygon';
        }
        draw = new Draw({
            source: drawSource,
            type: kind,
            geometryFunction: geometryFunction,
            style: new Style({
                fill: new Fill({
                    color: 'rgba(237, 57, 47, 0.35)'
                }),
                stroke: new Stroke({
                    color: '#ED392F',
                    width: 4,
                    lineDash: [10]
                }),
                image: new CircleStyle({
                    radius: 7,
                    fill: new Fill({
                        color: '#ED392F'
                    })
                })
            })
        });
        map.addInteraction(draw);
        setDrawType(type);
        
        // 监听线绘制结束事件,获取坐标
        draw.on('drawend', (event) => {
            // 移除绘制功能
            map.removeInteraction(draw);
            // 重置数据
            setDrawType(null);
            draw = null;
            // 获取绘制信息
            let geometryDraw = event.feature.getGeometry();
            console.log(geometryDraw);
            
            // 添加修改功能
            let features = new Collection();
            features.push(event.feature);
            modify = new Modify({
                features: features,
                style: new Style({
                    image: new CircleStyle({
                        radius: 7,
                        fill: new Fill({
                            color: '#ED392F'
                        })
                    })
                })
            });
            map.addInteraction(modify);
            // 监听修改事件
            modify.on('modifyend', () => {
            
            });
        });
    }
    useEffect(() => {
        if (map) {
            // 添加画板layer
            drawSource = new VectorSource();
            drawLayer = new VectorLayer({
                source: drawSource,
                style: new Style({
                    fill: new Fill({
                        color: 'rgba(237, 57, 47, 0.35)'
                    }),
                    stroke: new Stroke({
                        color: '#ED392F',
                        width: 4,
                        lineDash: [10]
                    })
                })
            });
            drawLayer.setZIndex(2);
            map.addLayer(drawLayer);
        }
    }, [map]);

    useEffect(() => {
        // 监听地图视图,创建地图
        if (view) {
            // 使用高德图层
            const tileLayer = new TileLayer({
                source: new XYZ({
                    url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&scl=1&size=1&style=7&x={x}&y={y}&z={z}'
                })
            });
            // 创建实例
            const _map = new Map({
                target: 'map',
                layers: [tileLayer], // 使用高德图层
                view: view
            });
            setMap(_map);
        }
    }, [view]);

    useEffect(() => {
        // View用于创建2D视图
        const viewObj = new View({
            center: Proj.transform([104.06403453968424, 30.597419070782898], 'EPSG:4326', 'EPSG:3857'), // 使用'EPSG:3857'投影
            zoom: 16
        });
        setView(viewObj);
    }, []);

    return <div className='interaction_container'>
        <div>openlayer地图绘制、修改圆形、矩形、多边形</div>
        <div className='map_box'>
            <div className='draw_type'>
                <span className="title">选择绘制图形</span>
                <div className={`list ${drawType === 1 ? "active" : ''}`} onClick={() => { setDraw(1); }}>圆形</div>
                <div className={`list ${drawType === 2 ? "active" : ''}`} onClick={() => { setDraw(2); }}>矩形</div>
                <div className={`list ${drawType === 3 ? "active" : ''}`} onClick={() => { setDraw(3); }}>多边形</div>
            </div>
            <div id='map' style={{ width: '100%', height: '100%' }}></div>
        </div>

    </div>;
}
export default OpenlayerInteraction;


// 样式
.interaction_container {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;

    .map_box {
        flex: 1;
        position: relative;

        .draw_type {
            position: absolute;
            z-index: 4;
            top: 16px;
            right: 16px;
            background-color: #ffffff;
            box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.1);
            border-radius: 4px;
            padding: 16px;
            color: #333333;

            .title {
                font-size: 14px;
                line-height: 20px;
                margin-bottom: 6px;
                display: inline-block;
            }

            .list {
                width: 130px;
                height: 32px;
                border-radius: 4px;
                display: flex;
                justify-content: center;
                align-items: center;
                margin-top: 8px;
                cursor: pointer;
                border: 1px solid #D5D5D5;
                color: #333333;
                background: #ffffff;
                transition: all .1s ease;
            }

            .list:hover {
                border: 1px solid #10BDFA;
                color: #ffffff;
                background: #10BDFA;
            }

            .active {
                border: 1px solid #10BDFA;
                color: #ffffff;
                background: #10BDFA;
            }
        }
    }
}

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

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

相关文章

2024.8.12(LVS)

一、LVS 1、描述以及工作原理 1. 什么是LVS linux virtural server的简称,也就是linxu虚拟机服务器,这是一个由章文嵩博士发起的开源项目,官网是http://www.linuxvirtualserver.org,现在lvs已经是linux内核标准的一部分,使用lvs可以达到的技术目标是:通过linux达到负载均衡技…

mysql注入-字符编码技巧

一、环境搭建 创建数据表 CREATE TABLE mysql_Bian_Man (id int(10) unsigned NOT NULL AUTO_INCREMENT,username varchar(255) COLLATE latin1_general_ci NOT NULL,password varchar(255) COLLATE latin1_general_ci NOT NULL,PRIMARY KEY (id) ) ENGINEMyISAM AUTO_INCREME…

Python办公自动化:使用`xlutils` 修改Excel文档

在日常办公自动化中&#xff0c;除了读取Excel文件&#xff0c;我们还经常需要对文件进行修改或更新。在Python中&#xff0c;除了xlrd&#xff0c;还可以使用xlutils库来实现对Excel文件的修改操作。本文将继续以“巴黎奥运会奖牌榜.xlsx”文件为例&#xff0c;讲解如何使用xl…

OpenCV + CUDA + cuDNN模块编译

简介 在追求高端性能与资源优化并重的应用场景中&#xff0c;如边缘计算设备或资源受限的开发板上运行YOLO等复杂深度学习模型&#xff0c;采用C结合OpenCV与GPU加速技术相较于传统的Python环境展现出显著优势。这种策略不仅极大地提升了执行效率&#xff0c;还显著降低了运行时…

陶晶池串口屏数据存储区概述与使用

陶晶池串口屏的数据存储区大小&#xff1a;x系列是2k字节的&#xff0c;其他系列是1k字节的&#xff0c;超出了就会从头覆盖最先的字节 你可以在主动解析模式下调用u[x]来访问数据存储区内第x-1字节是什么&#xff0c;也可以读取usize看看记录大小 它的原理是&#xff0c;每接收…

axios 封装避免重复请求(两种)

目录 前言 Demo 第一种实现方法 第二种方法&#xff08;axios版本0.22.0以上&#xff09; 前言 在当今的前端开发领域&#xff0c;数据交互是不可或缺的一环。Axios 作为一款基于 Promise 的 HTTP 客户端&#xff0c;因其简洁的 API 和丰富的配置选项&#xff0c;深受广大…

R语言的下载和安装

R是一种强大的编程语言和环境&#xff0c;主要用于统计计算和数据分析。自从R诞生以来&#xff0c;它在统计学家和数据科学家中迅速普及。然而&#xff0c;R本身只是一个命令行工具&#xff0c;对于大多数用户来说&#xff0c;单独使用R可能会有些困难或者不方便。RStudio作为一…

科技云报道:“大模型+机器人”,具身智能将开启“智械时代”

科技云报道原创。 从15世纪达芬奇绘制出世界上第一份人形机器人手稿&#xff0c;到如今波士顿动力、本田、特斯拉、Figure AI等企业相继推出了人形机器人产品&#xff0c;机器人新物种持续衍生&#xff0c;人形机器人产业已经从萌芽概念阶段进入产业化落地前期。 近日&#x…

Golang面试题四(并发编程)

目录 1.Go常见的并发模型 2.哪些方法安全读写共享变量 3.如何排查数据竞争问题 ​4.Go有哪些同步原语 1. Mutex (互斥锁) 2. RWMutex (读写互斥锁) 3. Atomic 3.1.使用场景 3.2.整型操作 3.3.指针操作 3.4.使用示例 4. Channel 使用场景 使用示例 5. sync.WaitGr…

Java同城生鲜配送物流配送到店独立骑手端系统小程序源码

&#x1f69a;【一键解锁新鲜生活&#xff01;同城生鲜配送系统全揭秘】&#x1f966;&#x1f680; &#x1f50d; 源码揭秘&#xff1a;打造高效生鲜配送的秘密武器 &#x1f527; 想要在家就能享受超市般的生鲜盛宴吗&#xff1f;揭秘同款城生鲜配送系统的源码&#xff0c…

信号与线性系统实验一:LTI连续系统时域响应测试与分析

文章目录 一、实验目的二、实验内容与原理&#xff08;简单列了一下提纲&#xff09;第一部分&#xff1a;连续系统时域响应MATLAB仿真分析第二部分&#xff1a;连续系统时域响应Multisim电路仿真分析 三、实验器材四、实验步骤第一部分&#xff1a;连续系统时域响应MATLAB仿真…

vulnhub系列:sp eric

vulnhub系列&#xff1a;sp eric 靶机下载 一、信息收集 nmap扫描存活&#xff0c;根据mac地址寻找IP nmap 192.168.23.0/24nmap扫描端口&#xff0c;开放端口&#xff1a;22、80 nmap 192.168.23.189 -p- -A -sV -Pndirb 扫描目录&#xff0c;.git 源码&#xff0c;admin…

【python】PyQt5中单行文本输入控件QLineEdit的详细解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

使用Python打造简易Web服务器

目录 准备工作 创建Web服务器 示例代码 运行服务器 结论 在开发过程中&#xff0c;了解Web服务器的工作原理是非常有用的。Python作为一个功能强大的编程语言&#xff0c;提供了http.server模块&#xff0c;让我们能够快速地搭建一个简易的Web服务器。本文将指导你如何使用…

【微服务】Spring Cloud Alibaba 的介绍以及和主要功能

文章目录 引言主要功能1. **服务发现与注册**2. **分布式配置管理**3. **流量管理与熔断限流**4. **消息驱动**5. **分布式事务管理**6. **远程调用&#xff08;RPC&#xff09;**7. **服务网关**8. **对象存储**9. **全链路跟踪**10. **阿里巴巴中间件支持**11. **高可用与容错…

LInux - 一文了解 ssh端口敲门knock

文章目录 基本概念工作原理实操注意事项 基本概念 SSH端口敲门技术是一种网络安全措施&#xff0c;用于防止未经授权的访问。通过端口敲门&#xff0c;可以动态地在防火墙上打开指定端口&#xff08;如SSH端口&#xff09;&#xff0c;仅允许符合特定敲门序列的用户访问。此技…

算法:魔法字典

1️⃣要求&#xff1a; 设计一个使用单词列表进行初始化的数据结构&#xff0c;单词列表中的单词 互不相同 。 如果给出一个单词&#xff0c;请判定能否只将这个单词中一个字母换成另一个字母&#xff0c;使得所形成的新单词存在于你构建的字典中。 实现 MagicDictionary 类…

Spring中WebSocket的使用

文章目录 前言什么是 WebSocketWebSocket 协议和 HTTP 协议的区别WebSocket 原理解析WebSocket 报文格式 Spring 中 WebSocket 的使用前后端发送的数据的数据类型是对象该如何做使用websocket协议如何获取到HTTP协议中的HttpSession WebSocket使用的完整代码 前言 我们在使用 …

docker基本管理和应用

一、docker是什么&#xff1a; 1.docker是什么&#xff1a;一个开源的应用容器引擎&#xff0c;基于go语言开发的&#xff0c;docker运行在linux的容器化工具&#xff0c;可以理解为轻量级的一个虚拟机。可以在任何主机上轻松创建的一个轻量级、可移植的自给自足的容器&#x…

【Tor】使用Debian系统搭建obfs4 Bridge网桥

你好 我是无聊的木子。 目录 前言 写作の原因 网桥是个啥&#xff1f; 正文 - 到底咋搭建捏 搞台机子先 比较简便の方法 - 买台云服务器 首月五折 一元试用 远程连接服务器 更加复杂の办法 - 自己拿物理机做网桥 开始搭建网桥 先安装Tor 然后配置网桥 最后组合网桥…