当前位置: 首页 > news >正文

openlayer的基本使用(区域绘制、点线绘制、手动绘制轨迹)

实现如图所示效果:

 html部分

<div style="height: 100vh;width: 100vw"><el-dropdown split-button size="mini" :disabled="isDelete" style="margin-right: 10px" @click="clickDraw">{{isDraw ? '结束绘制' : '开始绘制'}}{{drawTypeText}}<template #dropdown><el-dropdown-menu><el-dropdown-item @click.native="changeDrawType('plane')">飞机</el-dropdown-item><el-dropdown-item @click.native="changeDrawType('ship')">舰船</el-dropdown-item></el-dropdown-menu></template></el-dropdown><el-button :disabled="!isDraw" size="mini" @click="clearDraw">清除绘制</el-button><el-button size="mini" :disabled="isDraw" @click="deleteDraw">{{isDelete ? '确认删除' : '删除轨迹'}}</el-button><!-- 地图容器 --><div id="map" class="map"></div><!-- 地图需要展示的div内容 --><div style="display: none"><div id="overPlay"><div class="overPlayText" v-if="hoverPointInfo.type == 'plane'">名称:飞燕一号</div><div class="overPlayText" v-if="hoverPointInfo.type == 'ship'">名称:泰坦尼克号</div><div class="overPlayText" v-if="hoverPointInfo.type == 'plane'">飞行速度:2.25马赫(2400公里/小时)</div><div class="overPlayText" v-if="hoverPointInfo.type == 'ship'">航速:40节</div><div class="overPlayText" v-if="hoverPointInfo.type == 'event'">在这拐了个弯</div></div></div>
</div>

 需求需要的数据如下:

