EventSource 实时传输数据
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 8 <title>Dashboard</title> 9 <style> 10 *{margin:0;padding:0;} 11 /* TV Start */ 12 .RealTimeListTV { 13 width: 100%; 14 height: 100%; 15 overflow: scroll; 16 background: #030129 url('./image/tvBg.jpg') no-repeat; 17 background-size: 100% auto; 18 padding: 136px 0 0 0; 19 text-align: center; 20 position: relative; 21 box-sizing: border-box; 22 } 23 .RealTimeListTV .title { 24 font-size: 76px; 25 color: #fff; 26 letter-spacing: 6px; 27 } 28 .RealTimeListTV .totalValue { 29 font-size: 150px; 30 color: #fff; 31 letter-spacing: 6px; 32 } 33 .RealTimeListTV .totalValue .decoration { 34 width: 524px; 35 height: 136px; 36 display: block; 37 margin: 0 auto; 38 background: url('./image/lineH.png') no-repeat; 39 } 40 .RealTimeListTV .BusinessUnitList { 41 display: flex; 42 justify-content: space-between; 43 overflow: hidden; 44 line-height: 50px; 45 padding: 0 200px; 46 list-style: none; 47 } 48 .BusinessUnitList li { 49 float: left; 50 color: #fff; 51 position: relative; 52 letter-spacing: 6px; 53 } 54 .BusinessUnitList li .name { 55 font-size: 30px; 56 } 57 .BusinessUnitList li .value { 58 font-size: 36px; 59 } 60 .BusinessUnitList li .line { 61 width: 47px; 62 height: 48px; 63 background: url('./image/line.png') no-repeat; 64 position: absolute; 65 left: -70px; 66 top: 0; 67 } 68 .main{ 69 margin: 50px auto 0; 70 } 71 /* TV End */ 72 73 74 /* WEB Start */ 75 .RealTimeListWEB{ 76 width: 1280px; 77 background: #030129 url('./image/webBg.png') no-repeat; 78 background-size: 100% auto; 79 padding: 40px 0 0 0; 80 text-align: center; 81 position: relative; 82 box-sizing: border-box; 83 margin:0 auto; 84 } 85 86 .RealTimeListWEB .title{ 87 font-size: 46px; 88 color: #fff; 89 letter-spacing: 6px; 90 } 91 .RealTimeListWEB .totalValue { 92 font-size: 80px; 93 color: #fff; 94 letter-spacing: 6px; 95 } 96 .RealTimeListWEB .BusinessUnitList{ 97 list-style: none; 98 margin-top:110px; 99 } 100 .RealTimeListWEB .BusinessUnitList::after{ 101 content:"."; 102 clear:both; 103 display:block; 104 height:0; 105 overflow:hidden; 106 visibility:hidden; 107 } 108 109 110 .RealTimeListWEB .BusinessUnitList li{ 111 width: 20%; 112 padding-bottom: 30px; 113 letter-spacing: 3px; 114 } 115 .RealTimeListWEB .BusinessUnitList li .line{ 116 left: 25px; 117 top: -8px; 118 width: 32px; 119 height: 32px; 120 } 121 .RealTimeListWEB .BusinessUnitList li .name,.RealTimeListWEB .BusinessUnitList li .value{ 122 font-size: 20px; 123 padding-bottom: 20px; 124 } 125 .echartsList{ 126 margin-top: 200px; 127 } 128 /* WEB End */ 129 130 /* comment */ 131 .lageBoxNone,.smallBoxNone{ 132 display: none; 133 } 134 @media screen and (min-width:3000px) and (max-width:5000px) { 135 .lageBoxNone{ 136 display: block; 137 } 138 } 139 @media only screen and (max-width: 2999px) { 140 .smallBoxNone{ 141 display: block; 142 } 143 } 144 145 146 </style> 147 </head> 148 149 <body> 150 151 <!-- 电视尺寸 --> 152 <div class="RealTimeListTV lageBoxNone"> 153 <div class="title">总销售额</div> 154 <div class="totalValue">$<span>0.00</span><span class="decoration"></span></div> 155 <ul class="BusinessUnitList"> 156 <li> <span class="line"></span> <p class="name">SW事业部</p> <p class="value">$0.00</p></li> 157 <li> <span class="line"></span> <p class="name">SP事业部</p> <p class="value">$0.00</p></li> 158 <li> <span class="line"></span> <p class="name">JFN事业部</p> <p class="value">$0.00</p></li> 159 <li> <span class="line"></span> <p class="name">PJ事业部</p> <p class="value">$0.00</p></li> 160 <li> <span class="line"></span> <p class="name">Pi事业部</p> <p class="value">$0.00</p></li> 161 <li> <span class="line"></span> <p class="name">AG事业部</p> <p class="value">$0.00</p></li> 162 <li> <span class="line"></span> <p class="name">HA事业部</p> <p class="value">$0.00</p></li> 163 <li> <span class="line"></span> <p class="name">Q事业部</p> <p class="value">$0.00</p></li> 164 <li> <span class="line"></span> <p class="name">N事业部</p> <p class="value">$0.00</p></li> 165 <li> <span class="line"></span> <p class="name">GS事业部</p> <p class="value">$0.00</p></li> 166 </ul> 167 <!-- 为ECharts准备一个具备大小(宽高)的Dom --> 168 <div style="padding:0 50px;"> 169 <div id="main" class="main" style="width: 100%;height:1500px;"></div> 170 </div> 171 172 </div> 173 174 <!-- pc尺寸 --> 175 <div class="RealTimeListWEB smallBoxNone"> 176 <div class="title">总销售额</div> 177 <div class="totalValue">$<span>0.00</span></div> 178 <ul class="BusinessUnitList"> 179 <li> <span class="line"></span> <p class="name">SW事业部</p> <p class="value">$0.00</p></li> 180 <li> <span class="line"></span> <p class="name">SP事业部</p> <p class="value">$0.00</p></li> 181 <li> <span class="line"></span> <p class="name">JFN事业部</p> <p class="value">$0.00</p></li> 182 <li> <span class="line"></span> <p class="name">PJ事业部</p> <p class="value">$0.00</p></li> 183 <li> <span class="line"></span> <p class="name">Pi事业部</p> <p class="value">$0.00</p></li> 184 <li> <span class="line"></span> <p class="name">AG事业部</p> <p class="value">$0.00</p></li> 185 <li> <span class="line"></span> <p class="name">HA事业部</p> <p class="value">$0.00</p></li> 186 <li> <span class="line"></span> <p class="name">Q事业部</p> <p class="value">$0.00</p></li> 187 <li> <span class="line"></span> <p class="name">N事业部</p> <p class="value">$0.00</p></li> 188 <li> <span class="line"></span> <p class="name">GS事业部</p> <p class="value">$0.00</p></li> 189 </ul> 190 <!-- 为ECharts准备一个具备大小(宽高)的Dom --> 191 <div class="echartsList"> 192 <div id="main1" class="main" style="width: 1200px;height:450px;display: none;"></div> 193 <div id="main2" class="main" style="width: 1200px;height:450px;display: none;"></div> 194 <div id="main3" class="main" style="width: 1200px;height:450px;display: none;"></div> 195 <div id="main4" class="main" style="width: 1200px;height:450px;display: none;"></div> 196 <div id="main5" class="main" style="width: 1200px;height:450px;display: none;"></div> 197 <div id="main6" class="main" style="width: 1200px;height:450px;display: none;"></div> 198 <div id="main7" class="main" style="width: 1200px;height:450px;display: none;"></div> 199 <div id="main8" class="main" style="width: 1200px;height:450px;display: none;"></div> 200 <div id="main9" class="main" style="width: 1200px;height:450px;display: none;"></div> 201 <div id="main10" class="main" style="width: 1200px;height:450px;display: none;"></div> 202 <div id="main11" class="main" style="width: 1200px;height:450px;display: none;"></div> 203 <div id="main12" class="main" style="width: 1200px;height:450px;display: none;"></div> 204 <div id="main13" class="main" style="width: 1200px;height:450px;display: none;"></div> 205 <div id="main14" class="main" style="width: 1200px;height:450px;display: none;"></div> 206 <div id="main15" class="main" style="width: 1200px;height:450px;display: none;"></div> 207 </div> 208 </div> 209 210 </body> 211 <script src='./js/jquery-3.1.0.min.js'></script> 212 <script src="./js/echarts.min.js"></script> 213 <script src="./js/eventsource.min.js"></script> 214 215 <script type="text/javascript"> 216 /* 217 堆叠条形图 公共配置 218 xData: x轴数据 type=category arr 必填 219 yData: y轴数据 type=value arr 必填 220 HistogramW: 单个柱状图的宽度 str 如果不传默认是60 221 */ 222 // 基于准备好的dom,初始化echarts实例 223 function StackedBarChart(xData, yData, HistogramW) { 224 var yData1 = [], 225 yData2 = [], 226 yData3 = [], 227 yData4 = [], 228 HistogramW = HistogramW ? HistogramW : '60px'; 229 for (var i = 0, len = yData.length; i < len; i++) { 230 var cur = yData[i]; 231 yData1.push(cur * 0.1 >>> 0); 232 yData2.push(cur * 0.2 >>> 0); 233 yData3.push(cur * 0.3 >>> 0); 234 yData4.push(cur * 0.4 >>> 0); 235 } 236 return { 237 textStyle: { 238 color: '#fff', 239 fontSize: '42px' 240 }, 241 tooltip: { 242 trigger: 'axis', 243 axisPointer: { // 坐标轴指示器,坐标轴触发有效 244 type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' 245 }, 246 show: false 247 }, 248 grid: { 249 left: '3%', 250 right: '4%', 251 bottom: '3%', 252 containLabel: true 253 }, 254 xAxis: [{ 255 type: 'category', 256 axisLine: { // x轴的颜色和宽度 257 lineStyle: { 258 color: '#373750', 259 width: 5 //这里是坐标轴的宽度,可以去掉 260 } 261 }, 262 axisLabel: { 263 interval:0, 264 rotate:40 265 }, 266 data: xData 267 }], 268 yAxis: [{ 269 type: 'value', 270 axisLabel: { 271 show: true, 272 textStyle: { 273 color: '#fff' 274 } 275 }, 276 // 控制网格线是否显示 277 splitLine: { 278 show: true, 279 // 改变轴线颜色 280 lineStyle: { 281 // 使用深浅的间隔色 282 color: ['#24243f'] 283 } 284 } 285 286 }], 287 series: [ 288 289 { 290 type: 'bar', // 柱状图 291 stack: '站点总销售额', // 数据堆叠,同个类目轴上系列配置相同的stack值可以堆叠放置 292 itemStyle: { 293 normal: { 294 color: new echarts.graphic.LinearGradient( 295 0, 0, 0, 1, 296 [{ 297 offset: 0, 298 color: '#5fa2bc' 299 }, 300 { 301 offset: 0.7, 302 color: '#9fe595' 303 } 304 ] 305 ) 306 } 307 }, 308 309 barMaxWidth: HistogramW, 310 data: yData1 311 }, 312 { 313 type: 'bar', 314 stack: '站点总销售额', 315 itemStyle: { 316 normal: { 317 color: new echarts.graphic.LinearGradient( 318 0, 0, 0, 1, 319 [{ 320 offset: 0, 321 color: '#fae093' 322 }, 323 { 324 offset: 0.7, 325 color: '#f99c72' 326 } 327 ] 328 ) 329 } 330 }, 331 data: yData2 332 }, 333 { 334 type: 'bar', 335 stack: '站点总销售额', 336 itemStyle: { 337 normal: { 338 color: new echarts.graphic.LinearGradient( 339 0, 0, 0, 1, 340 [{ 341 offset: 0, 342 color: '#ff79aa' 343 }, 344 { 345 offset: 0.7, 346 color: '#e9566d' 347 } 348 ] 349 ) 350 } 351 }, 352 data: yData3 353 }, 354 { 355 // 只在最后一组数据中显示 label,由于最后一组数据的值来自 total * 0.4, 356 // 由此逆推出总数为 data / 0.4, 357 // >>> 用于去除小数部分 358 label: { 359 show: true, 360 position: 'top', 361 formatter: function (param) { 362 return Math.round(yData[param.dataIndex]); 363 } 364 }, 365 type: 'bar', 366 stack: '站点总销售额', 367 itemStyle: { 368 normal: { 369 color: new echarts.graphic.LinearGradient( 370 0, 0, 0, 1, 371 [{ 372 offset: 0, 373 color: '#94c8d3' 374 }, 375 { 376 offset: 0.7, 377 color: '#6a71e4' 378 } 379 ] 380 ) 381 } 382 }, 383 data: yData4 384 }, 385 386 ] 387 }; 388 } 389 390 function SetXYStyle(arr) { 391 return arr.map(function(item) { 392 return { 393 value: item, 394 textStyle: { 395 fontSize: 22 396 } 397 } 398 }) 399 } 400 /* 设置电视echarts图表尺寸 */ 401 var totalH = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight, 402 titleH = $('.title').outerHeight(true), 403 totalValueH = $('.totalValue').outerHeight(true), 404 businessUnitListH = $('.BusinessUnitList').outerHeight(true), 405 mainH = totalH - titleH - totalValueH - businessUnitListH - 136 - 50 ; 406 $('#main').css('height',mainH+'px'); 407 408 409 410 /*---------------- Echarts ---------------- */ 411 var is_pc = true, 412 params = 'is_pc=yes', 413 w = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth; 414 if (w > 3000) { 415 is_pc = false; 416 params = 'is_tv=yes' 417 } 418 419 var source = new EventSource('/rest/dashboard/fetch?' + params, { withCredentials: false, format: 'json' }); 420 421 // open事件 连接一旦建立,就会触发open事件,可以定义相应的回调函数。 422 source.onopen = function (event) { 423 // handle open event 424 console.log('onopen', event) 425 }; 426 427 // error事件 如果发生通信错误(比如连接中断),就会触发error事件。 428 source.onerror = function (event) { 429 // handle error event 430 var data = event.data; 431 if (typeof data == 'string') { 432 data = data.replace(/\n/g,'') 433 } 434 console.log('onerror', data) 435 }; 436 437 // 自定义事件 438 source.addEventListener("whole_total", function (event) { 439 var data = event.data; 440 var origin = event.origin; 441 var lastEventId = event.lastEventId; 442 // handle message 443 if (typeof data == 'string') { 444 data = data.replace(/\n/g,'') 445 } 446 447 $(".RealTimeListTV .totalValue span").eq(0).text(data) 448 $(".RealTimeListWEB .totalValue span").eq(0).text(data) 449 }, false); 450 451 // 自定义事件 452 source.addEventListener("depart_total", function (event) { 453 // handle message 454 var data = event.data; 455 // console.log('depart_total', data) 456 if (typeof data == 'string') { 457 data = data.replace(/\n/g,'') 458 data = JSON.parse(data); 459 } 460 461 var html = ''; 462 for (var i=0; i < data.length; i++) { 463 html += '<li>'; 464 html += ' <span class="line"></span>'; 465 html += ' <p class="name">' + data[i]['name'] + '</p>'; 466 html += ' <p class="value">$' + data[i]['data'] + '</p>'; 467 html += '</li>'; 468 } 469 470 $('.RealTimeListTV .BusinessUnitList').html(html); 471 $('.RealTimeListWEB .BusinessUnitList').html(html); 472 473 }, false); 474 475 // 自定义事件 476 source.addEventListener("site_total", function (event) { 477 478 var data = event.data; 479 480 if (typeof data == 'string') { 481 data = data.replace(/\n/g,'') 482 data = JSON.parse(data); 483 } 484 console.log('data.length', data.length) 485 486 // 循环15个一组, 重新渲染 487 if (is_pc) { 488 /*---------------- WEB Echarts ---------------- */ 489 for (var i = 0; i < data.length; i++) { 490 var id = 'main' + (i + 1); 491 $('#' + id).show() 492 var myChart = echarts.init(document.getElementById(id)), 493 xData = data[i].xData, 494 yData = data[i].yData; 495 myChart.setOption(StackedBarChart(xData, yData, '40')); 496 } 497 498 for (var i=data.length; i<15; i++) { 499 var id = 'main' + (i + 1); 500 $('#' + id).hide() 501 } 502 // 渲染30个一排 503 } else { 504 /* ---------------- TV Echarts ---------------- */ 505 var myChart = echarts.init(document.getElementById('main')), 506 xData = data[0].xData 507 yData = data[0].yData; 508 // 使用刚指定的配置项和数据显示图表。 509 myChart.setOption(StackedBarChart(SetXYStyle(xData),yData)); 510 } 511 512 }, false); 513 514 var last_hart_time = Math.round((new Date()).getTime() / 1000); 515 516 // 自定义事件 517 source.addEventListener("hart", function (event) { 518 var data = event.data; 519 var origin = event.origin; 520 var lastEventId = event.lastEventId; 521 // handle message 522 523 if (typeof data == 'string') { 524 data = data.replace(/\n/g,'') 525 data = JSON.parse(data) 526 } 527 var max_delay_seconds = data.max_delay || 5 528 var now_hart_time = Math.round((new Date()).getTime() / 1000); 529 if(now_hart_time - last_hart_time > max_delay_seconds) { 530 $.ajax({ 531 url: '/rest/dashboard/hartReply', 532 method: 'POST', 533 data: { uid: data['uid'], token: data['token'] }, 534 dataType: 'json', 535 success: function (result) { 536 last_hart_time = now_hart_time 537 console.log('reply') 538 } 539 }) 540 } 541 console.log('hart') 542 }, false); 543 544 // 自定义事件 545 source.addEventListener("close", function (event) { 546 var data = event.data; 547 var origin = event.origin; 548 var lastEventId = event.lastEventId; 549 // handle message 550 if (typeof data == 'string') { 551 data = data.replace(/\n/g,'') 552 } 553 554 // close方法用于关闭连接。 555 source.close(); 556 console.log('close', event) 557 }, false); 558 559 560 </script> 561 562 </html>