zoukankan      html  css  js  c++  java
  • 结合OpenLayers实现地图背景的拓扑图

    地图应用分三种级别:示意地图(Map Chart),地图(Map),地理信息系统(GIS),第一种通常使用相对坐标系,后两种则为真实的地理坐标,其中第二种以谷歌地图为代表,日常生活中普遍使用,后一种则为专业的GIS,专业领域做拓扑分析、流域分析时用到,示意地图我们已经有很多例子,比如美国大选示例中国地图示例等,今天介绍第二种地图的应用,结合OpenLayers和谷歌地图实现地图的拓扑图应用:demo.qunee.com/map/map.html OpenLayers + Qunee

    创建地图

    OpenLayers是开源地理基金会作(OSGeo.org)支持的项目之一,是一种通用的地理客户端平台,支持谷歌地图,Bing地图,WMS,GML等多种地图在线服务,这里用到的是谷歌地图,需要引入OpenLayers和google map的js类库和css文件 引入相关类库

    <link rel="stylesheet" href="OpenLayers/theme/default/style.css" type="text/css">
    <script src="http://maps.google.com/maps/api/js?v=3&sensor=false"></script>
    <script src="OpenLayers/OpenLayers.js"></script>

    初始化地图

    参照OpenLayers官方示例,完成地图初始化工作

    function initMap(canvas, lon, lat){
        map = new OpenLayers.Map(canvas, {
            projection: 'EPSG:3857',
            layers: [
                new OpenLayers.Layer.Google(
                    "Google Streets", // the default
                    {numZoomLevels: 20}
                ),
                new OpenLayers.Layer.Google(
                    "Google Physical",
                    {type: google.maps.MapTypeId.TERRAIN}
                ),
                new OpenLayers.Layer.Google(
                    "Google Hybrid",
                    {type: google.maps.MapTypeId.HYBRID, numZoomLevels: 20}
                ),
                new OpenLayers.Layer.Google(
                    "Google Satellite",
                    {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22}
                )
            ],
            center: new OpenLayers.LonLat(lon, lat).transform('EPSG:4326', 'EPSG:3857'),
            zoom: 5
        });
        map.addControl(new OpenLayers.Control.LayerSwitcher());
        return map;
    }
    

      

    运行效果

    左边是缩放按钮,右边可以选择地图图层 OpenLayers地图

    地图与拓扑图的结合

    OpenLayers与Qunee是两套不同的组件库,有着各自的交互系统和坐标系,需要实现组件叠加,以及坐标和交互的同步

    组件叠加

    OpenLayers结构复杂,具有多个HTML图层,而Qunee相对简单,所以最终决定将Qunee插入到OpenLayers的viewportDiv中

    var canvas = document.createElement('div');
    canvas.style.width = '100%';
    canvas.style.height = '100%';
    canvas.style.position = 'absolute';
    canvas.style.top = '0px';
    canvas.style.left = '0px';
    canvas.style.zIndex = 999;
    map.viewPortDiv.insertBefore(canvas, map.viewPortDiv.firstChild);
    
    Q.doSuperConstructor(this, MapGraph, [canvas]);

    坐标转换

    Qunee使用的是屏幕坐标,与地图坐标系完全不同,需要做转换

    经纬度转换成屏幕坐标

    需要两步,首先将经纬度转换成当前地图的投影坐标,使用的是OpenLayers提供的OpenLayers.LonLat#transform(原始投影, 目标投影)方法

    toLonLat: function(lon, lat){
        var l = new OpenLayers.LonLat(lon, lat);
        l.transform('EPSG:4326', graph.map.getProjectionObject());
        return l;
    }
    

      

    然后将转换后的坐标转换成屏幕坐标

    getPixelFromLonLat: function(lonLat){
        return this.map.getPixelFromLonLat(lonLat);
    }
    

      

    根据经纬度创建节点

    createNodeByLonLat: function(name, lon, lat){
        var l = this.toLonLat(lon, lat);
        var p = this.getPixelFromLonLat(l);
        var node = graph.createNode(name, p.x, p.y);
        node.lonLat = l;
        return node;
    }
    

      

    屏幕坐标转换成地理坐标

    同理,在节点移动后,需要将屏幕坐标转换成地理坐标 也需要两步,首先将qunee的逻辑坐标转换成屏幕坐标,然后再用OpenLayers的getLonLatFromPixel方法,转换成地理坐标

    var pixel = this.toCanvas(data.location.x, data.location.y);
    data.lonLat = this.map.getLonLatFromPixel(new OpenLayers.Pixel(pixel.x, pixel.y));
    

      

    在节点移动后都需要做这些转换,监听节点拖拽完成事件,进行坐标的同步

    this.interactionDispatcher.addListener(function(evt){
        if(evt.kind == Q.InteractionEvent.ELEMENT_MOVE_END){
            var datas = evt.datas;
            Q.forEach(datas, function(data){
                var pixel = this.toCanvas(data.location.x, data.location.y);
                data.lonLat = this.map.getLonLatFromPixel(new OpenLayers.Pixel(pixel.x, pixel.y));
            }, this);
        }
    }, this)
    

      

    交互同步

    OpenLayers和Qunee的交互是冲突的,比如拖拽操作,qunee响应了,OpenLayers就没法响应,这里我们在Qunee交互的基础之上实现地图的漫游缩放操作

    平移操作

    通过重写Q.Graph的translate方法,实现两者的同步,是不是挺简单

    translate: function (tx, ty) {
        Q.doSuper(this, MapGraph, "translate", arguments);
        this.map.moveByPx(-tx, -ty);
    }
    

      

    缩放操作

    OpenLayers默认的通过双击、鼠标滚轮实现缩放,这些事件默认会被Qunee所拦截,所以需要自己添加和派发

    this.html.ondblclick = createEventFunction(this, function(evt){
        if(this.getElementByMouseEvent(evt)){
            Q.stopEvent(evt);
        }
    });
    this.onmousewheel = function(evt){
        if (this._scaling) {
            return;
        }
        this._scaling = true;
        Q.callLater(function() {
            delete this._scaling;
        }, this, 200);
        this.map.zoomTo(this.map.zoom + (evt.delta > 0 ? 1 : -1), this.globalToLocal(evt));
    }
    

      

    缩放后的坐标同步 Qunee也有默认的缩放机制,但在地图应用中不太适用,所以需要屏蔽掉

    this.enableWheelZoom = false;
    this.enableDoubleClickToOverview = false;
    

      

    然后监听地图的缩放事件

    this.map.events.register('zoomend', this, function(){this.updateNodes(true)});
    

      

    实现对节点的坐标同步

    updateNodes: function(updateLocation){
        if(updateLocation === true){
            this.forEach(function(d){
                if(d instanceof Q.Node){
                    var l = d.lonLat;
                    var p = this.getPixelFromLonLat(l);
                    d.location = p;
                }
            }, this);
            this.translateTo(0, 0);
            return;
        }
        this.translateTo(this.map.layerContainerOriginPx.x, this.map.layerContainerOriginPx.y);
    }
    

      

    最终的运行效果

    在线演示:demo.qunee.com/map/map.html

    OpenLayers + Qunee

  • 相关阅读:
    hdu1556 Color the ball
    HDU
    《解读window核心编程》 之 字符和字符串处理方式
    WebService之CXF注解之四(測试类)
    gdal以GA_Update方式打开jpg文件的做法
    贪吃蛇源代码分析
    极光消息推送服务器端开发实现推送(上)
    2014,为了梦想宁愿破釜沉舟
    小强的HTML5移动开发之路(37)——jqMobi快速入门
    你可能不知道的5种 CSS 和 JS 的交互方式
  • 原文地址:https://www.cnblogs.com/nosand/p/3678041.html
Copyright © 2011-2022 走看看