基於HTML5技術繪製上海地鐵圖

某市政項目用到地鐵圖展現,展現地鐵站點以及相關信息流,使用Qunee組件能夠很好的解決這類需求,作出優美的展示,下面以上海2012地鐵圖爲例,效果以下:


 

示例講解
首先須要解決數據問題,能夠從維基百科或者上海地鐵官網中獲取,不過也免不了人工,要達到良好的顯示效果,須要不僅要記錄站點的位置,還須要設置文本標籤的理想位置,有時爲了不文字疊加,須要設置旋轉角度……總之事在人爲,想一想辦法,最終解決了數據問題,再加上Qunee圖形組件的強大展現效果,作出來能夠交互的在線地鐵圖

數據格式

採用JSON格式數據,分三種類型:文本標籤、站點、地鐵線

總的結構以下: java

{
"labels" : [  ... ],
"stations" : [ ... ],
"lines" : [ ... ]
}

文本標籤數據

包含座標和文字信息,若是文字須要旋轉,則會增長」rotate」屬性,下面是「莘莊」文本標籤信息 node

{
"text" : "莘莊",
"x" : 883.591,
"y" : 1625.695
}

文字與節點旋轉效果


 

站點數據

包含座標、旋轉角度以及編號信息,下面是「莘莊」站的信息 函數

{
"id" : 5,
"x" : 869.8513512641732,
"y" : 1597.6559686949402,
"rotate" : 0.7853981633974483
}

地鐵線數據

包含名稱,顏色,以及通過的站點編號 spa

{
"name" : "1",
"color" : "#e52035",
"stations" : [64, 70, 67, 71, 72, 65, 69, 73, 66, 68, 63, 62, 22, 61, 60, {"id": 21, "yOffset": 0.5}, 59, {"id": 18, "yOffset": -0.5}, 17, 58, 14, 7, 57, 6,
56, 44, 47, 5]
}

對於特殊狀況,好比兩條地鐵線共用一條線路的狀況,會出現兩條線重合,爲了不這種狀況,還能夠指定站點橫向偏移量,好比上面一號線中的以下數據 code

{"id": 21, "yOffset": 0.5}

由於上海地鐵三號線與四號線共用線路較多,因此這種處理更加明顯

三號線數據 對象

{
"name" : "3",
"color" : "#f9d300",
"stations" : [6, 95, 96, 97, {"id":12,"yOffset":0.5}, {"id":11,"yOffset":0.5}, {"id":8,"yOffset":0.5}, {"id":9,"yOffset":0.5},
{"id":10,"yOffset":0.5}, {"id":25,"yOffset":0.5}, {"id":26,"yOffset":0.5}, {"id":238,"yOffset":0.5}, {"id":22,"yOffset":-0.5}, {"id":27,"yOffset":-0.5},
98, 99, 100, 101, 104, 105, 107, 108, 109, 106, 110, 111]
}

地鐵共線效果


 
建立圖元
數據須要轉換成qunee圖元對象,三種類型分別對應三個建立函數

建立文本標籤 事件

function createText(name, x, y, rotate){
    var text = graph.createNode(name, x, y);
    if(rotate){
        text.rotate = rotate;
    }
    text.zIndex = 20;
    text.image = null;
    text.setStyle(Q.Styles.BACKGROUND_COLOR, Q.toColor(0x88FFFFFF));
    text.setStyle(Q.Styles.LABEL_ANCHOR_POSITION, Q.Position.LEFT_BOTTOM);
    text.setStyle(Q.Styles.LABEL_POSITION, Q.Position.CENTER_MIDDLE);
    text.setStyle(Q.Styles.LABEL_PADDING, PADDING);
    return text;
}

建立站點 ci

function createStation(station){
    var node = graph.createNode(null/**station.name*/, station.x, station.y);
    node.stationId = station.id;
    node.setStyle(Q.Styles.LABEL_FONT_SIZE, 10);
    node.setStyle(Q.Styles.LABEL_ANCHOR_POSITION, Q.Position.CENTER_MIDDLE);
    node.setStyle(Q.Styles.LABEL_POSITION, Q.Position.CENTER_MIDDLE);
    node.zIndex = 10;
    if(station.rotate){
        node.image = roundRect;
        node.rotate = station.rotate;
    }else{
        node.image = circle;
    }
    node.setStyle(Q.Styles.SHAPE_FILL_COLOR, "#FFF");
    node.setStyle(Q.Styles.SHAPE_STROKE_STYLE, "#000");
    return node;
}

建立地鐵線

createLine(…)函數用於建立地鐵線,使用了節點類型圖元,並設置節點主體爲路徑,函數updateLine(…)用於從站點信息自動生成線路路徑 get

function createLine(line){
    var stations = line.stations;

    var node = graph.createNode(line.name);
    node.stations = stations;
    node.movable = false;
    node.setStyle(Q.Styles.LABEL_FONT_SIZE, 50);
    node.setStyle(Q.Styles.LABEL_COLOR, line.color);
    node.setStyle(Q.Styles.LABEL_ANCHOR_POSITION, Q.Position.LEFT_BOTTOM);
    node.setStyle(Q.Styles.LABEL_POSITION, Q.Position.LEFT_TOP);
    node.setStyle(Q.Styles.LAYOUT_BY_PATH, true);
    node.anchorPosition = null;
    node.setStyle(Q.Styles.SHAPE_STROKE, size);
    node.setStyle(Q.Styles.SHAPE_STROKE_STYLE, line.color);

    updateLine(node, true);
    return node;
}
function updateLine(line, addListener){
    var path = new Q.Path();
    line.image = path;

    var stations = line.stations;
    var first = true;
    Q.forEach(stations, function(s){
        var station = getStation(s.id || s);
        if(!station){
            return;
        }
        if(addListener){
            addLocationChangeListener(station.stationId, line);
        }
        var location = station.location;
        var x = location.x, y = location.y;
        if(s.yOffset){
            var offset = s.yOffset * size;
            var rotate = station.rotate || 0;
            var sin = Math.sin(rotate);
            var cos = Math.cos(rotate);
            x += cos * offset;
            y += sin * offset;
        }
        if(first){
            first = false;
            path.moveTo(x, y);
        }else{
            path.lineTo(x, y);
        }
    })
}

交互處理

增長交互處理,監聽站點拖動事件,保持地鐵路線跟隨站點位置變化 it

graph.interactionDispatcher.addListener(function(evt){
    if(evt.kind != Q.InteractionEvent.ELEMENT_MOVING){
        return;
    }
    var datas = evt.datas;

    Q.forEach(datas, function(data){
        if(!data.stationId){
            return;
        }
        var listeners = stationLocationChangeListeners[data.stationId];
        if(listeners){
            for(var l in listeners){
                updateLine(listeners[l]);
            }
        }
    });
});

在線示例
http://demo.qunee.com/#Shanghai Metro Map 2012

相關文章
相關標籤/搜索