OpenLayers学习笔记(二)
中级篇
地图的分辨率设置
// 添加一个显示Open Street Map地图瓦片网格的图层
new ol.layer.Tile({
source: new ol.source.TileDebug({
projection: 'EPSG:3857',
tileGrid: osmSource.getTileGrid()
})
})
OpenLayers 3提供了一个用于调试瓦片的source: ol.source.TileDebug。可以清晰的看到每一个瓦片的坐标,这是我们用来显示瓦片坐标的方法。
瓦片坐标中有3个数字,第一个数字是层级z,第二个数字是表示经度方向上的x,第三个数字是表示维度方向上的y。
OpenLayers 3的ol.Map已提供了对应的方法getCoordinateFromPixel来帮助你实现坐标转换。
计算分辨率
// 监听层级变化,输出当前层级和分辨率
map.getView().on('change:resolution', function(){
document.getElementById('zoom').innerHTML = this.getZoom() + ',';
document.getElementById('resolution').innerHTML = this.getResolution();
})
document.getElementById('zoom').innerHTML = map.getView().getZoom() + ',';
document.getElementById('resolution').innerHTML = + map.getView().getResolution();
地图图标操作
OpenLayer3中添加图标有两种方式,一种是比较传统的overlay,另一种是Feature + Style的方式。
<div id="anchor"><img src="img/star.png" alt="示例五角星"/></div>
// 下面把上面的图标附加到地图上,需要一个ol.Overlay
var anchor = new ol.Overlay({
element: document.getElementById('anchor')
});
// 关键的一点,需要设置附加到地图上的位置
anchor.setPosition([116.403598,39.917553]);
// 然后添加到map上
map.addOverlay(anchor);
方法的优缺点
缺点:
- 当图标比较多的情况下,如果采用这种方式,那么我们会加入非常多的HTML元素,从而造成效率降低。 界面上元素的遍历在数量比较多的情况下,会变慢,基于此基础上的渲染,鼠标事件都会变慢。
优点:
- 这种使用传统的方式显示图标可以应用传统的HTML技术,比如鼠标移动到图标上,鼠标图标变成手势。 我们可以用css来处理就可以了
<style type="text/css">
#anchor {
cursor:pointer;
}
</style>
给图标添加动画效果
<style type="text/css">
@keyframes zoom
{
from {top: 0; left: 0; width: 32px; height: 32px;}
50% {top: -16px; left: -16px; width: 64px; height: 64px;}
to {top: 0; left: 0; width: 32px; height: 32px;}
}
/* Firefox */
@-moz-keyframes zoom
{
from {top: 0; left: 0; width: 32px; height: 32px;}
50% {top: -16px; left: -16px; width: 64px; height: 64px;}
to {top: 0; left: 0; width: 32px; height: 32px;}
}
/* Safari 和 Chrome */
@-webkit-keyframes zoom
{
from {top: 0; left: 0; width: 32px; height: 32px;}
50% {top: -16px; left: -16px; width: 64px; height: 64px;}
to {top: 0; left: 0; width: 32px; height: 32px;}
}
/* Opera */
@-o-keyframes zoom
{
from {top: 0; left: 0; width: 32px; height: 32px;}
50% {top: -16px; left: -16px; width: 64px; height: 64px;}
to {top: 0; left: 0; width: 32px; height: 32px;}
}
/* 应用css动画到图标元素上 */
#anchorImg
{
display: block;
position: absolute;
animation: zoom 5s;
animation-iteration-count: infinite; /* 一直重复动画 */
-moz-animation: zoom 5s; /* Firefox */
-moz-animation-iteration-count: infinite; /* 一直重复动画 */
-webkit-animation: zoom 5s; /* Safari 和 Chrome */
-webkit-animation-iteration-count: infinite; /* 一直重复动画 */
-o-animation: zoom 5s; /* Opera */
-o-animation-iteration-count: infinite; /* 一直重复动画 */
}
</style>
Feture+Style的方式加载图标
// 我们需要一个vector的layer来放置图标
var layer = new ol.layer.Vector({
source: new ol.source.Vector()
})
// 创建一个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/star.png'
})
}));
// 添加到之前的创建的layer中去
layer.getSource().addFeature(anchor);
流程:需要一个vector的layer来放置图标,然后我们创建一个Feature,并设置好在地图上的位置,然后设置样式Feature,在样式中就可以设置图标,最后将feature添加到之前的创建的layer中去。
overlayer和feature方式加载的异同点:
- 首先overlay需要HTML元素img,但这种方式不需要
- overlay是添加在map上的,但是这种方式需要一个Vector的layer,并添加在地图上
- 我们没有办法像overlay那样使用一些HTML技术
ol.style.Icon的构造参数,会看到可以设置位置,透明度,放大缩小,旋转等
根据层级放大缩小图标
ol.style.Icon中是可以设置scale,通过它可以使图标层级放大缩小。
// 监听地图层级变化
map.getView().on('change:resolution', function(){
var style = anchor.getStyle();
// 重新设置图标的缩放率,基于层级20来做缩放
style.getImage().setScale(this.getZoom() / 20);
anchor.setStyle(style);
})
通过绘制的形式直接加载图标
OpenLayers 3提供了一个规则几何体的样式类ol.style.RegularShape
// 添加一个三角形
var shape = new ol.Feature({
geometry: new ol.geom.Point([116.203598,39.927553])
});
shape.setStyle(new ol.style.Style({
image: new ol.style.RegularShape({
points: 3, // 顶点数
radius: 20, // 图形大小,单位为像素
//radius1: 20, // 外圈大小
//radius2: 10, // 内圈大小
stroke: new ol.style.Stroke({ // 设置边的样式
color: 'red',
size: 5
}),
fill: new ol.style.Fill({ // 设置五星填充样式
color: 'blue'
})
})
}));
layer.getSource().addFeature(shape);
不规则的图标(用canvas自己绘制)
// 使用canvas绘制一个不规则几何图形
var canvas =document.createElement('canvas');
canvas.width = 40;
canvas.height = 40;
var context = canvas.getContext("2d");
context.strokeStyle = "red";
context.lineWidth = 3;
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: canvas,
imgSize: [canvas.width, canvas.height],
rotation: 90 * Math.PI / 180
})
});
// 创建一个Feature
var shape = new ol.Feature({
geometry: new ol.geom.Point([116.403598,39.917553])
});
// 应用具有不规则几何图形的样式到Feature
shape.setStyle(style);
layer.getSource().addFeature(shape);
我们成功绘制了不规则图标并把它加入到了地图中!我们使用了ol.style.Icon样式的img属性来设置,需要注意的是,必须设置imgSize属性,因为仅仅通过img设置的图像对象,没有办法自动获取宽高。 同时,官网也提供了一个类似的例子earthquake-custom-symbol,只是使用OpenLayers3 内部提供的封装库来绘制图像到canvas上,原理一样。
根据环境条件动态修改图标样式
空心五角星,点击变红
// 添加一个空心的五星
var star = new ol.Feature({
geometry: new ol.geom.Point([116.403598,39.917553])
});
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
})
})
}));
layer.getSource().addFeature(star);
// 监听地图点击事件
map.on('click', function(event){
var feature = map.forEachFeatureAtPixel(event.pixel, function(feature){
return feature;
});
if (feature) {
alert("我要红了")
// 将空心五星为红色实心五星
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([116.403598,39.917553])
});
// 设置文字style
anchor.setStyle(new ol.style.Style({
text: new ol.style.Text({
font: '15px sans-serif', //默认这个字体,可以修改成其他的,格式和css的字体设置一样
text: '北京天安门',
fill: new ol.style.Fill({
color: 'red'
})
})
}));
layer.getSource().addFeature(anchor);
styleFunction的应用
// 应用style function,动态的获取样式
anchor.setStyle(function(resolution){
return [new ol.style.Style({
image: new ol.style.Icon({
src: 'img/star.png',
scale: map.getView().getZoom() / 20
})
})];
});
在这个例子中,我们是在feature上应用了styleFunction,通过官网API文档可以看到,其类型为ol.FeatureStyleFunction,函数仅带有一个参数resolution,在上面的代码中看到了,在函数体内this指的是当前的feature,根据文档说明,这个函数要范围一个style数组。
除了feature可以设置样式之外,layer也是可以设置样式的,同样地也支持styleFunction,但是需要注意的是,其定义和feature的不一样,类型为ol.style.StyleFunction,该函数具有两个参数,第一个参数为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: 5,
fill: new ol.style.Fill({
color: 'red'
})
})
});
} else if ( type === 'circle') { // 圆形
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 20,
stroke: new ol.style.Stroke({
color: 'red',
size: 3
})
})
});
} else { // 其他形状
style = new ol.style.Style({
image: new ol.style.RegularShape({
points: 5,
radius: 20,
fill: new ol.style.Fill({
color: 'blue'
})
})
});
}
// 返回 style 数组
return [style];
};
var layer2 = new ol.layer.Vector({
source: new ol.source.Vector(),
style: layerStyleFunction // 应用上面创建的 style function
});
var map2 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
layer2
],
target: 'map2',
view: new ol.View({
projection: 'EPSG:4326',
center: [104, 30],
zoom: 10
})
});
// 添加三个feature,并设置自定义属性 type
var rect = new ol.Feature({
geometry: new ol.geom.Point([104, 30])
});
layer2.getSource().addFeature(rect);
var circle = new ol.Feature({
geometry: new ol.geom.Point([104, 30])
});
circle.set('type', 'circle');
layer2.getSource().addFeature(circle);
var point = new ol.Feature({
geometry: new ol.geom.Point([104, 30])
});
point.set('type', 'point');
layer2.getSource().addFeature(point);
参考博文:https://blog.csdn.net/MagicMHD/article/details/91360052
https://blog.csdn.net/MagicMHD/article/details/91360954