js实现的时间轴效果
今天整理以前的资料发现以前写的一个时间轴效果,当时也是网上找了很久没有找到,就自己写了一个,现在发出来给有需要的人,代码写的可能有点乱。
效果图:
下面是美工做的设计图的效果(有个美工就是好):
下面是客户端源代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <html> 2 <head> 3 <style type="text/css"> 4 #container 5 { 6 font-size: 12px; 7 background-color: #ffffff; 8 border: 1px solid #cccccc; 9 position: relative; 10 margin: 0; 11 } 12 #stationContainer 13 { 14 background-color: #E5ECFF; 15 float: left; 16 width: 150px; 17 padding-top: 30px; 18 position: relative; 19 z-index: 200; 20 border-right: 1px solid black; 21 } 22 #stationContainer .station 23 { 24 border-top: 1px solid black; 25 width: 100%; 26 float: left; 27 height: 100px; 28 z-index: 300; 29 } 30 #timeContainer 31 { 32 float: left; 33 display: inline; 34 position: absolute; 35 z-index: 100; 36 width: 900px; 37 overflow: hidden; 38 } 39 #scrollContainer 40 { 41 position: relative; 42 } 43 #timeHeader 44 { 45 height: 30px; 46 background-color: #eeeeee; 47 position: relative; 48 overflow: hidden; 49 } 50 #timeHeader .unitTime 51 { 52 width: 4px; 53 float: left; 54 border-left: 1px solid black; 55 z-index: 100; 56 height: 10px; 57 margin-top: 20px; 58 position: absolute; 59 } 60 #timeHeader .halfHour 61 { 62 margin-top: 10px; 63 height: 20px; 64 } 65 #timeHeader .hour 66 { 67 height: 30px; 68 margin-top: 0px; 69 } 70 #timeBody 71 { 72 position: relative; 73 } 74 #timeBody .horizontalStation 75 { 76 position: relative; 77 width: 100%; 78 border-top: 1px solid black; 79 height: 100px; 80 z-index: 10; 81 } 82 #footer 83 { 84 clear: both; 85 width: 100%; 86 height: 20px; 87 background-color: #808080; 88 border-bottom: 1px solid #808080; 89 } 90 #timeLine 91 { 92 left: 500px; 93 border-right: 1px solid red; 94 float: left; 95 z-index: 100; 96 background-color: Red; 97 margin-top: 30px; 98 position: absolute; 99 } 100 101 .techinian 102 { 103 width: 100%; 104 height: 100%; 105 } 106 .techinian td 107 { 108 text-align: center; 109 } 110 .techinian .stationTd 111 { 112 width: 60px; 113 border-right: 1px solid black; 114 } 115 .car 116 { 117 height: 25%; 118 display: inline; 119 float: left; 120 width: 100px; 121 border: 1px solid #000000; 122 padding: 0px; 123 background-color: lightsteelblue; 124 text-decoration: none; 125 position: absolute; 126 outline: none; 127 margin-top: 5px; 128 top: 1px; 129 bottom: 1px; 130 font-family: 黑体; 131 color: Black; 132 font-size: large; 133 } 134 .virtual 135 { 136 border: 2px dashed #000000; 137 } 138 a.car:hover 139 { 140 cursor: pointer; 141 background-color: Fuchsia; 142 text-decoration: none; 143 } 144 .color0 145 { 146 background-color: Green; 147 } 148 .color70 149 { 150 background-color: Yellow; 151 } 152 .color100 153 { 154 background-color: Red; 155 } 156 </style> 157 <style type="text/css"> 158 .border_bottom 159 { 160 border-bottom: 1px solid black; 161 } 162 .border_top 163 { 164 border-top: 1px solid black; 165 } 166 .border_right 167 { 168 border-right: 1px solid black; 169 } 170 .border_left 171 { 172 border-left: 1px solid black; 173 } 174 .border_none 175 { 176 border: 0 none; 177 } 178 </style> 179 <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script> 180 <script type="text/javascript"> 181 Date.prototype.format = function (format) { 182 var o = 183 { 184 "M+": this.getMonth() + 1, //month 185 "d+": this.getDate(), //day 186 "h+": this.getHours(), //hour 187 "m+": this.getMinutes(), //minute 188 "s+": this.getSeconds(), //second 189 "q+": Math.floor((this.getMonth() + 3) / 3), //quarter 190 "S": this.getMilliseconds() //millisecond 191 } 192 if (/(y+)/.test(format)) 193 format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 194 for (var k in o) 195 if (new RegExp("(" + k + ")").test(format)) 196 format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)); 197 return format; 198 } 199 200 201 function MockTime(hour) 202 { 203 var now = new Date(); 204 return new Date(now.getFullYear()+'-'+(now.getMonth()+1)+'-'+now.getDate()+' '+hour+':00:00'); 205 } 206 207 </script> 208 <script type="text/javascript"> 209 var unitMinute = 5, halfHourCount = 30 / unitMinute, hourCount = 60 / unitMinute; 210 var unitCount = 24 * (60 / unitMinute); 211 var unitPx = 5; //每个格子的宽度加边框 212 var timelineInitLeft = 150; 213 var headerHeight = 30; 214 // 从服务端读取时间轴的开始和结束时间 215 //var validTime = new Date('<%=DateTime.Today.Date.Add(Xindeco.Bmw.Infrastruction.DefaultSetting.StationStartValid).ToString("yyyy/MM/dd HH:mm:ss")%>'); 216 //var invalidTime = new Date('<%=DateTime.Today.Date.Add(Xindeco.Bmw.Infrastruction.DefaultSetting.StationEndInvalid).ToString("yyyy/MM/dd HH:mm:ss")%>'); 217 var now = new Date(); 218 //从服务端读取服务器时间,使客户端和服务器时间同步 219 var serverTime = now; //静态页面测试直接赋值为客户端时间 220 var offsetTime = now -serverTime ; 221 var validTime = MockTime(8); 222 var invalidTime= MockTime(18); 223 224 $(function () { 225 var headerWidth = $("#container").width() - $("#stationContainer").width(); 226 unitPx = headerWidth / ((invalidTime - validTime) / 60000 / unitMinute); 227 228 for (var i = 0; i < unitCount; i++) { 229 var classstr = " "; 230 var hourstr = ""; 231 if (i % hourCount == 0) { 232 classstr = "hour"; 233 hourstr = i / hourCount; 234 } 235 else if (i % halfHourCount == 0) 236 classstr = "halfHour"; 237 var unitTime = $("<div id='time_" + i + "' class='unitTime " + classstr + "'>" + hourstr + "</div>"); 238 unitTime.css('left', i * unitPx); 239 $("#timeHeader").append(unitTime); 240 241 } 242 $("#scrollContainer").width(unitCount * unitPx); 243 $("#timeLine").height($("#stationContainer").height()); 244 $("#timeContainer").width($("#footer").width() - timelineInitLeft); 245 ScrollToTime(validTime.getHours(), invalidTime.getMinutes()); 246 SetTimeNow(); 247 }); 248 249 function SetTimeNow() { 250 serverTime.setTime(new Date().getTime() + offsetTime); 251 SetTimeLineByTime(serverTime.getHours(), serverTime.getMinutes()); 252 } 253 254 function ScrollToTime(hour, min) { 255 var count = (hourCount * hour + Math.round(min / unitMinute)); 256 $("#scrollContainer").css("left", -$("#time_" + count).position().left); 257 } 258 259 260 function SetTimeLineByTime(hour, min) { 261 262 var dateTime = new Date(serverTime.getFullYear(), serverTime.getMonth(), serverTime.getDate(), hour, min, 0); console.log(dateTime); 263 if (dateTime < validTime || dateTime > invalidTime) { 264 $("#timeLine").hide(); 265 return; 266 } 267 $("#timeLine").show(); 268 var count = (hourCount * hour + Math.round(min / unitMinute)); 269 $("#timeLine").css("left", $("#time_" + count).position().left + $("#scrollContainer").position().left + $("#stationContainer").width()); 270 } 271 272 function SetCarPositionByTime(car, hour, min) { 273 var count = (hourCount * hour + Math.round(min / unitMinute)); 274 $(car).css('left', $("#time_" + count).position().left); 275 SetHeight($(car)); 276 } 277 278 function AutoScroll() { 279 try { 280 serverTime.setTime(new Date().getTime() + offsetTime); 281 SetTimeLineByTime(serverTime.getHours(), serverTime.getMinutes()); 282 } catch (e) { 283 } 284 } 285 286 287 </script> 288 <script type="text/javascript"> 289 window['selectedCar'] = ''; 290 function Car(carData) { 291 var id = carData.ID; 292 var carNo = carData.CarNo; 293 var text = carData.DisplayText; 294 var stationId = carData.StationId; 295 //模拟的数据不需要做转换 296 //var startTime = ConvertJSONDateToJSDateObject(carData.StartTime); 297 //var endTime = ConvertJSONDateToJSDateObject(carData.EndTime); 298 var startTime = carData.StartTime; 299 var endTime = carData.EndTime; 300 var durationMinute = carData.TotalMinutes; 301 var isVirtual = carData.IsVirtual; 302 var title = ""; 303 var colorClass = ""; 304 if (carData.DisplayStartTime != null && carData.DisplayEndTime != null) { 305 title = ConvertJSONDateToJSDateObject(carData.DisplayStartTime).format("yyyy/MM/dd hh:mm") + "-" + ConvertJSONDateToJSDateObject(carData.DisplayEndTime).format("yyyy/MM/dd hh:mm"); 306 } 307 if (carData.Percent != null) { 308 var color = ""; 309 if (carData.Percent < 70) 310 color = 0; 311 else if (carData.Percent >= 70 && carData.Perent < 100) 312 color = 70; 313 else if (carData.Percent >= 100) 314 color = 100; 315 colorClass = "color" + color; 316 } 317 var car = $("<a id='car_" + id + "' href=\"#\" title='" + title + "' stationId='" + stationId + "' class=\"car " + colorClass + " " + (isVirtual ? 'virtual' : '') + "\"><div>" + text + "</div></a>"); 318 car.width(unitPx * durationMinute / unitMinute); 319 car.click(function () { 320 if (carData.ReachId != null) { 321 $(".panel .dxb img").hide(); 322 if (typeof ShowMsg != 'undefined') ShowMsg($("#msg"), "已选择:" + carNo); 323 window["selectedId"] = carData.ReachId; 324 } 325 }); 326 Car.prototype.Show = function () { 327 $("#station_" + stationId).append(car); 328 SetCarPositionByTime(car, startTime.getHours(), startTime.getMinutes()); 329 } 330 } 331 332 function SetHeight(dstCar) { 333 var cars = $("a[stationid='" + dstCar.attr("stationId") + "']"); 334 for (var i = 0; i < cars.length; i++) { 335 var car = $(cars[i]); 336 if (car.attr('id') != dstCar.attr('id') && (car.position().left + car.width()) > dstCar.position().left + 2) { 337 dstCar.css('top', car.position().top + car.height() + 4); 338 } 339 } 340 } 341 342 function Station(stationId) { 343 var station = $("<div id='station_" + stationId + "' class=\"horizontalStation\"></div>"); 344 station.height($(".station:first").height()); 345 Station.prototype.Show = function () { 346 $("#timeBody").append(station); 347 } 348 } 349 350 function ConvertJSONDateToJSDateObject(jsondate) { 351 var date = new Date(parseInt(jsondate.replace("/Date(", "").replace(")/", ""), 10)); 352 return date; 353 } 354 355 function LoadData() { 356 return MockData(); 357 //从服务端读取面板上需要显示的数据,包括所在工位,开始时间结束时间,以及其他需要显示的备注信息 358 var url = '<%=ResolveClientUrl("~/Handler/AutoDispatcher.ashx") %>?groupcodes=<%=string.Join(",", groupCodes) %>&r=' ; 359 $.getJSON(url+ Math.random(), function (data) { 360 window["data"] = data; 361 var stations = $("div.station[data-key]"); 362 $("#timeBody").html(''); 363 for (var i = 0; i < stations.length; i++) { 364 var stationId = $(stations[i]).attr('data-key'); 365 var station = new Station(stationId); 366 station.Show(); 367 var carList = data[stationId]; 368 if (typeof carList == 'undefined') continue; 369 for (var j = 0; j < carList.length; j++) { 370 var startTime = new Date(); 371 var carData = carList[j]; 372 var car = new Car(carData); 373 car.Show(); 374 } 375 } 376 }); 377 } 378 379 function MockData() 380 { 381 var data= {'1':[ 382 {ID:1,CarNo:'闽12345',DisplayText:'维修中',StationId:1,StartTime:MockTime(9),EndTime:MockTime(13),isVirtual:false,TotalMinutes:300,Percent:80}, 383 {ID:2,CarNo:'闽22345',DisplayText:'等待中',StationId:1,StartTime:MockTime(14),EndTime:MockTime(16),isVirtual:false,TotalMinutes:200,Percent:50} 384 ],'2':[ 385 {ID:3,CarNo:'闽12345',DisplayText:'维修中',StationId:2,StartTime:MockTime(8),EndTime:MockTime(12),isVirtual:false,TotalMinutes:300,Percent:80}, 386 {ID:4,CarNo:'闽22345',DisplayText:'等待中',StationId:2,StartTime:MockTime(13),EndTime:MockTime(14),isVirtual:false,TotalMinutes:200,Percent:50} 387 ],'3':[ 388 {ID:5,CarNo:'闽12345',DisplayText:'维修中',StationId:3,StartTime:MockTime(10),EndTime:MockTime(13),isVirtual:false,TotalMinutes:300,Percent:80}, 389 {ID:6,CarNo:'闽22345',DisplayText:'等待中',StationId:3,StartTime:MockTime(15),EndTime:MockTime(16),isVirtual:false,TotalMinutes:200,Percent:50} 390 ],'4':[ 391 {ID:7,CarNo:'闽12345',DisplayText:'维修中',StationId:4,StartTime:MockTime(9),EndTime:MockTime(12),isVirtual:false,TotalMinutes:300,Percent:80}, 392 {ID:8,CarNo:'闽22345',DisplayText:'等待中',StationId:4,StartTime:MockTime(13),EndTime:MockTime(15),isVirtual:false,TotalMinutes:200,Percent:50} 393 ]}; 394 window["data"] = data; 395 var stations = $("div.station[data-key]"); 396 $("#timeBody").html(''); 397 for (var i = 0; i < stations.length; i++) { 398 var stationId = $(stations[i]).attr('data-key'); 399 var station = new Station(stationId); 400 station.Show(); 401 var carList = data[stationId]; 402 if (typeof carList == 'undefined') continue; 403 for (var j = 0; j < carList.length; j++) { 404 var carData = carList[j]; 405 var car = new Car(carData); 406 car.Show(); 407 } 408 } 409 } 410 411 function Loop() { 412 AutoScroll(); 413 LoadData();//.complete(function () { setTimeout('Loop()', 20000) }); 414 } 415 416 window['LoadData'] = LoadData; 417 418 $(function () { 419 Loop(); 420 }); 421 </script> 422 </head> 423 <body> 424 <div id="container"> 425 <div id="stationContainer"> 426 <div class="station" data-key='1'> 427 <table border="0" class="techinian" cellpadding="0" cellspacing="0"> 428 <tr> 429 <td rowspan='4' class="stationTd"> 430 工位1 431 </td> 432 <td class='border_bottom'> 433 技师1 434 </td> 435 </tr> 436 <tr> 437 <td class='border_bottom'> 438 技师2 439 </td> 440 </tr> 441 <tr> 442 <td class='border_bottom'> 443 技师3 444 </td> 445 </tr> 446 <tr> 447 <td class=''> 448 技师4 449 </td> 450 </tr> 451 </table> 452 </div> 453 <div class="station" data-key='2'> 454 <table border="0" class="techinian" cellpadding="0" cellspacing="0"> 455 <tr> 456 <td rowspan='4' class="stationTd"> 457 工位2 458 </td> 459 <td class='border_bottom'> 460 技师5 461 </td> 462 </tr> 463 <tr> 464 <td class='border_bottom'> 465 技师6 466 </td> 467 </tr> 468 <tr> 469 <td class='border_bottom'> 470 技师7 471 </td> 472 </tr> 473 <tr> 474 <td class=''> 475 技师8 476 </td> 477 </tr> 478 </table> 479 </div> 480 <div class="station" data-key='3'> 481 <table border="0" class="techinian" cellpadding="0" cellspacing="0"> 482 <tr> 483 <td rowspan='4' class="stationTd"> 484 工位3 485 </td> 486 <td class='border_bottom'> 487 技师9 488 </td> 489 </tr> 490 <tr> 491 <td class='border_bottom'> 492 技师10 493 </td> 494 </tr> 495 <tr> 496 <td class='border_bottom'> 497 技师11 498 </td> 499 </tr> 500 <tr> 501 <td class=''> 502 技师12 503 </td> 504 </tr> 505 </table> 506 </div> 507 <div class="station" data-key='4'> 508 <table border="0" class="techinian" cellpadding="0" cellspacing="0"> 509 <tr> 510 <td rowspan='4' class="stationTd"> 511 工位4 512 </td> 513 <td class='border_bottom'> 514 技师13 515 </td> 516 </tr> 517 <tr> 518 <td class='border_bottom'> 519 技师14 520 </td> 521 </tr> 522 <tr> 523 <td class='border_bottom'> 524 技师3 525 </td> 526 </tr> 527 <tr> 528 <td class=''> 529 技师15 530 </td> 531 </tr> 532 </table> 533 </div> 534 </div> 535 <div id="timeContainer"> 536 <div id="scrollContainer"> 537 <div id="timeHeader"> 538 <div class="unitTime"> 539 <!--1111111111111111111--> 540 </div> 541 </div> 542 <div id="timeBody"> 543 <div class="horizontalStation"> 544 <a href="#" class="car"> 545 <div> 546 车辆1 547 </div> 548 </a><a href="#" class="car"> 549 <div> 550 车辆1 551 </div> 552 </a><a href="#" class="car"> 553 <div> 554 车辆1 555 </div> 556 </a><a href="#" class="car"> 557 <div> 558 车辆1 559 </div> 560 </a> 561 </div> 562 </div> 563 </div> 564 </div> 565 <div id="timeLine"> 566 </div> 567 <div style="clear: both;"> 568 </div> 569 </div> 570 <div id="footer"> 571 </div> 572 </body> 573 </html>