前面介绍了上海地铁图的绘制,最近有客户提出了新的需求:双车道,并显示路网状态信息。经过一番研究,在原地铁图基础上做了扩展实现
进入微软、亚马逊,谷歌等美国IT企业工作人才项目,起薪40万,百度搜索(MUMCS)
交通图介绍
路况状态在GIS系统中广泛应用,谷歌地图,百度地图都有实时路况的功能,太复杂并非好事,就像地铁图,按真实经纬度呈现反而不够直观,交通图、路网也是如此,去掉无关信息,将有限的数据(路,收费站,路况)展现出来,成为一种解决方案
百度地图中的路况信息
双车道的绘制
来看具体实现,原来的地铁图是一条线表示,改用双线绘制,可表现来往的方向,canvas并没有双线线形,需要自己实现,双线的算法类似2d中的stroke算法,stroke拐点有三种方式:尖的、圆角、斜面,考虑到路网拐角不会太尖,所以简单实现,采用miter方式,沿线各个拐点左右偏移
三种连接点类型
绘制双车道,计算拐点的法线和夹角
function drawDoubleLine(path, points, isDoubleLine, size, lineDirection) { var p0, p1; Q.forEach(points, function (p) { if (!p1) { p1 = p; return; } p1._a = Math.atan2(p.y - p1.y, p.x - p1.x); if (p0) { p1.angle = Math.atan2(Math.sin(p0._a) + Math.sin(p1._a),
Math.cos(p0._a) + Math.cos(p1._a)); p1.angle -= Math.PI / 2; var theta = Math.abs(p1._a - p0._a); if (theta > Math.PI) { theta = 2 * Math.PI - theta; } p1.inclinedAngle = Math.PI - theta; } else { p1.angle = p1._a - Math.PI / 2; } p0 = p1; p1 = p; }); p1.angle
= Math.atan2(p1.y - p0.y, p1.x - p0.x) - Math.PI / 2; if (lineDirection == "left") { drawLine(path, points, 0.5, size); return; } if (lineDirection == "right") { drawLine(path, points, -0.5, size); return; } if (!isDoubleLine) { drawLine(path, points, 0, size);
return; } drawLine(path, points, 0.5, size); drawLine(path, points, -0.5, size); }
绘制连线
function drawLine(path, points, yOffset, size, doubleLine) { Q.forEach(points, function (p, index) { var angle = p.angle; var inclinedAngle = p.inclinedAngle; var x = p.x, y = p.y; var offset = yOffset; if (offset) { offset *= 2 / 3 * 0.8; } if (p.yOffset)
{ offset += p.yOffset; } if (offset) { offset *= size; if (inclinedAngle) { offset /= Math.max(0.2, Math.sin(inclinedAngle / 2)); } var sin = Math.sin(angle); var cos = Math.cos(angle); x += cos * offset; y += sin * offset; } if (index == 0) { path.moveTo(x,
y); } else { path.lineTo(x, y); } }); }
双车道呈现效果
路况状态绘制
路况状态也是呈线条状,与路网绘制相同,只不过为单向,还是上面的绘制函数,参数lineDirection表示车道方向,左侧车道偏移50%,右侧则偏移-50%,这样可以实现两侧不同的状态
function drawDoubleLine(path, points, isDoubleLine, size, lineDirection) { ... if (lineDirection == "left") { drawLine(path, points, 0.5, size); return; } if (lineDirection == "right") { drawLine(path, points, -0.5, size); return; } ... }
路况模拟数据
与原来的例子相同,路况信息也可以通过JSON数据加载,整个为一个array,集合中每个元素为一条路的路况片段信息,"line"属性表示所在路线的编号,"fragments"表示路况片段集合,每个片段包含三个属性,与路线的json表示相同,只不过增加了"direction"属性,表示片段的方向
[{ "line": "11", "fragments": [ { "color": "#FF0000", "direction": "right", "stations": [230, 231, 232] }, { "color": "#FFFF00", "direction": "left", "stations": [229, 230, 231, 232] }, { "color": "#00FF00", "direction": "left", "stations": [227, 228, 229]
} ] }]
路况运行效果
上面11号线上的模拟数据,得到下面的效果
在线演示
在线演示:http://demo.qunee.com/#Shanghai Metro Map 2012
示例下载:路况图示例.zip
基于html5技术绘制上海地铁图 - 双车道路况信息