最近刚忙完一个新项目,是基于
WebGIS
开发技术采用离线瓦片地图进行交互,由于之前做过类似的项目,也花了一些时间做研究,所以接手这个"So Easy"
。主要技术栈是Vue+OpenLayers+地图
,下面会分享一些我用WebGIS开发的大致路线和入门知识,以及项目实战经验,如有不妥之处,还请批评纠正,也欢迎大家一起探讨学习。
首先来认识一下WebGIS是什么东东,如下图所示:
百度百科: WebGIS(网络地理信息系统)是指工作在Web网上的GIS,是传统的GIS在网络上的延伸和发展,具有传统GIS的特点,可以实现空间数据的检索、查询、制图输出、编辑等GIS基本功能,同时也是 Internet 上地理信息发布、共享和交流协作的基础。
https://baike.baidu.com/item/webgis/761986?fr=aladdin
Web + GIS 就是,在Web网页上的GIS系统,我们可以在网页(浏览器)上进行GIS数据处理操作、可视化展示等。
WebGIS 三层架构主要为展示层、地图服务层、数据层,通过UML图形进行理解,如下图所示:
3D WebGIS是近期未来的方向,因为大数据可视化,最佳配合展示方式是3D地图。
地图要素展示(建筑、路线信息),空间分析(最短路径、最快路径),数据分析可视化(交通实时情况),POI兴趣点(附近景点、商家、美食等)。
Web服务器一般指网站服务器,简单的可以理解为,电脑上的文件资源,可以通过Web服务器部署后,让通过因特网的人都能访问预览。
目前行业上比较流行的地图JS库,主要有:ArcGIS API for JavaScript、OpenLayers、Leaflet、Mapbox、maptalks.js
详细介绍请移步:「开源项目」8款最受欢迎的地图API和javascript库
新手看到上面的学习路线,心里就会嘀咕着想打退堂鼓,别灰心,继续跟着我的节奏往下走,已准备好一个快速上手开发的操作步骤。只要有前端基础,信手拈来。
小编推荐两个免费地图下载器工具,如需下载工具及源码请关注公众号:[懒人码农],回复关键词“地图”即可下载使用。
支持地图种类繁多:几乎包含所有主流在线地图,包括不仅限于谷歌、百度、高德、四维、微软、诺基亚、天地图、腾讯、ArcGIS、雅虎等地图,每种地图各有千秋。
下载离线瓦片地图数据源(可以根据自己需求下载地图级别数据源,等级越大数据量越大,下载时间越久)
全能电子地图下载器的操作方法:
菜单栏选择“地图” —— 目前提供多种地图:百度地图、MapABC地图、谷歌普通地图、谷歌卫星图、谷歌混合图、谷歌地形图、腾讯普通地图,腾讯卫星图,腾讯混合图、雅虎中国地图。
左侧栏勾选“地图等级” —— 谷歌地图等级为0-19级,其他地图是3-18级,地形图0-14级,建议下载区域遵循以下原则即可:世界1-4级,中国4-7级,城市8-17级。
选择“下载区域” —— 点击地图左上角选择工具,选择感兴趣的区域, 支持按矩形、不规则多边形、圆形区域,还可以按省/市区域下载。
左侧栏选择“当前视野”或“显示范围”,地图上会框选被选区域。
左侧栏点击“开始”按钮即可下载地图,也可以选择省份下载。
1) 打开命令行窗口,输入 node -v 查看,出现版本号说明已安装成功,如下图:
2) 使用以下命令安装Vue
npm install -g @vue/cli
// 安装指定版本
npm install -g @vue/cli@4.5.13
// OR
yarn global add @vue/cli
3)安装完成,检查vue版本,如下图:
vue -V
4) vue-cli4 创建项目及运行
vue create mapdemo
cd mapDemo
npm run serve
在浏览器地址栏输入:http://localhost:8080/
npm install ol
按照上面的步骤已完成脚手架构建,并把需要的 Openlayers 依赖库引入和安装配置好,准备上刺刀开干。
https://openlayers.org/en/latest/doc/quickstart.html
在 main.js 文件中挂载,代码如下:
// 将全局的ol对象挂载到Vue的原型对象上
// 在别的组件中使用 this.$ol
Vue.prototype.$ol = window.ol
在 components 文件夹新建组件demo1.vue文件,代码如下:
<template>
<div class="page-map">
<div id="map" class="map"></div>
</div>
</template>
<script>
export default {
name: "Demo1",
data() {
return {
map: null
}
},
mounted() {
this.initMap()
},
methods: {
// 初始化地图
initMap() {
this.map = new this.$ol.Map({
target: 'map',
layers: [
new this.$ol.layer.Tile({
source: new this.$ol.source.OSM()
})
// new this.$ol.layer.Tile({
// source: new this.$ol.source.XYZ({
// // 在线加载 Mapbox 卫星影像底图
// url: 'https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg?access_token=pk.eyJ1Ijoid2FuZ2hhaGExIiwiYSI6ImNqeHUycXF5ZDEweDQzYnBiOTcwZGoxMHAifQ.eCGuiA6erHJ7ew-Fkc7dRA'
// })
// }),
// new this.$ol.layer.Tile({
// source: new this.$ol.source.XYZ({
// // 在线加载谷歌卫星底图(需)
// url: 'http://mt2.google.com/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}'
// })
// })
],
view: new this.$ol.View({
center: this.$ol.proj.fromLonLat([121.3431, 25.067]),
zoom: 4
})
});
}
}
};
</script>
<style scoped>
.map {
width: 100%;
height: 100vh;
}
</style>
效果图如下所示:
在utils文件夹中新建gisHelper.js文件,JS模块化代码实现如下:
// 创建initMap方法,初始化地图
initMap(targetName) {
// let googleMapLayer = []
// googleMapLayer = [
// this.layers.googleScreenAgeMapLayer
// ]
// 实例化Map对象,用于加载地图
this.map = new ol.Map({
// 地图容器div的id
target: targetName,
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([121.3431, 25.067]),
zoom: 8,
minZoom: 4,
maxZoom: 12,
extent: this.extents.World
}),
// 地图控件
controls: ol.control.defaults({
attribution: false,
zoom: false,
rotate: false
}).extend([])
})
}
// 鼠标响应手形变化
this.map.on('pointermove', (e) => {
let pixel = this.map.getEventPixel(e.originalEvent)
if (this.map.hasFeatureAtPixel(pixel)) {
this.map.getTargetElement().style.cursor = 'pointer'
} else {
this.map.getTargetElement().style.cursor = ''
}
})
// 点击地图获取经纬度,或点击要素
this.map.on('click', (e) => {
console.log(e.pixel)
let feature = this.map.forEachFeatureAtPixel(e.pixel, (ft) => {
// 鼠标点击某一个要素后,获取这个要素,执行业务逻辑
return ft
})
console.log(feature);
if (feature) {
// this.addUnitDetailPopUp(feature.get('extraData'))
}
})
// 设置视角(中心点)
setView(lngLat) {
this.map.getView().animate({
center: ol.proj.fromLonLat(lngLat)
})
}
// 设置地图缩放
setZoom(zoomLevel) {
this.map.getView().animate({
zoom: zoomLevel
});
}
// 点击地图获取经纬度
this.map.on('click', (e) => {
let lngLat = ol.proj.toLonLat(e.coordinate), // 点击获取经纬度
feature = this.map.forEachFeatureAtPixel(e.pixel, (ft) => {
// forEachFeatureAtPixel()方法获取选中要素
return ft;
})
})
// 地图上显示要素标记点
addFeatureMarker(arr) {
let features = [];
arr.forEach((e) => {
let feature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([e.longitudeX, e.latitudeY])),
})
feature.setStyle(new ol.style.Style({
image: new ol.style.Icon({
src: e.imgPath,
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
anchorOrigin: 'top-right',
offsetOrigin: 'top-right',
anchor: [0.5, 60]
}),
text: new ol.style.Text({
text: e.name,
textAlign: 'center',
textBaseline: 'middle',
font: "normal 13px sans-serif",
padding: [3, 8, 3, 8],
backgroundFill: new ol.style.Fill({
color: 'rgba(218, 77, 81, .2)',
}),
fill: new ol.style.Fill({
color: '#fff',
})
}),
}))
feature.set("extraData", e);
features.push(feature);
})
this.featureSource.addFeatures(features);
}
// 显示气泡弹框PopUp
addDialogPopUp(item) {
let lngLat = [item.longitudeX, item.latitudeY];
this.removeOverlayPopUp();
this.dialogOverlay = new ol.Overlay({
element: this.createDialogDom(item),
position: ol.proj.fromLonLat(lngLat),
autoPan: true,
positioning: 'bottom-left',
offset: [50, -50]
})
this.map.addOverlay(this.dialogOverlay);
}
setCircle(location, size) {
let circle = new ol.geom.Circle(ol.proj.transform(location, 'EPSG:4326', 'EPSG:3857'), size);
this.circleFeature = new ol.Feature(circle);
this.circleFeature.setStyle(
new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, .2)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 1
})
})
);
this.circleSource.addFeature(this.circleFeature);
}
// 设置线条带箭头
setLineString(location) {
let line = new ol.geom.LineString([ol.proj.fromLonLat(this.posCenter), location]);
this.lineFeature = new ol.Feature(line);
let geometry = this.lineFeature.getGeometry(),
sta = geometry.flatCoordinates.slice(-4),
dx = sta[2] - sta[0],
dy = sta[3] - sta[1],
rotation = Math.atan2(dy, dx), // 获取线段的角度(弧度)
arrowLonLat = [sta[2], sta[3]];
this.lineFeature.setStyle([
new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, .2)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
lineDash: [1, 2, 3, 4, 5, 6],
width: 3
})
}),
new ol.style.Style({
geometry: new ol.geom.Point(arrowLonLat),
image: new ol.style.Icon({
src: require('../assets/arrow.png'),
anchor: [0.75, 0.5], // 图标锚点
rotateWithView: true, // 与地图视图一起旋转
rotation: -rotation // 因为角度以顺时针旋转为正值,所以前面添加负号
})
})
]);
this.lineSource.addFeature(this.lineFeature);
}
这次分享的内容写得比较仓促,涉及知识面不是很广,毕竟小编词库有限。看到这里相信小伙伴们,对WebGIS开发都有所了解,赶快动手操作一波吧。
如果这篇文章对你有一丝帮助,可以点赞、评论、转发分享,也是对我的一种支持,万分感谢。如需获取更多实战项目经验或源码资源,请关注公众号:「懒人码农」,回复关键词
“地图”
即可下载本资源,也可以加我微信【lazycode520】,一起学习一起进步。