openlayer实现webgis端绘制制图及编辑

在WebGIS端制图是指通过Web浏览器界面实现地理信息数据的可视化、编辑、分析以及地图产品的制作。这一过程通常涉及以下几个关键环节:

**1. 前端技术栈:

•HTML/CSS/JavaScript:作为Web开发的基础,用于构建用户界面布局、样式设计以及交互逻辑。

•Web地图库:

•Leaflet、OpenLayers、Mapbox GL JS等开源库,提供地图容器、图层管理、交互控件等功能,便于快速构建Web地图应用。

•GIS服务接口:

•Web Map Service (WMS):用于请求地图影像瓦片。

•Web Feature Service (WFS):用于获取矢量地理数据。

•Web Coverage Service (WCS):用于获取栅格数据。

•GeoJSON、TopoJSON、KML等数据格式,直接嵌入或通过API加载。

•地图样式与主题:

•Mapbox Studio、QGIS Cloud等在线工具,或使用JSON-based样式语言(如Mapbox Style Specification、OpenLayers Style Format)自定义地图样式。

**2. 数据准备与集成:

•数据源接入:

连接本地或远程GIS服务器、云存储(如AWS S3、Azure Blob Storage)、开放数据平台(如OpenStreetMap、ArcGIS Online)等,获取所需GIS数据。

•数据处理:

•对接地理编码服务(如Google Maps Geocoding API、Mapbox Geocoding API)进行地址解析或逆地理编码。

•使用客户端库(如Turf.js、Mapbox GL Geostats)进行空间分析、统计计算。

•缓存与优化:

•利用客户端缓存(如IndexedDB、localStorage)存储常用数据或结果,提高加载速度。

•使用矢量瓦片、切片金字塔技术优化大规模数据展示。

**3. 地图交互设计:

•基础交互:缩放、平移、旋转地图,开启/关闭图层,调整图层透明度等。

•高级交互:

•查询与标注:实现点击查询、范围选择、热点分析等功能,显示相关信息或动态标注。

•编辑与绘图:支持用户在地图上添加、修改、删除地理要素,如使用Leaflet.draw、OpenLayers Editing等插件。

•路由规划:集成路线规划服务(如OSRM、GraphHopper),提供驾车、步行、骑行路径规划。

•空间分析:在浏览器端进行简单分析操作,如缓冲区分析、叠加分析等。

**4. 地图定制与输出:

•地图样式定制:通过调整颜色、图标、文字样式等元素,创建符合项目主题的地图样式。

•地图打印与导出:

•实现Web页面打印预览,支持自定义打印范围、比例尺、布局等。

•提供地图截图、PDF导出功能,或集成地图打包服务(如Mapfish Print、GeoServer Print)。

•地图分享与嵌入:

•提供短链接、嵌入代码,方便用户将地图分享至社交媒体或嵌入到其他网站。

**5. 跨平台兼容与响应式设计:

•移动端适配:确保地图应用在不同尺寸的移动设备上具有良好用户体验,如使用触屏手势、自适应布局。

•多浏览器支持:测试在主流浏览器(Chrome、Firefox、Safari、Edge)上的兼容性。

**6. 性能监控与优化:

•性能指标跟踪:监控地图加载时间、内存占用、网络请求等指标,识别性能瓶颈。

•优化措施:

•压缩与合并静态资源,减少HTTP请求。

•使用Web Workers进行大数据处理,避免阻塞主线程。

•采用矢量瓦片、LOD(Level of Detail)策略,按需加载数据。通过上述技术手段和流程,WebGIS端制图实现了从数据获取、处理到地图展现、交互的全流程操作,让用户能够在Web浏览器环境中便捷地进行地图制作与分析,满足各种GIS应用场景的需求。

关键代码实现

组件化代码:

import Draw from 'ol/interaction/Draw'
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

import {unByKey} from 'ol/Observable.js';
import Overlay from 'ol/Overlay';
import {getArea, getLength} from 'ol/sphere.js';
import View from 'ol/View';
import {LineString, Polygon} from 'ol/geom.js';
import {Circle as CircleStyle, Fill, Stroke, Style} from 'ol/style.js';
import {generateUUID, getLayerByCode} from "@/components/iClientOpenLayers/MapCommon";

