前言

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

效果图对比

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

再来看看小弟做的:

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

文本提示弹弹弹

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

站点图标变变变

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

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

  1. twaver.Util.registerImage('station',{
  2. w: linkWidth*1.6,
  3. h: linkWidth*1.6,
  4. v: function (data, view) {
  5. var result = [];
  6. if(data.getClient('focus')){
  7. result.push({
  8. shape: 'circle',
  9. r: linkWidth*0.7,
  10. lineColor:  data.getClient('lineColor'),
  11. lineWidth: linkWidth*0.2,
  12. fill: 'white',
  13. });
  14. result.push({
  15. shape: 'circle',
  16. r: linkWidth*0.2,
  17. fill:  data.getClient('lineColor'),
  18. });
  19. }else{
  20. result.push({
  21. shape: 'circle',
  22. r: linkWidth*0.6,
  23. lineColor: data.getClient('lineColor'),
  24. lineWidth: linkWidth*0.2,
  25. fill: 'white',
  26. });
  27. }
  28. return result;
  29. }
  30. });

动画效果拽拽拽

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

  1. twaver.Util.registerImage('rotateArrow', {
  2. w: 124,
  3. h: 124,
  4. v: [{
  5. shape: 'vector',
  6. name: 'doubleArrow',
  7. rotate: 360,
  8. animate: [{
  9. attr: 'rotate',
  10. to: 0,
  11. dur: 2000,
  12. reverse: false,
  13. repeat: Number.POSITIVE_INFINITY
  14. }]
  15. }]
  16. });

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

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

混合缩放炫炫炫

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

代码也不复杂:

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

交互功能用起来

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

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

连续单击同一站点

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

双击站点

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

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

数据文件的整理

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

  1. {
  2. "stations":{
  3. "l01s01":{ },
  4. …………
  5. }
  6. "lines":{
  7. "l01":{……},
  8. …………
  9. }
  10. "sundrys":{
  11. "railwaystationshanghai":{……},
  12. …………
  13. }
  14. }

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

  1. "l01s01":{
  2. "id":"l01s01",
  3. "name":"莘庄",
  4. "loc":{"x":419,"y":1330},
  5. "label":"bottomright.bottomright",
  6. },
  7. …………

站点路线的创建

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

  1. function loadJSON(path,callback){
  2. var xhr = new XMLHttpRequest();
  3. xhr.onreadystatechange = function(){
  4. if (xhr.readyState === 4) {
  5. if (xhr.status === 200) {
  6. dataJson = JSON.parse(xhr.responseText);
  7. callback && callback();
  8. }
  9. }
  10. };
  11. xhr.open("GET", path, true);
  12. xhr.send();
  13. }

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

  1. function init(){
  2. loadJSON("shanghaiMetro.json", function(){
  3. initNetwork(dataJson);
  4. initNode(dataJson);
  5. });
  6. }

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

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

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

  1. for(lineId in json.lines) {
  2. ……
  3. for(staSn in line.stations) {
  4. ……
  5. var link = new twaver.Link(linkId,prevSta,staNode);
  6. link.s('link.color', line.color);
  7. link.s('link.width', linkWidth);
  8. link.setToolTip(line.name);
  9. box.add(link);
  10. }
  11. }

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

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

路线拐点的添加

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

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

  1. var createTurnSta = function(line, staSn){
  2. staTurn = new twaver.Node(staSn);
  3. staTurn.setImage();
  4. staTurn.setClient('lineColor',line.color);
  5. staTurn.setClient('lines',[line.id]);
  6. var loc = line.stations[staSn];
  7. staTurn.setClient('location',loc);
  8. box.add(staTurn);
  9. return staTurn;
  10. }

接点位置的调整

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

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

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

  1. var azimuth = {
  2. bb: {x: 0, y: linkWidth*zoom/2},
  3. tt: {x: 0, y: -linkWidth*zoom/2},
  4. rr: {x: linkWidth*zoom/2, y: 0},
  5. ll: {x: -linkWidth/2, y: 0},
  6. br: {x: linkWidth*zoom*0.7/2, y: linkWidth*zoom*0.7/2},
  7. bl: {x: -linkWidth*zoom*0.7/2, y: linkWidth*zoom*0.7/2},
  8. tr: {x: linkWidth*zoom*0.7/2, y: -linkWidth*zoom*0.7/2},
  9. tl: {x: -linkWidth*zoom*0.7/2, y: -linkWidth*zoom*0.7/2},
  10. BB: {x: 0, y: linkWidth*zoom},
  11. TT: {x: 0, y: -linkWidth*zoom},
  12. RR: {x: linkWidth*zoom, y: 0},
  13. LL: {x: -linkWidth, y: 0},
  14. BR: {x: linkWidth*zoom*0.7, y: linkWidth*zoom*0.7},
  15. BL: {x: -linkWidth*zoom*0.7, y: linkWidth*zoom*0.7},
  16. TR: {x: linkWidth*zoom*0.7, y: -linkWidth*zoom*0.7},
  17. TL: {x: -linkWidth*zoom*0.7, y: -linkWidth*zoom*0.7}
  18. };

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

作者:MonoLog

