Blog

Blog

PHODAL

地图移动应用实战:Ionic OpenLayer 地图显示

在上一篇《地图移动应用实战:Ionic ElasticSearch 搜索服务》中我们说到了,如果创建一个搜索服务,以及使用搜索接口。接着,我们来将他们显示到地图上。

效果图:

Ionic ElasticSearch Map Show

设计思路

  1. 判断是否有上次记录的位置信息,如果有则将地图的中心设置为上次的位置。

  2. 将位置添加到ElasticSearch的Query中。

  3. 从ElasticSearch中获取数据,并解析Render到地图上。

OpenLayer

OpenLayers是一个用于开发WebGIS客户端的JavaScript包。OpenLayers 支持的地图来源包括Google Maps、Yahoo、 Map、微软Virtual Earth 等,用户还可以用简单的图片地图作为背景图,与其他的图层在OpenLayers 中进行叠加,在这一方面OpenLayers提供了非常多的选择。除此之外,OpenLayers实现访问地理空间数据的方法都符合行业标准。OpenLayers 支持Open GIS 协会制定的WMS(Web Mapping Service)和WFS(Web Feature Service)等网络服务规范,可以通过远程服务的方式,将以OGC 服务形式发布的地图数据加载到基于浏览器的OpenLayers 客户端中进行显示。OpenLayers采用面向对象方式开发,并使用来自Prototype.js和Rico中的一些组件。

添加OpenLayer 3

1.下载OpenLayer

2.添加到index.html:

<script src="js/ol.js"></script>

Ionic OpenLayer 地图显示:

创建NSService

新建一个MapCtrl,需要用到ESServiceNSService,NSService是官方示例中的一个函数,提供了一个getRendererFromQueryString方法。

.factory('NSService', function(){
      var exampleNS = {};

      exampleNS.getRendererFromQueryString = function() {
        var obj = {}, queryString = location.search.slice(1),
            re = /([^&=]+)=([^&]*)/g, m;

        while (m = re.exec(queryString)) {
          obj[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
        }
        if ('renderers' in obj) {
          return obj['renderers'].split(',');
        } else if ('renderer' in obj) {
          return [obj['renderer']];
        } else {
          return undefined;
        }
      };

      return {
        "exampleNS": exampleNS
      };
})

创建基本地图显示

这里我们使用的是Bing地图:

  var view = new ol.View({
    center: map_center,
    zoom: 4
});

var controls = ol.control.defaults({rotate: false});
var interactions = ol.interaction.defaults({altShiftDragRotate:false, pinchRotate:false});

var map = new ol.Map({
    controls: controls,
    interactions: interactions,
    layers: [
        new ol.layer.Tile({
            source: new ol.source.BingMaps({
                key: 'Ak-dzM4wZjSqTlzveKz5u0d4IQ4bRzVI309GxmkgSVr1ewS6iPSrOvOKhA-CJlm3',
                culture: 'zh-CN',
                imagerySet: 'Road'
            })
        })
    ],
    renderer: NSService.exampleNS.getRendererFromQueryString(),
    target: 'map',
    view: view
});

一个简单的地图如上如示。

获取当前位置

ngCordova有一个插件是$cordovaGeolocation,用于获取当前的位置。代码如下所示:

var posOptions = {timeout: 10000, enableHighAccuracy: true};
$cordovaGeolocation
    .getCurrentPosition(posOptions)
    .then(function (position) {
        var pos = new ol.proj.transform([position.coords.longitude, position.coords.latitude], 'EPSG:4326', 'EPSG:3857');

        $localstorage.set('position', [position.coords.latitude, position.coords.longitude].toString());
        $localstorage.set('map_center', pos);

        view.setCenter(pos);
    }, function (err) {
        console.log(err)
    });

当获取到位置时,将位置存储到localstorage中。

获取结果并显示

最后代码如下所示,获取解析后的结果,添加icon

ESService.search("", 0).then(function(results){
    var vectorSource = new ol.source.Vector({ });
    $.each(results, function(index, result){
        var position = result.location.split(",");
        var pos = ol.proj.transform([parseFloat(position[1]), parseFloat(position[0])], 'EPSG:4326', 'EPSG:3857');

        var iconFeature = new ol.Feature({
                geometry: new ol.geom.Point(pos),
                name: result.title,
                phone: result.phone_number,
                distance: result.distance
        });
        vectorSource.addFeature(iconFeature);
    });

    var iconStyle = new ol.style.Style({
        image: new ol.style.Icon(({
            anchor: [0.5, 46],
            anchorXUnits: 'fraction',
            anchorYUnits: 'pixels',
            opacity: 0.75,
            src: 'img/icon.png'
        }))
    });

    var vectorLayer = new ol.layer.Vector({
        source: vectorSource,
        style: iconStyle
    });
    map.addLayer(vectorLayer);
});

添加点击事件

在上面的代码中添加:

    var element = document.getElementById('popup');

    var popup = new ol.Overlay({
        element: element,
        positioning: 'bottom-center',
        stopEvent: false
    });
    map.addOverlay(popup);

    map.on('click', function(evt) {
        var feature = map.forEachFeatureAtPixel(evt.pixel,
            function(feature, layer) {
                return feature;
            });

        if (feature) {
            var geometry = feature.getGeometry();
            var coord = geometry.getCoordinates();
            popup.setPosition(coord);
            $(element).popover({
                'placement': 'top',
                'html': true,
                'content': "<h4>商品:" + feature.get('name') + "</h4>" + '' +
                '<div class="button icon-left ion-ios-telephone button-calm button-outline">' +
                '<a ng-href="tel: {{result.phone_number}}">' + feature.get('phone') + '</a> </div>' +
                    "<p class='icon-left ion-ios-navigate'> " + feature.get('distance') + "公里</p>"
            });
            $(element).popover('show');
        } else {
            $(element).popover('destroy');
        }
    });

当用户点击时,调用Bootstrap的Popover来显示信息。

其他:

服务端代码: https://github.com/phodal/django-elasticsearch

客户端代码: https://github.com/phodal/ionic-elasticsearch

关于我

Github: @phodal     微博:@phodal     知乎:@phodal    

微信公众号(Phodal)

围观我的Github Idea墙, 也许,你会遇到心仪的项目

QQ技术交流群: 321689806
comment

Feeds

RSS / Atom

最近文章

关于作者

Phodal Huang

Engineer, Consultant, Writer, Designer

ThoughtWorks 技术专家

工程师 / 咨询师 / 作家 / 设计学徒

开源深度爱好者

出版有《前端架构:从入门到微前端》、《自己动手设计物联网》、《全栈应用开发:精益实践》

联系我: h@phodal.com

微信公众号: 最新技术分享

标签