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 +})();
... ...