openlayers很久之前就听说过一个不错的开源架构,由于这一年来做的项目都是桌面端的,使用的GMap .Net和ArcGisEngine,所以对openlayers很少有研究,年底时间暂时充裕,花费一点时间对此开源架构进行学习和使用。
OpenLayers简介
对于OpenLayers的简介就不多说废话了,这就交到度娘手中吧,它就是一个模块化、高性能并且功能丰富的WebGIs客户端的JavaScript包,用于显示地图及空间数据,是一个免费的、开源的JavaScript库,目前版本为5.x
OpenLayers体系结构
Map:整个地图的容器,其中核心如下
- Layer:地图图层
- Source:对应图层的数据源
- Style:矢量图层样式
- View:地图表现相关的地图视图
除此之外还有一些与地图交互操作控件以及请求事件等,在最底层是OpenLayers的数据源(Image、KML、GML、JSON...)这些数据是经过Renderer渲染显示到地图容器的图层中。
OpenLayers的工作原理
Gis的核心是空间数据,关键是如何将空间数据应用到各行各业中,充分体现出空间数据的价值,针对复杂的空间数据OpenLayers是如何将这些空间数据抽象为类?如何解析各种空间数据源?又是如何渲染到客户端展示?数据加载到地图中是如何操作地图?下面我们就从这几个方面进行简单的分析。
1、数据组织
首先我们了解OPenLayers的数据结构和组织,从表面上看,空间数据是由点、线、面三要素构成,将这些要素呈现在web中需要抽象为相应的类,包括要素之间的关系,再ol中矢量数据抽象是由ol.geom.Geometry基类下的集合对象子类实现的,下图为基类与子类的继承关系。
- Point与MultiPoint(点与多点)
- LineString与MultiLineString(线与多线)
- Polygon与MultiPolygon(区与多区)
- LinearRing(线性环)
- Cirle(圆)
对于Web网页地图应用而言,除了矢量数据,还有瓦片数据,以及图片等各类数据,接下来我们简单了解下ol的数据组织与实现原理
ol的地图数据通过图层(Layer)组织渲染的,且通过数据源(Source)设置具体的地图数据来源,因此图层和数据源就想夫妻一样形影不离,密切相关,地图数据根据数据源可分为Image、Tile、Vector三大类,对应设置到这三大类的图层中,地图图层与数据源的关系如下图所示,其中矢量图层Vector通过样式(Style)来设置矢量数据渲染的方式和外观
2、数据解析
通过上面组织图可以看出,地图的数据源可以分为Image、Tile、Vector三大类,其中Image和Tile两者得本质是一样的,都是图片,Vector为矢量基类,由于数量数据类型繁多,需要通过Format属性进行设置,即通过ol.format.Feature类得子类进行各种格式矢量数据的解析
3、数据渲染
基于OpenLayers的地图整个表现过程为:先通过URL调用数据,然后用各种格式的数据解析器解析数据,再用相应的渲染器在图层中进行渲染,最后结合相应的控件表现出来,呈现出地图样式。
openLayers渲染功能主要是依靠渲染器(Renderer)实现,通过Map的Renderer属性设置渲染方式,然后根据不同的渲染方式(Canvas、WebGL)、与图层类型(Image、Tile、Vector)匹配渲染器将图层数据渲染出来。
4、地图表现
大家都知道Web客户端通常是有Html表现出来的网页内容,通过javascript实现动态交互效果,那么基于openlayers的地图应用也同样是这个原理。
在Web网页中,地图容器通过div标签来显示的,通过Map类的target属性关联作为地图容器的html元素,即将此地图容器div与javaScript的map对象绑定,然后将layers、controls等内容加载到Map中。如下代码所示
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<style>
.map {
height: 800px;
width: 100%;
}
</style>
<script type="text/javascript" src="javascript/ol.js"></script>
</head>
<body>
<h2>My Map</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
// // 地图设置中心,设置到北京,在本地离线地图 offlineMapTiles刚好有一张zoom为4的成都瓦片
var center = ol.proj.transform([117.06667, 39.66667], 'EPSG:4326', 'EPSG:3857');
//创建地图
var map = new ol.Map({
view: new ol.View({
center: center,
zoom: 4
}),
target: 'map'
});
// 添加一个使用离线瓦片地图的层
var offlineMapLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
// 设置本地离线瓦片所在路径,由于例子里面只有一张瓦片,页面显示时就只看得到一张瓦片。
//url: 'http://localhost:7080/{z}/{x}/{y}.jpg'
//url:'http://mt0.google.cn/maps/vt?lyrs=s@773&gl=cn&x={x}&y={y}&z={z}'
url:'http://www.google.cn/maps/vt?lyrs=m@189&gl=cn&x={x}&y={y}&z={z}'
})
});
map.addLayer(offlineMapLayer);
var beijing = ol.proj.fromLonLat([116.28, 39.54]);
//var map = new ol.Map({
// target: 'map',
// layers: [
// new ol.layer.Tile({
// source: new ol.source.OSM()
// })
// ],
// view: new ol.View({
// center: beijing,
// zoom: 4
// })
//});
//实例化矢量点要素,通过矢量图层添加到地图容器中
//这样就实现了预先加载图文标注
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(beijing),
name: '北京市', //名称属性
population: 2115 //人口数(万)
});
//设置点要素样式
iconFeature.setStyle(createLabelStyle(iconFeature));
//矢量标注的数据源
var vectorSource = new ol.source.Vector({
features: [iconFeature]
});
//矢量标注图层
var vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
//矢量标注样式设置函数,设置image为图标ol.style.Icon
function createLabelStyle(feature){
console.log(feature);
return new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 60], //锚点
anchorOrigin:'top-right', //锚点源
anchorXUnits: 'fraction', //锚点X值单位
anchorYUnits: 'pixels', //锚点Y值单位
offsetOrigin: 'top-right', //偏移原点
opacity: 0.75,
src: 'image/x_dxd.png' //图标的URL
}),
text: new ol.style.Text({
textAlign: 'center', //位置
textBaseline: 'middle', //基准线
font: 'normal 14px 微软雅黑', //文字样式
text: feature.get('name'), //文本内容
fill: new ol.style.Fill({ //文本填充样式(即文字颜色)
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#F00',
width: 2
})
})
});
}
map.on('click', function(evt){
var coordinate = evt.coordinate; //鼠标单击点的坐标
//新建一个要素ol.Feature
var newFeature = new ol.Feature({
geometry: new ol.geom.Point(coordinate), //几何信息
name: '标注点'
});
newFeature.setStyle(createLabelStyle(newFeature)); //设置要素样式
vectorSource.addFeature(newFeature);
});
</script>
</body>
</html>
上面代码就是一段简单地图加载代码,下面我们在调试状态下看一下页面具体标签
上图中很明显,我们定义了一个id为map的div容器,在div容器下面openlayers创建了ol-viewport容器(class为ol-viewport),在这个容器中分别创建了三个关键的内容层,分别渲染呈现地图容器中的内容:
- 地图渲染层:根据地图渲染方式创建的canvas元素
- 内容叠加层:类名为ol-overlaycontainer的div层,装载叠加层(ol.Overlay)内容
- 地图控件层:类名为ol-overlaycontainer-stopevent的div层,装载显示地图控件或叠加内容
5、地图事件
从我们操作方面我们知道,当地图加载到web页面后,我们会对地图进行不同的操作,如:单击、双击、指针移动、改变要素等一些交互事件,下面就总结下用户和地图的交互事件
- 地图事件(ol.MapEvent):包含moveend、postrender事件
- 地图浏览器事件类(ol.MapBrowserEvent):包括singleclick、click、dbclick事件等
- 对象事件类(ol.Object.Event):包括change、propertychange事件
- 选择控件事件类(ol.interaction.Select.Event):包括select事件
- 绘制控件事件类(ol.interaction.Draw.Event):包括drawstart、drawend事件
- 修改控件事件类(ol.interaction.Modify.Event):包括modifystart、modiftend事件
- 集合事件类(ol.Collection.Event):包括add、remove事件
针对各类事件openlayers提供了on与once方法添加事件监听,通过un与unByKey方法移除事件监听。
总结
目前来说,openlayers市场使用率还是挺高,经过BOSS直聘查看,设计到webgis的公司都会有一条熟悉openlayers可见这款开源webgis架构还是很火爆的,总体来说openlayers的功能是很强大的,强大到什么地步,咱们一点点研究,在这里只是简单的说了一些最基础的东西,让大家对openlayers有一个印象。最后想说的就是openlayers开发方式有2种,一种就是传统的开发方式:直接下载资源库,将资源进行加载其实本质就是html+javascript,另一种就是NodeJS:理用npm或cnpm(淘宝镜像)进行下载,再用import将模块包导入。