HTML5,不只是看上去很美(第四弹:可交互地铁线路图)

news/2024/6/28 3:03:01 标签: html5, 前端可视化, 地图

前言

最近特别忙,承蒙大伙关照,3D机房的项目一个接着一个,领了一帮小弟,搞搞传帮带,乌飞兔走,转眼已经菊黄蟹肥……有个小弟很不错,勤奋好学,很快就把API都摸透了,自己折腾着做了个HTML5的魔都的地铁线路图,能拖能拽的,还和电子地图做了交互。哥决定把小弟的成果纳入“HTML5,不只是看上去很美”系列,以示鼓励(P.S. 其实还挺有压力的,后浪推前浪,新人赶旧人。我们这些老鸟也得注意,免得让00后给抢了饭碗)

效果图对比

网上的地铁图还是很多的,小弟选了这张比较新的做参考。想当年哥来魔都打拼时,图上可就一红一绿打个叉……暴露年龄的话不多说,看图:

上海地铁线路图

再来看看小弟做的:

HTML5地铁线路图

我是一眼看不出区别,但这可不是一张效果图,而是一个新手仅用了几天做出来的东西,而且里面许多美化和调整是通过程序自动完成的,这就不容易了。更重要的是,它并不是一张死图,而是纯矢量、可交互、有动态效果、无失真缩放的拓扑图!我们先简单看一下交互效果,后面可以详细说说代码的实现。

文本提示弹弹弹

首先,把鼠标移到站点、路段、图标等位置,都会有文本提示弹出,这个比较基本,百度家的就有,小弟也就放了比较简单的弹出内容。如果加上基本介绍啊、相关提示啊、周边信息啊……要是加上广告,就可以赚钱了……反正什么都可以加嘛,就是一个setToolTip命令而已。

地铁图之文本提示

站点图标变变变

当鼠标移到站点上时,站点图标做了放大效果,这个效果很贴心,看了下百度家,用的是发光效果。

地铁图之动态站点

实现的方法也很简便,就是在注册站点矢量图形时,加入了动态判断。以下注册普通站点矢量图形的代码:

twaver.Util.registerImage('station',{
    w: linkWidth*1.6,
    h: linkWidth*1.6,
    v: function (data, view) {
        var result = [];
        if(data.getClient('focus')){
            result.push({
                shape: 'circle',
                r: linkWidth*0.7,
                lineColor:  data.getClient('lineColor'),
                lineWidth: linkWidth*0.2,
                fill: 'white',
            });
            result.push({
                shape: 'circle',
                r: linkWidth*0.2,
                fill:  data.getClient('lineColor'),
            });
        }else{
            result.push({
                shape: 'circle',
                r: linkWidth*0.6,
                lineColor: data.getClient('lineColor'),
                lineWidth: linkWidth*0.2,
                fill: 'white',
            });
        }
        return result;
    }
});

动画效果拽拽拽

从上图还可以看到,在换乘站图标中,除了增加了颜色,还实现了旋转效果。这个就秒杀百度家了。
来看代码:

    twaver.Util.registerImage('rotateArrow', {
        w: 124,
        h: 124,
        v: [{
            shape: 'vector',
            name: 'doubleArrow',
            rotate: 360,
            animate: [{
                attr: 'rotate',
                to: 0,
                dur: 2000,
                reverse: false,
                repeat: Number.POSITIVE_INFINITY
            }]
        }]
    });

当然这对于TWaver来说也很容易,只不过对rotate属性进行了动态改变而已。

另外,在单击和双击站点时,还实现了selected和loading的动画效果,值得点赞!

地铁图单击 地铁图之缓冲

混合缩放炫炫炫

无失真缩放是矢量图的先天优势,小弟也掌握得炉火纯青,把TWaver的混合缩放模式用到极致,还有缩放比例控制、文字自动隐藏等小功能,方便订制。

地铁图缩放

代码也不复杂:

    network.setZoomManager(new twaver.vector.MixedZoomManager(network));
    network.setMinZoom(0.2);
    network.setMaxZoom(3);
    network.setZoomVisibilityThresholds({
        label : 0.6,
    });

交互功能用起来

小弟很自豪地给我介绍这个功能:图标可以自由拖动,松开后会自动弹回。哥问小弟这有什么用,他一本正经地说:证明图是活的!

地铁图拖拽回弹

好吧你赢了,虽然是个没什么卵用的功能,但闲的蛋疼的时候可以随便玩上几十分钟我也是信的。

连续单击同一站点

连续单击同一站点(注意不是双击),可以将经过此站点的所有线路突出显示出来。小弟说加入这个功能纯粹因为简单易做,我……竟然表示非常理解,谁年轻时没耍过这类轻松又讨好的小招数呢?

地铁图经过线路

双击站点

双击站点,竟然弹出了本站周边的电子地图!知道引入他山之玉,看来小子可教啊。我发现他的定位方法,有的是用经纬度,有的是关键词查询。小弟狡黠地说,开始是人工查每个站点经纬度的,干了一段儿发现太麻烦,后来改路子了。马大大说的,懒人改变世界,我服!