var DrawMap= /** @class */ (function () {
    function DrawMap(map, drawMapType,drawType,freeHand) {
        /**
         * Currently drawn feature.
         * @type {module:ol/Feature~Feature}
         */
        this.sketch=null;

        this.freeHand=freeHand;


        /**
         * The help tooltip element.
         * @type {Element}
         */
        this.helpTooltipElement=null;


        /**
         * Overlay to show the help messages.
         * @type {module:ol/Overlay}
         */
        this.helpTooltip=null;


        /**
         * The drawMap tooltip element.
         * @type {Element}
         */
        this.drawMapTooltipElement=null;


        /**
         * Overlay to show the drawMapment.
         * @type {module:ol/Overlay}
         */
        this.drawMapTooltip=null;


        /**
         * Message to show when the user is drawing a polygon.
         * @type {string}
         */
        this.continuePolygonMsg = '继续点击绘制多边形';


        /**
         * Message to show when the user is drawing a line.
         * @type {string}
         */
        this.continueLineMsg = '继续点击绘制线';
        this.map=map;
        this.drawMapType=drawMapType;
        this.draw=null;
        this.listener=null;
        this.source=null;
        // var layer ;
        // 获取存放feature的vectorlayer层。map初始化的时候可以添加好了
        for(let layerTmp of map.getLayers().getArray()){
            if(layerTmp.get("name")=="DrawMap"){
                this.source= layerTmp.getSource();
            }
        }
        if(this.source==undefined||this.source==null){
            this.source=getLayerByCode(this.map,"CRegion").getSource()
            // this.source = new VectorSource();

            // var vector = new VectorLayer({
            //     source: this.source,
            //     style: new Style({
            //         fill: new Fill({
            //             color: 'rgba(255, 255, 255, 0.2)',
            //         }),
            //         stroke: new Stroke({
            //             color: '#ffcc33',
            //             width: 2,
            //         }),
            //         image: new CircleStyle({
            //             radius: 7,
            //             fill: new Fill({
            //                 color: '#ffcc33',
            //             }),
            //         }),
            //     }),
            // });
            // vector.set("name","DrawMap");
            // vector.set("code","DrawMap");
            // this.map.addLayer(vector);
        }
        if(drawType=="DrawMap"){
            this.createDrawMapTooltip();
            this.createHelpTooltip();
            let that=this;
            this.pointerMoveHandler = function (evt) {
                if (evt.dragging) {
                    return;
                }
                /** @type {string} */
                var helpMsg = '请点击开始绘制';

                if (that.sketch) {
                    var geom = (that.sketch.getGeometry());
                    if (geom instanceof Polygon) {
                        helpMsg = that.continuePolygonMsg;
                    } else if (geom instanceof LineString) {
                        helpMsg = that.continueLineMsg;
                    }
                }

                that.helpTooltipElement.innerHTML = helpMsg;
                that.helpTooltip.setPosition(evt.coordinate);

                that.helpTooltipElement.classList.remove('hidden');
            };
            /**
             * Handle pointer move.
             * @param {module:ol/MapBrowserEvent~MapBrowserEvent} evt The event.
             */
            map.on('pointermove', this.pointerMoveHandler);

            map.getViewport().addEventListener('mouseout',() =>{
                this.helpTooltipElement.classList.add('hidden');
            });
            // 量测调用
            this.addInteraction();
        }else if(drawType=="Draw"){
            // 量测调用
            this.addInteractionEx();
        }

    };
    DrawMap.prototype. formatLength = function (line) {
        var length = getLength(line,{projection:'EPSG:4326'});
        var output;
        if (length > 100) {
            output = (Math.round(length / 1000 * 100) / 100) +
                ' ' + 'km';
        } else {
            output = (Math.round(length * 100) / 100) +
                ' ' + 'm';
        }
        return output;
    };
    DrawMap.prototype. formatArea = function (polygon) {
        var area = getArea(polygon,{projection:'EPSG:4326'});
        var output;
        if (area > 10000) {
            output = (Math.round(area / 1000000 * 100) / 100) +
                ' ' + 'km<sup>2</sup>';
        } else {
            output = (Math.round(area * 100) / 100) +
                ' ' + 'm<sup>2</sup>';
        }
        return output;
    };
    DrawMap.prototype.addInteraction=function() {
        var type = (this.drawMapType == 'area' ? 'Polygon' : 'LineString');
        this.draw = new Draw({
            ol_uid:'draw',
            source: this.source,
            type: type,
            snapTolerance:20,
            freehand: this.freeHand,
            style: new Style({
                fill: new Fill({
                    color: 'rgba(255, 255, 255, 0.2)'
                }),
                stroke: new Stroke({
                    color: 'rgba(0, 0, 0, 0.5)',
                    lineDash: [10, 10],
                    width: 2
                }),
                image: new CircleStyle({
                    radius: 5,
                    stroke: new Stroke({
                        color: 'rgba(0, 0, 0, 0.7)'
                    }),
                    fill: new Fill({
                        color: 'rgba(255, 255, 255, 0.2)'
                    })
                })
            })
        });
        this.map.addInteraction(this.draw);


        this.draw.on('drawstart',
            (evt)=> {
                // set sketch
                this.sketch = evt.feature;

                /** @type {module:ol/coordinate~Coordinate|undefined} */
                var tooltipCoord = evt.coordinate;

                this.listener = this.sketch.getGeometry().on('change', (evt)=> {
                    var geom = evt.target;
                    var output;
                    if (geom instanceof Polygon) {
                        output = this.formatArea(geom);
                        tooltipCoord = geom.getInteriorPoint().getCoordinates();
                    } else if (geom instanceof LineString) {
                        output = this.formatLength(geom);
                        tooltipCoord = geom.getLastCoordinate();
                    }
                    this.drawMapTooltipElement.innerHTML = output;
                    this.drawMapTooltip.setPosition(tooltipCoord);
                });
            }, this);

        this.draw.on('drawend',
            (e)=> {
                this.drawMapTooltipElement.className = 'ol-tooltip ol-tooltip-static';
                this.drawMapTooltip.setOffset([0, -7]);
                let cFeature = e.feature;
                cFeature.values_["ID"]=generateUUID()
                // unset sketch
                this.clearDraw();
            }, this);
    };

    DrawMap.prototype.addInteractionEx=function(){
        var type = (this.drawMapType == 'area' ? 'Polygon' : 'LineString');
        if(this.drawMapType=="Point"){
            type=this.drawMapType;
        }
        this.draw = new Draw({
            source: this.source,
            type: type,
            freehand: this.freeHand,
            snapTolerance:20,
        });
        this.draw.on('drawend',
            (e)=> {
                const geometry = e.feature.getGeometry()
                const corrdinates = geometry.getCoordinates()
                let cFeature = e.feature;
                cFeature.values_["ID"]=generateUUID()
                // unset sketch
                this.clearDraw();
            }, this);
        this.map.addInteraction(this.draw);
    };

    DrawMap.prototype.createDrawMapTooltip=function() {
        if (this.drawMapTooltipElement) {
            this.drawMapTooltipElement.parentNode.removeChild(this.drawMapTooltipElement);
        }
        this.drawMapTooltipElement = document.createElement('div');
        this.drawMapTooltipElement.className = 'ol-tooltip ol-tooltip-drawMap';
        this.drawMapTooltip = new Overlay({
            element: this.drawMapTooltipElement,
            offset: [0, -15],
            positioning: 'bottom-center'
        });
        this.drawMapTooltip.set("name","DrawMap");
        debugger
        this.drawMapTooltip.getElement().style.display = ''
        this.map.addOverlay(this.drawMapTooltip);
    };
    DrawMap.prototype.createHelpTooltip=function () {
        if (this.helpTooltipElement) {
            this.helpTooltipElement.parentNode.removeChild(this.helpTooltipElement);
        }
        this.helpTooltipElement = document.createElement('div');
        this.helpTooltipElement.className = 'ol-tooltip hidden';
        this.helpTooltip = new Overlay({
            element: this.helpTooltipElement,
            offset: [15, 0],
            positioning: 'center-left'
        });
        this.map.addOverlay(this.helpTooltip);
    };

    DrawMap.prototype.clearDraw=function () {
        debugger
        this.sketch = null;
        // unset tooltip so that a new one can be created
        this.drawMapTooltipElement = null;
        // this.createDrawMapTooltip();
        if(this.listener!=undefined&&this.listener!=null){
            unByKey(this.listener);
        }
        try{
            this.map.un('pointermove', this.pointerMoveHandler);
        }
        catch (e){

        }
        if(this.draw!=undefined&&this.draw!=null){
            for(let i = 0; i < this.map.interactions.array_.length; i++){
                if(this.draw.ol_uid == this.map.interactions.array_[i].ol_uid){
                    this.map.removeInteraction(this.map.interactions.array_[i]);break
                }
            }
        }
        if(this.helpTooltipElement!=undefined&&this.helpTooltipElement!=null){
            this.helpTooltipElement.classList.add('hidden');
        }
        if(this.helpTooltip!=undefined&&this.helpTooltip!=null){
            this.map.removeOverlay(this.helpTooltip);
        }

    };
    return DrawMap;
}());

