陈慧琳合成图,点睛网,002578
前段时间帮助同事重构一个地图类的项目,然后就学习了openlayer3这个框架,但是官网上没有中文版,也没有详细的例子解释,我只能遇到看不懂的就翻译成中文来用,为了方便以后再用这个ol,能够更快的上手,就花了几天的时间总结了ol的知识,ol功能很丰富,api也很多,没有写太多,只是写了怎么用的,只要学会了根本,就可以很快的使用api去操作map。
另外,在总结知识的同时,还写了demo,加深自己的理解,大家觉得不错的话,给个star~ github
var map = new ol.map({ target:'map', layers:[], view:views, interactions:interactions, controls:controls, })
map是openlayers的核心
组件,所有的操作方法以及渲染都是挂载到map上面。创建的map对象需要传一个对象进去,最常见的就有以下几个属性,
* target --> 地图的挂载元素,就是在html元素里声明的id * layers --> 层,是个数组,可以放很多层,如果未定义,则将呈现没有图层的地图,图层是按照提供的顺序渲染的,因此,如果您希望(例如)矢量图层显示在图块图层的顶部,则它必须位于图块图层之后。 * view --> map的视图, * interactions --> 交互,比如鼠标事件导致放大,缩小,旋转之类的,默认都是true * controls --> 控件,类似与按钮,有放大,缩小,全屏等的按钮
最简单的显示地图:
document.body.innerhtml = `<div id="map" style="height:400px;width:100%"></div>`; var map = new ol.map({ target:'map', layers:[new ol.layers.tile({ source: new ol.source.osm() })], view: new ol.view({ center:[0,0], projection: 'epsg:4326', zoom:10, }), interactions: ol.interaction.defaults({ doubleclickzoom:false, altshiftdragrotate:false }), controls: ol.control.defaults({ attribution: false, }) })
这个map不是里面的map,而是初始化后的map,map = new ol.map()
;在openlayers3 的api中,有很多方法,可以通过方法去操作layers,view,interactions,controls。
打印map,可以发现map里面有很多属性,可以简单知道map上有多少个层,target是谁,size是多少等等,也可以通过api方法去获取
var target = map.gettarget(); // 获取 target的值 -- map var size = map.getsize(); // 获取可视区域的宽高。
同样的,也可以在map上设置
map.addcontrol(new ol.control.fullscreen()); // 添加全屏控件 map.addlayers( new ol.layer.vector({ source:new ol.source.vector() })) // 添加一个矢量图层
*map里有一个函数方法,可以通过点击某个图层或某个点而获取到当前的层和信息。
foreachfeatureatpixel
(pixel, callback, opt_options)
params: pixel:坐标
callback:回调函数,将使用两个参数调用回调,第一个是feature,第二个是layers
opt_options:可选
map.on('click',function(e){ var feature = map.foreachfeatureatpixel(e.pixel,function(f){ return f; }) console.log(feature); // ol.feature })
视图
.view对象表示地图的简单2d视图。这是用于更改地图的中心,分辨率和旋转的对象。
一个视图是由三种状态确定:center,resolution,zoom和rotation。每个状态具有相应的获取和设置。
ol.proj.transform(coordinates,'epsg:4326','epsg:3857')
ol.proj.transform(coordinates,'epsf:3857','epsg:4326')
var view = new ol.view({ center:[104.06,30.67], projection:'epsg:4326', // center: ol.proj.transform([104.06,30,67],'epsg:4326','epsg:3857'); // 这个和上面的结合体。 zoom:10, rotation:math.pi/10, })
视图对应的也有get和set系列的方法,用于获取和设置zoom,center,rotation等等,除此之外,还有约束方法,constrainrotation(),约束旋转度,api上有详细解释。
map.getview() // 就是当前视图,view view.getzoom() // 获取缩放级别; view.getcenter() // 获取初始中心坐标 view.setcenter([20,30]) // 设置初始中心[20,30],也可以用ol.proj.transform view.constrainrotation(2,5) // 获取此视图的约束旋转
层,是一个对象数组,将那些与数据显示方式相关的属性组合在一起,形成一个层,openlayer就是由一个一个的层形成的,包括地图,瓦片地图,图片,图形都是由layer形成而呈现在map上的
简单的来说,layer可以是一个地图,也可以是一个图形,也可以是个图片,因为是个数组,可以互相叠加的,[map,image,shape],在相同位置的情况下,后者会覆盖前者。
根据这个图片可知,layers有三种形式
每个形式都需要一个source,数据源,所以每一个形式都对应一个数据源,source和layer是一对一的关系,有一个source,必然需要一个layer,然后把这个layer添加到map上,就可以显示出来了。
对于瓦片数据源,也有很多属性,
source
有很多形式,var osmtile = new ol.layer.tile({ source:new ol.source.osm() }) var qqtile = new ol.layer.tile({ source: new ol.source.xyz({ url: 'http://map.geoq.cn/arcgis/rest/services/chinaonlinecommunity/mapserver/tile/{z}/{y}/{x}' }), }) map.addlayer(osmtile); // 添加open street map作为底图 map.addlayer(qqtile) // 添加腾讯地图
map.addlayer()这个方法就相当于初始化中的layers的数组中添加一样,如下代码,这俩是等价的,只不过后者更灵活些。
var map = new ol.map({ layers:[osmtile,qqtile] }) // 等价于下面 map.addlayer(osmtile); map.addlayer(qqtile)
ps!当添加地图作为底图时,会发现腾讯底图覆盖率osm地图,是因为layer是一个数组,遵遁先来先渲染,后来居上的原则。
layer也有get/set方法,用来设置或获取属性,其实通过api就可以知道响应方法去操作。
关于静态图片层,运用的不多,一般作为写死的,不经常换的实例中。
同样,ol.layer.image也有数据源,一般就是ol.source.imagestatic,ol.source.imagecanvas等等。
var center = ol.proj.transform([104.06667, 30.66667], 'epsg:4326', 'epsg:3857'); // 计算静态图映射到地图上的范围,图片像素为 550*344,保持比例的情况下,把分辨率放大一些 var extent = [center[0]- 550*1000/2, center[1]-344*1000/2, center[0]+550*1000/2, center[1]+344*1000/2]; var imagestatic = new ol.layer.image({ source: new ol.source.imagestatic({ url: '../pandabase.jpg', // 静态图 imageextent: extent // 映射到地图的范围 }) }) map.addlayer(imagestatic);
矢量图层,是用来渲染矢量数据的图层类型,在openlayers里,它是可以定制的,可以控制它的透明度,颜色,以及加载在上面的要素形状等。常用于从数据库中请求数据,接受数据,并将接收的数据解析成图层上的信息。比如将鼠标移动到中国,相应的区域会以红色高亮显示出来,高亮便是矢量图层的行为
既然是个矢量图,可以改变大小,颜色,以及形状。包含source数据源类,style类设置样式,以及其他的zindex,opacity等等。
feature类是vector类用来在地图上展示几何对象,是vector图层类一个属性。这个属性是个*要素数组*。
对应的数据源ol.source.vector也是个对象。最常见属性的是features
和format
以及url
。通常url和format一块,url按理传来的是geojson格式的矢量图,需要format格式化一下。最常用还是features。
ol.feature
feature名.getgeometry()
获取applytransform(ol.proj.gettransform('epsg:4326', 'epsg:3857'))
,(部分图形展示请看demo)var polygon = new ol.geom.polygon([[[110, 39], [116, 39], [116, 33], [110, 33], [110, 39]]]); polygon.applytransform(ol.proj.gettransform('epsg:4326', 'epsg:3857')); // 坐标转换 var square = new ol.feature({ geometry:polygon }) layer.getsource().addfeature(square)
一个style对象,包含style类,有7个属性:
// 最简单的呈现方式,复杂的请参考demo var layer = new ol.layer.vector({ source: new ol.source.vector({ features:[new ol.feature({ geometry: new ol.geom.point(ol.proj.transform([104, 30], 'epsg:4326', 'epsg:3857')), })] }), style: new ol.style.style({ image: new ol.style.circle({ radius: 30, fill: new ol.style.fill({ color: 'red' }) }) }), opacity:0.5 }) map.addlayer(layer)
一个层layer有一个featrue,也可以有多个feature,因为feature类是vector类用来在地图上展示几何对象,是vector图层类一个属性。这个属性是个*要素数组*。
对于style样式问题,feature的style的层级比layer.vector的层级要高,所以feature的style会覆盖layer的style。
ps:feature中的样式不能以属性名的形式写,因为feature类中没有style属性名,只有geometry
,所以要以方法的形式去添加,setstyle()。
其实关于layer,vector,api上都有其方法,包括set/get,虽然类有很多子类,子类又有很多子子类,也无妨,只要抓住想要操作的是哪一个部分就行,是feature,还是layer,还是geometry等等。
stylefunction
在feature
中可以使用stylefunction
来设置自己随心所欲的样式,通过官网api文档可以看到,其类型为ol.featurestylefunction,函数仅带有一个参数resolution,在函数体内this指的是当前的feature,根据文档说明,这个函数要返回一个style数组。
除了feature可以设置样式之外,layer也是可以设置样式的,同样地也支持stylefunction,但是需要注意的是,其定义和feature的不一样,类型为ol.style.stylefunction,该函数具有两个参数,第一个参数为feature,第二个参数为resolution,同样地,该函数需要返回style数组。
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 ], target: 'map', view: new ol.view({ projection: 'epsg:4326', center: [104, 30], zoom: 10 }) }); 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);
地图控件,包括缩放按钮,标尺,版权说明,指北针等等,不会随着地图的放大而放大,缩小而缩小,就相当于position:fixed一样,固定在某个地方。 在实现上,并不是在画布上绘制的,而是使用传统的html元素来实现的,便于同地图分离,也便于界面实现。
在openlayers 3 中,默认情况下,在地图上是不会显示这么多地图控件的,只会应用ol.control.defaults()这个函数返回的地图控件,默认包含了ol.control.zoom,ol.control.rotate和ol.control.attribution这个控件。
openlayers 3目前内置的地图控件类都在包ol.control下面:
var map = new ol.map({ target:'map', layers:[new ol.layers.tile({ source: new ol.source.osm() })], view: new ol.view({ center:[0,0], projection: 'epsg:4326', zoom:10, }) controls: ol.control.defaults({ attribution: false, // 信息false rotate: false, // 旋转false zoom: false // 缩放false }) })
map.getcontrols()是获取控件的信息,
如果想要添加其他的控件,可以使用map中的一个方法,map.addcontrol()
map.addcontrol(ol.control.overviewmap) // 添加鸟瞰图控件
控件不是在画布上绘制的,而是用html实现的,所以样式问题可以按照css+html的形式去修改。
交互,就是人与机之间的交互模式,比如用鼠标左键双击地图可以放大地图,按住鼠标左键拖动地图可以移动浏览地图,用滚动鼠标中间的滑轮可以放大缩小地图等等。这些都是openlayers内置的,其实也可以自己去interact。
内置的交互在map中都是默认的。
var map = new ol.map({ interactions: ol.interaction.defaults().extends() // .... 其余代码 })
ol.interaction.defaults()默认包含以下交互:
注意:需要设置tabindex,才能使div获得键盘事件
,就是在声明id的那个div中添加:tabindex="0")
如果想要取消某个交互事件
var map = new ol.map({ interactions: ol.interaction.defaults({ mousewheelzoom: false, // 取消滚动鼠标中间的滑轮交互 shiftdragzoom: false, // 取消shift+wheel左键拖动交互 }) // .... 其余代码 })
extend()为扩展
var map = new ol.map({ interactions: ol.interaction.defaults().extend() // .... 其余代码 })
map.getinteraction()是获取控件的信息,
如果想要添加其他的交互,可以使用map中的一个方法,map.addinteraction()
map.addinteraction(new ol.interaction.mousewheelzoom);
关于new interaction(),总共有7个子类,可以用在extend([])中,也可以用addinteraction()
draw
interaction,绘制地理要素功能;select
interaction,选择要素功能;modify
interaction,更改要素;这些子类都可以查api,有详细解释。这些子类中,有个常用的属性condition
或方法handleevent(mapbrowserevent)
condition
代表的是事件名称,比如:click,doubleclick,主要是依据ol.events
。主要有以下几种,默认是singleclick
handleevent(mapbrowserevent)
function (mapbrowserevent){ return ol.events.condition.click(mapbrowserevent) && ol.events.condition.shiftkeyonly(mapbrowserevent); }
是个选择图形的类,用于交互.
new ol.interaction.select(options)
options是个对象参数,包括:
selectsingleclick.on('select', function (event) { console.log(event) })
该select也有set/get方法,用来获取或者设置属性,比如获取选中的features,获取所有属性名称和值的对象getproperties。
是个绘制图形的类,默认支持绘制的图形类型包含 point(点)、linestring(线)、polygon(面)和circle(圆)。触发的事件包含 drawstart和drawend,分别在勾绘开始时候(单击鼠标)和结束时候触发(双击鼠标)。
new ol.interaction.draw(options)
options是个对象参数,包括:
point
linestring
polygon
circle
var drawlayer = new ol.layer.vector({ source:new ol.source.vector() }) // 新建一个层 map.addlayer(drawlayer) var draw = new ol.interaction.draw({ source: drawlayer.getsource(), // 数据源就是新建层的数据源 type: 'point', }) map.addinteraction(draw);
var draw = new ol.interaction.draw({ // 绘制矩形 type: 'linestring', maxpoints: 2, geometryfunction: function(coordinates, geometry){ if(!geometry){ geometry = new ol.geom.polygon(null); } var start = coordinates[0]; var end = coordinates[1]; geometry.setcoordinates([ [start, [start[0], end[1]], end, [end[0], start[1]], start] ]); return geometry; } // 其余代码块 })
// 绘制结束时进行回调 draw.addeventlistener('drawend', function (evt) { // 获取绘制图形的所有坐标点(终止点是起始点) var feature = evt.feature var geometry = feature.getgeometry() var coordinate = geometry.getcoordinates() // console.log(coordinate) var lent = coordinate[0].length // 坐标点个数 })
用于修改要素几何的交互。要修改已添加到现有源的功能,请使用该source选项构建修改交互,如果要修改集合中的要素(例如,选择交互使用的集合),请使用该features选项构建交互。必须使用source或features构建交互
默认情况下,交互将允许在alt 按下键时删除顶点。要配置具有不同删除条件的交互,请使用该deletecondition选项。
new ol.interaction.modify(options)
options是一个参数对象,如下:
在修改或绘制矢量要素时处理矢量要素的捕捉。这些功能可以来自一个module:ol/source/vector或module:ol/collection-collection 任何交互对象,允许用户使用鼠标与功能进行交互可以从捕捉中受益,只要它之前添加。
快照交互会修改地图浏览器事件coordinate和pixel 属性,以强制对其进行的任何交互进行快照。
new ol.interaction.snap(options)
看api
options:
官方例子snap interaction
var map = new ol.map({ layers: [ new ol.layer.tile({ source: new ol.source.osm() }) ], target: 'map', view: new ol.view({ center: ol.proj.transform( [104, 30], 'epsg:4326', 'epsg:3857'), zoom: 10 }) }); // 监听singleclick事件 map.on('singleclick', function(event){ // 通过geteventcoordinate方法获取地理位置,再转换为wgs84坐标,并弹出对话框显示 alert(ol.proj.transform(map.geteventcoordinate(event), 'epsg:3857', 'epsg:4326')); })
任意的事件应用,必然会有三个步骤:
编写事件响应函数,在openlayers中,事件发送者都会有一个名字为on的函数,调用这个函数,就能监听指定的事件,响应函数listener具有一个参数event,这个event类就对应于api文档中事件名称后边括号里的类。
foreachfeatureatpixel(pixel, callback, opt_options)
// 创建事件监听器 var singleclicklistener = function(event){ alert('...'); // 在响应一次后,注销掉该监听器 map.un('singleclick', singleclicklistener); }; map.on('singleclick', singleclicklistener);
// 使用once函数,只会响应一次事件,之后自动注销事件监听 map.once('singleclick', function(event){ alert('...'); })
要添加自定义事件,需要知道这样一个事实:ol.feature继承于ol.object,而ol.object具有派发事件(dispatchevent)和监听事件(on)的功能。
on(type, listener) 触发type类型的监听器。
// 为地图注册鼠标移动事件的监听 map.on('pointermove', function (event) { map.foreachfeatureatpixel(event.pixel, function (feature) { // 为移动到的feature发送自定义的mousemove消息 feature.dispatchevent({ type: 'mousemove', event: event }); // feature.dispatchevent('mousemove'); }); }); // 为feature1(之前创建的一个feature)注册自定义事件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' }) }) })); });
dispatchevent的参数具有type和event属性,必须这样构造吗?在回答这个问题之前,需要先看一下api文档,发现参数类型为goog.events.eventlike,说明它其实用的是google的closure库来实现的,通过closure库的源码我们知道,派发的事件如果是一个对象,那么必须包含type属性,用于表示事件类型。其他的属性可以自由定义,比如此处定义了event属性,并设置对应的值,为的是让鼠标事件传递给feature1的监听函数。dispatchevent的参数会被原封不动的传递给事件响应函数,对应代码`feature1.on('mousemove', function(event){}`里参数event,可以通过调试窗口看到此处的event和dispatchevent的参数是一样的。注意事件名称是可以自定义的,只要派发和监听使用的事件名称是一致的就可以。
除了可以通过dispatchevent({type: 'mousemove', event: event})这种形式派发一个事件之外,还可以通过dispatchevent('mousemove')这中形式直接发送mousemove事件。
openlayers功能很多,有的地方自己因时间有限还没有深入了解,但是大部分是够用了,有大部分都是参考资料的,因为讲的很通透,所以就拿过来了。,对于openylayers3,一定多看看官方例子,例子有很多吸收的知识点,特别有用
。有时间后会自己补上这一环节,大家如果有疑问或者我不对的地方请下方评论或私信。大家一起进步加油!
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
利用JavaScript更改input中radio和checkbox样式
网友评论