drawSvg.js 9.79 KB
/**
* 画线路svg 图
* type: 0 上行站点  1 下行站点  2  上下行共有  3 不同名合并
*/
var drawSvg = (function(){
	
	var mt = 44//顶部距离
		,p = 112//上下行之间的间隔  132
		,x = d3.scale.linear()
		,w
		,homeSvgMapp = {}
		,aloneSvgMapp = {}
		,lineStations = {}
		,seGps = {} //起终点gps信号;
	
/*	var arcPath = function(cx, cy, arc){
		return 'M' + cx + ',' + cy + ' C' + arc + ',' + (cy + 5) + ' ' + arc + ',' + (cy + p - 13) + ' ' + cx + ',' + (cy + p - 8);
	}*/
	
	var upStation = function(value){
		return value.type != 1 ;
	}
	
	var downStation = function(value){
		return value.type != 0;
	}
	
	var line = {
		up: d3.svg.line().x(function(d) {
			return d.cx;
		}).y(function(){return mt}),
		down: d3.svg.line().x(function(d) {
			return d.cx;
		}).y(function(){return mt + p})
	}
	
	
	var cx = function(d, i){
		return x(i);
	}
	
	var cutNbbm = function(nbbm){
		return nbbm.substr(nbbm.length - 3, nbbm.length);
	}

	var drawSvgObject = {
		initHomeSvg: function(lineId, data, container){
			var w = $('.line_chart:first').width(),
				svg = drawSvgObject.init(lineId, data, container, w, 80);
			//线路编码 和 首页SVG对照
			homeSvgMapp[lineId] = svg;
			if(svg && svg.length > 0){
				//双击事件
				$(svg[0]).dblclick(function(){
					$('#top-tabs-wrap .nav-tabs a[data-id='+this.id+']').click();
				});
			}
		},
		initAloneSvg: function(lineId, data, container){
			var w = $(document).width(),
				svg = drawSvgObject.init(lineId, data, container,w , 44);
			//线路编码 和 单线路SVG对照
			aloneSvgMapp[lineId] = svg;
		},
		init: function(lineId, data, container, w, mtop){
			if(!data || data.length == 0)
				return;
				
			mt = mtop;
			//起终点站
			$.each(data, function(){
				if(this.stationMark == 'B' || this.stationMark == 'E' )
					seGps[lineId + '_' + this.id[0]] = [];
			});
			
			var svg = d3.select('#' + container).append('svg')
				.attr('width', w).attr('opacity', 0)
				.attr('id', lineId);
			
			
			lineStations[lineId] = data.slice(0);
			//抽站
			cleanStation(w, data);
			var dLen = data.length;
			
			x.range([ 60 , w - 15]).domain([ 0,  dLen]);
			
			//上行线条
			drawPath(svg, data, 'up', 11);
			//下行线条
			drawPath(svg, data, 'down', 10);
			
/*			//左弧线 path
			svg.append('path')
				.attr('d', function(){
					var cx = x(0) - 8;
					return arcPath(cx , mt + 5,cx - 20);
				})
				.attr('class', 'up_path arc');
			
			//右弧线 path
			svg.append('path')
				.attr('d', function(){
					var cx = x(dLen - 1) + 8;
					return arcPath(cx , mt + 5,cx + 20);
				})
				.attr('class', 'down_path arc');*/
			
			var g = svg.append('g').selectAll('g')
					.data(data)
					.enter()
					.append('g').attr('class', 'item');
			
			//上行站点 circle
			drawCircle(g, 'up', lineId);
			
			//下行站点 circle
			drawCircle(g.select(function(d){return d.type!=0?this:null}), 'down', lineId);
			
			//站点名称 text
			g.append('text').attr('class', function(d, i){
					var c = 'station_text';
					if(i == 0)
						c += ' start';
					else if(i == dLen - 1)
						c += ' end';
					if(d.type == 3)
						c += ' up';
					return c;
				})
				.text(function(d){
					return d.type==3 ? d.name[0] : d.name;
				})
				.attr('x', function(d, i){return (d.type==3?(x(i) - 8):x(i))})
				.attr('y', mt + 10);
			
			
			//上下行不同名(异站合并)
			g.select(function(d){return d.type==3?this:null})
				.append('text')
				.attr('class', 'station_text down')
				.text(function(d){return d.name[1]})
				.attr('x', function(d, i){return x(i) + 8;})
				.attr('y', mt + 10);
			
			/**
			 * ---------------  文字居中啊,长度截断啊处理一下 ----------------------
			 */
			svg.selectAll('text')
				.attr('transform', function(d, i){
					var len = $(this).text().length;
					return 'translate(0,' + (len < 6?(6 - len) * 8:0) + ')';
				})
				.text(function(){
					var t = $(this).text()
						len = t.length;
					if(len > 6){
						var sortText = t.substring(0, 6);
						return sortText;
					}
					return t;
				});
			
			$(' .text-load', '#'+container).remove();
			svg.transition().duration(500).attr('opacity', 1);
			
			//GPS点容器
			svg.append('g').attr('class', 'gps-g-wrap');
			
			d3.selectAll('g.item circle').select(function(){
				return $(this).attr('class')?null:this;
			}).remove();
			
			return svg;
		},
		
		//画出GPS点
		drawVehicle: function(gpsArray){
			
			for(var i = 0, gps; gps = gpsArray[i ++];){
				//drawGpsToSvg(gps, aloneSvgMapp[gps.lineId]);
				drawGpsToSvg(gps, homeSvgMapp[gps.lineId]);
			}
			
			//画出起终点GPS信号
			var len;
			for(var eid in seGps){
				len = seGps[eid].length;
				if(len > 0){
					var e = $('#' + eid)
					,x = parseInt(e.attr('cx'))
					,y = parseInt(e.attr('cy'));
					
					var svg = homeSvgMapp[seGps[eid][0].lineId];
					
					var gs = svg.append('g').classed({'start': e.attr('class').indexOf('start') != -1, 'park': true})
						.selectAll('g').data(seGps[eid]).enter().append('g');
					//Y轴居中
					y = (y + 66) - len * 13;
					gs.append('rect')
						.attr('x', x + 15)
						.attr('y', function(d, i){
							return y + i * 27;
						})
						.classed({'gps-rect': true});
					
					gs.append('text')
						.attr('x', x + 18)
						.attr('y', function(d, i){
							return y + i * 27 + 17;
						})
						.text(function(d){return cutNbbm(d.nbbm)});
					
					_tooltip.initStartAndEndGPS(gs);
				}
			}
			
			/**
			 * 堆叠多个GPS信号
			 */
			$.each($('.station-gps-container'), function(i, multiGps){
				var tArray = $(multiGps).find('g')
					,updowm = $(multiGps).attr('updown')
					,translateY
					,len = tArray.length;
				
				var circle = $('#' + $(multiGps).attr('for')) 
					,c = circle.attr('class')
					,start = c.indexOf('start') != -1
					,end = c.indexOf('end') != -1;
				
				if(start || end || len > 2){
					tArray.hide();
					drawNumber(multiGps, len, this, start, end);
				}if(len == 2){
					if(updowm == 0){
						translateY = -60;
					}else
						translateY = 32;
					
					$(tArray[1]).css('transform', 'translate(-15px, '+ translateY +'px)');
				}
			});
			
			function drawNumber(multiGps, num, that, start, end){
				var circle = $('#' + $(multiGps).attr('for'))
				,x = circle.attr('cx')
				,y = circle.attr('cy');
				
				//数字标记
				var numberG = d3.select(that).append('g').attr('class', 'number-g');
				
				if(start)
					numberG.classed({'start': true});//始发站
				else if(end)
					numberG.classed({'end': true});//终点站
				
				numberG.append('rect').attr('x', x).attr('y', y);
				numberG.append('text').attr('x', x).attr('y', y).text(num);
			}
		}
	};
	
	function drawGpsToSvg(gps, svg){
		var stionId = gps.lineId + '_' + gps.stopNo
		,station = $('#' + stionId)
		,c = station.attr('class')||""
		,start = c.indexOf('start') != -1
		,end = c.indexOf('end') != -1;

		if(station.length == 0)
			return;
		
		//起终点站GPS信号
		if(seGps[stionId]){
			seGps[stionId].push(gps);
			return;
		}
		
		var cx = parseInt(station.attr('cx'))
			,cy = parseInt(station.attr('cy'))
			,updown = station.attr('updown')
			,gpsGWrap = svg.select('.gps-g-wrap')
			,gpscont;
		
		if($('g[for='+stionId+']').length == 0){
			gpscont = gpsGWrap.append('g')
				.attr('class', 'station-gps-container')
				.attr('updown', updown)
				.attr('for', stionId);
		}else{
			gpscont = gpsGWrap.selectAll('g')
					.select(function(){return $(this).attr('for') == stionId?this:null})
					.classed({'multiple': true});
		}
		var vg = gpscont.selectAll('g[deviceId="'+gps.deviceId+'"]')
			.data([gps]).enter().append('g')
			.attr('deviceId', gps.deviceId)
			.attr('class', 'vehci-g ' + (updown==0?'up':'down'))
			.attr('station', gps.stopNo);
		
		//上下行异常
		/*if(!start && !end && updown != gps.upDown){
			vg.classed({'updown-error': true});
		}*/
		
		vg.append('text')
			.attr('x', cx + 4).attr('y', cy + 17)
			.text(cutNbbm(gps.nbbm));
		
		var rect = vg.append('rect').attr('x', cx).attr('y', cy);
		
		//tooltip
		_tooltip.initGpsTip(vg);
	}
	
	function drawPath(svg, data,updown, noclear){
		svg.append('g').selectAll('path')
			.data(data.slice(0, data.length - 1)).enter().append('path')
			.attr('d', function(d, i) {
				return line[updown]([{cx: x(i)}, {cx: x(i + 1)} ]);
			})
			.attr('class', updown + '_path')
			.attr('stroke-dasharray', function(d){//虚线
				if(d.clear && d.clear != noclear){
					$(this).css('stroke-width', '5px');
					return '2,1';
				}
				return 0;
		}); 
	}
	
	function drawCircle(g, updown, lineId){
		var len = g[0].length;
		g.append('circle')
			.attr('cx', cx)
			.attr('cy',  updown=='up'?mt:mt + p)
			.attr('id',function(d){
				if(d.id[0] != -1)
					return lineId + '_' + d.id[0];
			})
			.attr('updown', updown=='up'?0:1)
			.attr('class', function(d, i){
				var no = updown=='up'?1:0
					,classz= '';
				if(d.type != no)
					classz += (updown + '_station_circle');
				
				if(i == 0)
					classz += ' start';
				else if(i == len-1)
					classz += ' end';
				
				return classz;
			});
	}
	
	function cleanStation(w,data){
		var ms = w / 45
		,dLen = data.length;
		if(ms < dLen){
			var end;
			//最多清理一半
			if(ms < dLen / 2)
				end = parseInt(dLen / 2) + 1;
			else
				end = dLen - ms + 1;
			
			for(var i = 1; i < end; i ++){
				var rem = data[i];
				var prev = data[i - 1];
				
				prev.clear = rem.type + 10;//设置哪些点需要虚线连接
				data.splice(i, 1);//要被清理的站点
				
			}
		}
	}
	
	//双击svg切换
	//$('.line_chart svg').
	
	return drawSvgObject;
})();