export {DrawMap};

调用代码:

//绘制制图切换
drawMapSwitch(pIndex){
  if(this.curDraw!=null){
    this.curDraw.clearDraw();
    this.curDraw=null;
  }
  if(pIndex==0){
    this.curDraw=new DrawMap(this.sMap, "LineString","Draw",false);
  }else if(pIndex==1){
    this.curDraw=new DrawMap(this.sMap, "area","Draw",false);
  }else if(pIndex==2){
    this.curDraw=new DrawMap(this.sMap, "Point","Draw",false);
  }else if(pIndex==3){
    this.curDraw=new DrawMap(this.sMap, "LineString","Draw",true);
  }else if(pIndex==4){
    this.curDraw=new DrawMap(this.sMap, "area","Draw",true);
  }else if(pIndex==5){
    for(let layerTmp of this.sMap.getLayers().getArray()){
      if(layerTmp.get("code")=="CRegion"){
        layerTmp.getSource().clear();
        break;
      }
    }
    for(let i=0;i<this.sMap.getOverlays().getArray().length;i++){
      if(this.sMap.getOverlays().getArray()[i].get("code")=="CRegion"){
        this.sMap.removeOverlay(this.sMap.getOverlays().getArray()[i]);
        i--;
      }
    }
  }else if(pIndex==6){
    let geojson=getGeojsonByLayerCode(this.sMap,"CRegion")
    alert(geojson)
  }

}

