持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
“金秋十月,我要连续30天更文,做劳模,拿手机摄影神器!点击查看活动详情 “即可成功参与
开发过程
进行WebGIS应用开发,一般均采用前端开发库+GIS服务的模式,开发者须完成如下三个步骤
第一步:安装配置开发环境
第二步:发布GIS服务资源
第三步:获取前端开发库(MapGIS Client for JavaScript开发库)
通过文件拷贝或npm方式引用开发库,进行WebGIS二维或三维应用开发
Openlayers二位地图
Cesium三位地图
通过 npm 命令引入 OpenLayers 地图引擎,建议使用 5.x 版本
npm install ol@5.3.0
OpenLayers的地图导入渲染,以及坐标点的点击事件
1、项目引入Openlayers
//Openlayers的npm包名为ol,咱们直接在项目中引入ol就行
npm install ol
// or
yarn add ol
2、底层渲染
//在map组件中进行map渲染,这里采用的是高德地图的切片地图模式
<template>
<div>
<!-- 地图容器 -->
<div class="ol-map" ref="olMap"></div>
</div>
</template>
<script>
import Map from 'ol/Map'
import View from 'ol/View'
import { Tile as TileLayer } from 'ol/layer'
import { XYZ } from 'ol/source'
// fromLonLat方法能将坐标从经度/纬度转换为其他投影
import { fromLonLat } from 'ol/proj'
// 拖拽旋转
import { defaults as defaultInteractions, DragRotateAndZoom } from 'ol/interaction'
export default {
name: 'newMap',
data () {
return {
map: null
}
},
created () {
},
computed: {
},
mounted () {
this.init()//当DOM挂载完毕后调用方法,展示地图
},
methods: {
//将地图进行封装
init () {
// 使用高德
const tileLayer = new TileLayer({
source: new XYZ({
url: 'https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
})
})
this.map = new Map({
layers: [tileLayer],
view: new View({
center: fromLonLat([120.771441, 30.756433]), // 地图中心点
zoom: 15, // 缩放级别
minZoom: 0, // 最小缩放级别
maxZoom: 18, // 最大缩放级别
constrainResolution: true// 因为存在非整数的缩放级别,所以设置该参数为true来让每次缩放结束后自动缩放到距离最近的一个整数级别,这个必须要设置,当缩放在非整数级别时地图会糊
}),
target: this.$refs.olMap, // DOM容器
interactions: defaultInteractions().extend([new DragRotateAndZoom()]) // 按住shit旋转
})
}
}
}
</script>
<style lang='less' scoped>
.ol-map{
width: 1000px;
height: 500px;
margin-top: 30px;
}
</style>
基本类介绍,Openlayers中4个主要的类:
- Map:地图容器,通过target指定地图绘制的容器id,如代码中的map;
- Layer:图层,map拥有1个获多个图层,可以理解成PS绘图中的图层概念,整个map是由一个个图层堆叠出来的;
- View:可视区域,这个类主要是控制地图与人的交互,如进行缩放,调节分辨率、地图的旋转等控制。同时可以设置投影,默认为球形墨卡托,代码中olProj.fromLonLat方法也是将经纬度转换成对应的坐标,这块不做拓展,有需要的同学可自行去学习GIS的理论。
- source:数据来源,即图层Layers的数据组成部分,上文代码中TileLayer就是使用了一个高德地图XYZ格式的切片数据绘制而成,
此时运行项目已经能够看到地图展示了
3、标记绘制
地图中最常见的需求就是做点位标记,同理,这时我们只需要在之前的地图Layer上再盖一层点位标记的Layer即可,使用的是VectorLayer跟VectorSource,矢量图层以及一个矢量数据
import { Vector as VectorLayer} from 'ol/layer';
import { Vector as VectorSource} from 'ol/source';
我们这里简单实现,直接将一个点位添加到openMap的layers数组里;
// import
import { Map, View, Feature } from "ol";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ, Vector as VectorSource } from "ol/source";
import * as olProj from "ol/proj";
import { Point } from "ol/geom";
import { Style, Fill, Stroke, Circle as sCircle } from "ol/style";
// methods添加setMarker方法
mounted() {
this.initMap();
this.setMarker();
},
// setMarker
setMarker() {
let _style = new Style({
image: new sCircle({
radius: 10,
stroke: new Stroke({
color: "#fff",
}),
fill: new Fill({
color: "#3399CC",
}),
}),
});
let _feature = new Feature({
geometry: new Point(olProj.fromLonLat([108.945951, 34.465262])),
});
_feature.setStyle(_style);
let _marker = new VectorLayer({
source: new VectorSource({
features: [_feature],
}),
});
this.openMap.addLayer(_marker);
},
成功在地图上添加了一个点位。
上方代码中import了几个新的类:Feature,Point,Style等,主要是具有几何的地理要素的矢量对象以及具体的样式,然后通过setStyle将样式赋予Feature,主要就在地图上绘制出了一个坐标点。
4、弹窗显示标记信息
接下来咱们需要给3小节中的坐标点添加点击事件,同时能够在地图上显示一个弹框,展示点位的一些信息。
首先添加点击事件,这里使用单击singleclick
singleclick() {
this.openMap.on("singleclick", (e) => {
// 判断是否点击在点上
let feature = this.openMap.forEachFeatureAtPixel(
e.pixel,
(feature) => feature
);
console.log(feature);
});
},
当我们没有点击在点上时,会打印undefined,而点击在点上时会打印出对应的feature信息
这里我们同时添加一个事件pointermove,改变鼠标移到到点位上的光标样式。
pointermove() {
this.openMap.on("pointermove", (e) => {
if (this.openMap.hasFeatureAtPixel(e.pixel)) {
this.openMap.getViewport().style.cursor = "pointer";
} else {
this.openMap.getViewport().style.cursor = "inherit";
}
});
},
接着上面的点击事件,当我们点击时希望能够在点位的上方显示出该点的信息弹窗 先在vue添加个弹窗组件,需要引入一个新的类Overlay
import { Overlay } from "ol";
复制代码
// template
<!-- 弹框 -->
<div ref="popup" class="popup" v-show="shopPopup">
<div class="info">
<ul>
<li>信息1:xxx</li>
<li>信息2:xxx</li>
<li>信息3:xxx</li>
</ul>
</div>
</div>
// script
addOverlay() {
// 创建Overlay
let elPopup = this.$refs.popup;
this.popup = new Overlay({
element: elPopup,
positioning: "bottom-center",
stopEvent: false,
offset: [0, -20],
});
this.openMap.addOverlay(this.popup);
},
// style
.popup {
width: 200px;
background-color: white;
padding: 18px;
border-radius: 10px;
box-shadow: 0 0 15px rgb(177, 177, 177);
.info {
font-size: 14px;
text-align: left;
ul {
padding-left: 0;
}
}
}
使用ol的addOverlay方法,将弹出层添加到map的Overlay上,然后修改之前的点击事件函数
singleclick() {
// 点击
this.openMap.on("singleclick", (e) => {
// 判断是否点击在点上
let feature = this.openMap.forEachFeatureAtPixel(
e.pixel,
(feature) => feature
);
console.log(feature);
if (feature) {
this.shopPopup = true;
// 设置弹窗位置
let coordinates = feature.getGeometry().getCoordinates();
this.popup.setPosition(coordinates);
} else {
this.shopPopup = false;
}
});
},
可以看到有设置弹窗位置的代码
// 设置弹窗位置
let coordinates = feature.getGeometry().getCoordinates();
this.popup.setPosition(coordinates);
获取当前点击点的坐标,然后设置给弹窗,同时之前弹窗设置了y轴-30的偏移 以防覆盖掉点位标记。 至此,咱们整个点击弹窗就实现完成了。
最后,附上完整代码,主要是Home.vue的修改
<template>
<div class="home">
<div id="map" class="map-home"></div>
<!-- 弹框 -->
<div ref="popup" class="popup" v-show="shopPopup">
<div class="info">
<ul>
<li>信息1:xxx</li>
<li>信息2:xxx</li>
<li>信息3:xxx</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import { Map, View, Feature, Overlay } from "ol";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { XYZ, Vector as VectorSource } from "ol/source";
import * as olProj from "ol/proj";
import { Point } from "ol/geom";
import { Style, Fill, Stroke, Circle as sCircle } from "ol/style";
export default {
name: "Home",
components: {},
data() {
return {
openMap: null,
popup: null,
shopPopup: false,
};
},
mounted() {
this.initMap();
},
methods: {
initMap() {
this.openMap = new Map({
target: "map",
layers: [
new TileLayer({
source: new XYZ({
url: "https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
}),
}),
],
view: new View({
center: olProj.fromLonLat([108.945951, 34.465262]),
zoom: 1,
}),
controls: [],
});
this.setMarker();
this.addOverlay();
this.singleclick();
this.pointermove();
},
setMarker() {
let _style = new Style({
image: new sCircle({
radius: 10,
stroke: new Stroke({
color: "#fff",
}),
fill: new Fill({
color: "#3399CC",
}),
}),
});
let _feature = new Feature({
geometry: new Point(olProj.fromLonLat([108.945951, 34.465262])),
});
_feature.setStyle(_style);
let _marker = new VectorLayer({
source: new VectorSource({
features: [_feature],
}),
});
this.openMap.addLayer(_marker);
},
addOverlay() {
// 创建Overlay
let elPopup = this.$refs.popup;
this.popup = new Overlay({
element: elPopup,
positioning: "bottom-center",
stopEvent: false,
offset: [0, -20],
});
this.openMap.addOverlay(this.popup);
},
singleclick() {
// 点击
this.openMap.on("singleclick", (e) => {
// 判断是否点击在点上
let feature = this.openMap.forEachFeatureAtPixel(
e.pixel,
(feature) => feature
);
console.log(feature);
if (feature) {
this.shopPopup = true;
// 设置弹窗位置
let coordinates = feature.getGeometry().getCoordinates();
this.popup.setPosition(coordinates);
} else {
this.shopPopup = false;
}
});
},
pointermove() {
this.openMap.on("pointermove", (e) => {
if (this.openMap.hasFeatureAtPixel(e.pixel)) {
this.openMap.getViewport().style.cursor = "pointer";
} else {
this.openMap.getViewport().style.cursor = "inherit";
}
});
},
},
};
</script>
<style lang="scss" scoped>
.map-home {
width: 100vw;
height: 100vh;
}
.popup {
width: 200px;
background-color: white;
padding: 18px;
border-radius: 10px;
box-shadow: 0 0 15px rgb(177, 177, 177);
.info {
font-size: 14px;
text-align: left;
ul {
padding-left: 0;
}
}
}
</style>
本文主要是OpenLayers的入门教程,完成OpenLayers的地图导入渲染,以及坐标点的点击事件。