Commit efae28850451effe9c868003ccf0caa86ea6c3af

Authored by 王通
1 parent 820760db

1.线调主页点击模拟图切换(只显示上行或下行)

src/main/resources/static/real_control_v2/fragments/home/layout.html
1 -<div>  
2 - <!-- home tab template -->  
3 - <script id="home-layout-tab-temp" type="text/html">  
4 - <ul id="home-main-content" class="uk-switcher">  
5 - {{each tabs as t i}}  
6 - <li {{if i==0}}class="uk-active"{{/if}} >{{t}}</li>  
7 - {{/each}}  
8 - </ul>  
9 -  
10 - <div class="home-panel-footer">  
11 - <ul class="uk-subnav uk-subnav-pill" data-uk-switcher="{connect:'#home-main-content', swiping: false}">  
12 - {{each tabs as t i}}  
13 - <li {{if i==0}}class="uk-active"{{/if}}><a> {{t}}</a></li>  
14 - {{/each}}  
15 - </ul>  
16 - <div class="home-rb-explain-icon ">  
17 - <a href="/real_control_v2/alone_page/home/home_wrap.html" target="_blank">  
18 - <i class="uk-icon-send-o home_alone_page uk-icon-hover" ></i>  
19 - </a>  
20 - &nbsp;&nbsp;  
21 - <i class="uk-icon-question-circle uk-icon-hover"></i>  
22 - </div>  
23 - </div>  
24 - </script>  
25 -  
26 - <!-- home line template -->  
27 - <script id="home-layout-line-temp" type="text/html">  
28 - {{each list as line i}}  
29 - <div class="uk-grid home-line-card" data-line-code="{{line.lineCode}}">  
30 - <div class="uk-width-medium-1-5 data-wrap up" id="home_{{line.lineCode}}_0"></div>  
31 - <div class="uk-width-medium-3-5 svg-chart-wrap">  
32 - <div class="home-svg-edit-icon" data-line-code="{{line.lineCode}}"></div>  
33 - <div class="top-center-big-text">  
34 - {{line.name}}  
35 - </div>  
36 - </div>  
37 - <div class="uk-width-medium-1-5 data-wrap down" id="home_{{line.lineCode}}_1"></div>  
38 - </div>  
39 - {{/each}}  
40 - </script>  
41 -  
42 - <script id="home-rb-explain-help-temp" type="text/html">  
43 - <ul class="uk-list">  
44 - <li>场外车辆,距离线路超过100米即为越界</li>  
45 - <li>超速以线路标准限速为准,为空则默认60</li>  
46 - <li>有任务时,连续2分钟无信号即为掉线</li>  
47 - <li>无任务时,连续10分钟无信号则已离线</li>  
48 - </ul>  
49 - </script>  
50 -</div> 1 +<div>
  2 + <!-- home tab template -->
  3 + <script id="home-layout-tab-temp" type="text/html">
  4 + <ul id="home-main-content" class="uk-switcher">
  5 + {{each tabs as t i}}
  6 + <li {{if i==0}}class="uk-active"{{/if}} >{{t}}</li>
  7 + {{/each}}
  8 + </ul>
  9 +
  10 + <div class="home-panel-footer">
  11 + <ul class="uk-subnav uk-subnav-pill" data-uk-switcher="{connect:'#home-main-content', swiping: false}">
  12 + {{each tabs as t i}}
  13 + <li {{if i==0}}class="uk-active"{{/if}}><a> {{t}}</a></li>
  14 + {{/each}}
  15 + </ul>
  16 + <div class="home-rb-explain-icon ">
  17 + <a href="/real_control_v2/alone_page/home/home_wrap.html" target="_blank">
  18 + <i class="uk-icon-send-o home_alone_page uk-icon-hover" ></i>
  19 + </a>
  20 + &nbsp;&nbsp;
  21 + <i class="uk-icon-question-circle uk-icon-hover"></i>
  22 + </div>
  23 + </div>
  24 + </script>
  25 +
  26 + <!-- home line template -->
  27 + <script id="home-layout-line-temp" type="text/html">
  28 + {{each list as line i}}
  29 + <div class="uk-grid home-line-card" data-line-code="{{line.lineCode}}">
  30 + <div class="uk-width-medium-1-5 data-wrap up" id="home_{{line.lineCode}}_0"></div>
  31 + <div class="uk-width-medium-3-5 svg-chart-wrap" id="svg_title_{{line.lineCode}}">
  32 + <div class="home-svg-edit-icon" data-line-code="{{line.lineCode}}"></div>
  33 + <div class="top-center-big-text">
  34 + {{line.name}}
  35 + </div>
  36 + </div>
  37 + <div class="uk-width-medium-1-5 data-wrap down" id="home_{{line.lineCode}}_1"></div>
  38 + </div>
  39 + {{/each}}
  40 + </script>
  41 +
  42 + <script id="home-rb-explain-help-temp" type="text/html">
  43 + <ul class="uk-list">
  44 + <li>场外车辆,距离线路超过100米即为越界</li>
  45 + <li>超速以线路标准限速为准,为空则默认60</li>
  46 + <li>有任务时,连续2分钟无信号即为掉线</li>
  47 + <li>无任务时,连续10分钟无信号则已离线</li>
  48 + </ul>
  49 + </script>
  50 +</div>
