基於HTML5的網絡拓撲圖(2)-結合OpenLayers實現地圖背景的拓撲圖

地圖應用分三種級別:示意地圖(Map Chart),地圖(Map),地理信息系統(GIS),第一種一般使用相對座標系,後兩種則爲真實的地理座標,其中第二種以谷歌地圖爲表明,平常生活中廣泛使用,後一種則爲專業的GIS,專業領域作拓撲分析、流域分析時用到,示意地圖咱們已經有不少例子,好比美國大選示例中國地圖示例等,今天介紹第二種地圖的應用,結合OpenLayers和谷歌地圖實現地圖的拓撲圖應用:demo.qunee.com/map/map.html OpenLayers + Qunee javascript

建立地圖

OpenLayers是開源地理基金會做(OSGeo.org)支持的項目之一,是一種通用的地理客戶端平臺,支持谷歌地圖,Bing地圖,WMS,GML等多種地圖在線服務,這裏用到的是谷歌地圖,須要引入OpenLayers和google map的js類庫和css文件 引入相關類庫 css

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

初始化地圖

參照OpenLayers官方示例,完成地圖初始化工做 html

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地圖 java

地圖與拓撲圖的結合

OpenLayers與Qunee是兩套不一樣的組件庫,有着各自的交互系統和座標系,須要實現組件疊加,以及座標和交互的同步 node

組件疊加

OpenLayers結構複雜,具備多個HTML圖層,而Qunee相對簡單,因此最終決定將Qunee插入到OpenLayers的viewportDiv中 canvas

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使用的是屏幕座標,與地圖座標系徹底不一樣,須要作轉換 api

經緯度轉換成屏幕座標

須要兩步,首先將經緯度轉換成當前地圖的投影座標,使用的是OpenLayers提供的OpenLayers.LonLat#transform(原始投影, 目標投影)方法 ide

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

而後將轉換後的座標轉換成屏幕座標 this

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

根據經緯度建立節點 google

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

相關文章
相關標籤/搜索