data(){return {map: null,areaLayer: null,  //区域pointLayer: null, //点trailLayer: null,  //轨迹pointInfo: {},   //鼠标点击点信息hoverPointInfo: {},  //鼠标移入点信息drawLayer: null,   //绘图的轨迹pointTempLayer: null,  //绘制轨迹时添加的临时点isDraw: false,  //是否正在绘制isDelete: false, //是否在删除clickPoints: [],  //绘制时暂存的点tempLine: null,  //临时边tempPoint: null,  //临时点drawType: '',    //地图绘制类型}
},
computed: {drawTypeText(){let text = ''let map = {plane: '飞机',ship: '船舰',}if(this.drawType){text = map[this.drawType]}return (text ? ('(' + text + ')') : '')}
},
绘制地图
initMap(){this.map = nullthis.layer = nullthis.pointLayer = nullthis.trailLayer = null// 图层this.layer = new TileLayer({source: new XYZ({visible: true,url: 'http://webrd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=2&scale=1&style=8',wrapX: true,}),})//区域this.areaLayer = new Vector({source: new VectorSource(),})//点this.pointLayer = new Vector({source: new VectorSource(),})//轨迹this.trailLayer = new Vector({source: new VectorSource(),})//临时点this.pointTempLayer = new Vector({source: new VectorSource(),})// 初始化地图到指定DOM元素this.map = new Map({layers: [this.layer, this.trailLayer, this.areaLayer,  this.pointLayer, this.pointTempLayer],target: "map",view: new View({projection: 'EPSG:4326',center: [135.403218, 30.92372],zoom: 4,maxZoom: 11,constrainResolution: true,  // 设置缩放级别为整数smoothResolutionConstraint: false,  // 关闭无级缩放地图}),});//鼠标点击点图层,获取该点的数据let selectInteraction = new Select({layers: [this.pointLayer],});this.map.addInteraction(selectInteraction)selectInteraction.on('select', e => {const selectedFeature = (e.selected || [])[0];if(selectedFeature){this.pointInfo = selectedFeature.getProperties()console.log(this.pointInfo)}})//鼠标移入显示id为overPlay的divlet hoverFeature = nullthis.map.on('pointermove',(e) => {let feature = this.map.forEachFeatureAtPixel(e.pixel, (feature, layer) => {return feature},{hitTolerance: 5})//有feature且feature变化才执行if(feature != hoverFeature){hoverFeature = featureif(feature && feature.getGeometry().getType() == 'Point'){this.map.getTargetElement().style.cursor = "pointer";this.hoverPointInfo = feature.getProperties()this.addOverlay(this.hoverPointInfo.coords,'overPlay')}else{this.map.getTargetElement().style.cursor = "";this.hoverPointInfo = {}this.removeOverlays()}}})},
地图上加区域
//地图上加区域
addArea(data){let feature = new Feature({geometry: new Polygon(data),})feature.setStyle(mapStyle.redAreaStyle)this.areaLayer.getSource().addFeature(feature)
},
 地图上加点
//地图上加点
addPoint(type, data){if(type == 'plane'){let point = new Point(data.coords)let pointFeature = new Feature({geometry: point,...data})pointFeature.setStyle(mapStyle.pointRedPlane)this.pointLayer.getSource().addFeature(pointFeature)}if(type == 'ship'){let point = new Point(data.coords)let pointFeature = new Feature({geometry: point,...data})pointFeature.setStyle(mapStyle.pointRedShip)this.pointLayer.getSource().addFeature(pointFeature)}if(type == 'red'){let point = new Point(data.coords)let pointFeature = new Feature({geometry: point,...data})pointFeature.setStyle(mapStyle.pointRed)this.pointLayer.getSource().addFeature(pointFeature)}},
地图上加轨迹
//地图上加轨迹
addTrail(type,data){data.forEach(e => {let feature = new Feature({geometry: new LineString(e),})feature.setStyle(mapStyle.redLineArrow(feature))this.trailLayer.getSource().addFeature(feature)})
},
 地图上加div

        删除overlay后,再次调用addOverlay方法新增overlay不显示,所以鼠标移除时隐藏overlay。调用addOverlay方法后会创建dom,避免出现过多无用dom情况,下次新增时只改变overlay的位置。

//地图上加div
addOverlay(data,id){if(!this.map.getOverlayById(id)){let marker = new Overlay({id,position: data,element: document.getElementById(id),offset: [10, 20]});this.map.addOverlay(marker);marker.setPositioning("top-left");} else{let marker = this.map.getOverlayById(id)marker.setPosition(data)}
},
地图上删除div
//地图上删除div
removeOverlays() {let overlays = this.map.getOverlays();for (let i = 0, len = overlays.getLength(); i < len; i++) {overlays.item(i).setPosition(undefined)}
},
手动绘制轨迹

        点击开始绘制按钮后为地图新增点击事件,用户需要在地图上点击地图生成临时点,当临时点数量大于等于2时,临时点连接生成临时边,当点击结束绘制按钮后,关闭该点击事件,临时点和临时线转化为真实点和真实线。

//修改绘制类型
changeDrawType(type){this.drawType = type
},
//开始绘制地图
clickDraw(){if(this.isDraw){this.endDraw()}else{if (!this.drawType) {this.$message.warning('请选择绘制类型')return}this.drawTrail()}
},
//进入开始手动绘制状态
drawTrail(){if(!this.isDraw){this.isDraw = truethis.clickPoints = []this.map.on('click', this.handleMapClick)}
},
//结束手动绘制状态
endDraw(){if(this.isDraw){this.isDraw = falsethis.map.un('click', this.handleMapClick)//唯一标识,便于统一管理let groupId = 'point-' + Date.now()//临时点改为真实点if(this.clickPoints){this.pointTempLayer.getSource().clear()this.tempPoint = nullthis.clickPoints.forEach((e, index) => {if(index == 0 || index == (this.clickPoints.length - 1)){this.addPoint(this.drawType, {type: this.drawType,coords: e,groupId})}})}//临时线改为真实线if(this.clickPoints.length >= 2){let feature = new Feature({geometry: new LineString(this.clickPoints),groupId})feature.setStyle(mapStyle.redLineArrow(feature))this.trailLayer.getSource().addFeature(feature)if(this.tempLine){this.trailLayer.getSource().removeFeature(this.tempLine)this.tempLine = null}this.clickPoints = []}}
},
//绘制的点击事件
handleMapClick(e){if(!this.isDraw) return;const coord = e.coordinatethis.clickPoints.push(coord)if(this.tempLine){this.trailLayer.getSource().removeFeature(this.tempLine)}if(this.clickPoints.length >= 2){this.tempLine = new Feature({geometry: new LineString(this.clickPoints),})this.tempLine.setStyle(mapStyle.tempLineArrow(this.tempLine))this.trailLayer.getSource().addFeature(this.tempLine)}if(coord){this.tempPoint = new Feature({geometry: new Point(coord)})this.tempPoint.setStyle(mapStyle.positionPointTemp)this.pointTempLayer.getSource().addFeature(this.tempPoint)}}
清除绘制

        清除临时点和临时线

//清除绘制
clearDraw(){this.pointTempLayer.getSource().clear()this.tempPoint = nullif(this.tempLine){this.trailLayer.getSource().removeFeature(this.tempLine)this.tempLine = null}this.clickPoints = []
},
删除绘制内容

        临时点和临时线转为真实点和真实线时,为其加上groupId属性表示该轨迹为手绘轨迹,仅有手绘轨迹可删除。该删除为删除掉有groupId的真实点和真实线。

//删除轨迹
deleteDraw(){this.isDelete = !this.isDeleteif(this.isDelete){this.map.on('click',this.handleMapDelete)}else{this.map.un('click',this.handleMapDelete)}
},
handleMapDelete(e){let feature = this.map.forEachFeatureAtPixel(e.pixel, (feature, layer) => {return feature},{hitTolerance: 5})if(!feature.get('groupId')){this.$message.warning('该轨迹非手绘轨迹,不可删除')return}const pointFeatures = this.pointLayer.getSource().getFeatures()pointFeatures.forEach(f => {if(f.get('groupId') == feature.get('groupId')){this.pointLayer.getSource().removeFeature(f)}})const lineFeatures = this.trailLayer.getSource().getFeatures()lineFeatures.forEach(f => {if(f.get('groupId') == feature.get('groupId')){this.trailLayer.getSource().removeFeature(f)}})
},
样式
import Fill from "ol/style/fill";
import Stroke from "ol/style/stroke";
import Style from "ol/style/style";
import Icon from "ol/style/icon";
import Circle from "ol/style/circle";
import Point from "ol/geom/point";//红色多边形样式
function redAreaStyle(){let fillColor = new Fill({color: 'rgba(255, 0, 0, 0.2)'})let stroke = new Stroke({color: 'red',width: 1,})return new Style({stroke,fillColor})
}//红色船
function pointRedPlane(){return new Style({image: new Icon({src: require('../img/redPlane.svg'),scale: 0.2,  //缩放比例})})
}
//红色飞机
function pointRedShip(){return new Style({image: new Icon({src: require('../img/redShip.svg'),scale: 0.2,  //缩放比例})})
}
//红色点
function pointRed(){return new Style({image: new Circle({radius: 5,fill: new Fill({color: 'red'})})})
}//红色轨迹线
function redLineArrow(feature) {let geometry = feature.getGeometry();let styles = [new Style({stroke: new Stroke({color: '#d71106',width: 2,lineDash: [6,5]})})];geometry.forEachSegment(function (start, end) {let dx = end[0] - start[0];let dy = end[1] - start[1];let rotation = Math.atan2(dy, dx);const kx = (end[0] + start[0]) / 2const ky = (end[1] + start[1]) / 2console.log(kx,ky)//arrowsstyles.push(new Style({geometry: new Point([kx, ky]),image: new Icon({src: require('../img/arrow_red.png'),anchor: [0.75, 0.5],rotateWithView: false,rotation: -rotation})}));});return styles
}//临时箭头
function tempLineArrow(feature) {let geometry = feature.getGeometry();let styles = [new Style({stroke: new Stroke({color: '#ffcc33',width: 2,lineDash: [6,5]})})];geometry.forEachSegment(function (start, end) {let dx = end[0] - start[0];let dy = end[1] - start[1];let rotation = Math.atan2(dy, dx);const kx = (end[0] + start[0]) / 2const ky = (end[1] + start[1]) / 2//arrowsstyles.push(new Style({geometry: new Point([kx, ky]),image: new Icon({src: require('../img/arrow.png'),anchor: [0.75, 0.5],rotateWithView: false,rotation: -rotation})}));});return styles;
}
//临时点
function positionPointTemp(){return new Style({image: new Circle({radius:5,fill:new Fill({color: '#ffcc33'})}),});
}let mapStyle = {redAreaStyle,pointRedPlane,pointRedShip,pointRed,redLineArrow,positionPointTemp,tempLineArrow,
}
export default mapStyle

项目地址

相关文章:

  • 【LaTeX】Misplaced alignment tab character . ^^I
  • 如何下载免费地图数据?
  • GKI 介绍
  • C++算法(9):数组作为函数参数,注意事项与实践
  • 【C++算法】61.字符串_最长公共前缀
  • 利用 Python 和 AI 技术创作独特的图像艺术作品
  • Flutter 与原生通信
  • SAP系统交货已完成标识
  • Redis(一) - Redis安装教程(Windows + Linux)
  • 数据结构与算法入门 Day 0:程序世界的基石与密码
  • 前端ES6基本语法,以及前端项目模板vue-admin-template和后端进行对接(跨域问题的解决)
  • 如何解除Excel只读状态?4种方法全解析
  • 人工智能——梯度提升决策树算法
  • Mitmproxy 11 发布 —— 完整支持 HTTP/3!
  • 特性(Attribute)
  • 大模型Benchmark评估体系解析
  • 网络威胁情报 | 威胁情报工具
  • 朋克编码以潮玩语言讲述中国文化|益民艺术馆展演东方潮力
  • GIS开发笔记(6)结合osg及osgEarth实现半球形区域绘制
  • 数据库10(代码相关语句)
  • 杭州网站建设/微商推广哪家好
  • 贵州省住房和城乡建设厅查询网站/广州谷歌优化
  • 怎么做淘课网站/营口建网站的公司
  • 3d动画制作收费标准/seo网站系统
  • html视频网站模板/万网域名续费
  • 问佛教网站大师做早课烧香烛可以吗/公司产品推广文案