src/main/resources/static/real_control_v2/js/utils/svg_chart.js
1 -/* 线路模拟图 */  
2 -  
3 -var gb_svg_chart = (function () {  
4 -  
5 - //chart height  
6 - var chart_height = 122;  
7 - //left right padding  
8 - var x_padd = 30;  
9 - //上空白部分  
10 - var y_top_padd = 4;  
11 - //text max size  
12 - var t_max_size = 7;  
13 - //svg namespace  
14 - var svgns = 'http://www.w3.org/2000/svg';  
15 - var wraps={};  
16 - //根据wrap的class区分是home还是电子路单界面  
17 - var suffixs={  
18 - 'uk-width-medium-3-5 svg-chart-wrap': 'home',  
19 - 'svg-wrap': 'line'  
20 - }  
21 -  
22 - //站点间隔 线路编码 -> space  
23 - var circle_spaces={};  
24 - //var circle_space;  
25 - //是否启用动画  
26 - var animation = true;  
27 -  
28 - var calc_text_y = function (t) {  
29 - return (chart_height - (chart_height / t_max_size * t.length)) / 2 + 5;  
30 - },  
31 - cat_text = function (t) {  
32 - if(!t)  
33 - return 0;  
34 - return t.length > t_max_size ? t.substr(0, t_max_size) : t;  
35 - },  
36 - get_width = function (wrap) {  
37 - return wrap.actual('outerWidth');  
38 - },  
39 - get_height = function (wrap) {  
40 - var h = wrap.actual('outerHeight');  
41 - //隐藏元素取最外层的高度  
42 - return h < 20 ? wrap.parent().actual('outerHeight') - 2 : h;  
43 - };  
44 -  
45 - /**  
46 - * 绘制线路模拟图  
47 - * @param lineCode 线路编码  
48 - * @param wrap dom容器  
49 - * @param enableAttr 是否启用配置  
50 - */  
51 - var draw_line = function (lineCode, wrap, enableAttr) {  
52 - var wrapId = lineCode+'_'+suffixs[wrap.attr('class')];  
53 - wraps[wrapId]=wrap;  
54 - //环线  
55 - var loopLine = gb_data_basic.isLoopLine(lineCode);  
56 -  
57 - var routes = gb_data_basic.stationRoutes(lineCode);  
58 - if(!routes)  
59 - return;  
60 - var data = gb_svg_data_convert.mergeRoute(JSON.parse(JSON.stringify(routes)), enableAttr, lineCode, loopLine),  
61 - len = data.length;  
62 -  
63 - var w = get_width(wrap),  
64 - h = parseInt(get_height(wrap))  
65 - //x scale  
66 - ,  
67 - xScale = d3.scale.linear().range([x_padd, w - x_padd]).domain([0, len - 1]),  
68 - cx = function (d, i) {  
69 - return xScale(i);  
70 - },  
71 - cy = function () {  
72 - return (h - chart_height) / 2 + y_top_padd;  
73 - },  
74 - ty = function (d) {  
75 - return cy() + calc_text_y(cat_text(d.name[0]));  
76 - }  
77 - //line generator  
78 - ,  
79 - upLine = d3.svg.line().x(xScale).y(cy),  
80 - downLine = d3.svg.line().x(xScale).y(function () {  
81 - return cy() + chart_height  
82 - }),  
83 - multi_text = function (d, i, that) {  
84 -  
85 - var dText = document.createElementNS(svgns, 'text'),  
86 - t = cat_text(d.name[1]);  
87 - $(dText).attr('class', 'station_text down')  
88 - .attr('x', cx(d, i) + 8).attr('y', cy() + calc_text_y(t))  
89 - .attr('title', d.name[1])  
90 - .text(t);  
91 -  
92 - $(that).after(dText);  
93 - return cx(d, i) - 8;  
94 - };  
95 -  
96 - circle_spaces[wrapId] = (w - (x_padd * 2)) / len;  
97 - //add svg dom  
98 - var svg = d3.select(wrap[0]).append('svg')  
99 - .classed({  
100 - 'line-chart': true  
101 - }).attr('data-code', lineCode)  
102 - .attr('onselectstart', 'return false')  
103 - .style('height', h);  
104 -  
105 - //add item g  
106 - var items = svg.selectAll('g.item').data(data)  
107 - .enter().append('g').classed({  
108 - 'item': true  
109 - });  
110 -  
111 - //up station link path  
112 - var p_clzz = {  
113 - 'station_link': true  
114 - };  
115 - items.append('path').classed(p_clzz)  
116 - .attr('d', function (d, i) {  
117 - return i < len - 1 ? upLine([i, i + 1]) : '';  
118 - });  
119 -  
120 - //down station link path  
121 - p_clzz.down = true;  
122 - p_clzz.loop_line = loopLine;  
123 - items.append('path').classed(p_clzz)  
124 - .attr('d', function (d, i) {  
125 - return i < len - 1 ? downLine([i, i + 1]) : '';  
126 - });  
127 -  
128 - //up circle  
129 - var c_clzz = {  
130 - 'station_circle': true  
131 - };  
132 - items.select(function (d) {  
133 - return d.type != 1 ? this : null;  
134 - })  
135 - .append('circle').classed(c_clzz)  
136 - .attr('cx', cx)  
137 - .attr('cy', cy)  
138 - .attr('data-id', function (d) {  
139 - return d.id[0];  
140 - });  
141 -  
142 - //down circle  
143 - c_clzz.down = true;  
144 - items.select(function (d) {  
145 - return d.type != 0 ? this : null;  
146 - })  
147 - .append('circle').classed(c_clzz)  
148 - .attr('cx', cx)  
149 - .attr('cy', function (d, i) {  
150 - return cy(d, i) + chart_height;  
151 - })  
152 - .attr('data-id', function (d) {  
153 - return d.type == 1 ? d.id[0] : d.id[1];  
154 - });  
155 -  
156 - //station name text  
157 - items.append('text').classed({  
158 - 'station_text': true,  
159 - 'up': function (d) {  
160 - return d.type == 3 || d.type == 0 ? true : false;  
161 - },  
162 - 'down': function (d) {  
163 - return d.type == 1 ? true : false;  
164 - }  
165 - })  
166 - .text(function (d) {  
167 - return cat_text(d.name[0]);  
168 - })  
169 - .attr('title', function (d) {  
170 - return d.name[0];  
171 - })  
172 - .attr('x', function (d, i) {  
173 - return d.type == 3 ? multi_text(d, i, this) : cx(d, i)  
174 - })  
175 - .attr('y', ty);  
176 -  
177 - //gps wrap  
178 - svg.append('g').classed({  
179 - 'gps-wrap': true  
180 - });  
181 - //marker clusterer wrap  
182 - svg.append('g').classed({  
183 - 'marker-clusterer': true  
184 - });  
185 - };  
186 -  
187 -  
188 - // ----- draw gps ------  
189 - //gps 按线路站点分组后的下标映射  
190 - var line_gps_index = {};  
191 - var get_circle = function (dataId, svg) {  
192 - try {  
193 - var circle = $('.station_circle[data-id=' + dataId + ']', svg);  
194 - if (circle.length == 0)  
195 - circle = null;  
196 - } catch (e) {  
197 - console.log('get_circle error! station_circle data-id:' + dataId);  
198 - return null;  
199 - }  
200 - return circle;  
201 - },  
202 - gx = function (gps, svg, wrapId) {  
203 - var circle = get_circle(gps.stopNo + '_' + gps.upDown, svg);  
204 - if (!circle) return -100;  
205 -  
206 - var x = circle.attr('cx') - 16.5,  
207 - s = circle_spaces[wrapId] / 2;  
208 - // console.log('ss', gps.lineId + '=' + s);  
209 - //s = 5;  
210 - if(gps['instation']==0)  
211 - x = (gps['upDown']==0?x+s:x-s);  
212 - return x;  
213 - },  
214 - gy = function (gps, svg) {  
215 - var circle = get_circle(gps.stopNo + '_' + gps.upDown, svg);  
216 - if (!circle) return -100;  
217 -  
218 - var cy = parseInt(circle.attr('cy')),  
219 - index = line_gps_index[gps.lineId][gps.stopNo + '_' + gps.upDown][gps.deviceId];  
220 -  
221 - return gps.upDown == 0 ? cy - 22 - (index * 17) : cy + 6 + (index * 19);  
222 - },  
223 - ups_gps = function (d) {  
224 - return d.gpsUps;  
225 - },  
226 - downs_gps = function (d) {  
227 - return d.gpsDowns;  
228 - },  
229 - gps_index_mapp = function (data) {  
230 - var rs = {};  
231 - var dataGroupStop = gb_svg_data_convert.groupByStationAndUpdown(data);  
232 - for (var stopNo in dataGroupStop) {  
233 - rs[stopNo] = {};  
234 - $.each(dataGroupStop[stopNo], function (i, gps) {  
235 - rs[stopNo][gps.deviceId] = i;  
236 - });  
237 - }  
238 - return rs;  
239 - },  
240 - g_text = function (d) {  
241 - var len = (d.nbbm == false ? 0 : d.nbbm.length)  
242 - , t = len > 3 ? d.nbbm.substr(len - 3) : d.nbbm;  
243 -  
244 - if (d.nbbm.indexOf('-') > 0) {  
245 - t = d.nbbm.substr(d.nbbm.indexOf('-') - 1, 1) + t;  
246 - }  
247 - return t + d.suffix;  
248 - },  
249 - gps_key = function (d) {  
250 - return d.deviceId;  
251 - },  
252 - gps_update_point = function (e, svg, wrapId) {  
253 - var x,e1;  
254 - e1 = e;  
255 - if(animation)  
256 - e1 = e.transition();  
257 - e1.attr('x', function (d) {  
258 - x = gx(d, svg, wrapId);  
259 - if(x == -100)  
260 - $(this).css('transition-duration', 0).hide();  
261 - else  
262 - $(this).show();//找不到停靠点,直接隐藏  
263 - return x;  
264 - })  
265 - .attr('y', function (d) {  
266 - return gy(d, svg);  
267 - })  
268 - .attr('updown', function (d) {  
269 - return d.upDown;  
270 - });  
271 - e.classed({'abnormal': function (d) {  
272 - return d.abnormalClaszz;  
273 - }, 'offline': function (d) {  
274 - return d['abnormalStatus']=='offline';  
275 - }});  
276 - //update tip position  
277 - gb_svg_tooltip.update(e);  
278 - },  
279 - rct_id = function (d) {  
280 - return 'rct_' + d.deviceId;  
281 - },  
282 - tx_id = function (d) {  
283 - return 'tx_' + d.deviceId;  
284 - };  
285 -  
286 - var setGps = function (lineCode) {  
287 - var svgs = $('.line-chart[data-code=' + lineCode + ']');  
288 - if(svgsIsHidden(svgs))  
289 - return;  
290 - var data = gb_data_gps.gpsByLineCode(lineCode);  
291 -  
292 - var list = [], suffix, abmStatus;  
293 - //过滤无站点字段的数据  
294 - $.each(data, function () {  
295 - if (!this.stopNo || this.stopNo == '')  
296 - return true;  
297 -  
298 - abmStatus = this['abnormalStatus'];  
299 - suffix = '';  
300 - if(abmStatus != 'offline'){  
301 - this['abnormalClaszz'] = true;  
302 - if(abmStatus=='outBounds')  
303 - suffix = '界';  
304 - else if(abmStatus=='overspeed')  
305 - suffix = '速';  
306 - else if(abmStatus=='gps-offline')  
307 - suffix = '掉';  
308 - else  
309 - this['abnormalClaszz'] = false;  
310 - }  
311 - else  
312 - this['abnormalClaszz'] = false;  
313 -  
314 - this.suffix = suffix;  
315 - list.push(this);  
316 - });  
317 -  
318 - line_gps_index[lineCode] = gps_index_mapp(list);  
319 - $.each(svgs, function () {  
320 - if(!$(this).parent().is(":visible"))  
321 - return true;  
322 -  
323 - //绘制gps  
324 - draw_gps(this, list);  
325 - //聚合gps  
326 - marker_clusterer(this, lineCode);  
327 - });  
328 -  
329 - //刷新tooltip  
330 - gb_svg_tooltip.refresh();  
331 - };  
332 -  
333 - var draw_gps = function (svg, data) {  
334 - //remove merge_hide class  
335 - $('.merge_hide', svg).removeAttr('class');  
336 -  
337 - var gps_cont = d3.select(svg).select('.gps-wrap');  
338 - //rect  
339 - var rects = gps_cont.selectAll('rect').data(data, gps_key);  
340 - rects.enter().append('rect').attr('_id', rct_id);  
341 -  
342 - //lineCode+'_'+suffixs[wrap.attr('class')]  
343 - var wrapId = $(svg).data('code') + '_' + suffixs[$(svg).parent().attr('class')];  
344 - gps_update_point(rects, svg, wrapId);  
345 - //text  
346 - var ts = gps_cont.selectAll('text').data(data, gps_key);  
347 - ts.enter().append('text').attr('_id', tx_id);  
348 - ts.text(g_text)  
349 - gps_update_point(ts, svg, wrapId);  
350 - };  
351 -  
352 - var marker_clusterer = function (svg, lineCode) {  
353 - //debugger  
354 - var gpsArr, idxMapp = line_gps_index[lineCode];  
355 - for (var stopNo in idxMapp) {  
356 - gpsArr = gb_common.get_keys(idxMapp[stopNo]);  
357 - //remove old merger point  
358 - $('g[_id=' + 'merger_' + stopNo + ']', svg).remove();  
359 - if (gpsArr.length <= 2)  
360 - continue;  
361 -  
362 - marker_clusterer_merge(svg, stopNo, gpsArr);  
363 - }  
364 - };  
365 -  
366 - var marker_clusterer_merge = function (svg, stopNo, gpsArr) {  
367 - //stop circle  
368 - var circle = get_circle(stopNo, svg);  
369 - if (!circle) return;  
370 -  
371 - var x = parseInt(circle.attr('cx')),  
372 - y = parseInt(circle.attr('cy')),  
373 - isDown = circle.attr('class').indexOf('down') != -1;  
374 -  
375 - var svg = d3.select(svg);  
376 - //hide old element  
377 - $.each(gpsArr, function (i, d) {  
378 - $('rect[_id=rct_' + d + '],text[_id=tx_' + d + ']').attr('class', 'merge_hide');  
379 - });  
380 -  
381 - var mergerG = svg.selectAll('g.marker-clusterer').append('g').attr('_id', 'merger_' + stopNo)  
382 - .classed({  
383 - 'merge-item': true  
384 - });  
385 - //merge rect  
386 - mergerG.append('rect').attr('x', x - 11)  
387 - .attr('y', function () {  
388 - return isDown ? y + 8 : y - 31;  
389 - });  
390 - //merge text  
391 - var len = gpsArr.length;  
392 - mergerG.append('text').text(len)  
393 - .attr('x', x - ((len + '').length * 4.5))  
394 - .attr('y', isDown ? y + 24 : y - 14);  
395 - };  
396 -  
397 -  
398 - /**  
399 - * 设备掉线  
400 - * @param gps  
401 - */  
402 - var deviceOffline = function (gps) {  
403 - $('svg text[_id=tx_'+gps.deviceId+']').addClass('offline');  
404 - $('svg rect[_id=tx_'+gps.deviceId+']').addClass('offline');  
405 - };  
406 -  
407 - /**  
408 - * 刷新可见的模拟图  
409 - */  
410 - var refreshByVisible = function () {  
411 - for(var k in wraps){  
412 - if(wraps[k].is(":visible")){  
413 - setGps(k.split('_')[0]);  
414 - }  
415 - }  
416 - };  
417 -  
418 - var svgsIsHidden = function (svgs) {  
419 - for(var i=0,svg;svg=svgs[i++];){  
420 - if($(svg).parent().is(":visible"))  
421 - return false;  
422 - }  
423 - return true;  
424 - };  
425 -  
426 - return {  
427 - draw_line: draw_line,  
428 - setGps: setGps,  
429 - deviceOffline: deviceOffline,  
430 - refreshByVisible: refreshByVisible,  
431 - disabledAnimation: function () {  
432 - animation = false;  
433 - },  
434 - enabledAnimation: function () {  
435 - animation = true;  
436 - }  
437 - };  
438 -})(); 1 +/* 线路模拟图 */
  2 +
  3 +var gb_svg_chart = (function () {
  4 +
  5 + //chart height
  6 + var chart_height = 122;
  7 + //left right padding
  8 + var x_padd = 30;
  9 + //上空白部分
  10 + var y_top_padd = 4;
  11 + //text max size
  12 + var t_max_size = 7;
  13 + //svg namespace
  14 + var svgns = 'http://www.w3.org/2000/svg';
  15 + var wraps={};
  16 + //根据wrap的class区分是home还是电子路单界面
  17 + var suffixs={
  18 + 'uk-width-medium-3-5 svg-chart-wrap': 'home',
  19 + 'svg-wrap': 'line'
  20 + }
  21 +
  22 + //站点间隔 线路编码 -> space
  23 + var circle_spaces={};
  24 + //var circle_space;
  25 + //是否启用动画
  26 + var animation = true;
  27 +
  28 + var calc_text_y = function (t) {
  29 + return (chart_height - (chart_height / t_max_size * t.length)) / 2 + 5;
  30 + },
  31 + cat_text = function (t) {
  32 + if(!t)
  33 + return 0;
  34 + return t.length > t_max_size ? t.substr(0, t_max_size) : t;
  35 + },
  36 + get_width = function (wrap) {
  37 + return wrap.actual('outerWidth');
  38 + },
  39 + get_height = function (wrap) {
  40 + var h = wrap.actual('outerHeight');
  41 + //隐藏元素取最外层的高度
  42 + return h < 20 ? wrap.parent().actual('outerHeight') - 2 : h;
  43 + };
  44 +
  45 + /**
  46 + * 绘制线路模拟图
  47 + * @param lineCode 线路编码
  48 + * @param wrap dom容器
  49 + * @param enableAttr 是否启用配置
  50 + */
  51 + var draw_line = function (lineCode, wrap, enableAttr, direction) {
  52 + var wrapId = lineCode+'_'+suffixs[wrap.attr('class')];
  53 + wraps[wrapId]=wrap;
  54 + //环线
  55 + var loopLine = gb_data_basic.isLoopLine(lineCode);
  56 +
  57 + var routes = gb_data_basic.stationRoutes(lineCode);
  58 + if(!routes)
  59 + return;
  60 + var data = gb_svg_data_convert.mergeRoute(JSON.parse(JSON.stringify(routes)), enableAttr, lineCode, loopLine),
  61 + len = data.length;
  62 +
  63 + var w = get_width(wrap),
  64 + h = parseInt(get_height(wrap))
  65 + //x scale
  66 + ,
  67 + xScale = d3.scale.linear().range([x_padd, w - x_padd]).domain([0, len - 1]),
  68 + cx = function (d, i) {
  69 + return xScale(i);
  70 + },
  71 + cy = function () {
  72 + return (h - chart_height) / 2 + y_top_padd;
  73 + },
  74 + ty = function (d) {
  75 + return cy() + calc_text_y(cat_text(d.name[0]));
  76 + }
  77 + //line generator
  78 + ,
  79 + upLine = d3.svg.line().x(xScale).y(cy),
  80 + downLine = d3.svg.line().x(xScale).y(function () {
  81 + return cy() + chart_height
  82 + }),
  83 + multi_text = function (d, i, that) {
  84 +
  85 + var dText = document.createElementNS(svgns, 'text'),
  86 + t = cat_text(d.name[1]);
  87 + $(dText).attr('class', 'station_text down')
  88 + .attr('x', cx(d, i) + 8).attr('y', cy() + calc_text_y(t))
  89 + .attr('title', d.name[1])
  90 + .text(t);
  91 +
  92 + $(that).after(dText);
  93 + return cx(d, i) - 8;
  94 + },
  95 + dynamic_text = function(d, i, that, direction) {
  96 + var t = (direction == 2 ? d.name[1] : d.name[0]);
  97 + $(that).attr('class', 'station_text ' + (direction == 2 ? 'down' : 'up'))
  98 + .attr('x', cx(d, i) + 8).attr('y', cy() + calc_text_y(cat_text(t)))
  99 + .attr('title', t)
  100 + .text(cat_text(t));
  101 +
  102 + return cx(d, i);
  103 + }
  104 +
  105 + circle_spaces[wrapId] = (w - (x_padd * 2)) / len;
  106 + //add svg dom
  107 + var svg = d3.select(wrap[0]).append('svg')
  108 + .classed({
  109 + 'line-chart': true
  110 + }).attr('data-code', lineCode)
  111 + .attr('onselectstart', 'return false')
  112 + .style('height', h);
  113 +
  114 + //add item g
  115 + var items = svg.selectAll('g.item').data(data)
  116 + .enter().append('g').classed({
  117 + 'item': true
  118 + });
  119 +
  120 + //up station link path
  121 + var p_clzz = {
  122 + 'station_link': true
  123 + };
  124 + items.append('path').classed(p_clzz)
  125 + .attr('d', function (d, i) {
  126 + return i < len - 1 ? upLine([i, i + 1]) : '';
  127 + });
  128 +
  129 + //down station link path
  130 + p_clzz.down = true;
  131 + p_clzz.loop_line = loopLine;
  132 + items.append('path').classed(p_clzz)
  133 + .attr('d', function (d, i) {
  134 + return i < len - 1 ? downLine([i, i + 1]) : '';
  135 + });
  136 +
  137 + //up circle
  138 + var c_clzz = {
  139 + 'station_circle': true
  140 + };
  141 + items.select(function (d) {
  142 + return d.type != 1 ? this : null;
  143 + })
  144 + .append('circle').classed(c_clzz)
  145 + .attr('cx', cx)
  146 + .attr('cy', cy)
  147 + .attr('data-id', function (d) {
  148 + return d.id[0];
  149 + });
  150 +
  151 + //down circle
  152 + c_clzz.down = true;
  153 + items.select(function (d) {
  154 + return d.type != 0 ? this : null;
  155 + })
  156 + .append('circle').classed(c_clzz)
  157 + .attr('cx', cx)
  158 + .attr('cy', function (d, i) {
  159 + return cy(d, i) + chart_height;
  160 + })
  161 + .attr('data-id', function (d) {
  162 + return d.type == 1 ? d.id[0] : d.id[1];
  163 + });
  164 +
  165 + //station name text
  166 + items.append('text').classed({
  167 + 'station_text': true,
  168 + 'up': function (d) {
  169 + return (d.type == 3 || d.type == 0) && direction != 2;
  170 + },
  171 + 'down': function (d) {
  172 + return d.type == 1 && direction != 1;
  173 + }
  174 + })
  175 + .text(function (d) {
  176 + return cat_text(d.name[0]);
  177 + })
  178 + .attr('title', function (d) {
  179 + return d.name[0];
  180 + })
  181 + .attr('y', ty)
  182 + .attr('x', function (d, i) {
  183 + return d.type == 3 ? (direction ? dynamic_text(d, i, this, direction) : multi_text(d, i, this)) : cx(d, i)
  184 + });
  185 +
  186 + //gps wrap
  187 + svg.append('g').classed({
  188 + 'gps-wrap': true
  189 + });
  190 + //marker clusterer wrap
  191 + svg.append('g').classed({
  192 + 'marker-clusterer': true
  193 + });
  194 + var count = $('#svg_title_' + lineCode).data('count');
  195 + if (!count) {
  196 + $('#svg_title_' + lineCode).data('count', 1);
  197 + $('#svg_title_' + lineCode).click(function () {
  198 + var count = $(this).data('count');
  199 + var wrap = $('#home-main-content .home-line-card[data-line-code='+lineCode+'] .svg-chart-wrap');
  200 + wrap.find('svg.line-chart').remove();
  201 + gb_svg_chart.draw_line(lineCode, wrap, true, count % 2 + 1);
  202 + $(this).data('count', count + 1);
  203 + })
  204 + }
  205 + };
  206 +
  207 +
  208 + // ----- draw gps ------
  209 + //gps 按线路站点分组后的下标映射
  210 + var line_gps_index = {};
  211 + var get_circle = function (dataId, svg) {
  212 + try {
  213 + var circle = $('.station_circle[data-id=' + dataId + ']', svg);
  214 + if (circle.length == 0)
  215 + circle = null;
  216 + } catch (e) {
  217 + console.log('get_circle error! station_circle data-id:' + dataId);
  218 + return null;
  219 + }
  220 + return circle;
  221 + },
  222 + gx = function (gps, svg, wrapId) {
  223 + var circle = get_circle(gps.stopNo + '_' + gps.upDown, svg);
  224 + if (!circle) return -100;
  225 +
  226 + var x = circle.attr('cx') - 16.5,
  227 + s = circle_spaces[wrapId] / 2;
  228 + // console.log('ss', gps.lineId + '=' + s);
  229 + //s = 5;
  230 + if(gps['instation']==0)
  231 + x = (gps['upDown']==0?x+s:x-s);
  232 + return x;
  233 + },
  234 + gy = function (gps, svg) {
  235 + var circle = get_circle(gps.stopNo + '_' + gps.upDown, svg);
  236 + if (!circle) return -100;
  237 +
  238 + var cy = parseInt(circle.attr('cy')),
  239 + index = line_gps_index[gps.lineId][gps.stopNo + '_' + gps.upDown][gps.deviceId];
  240 +
  241 + return gps.upDown == 0 ? cy - 22 - (index * 17) : cy + 6 + (index * 19);
  242 + },
  243 + ups_gps = function (d) {
  244 + return d.gpsUps;
  245 + },
  246 + downs_gps = function (d) {
  247 + return d.gpsDowns;
  248 + },
  249 + gps_index_mapp = function (data) {
  250 + var rs = {};
  251 + var dataGroupStop = gb_svg_data_convert.groupByStationAndUpdown(data);
  252 + for (var stopNo in dataGroupStop) {
  253 + rs[stopNo] = {};
  254 + $.each(dataGroupStop[stopNo], function (i, gps) {
  255 + rs[stopNo][gps.deviceId] = i;
  256 + });
  257 + }
  258 + return rs;
  259 + },
  260 + g_text = function (d) {
  261 + var len = (d.nbbm == false ? 0 : d.nbbm.length)
  262 + , t = len > 3 ? d.nbbm.substr(len - 3) : d.nbbm;
  263 +
  264 + if (d.nbbm.indexOf('-') > 0) {
  265 + t = d.nbbm.substr(d.nbbm.indexOf('-') - 1, 1) + t;
  266 + }
  267 + return t + d.suffix;
  268 + },
  269 + gps_key = function (d) {
  270 + return d.deviceId;
  271 + },
  272 + gps_update_point = function (e, svg, wrapId) {
  273 + var x,e1;
  274 + e1 = e;
  275 + if(animation)
  276 + e1 = e.transition();
  277 + e1.attr('x', function (d) {
  278 + x = gx(d, svg, wrapId);
  279 + if(x == -100)
  280 + $(this).css('transition-duration', 0).hide();
  281 + else
  282 + $(this).show();//找不到停靠点,直接隐藏
  283 + return x;
  284 + })
  285 + .attr('y', function (d) {
  286 + return gy(d, svg);
  287 + })
  288 + .attr('updown', function (d) {
  289 + return d.upDown;
  290 + });
  291 + e.classed({'abnormal': function (d) {
  292 + return d.abnormalClaszz;
  293 + }, 'offline': function (d) {
  294 + return d['abnormalStatus']=='offline';
  295 + }});
  296 + //update tip position
  297 + gb_svg_tooltip.update(e);
  298 + },
  299 + rct_id = function (d) {
  300 + return 'rct_' + d.deviceId;
  301 + },
  302 + tx_id = function (d) {
  303 + return 'tx_' + d.deviceId;
  304 + };
  305 +
  306 + var setGps = function (lineCode) {
  307 + var svgs = $('.line-chart[data-code=' + lineCode + ']');
  308 + if(svgsIsHidden(svgs))
  309 + return;
  310 + var data = gb_data_gps.gpsByLineCode(lineCode);
  311 +
  312 + var list = [], suffix, abmStatus;
  313 + //过滤无站点字段的数据
  314 + $.each(data, function () {
  315 + if (!this.stopNo || this.stopNo == '')
  316 + return true;
  317 +
  318 + abmStatus = this['abnormalStatus'];
  319 + suffix = '';
  320 + if(abmStatus != 'offline'){
  321 + this['abnormalClaszz'] = true;
  322 + if(abmStatus=='outBounds')
  323 + suffix = '界';
  324 + else if(abmStatus=='overspeed')
  325 + suffix = '速';
  326 + else if(abmStatus=='gps-offline')
  327 + suffix = '掉';
  328 + else
  329 + this['abnormalClaszz'] = false;
  330 + }
  331 + else
  332 + this['abnormalClaszz'] = false;
  333 +
  334 + this.suffix = suffix;
  335 + list.push(this);
  336 + });
  337 +
  338 + line_gps_index[lineCode] = gps_index_mapp(list);
  339 + $.each(svgs, function () {
  340 + if(!$(this).parent().is(":visible"))
  341 + return true;
  342 +
  343 + //绘制gps
  344 + draw_gps(this, list);
  345 + //聚合gps
  346 + marker_clusterer(this, lineCode);
  347 + });
  348 +
  349 + //刷新tooltip
  350 + gb_svg_tooltip.refresh();
  351 + };
  352 +
  353 + var draw_gps = function (svg, data) {
  354 + //remove merge_hide class
  355 + $('.merge_hide', svg).removeAttr('class');
  356 +
  357 + var gps_cont = d3.select(svg).select('.gps-wrap');
  358 + //rect
  359 + var rects = gps_cont.selectAll('rect').data(data, gps_key);
  360 + rects.enter().append('rect').attr('_id', rct_id);
  361 +
  362 + //lineCode+'_'+suffixs[wrap.attr('class')]
  363 + var wrapId = $(svg).data('code') + '_' + suffixs[$(svg).parent().attr('class')];
  364 + gps_update_point(rects, svg, wrapId);
  365 + //text
  366 + var ts = gps_cont.selectAll('text').data(data, gps_key);
  367 + ts.enter().append('text').attr('_id', tx_id);
  368 + ts.text(g_text)
  369 + gps_update_point(ts, svg, wrapId);
  370 + };
  371 +
  372 + var marker_clusterer = function (svg, lineCode) {
  373 + //debugger
  374 + var gpsArr, idxMapp = line_gps_index[lineCode];
  375 + for (var stopNo in idxMapp) {
  376 + gpsArr = gb_common.get_keys(idxMapp[stopNo]);
  377 + //remove old merger point
  378 + $('g[_id=' + 'merger_' + stopNo + ']', svg).remove();
  379 + if (gpsArr.length <= 2)
  380 + continue;
  381 +
  382 + marker_clusterer_merge(svg, stopNo, gpsArr);
  383 + }
  384 + };
  385 +
  386 + var marker_clusterer_merge = function (svg, stopNo, gpsArr) {
  387 + //stop circle
  388 + var circle = get_circle(stopNo, svg);
  389 + if (!circle) return;
  390 +
  391 + var x = parseInt(circle.attr('cx')),
  392 + y = parseInt(circle.attr('cy')),
  393 + isDown = circle.attr('class').indexOf('down') != -1;
  394 +
  395 + var svg = d3.select(svg);
  396 + //hide old element
  397 + $.each(gpsArr, function (i, d) {
  398 + $('rect[_id=rct_' + d + '],text[_id=tx_' + d + ']').attr('class', 'merge_hide');
  399 + });
  400 +
  401 + var mergerG = svg.selectAll('g.marker-clusterer').append('g').attr('_id', 'merger_' + stopNo)
  402 + .classed({
  403 + 'merge-item': true
  404 + });
  405 + //merge rect
  406 + mergerG.append('rect').attr('x', x - 11)
  407 + .attr('y', function () {
  408 + return isDown ? y + 8 : y - 31;
  409 + });
  410 + //merge text
  411 + var len = gpsArr.length;
  412 + mergerG.append('text').text(len)
  413 + .attr('x', x - ((len + '').length * 4.5))
  414 + .attr('y', isDown ? y + 24 : y - 14);
  415 + };
  416 +
  417 +
  418 + /**
  419 + * 设备掉线
  420 + * @param gps
  421 + */
  422 + var deviceOffline = function (gps) {
  423 + $('svg text[_id=tx_'+gps.deviceId+']').addClass('offline');
  424 + $('svg rect[_id=tx_'+gps.deviceId+']').addClass('offline');
  425 + };
  426 +
  427 + /**
  428 + * 刷新可见的模拟图
  429 + */
  430 + var refreshByVisible = function () {
  431 + for(var k in wraps){
  432 + if(wraps[k].is(":visible")){
  433 + setGps(k.split('_')[0]);
  434 + }
  435 + }
  436 + };
  437 +
  438 + var svgsIsHidden = function (svgs) {
  439 + for(var i=0,svg;svg=svgs[i++];){
  440 + if($(svg).parent().is(":visible"))
  441 + return false;
  442 + }
  443 + return true;
  444 + };
  445 +
  446 + return {
  447 + draw_line: draw_line,
  448 + setGps: setGps,
  449 + deviceOffline: deviceOffline,
  450 + refreshByVisible: refreshByVisible,
  451 + disabledAnimation: function () {
  452 + animation = false;
  453 + },
  454 + enabledAnimation: function () {
  455 + animation = true;
  456 + }
  457 + };
  458 +})();