前言
最近特别忙,承蒙大伙关照,3D机房的项目一个接着一个,领了一帮小弟,搞搞传帮带……有个小弟很不错,勤奋好学,很快就把API都摸透了,自己折腾着做了个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, });
交互功能用起来
小弟很自豪地给我介绍这个功能:图标可以自由拖动,松开后会自动弹回。哥问小弟这有什么用,他一本正经地说:证明图是活的!
好吧你赢了,虽然是个没什么卵用的功能,但闲的蛋疼的时候可以随便玩上几十分钟我也是信的。
连续单击同一站点
连续单击同一站点(注意不是双击),可以将经过此站点的所有线路突出显示出来。小弟说加入这个功能纯粹因为简单易做,我……竟然表示非常理解,谁年轻时没耍过这类轻松又讨好的小招数呢?
双击站点
双击站点,竟然弹出了本站周边的电子地图!知道引入他山之玉,看来小子可教啊。我发现他的定位方法,有的是用经纬度,有的是关键词查询。小弟狡黠地说,开始是人工查每个站点经纬度的,干了一段儿发现太麻烦,后来改路子了。马大大说的,懒人改变世界,我服!
最后来八一八程序设计的思路吧,小弟是棵好苗子,能做出那么像样的程序,必然是深思熟虑过的。不想再听我啰嗦的朋友,也可以直接发邮件给我,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。
相关推荐
本资源是关于“数据可视化实战:使用D3设计交互式图表”的教程,结合了理论知识与实际操作,旨在帮助用户掌握D3.js库在创建交互式数据可视化中的应用。 D3.js,全称Data-Driven Documents,是由Mike Bostock开发的...
本书《精通D3.js:交互式数据可视化高级编程》系统地介绍了D3.js的所有重要知识点,从基础入门到深入内容都有详细讲解,适合希望提高数据可视化能力的读者。 在介绍D3.js之前,首先需要了解Web标准技术的基础,包括...
梗概:爬取公交路径坐标,处理成为符合高德地图Map Lab线形图的格式,通过该平台绘制公交(地铁)线路图等 一些必要的知识点可在该系列博客的其他内容中获得! 1 采用循环法获取线路名 怎么获取一个城市有哪些线路名...
第1章写在前面11.1 数据为什么要可视化 11.2 为什么要写代码 21.3 为什么要交互 21.4 为什么要在 Web 上 31.5 这是一本什么书 31.
这本书旨在帮助读者从初级到高级全面掌握D3.js,特别关注交互式数据可视化的实现。书中涵盖了以下核心知识点: - **D3.js基础知识**:讲解D3.js的核心概念,如选择集、数据绑定、元素的添加与更新、转换和动画。 - ...
《精通D3.js:交互式数据可视化高级编程》以当前流行的数据可视化技术D3.js为主要内容,分为三大部分,共计13章。第一部分讲述基础知识,第二部分学习制作各种常见图表,第三部分讲解交互式图表及地图的进阶应用。...
14. **数据可视化库Matplotlib**:Matplotlib是最基础的Python绘图库,可以生成各种静态、动态和交互式图表,如折线图、散点图、直方图等。 15. **Seaborn**:Seaborn是基于Matplotlib的高级数据可视化库,提供了更...
5. **Bokeh库**:Bokeh专注于高性能、交互式的Web可视化,能够处理大量数据,适用于大数据分析和实时应用。读者将学习如何利用Bokeh创建可缩放的图形,并实现浏览器中的交互功能。 6. **数据可视化原则**:书中会...
在绘制地铁线路图时,JQuery主要负责处理用户交互和数据操作。 要绘制北京地铁线路图,我们需要以下步骤: 1. 数据准备:收集北京地铁线路、站点和连接信息,通常以JSON或XML格式存储。这些数据包括线路颜色、站点...
《精通D3.js 交互式数据可视化高级编程》是一本深度探讨D3.js库的专著,旨在帮助读者掌握利用D3.js进行高效且富有吸引力的数据可视化的技能。D3.js,全称Data-Driven Documents,是一种强大的JavaScript库,允许...
在这个专题中,“数据可视化大屏-前后端数据交互”指的是在构建可视化大屏时,前端与后端如何有效地进行数据通信以实现动态展示和实时更新。 **一、前端数据可视化** 前端是用户与应用交互的界面,对于数据可视化...
HTML、CSS和JavaScript是构建网页和交互式应用的基础技术,而在数据可视化的领域,这三者结合能够创建出令人印象深刻的动态数据大屏。在这个"HTML+CSS+JS数据可视化大屏平台模板实例10-大数据地图"中,我们将探讨...
4. **交互式可视化**:为了更好地探索和理解数据,交互式可视化可以提供用户参与的能力,例如通过鼠标悬停查看具体数据点信息,或通过拖动改变视图。 5. **颜色编码**:在数据可视化中,颜色选择和用法至关重要。...
交互式数据可视化期末大作业基于Python+pyecharts的结婚离婚数据分析与可视化项目源码(高分项目)交互式数据可视化期末大作业基于Python+pyecharts的结婚离婚数据分析与可视化项目源码(高分项目)交互式数据可视化...
《数据可视化实战-使用D3设计交互式图表》这本书专注于介绍如何利用D3.js这个强大的JavaScript库来创建交互式的Web图表。 D3全称为Data-Driven Documents,它允许开发者直接操作DOM(Document Object Model)来绑定...
VISDMiner:一个交互式数据挖掘过程可视化系统.pdf
HTML5炫酷科技感十足数据可视化HTML5炫酷科技感十足数据可视化HTML5炫酷科技感十足数据可视化HTML5炫酷科技感十足数据可视化HTML5炫酷科技感十足数据可视化HTML5炫酷科技感十足数据可视化HTML5炫酷科技感十足数据...
3. **交互式可视化**:现代数据可视化工具通常提供交互功能,用户可以通过点击、拖动等方式探索数据,这使得分析过程更加动态和直观。交互式可视化可以深入数据细节,发现隐藏的模式。 4. **数据故事讲述**:数据...
5. **Pandas**: 虽然不是专门的可视化库,但Pandas的DataFrame对象与上述所有可视化库紧密集成,提供了方便的数据预处理和分析功能,是进行数据可视化工作的重要基础。 在《Python数据可视化编程实战》的配套文件中...
5. **数据看板图片**:数据看板是一种交互式的信息展示工具,包含各种图表和指标,用于实时更新和展示关键绩效指标(KPIs)。在地图数据可视化看板中,图片可能包括自定义的地图背景、动态的区域高亮、以及随着时间...