在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 sketchthis.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 sketchthis.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 sketchthis.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");debuggerthis.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 () {debuggerthis.sketch = null;// unset tooltip so that a new one can be createdthis.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