前端代码设计

<div class="operate map_huizhi">
  <i class="icon huizhi"></i>
  <ul class="map-sub-nav">
    <li v-for="(item,index) in drawMapData" @click="drawMapSwitch(index)">{{item}}</li>
  </ul>
</div>
.huizhi{
  width: 38px;
  height: 38px;
  background: url('./img/huizhi.png') no-repeat center center;
  background-image: -webkit-image-set(url('./img/huizhi.png') 1x, url("./img/huizhi@2x.png") 2x);
  background-image: image-set(url('./img/huizhi.png') 1x, url("./img/huizhi@2x.png") 2x);
  background-repeat: no-repeat;
  background-position: center center;
}

软件实现效果:

最后分享下地图下载器下载地址

通过百度网盘分享的文件:V-2.0jbr…
链接:https://pan.baidu.com/s/1AiFKTTknkEHkJ7t4nQ2P1g 
提取码:8664
复制这段内容打开「百度网盘APP 即可获取」

如果对您有所帮助,请点赞打赏支持!

技术合作交流qq:2401315930

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

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

相关文章

Go —— channel (二)

一个空的 channel 会产生哪些问题 读写nil管道均会阻塞触发死锁。关闭的管道仍然可以读取数据&#xff0c;向关闭的管道写数据会触发panic。 问&#xff1a;如果有多个协程同时读取一个channel&#xff0c;channel会如何选择消费者 channel 会按照维护的 recvq 等待读消息的…

vue canvas绘制信令图,动态显示标题、宽度、高度

需求: 1、 根据后端返回的数据&#xff0c;动态绘制出信令图 2、根据 dataStatus 返回值&#xff1a; 0 和 1&#xff0c; 判断 文字内容的颜色&#xff0c;0&#xff1a;#000&#xff0c;1&#xff1a;red 3.、根据 lineType 返回值&#xff1a; 0 和 1&#xff0c; 判断 箭…

栈的详解和例题(力扣有效括号)

感谢各位大佬的光临&#xff0c;希望和大家一起进步&#xff0c;望得到你的三连&#xff0c;互三支持&#xff0c;一起进步 个人主页&#xff1a;LaNzikinh-CSDN博客 收入专栏:初阶数据结构_LaNzikinh篮子的博客-CSDN博客 文章目录 前言一.什么是栈二.栈的实现三.例题&#xff…

推荐系统(唐宇迪)含具体代码

一、推荐系统介绍 用户冷启动 1.1 经典流程 1.2 涉及的技术点 二、协同过滤与矩阵分解 2.1 基于物品流行度&#xff08;排行榜榜单&#xff09;的推荐算法 class popularity_recommender_py():def __init__(self):self.train_data Noneself.user_id Noneself.item_id None…

Java每日一题(三道同一类型的题)

前言 本文一共有三道题:1.两数之和 2.三数之和 3. 四数之和 为什么把这三道题放一起呢&#xff0c;因为三数之和是可以根据两数之和进行推导&#xff0c;四数之和可以根据三数之和进行推导。 两数之和 思路分析: 我的思路: 1.排序 2.使用左右指针 3.处理细节问题 先让数组…

人工智能——深度学习

4. 深度学习 4.1. 概念 深度学习是一种机器学习的分支&#xff0c;旨在通过构建和训练多层神经网络模型来实现数据的高级特征表达和复杂模式识别。与传统机器学习算法相比&#xff0c;深度学习具有以下特点&#xff1a; 多层表示学习&#xff1a;深度学习使用深层神经网络&a…

Java后端常见场景业务问题

