关注前端开发
关注用户体验

HTML5绘制上海地铁线路图

某市政项目用到地铁图展示,展示地铁站点以及相关信息流,使用Qunee组件可以很好的解决这类需求,做出优美的展现,下面以上海2012地铁图为例,效果如下:
上海2012地铁图效果

示例讲解

首先需要解决数据问题,可以从维基百科或者上海地铁官网中获取,不过也免不了人工,要达到良好的显示效果,需要不只要记录站点的位置,还需要设置文本标签的理想位置,有时为了避免文字叠加,需要设置旋转角度……总之事在人为,想想办法,最终解决了数据问题,再加上Qunee图形组件的强大展示效果,做出来可以交互的在线地铁图

数据格式

采用JSON格式数据,分三种类型:文本标签、站点、地铁线

总的结构如下:

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

文本标签数据

包含坐标和文字信息,如果文字需要旋转,则会增加”rotate”属性,下面是“莘庄”文本标签信息

{
"text" : "莘庄",
"x" : 883.591,
"y" : 1625.695
}
文字与节点旋转效果

文字与节点旋转效果

站点数据

包含坐标、旋转角度以及编号信息,下面是“莘庄”站的信息

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

地铁线数据

包含名称,颜色,以及经过的站点编号

{
"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]
}

对于特殊情况,比如两条地铁线共用一条线路的情况,会出现两条线重合,为了避免这种情况,还可以指定站点横向偏移量,比如上面一号线中的如下数据

{"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;
}

创建站点

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(…)用于从站点信息自动生成线路路径

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);
        }
    })
}

交互处理

增加交互处理,监听站点拖动事件,保持地铁路线跟随站点位置变化

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

未经允许不得转载:大前端 » HTML5绘制上海地铁线路图
分享到: 更多 (0)