来源:51CTO

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

  1. db4o, 看上去很美

    由于厌烦了手写Sql,在几个小项目中尝试着使用了Db4O.DAL层写起来是爽了,但是,还是有很多其它东西会绊你的脚. 没有主键的概念(因为对象的内存地址,或者引用就能标志一个对象了).因而外界想指向一 ...

  2. 看起来很美 VS. 是你来检阅我的忧伤了吗?

    看来了wayfarer "设计,看上去很美!"--算是我的随想<?xml:namespace prefix = o ns = "urn:schemas-micros ...

  3. 你的IT运维管理,是否只是“看起来很美”?

    原文[请点击] 又有个故事,说是有两只老虎,有一天路过一片肥美的草地,其中一只看见这里环境优美,便被深深吸引,留恋不已 .另一只老虎劝说道:"这里景色虽说不错,但看不见一只牛羊,根本不适合我 ...

  4. 设计,看上去很美 wayfarer

    设计,看上去很美 设计没有标准,模式充满变化,我们对设计与模式的探讨,就是希望能从没有标准的设计中体验设计的乐趣,从充满变化的模式中寻求问题的解决之道.     我这里所谓"设计没有标准&q ...

  5. 转龚文祥的一篇文章:对看起来很美的网站要保持审慎的乐观

    做网站的人很喜欢参考竞争对手的网站,也总是觉得别人网站模式.设计及新产品做的好,其实客观的心态是对于人家网站的好的东西要借鉴,但不能盲从,尤其对于暂时成功的网站要以在一定背景.大形势下成功的眼光去看, ...

  6. 一枝看上去很美的花——书评《Java与模式》

    一枝看上去很美的花 --书评<Java与模式> 撰文/剃刀 (本文首发于<程序员>杂志2003年第1期) 躺在我面前的,是阎宏博士编著.电子工业出版社出版的厚达1024页的&l ...

  7. 显示器3d测试软件,3D显示器专题测试看上去很美.pdf

    3D显示器专题测试看上去很美.pdf 3D 显 示 器 专 题 测 试 当 无 拖 影 . L E D 背 光 和 广 色 域 等 技 术 E 经 不 再 新 鲜 . 液 晶 显 示 器 再 次 遇 ...

  8. SAP HR技术系列之一:e-HR,不只是看起来很美

    转载:http://qyzx.jxufe.edu.cn/ehr/EHRzixun/2013-05-26/58.html 伴随劳动法规的逐步完善以及金融危机影响的持续深入,大力控制人工成本成为很多企业的 ...

  9. 转: 看上去很美——国内CDN现状与美国对比

    来自:http://blog.csdn.net/fayu0903/archive/2009/03/25/4022979.aspx 天国王朝(Kingdom of Heaven) 作者:阀域 CDN的理 ...

  10. 看上去很美——关于SaaS的八大误区

    看上去很美--关于SaaS的八大误区 作者:  Amteam.org 原文地址: http://www.vsharing.com/k/2008-11/618046.html 1.SaaS是一种因为提供 ...

最新文章

  1. 关闭webstorm自动保存,并显示文件未保存标识
  2. RF-LIO:面向高动态场景的紧耦合LiDAR惯导融合里程计(IROS 2021)
  3. 在同一台电脑上弄分布(异步)式训练
  4. 是什么_什么是模电,什么是数电
  5. android camera 检测,检测Android Camera文件夹
  6. Java窗口(JFrame)从零开始(8)——文本框+文本域+密码框
  7. fatjar打包mysql_一个简单的解压ZIP Excl文件---gt;按时间读取Excle文件,通过Fat jar打成jar相对应的添加到mysql数据库中。 - 明月 - ITeye博客...
  8. hdu 6386 Age of Moyu (重边判断)
  9. UOJ#449. 【集训队作业2018】喂鸽子 min-max容斥,FFT
  10. Linux常用指令---netstat(网络端口)
  11. 广播(有序)跨应用发送简单举例
  12. POJ NOI0105-42 画矩形
  13. C# winform+ springboot + mybatis 分页查询
  14. 数据库入门级学习(1)
  15. OSAL操作系统抽象层
  16. 计算混响时间的意义_大盘点:混响时间常用的几种计算公式
  17. 2017云栖大会Tech Insight亮点大剧透
  18. 12306验证码分割
  19. 计算机组成原理(动态随机存储器)
  20. 【百度网盘】 个人资源共享

热门文章

  1. Neo4j(一):Neo4j的下载与安装
  2. 【虚拟机】VirtualBox 安装 Windows 11 虚拟机简介
  3. CSS字体和文本相关
  4. 七天学会php,十天学会PHP之第六天
  5. 移动,电信,中行软开,微软,百度等企业工作纯技术性分析
  6. 2019年上半年信息系统项目管理师下午案例分析真题及答案解析
  7. Overloud TH3 for Mac - 电吉他效果器
  8. 计算机关于职业与道德的论文怎么写,计算机职业道德论文提纲模板 计算机职业道德论文大纲怎么写...
  9. 这是我转载的一篇,真的是不错《把SWF变回FLA》大家可以试试
  10. 学习记录之显示屏语言模块确定,星瞳学习