地铁图电子<a class=地图" src="https://img-blog.csdn.net/20161102151159720" />

最后来八一八程序设计的思路吧,小弟是棵好苗子,能做出那么像样的程序,必然是深思熟虑过的。不想再听我啰嗦的朋友,也可以直接发邮件给我,tw-service@servasoft.com,来鉴赏下小弟的成果。

数据文件的整理

数据格式,选择了JavaScript原生支持的json文件,直观方便。
数据结构,按照站点、线路、杂项三大块来组织,结构清晰,利于遍历、查询等操作。

    {
        "stations":{
            "l01s01":{ },
            …………
        }
        "lines":{
            "l01":{……},
            …………
        }
        "sundrys":{
            "railwaystationshanghai":{……},
            …………
        }
    }

命名比较规范,通过名字就可以看出基本信息(例如“l01s01”就是1号线第1个站点),甚至直接利用名字就可以进行查询和遍历。

    "l01s01":{
        "id":"l01s01",
        "name":"莘庄",
        "loc":{"x":419,"y":1330},
        "label":"bottomright.bottomright",
    },
    …………

站点路线的创建

首先是读取json文件的数据。

    function loadJSON(path,callback){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                   dataJson = JSON.parse(xhr.responseText);
                   callback && callback();
               }
           }
       };
       xhr.open("GET", path, true);
       xhr.send();
    }

因为读取文件是一个异步的过程,所以要程序的展开都要放在文件读取函数的内部。

    function init(){
        loadJSON("shanghaiMetro.json", function(){
            initNetwork(dataJson);
            initNode(dataJson);
        });
    }

只要通过对站点进行一次遍历,车站的建立就完成了。

    for(staId in json.stations){
        var station = json.stations[staId];
        staNode = new twaver.Node({
            id: staId,
            name: station.name,
            image:'station',
        });
        staNode.s('label.color','rgba(99,99,99,1)');
        staNode.s('label.font','12px 微软雅黑');
        staNode.s('label.position',station.label);
        staNode.setClient('location',station.loc);
        box.add(staNode);
    }

再对数据文件中的各条线路下的所有站点进行遍历,在站点间依次创建Link。

    for(lineId in json.lines) {
        ……
        for(staSn in line.stations) {
            ……
            var link = new twaver.Link(linkId,prevSta,staNode);
            link.s('link.color', line.color);
            link.s('link.width', linkWidth);
            link.setToolTip(line.name);
            box.add(link);
        }
    }

再对label位置进行调整,否则站点名称会显示的很乱。小弟是通过在原始数据中手动加入位置信息来实现的,稍显笨了一点,应该可以通过程序自动判断站点周围空间来进行智能调整。

最后再加入图标,一张原始的地铁图就呈现出来了。

初始地铁图

路线拐点的添加

基本的示意功能已经具备了,这里,小弟让我很欣赏的一点是没有就此停止,而是进一步做了调整,使线路只保留了横平竖直和正斜的走向,以达到整齐美观的效果。可能看起来与参考图稍稍有些不同,主要因为各路段基本只添加了一个拐点,这样做既大大简化了程序,又基本保证了图形的美观度。想远一点,做多一点,是块做产品的好料子。

智能拐点

当然为了提高程序的灵活性,应对必须添加两个或以上拐点的情况,也使用了人工拐点的手段。不过这里人工拐点被设成一个隐形的节点,可能利于智能拐点的判断,但也有可能在路线操作时造成混乱。如何处理更好还可以进一步推敲。

var createTurnSta = function(line, staSn){
    staTurn = new twaver.Node(staSn);
    staTurn.setImage();
    staTurn.setClient('lineColor',line.color);
    staTurn.setClient('lines',[line.id]);
    var loc = line.stations[staSn];
    staTurn.setClient('location',loc);
    box.add(staTurn);
    return staTurn;
}

接点位置的调整

大家可以看到,并不是所有路段都直接连入站点中心,在许多情况下必须要进行偏移。

var createFollowSta = function(json, line, staNode, staId){
    staFollow = new twaver.Follower(staId);
    staFollow.setImage();
    staFollow.setClient('lineColor',line.color);
    staFollow.setClient('lines',[line.id]);
    staFollow.setHost(staNode);
    var az = azimuth[staId.substr(6,2)];
    var loc0 = json.stations[staId.substr(0,6)].loc;
    var loc = {x:loc0.x+az.x, y:loc0.y+az.y};
    staFollow.setClient('location',loc);
    box.add(staFollow);
    return staFollow;
}

并行线路

小弟采取了虚拟节点的办法,就是在站点的旁边,添加一个Follower(但并不显示出来),让并行的不同线路连接到不同的Follower上。通过调整Follower的位置,来实现线路与站点连接点的控制。