评论 63

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #41

    强大的HTML功能

    qianrenzhang3年前 (2015-01-28)回复
  2. #40

    彻底学会这个插件要花点时间吧

    顾陌博客3年前 (2015-01-21)回复
  3. #39

    牛逼,HTML功能就是强大

    数据库备份3年前 (2014-11-21)回复
  4. #38

    老大,代码高亮是用的插件吗,或者怎么实现的?

    lixiaolong3年前 (2014-11-06)回复
  5. #37

    浩哥。。我想问问阿里百秀的站长和你什么关系。。你还帮备案。。

    随便说说3年前 (2014-10-05)回复
  6. #36

    不懂,打酱油的。

    大城小我3年前 (2014-07-19)回复
  7. #35

    HTML5太强大了!! :mrgreen:

    多玩小说3年前 (2014-07-15)回复
  8. #34

    全是代码,没看懂,欢迎互访

    南京艺考培训学校3年前 (2014-07-13)回复
  9. #33

    确实很深奥,我都是调用百度的

    天津做网站3年前 (2014-07-09)回复
  10. #32

    确实不错的文章,学习了!

    坏小子3年前 (2014-07-06)回复
  11. #31

    好深奥,比我看到标题进来前高大上多了

    南京高起专学历3年前 (2014-06-30)回复
  12. #30

    😎

    iris3年前 (2014-05-14)回复
  13. #29

    很赞。。。

    云枫3年前 (2014-05-13)回复
  14. #28

    评论好像有问题

    sad3年前 (2014-05-07)回复
  15. #27

    😀 好深奥,比我看到标题进来前高大上多了~~~

    诸葛小觉3年前 (2014-05-06)回复
  16. #26

    博客貌似好久没更新了

    锤子3年前 (2014-04-25)回复
  17. #25

    很不错哦。赞一个

    电商大叔3年前 (2014-04-24)回复
  18. #24

    3年前 (2014-04-24)回复
  19. #23

    浩哥,你的主题实在是很漂亮,我看到你详细页下的相关文章是关联同一分类的文章,能改成同一标签的文章吗?这样是否会好些?

    顶礼膜拜3年前 (2014-04-24)回复
    • 首先关联标签,数量不足就关联分类

      浩子3年前 (2014-04-27)回复
  20. #22

    谁想到这个的…也是够无聊

    Kane3年前 (2014-04-22)回复
    • 哈哈,技术文,角度不一样吧

      浩子3年前 (2014-04-27)回复
  21. #21

    太牛逼了,果断收藏了

    泰安网站建设3年前 (2014-04-22)回复
  22. #20

    ➡ 我的博客,回复评论一直在提交中…半天才提交成功…

    萧晔离3年前 (2014-04-17)回复
    • 看了,是很慢,你试试mail插件,怀疑邮件发送问题

      浩子3年前 (2014-04-18)回复
  23. #19

    尊敬的站长,新版的D8什么时候更新?现在通过微信访问网站,只有图片没有文字

    3ice3年前 (2014-04-15)回复
    • 抱歉,目前可以使用下面方式解决http://www.daqianduan.com/5327.html

      浩子3年前 (2014-04-18)回复
  24. #18

    阿里百秀是一款WordPress主题吗,很喜欢,会发售吗?

    享乐3年前 (2014-04-15)回复
    • 哥们,我想说,那是广告位,你晓得不

      浩子3年前 (2014-04-15)回复
      • 阿里百秀上有推荐你,他的主题是不是你这边开发的?很漂亮

        灰度3年前 (2014-04-28)回复
        • 没错,这事是我干的

          浩子3年前 (2014-04-28)
      • 晕死,原来是你的站?网站备案这两个域名是同一个备案

        灰度3年前 (2014-04-28)回复
        • 要知道,对于小白来说,备案很困难,包括服务器都是我的阿里云

          浩子3年前 (2014-04-28)
  25. #17

    啊啊啊啊

    ads3年前 (2014-04-07)回复
  26. #16

    文章页面的百度分享按钮建议更新下,百度分享现在有新的样式了,更加漂亮。

    随心3年前 (2014-04-06)回复
    • 已经在测试阶段了,近几天的新版本加上

      浩子3年前 (2014-04-06)回复
      • 这几天等的难受死了啊

        购买主题呢3年前 (2014-04-15)回复
  27. #15

    好难啊。

    智享互联3年前 (2014-04-05)回复
  28. #14

    评论你的文章后,你回复我,会有邮箱提醒,这是通过php函数实现的还是smtp?

    主题评论3年前 (2014-04-05)回复
  29. #13

    写错了,是文章里的代码区域是黑色的,是怎么实现的

    主题蛮好的3年前 (2014-04-05)回复
    • 请参看:http://www.daqianduan.com/5253.html

      浩子3年前 (2014-04-05)回复
  30. #12

    主题里代码区域是黑色的,是主题自带的?还是插件实现的啊?

    主题蛮好的3年前 (2014-04-05)回复
  31. #11

    主题不错。

    d83年前 (2014-04-04)回复
  32. #10

    演示站打开好慢啊

    donghaichen3年前 (2014-04-03)回复
  33. #9

    反馈大前端一个BUG,用同一表情评论两次,网页变型啦

    反馈大前端BUG3年前 (2014-04-02)回复
    • 我看看这是什么个情况

      浩子3年前 (2014-04-05)回复
  34. #8

    演示站打开好慢啊

    东子3年前 (2014-03-31)回复
  35. #7

    这么赞!

    sylar3年前 (2014-03-31)回复
  36. #6

    反馈大前端一个BUG,浩子哥试试 用同一表情评论两次,看看网页变成了什么样—-360安全浏览器

    1233年前 (2014-03-31)回复
  37. #5

    :mrgreen:

    1233年前 (2014-03-31)回复
  38. #4

    相当的不错

    Win7en乐园3年前 (2014-03-27)回复
  39. #3

    强大啊,太酷了,html5确实强大,看看DEMO

    礼品定制3年前 (2014-03-26)回复
    • 肯定又是从哪里复制来的。然后改改的。

      路过3年前 (2014-06-17)回复
  40. #2

    原文在哪里

    胡绪宜3年前 (2014-03-25)回复
  41. #1

    很赞啊,特别是点击某条线路,然后高亮,这效果很棒。看过一个用HTML5绘出来的中国地图,是百度上次植树节做的,那效果也很好

    水中月明3年前 (2014-03-25)回复

themebetter 国内更好的WordPress主题服务商

立即前往