官网地址:openlayers.org/ 中文相关资料链接和参考资料:
快速开始
- 引入openlayers相关资源
- 创建一个作为地图容器
- 使用JavaScript创建一个简单的地图
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.13.0/css/ol.css" type="text/css">
<style>
.map {
height: 400px;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.13.0/build/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<h2>My Map</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var map = new ol.Map({
//target参数是地图容器的id
target: 'map',
//layers设置图层
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
//view设置地图中心点,缩放级别,分辨率和旋转
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
</script>
</body>
</html>
常用类简介
Layer 类
layer 是各种图层的基类,只用于让子类型继承和实现,一般自身不会实例化。主要有 WebGLPoints Layer、热力图(HeatMap Layer)、图片图层(Image Layer)、切片图层(Tile Layer) 和 矢量图层(Vector Layer) 五种类型。主要功能是对矢量数据和栅格数据的可视化。图层渲染结果的样式,主要与数据渲染方式有关,与数据源关系不大。
属性
- source,指定了图层的数据来源,图层作用是以一定的样式渲染数据,source则指定了数据;
- className,图层各个元素的样式;
- opacity,透明度,默认为 1 ,即完全透明;
- visible,是否可见;
- zIndex,图层的叠加次序,默认是0,最底层,如果使用setMap方法添加的图层,zIndex值是Infinity,在最上层;
- extent,图层渲染的区域,即浏览器窗口中可见的地图区域。extent 是一个矩形范围,格式是[number, number, number, number] 分别代表 [left, bottom, right, top] 。为了提升渲染效率和加载速度,extent范围之外的瓦片是不会请求的,当然也不会渲染;
- minResolution,图层可见的最小分辨率;
- maxResolution,图层可见的最大分辨率;
- minZoom,图层可见的最小zoom level;
- maxZoom,图层可见的最大zoom level;
事件触发
- postrender ( module:ol/render/Event~RenderEvent ) - 渲染图层后触发。
- prerender ( module:ol/render/Event~RenderEvent ) - 在渲染层之前触发。
- propertychange ( module:ol/Object.ObjectEvent ) - 更改属性时触发。
行为
各种类型的图层
openlayers的图层主要分为两类:Vector(矢量)和Raster(栅格),矢量图层是指在渲染发生在浏览器的图层,source返回的数据类型是矢量,如geojson的坐标串;栅格图层则是由服务器渲染,返回到浏览器的是一张张的瓦片图片,栅格图层主要是展示。 矢量图层类型有:
- Graticule,地图上覆盖的网格标尺图层;
- HeatMap,热力图;
- Vector,矢量图
- VectorImage,单张的矢量图层
- VectorTile,矢量瓦片图层
- WebGLPoints,WebGL渲染的海量点图层
栅格图层类型较为简单,只有Tile图层。
各种图层详细介绍:
WebGLPoint Layer:对于海量数据的个性化渲染也成为了可能,WebGLPoint Layer的style也变成了一个非常实用的功能。
Heatmap Layer:将矢量数据渲染成热度图的类,继承了 ol.layer.Vector 类,ol.layer.Vector 继承了ol.layer.Layer 类, 额外的参数是 olx.layer.HeatmapOptions
blur 控制圆点的边缘,对边缘做模糊化; radius 则规定了圆点的半径
var heatmap = new ol.layer.Heatmap({
source: new ol.source.KML({
url: 'data/kml/2012_Earthquakes_Mag5.kml',
projection: 'EPSG:3857',
extractStyles: false
}),
blur: parseInt(blur.value, 10),
radius: parseInt(radius.value, 10)
});
map = new ol.Map({ //初始化map
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
}),
heatmap
],
view: new ol.View({
center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
zoom: 4
})
});
Image Layer:主要是指服务器端渲染的图像,可能是已经渲染好的图像,或者是每一次请求,都根据请求内容定制化地生成一幅图片,该图层类型支持任意的范围和分辨率。
var imageLayer = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'sample.jpg',
projection: projection,
imageExtent: extent
})
})
map = new ol.Map({ //初始化map
target: 'map',
layers: [ imageLayer ],
view: new ol.View({
projection: projection,
center: ol.extent.getCenter(extent),
zoom: 2
})
});
Tile Layer:切片地图是比较常用的图层类型,切片的概念,就是利用网格将一幅地图切成大小相等的小正方形 Vector Layer:即矢量图层,矢量图层实际上是在客户端渲染的图层类型,服务器返回的数据或者文件会通过 OpenLayers 进行渲染,得到相应的矢量图层。vectorlayer 相对于其他类型的图层,还包含了一个 style 参数,这个参数便是控制矢量图层的外观样式的,style 是一个 ol.style.Style 类型。
vectorLayer = new ol.layer.Vector({ //初始化矢量图层
source: new ol.source.GeoJSON({
projection: 'EPSG:3857',
url: 'data/geojson/countries.geojson' //从文件加载边界等地理信息
}),
style: function(feature, resolution) {
style.getText().setText(resolution < 5000 ? feature.get('name') : ''); //当放大到1:5000分辨率时,显示国家名字
return [style];
}
});
Source
source 是 Layer 的重要组成部分,表示图层的来源,也就是服务地址。除了在构造函数中制定外,可以使用 layer.setSource(source) 稍后指定。 source 是 layer 中必须的选项,定义着地图数据的来源,与数据有关的函数,如addfeature、getfeature等函数都定义在 source 中,而且数据源支持多种格式。
类型:
- ol.source.Vector:矢量图层的数据来源
- ol.source.Tile:提供被切分为切片的图片地图数据
- ol.source.Image:提供单一的图片地图
以下介绍主要基于ol.source.Vector
用法说明
包含四个事件,addfeature,changefeature,clear,removefeature。
- addfeature,当一个要素添加到 source 中触发;
- changefeature,当要素变化时触发;
- clear,当 source 的 clear 方法调用时候触发;
- removefeature,当要素移除时候发生。
参数
- attribution,地图右下角的 logo 包含的内容;
- features,地理要素,从字符串读取的数据;
- format,url属性设置后,加载要素使用的数据格式,采用异步的 AJAX 加载;
- loader,加载要素使用的加载函数;
- logo,logo包含的内容;
- strategy,加载要素使用的策略,默认是 一次性加载所有要素;
- url,要素数据的地址;
- wrapX,是否在地图水平坐标轴上重复,默认是 true。
方法
features 方法:假如有一个包含空间数据的字符串,geojsonObject,是GeoJSON字符串格式,那么可以用来初始化一个图层。
var vectorSource = new ol.source.Vector({
features: (new ol.format.GeoJSON()).readFeatures(geojsonObject)
});
var vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: style
});
map.addLayer(vectorLayer);
url + format 方法:如果有一个文件作为数据源,那么可以配置 url 属性来加载数据
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'data/geojson/countries.geojson',
format: new ol.format.GeoJSON()
})
});
这两种方法中都会指定数据来源格式, 矢量数据源支持的格式包含很多:gml、EsriJSON、geojson、gpx、igc、kml、osmxml、ows、polyline、topojson、wfs、wkt、wms capabilities(兼容 wms 的格式)、 wms getfeatureinfo、 wmts capabilities、xlink、xsd等格式。这些格式都有**readFeatures **、**readFeature 和readGeometry **方法用于读取数据。
interaction
地图的交互功能包含很多,如地图双击放大,鼠标滚轮缩放,矢量要素点选,地图上绘制图形等等。只要是涉及到与地图的交互,就会涉及到 intercation 类,它定义了用户与地图进行交互的基本要素和事件。
属性
- doubleclickzoom interaction,双击放大交互功能;
- draganddrop interaction,以“拖文件到地图中”的交互添加图层;
- dragbox interaction,拉框,用于划定一个矩形范围,常用于放大地图;
- dragpan interaction,拖拽平移地图;
- dragrotateandzoom interaction,拖拽方式进行缩放和旋转地图;
- dragrotate interaction,拖拽方式旋转地图;
- dragzoom interaction,拖拽方式缩放地图;
- draw interaction,绘制地理要素功能;
- interaction defaults ,规定了默认添加的交互功能;
- keyboardpan interaction,键盘方式平移地图;
- keyboardzoom interaction,键盘方式缩放地图;
- select interaction,选择要素功能;
- modify interaction,更改要素;
- mousewheelzoom interaction,鼠标滚轮缩放功能;
- pinchrotate interaction,手指旋转地图,针对触摸屏;
- pinchzoom interaction,手指进行缩放,针对触摸屏;
- pointer interaction,鼠标的用户自定义事件基类;
- snap interaction,鼠标捕捉,当鼠标距离某个要素一定距离之内,自动吸附到要素。
交互
interaction defaults - 默认添加的交互功能 默认添加的交互包括: DragRotate, DragZoom, DoubleClickZoom, PinchRotate, PinchZoom, DragPan, KeyboardZoom, KeyboardPan, MouseWheelZoom
//去除某个默认项
interactions: ol.interaction.defaults([
doubleClickZoom: false
]),
draw interaction - 绘图功能 绘图交互允许绘制几何地理要素,可选参数为一个对象,包含以下属性。
- features,绘制的要素的目标集合;
- source,绘制的要素的目标图层来源,即目标图层的 source属性 ;
- snapTolerance,自动吸附完成点的像素距离,也就是说当鼠标位置距离闭合点小于该值设置的时候,会自动吸附到闭合点,默认值是 12;
- type,绘制的地理要素类型,ol.geom.GeometryType类型,包含 Point、 LineString、 Polygon、MultiPoint、MultiLineString 或者 MultiPolygon;
- minPointsPerRing,绘制一个多边形需要的点数最小值,数值类型,默认是 3;
- style,要素素描的样式,是 ol.style.Style对象之一;
- geometryName,绘制的地理要素的名称,string类型;
- condition,一个函数,接受一个ol.MapBrowserEvent类型的参数,返回一个布尔值表示是否应该调用事件处理函数。默认情况下,增加一个顶点,类型为 ol.events.ConditionType。
//给地图添加该交互功能,首先需要实例化一个ol.interaction.Draw,必须指定 source和type属性
var draw = new ol.interaction.Draw({
source: source,
type: "Polygon"
});
//然后将该功能添加到地图中。
map.addInteraction(draw)
dragrotateandzoom interaction - 鼠标拖拽进行缩放和旋转地图
var interactions = ol.interaction.defaults().extend([
new ol.interaction.DragRotateAndZoom()
]);
var map = new ol.Map({
...
interactions:interactions,
...
})
dragbox interaction - 拉框交互 draganddrop interaction - 拖拽文件到地图 将空间数据使用鼠标或者手指拖拽到地图中,解析成一个图层添加到地图中。目前只支持矢量数据,未来可能支持更多的空间数据格式。目前,支持的格式包括 GeoJSON, GML, KML, GPX, OSMXML, TopoJSON 和 IGC。
var dragAndDropInteraction = new ol.interaction.DragAndDrop({
formatConstructors: [
ol.format.GeoJSON,
ol.format.KML
]
});
var interactions = ol.interaction.defaults().extend([
new ol.interaction.DragRotateAndZoom(),
dragAndDropInteraction
]);
keyboard interaction - 键盘交互功能 modify 和 select interaction select 就像名字暗示的一样,是用来选中要素的;而 modify 是修改要素的,主要是通过拖拽方式修改点的坐标。
//模拟选中并修改要素的交互功能需要添加如下代码
var select = new ol.interaction.Select();
var moddify = new ol.interaction.Modify({
features:select.getFeatures()
});
pinchrotate ,pinchzoom interaction - 两个手指缩放和旋转地图 pointer interaction - 自定义鼠标事件 针对鼠标的行为按下(Down)、移动(Move)和抬起(Up),自定义事件。这三个事件发生有先后顺序,首先是触发按下,之后是移动事件,最后是抬起事件。只要配置相关的属性,包含handleDownEvent,handleDragEvent,handleMoveEvent,handleUpEvent分别对应鼠标的 down、drag、move和up四种事件。
new ol.interaction.Pointer({
handleDownEvent: functionName
})
snap interaction - 鼠标捕捉 当修改和绘制矢量要素时,鼠标距离某个要素一定距离之内,自动吸附到要素。
control类(地图控件)
控件
OpenLayers 中包含的控件有:
- controldefaults,地图默认包含的控件,包含缩放控件和旋转控件;
- fullscreencontrol,全屏控件,用于全屏幕查看地图;
- mousepositioncontrol,鼠标位置控件,显示鼠标所在地图位置的坐标,可以自定义投影;
- overviewmapcontrol,地图全局视图控件;
- rotatecontrol,地图旋转控件;
- scalelinecontrol,比例尺控件;
- zoomcontrol,缩放控件;
- zoomslidercontrol,缩放刻度控件;
- zoomtoextentcontrol,缩放到全局控件。
方法
调整控件样式的两种方法: 1.** 修改控件的可选参数的默认值**
<div id="mouse-position" class="mouse-position-wrapper">
<div class="custom-mouse-position"></div>
</div>
.mouse-position-wrapper{
width:300px;
height:29px;
color:#FFFFFF;
position:absolute;
right:20px;
bottom:6px;
z-index:999;
}
//调整控件位置
controls: ol.control.defaults().extend([
new ol.control.FullScreen(),
new ol.control.MousePosition({
coordinateFormat: ol.coordinate.createStringXY(4),
projection: 'EPSG:4326',
className: 'custom-mouse-position',
target: document.getElementById('mouse-position')
})
]),
2.覆盖默认样式- 在自己的 CSS 样式表中添加如下代码(因为自己的CSS文件样式优先级比外部链接引入的样式优先级高)
/* rewrite the default css in `ol.css` */
.ol-rotate{
right:40px;
}
View
初始化一幅地图,必备的三要素之一就是视图(view),这个对象主要是控制地图与人的交互,如进行缩放,调节分辨率、地图的旋转等控制。
属性
- view 的构造函数需要的参数是一个 olx.ViewOptions对象,主要属性如下:
- center 是一个坐标[x, y],表示地图视图的中心位置;
- extent 是一个数组对象 – [left, bottom, right, top],表示地图视图的初始范围;
- projection 是地图的投影坐标系统;
- resolution 表示地图的分辨率,单位并不是普通的单位面积的像素,而是单位像素表示的距离单位,比如 米/像素;
- rotation 表示地图的旋转角度;
- zoom 表示地图初始的缩放级别。
style
地图样式是由 style 类控制的,其包含了地图样式的方方面面,例如,填充色、图标样式、图片样式、规则图形样式、边界样式、文字样式等,样式一般针对矢量要素图层。 矢量图层样式可以事先写好,写成静态的,矢量图层直接按照定义好的样式渲染,也可以动态使用样式的 set() 方法,但是要注意刷新矢量图层,重新渲染,否则动态样式不生效。 样式主要针对矢量图层数据,既可以配置一个全局的样式,也可以针对每个feature单独配置;既可以应用统一的样式,也可以根据要素和分辨率应用条件样式。样式应用是非常灵活的。
配置项
- geometry,要素的属性,或者要素,或者一个返回一个地理要素的函数,用来渲染成相应的地理要素;
一般与 image 样式配合使用,表示 image 放置的位置
//该样式配置了一个 image 属性,表示在相应的位置放置的图片的样式,
//这里是一个半径为 5,填充色为橙色的圆形的图片样式
new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: 'orange'
})
}),
geometry: function(feature) {
// return the coordinates of the first ring of the polygon
var coordinates = feature.getGeometry().getCoordinates()[0];
return new ol.geom.MultiPoint(coordinates);
}
})
- fill,填充要素的样式;
配置图层的要素的填充颜色和透明度
- iamge,图片样式,类型为 ol.style.Image;
样式主要针对矢量图层(vector layer),矢量图层中包含一个或多个要素(feature),要素中包含一个地理属性(geometry)表示地理位置,还可能包含一个或多个其他属性,比如要素的名称、类型等等,要素可以使用单独的样式,这时候要使用 feature.setStyle(ol.style.Style) 来设置单独使用的样式,否则直接继承矢量图层的样式
//定义一个图标样式
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(({
src: 'data/icon.png'
}))
});
//定义一个点要素
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point([0, 0]),
});
//将样式应用于点要素
iconFeature.setStyle(iconStyle);
//定义一个矢量图层,并加入该要素
var iconLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [iconFeature]
})
});
- stroke,要素边界样式,类型为 ol.style.Stroke;
color: '#319FD3', width: 1
- text,要素文字的样式,类型为 ol.style.Text;
text: new ol.style.Text({
font: '12px Calibri,sans-serif', //字体与大小
fill: new ol.style.Fill({ //文字填充色
color: '#000'
}),
stroke: new ol.style.Stroke({ //文字边界宽度与颜色
color: '#fff',
width: 3
})
})
- zIndex,CSS中的zIndex,即叠置的层次,为数字类型。
子类
- ol.style.Circle,针对矢量要素设置圆形的样式,继承 ol.style.Image;
- ol.style.Icon,针对矢量数据设置图标样式,继承 ol.style.Image;
- ol.style.Fill,针对矢量要素设置填充样式;
- ol.style.RegularShape,对矢量要素设置规则的图形样式,如果设置 radius,结果图形是一个规则的多边形,如果设置 radius1 和 radius2,结果图形将是一个星形;
- ol.style.Stroke,矢量要素的边界样式;
- ol.style.Text,矢量要素的文字样式。
var style = new ol.style.Style({
fill: new ol.style.Fill({ //矢量图层填充颜色,以及透明度
color: 'rgba(255, 255, 255, 0.6)'
}),
stroke: new ol.style.Stroke({ //边界样式
color: '#319FD3',
width: 1
}),
text: new ol.style.Text({ //文本样式
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 3
})
})
});
条件样式
条件样式是将样式配置为一个回调函数,其参数包含要素本身和分辨率,可以根据要素本身的属性和地图的分辨率,显示动态的样式,形式如 style: function(feature, resolution) {}。 例如,以下代码段配置当分辨率小于 5000 时候,在要素上显示一个标签,标识要素名称:
style: function(feature, resolution) {
style.getText().setText(resolution < 5000 ? feature.get('name') : '');
return styles;
}
Vector
在 GIS 中,地图一般分为两大类:栅格地图和矢量地图,栅格地图其实就是数码照片,只不过有的是卫星拍的。它们有一个共同特征,就是它们都是由很多个像素组成,像素大小是一致的,行高和列宽是一致的,从这个角度看,一幅遥感影像就像栅格。
矢量地图,是由很多要素组成的,每个要素都有自己的地理坐标,基于数学规则,无论矢量地图怎么放大,地图都不会失真。它是 OpenLayers 中非常重要的一种图层类型,利用矢量地图可以实现非常多的功能,如 动态标绘、调用 WFS 服务、编辑要素、可点击的要素、动态加载要素 等等。
矢量图层是在客户端渲染的,在 web 环境中,对应的就是浏览器。构成一个矢量图层的包含一个数据(source)和一个样式(style),数据构成矢量图层的要素,样式规定要素显示的方式和外观。一个初始化成功的矢量图层包含一个到多个要素(feature),每个要素由地理属性(geometry)和多个其他的属性,可能包含名称等。结构如下图:
属性
在初始化矢量图层时,可以有很多选项配置矢量图层的行为和外观,常用的有:
- brightness、contrast,图层亮度和对比度,都是一个数值;
- renderOrder,一个指定规则的函数 (function(ol.Feature, ol.Feature));
- hue,色调,是一个数值;
- minResolution,可见的最小分辨率;
- maxResolution,可见的最大分辨率;
- opacity,图层的透明度,0~1之间的数值,1表示不透明;
- saturation,饱和度;
- source,图层数据来源;
- style,图层样式,一个ol.style.Style或者一个ol.style.Style数组,或者一个返回 ol.style.Style 的函数;
- visible,图层可见性,默认为 true。
//初始化一个矢量图层
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'data/china_province_boundries.geojson', //数据来源
projection: 'EPSG:3857',
//数据解析器 因为 url 规定的数据来源是 geojson 格式,所以解析器也是 geojson 解析器 new ol.format.GeoJSON
format: new ol.format.GeoJSON({
extractStyles: false
})
}),
style: style
});
方法
取得要素 vector 的数据包含在 source 中,要取得 vector 的 feature 数据,要在 source 中,例如 vector.getSource().getFeatures(),该函数会返回一个 feature array,直接使用 [ ],取用即可,或者根据要素的 ID 取得(getFeatureById())。 取得要素的 geometry 利用 getGeometry() 可以获得要素的地理属性,这个函数当然返回要素包含的 geometry,geometry 包含很多类型,主要有 point、multi point、linear ring、line string、multi line string、polygon、multi polygon、circle。 取得 geometry 后,就可以获得要素的坐标了,可以根据坐标做一些地理判断,比如判断 一个坐标是否位于要素内(containsCoordinate(coordinate) 或者 containsXY(x, y)),取得要素的中心坐标等。
Overlay(覆盖物)
主要的用途就是在地图之上再覆盖一层,用以显示额外的可见元素,可见元素一般是 HTML 元素,利用 overlay,可以将可见元素放置到地图的任意位置,形成地图上再浮动一层的效果。例如在地图上相应的坐标放置一个标志,标签,利用 overlay 都可以做到,具体来说,点击地图上某位置,在点击位置弹出弹出框就是利用了 overlay。
配置项
- id,为对应的 overlay 设置一个 id,便于使用 ol.Map 的 getOverlayById 方法取得相应的 overlay;
- element,overlay 包含的 DOM element;
- offset,偏移量,像素为单位,overlay 相对于放置位置(position)的偏移量,默认值是 [0, 0],正值分别向右和向下偏移;
- position,在地图所在的坐标系框架下,overlay 放置的位置;
- positioning,overlay 对于 position 的相对位置,可能的值包括 bottom-left、bottom-center、bottom-right 、center-left、center-center、center-right、top-left、top-center、top-right,默认是 top-left,也就是 element 左上角与 position 重合;
- stopEvent,地图的事件传播是否停止,默认是 true,即阻止传播,可能不太好理解,举个例子,当鼠标滚轮在地图上滚动时,会触发地图缩放事件,如果在 overlay 之上滚动滚轮,并不会触发缩放事件,如果想鼠标在 overlay 之上也支持缩放,那么将该属性设置为 false 即可;
- insertFirst,overlay 是否应该先添加到其所在的容器(container),当 stopEvent 设置为 true 时,overlay 和 openlayers 的控件(controls)是放于一个容器的,此时将 insertFirst 设置为 true ,overlay 会首先添加到容器,这样,overlay 默认在控件的下一层(CSS z-index),所以,当 stopEvent 和 insertFirst 都采用默认值时,overlay 默认在 控件的下一层;
- autoPan,当触发 overlay setPosition 方法时触发,当 overlay 超出地图边界时,地图自动移动,以保证 overlay 全部可见;
- autoPanAnimation,设置 autoPan 的效果动画,参数类型是 olx.animation.panOptions;
- autoPanMargin,地图自动平移时,地图边缘与 overlay 的留白(空隙),单位是像素,默认是 20像素;
事件
- change,当引用计数器增加时,触发;
- change:element,overlay 对应的 element 变化时触发;
- change:map,overlay 对应的 map 变化时触发;
- change:offset,overlay 对应的 offset 变化时触发;
- change:position,overlay 对应的 position 变化时触发;
- change:positioning,overlay 对应的 positioning 变化时触发;
- propertychange,overlay 对应的属性变化时触发;
// example overlay event binding
var overlay = new ol.Overlay({
// ...
});
overlay.on("change:position", function(){
console.log("位置改变!");
})
方法
- getElement,取得包含 overlay 的 DOM 元素;
- getId,取得 overlay 的 id;
- getMap,获取与 overlay 关联的 map对象;
- getOffset,获取 offset 属性;
- getPosition,获取 position 属性;
- getPositioning,获取 positioning 属性;
- setElement;设置 overlay 的 element;
- setMap,设置与 overlay 的 map 对象;
- setOffset,设置 offset;
- setPosition,设置 position 属性;
- setPositioning,设置 positioning 属性。
常用操作
加载天地图底图
// 背景
let tian_di_tu_road_layer = new ol.layer.Tile({
title: "天地图路网",
source: new ol.source.XYZ({
url: "http://t4.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=xxx"
})
});
// 文字标注
let tian_di_tu_annotation = new ol.layer.Tile({
title: "天地图文字标注",
source: new ol.source.XYZ({
url: 'http://t4.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=xxx'
})
});
// 地图创建
let map = new ol.Map({
...
// 图层
layers: [tian_di_tu_road_layer, tian_di_tu_annotation],
...
});
加载 WFS 服务
WFS服务,可以通过OL进行加载,加载有简单方式也有GetFeature方式,该种方式自由度更大,可以结合一些过滤条件,这样一方面可以提高加载数据的效率。
一次性加载数据
// WFS 格式化工具
const wfsJsonFormat = new ol.format.WFS();
// GML 格式化工具
const gmlJsonFormat = new ol.format.GML();
// 矢量数据源
const vectorSource = new ol.source.Vector();
// 创建一个请求
const featureRequest = wfsJsonFormat.writeGetFeature({
srsName: 'EPSG:4326',//坐标系
featureNS: url,
// 注意这个值必须为创建工作区时的命名空间URI
featurePrefix: 'XXX_LAYER',
//工作区的名称
featureTypes: ['PUMP_GATE_STATION_POINT'],
//所要访问的图层
outputFormat: 'application/json'
//这里面有三个参数是必须的:featureNS、featurePrefix、featureTypes。这三个参数必须赋值否则错误。
});
// 利用 XMLSerializer.serializeToString 将 xml 格式转为 string
//let xmlSerializer = new XMLSerializer();
//let params = xmlSerializer.serializeToString(featureRequest);
// 发起请求
fetch(url, {
method: 'POST',
body: new XMLSerializer().serializeToString(featureRequest)
}).then(response => {
// xml 格式不能直接用 response.json() 转
return response.text();
//非xml格式
//return response.json();
}).then(data => {
// 读取图形信息
let features = gmlJsonFormat.readFeatures(data);
//非xml格式
//var features = new ol.format.GeoJSON().readFeatures(json);
if (features.length > 0) {
// 添加图形
vectorSource.addFeatures(features);
// 调整地图视角
map.getView().fit(vectorSource.getExtent());
}
})
// 矢量图层
const layer = new ol.layer.Vector({
// 设置数据源
source: vectorSource,
// 设置图层样式
style: new ol.style.Style({
image: new ol.style.Icon({
scale: 0.8,
src: require("imgurl")
})
})
});
// 将图层添加到地图上
map.addLayer(layer);
动态加载数据
// 矢量数据源
const vectorSource = new VectorSource({
// 设置格式化类型
format: new ol.format.GeoJSON(),
// url(extent) 在地图范围变化时调用,返回当前的地图范围
url: function (extent) {
return (
`url?service=WFS&version=1.0.0&request=GetFeature&typeName=luhao%3Asuqian&maxFeatures=50&outputFormat=application%2Fjson&bbox=${extent.join(',')},EPSG:4326`
);
},
strategy: ol.loadingstrategy.bbox
});
// 矢量图层
const layer = new ol.layer.Vector({
// 设置数据源
source: vectorSource,
// 设置图层样式也可以 function (feature) { /** 根据内容动态加载样式 **/ return Style}
style: new ol.style.Style({
image: new ol.style.Icon({
scale: 0.8,
src: require("imgurl")
})
})
});
// 将图层添加到地图上
map.addLayer(layer);
加载 geoService 服务
一次性加载数据
// GeoJSON 格式化工具
const geoJsonFormat = new ol.format.GeoJSON();
// 矢量数据源
const vectorSource = new ol.source.Vector();
// 请求参数
let params = {
service: "WFS",
version: "1.0.0",
request: "GetFeature",
typeName: "name",
maxFeatures: "50",
outputFormat: "application/json",
}
// 发起请求
request({url: 'url', params}).then(response => {
// 读取图形数据
const features = geoJsonFormat.readFeatures(response);
if (features.length > 0) {
// 添加图形
vectorSource.addFeatures(features);
// 调整地图视角
map.getView().fit(vectorSource.getExtent());
}
});
// 矢量图层
const layer = new ol.layer.Vector({
// 设置数据源
source: vectorSource,
// 设置图层样式也可以 function (feature) { /** 根据内容动态加载样式 **/ return Style}
style: new ol.style.Style({
image: new ol.style.Icon({
scale: 0.8,
src: require("imgurl")
})
})
});
// 将图层添加到地图上
map.addLayer(layer);
动态加载数据
// 矢量数据源
const vectorSource = new ol.source.Vector({
// 设置格式化类型
format: new ol.format.GeoJSON(),
// url(extent) 在地图范围变化时调用,返回当前的地图范围
url: function (extent) {
return 'url?service=WFS&version=1.0.0&request=GetFeature&typeName=luhao%3Asuqian&maxFeatures=50&outputFormat=application%2Fjson&' + 'bbox=' +
extent.join(',') +
',EPSG:4326';
},
strategy: ol.loadingstrategy.bbox,
});
// 矢量图层
const layer = new ol.layer.Vector({
// 设置数据源
source: vectorSource,
// 设置图层样式也可以 function (feature) { /** 根据内容动态加载样式 **/ return Style}
style: new ol.style.Style({
image: new ol.style.Icon({
scale: 0.8,
src: require("imgurl")
})
})
});
// 将图层添加到地图上
map.addLayer(layer);
加载 arcgis 服务
一次性加载数据
// EsriJSON 格式化工具
const esriJsonFormat = new ol.format.EsriJSON();
// 矢量数据源
const vectorSource = new ol.source.Vector();
// 请求参数
let params = {
f: 'json',
where: '1=1',
returnGeometry: true,
spatialRel: 'esriSpatialRelIntersects',
inSR: 4326,
outSR: 4326,
outFields: '*',
};
// 发起请求
request({url: 'url', params}).then(response => {
// 读取图形数据
const features = esriJsonFormat.readFeatures(response);
if (features.length > 0) {
// 添加图形
vectorSource.addFeatures(features);
// 调整地图视角
map.getView().fit(vectorSource.getExtent());
}
});
// 唯一值渲染
let {Style, Icon} = ol.style;
const styleCache = {
'流量': new Style({
image: new Icon({
scale: 0.8,
src: require("imgurl")
})
}),
'雨量': new Style({
image: new Icon({
scale: 0.8,
src: require("imgurl")
})
}),
'水位': new Style({
image: new Icon({
scale: 0.8,
src: require("imgurl")
})
})
};
// 矢量图层
const layer = new ol.layer.Vector({
// 设置数据源
source: vectorSource,
// 设置图层样式
style: function (feature) {
// 获取属性 MONITOR_TYPE 的值
const classify = feature.get('MONITOR_TYPE');
// 根据值动态渲染
return styleCache[classify];
}
});
// 将图层添加到地图上
map.addLayer(layer);
动态加载数据
// 矢量数据源
const vectorSource = new ol.source.Vector({
loader: function (extent, resolution, projection, success, failure) {
// 请求参数
let params = {
f: 'json',
where: '1=1',
returnGeometry: true,
spatialRel: 'esriSpatialRelIntersects',
inSR: 4326,
outSR: 4326,
outFields: '*',
geometryType: 'esriGeometryPolygon',
geometry: encodeURIComponent(
'{"xmin":' +
extent[0] +
',"ymin":' +
extent[1] +
',"xmax":' +
extent[2] +
',"ymax":' +
extent[3] +
',"spatialReference":{"wkid":4326}}'
)
}
// 发起请求
request({url: url, params}).then(response => {
// 读取图形数据
const features = esriJsonFormat.readFeatures(response);
if (features.length > 0) {
// 添加图形
vectorSource.addFeatures(features);
}
});
},
strategy: ol.loadingstrategy.tileStrategy(
createXYZ({
tileSize: 512,
})
),
});
// 矢量图层
const layer = new ol.layer.Vector({
// 设置数据源
source: vectorSource,
// 设置图层样式也可以 function (feature) { /** 根据内容动态加载样式 **/ return Style}
style: new ol.style.Style({
image: new ol.style.Icon({
scale: 0.8,
src: require(imgurl)
})
})
});
// 将图层添加到地图上
map.addLayer(layer);
获取加载后的所有feature(注意异步)
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
url: '../data/geojson/line-samples.geojson',
format: new ol.format.GeoJSON()
})
});
// 因为是异步加载,所以要采用事件监听的方式来判定是否加载完成
var listenerKey = vectorLayer.getSource().on('change', function(){
// 判定是否加载完成
if (vectorLayer.getSource().getState() === 'ready') {
document.getElementById('count').innerHTML = vectorLayer.getSource().getFeatures().length;
// 注销监听器
vectorLayer.getSource().unByKey(listenerKey);
}
});
//
map.addLayer(vectorLayer);
图层显示隐藏
//利用方法setVisible和setZIndex来控制图层,满足80%的这种需求
// 隐藏显示osm图层
function checkOsm(elem) {
osmLayer.setVisible(elem.checked);
}
// 置顶osm图层到最上面
function upOsm (elem) {
if (elem.checked) {
osmLayer.setZIndex(3);
circleLayer.setZIndex(circleLayer.getZIndex()-1);
pointLayer.setZIndex(pointLayer.getZIndex()-1);
}
}
利用overlay加载图标
<div id="map" style="width: 100%"></div>
<!--下面就是传统的显示一个图片图标的方式,用img-->
<div id="anchor"><img src="../img/anchor.png" alt="示例锚点"/></div>
var anchor = new ol.Overlay({
element: document.getElementById('anchor')
});
// 关键的一点,需要设置附加到地图上的位置
anchor.setPosition([104, 30]);
// 然后添加到map上
map.addOverlay(anchor);
优点:可以直接对元素进行css处理
利用Featue + Style加载图标
// 我们需要一个vector的layer来放置图标
var layer = new ol.layer.Vector({
source: new ol.source.Vector()
})
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
//把layer添加到layers
layer
],
target: 'map',
view: new ol.View({
projection: 'EPSG:4326',
center: [104, 30],
zoom: 10
})
});
// 创建一个Feature,并设置好在地图上的位置
var anchor = new ol.Feature({
geometry: new ol.geom.Point([104, 30])
});
// 设置样式,在样式中就可以设置图标
anchor.setStyle(new ol.style.Style({
image: new ol.style.Icon({
src: '../img/anchor.png'
})
}));
// 添加到之前的创建的layer中去 可以理解为向layer的source中添加要素
layer.getSource().addFeature(anchor);
图标根据地图层级放大缩小
// 监听地图层级变化
map.getView().on('change:resolution', function(){
var style = anchor.getStyle();
// 重新设置图标的缩放率,基于层级10来做缩放
style.getImage().setScale(this.getZoom() / 10);
anchor.setStyle(style);
})
svg代替图片作为图标
// 构建svg的Image对象
var svg = '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30px" height="30px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">'+
'<path fill="#156BB1" d="M22.906,10.438c0,4.367-6.281,14.312-7.906,17.031c-1.719-2.75-7.906-12.665-7.906-17.031S10.634,2.531,15,2.531S22.906,6.071,22.906,10.438z"/>'+
'<circle fill="#FFFFFF" cx="15" cy="10.677" r="3.291"/></svg>';
var mysvg = new Image();
mysvg.src = 'data:image/svg+xml,' + escape(svg);
创建规则几何图标
var shape = new ol.Feature({
geometry: new ol.geom.Point([104, 30])
});
// 添加一个三角形
shape.setStyle(new ol.style.Style({
image: new ol.style.RegularShape({
points: 3, // 顶点数
radius: 10, // 图形大小,单位为像素
stroke: new ol.style.Stroke({ // 设置边的样式
color: 'red',
size: 2
})
})
}));
layer.getSource().addFeature(shape);
// 添加一个五星
...
star.setStyle(new ol.style.Style({
image: new ol.style.RegularShape({
points: 5, // 顶点个数
radius1: 20, // 外圈大小
radius2: 10, // 内圈大小
stroke: new ol.style.Stroke({ // 设置边的样式
color: 'red',
size: 2
}),
fill: new ol.style.Fill({ // 设置五星填充样式
color: 'blue'
})
})
}));
...
canvas自绘图标
// 使用canvas绘制一个不规则几何图形
var canvas =document.createElement('canvas');
canvas.width = 20;
canvas.height = 20;
var context = canvas.getContext("2d");
context.strokeStyle = "red";
context.lineWidth = 1;
context.beginPath();
context.moveTo(0, 0);
context.lineTo(20, 10);
context.lineTo(0, 20);
context.lineTo(10, 10);
context.lineTo(0, 0);
context.stroke();
// 把绘制了的canvas设置到style里面
var style = new ol.style.Style({
image: new ol.style.Icon({
//img属性设置具体样式,与svg相同
img: canvas,
//必须设置imgSize
imgSize: [canvas.width, canvas.height],
rotation: 90 * Math.PI / 180
})
});
动态改变图标
// 监听地图点击事件
map.on('click', function(event){
var feature = map.forEachFeatureAtPixel(event.pixel, function(feature){
return feature;
});
if (feature) {
// 将空心五星为红色实心五星
var style = feature.getStyle().getImage();
feature.setStyle(new ol.style.Style({
image: new ol.style.RegularShape({
points: 5,
radius1: 20,
radius2: 10,
stroke: style.getStroke(),
fill: new ol.style.Fill({
color: 'red'
})
})
}));
}
});
设置文字
var anchor = new ol.Feature({
geometry: new ol.geom.Point([104.06, 30.67])
});
// 设置文字style
anchor.setStyle(new ol.style.Style({
text: new ol.style.Text({
// font: '10px sans-serif' 默认这个字体,可以修改成其他的,格式和css的字体设置一样
text: '这里是成都',
fill: new ol.style.Fill({
color: 'red'
})
})
}));
layer.getSource().addFeature(anchor);
style Function应用(根据层级放大缩小图标)
在feature上应用了styleFunction,通过官网API文档可以看到,其类型为ol.FeatureStyleFunction,函数仅带有一个参数resolution,在上面的代码中看到了,在函数体内this指的是当前的feature
var anchor = new ol.Feature({
geometry: new ol.geom.Point([104, 30])
});
// 应用style function,动态的获取样式
anchor.setStyle(function(resolution){
//这里需要返回一个数组!!!
return [new ol.style.Style({
image: new ol.style.Icon({
src: '../img/anchor.png',
scale: map.getView().getZoom() / 10
})
})];
});
layer.getSource().addFeature(anchor);
layer style使用Function
该函数具有两个参数,第一个参数为feature,第二个参数为resolution,同样地,该函数需要返回style数组。
// 创建layer使用的style function,根据feature的自定义type,返回不同的样式
var layerStyleFunction = function(feature, resolution) {
var type = feature.get('type');
var style = null;
// 点
if (type === 'point') {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 1,
fill: new ol.style.Fill({
color: 'red'
})
})
});
} else if ( type === 'circle') { // 圆形
...
} else { // 其他形状
style = new ol.style.Style({
...
}
// 返回 style 数组
return [style];
};
var layer2 = new ol.layer.Vector({
source: new ol.source.Vector(),
style: layerStyleFunction // 应用上面创建的 style function
});
大量图标方案
如果图标不进行交互,可以把图标渲染到底图上。
复用样式减少内存占用
在应用大量图标的时候,其实图标样式差异化并不大,比如快餐店,公共厕所,公交站点等等有很多,但都是用同样的图标在地图上标准,在不注意的时候,我们是采用下面的方式来添加图标的:
//for (var index = 0; index < 10000; index++) {
// var feature = new ol.Feature({
// geometry: new ol.geom.Point([latlon[index].lon, latlon[index].lat])
// });
// feature.setStyle(new ol.style.Style({
// image: new ol.style.Icon({
// src: '../img/marker.png'
// })
// }));
//}
//对每个feature设置style的时候,都是直接new的,这样势必会创建很多对象,占用很多内存
//优化
var styles = [
new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker1.png'
})
}),
new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker2.png'
})
}),
new ol.style.Style({
image: new ol.style.Icon({
src: '../img/marker3.png'
})
})
];
for (var index = 0; index < 10000; index++) {
var feature = new ol.Feature({
geometry: new ol.geom.Point([latlon[index].lon, latlon[index].lat])
});
feature.setStyle(styles[index % styles.length]);
}
复用Canvas提高效率
用一个大的canvas来绘制多个图标,这样就能减少canvas的数量,从而提高效率
提示信息
<!--此处用html布局,各种样式均在css中定义好了-->
<div id="popup" class="ol-popup">
<a href="#" id="popup-closer" class="ol-popup-closer"></a>
<div id="popup-content"></div>
</div>
......
<script>
// 获取到popup的节点
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
// 创建一个overlay, 绑定html元素container
var overlay = new ol.Overlay(/** @type {olx.OverlayOptions} */ ({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
}));
......
// 监听地图点击事件
map.on('singleclick', function(evt) {
// 获取当前点击坐标,并设置到HTML元素上去
var coordinate = evt.coordinate;
var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
coordinate, 'EPSG:3857', 'EPSG:4326'));
content.innerHTML = '<p>You clicked here:</p><code>' + hdms +
'</code>';
// 设置overlay的位置,从而显示在鼠标点击处
overlay.setPosition(coordinate);
});
</script>
注册/注销事件
// 监听singleclick事件
map.on('singleclick', function(event){
// 通过getEventCoordinate方法获取地理位置,再转换为wgs84坐标,并弹出对话框显示
alert(ol.proj.transform(map.getEventCoordinate(event), 'EPSG:3857', 'EPSG:4326'));
})
var key = map.on('singleclick', function(event){
alert('这是一个演示如何取消事件监听的应用,之后再点击地图时,你将不会再看到这个说明。');
// 下面这行代码就是取消事件监听
map.unByKey(key);
})
// 创建事件监听器
var singleclickListener = function(event){
alert('这是一个演示如何取消事件监听的应用,之后再点击地图时,你将不会再看到这个说明。');
// 在响应一次后,注销掉该监听器
map.un('singleclick', singleclickListener);
};
map.on('singleclick', singleclickListener);
// 使用once函数,只会响应一次事件,之后自动注销事件监听
map.once('singleclick', function(event){
alert('这是一个演示如何取消事件监听的应用,之后再点击地图时,你将不会再看到这个说明。');
})
常用事件
常用鼠标事件
- 地图鼠标左键单击事件 对应的类为ol.Map,事件名为singleclick。
- 地图鼠标左键双击事件 对应的类为ol.Map,事件名为dblclick。
- 地图鼠标点击事件 对应的类为ol.Map,事件名为click。
- 地图鼠标移动事件 对应的类为ol.Map,事件名为pointermove。
- 地图鼠标拖拽事件 对应的类为ol.Map,事件名为pointerdrag。
- 地图移动事件 对应的类为ol.Map,事件名为moveend。
注意:在singleclick和dblclick响应之前,都会触发click事件,在选择事件时,需要谨慎考虑。 同时发现moveend事件在地图缩放的时候,也会触发。
非直接交互事件
- 地图缩放事件 对应的类为ol.View,事件名为 change:resolution
- 地图中心改变事件 对应的类是ol.View,事件名为 change:center
自定义事件
注意事件名称是可以自定义的,只要派发和监听使用的事件名称是一致的就可以。除了可以通过dispatchEvent({type: 'mousemove', event: event})这种形式派发一个事件之外,还可以通过dispatchEvent('mousemove')这中形式直接发送mousemove事件
// 为地图注册鼠标移动事件的监听
map.on('pointermove', function(event){
//forEachFeatureAtPixel--对矢量数据源,通过鼠标点击坐标与map坐标对比,获取选中要素
map.forEachFeatureAtPixel(event.pixel, function(feature){
// 为移动到的feature发送自定义的mousemove消息
feature.dispatchEvent({type: 'mousemove', event: event});
});
});
// 为feature1注册自定义事件mousemove的监听
feature1.on('mousemove', function(event){
// 修改feature的样式为半径100像素的园,用蓝色填充
this.setStyle(new ol.style.Style({
image: new ol.style.Circle({
radius: 100,
fill: new ol.style.Fill({
color: 'blue'
})
})
}));
});
交互-选中样式
feature的样式优先级是大于layer的样式的优先级
<div id="map2" style="width: 100%"></div>
<script type="text/javascript">
var layer2 = new ol.layer.Vector({
source: new ol.source.Vector(),
// 注意:把feature上的style,直接移到layer上,避免直接在feature上设置style
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: 'red'
})
})
})
});
var map2 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
layer2
],
target: 'map2',
view: new ol.View({
center: ol.proj.transform(
[104, 30], 'EPSG:4326', 'EPSG:3857'),
zoom: 10
})
});
// 在地图上添加一个圆
var circle2 = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform(
[104, 30], 'EPSG:4326', 'EPSG:3857'))
})
// 此处不再为feature设置style
layer2.getSource().addFeature(circle2);
// 添加一个用于选择Feature的交互方式
map2.addInteraction(new ol.interaction.Select({
// 设置选中后的style
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: 'blue'
})
})
})
}));
//移入选中变色
// 添加一个用于选择Feature的交互方式
map.addInteraction(new ol.interaction.Select({
condition: ol.events.condition.pointerMove, // 唯一的不同之处,设置鼠标移到feature上就选取
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: 'blue'
})
})
}),
//过滤条件
// 关键: 设置过了条件,可以用feature来写过滤,也可以用layer来写过滤
filter: function(feature, layer){
return layer === circleLayer;
}
}));
//取消
// 添加一个用于选择Feature的交互方式
var clickSelect = new ol.interaction.Select({
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: 'blue'
})
})
})
});
map.addInteraction(clickSelect);
// 取消选中
function unselectFeature() {
clickSelect.getFeatures().clear();
// 下面这样也是可以取消选中的,根据情况选择
// map.removeInteraction(clickSelect);
}
</script>
绘图
//画线为例
// 添加一个绘制的线使用的layer
var lineLayer = new ol.layer.Vector({
source: new ol.source.Vector(),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
size: 1
})
})
})
map2.addLayer(lineLayer);
map2.addInteraction(new ol.interaction.Draw({
type: 'LineString',
source: lineLayer.getSource() // 注意设置source,这样绘制好的线,就会添加到这个source里
}));
map.addInteraction(new ol.interaction.Draw({
type: 'LineString', // 设置绘制线
source: lineLayer.getSource() // 注意设置source,这样绘制好的线,就会添加到这个source里
}));