var azimuth = {
    bb: {x: 0, y: linkWidth*zoom/2},
    tt: {x: 0, y: -linkWidth*zoom/2},
    rr: {x: linkWidth*zoom/2, y: 0},
    ll: {x: -linkWidth/2, y: 0},
    br: {x: linkWidth*zoom*0.7/2, y: linkWidth*zoom*0.7/2},
    bl: {x: -linkWidth*zoom*0.7/2, y: linkWidth*zoom*0.7/2},
    tr: {x: linkWidth*zoom*0.7/2, y: -linkWidth*zoom*0.7/2},
    tl: {x: -linkWidth*zoom*0.7/2, y: -linkWidth*zoom*0.7/2},
    BB: {x: 0, y: linkWidth*zoom},
    TT: {x: 0, y: -linkWidth*zoom},
    RR: {x: linkWidth*zoom, y: 0},
    LL: {x: -linkWidth, y: 0},
    BR: {x: linkWidth*zoom*0.7, y: linkWidth*zoom*0.7},
    BL: {x: -linkWidth*zoom*0.7, y: linkWidth*zoom*0.7},
    TR: {x: linkWidth*zoom*0.7, y: -linkWidth*zoom*0.7},
    TL: {x: -linkWidth*zoom*0.7, y: -linkWidth*zoom*0.7}
};

介绍到这里就结束了,虽然是个小例子,实在是但美观性和实用性都还过得去,小弟花了心思去做,其实稍加改造就可以做出高铁图、公交图、运行图等应用。设想一下,如果能用在轨道交通列控中心大屏监控里,是多么炫酷。说到这,又想起了前段时间云栖大会上刚看到的杭州城市数据大脑,不知何时,哥也能参与一把那样的项目呢?可视化,哥的强项……

最后,想要看程序,或者想玩“地铁拖拖乐”的各位,都可以给我留言和发邮件:tw-service@servasoft.com。


http://www.niftyadmin.cn/n/1765720.html

相关文章

两种在wordperss中动态设置body ID的方法

在我们设计网站的时候&#xff0c;在不同的页面中为元素设置相应的id是有非常大的好处的&#xff0c;这非常有利于识别创建独特的css样式。今天向大家分享四种在wordperss中动态设置body ID 的方法。 例如我们常见的 <body id"about"> 在这种情况下&#xff0…

10个TWaver网页3D可视化精彩案例

以下网页3D案例均为TWaver原创出品&#xff0c;推荐使用Chrome, FireFox, Safari等对WebGL支持良好的浏览器运行。案例排名不分先后&#xff0c;如需Demo&#xff0c;可直接申请试用。 1、化学元素周期表 六种排列方式&#xff0c;炫酷动画效果&#xff0c;TWaver 3D轻松实现…

C# 开发者代码审查清单【转】

这是为C#开发者准备的通用性代码审查清单&#xff0c;可以当做开发过程中的参考。这是为了确保在编码过程中&#xff0c;大部分通用编码指导原则都能注意到。对于新手和缺乏经验&#xff08;0到3年工作经验&#xff09;的开发者&#xff0c;参考这份清单编码会很帮助。 清单 1.…

VR技术在数据中心3D机房中的应用(上)

前言 前两天跟朋友A吃饭&#xff0c;吃着吃着就说到了VR。近几年来&#xff0c;VR技术越来越火&#xff0c;感觉能跟VR沾点边的都特别高大上&#xff0c;朋友A也是&#xff0c;一提到VR&#xff0c;就怎么都掩盖不住他发自肺腑的敬仰之情。好吧&#xff0c;作为一个技术宅&…

[妙味JS基础]第二课:for应用、this关键字

知识点总结 getElementsByTagName&#xff08;动态方法&#xff09; 与 getElementById&#xff08;静态方法&#xff09; 的区别1、ID前面只能跟document,不能跟其他元素&#xff0c;比如&#xff1a;document.getElementById(list)TagName前面可以跟其他元素也可以跟document…

TCPView for Windows

TCPView是一个用来显示系统中所有的TCP和UDP端点&#xff08;endpoint&#xff09;列表的Windows程序&#xff0c;包括本地和远程的网络地址&#xff0c;以及TCP连接的状态。在Windows Server 2008、Vista、NT、2000和XP上&#xff0c;TCPView还会显示拥有端点的进程名。TCPVie…

CSS知识点汇总(六)--垂直居中动画实现方式

文章目录 1. CSS 垂直居中有哪些实现方式&#xff1f;2.css加载会造成阻塞吗&#xff1f;3. 前端实现动画有哪些方式&#xff1f; 1. CSS 垂直居中有哪些实现方式&#xff1f; 在布局一个页面时&#xff0c;通常都会用到水平居中和垂直居中&#xff0c;处理水平居中很好处理&am…

VR技术在数据中心3D机房中的应用(下)

VR技术在数据中心3D机房中的应用 &#xff08;下&#xff09; 前面给大家简单科普了一下VR的硬件设备以及VR在各个领域的应用&#xff0c;是不是觉得非常高大上&#xff1f;千言万语概括成一句话&#xff0c;VR能给用户带来前所未有的沉浸感和交互方式&#xff0c;让人足不出户…