静态地图及应用

此处说的静态地图指没有经过地理投影什么的普通地图,比如一些规划图,室内建筑图,平面示意图等等,这些图一般都不会很大,但常用于一些演示系统中。 会涉及到一些简单的定位,标注等。 OpenLayers 3也充分考虑到了这样的需求,提供了对应的source类: ol.source.ImageStatic。 示例请看下面这个地图,显示的是成都熊猫基地的平面图:

因为应用于OpenLayers 3中,所以地图可以放大缩小,具备相应的功能,对于演示而言,无疑加快了开发效率。 对应的代码如下:

<div id="map" style="width: 100%"></div>
<script type="text/javascript">

    // 地图设置中心,设置到成都,在本地离线地图 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({
        view: new ol.View({ 
            center: center,
            zoom: 7
        }),
        target: 'map'
    });

    // 加载熊猫基地静态地图层
    map.addLayer(new ol.layer.Image({
        source: new ol.source.ImageStatic({
            url: '../img/pandaBase.jpg', // 熊猫基地地图
            imageExtent: extent     // 映射到地图的范围
        })
    }));
</script>

代码中有详细注释,可帮助理解,要应用静态地图,需要注意设置图片在地图中占据的extent。 如果没有这个设置,图片就不能和位置关联在一起,也就不能应用于OpenLayers 3中。 大家肯定非常关心extent的计算[center[0]- 550*1000/2, center[1]-344*1000/2, center[0]+550*1000/2, center[1]+344*1000/2],为什么这样计算? 这个地方我想让图片本身的大小和地理范围产生联系,图片的大小为550*344像素,在此基础上同比放大1000倍,作地理范围。当然也可以不用放大,直接作为地理范围,只是这样需要放大地图到很高的层级才能看到它。 有了这样的映射关系后,图片能保持长宽比不变,从而不变形。 为什么引入center,除以2相关的计算? 这是一个简单计算,目的在于设置图片显示在地图中心。

把地图加载出来只是第一步,我们最重要的是在地图上定位,并处理相应的业务。比如我们希望在图片[390,145]像素位置添加一个活动图标表示这个地方有现场活动,就像下面这样:

看到地图上的小旗帜没有,它就是新加上去的活动图标。 那么我们是如何做到的呢:

<div id="map2" style="width: 100%"></div>
<script type="text/javascript">

    // 地图设置中心,设置到成都,在本地离线地图 offlineMapTiles刚好有一张zoom为4的成都瓦片
    var center2 = ol.proj.transform([104.06667, 30.66667], 'EPSG:4326', 'EPSG:3857');
    // 计算熊猫基地地图映射到地图上的范围,图片像素为 550*344,保持比例的情况下,把分辨率放大一些
    var extent2 = [center[0]- 550*1000/2, center[1]-344*1000/2, center[0]+550*1000/2, center[1]+344*1000/2];

    //创建地图
    var map2 = new ol.Map({
        view: new ol.View({ 
            center: center,
            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([center[0]- 550*1000/2 + 390 * 1000, center[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的位置为什么要这样计算: [center[0]- 550*1000/2 + 390 * 1000, center[1]-344*1000/2 + (344 - 145) * 1000]。 如果翻译成下面这样,你可能会更容易理解:extentLeft+picX, extentTop+picY,此处的picXpicY显然是需要在图片像素位置的基础上放大1000倍,才能对应于地理位置。 [center[0]- 550*1000/2对应的就是extentLeft, center[1]-344*1000/2对应的是extentBottom,并不是extentTop,所以我们要做一个简单的计算(344 - 145) * 1000,而不是直接用145*1000

从图片的像素坐标转换为地图的地理坐标,关键在于通过像素大小,映射到一个地理的extent,希望能理解这个过程。 在此基础上,就能充分应用OpenLayers 3的功能了。

对于图片比较大的情况,可以自行切片,然后分片加载,从而拼成一整张地图,可按照上面的方法自行尝试,作为课后练习。