初识webGIS库—OpenLayers
文章目录
- 前言
- 一、OpenLayers是什么?
- 二、快速开始
- 1.安装
- 2.入门使用
- 三、配置
- 1.Map
- 2.Layer
- 3.Source
- 4.View
- 5.Control
- 6.Interaction
- 四、实践
- 实现思路
- 完整代码
- 总结
前言
GIS 作为获取、存储、分析和管理地理空间数据的重要工具,用 GIS 技术绘制地图比用传统的手工操作或自动制图工具更加灵活。今天给大家分享一个专为 GIS 客户端开发提供的 JavaScript 类库包 — OpenLayers。
一、OpenLayers是什么?
OpenLayers 是一个专为 Web GIS 客户端开发提供的 JavaScript 类库包,用于实现标准格式发布的地图数据访问。它的主要作用就是用于展现数据并且提供相应的地图操作工具。官方文档地址:https://openlayers.org/
二、快速开始
1.安装
npm i --save ol
cnpm i --save ol
2.入门使用
2.1 为地图准备一个
div
的容器
<div style="height: 100%; width: 100vw"><div id="map" ref="map"></div>
</div>
2.2 绑定
id
初始化一个地图;将图层Layer
添加到Map
中,指定数据源服务(url)
;设置Map
容器的视图窗口。
initMap() {this.map = new Map({target: "map", // html中的地图id// 图层的基类layers: [new TileLayer({source: new OSM(), //指定了图层的数据来源,图层作用是以一定的样式渲染数据,source则指定数据}),],view: new View({projection: "EPSG:4326", //坐标系,有EPSG:4326和EPSG:3857center: [116.23, 39.54], //中心坐标点zoom: 10, //默认缩放级别}),});
},
完整代码
<template><div style="height: 100%; width: 100vw"><div id="map" ref="map"></div></div>
</template><script>
import "ol/ol.css";
import { Map, View } from "ol";
import TileLayer from "ol/layer/Tile";
import OSM from "ol/source/OSM";
export default {data() {return {map: null,};},mounted() {this.initMap(); //定义一个方法}, methods: {// 初始化地图initMap() {this.map = new Map({target: "map", // html中的地图id// 图层的基类(添加图层)layers: [new TileLayer({source: new OSM(), //指定了图层的数据来源,图层作用是以一定的样式渲染数据,source则指定数据}),],view: new View({projection: "EPSG:4326", //坐标系,有EPSG:4326和EPSG:3857center: [116.23, 39.54], //中心坐标点zoom: 10, //默认缩放级别}),});},},
};
</script><style>
#map {width: 100%;height: 100%;
}
</style>
实现效果
三、配置
在所有配置中,Map、Layer、Source、View、Control、Interaction 是 Openlayers 的核心配置;下面为大家一一讲解。
1.Map
Map 是 Openlayers 使用基础,所有的图层、地图控件、地图工具等必须添加到 Map 中才能使用。
1.1 Map 常用的属性、方法和事件
属性:
- layers 图层
- view 视图
- controls 地图控件
- target 地图容器
- overlays 叠加图层
例:view 方法的使用
view: new View({projection: "EPSG:4326", center: [116.23, 39.54], zoom: 10,}),
方法:
- addControl(control) 添加控件
- addInteraction(interaction) 添加交互
- addLayer(layer) 添加图层
- addOverlay(overlay) 添加覆盖物
- dispatchEvent(event) 调度事件并调用所有侦听此类型事件的侦听器
- on(type, listener) 侦听某种类型的事件
- getOverlays() 获取所有覆盖物
- removeOverlay(overlay) 删除指定覆盖物
例:addControl 方法的使用
this.map.addControl(new control.OverviewMap({collapsed: true,})
);
事件:
- click 地图点击事件
- dblclick 地图双击事件
- moveend 地图移动时触发
- movestart 地图开始移动时触发
- postrender 地图渲染后触发
- singleclick 地图单击事件
例:click 事件的使用
this.map.on("click", (evt) => {this.mapPointerClick(evt);
});
2.Layer
Layer 是 Map 的核心组成部分,ol 定义了四种基本的图层类型,分别是分别是 Tile(瓦片)、Image(图片)、Vector(矢量)、VectorTile(矢量切片),这四种类有一个共同的基类 Layer,它们的大多数属性和方法都继承自这个类。
2.1 Layer 常用的属性和方法
属性:
- source 指定了图层的数据来源
- className 图层各个元素的样式
- opacity 透明度,默认为 1
- visible 是否可见,默认是 true
- zIndex 图层的叠加顺序,默认是 0
- extent 图层渲染的区域(浏览器窗口中可见的地图区域)
- minResolution 图层最小分辨率,当 layer 缩放级别小于这个分辨率时,图层隐藏
- maxResolution 图层最大分辨率
- minZoom 图层最小缩放级别
- maxZoo 图层最大缩放级别
例:source 属性的使用
layers: [new TileLayer({source: new OSM(),}),
],
方法:
- getLayersArray() 拿到所有图层
- getLayerStatesArray() 拿到所有图层状态
- getSource() 拿到相应图层的来源
- getSourceState() 拿到相应图层的来源状态
- setSource() 设置图层 source 属性,参数为一个 source 对象
- setMap() 添加 Layer 到 Map,并由 Map 管理
例:getSourceState 方法的使用
this.clusterSource.getSource().forEachFeature((feature) => {//执行操作
});
3.Source
Source 就是数据来源和格式。简单理解就是在使用 layers(图层) 时,不同的图层需要传入不同的数据类型才能渲染地图。它们需要的数据格式都是通过 Source 定义好的,我们只需要把现有的数据按照规定传入数据源中即可。
3.1 Source 的数据类型
分类:
- ol.source.BingMaps Bing 地图图块数据的图层源
- ol.source.CartoDB CartoDB Maps API 的图层源
- ol.source.Cluster 聚簇矢量数据
- ol.source.Vector 提供矢量图层数据
- ol.source.Image 提供单一图片数据的类型
- ol.source.ImageCanvas 数据来源是一个 canvas 元素,其中的数据是图片
- ol.source.ImageMapGuide Mapguide 服务器提供的图片地图数据
- ol.source.ImageStatic 提供单一的静态图片地图
- ol.source.ImageVector数据来源是一个 canvas 元素,但是其中的数据是矢量来源
- ol.source.ImageWMS WMS 服务提供的单一的图片数据
- ol.source.MapQuest MapQuest 提供的切片数据
- ol.source.Stamen Stamen 提供的地图切片数据
- ol.source.Tile 提供被切分为网格切片的图片数据
- ol.source.TileVector 被切分为网格的矢量数据
- ol.source.TileDebug 并不从服务器获取数据
- ol.source.TileImage 提供切分成切片的图片数据
- ol.source.TileUTFGrid TileJSON 格式 的 UTFGrid 交互数据
- ol.source.TileJSON TileJSON 格式的切片数据
- ol.source.TileArcGISRest ArcGIS Rest 服务提供的切片数据
- ol.source.WMTS WMTS 服务提供的切片数据
- ol.source.Zoomify Zoomify 格式的切片数据
- ol.source.OSM OpenStreetMap 提供的切片数据
- ol.source.XYZ 具有在 URL 模板中定义的一组 XYZ 格式的 URL 的切片数据的图层源
例:通过 layer 使用 source
this.layer = new TileLayer({source: new XYZ({url: "http://192.168.0.138/OSM/{z}_{x}_{y}.png",wrapX: true,}),
});
4.View
view 的作用主要是控制地图的交互,例如设置地图的展示位置范围、地图中心位置以及当前地图使用的投影坐标系等等。
4.1 View 常用的属性和方法
属性:
- center 视图初始化中心点位
- enableRotation 是否启用旋转
- constrainRotation 旋转约束;false 意味着没有约束;true 意味着没有约束,但在 0 附近捕捉到 0。数字将旋转限制为该数量的值,就是设置 90 只能旋转 90 度
- extent 限制视图的范围;可选:[minx, miny, maxx, maxy]
- constrainOnlyCenter 若为 true,则范围约束将仅适用于视图中心而不是整个范围
- smoothExtentConstraint 若为 true,范围约束将被平滑地应用,即允许视图稍微超出给定的 extent
- maxResolution 用于确定分辨率约束的最大分辨率
- minResolution 用于确定分辨率约束的最小分辨率
- maxZoom 用于确定分辨率约束的最大缩放级别
- minZoom 用于确定分辨率约束的最小缩放级别
- constrainResolution 若为 true,则视图将始终在交互后以最接近的缩放级别进行动画处理;false 表示允许中间缩放级别
- resolutions决定缩放级别的分辨率
- zoom 只有 resolution 未定义时使用;缩放级别用于计算视图的初始分辨率
- rotation 以弧度为单位的视图初始旋转(顺时针旋转,0 表示北)
例:maxZoom 事件的使用
view: new View({// 地图视图projection: "EPSG:4326", center: [118.27, 39.71],zoom: 10, maxZoom: 20,}),
方法:
- getCenter 获取视图中心,返回地图中心坐标
- getZoom 获取当前的缩放级别
- getMaxZoom 获取视图的最大缩放级别
- getMinZoom 获取视图的最小缩放级别
- getProjection 获取地图使用的“投影坐标系统”,如 EPSG:3857
- getMaxResolution 获取视图的最大分辨率
- getMinResolution 获取视图的最低分辨率
- getRotation 获取视图旋转
- getZoomForResolution 获取分辨率的缩放级别
- setCenter 设置当前视图的中心
- setConstrainResolution 设置视图是否应允许中间缩放级别
- setZoom 缩放到特定的缩放级别。任何分辨率限制都将适用
- setMaxZoom 为视图设置新的最大缩放级别
- setMinZoom 为视图设置新的最小缩放级别
- setRotation 设置该视图的旋转角度
例:getZoom 事件的使用
//amend 点击事件
amend() {const view = this.map.getView();const zoom = view.getZoom();view.setZoom(zoom - 1);console.log(view, "缩放级别:" + zoom);
},
5.Control
Control 控件,操作地图相关的工具。
5.1 Control 常用的控件
控件:
- FullScreen() 全屏控制
- MousePosition() 坐标拾取控件
- ScaleLine() 比例尺控件
- ZoomSlider() 滑块缩放控件
- OverviewMap() 鹰眼控件
- Attribution() 官方 LoGo
例:Control 控件的使用
this.map = new Map({controls: control.defaults().extend([// 根据需要打开关闭即可new control.FullScreen(), //全屏控制// new control.MousePosition(), //坐标拾取控件// new control.ScaleLine(),//比例尺控件// new control.ZoomSlider(),//滑块缩放控件// new control.OverviewMap(),//鹰眼控件]),
});
6.Interaction
Interaction 也是用来控制地图的,但与控件不同的是 Interaction 是在地图上绘制要素、选择、修改、移动、拉伸等等操作。
6.1 Interaction 常用的交互功能
常用交互功能:
- doubleclickzoom 双击地图进行缩放
- draganddrop 以“拖文件到地图中”的交互添加图层
- dragbox 用于划定一个矩形范围
- dragpan 拖拽平移地图
- dragrotateandzoom 拖拽方式进行缩放和旋转地图
- dragrotate 拖拽方式旋转地图
- dragzoom 拖拽方式缩放地图
- draw 绘制地理要素功能
- keyboardpan 键盘方式平移地图
- keyboardzoom 键盘方式缩放地图
- select 选择要素功能
- modify 更改要素
- mousewheelzoom 鼠标滚轮缩放功能
- pinchrotate 手指旋转地图,针对触摸屏
- pinchzoom 手指进行缩放,针对触摸屏
- pointer 鼠标的用户自定义事件基类
- snap 鼠标捕捉,当鼠标距离某个要素一定距离之内,自动吸附到要素
例:dragrotateandzoom 交互的使用
this.map = new Map({interactions: defaultInteractions().extend([new DragRotateAndZoom()]),
});
四、实践
经过以上的学习,相信大家对 OpenLayers 已经有了初步的认识,下面我们来写一个简单的操作,根据接口数据中的经纬度在地图上渲染点位,点击点位展示当前点击点位的详情数据,如下图:
实现思路
1.引入所需组件;
2.初始化一个地图;
3.循环接口数据拿到所需经纬度,通过 addLayer 方法添加到地图中;
4.添加弹详情出层,通过 id 拿到定义的容器,添加 overlay 到 map;
5.创建点击事件,点击点位后,利用 feature.get 方法拿到数据渲染点位详情即可。
完整代码
<template><div><div class="mapBox" id="map"><div id="popup" class="ol-popup"><a href="#" id="popup-closer" class="ol-popup-closer"></a><div id="popup-content"><div class="detailsBox"><div>所属区县:{{mapDataDetail.qx}}</div><div>加油站地址:{{mapDataDetail.jyzdz}}</div><div>加油站负责人:{{mapDataDetail.jyzfzr}}</div><div>联系电话:{{mapDataDetail.lxdh}}</div></div></div></div></div></div>
</template><script>
import areaGeo from "./map.json";
import { Map, View, Feature, ol } from "ol";
import TileLayer from "ol/layer/Tile";
import * as control from "ol/control";
import { Polygon, MultiPolygon } from "ol/geom";
import VectorLayer from "ol/layer/Vector";
import { Cluster, OSM, Vector as VectorSource, XYZ } from "ol/source";
import "ol/ol.css";
import {Style,Stroke,Fill,Icon,Circle as CircleStyle,Text,
} from "ol/style";
import GeoJSON from "ol/format/GeoJSON";
import Point from "ol/geom/Point";
import { toStringHDMS } from "ol/coordinate";
import { toLonLat } from "ol/proj";
import Overlay from "ol/Overlay";
export default {data() {return {mapData: [], //地图点位mapPointVectorLayer: null, //地图点位图层控制器geoRouteLayer: null, //geo市局边界图层clusterSource: null,map: null,overlay: null, //业务点聚合图层详情图层mapDataDetail: {qx: "",jyzdz: "",jyzfzr: "",lxdh: "",jyzzz: "",}, //点位详情数据};},methods: {//初始化地图initMap() {// 地图实例this.map = new Map({target: "map", // 对应页面里 id 为 map 的元素controls: control.defaults().extend([// 根据需要打开关闭即可new control.FullScreen(), //全屏控制]),layers: [new TileLayer({source: new OSM(),}),],view: new View({// 地图视图projection: "EPSG:4326", // 坐标系,有EPSG:4326和EPSG:3857center: [118.27, 39.71], // 默认打开的中心坐标zoom: 10.1, // 地图缩放级别(打开页面时默认级别)minZoom: 10, //最小缩放级别maxZoom: 20, //最大缩放级别}),});},//模拟请求接口mapList() {let data = [{district: "路北区",lat: "118.080181",lng: "39.588275",oilStationAddress: "唐山市路北区安立路",oilStationCharge: "吴彦祖",oilStationChargePhone: "18888888888",oilStationName: "唐山加油站",oilStationStatus: "0",},{district: "路北区",lat: "118.202271",lng: "39.651675",oilStationAddress: "唐山市路北区上海路",oilStationCharge: "谢霆锋",oilStationChargePhone: "18888888888",oilStationName: "唐山",oilStationStatus: "1",},];this.mapData = data;this.showPoints();this.addPopup();this.map.on("click", (evt) => {this.mapPointerClick(evt);});},//添加弹出层addPopup() {this.overlay = new Overlay({element: document.getElementById("popup"),offset: [0, -13],});//添加 overlay 到 mapthis.map.addOverlay(this.overlay);// 关闭弹出层var closer = document.getElementById("popup-closer");closer.onclick = () => {this.overlay.setPosition(undefined);closer.blur();return false;};},//展示聚合点位showPoints() {// 聚合图层数据源this.clusterSource = new Cluster({distance: 100,source: new VectorSource({features: [],}),});this.mapPointVectorLayer = new VectorLayer({source: this.clusterSource,style: (feature) => {return this.setClusterStyle(feature);},});let features = [];this.mapData.forEach((item) => {if (item.lng != "" && item.lat != "") {let newObj = Object.assign({}, item);newObj.geometry = new Point([Number(item.lat), Number(item.lng)]);features.push(new Feature(newObj));}});this.clusterSource.getSource().addFeatures(features);this.map.addLayer(this.mapPointVectorLayer);},//鼠标点击事件。若悬浮到设备上,则现在设备的具体信息mapPointerClick(evt) {let pixel = this.map.getEventPixel(evt.originalEvent);let featureMouseOver = this.map.forEachFeatureAtPixel(pixel,function (feature, layer) {return feature;});let coordinate;if (featureMouseOver) {if (featureMouseOver.getProperties().features) {//聚合情况下if (featureMouseOver.getProperties().features.length == 1) {console.log(1111);//只有一个要素000000000000000let f = featureMouseOver.getProperties().features[0]; //获取该要素this.clusterSource.getSource().forEachFeature((feature) => {if (f == feature) {coordinate = [feature.get("lat"), feature.get("lng")];this.mapDataDetail.qx = feature.get("district");this.mapDataDetail.jyzdz = feature.get("oilStationAddress");this.mapDataDetail.jyzfzr = feature.get("oilStationCharge");this.mapDataDetail.lxdh = feature.get("oilStationChargePhone");this.mapDataDetail.jyzzz = feature.get("oilStationStatus");console.log(feature.get("oilStationAddress"));this.overlay.setPosition(coordinate);}});}}}if (!coordinate) {this.overlay.setPosition(undefined);}},//设置聚合图层的样式setClusterStyle(feature) {var features = feature.get("features");var size = features.length;var style;if (size == 1) {style = [new Style({image: new Icon({src: "https://s1.ax1x.com/2022/07/06/ja5kvQ.png", //详情点位icon}),}),];} else {// 样式处理style = new Style({image: new CircleStyle({radius: 18,stroke: new Stroke({color: "#fff",}),fill: new Fill({color: "#3399CC",}),}),text: new Text({font: "15px sans-serif",text: size.toString(),fill: new Fill({color: "#fff",}),}),});}return style;},//设置区域addArea(geo = []) {if (geo.length == 0) {return false;}let features = [];var geoserver = geo[0].features;geoserver.forEach((g) => {let lineData = g;let routeFeature = "";if (lineData.geometry.type == "MultiPolygon") {routeFeature = new Feature({geometry: new MultiPolygon(lineData.geometry.coordinates),});} else if (lineData.geometry.type == "Polygon") {routeFeature = new Feature({geometry: new Polygon(lineData.geometry.coordinates),});}routeFeature.setStyle(new Style({fill: new Fill({color: "#4e98f444", //填充颜色}),stroke: new Stroke({width: 3, //边界宽度color: [71, 137, 227, 1], //边界颜色}),}));features.push(routeFeature);});// 设置图层this.geoRouteLayer = new VectorLayer({source: new VectorSource({features: features,}),});// 添加图层this.map.addLayer(this.geoRouteLayer);},},mounted() {this.initMap(); //加载默认图层this.addArea(areaGeo); //加载边界图层this.mapList(); //模拟接口},
};
</script><style scoped>
.mapBox {width: 100%;height: 100vh;
}
.detailsBox {padding: 14px;font-size: 14px;color: white;box-shadow: 0px 0px 30px 0px #0085f7 inset;background: rgba(6, 13, 45, 0.8);
}
</style>
总结
OpebLayers 作为 webGIS 客户端的 JavaScript 包,如今的 OpebLayers 功能也在日益完善,在很多项目中已经可以完全可以替代 ArcGIS API for JavaScript,也希望日后 OpebLayers 的更新能带给用户更丰富的体验。
初识webGIS库—OpenLayers相关推荐
- DirectX12(D3D12)基础教程(四)——初识DirectXMath库、使用独立堆创建常量缓冲、理解管线状态对象、理解围栏同步
目录 1.前言及本章内容提要 2.初识DirectXMath库 3.使用独立堆创建常量缓冲 4.理解管线状态对象 5.理解围栏同步 6.完整代码 1.前言及本章内容提要 经过了之前3篇教程的跨度有点大 ...
- $python数据分析基础——初识numpy库
numpy库是python的一个著名的科学计算库,本文是一个quickstart. 引入:计算BMI BMI = 体重(kg)/身高(m)^2 假如有如下几组体重和身高数据,让求每组数据的BMI值: ...
- day38 mycql 初识概念,库(增删改查),表(增删改)以及表字段(增删改查),插入更新操作...
在Navicat中把已经生成的表逆向成模型 数据库上,右键-逆向数据库到模型 ego笔记: 增删改查 文件夹(库)增create database day43 charset utf8;改alter ...
- 【WebGIS】Openlayers流动线与风场效果
目录 基础开发 一.流动线 二.风场 源码 基础开发 一.流动线 效果展示 基础原理 通过openlayers API,设置线段样式 ol/style/Stroke下的 lineDash 和 line ...
- Turtle库_初识Turtle库
在python中,有许多自带的库,无需安装,它们的功能俱全,可以帮助我们完成很多工作,今天我们就来学习比较容易上手的Turtle库. (Turtle在英文中是乌龟
- 初识标准库vector
vector:相同类型对象的集合(不能包含引用,引用不是对象),有索引,是一个类模板,通常称容器. 初始化:与string有些类似,但也有些不同 #include<iostream> #i ...
- 【ChatBot开发笔记】聊天机器人准备工作——初识NLTK库、语料与词汇资源
目录 简述 一.NLTK 1.安装 2.搜索 3.词统计 二.语料与词汇资源 1.举例 2.类似的语料库还有: 3.语料库的通用接口: 4.其他词典资源: 5.加载自己的语料库 结语 简述 2021. ...
- OpenLayers加载天地图
openlayer 是基于JavaScript的webGIS库 ,通过openlayer可以很容易的调用地图,并做相应的操作. 在head中载入openlayer的js文件: <link rel ...
- 手把手教你用vue+JavaScript+openlayers+iview制作实时天气预报图
啥都不说先看效果 还有事件统计功能,以及本地天气预报功能. 这算是前端技术中的webgis相关的知识,这些实现都是用的纯前端加上中国天气网api和高德地图的地理编码的api请求数据.因为这个小demo ...
最新文章
- 【iOS 开发】iOS 10.3 如何更换 app 图标
- 程序计算机限制无法打开,由于一个软件限制策略的阻止,windows无法打开此程序...解决方案参考...
- 20165235实验四 Android程序设计
- 1、ios开发之 内购
- 5G NR 逻辑信道、传输信道和物理信道
- 服务器操作系统字符集,设置服务器字符集
- C#学习笔记——25个经典问题
- Async Program 基本知识 (Process、Thread、Context Switch)
- 关于图片轮换与Tab标签
- idata界面_iData手持移动终端组合键恢复出厂设置教程
- Lucene应用开发揭秘 上线啦!((更新程度:完毕))
- UWP 颜色选择器(ColorPicker) 和 自定义的Flyout(AdvancedFlyout)
- XML PUBLISHER输出excel存在科学计数
- Word2vec 源码详解
- 生成特定区间的随机数
- 国密 SM4 高并发服务 加压测服务 加生成秘钥 结合上篇一起使用 国密 SM2 SM3 SM4 后续升级版本,内容丰富单独写一篇百万压测4000毫秒加解密
- Java商城 架构演化
- 农历日期用html怎么显示,怎么显示阴历(农历)日期的js代码?
- markdown语法测试
- python三维可视化
热门文章
- Robotiq+UR3e+Kinect V2 Gazeobo仿真成功,解决robotiq抖动问题
- UR3e+robotiq+抓取仿真实验
- html有分隔符的输入框,char语句输入分隔符
- python-视频声音根据语音识别自动转为带时间的srt字幕文件
- 各大搜索引擎提交网站的入口地址
- SILKYPIX Developer Studio Pro for Mac v11.0.3 专业的RAW图像处理软件
- 摄像头 保存到外网服务器_【小喵科技】物联网教程系列四:喵家外网IOT服务器...
- python-输入圆半径,求圆周长和圆面积
- java.lang.ClassNotFoundException: Didn't find class com.test.test.activity.MainActivity
- 网络设备配置--1、配置交换机enable、console、telnet密码