目录 单点登录如何实现权限认证如何实现上传数据的安全性如何保证订单表每天新增500W数据,分库分表的方案应该如何设计?订单表每天新增500W数据,分库分表的方案应该如何设计?*********************项目日志如何采集已经上线的bug如何排查如何快速定位系统瓶颈单点登录如何实…

Golang使用PGO优化程序性能

文章目录 参考文章PGO是什么使用PGO的好处PGO做了什么热函数内联什么是内联内联的好处Go默认的内联策略PGO的热函数内联 去虚拟化调用指令高速缓存 PGO有什么缺点可执行程序变大构建时间变长 PGO怎么使用典型的工作流程收集CPU配置文件生产环境启动PGO代码改动重新生成CPU配置文…

基于Whisper语音识别的实时视频字幕生成 (一): 流式显示视频帧和音频帧

Whishow Whistream&#xff08;微流&#xff09;是基于Whisper语音识别的的在线字幕生成工具&#xff0c;支持rtsp/rtmp/mp4等视频流在线语音识别 1. whishow介绍 whishow&#xff08;微秀&#xff09;是在线音视频流播放python实现&#xff0c;支持rtsp/rtmp/mp4等输入&…

人工智能——大语言模型

5. 大语言模型 5.1. 语言模型历史 20世纪90年代以前的语言模型都是基于语法分析这种方法&#xff0c;效果一直不佳。到了20世纪90年代&#xff0c;采用统计学方法分析语言&#xff0c;取得了重大进展。但是在庞大而复杂的语言信息上&#xff0c;基于传统统计的因为计算量巨大…

【Docker】Docker概述及引擎

一、docker概述 DevOps DevOps是一种执行标准&#xff08;思想&#xff09;&#xff0c;主要用于促进开发、测试与运维的整合 容器与虚拟机的区别 最大的区别是&#xff0c;虚拟机中存在独立的硬件系统与操作系统&#xff0c;容器中全部是共享的宿主机中的操作系统与硬件系…

[dvwa] sql injection(Blind)

blind 0x01 low 1’ and length(version()) 6 # syntax: substr(string , from<start from 1>, cut length) 1’ and substr(version(),1,1) ‘5’ # 1’ and substr(version(),2,1) ‘.’ # 1’ and substr(version(),3,1) ‘7’ # 1’ and substr(version(),4,…

酷写写靠谱不 #知识分享#媒体

酷写写是一个值得推荐的论文写作工具&#xff0c;它不仅靠谱而且非常好用。在如今这个信息爆炸的时代&#xff0c;学术界对于论文的要求越来越严格&#xff0c;论文必须具有独创性和高质量才能获得认可。而酷写写的出现&#xff0c;为广大学生和学者提供了一个便捷、高效的写作…

SuperMap三维复杂模型建模之3D极坐标建模——原理篇

作者&#xff1a;超图研究院技术支持中心-于丁 随着SuperMap iDesktop 10i(2021) V10.2.1的上线发布&#xff0c;为进一步拓展全空间数据模型及其分析计算能力&#xff0c;一个新功能“3D极坐标建模”也随着该版本悄然上线。 3D极坐标建模功能实现根据UV参数和数学表达式&…

【Python系列】Jupyter Notebook 中执行 Shell 脚本的方法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【随笔】Git 高级篇 -- 项目里程碑 git tag(二十)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

绝地求生:杜卡迪系列活动集合 各种活动送不停

今天更新已结束&#xff0c;速度上好开冲&#xff01; 春季签到活动&#xff08;第1轮&#xff09; 活动时间 4月9日 - 4月22日 12&#xff1a;00 任务要求 每日登录游戏&#xff08;每日上午10点刷新&#xff09; 活动期间全勤可获得奖励如下 杜卡迪物资箱 (x1) 杜卡迪活…

【C++杂货铺】详解 stack 和 queue

&#x1f308;前言&#x1f308; 欢迎收看本期【C杂货铺】&#xff0c;本期内容将讲解CSTL中stack和queue的内容&#xff0c;其中包含了stack &#xff0c; queue&#xff0c;priority_queue是什么&#xff0c;怎么使用以及模拟实现这些容器。 此外&#xff0c;还将将讲解设计模…

【迅为iMX6Q】开发板 Linux version 6.6.3 SD卡 启动

开发环境 win10 64位 VMware Workstation Pro 16 ubuntu 20.04 【迅为imx6q】开发板&#xff0c; 2G DDR RAM linux-imx 下载 使用 NXP 官方提供的 linux-imx&#xff0c;代码地址为&#xff1a; https://github.com/nxp-imx/linux-imx 使用 git 下载 linux-imx&#xff…