本文主要是介绍Vue2 + Openlayers 实现绘制、平移和框选平移功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- Vue2 + Openlayers 实现绘制、平移和框选平移功能
- Vue2安装
- 安装Openlayers
- 最新版本Openlayers安装
- 指定版本Openlayers安装
- 其他方式安装可以参照Openlayers官网
- 初始化地图
- 绘制方法的实现
- 平移功能(拖拽功能)的实现
- 框选平移功能的实现
- 框选平移详细介绍
- 绘制两个图形
- 清空功能的实现
- 注意事项
- 项目源码
Vue2 + Openlayers 实现绘制、平移和框选平移功能
Vue2安装
本文不详细介绍Vue2的安装,具体可以参考这篇博客
Vue2安装
安装Openlayers
Openlayers有多种引用或安装方式,博主采用的是npm安装方式。
最新版本Openlayers安装
npm install -s ol
指定版本Openlayers安装
运行npm install -s ol后,找到package.json中的ol,将后面的版本号改成想要的版本,再运行npm install即可
本文采用的是5.3.3版本
其他方式安装可以参照Openlayers官网
Openlayers官网
初始化地图
使用Openlayers例子中的OSM地图。
Openlayers地图加载可以有很多参数,具体请看Openlayers官方API
博主使用的版本是5.3.3,但是官方文档看5.3.0的就可以
<script>//引入
import Map from "ol/Map"
import {Tile as TileLayer} from "ol/layer";
import OSM from 'ol/source/OSM';
import View from "ol/View"
import {fromLonLat} from "ol/proj";export default {name: "Map",data(){return {// 根据个人需求可以选择把数据不定义成全局的,但是有些功能需要全局变量,请读者自行斟酌map:{}, //地图容器,后续可能会涉及到map的相关操作,比如map.addLayer等,所以定义成全局的drawSource:new Vector(), //绘制图层的数据源,后续某些功能可能会需要清空drawSource,所以定义成全局的//绘制功能初始化的地方,因为可能会需要用map.addInteraction()和map.removeInteraction(),所以定义成全局的draw :{} }},methods:{//地图初始化方法initialMap(){//用that代替this,防止某些位置this指向发生变化let that = thisthat.map = new Map({target:"map", //挂载到id为map的div容器上layers:[new TileLayer({source: new OSM() //OSM地图}),//绘制图层new VectorLayer({source:that.drawSource, //数据源style: new Style({//图层样式fill: new Fill({color: "rgba(0, 0, 255, 0.2)", //填充颜色}),stroke: new Stroke({color: "#0000ff", //边框颜色width: 2, // 边框宽度}),image: new Circle({radius: 7,fill: new Fill({color: "#0000ff",}),}),}),})],//设置视图,包括中心点,坐标系,默认缩放级别,最大、最小缩放级别view: new View({projection:'EPSG:3857', //坐标系center: fromLonLat([120.2,30.35]), //中心点zoom: 10, //默认缩放级别minZoom:1, //最小缩放级别maxZoom:18 //最大缩放级别})})console.log(that.map.getLayers())},},mounted() {this.initialMap() //立即执行初始化地图方法}
}
</script>
绘制方法的实现
<script>//引入
import Map from "ol/Map"
import {Tile as TileLayer, Vector as VectorLayer} from "ol/layer";
import OSM from 'ol/source/OSM';
import View from "ol/View"
import {fromLonLat} from "ol/proj";
import {DoubleClickZoom, Draw} from "ol/interaction";
import {Fill, Stroke, Style,Circle} from "ol/style";
import {Vector} from "ol/source"export default {name: "Map",data(){return {map:{}, //地图容器,后续可能会涉及到map的相关操作,比如map.addLayer等,所以定义成全局的drawSource:new Vector(), //正常项目可能需要在其他函数中清空drawSource,所以定义成全局的drawVector:{}, //平移功能需要声明哪些图层可以被平移,所以定义成全局的draw :{}, //绘制功能,可能会在其他函数中使用this.map.removeInteraction(this.draw),所以定义成全局}},methods:{//地图初始化方法initialMap(){//用that代替this,防止某些位置this指向发生变化let that = thisthat.map = new Map({target:"map", //挂载到id为map的div容器上layers:[new TileLayer({source: new OSM() //OSM地图}),that.drawVector = new VectorLayer({source:that.drawSource,style: new Style({//图层样式fill: new Fill({color: "rgba(0, 0, 255, 0.2)", //填充颜色}),stroke: new Stroke({color: "#0000ff", //边框颜色width: 2, // 边框宽度}),image: new Circle({radius: 7,fill: new Fill({color: "#0000ff",}),}),}),})],//设置视图,包括中心点,坐标系,默认缩放级别,最大、最小缩放级别view: new View({projection:'EPSG:3857', //坐标系center: fromLonLat([120.2,30.35]), //中心点zoom: 10, //默认缩放级别minZoom:1, //最小缩放级别maxZoom:18 //最大缩放级别})})console.log(that.map.getLayers())},//绘制方法sketch() {let that = this;//移除双击缩放功能,使双击只用于关闭编辑状态const dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction);//双击执行取消绘制that.map.on("dblclick", function () {that.MyDraw.setActive(false);});//初始化绘制交互that.draw = new Draw({//绘制对象source: that.drawSource, //绘制层数据源,勾绘的要素属于的数据集type: "Polygon", //绘制的类型,这里绘制一个多边形,也可以是POINT(点)、LINE_STRING(线)、CIRCLE(圆)//设置一些样式style: new Style({fill: new Fill({color: "rgba(0,0,255,0.2)",}),stroke: new Stroke({color: "#0000ff",width: 2,}),image: new Circle({radius: 7,fill: new Fill({color: "#0000ff",}),}),}),});// 加载交互绘制控件函数that.MyDraw = {//执行绘制函数的方法init: function () {that.map.addInteraction(that.draw); //添加交互//绑定交互绘制工具开始绘制的事件that.draw.on("drawstart", function (evt) {//逻辑代码});//绑定交互绘制工具结束绘制的事件that.draw.on("drawend", function (evt) {//逻辑代码that.MyDraw.setActive(false); //绘制完毕以后关闭控件})},//控制控件开启或关闭的函数,active要传boolean类型/** setActive()是Openlayers中Interaction的函数,作用是开启和关闭控件* 这里也可以不用setActive()函数,可以使用this.map.addInteraction()加载控件和this.map.removeInteraction()* 在绘制结束的时候移除控件。如果使用这种方法,就需要把map定义成全局的。*/setActive: function (active) {that.draw.setActive(active); //激活控件},};that.MyDraw.init(); //执行绘制函数方法}},mounted() {this.initialMap() //立即执行初始化地图方法}
}
</script>
上面的函数也可以写成另一种形式,效果都是一样的
sketch2(){let that = this;//移除双击缩放功能,使双击只用于关闭编辑状态const dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction);//双击执行取消绘制that.map.on("dblclick", function () {that.map.removeInteraction(that.draw)});//初始化绘制交互that.draw = new Draw({//绘制对象source: that.drawSource, //绘制层数据源,勾绘的要素属于的数据集type: "Polygon", //绘制的类型,这里绘制一个多边形,也可以是POINT(点)、LINE_STRING(线)、CIRCLE(圆)//设置一些样式style: new Style({fill: new Fill({color: "rgba(0,0,255,0.2)",}),stroke: new Stroke({color: "#0000ff",width: 2,}),image: new Circle({radius: 7,fill: new Fill({color: "#0000ff",}),}),}),});// 加载交互绘制控件函数(function initDraw() {that.map.addInteraction(that.draw); //添加交互//绑定交互绘制工具开始绘制的事件that.draw.on("drawstart", function (evt) {//逻辑代码});//绑定交互绘制工具结束绘制的事件that.draw.on("drawend", function (evt) {//逻辑代码})})()}
效果展示
平移功能(拖拽功能)的实现
平移功能使用ol-ext实现
博主使用的版本是3.2.3,下面的方式是安装最新版的ol-ext,也可以使用开篇提到的方式更改成指定版本
npm install ol-ext
//平移功能(拖拽功能)translation(){let that = thisconst dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction); //移除双击缩放功能,使双击只用于关闭平移状态that.interactionDrag = new ExtTransform({enableRotatedTransform: false, //地图旋转时启用变换hitTolerance: 2, //偏移量translate: true, // 拖拽stretch: false, // 拉伸scale: false, // 缩放rotate: false, // 旋转translateFeature: false, //显示中心位置noFlip: false, //防止特征几何翻转,默认为 falselayers: [that.drawVector], //指定可以拖拽的图层});//添加交互that.map.addInteraction(that.interactionDrag);that.interactionDrag.on(["translatestart"], function (evt) {});that.interactionDrag.on(["translating"], function (evt) {//逻辑代码});that.interactionDrag.on(["translateend"], function (evt) {//逻辑代码});that.map.on("dblclick",function (){//双击移除控件,不再平移that.map.removeInteraction(that.interactionDrag)})}
框选平移功能的实现
//框选平移boxSelectAndMove() {let that = this;//移除双击缩放功能,使双击只用于关闭编辑状态const dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction);// 创建绘制矩形工具let drawBox = new Draw({source: new Vector(),type: 'Circle', //绘制的图形是圆形//官网描述geometryFunction://将坐标数组和可选的现有几何图形和投影作为参数并返回几何图形的函数。//可选的现有几何是在没有第二个参数的情况下调用函数时返回的几何。geometryFunction: createBox(), //将圆形改成矩形框,如果没有这行代码绘制出来的框会变成圆形//设置一些样式style: new Style({image: new Circle({radius: 7,fill: new Fill({color: "rgba(255, 128, 0,1)",}),}),fill: new Fill({color: "rgba(1, 92, 199,0.1)",}),stroke: new Stroke({color: "rgba(56, 239, 255,1)",width: 1})})});that.map.addInteraction(drawBox) //添加交互let myTransform = {} //定义一个接收初始化框选平移的变量,后面需要双击的时候移除交互,所以定义在这里drawBox.on('drawstart', function (evt) {//逻辑代码})drawBox.on('drawend', function (evt) {let polygon = evt.feature.getGeometry() // 用polygon存储画出来的矩形框的信息,包括坐标等let features = that.drawSource.getFeatures() //取出所有要素,每一个都要判断是否相交let needToMoveFeatures = [] //相交的要素存在这里let isIntersect = false // 是否相交for(let i=0;i<features.length;i++){let coordinates = features[i].values_.geometry.flatCoordinatesfor(let j=0;j<coordinates.length;j+=2){// containsXY()是Openlayers的内置函数,可以判断点是否在多边形内。// 这里的应用是判断每一个feature的顶点是否在polygon内// 因为画的是矩形框,如果框选到了feature,那么这个feature的某一个顶点一定在矩形框内// 如果是其他逻辑,需要参照Openlayers官方文档使用其他方法if(polygon.containsXY(coordinates[j], coordinates[j + 1])){// 如果已经判断相交,直接跳出循环即可isIntersect = trueneedToMoveFeatures.push(features[i])break}}}if(isIntersect){that.map.removeInteraction(drawBox)// 这里不再写注释了,和平移功能的实现是一样的myTransform = new ExtTransform({enableRotatedTransform: false,layers: [that.drawVector],hitTolerance: 2,scale: false,rotate: false,keepAspectRatio: false,keepRectangle: false,translate: true,translateFeature: false,noFlip: false,stretch: false,})that.map.addInteraction(myTransform) //添加控件myTransform.setSelection(needToMoveFeatures) //ol-ext中transform函数,可以直接把所有框选的要素当成一个整体myTransform.on('translatestart',function (evt){//逻辑代码})myTransform.on('translating',function (evt){//逻辑代码})myTransform.on('translateend',function (evt){//逻辑代码console.log(evt)//这里的evt包含了平移结束以后的feature信息,具体信息见下图})}})that.map.on('dblclick', function () {that.map.removeInteraction(drawBox)that.map.removeInteraction(myTransform)})},
效果展示
框选平移详细介绍
绘制两个图形
绘制了两个要素,一个是四边形,一个是六边形。
由于两个要素都是polygon类型的,所以四边形的要素坐标会显示5个,第一个和第五个是一样的。同理,六边形的坐标会显示7个,第一个和第七个也是一样的。
坐标系有两种情况,一种是一对一对的出现,另一种就是我后面截图上显示的情况,也就是横坐标和纵坐标是分开显示的
我在绘制完成后(drawend事件的回调函数里)输出了evt,可以看到两个要素的具体信息
框选平移结束事件后(translateend的回调函数中),我输出了evt,可以在这里面看到移动后要素的信息。
这里需要注意的是,看的是oldgeoms里面的信息。
可以根据不同需求,获取不同的信息。
这种方式是在框选平移结束后就需要要素的信息时使用,如果需要在别的函数里面获取新的要素信息,可以直接使用source.getFeatures()函数,就可以查看到最新的要素信息。
比如我这里就应该是this.drawSource.getFeatures()
这就需要把source定义成全局变量。
清空功能的实现
清空功能就不再赘述了,根据需求进行清空即可。记得清空source
clear(){//只写了最简单的,根据需求增加即可this.drawSource.clear()},
注意事项
最好把每个交互都设置成全局变量,在执行每个函数之前都要移除一下交互,比如在执行平移的时候,要移除绘制的交互。
这样做可以避免用户在点击添加后发现自己点错了,又去点击平移,会导致两个函数都在执行,又绘制又平移,可能会出现错误。
项目源码
<template><div><div id="map"></div><div class="Cards"><Card style="margin-top: 8px; width: 250px; z-index: 5"><Row><Button style="margin-right: 6px; width:100px;" type="success" @click="sketch"><Icon type="md-add"/>添加</Button><Button style="margin-right: 6px; width:100px;" type="error" @click="clear"><Icon type="md-close" />清空</Button></Row><Row style="margin-top: 4px;"><Button style="margin-right: 6px; width:100px;" type="info" @click="translation"><Icon type="md-move"/>平移</Button><Button style="margin-right: 6px; width:100px;" type="warning" @click="boxSelectAndMove()"><Icon type="md-move"/>框选平移</Button></Row></Card></div></div>
</template><script>//引入
import Map from "ol/Map"
import {Tile as TileLayer, Vector as VectorLayer} from "ol/layer";
import OSM from 'ol/source/OSM';
import View from "ol/View"
import {fromLonLat} from "ol/proj";
import {DoubleClickZoom, Draw} from "ol/interaction";
import {Fill, Stroke, Style,Circle} from "ol/style";
import {Vector} from "ol/source"
import ExtTransform from "ol-ext/interaction/Transform"
import {unByKey} from "ol/Observable";
import {GeoJSON} from "ol/format";
import {createBox} from "ol/interaction/Draw";export default {name: "Map",data(){return {map:{}, //地图容器,后续可能会涉及到map的相关操作,比如map.addLayer等,所以定义成全局的drawSource:new Vector(), //正常项目可能需要在其他函数中清空drawSource,所以定义成全局的drawVector:{}, //平移功能需要声明哪些图层可以被平移,所以定义成全局的draw :{}, //绘制功能,可能会在其他函数中使用this.map.removeInteraction(this.draw),所以定义成全局}},methods:{//地图初始化方法initialMap(){//用that代替this,防止某些位置this指向发生变化let that = thisthat.map = new Map({target:"map", //挂载到id为map的div容器上layers:[new TileLayer({source: new OSM() //OSM地图}),that.drawVector = new VectorLayer({source:that.drawSource,style: new Style({//图层样式fill: new Fill({color: "rgba(0, 0, 255, 0.2)", //填充颜色}),stroke: new Stroke({color: "#0000ff", //边框颜色width: 2, // 边框宽度}),image: new Circle({radius: 7,fill: new Fill({color: "#0000ff",}),}),}),})],//设置视图,包括中心点,坐标系,默认缩放级别,最大、最小缩放级别view: new View({projection:'EPSG:3857', //坐标系center: fromLonLat([120.2,30.35]), //中心点zoom: 10, //默认缩放级别minZoom:1, //最小缩放级别maxZoom:18 //最大缩放级别})})},//绘制方法sketch() {let that = this;that.map.removeInteraction(that.draw)that.map.removeInteraction(that.interactionDrag)//移除双击缩放功能,使双击只用于关闭编辑状态const dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction);//双击执行取消绘制that.map.on("dblclick", function () {that.MyDraw.setActive(false);that.map.removeInteraction(that.draw)});//初始化绘制交互that.draw = new Draw({//绘制对象source: that.drawSource, //绘制层数据源,勾绘的要素属于的数据集type: "Polygon", //绘制的类型,这里绘制一个多边形,也可以是POINT(点)、LINE_STRING(线)、CIRCLE(圆)//设置一些样式style: new Style({fill: new Fill({color: "rgba(0,0,255,0.2)",}),stroke: new Stroke({color: "#0000ff",width: 2,}),image: new Circle({radius: 7,fill: new Fill({color: "#0000ff",}),}),}),});// 加载交互绘制控件函数that.MyDraw = {//执行绘制函数的方法init: function () {that.map.addInteraction(that.draw); //添加交互//绑定交互绘制工具开始绘制的事件that.draw.on("drawstart", function (evt) {//逻辑代码});//绑定交互绘制工具结束绘制的事件that.draw.on("drawend", function (evt) {//逻辑代码that.MyDraw.setActive(false); //绘制完毕以后关闭控件console.log(evt)})},//控制控件开启或关闭的函数,active要传boolean类型/** setActive()是Openlayers中Interaction的函数,作用是开启和关闭控件* 这里也可以不用setActive()函数,可以使用this.map.addInteraction()加载控件和this.map.removeInteraction()* 在绘制结束的时候移除控件。如果使用这种方法,就需要把map定义成全局的。*/setActive: function (active) {that.draw.setActive(active); //激活控件},};that.MyDraw.init(); //执行绘制函数方法},//第二种绘制方法sketch2(){let that = this;//移除双击缩放功能,使双击只用于关闭编辑状态const dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction);//双击执行取消绘制that.map.on("dblclick", function () {that.map.removeInteraction(that.draw)});//初始化绘制交互that.draw = new Draw({//绘制对象source: that.drawSource, //绘制层数据源,勾绘的要素属于的数据集type: "Polygon", //绘制的类型,这里绘制一个多边形,也可以是POINT(点)、LINE_STRING(线)、CIRCLE(圆)//设置一些样式style: new Style({fill: new Fill({color: "rgba(0,0,255,0.2)",}),stroke: new Stroke({color: "#0000ff",width: 2,}),image: new Circle({radius: 7,fill: new Fill({color: "#0000ff",}),}),}),});// 加载交互绘制控件函数(function initDraw() {that.map.addInteraction(that.draw); //添加交互//绑定交互绘制工具开始绘制的事件that.draw.on("drawstart", function (evt) {//逻辑代码});//绑定交互绘制工具结束绘制的事件that.draw.on("drawend", function (evt) {//逻辑代码})})()},//清空clear(){this.drawSource.clear()},//平移功能(拖拽功能)translation(){let that = thisthat.map.removeInteraction(that.draw)const dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction); //移除双击缩放功能,使双击只用于关闭编辑状态that.interactionDrag = new ExtTransform({enableRotatedTransform: false,hitTolerance: 2, //偏移量translate: true, // 拖拽stretch: false, // 拉伸scale: false, // 缩放rotate: false, // 旋转translateFeature: false, //显示中心位置noFlip: false, //防止特征几何翻转,默认为 falselayers: [that.drawVector], //指定可以拖拽的图层});//添加交互that.map.addInteraction(that.interactionDrag);that.interactionDrag.on(["translatestart"], function (evt) {});that.interactionDrag.on(["translating"], function (evt) {//逻辑代码});that.interactionDrag.on(["translateend"], function (evt) {//逻辑代码});that.map.on("dblclick",function (){//双击移除控件,不再平移that.map.removeInteraction(that.interactionDrag)})},//框选平移boxSelectAndMove() {let that = this;that.map.removeInteraction(that.draw)that.map.removeInteraction(that.interactionDrag)//移除双击缩放功能,使双击只用于关闭编辑状态const dblClickInteraction = that.map.getInteractions().getArray().find((interaction) => {return interaction instanceof DoubleClickZoom;});that.map.removeInteraction(dblClickInteraction);// 创建绘制矩形工具let drawBox = new Draw({source: new Vector(),type: 'Circle', //绘制的图形是圆形//将坐标数组和可选的现有几何图形和投影作为参数并返回几何图形的函数。可选的现有几何是在没有第二个参数的情况下调用函数时返回的几何。geometryFunction: createBox(), //将圆形改成矩形框,如果没有这行代码绘制出来的框会变成圆形//设置一些样式style: new Style({image: new Circle({radius: 7,fill: new Fill({color: "rgba(255, 128, 0,1)",}),}),fill: new Fill({color: "rgba(1, 92, 199,0.1)",}),stroke: new Stroke({color: "rgba(56, 239, 255,1)",width: 1})})});that.map.addInteraction(drawBox) //添加交互let myTransform = {} //定义一个接收初始化框选平移的变量,后面需要双击的时候移除交互,所以定义在这里drawBox.on('drawstart', function (evt) {//逻辑代码})drawBox.on('drawend', function (evt) {let polygon = evt.feature.getGeometry() // 用polygon存储画出来的矩形框的信息,包括坐标等let features = that.drawSource.getFeatures() //取出所有要素,每一个都要判断是否相交let needToMoveFeatures = [] //相交的要素存在这里let isIntersect = false // 是否相交for(let i=0;i<features.length;i++){let coordinates = features[i].values_.geometry.flatCoordinatesfor(let j=0;j<coordinates.length;j+=2){// containsXY()是Openlayers的内置函数,可以判断点是否在多边形内。// 这里的应用是判断每一个feature的顶点是否在polygon内// 因为画的是矩形框,如果框选到了feature,那么这个feature的某一个顶点一定在矩形框内// 如果是其他逻辑,需要参照Openlayers官方文档使用其他方法if(polygon.containsXY(coordinates[j], coordinates[j + 1])){// 如果已经判断相交,直接跳出循环即可isIntersect = trueneedToMoveFeatures.push(features[i])break}}}if(isIntersect){that.map.removeInteraction(drawBox)// 这里不再写注释了,和平移功能的实现是一样的myTransform = new ExtTransform({enableRotatedTransform: false,layers: [that.drawVector],hitTolerance: 2,scale: false,rotate: false,keepAspectRatio: false,keepRectangle: false,translate: true,translateFeature: false,noFlip: false,stretch: false,})that.map.addInteraction(myTransform) //添加控件myTransform.setSelection(needToMoveFeatures) //ol-ext中transform函数,可以直接把所有框选的要素当成一个整体myTransform.on('translatestart',function (evt){//逻辑代码})myTransform.on('translating',function (evt){//逻辑代码})myTransform.on('translateend',function (evt){//逻辑代码console.log(evt)//这里的evt包含了平移结束以后的feature信息,具体信息见下图})}})that.map.on('dblclick', function () {that.map.removeInteraction(drawBox)that.map.removeInteraction(myTransform)})},},mounted() {this.initialMap() //立即执行初始化地图方法}
}
</script><style scoped>#map{width: 100%;height: 100%;position: absolute;}.Cards{position: absolute;top: 0%;right: 10%;}
</style>
博主第一次写文,如果写的不好请多多担待,有哪里写错了,也请大家批评斧正!感谢各位的支持!
这篇关于Vue2 + Openlayers 实现绘制、平移和框选平移功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!