此处说的静态地图指没有经过地理投影什么的普通地图,比如一些规划图,室内建筑图,平面示意图等等,这些图一般都不会很大,但常用于一些演示系统中。会涉及到一些简单的定位,标注等。
OpenLayers也充分考虑到了这样的需求,提供了对应的source类:ol.source.ImageStatic。示例请看下面这个地图,显示的是成都熊猫基地的平面图:
因为应用于OpenLayers中,所以地图可以放大、缩小,具备相应的功能,对于演示而言,无疑加快了开发效率。对应的代码如下:
<div id="map"></div>
<script>
//地图设置中心,设置到成都,在本地离线地图offlineMapTiles刚好有一张zoom为4的成都瓦片
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 map = new ol.Map({
target: 'map',
view: new ol.View({
center: center,
zoom: 7
})
});
//加载熊猫基地静态图层
map.addLayer(new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'img/pandaBase.jpg', // 熊猫基地地图
imageExtent: extent //映射到地图的范围
})
}));
</script>
代码中有详细注释,可帮助理解,要应用静态地图,需要注意设置图片在地图中占据的extent。如果没有这个设置,图片就不能和位置关联在一起,也就不能应用于OpenLayers中。
大家肯定非常关心extent的计算[center[0] - 550 * 1000 / 2, center[1] - 344 * 1000 / 2, center[0] + 550 * 1000 / 2, center[1] + 344 * 1000 / 2],为什么这样计算?这个地方我想让图片本身的大小和地理范围产生联系,图片的大小为550*334像素,在此基础上同比放大1000倍,作地理范围。当然也可以不用放大,直接作为地理范围,只是这样需要放大地图到很高的层级才能看到它。有了这样的映射关系后,图片能保持长宽比不变,从而不变形。
为什么引入center,除以2相关的计算?这是一个简单计算,目的在于设置图片显示在地图中心。
把地图加载出来只是第一步,我们最重要的是在地图上定位,并处理相应的业务。比如我们希望在图片[390, 145]像素位置添加一个活动图标表示这个地方有现场活动,就像下面这样:
看到图片上的小旗帜没有,它就是新加上去的活动图标。那么我们是如何做到的呢:
<div id="map2"></div>
<script>
// 地图设置中心,设置到成都,在本地离线地图 offlineMapTiles刚好有一张zoom为4的成都瓦片
var center2 = ol.proj.transform([104.06667, 30.66667], 'EPSG:4326', 'EPSG:3857');
// 计算熊猫基地地图映射到地图上的范围,图片像素为 550*344,保持比例的情况下,把分辨率放大一些
var extent2 = [
center2[0] - 550 * 1000 / 2,
center2[1] - 344 * 1000 / 2,
center2[0] + 550 * 1000 / 2,
center2[1] + 344 * 1000 / 2
];
//创建地图
var map2 = new ol.Map({
view: new ol.View({
center: center2,
zoom: 7
}),
target: 'map2'
});
//加载熊猫基地静态地图层
map2.addLayer(new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'img/pandaBase.jpg', //熊猫基地地图
imageExtent: extent2 //映射到地图的范围
})
}));
//创建一个用于放置活动图标的layer
var activityLayer = new ol.layer.Vector({
source: new ol.source.Vector()
});
//创建一个活动图标需要的Feature,并设置位置
var activity = new ol.Feature({
geometry: new ol.geom.Point([center2[0]- 550*1000/2 + 390 * 1000, center2[1]-344*1000/2 + (344 - 145) * 1000])
});
//设置Feature的样式,使用小旗帜图标
activity.setStyle(new ol.style.Style({
image: new ol.style.Icon({
src: 'img/flag_right.png',
anchor: [0, 1],
scale: 0.2
})
}));
//添加活动Feature到layer上,并把layer添加到地图中
activityLayer.getSource().addFeature(activity);
map2.addLayer(activityLayer);
</script>
注释足够帮助大家理解代码意图,我想最关键的在于activity这个feature的位置为什么要这样计算:
[center2[0]- 550*1000/2 + 390 * 1000, center2[1]-344*1000/2 + (344 - 145) * 1000]。如果翻译成下面这样,你可能会更容易理解:extentLeft+picX,extentTop+picY,此处的picX和picY显然是需要在图片像素位置的基础上放大1000倍,才能对应于地理位置。center[0]-550*1000/2对应的就是extentLeft,center[1]-344*1000/2对应的是extentBottom,并不是extentTop,所以我们要做一个简单的计算(344-145)*1000,而不是直接用145*1000。
从图片的像素坐标转换为地图的地理坐标,关键在于通过像素大小,映射到一个地图的extent,希望能理解这个过程。在此基础上,就能充分应用OpenLayer3的功能了。