Changeset 311 in tmcsimulator for trunk/src/cptms/cptms.html
- Timestamp:
- 03/14/2019 01:45:00 PM (7 years ago)
- File:
-
- 1 moved
-
trunk/src/cptms/cptms.html (moved) (moved from trunk/src/cptms/cptms_map.html) (23 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/cptms/cptms.html
r307 r311 2 2 <html> 3 3 <head> 4 <!-- Launch with python -m CGIHTTPServer 80 80-->4 <!-- Launch with python -m CGIHTTPServer 80 --> 5 5 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> 6 <title>CPTMS Map v0.6. 0</title>6 <title>CPTMS Map v0.6.1</title> 7 7 <style> 8 8 @font-face { … … 95 95 position: relative;\ 96 96 } 97 .gm-style-iw { 98 background-color: #729FFF; 99 border-color: #729FFF; 100 } 97 101 #dialog { 98 102 position: absolute; … … 114 118 /* The Close Button */ 115 119 .close { 116 color: orange;120 color: #2E2E2E; 117 121 float: right; 118 font-size: 20px;122 font-size: 30px; 119 123 font-weight: bold; 120 124 } 121 125 .close:hover, 122 126 .close:focus { 123 color: red;127 color: black; 124 128 text-decoration: none; 125 129 cursor: pointer; … … 130 134 <body> 131 135 <!-- 136 Version 6.1 Puts cms messages in json formatted file. Polls for updates. 132 137 Version 6.0 Adds speed-dependent images to infowindow for cctv icons 133 138 Version 5.8 Adds an infowindow with a static image for all cctv icons … … 158 163 <!-- The div element for the popup dialog --> 159 164 <div id="dialog" style="display:none;"> 160 <span class="close">& times;</span>165 <span class="close">☒</span> <!-- close button symbol --> 161 166 <br> 162 167 <div id="cms-info-label" style="font-family:'Courier New'">CMS ID: xxx LOCATION: </div> … … 181 186 182 187 <script> 188 //TODO: Can we speed up vds loading? can we load the data in the background 189 // only display dots when the button is clicked? Does using setStyle slow it down? Instead of setstyle should we simply set the color on each marker (like we do for cms icons?) What's the difference between a feature created by loadGeoJson and just a marker added individually? 190 // would pre-computing coords for each zoom level and have them accessed in a table make a difference? 191 // Add interval refresh for cms icon colors. 192 // Add phase 2 to messages. 193 // cms set visible gets undefined error after last icon is processed. 194 // have we solved the duplicate cms defect? 195 183 196 // a global variable for the google map 184 var map; 197 var map; 185 198 // a global dictionary to lookup a station's original coordinates 186 199 var vds_coords = {}; … … 194 207 //var centerPoint = {lat: 33.687228, lng: -117.872148}; 195 208 // Constant for map center location in District 12 196 var centerPoint = {lat: 33.693385, lng: -117.798937}; 209 var centerPoint = { 210 lat: 33.693385, 211 lng: -117.798937 212 }; 197 213 // Initial map zoom 198 214 var initZoom = 11; … … 200 216 // and their associated zvalues so slower traffic dots are more visible. 201 217 // white means a disabled spot 202 var colorZvalues = {"white":5,"lime":10,"yellow":20,"red":30}; 203 var kCMSstartupFile = "cmsStatusD12.json"; 204 var kCCTVfile = "cctv_locations_D12.json"; 205 var blueFlag = "images/CPTMSImages/icon_cmsBlue.png"; 206 var yellowFlag = "images/CPTMSImages/icon_cmsYellow.png"; 207 var cctvIcon = "images/CPTMSImages/icon_cctvCyan.png"; 208 var cctvIconWhite = "images/CPTMSImages/icon_cctvWhite.png"; 209 var messageList; 210 var cms_info; 211 var cmsList = []; 212 var cctvList = []; 213 var cms_showing = false; 214 var vds_showing = true; 215 var cctv_showing = false; 218 var colorZvalues = { 219 "white": 5, 220 "lime": 10, 221 "yellow": 20, 222 "red": 30 223 }; 224 var kCMSstartupFile = "cmsStatusD12.json"; 225 var kCCTVfile = "cctv_locations_D12.json"; 226 var blueFlag = "images/CPTMSImages/icon_cmsBlue.png"; 227 var yellowFlag = "images/CPTMSImages/icon_cmsYellow.png"; 228 var cctvIcon = "images/CPTMSImages/icon_cctvCyan.png"; 229 var cctvIconWhite = "images/CPTMSImages/icon_cctvWhite.png"; 230 231 var cms_info; 232 var cmsList = []; 233 var messageDict = {}; 234 var cctvList = []; 235 var cms_showing = false; 236 var vds_showing = true; 237 var cctv_showing = false; 216 238 // Build a solid colored icon to use instead of the classic pin 217 239 // Use a diamond on N and E directions, circle on S and W directions 218 function dotSymbol(color, postmileID) //,direction)240 function dotSymbol(color, postmileID) //,direction) 219 241 { 220 242 var circle = google.maps.SymbolPath.CIRCLE; … … 230 252 scale: 5, 231 253 strokeColor: "black", // the border color 232 strokeWeight: 1, // the border thickness254 strokeWeight: 1, // the border thickness 233 255 fillColor: color, 234 256 fillOpacity: 1.0 … … 240 262 { 241 263 // Load the static map data and call saveCoords when done 242 map.data.loadGeoJson(kMapStartupFile, null,saveCoords)264 map.data.loadGeoJson(kMapStartupFile, null, saveCoords) 243 265 244 266 // Style the map data by applying the desired properties to each feature (marker) 245 267 // The function will be called every time a feature's properties are updated. 246 map.data.setStyle(function(feature) 268 map.data.setStyle(function(feature) 247 269 { 248 270 // Get the postmile id … … 252 274 var street = feature.getProperty("street"); 253 275 // Build the marker 254 var iconSymbol = dotSymbol(ptColor, name);276 var iconSymbol = dotSymbol(ptColor, name); 255 277 // return the StyleOptions 256 278 return { 257 icon: iconSymbol,258 title: name + " @" + street,// set rollover text259 // set zIndex for slowed traffic to a higher value so they overlap260 zIndex: colorZvalues[ptColor]261 };279 icon: iconSymbol, 280 title: name + " @" + street, // set rollover text 281 // set zIndex for slowed traffic to a higher value so they overlap 282 zIndex: colorZvalues[ptColor] 283 }; 262 284 }); 263 285 } … … 269 291 features.forEach(function(feature) 270 292 { 271 var pt = feature.getGeometry().get(); 272 vds_coords[feature.getId()] = pt; // save the Point in a dictionary293 var pt = feature.getGeometry().get(); 294 vds_coords[feature.getId()] = pt; // save the Point in a dictionary 273 295 }); 274 296 // update the dot colors from the dynamic json data … … 282 304 { 283 305 // 15 is maximum zoom, the point at which no adjustment is needed 284 return (.0005 *(15-map.getZoom()));306 return (.0005 * (15 - map.getZoom())); 285 307 } 286 308 … … 302 324 var perpx = feature.getProperty("perpx") 303 325 var perpy = feature.getProperty("perpy") 304 // Make adjustment and save it326 // Make adjustment and save it 305 327 var myLat = coords.lat() + perpy * adjAmount 306 328 var myLong = coords.lng() + perpx * adjAmount 307 feature.setGeometry({lat:myLat, lng:myLong}); 308 }); 309 } 310 311 // update the color (as needed) for a given marker 312 function updateMarker(marker) 313 { 329 feature.setGeometry( 330 { 331 lat: myLat, 332 lng: myLong 333 }); 334 }); 335 } 336 337 // update the color (as needed) for a given marker 338 function updateMarker(marker) 339 { 314 340 target = marker.id; 315 341 newColor = marker.properties.color; … … 320 346 if (currentColor != newColor) 321 347 { 322 currentFeature.setProperty("color", newColor);348 currentFeature.setProperty("color", newColor); 323 349 // set zIndex for slowed traffic to a higher value so they overlap 324 350 currentFeature.setProperty("zIndex", colorZvalues[newColor]); 325 351 } 326 }352 } 327 353 328 354 // Load the dynamic json file for highways, etc. 329 355 // Ref: https://codepen.io/KryptoniteDove/post/load-json-file-locally-using-pure-javascript 330 function loadJSON(inFile, callback)331 {332 var xobj = new XMLHttpRequest();333 xobj.overrideMimeType("application/json");334 xobj.open('GET', inFile, true);335 xobj.onreadystatechange = function()336 {337 if (xobj.readyState == 4 && xobj.status == "200")338 {339 callback(xobj.responseText);340 }341 };342 // We want ajax to ignore any cached responses343 xobj.setRequestHeader('If-Modified-Since', 'Sat, 01 Jan 2000 01:01:01 GMT')344 xobj.send(null);345 }346 // Load the highways dynamic json file and update the map347 function updateMap()348 {356 function loadJSON(inFile, callback) 357 { 358 var xobj = new XMLHttpRequest(); 359 xobj.overrideMimeType("application/json"); 360 xobj.open('GET', inFile, true); 361 xobj.onreadystatechange = function() 362 { 363 if (xobj.readyState == 4 && xobj.status == "200") 364 { 365 callback(xobj.responseText); 366 } 367 }; 368 // We want ajax to ignore any cached responses 369 xobj.setRequestHeader('If-Modified-Since', 'Sat, 01 Jan 2000 01:01:01 GMT') 370 xobj.send(null); 371 } 372 // Load the highways dynamic json file and update the map 373 function updateMap() 374 { 349 375 var parsed_JSON; 350 loadJSON(kMapPointsFile, function(response)376 loadJSON(kMapPointsFile, function(response) 351 377 { 352 378 // Parse JSON string into object … … 355 381 parsed_JSON.features.forEach(updateMarker); 356 382 }); 357 }383 } 358 384 359 385 // Initialize the center button (to re-center the map) … … 365 391 366 392 // Setup the click event listeners: reset center location and zoom factor 367 centerBtnDiv.addEventListener('click', function() { 368 map.setCenter(centerPoint); 369 map.setZoom(initZoom); 370 clearPlacePins(); 393 centerBtnDiv.addEventListener('click', function() 394 { 395 map.setCenter(centerPoint); 396 map.setZoom(initZoom); 397 clearPlacePins(); 371 398 }); 372 399 } … … 381 408 382 409 // Bias the SearchBox results towards current map's viewport. 383 map.addListener('bounds_changed', function() { 384 searchBox.setBounds(map.getBounds()); 410 map.addListener('bounds_changed', function() 411 { 412 searchBox.setBounds(map.getBounds()); 385 413 }); 386 414 387 415 // Listen for the event fired when the user selects a prediction and retrieve 388 416 // more details for that place. 389 searchBox.addListener('places_changed', function() { 390 var places = searchBox.getPlaces(); 391 392 if (places.length == 0) { 393 return; 394 } 395 396 clearPlacePins(); 397 398 // Create a bounding region to include the search result places 399 var bounds = new google.maps.LatLngBounds(); 400 // For each place, get the icon, name and location. 401 // There may be multiple search results 402 places.forEach(function(place) { 403 if (!place.geometry) { 404 console.log("Returned place contains no geometry"); 405 return; 406 } 407 408 // Create a marker for each place. 409 placeMarker = new google.maps.Marker({ 410 map: map, 411 title: place.name, 412 position: place.geometry.location 413 }) 414 415 // Click on the marker to remove it from the display 416 placeMarker.addListener('click', function() { 417 placeMarker.setMap(null); 417 searchBox.addListener('places_changed', function() 418 { 419 var places = searchBox.getPlaces(); 420 421 if (places.length == 0) 422 { 423 return; 424 } 425 426 clearPlacePins(); 427 428 // Create a bounding region to include the search result places 429 var bounds = new google.maps.LatLngBounds(); 430 // For each place, get the icon, name and location. 431 // There may be multiple search results 432 places.forEach(function(place) 433 { 434 if (!place.geometry) 435 { 436 console.log("Returned place contains no geometry"); 437 return; 438 } 439 440 // Create a marker for each place. 441 placeMarker = new google.maps.Marker( 442 { 443 map: map, 444 title: place.name, 445 position: place.geometry.location 446 }) 447 448 // Click on the marker to remove it from the display 449 placeMarker.addListener('click', function() 450 { 451 placeMarker.setMap(null); 452 }); 453 454 // Add this marker to the collection of current markers 455 placePins.push(placeMarker); 456 457 // Create a bounding region to include this place 458 if (place.geometry.viewport) 459 { 460 // Only geocodes have viewport. 461 bounds.union(place.geometry.viewport); 462 } 463 else 464 { 465 bounds.extend(place.geometry.location); 466 } 418 467 }); 419 420 // Add this marker to the collection of current markers 421 placePins.push(placeMarker); 422 423 // Create a bounding region to include this place 424 if (place.geometry.viewport) { 425 // Only geocodes have viewport. 426 bounds.union(place.geometry.viewport); 427 } else { 428 bounds.extend(place.geometry.location); 429 } 430 }); 431 // This will pan and zoom to the area around the marker 432 //map.fitBounds(bounds); 433 // This will center the map on the new marker(s) but not zoom 434 map.setCenter(bounds.getCenter()); 468 // This will pan and zoom to the area around the marker 469 //map.fitBounds(bounds); 470 // This will center the map on the new marker(s) but not zoom 471 map.setCenter(bounds.getCenter()); 435 472 }); 436 473 } … … 439 476 function clearPlacePins() 440 477 { 441 placePins.forEach(function(marker) { 478 placePins.forEach(function(marker) 479 { 442 480 marker.setMap(null); 443 }); 444 placePins = []; 445 } 446 // Initialize the view/hide buttons 447 function initButton() 448 { 449 var cctvBtnDiv = document.getElementById('cctvButton'); 450 map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(cctvBtnDiv) 451 cctvBtnDiv.title = 'Click to toggle cctv view'; 452 // Setup the click event listeners to toggle icon display 453 cctvBtnDiv.addEventListener('click', function() { 481 }); 482 placePins = []; 483 } 484 // Initialize the view/hide buttons 485 function initButton() 486 { 487 var cctvBtnDiv = document.getElementById('cctvButton'); 488 map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(cctvBtnDiv) 489 cctvBtnDiv.title = 'Click to toggle cctv view'; 490 // Setup the click event listeners to toggle icon display 491 cctvBtnDiv.addEventListener('click', function() 492 { 454 493 cctv_showing = !cctv_showing; 455 494 // reveal or hide all the icons 456 for (var i = 0; i < cctvList.length; i++)457 { 458 cctvList[ i].setVisible(cctv_showing);495 for (var key in cctvList) 496 { 497 cctvList[key].setVisible(cctv_showing); 459 498 } 460 499 // Determine which button image to show … … 467 506 pic = "images/CPTMSImages/btnReady_CCTV.png" 468 507 } 469 document.getElementById('cctvBtnImg').src=pic; 470 }); 471 472 var cmsBtnDiv = document.getElementById('cmsButton'); 473 map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(cmsBtnDiv) 474 cmsBtnDiv.title = 'Click to toggle cms view'; 475 // Setup the click event listeners to toggle icon display 476 cmsBtnDiv.addEventListener('click', function() { 508 document.getElementById('cctvBtnImg').src = pic; 509 }); 510 511 var cmsBtnDiv = document.getElementById('cmsButton'); 512 map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(cmsBtnDiv) 513 cmsBtnDiv.title = 'Click to toggle cms view'; 514 // Setup the click event listeners to toggle icon display 515 cmsBtnDiv.addEventListener('click', function() 516 { 477 517 cms_showing = !cms_showing; 478 518 // reveal or hide all the icons 479 for (var i = 0; i < cmsList.length; i++) 480 { 481 cmsList[i].setVisible(cms_showing); 519 for (var key in cmsList) 520 { 521 //key = Object.keys(cmsList)[i]; 522 cmsList[key].setVisible(cms_showing); 482 523 } 483 524 // Determine which button image to show … … 490 531 pic = "images/CPTMSImages/btnReady_CMS.png" 491 532 } 492 document.getElementById('cmsBtnImg').src=pic; 493 }); 494 495 var vdsBtnDiv = document.getElementById('vdsButton'); 496 map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(vdsBtnDiv) 497 vdsBtnDiv.title = 'Click to toggle vds view'; 498 499 // Setup the click event listeners to toggle icon display 500 vdsBtnDiv.addEventListener('click', function() { 533 document.getElementById('cmsBtnImg').src = pic; 534 }); 535 536 var vdsBtnDiv = document.getElementById('vdsButton'); 537 map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(vdsBtnDiv) 538 vdsBtnDiv.title = 'Click to toggle vds view'; 539 540 // Setup the click event listeners to toggle icon display 541 vdsBtnDiv.addEventListener('click', function() 542 { 501 543 vds_showing = !vds_showing; 502 544 // reveal or hide all the dots 503 545 map.data.forEach(function(feature) 504 546 { 505 map.data.overrideStyle(feature, {visible:vds_showing}); 547 map.data.overrideStyle(feature, 548 { 549 visible: vds_showing 550 }); 506 551 }); 507 552 // Determine which button image to show … … 514 559 pic = "images/CPTMSImages/btnReady_VDS.png" 515 560 } 516 document.getElementById('vdsBtnImg').src=pic; 517 }); 518 } 519 function setCMSmarkers() 520 { 521 var simpleImage = ""; 522 loadJSON(kCMSstartupFile, function(response) 523 { 524 // Parse JSON string into object 525 cms_info = JSON.parse(response); 526 //console.log(cms_info.data[0].cms); 527 // Process each new marker 528 for (var i = 0; i < cms_info.data.length; i++) 529 { 530 var cms = cms_info.data[i].cms; 531 var currLat = Number(cms.location.latitude); 532 var currLong = Number(cms.location.longitude); 561 document.getElementById('vdsBtnImg').src = pic; 562 }); 563 } 564 565 function setCMSmarkers() 566 { 567 var simpleImage = ""; 568 loadJSON(kCMSstartupFile, function(response) 569 { 570 // Parse JSON string into object 571 cms_info = JSON.parse(response); 572 //console.log(cms_info.data[0].cms); 573 // Process each new marker 574 for (var i = 0; i < cms_info.data.length; i++) 575 { 576 var cms = cms_info.data[i].cms; 577 var currLat = Number(cms.location.latitude); 578 var currLong = Number(cms.location.longitude); 579 var cmsID = cms.index; 580 var directionCode = cms.location.direction.charAt(0); 581 var locationInfo = directionCode + " " + cms.location 582 .route + " " + cms.location.postmile + " " + cms 583 .location.locationName 584 cmsList[cmsID] = new google.maps.Marker( 585 { 586 cmsid: cmsID, 587 position: 588 { 589 lat: currLat, 590 lng: currLong 591 }, 592 map: map, 593 icon: yellowFlag, 594 title: "#" + cmsID + " " + locationInfo, 595 location: locationInfo 596 }); 597 cmsList[cmsID].setVisible(false); // initially hidden 598 google.maps.event.addListener(cmsList[cmsID], 'click', 599 function() 600 { 601 var dialog = document.getElementById('dialog'); 602 dialog.style.display = 'block'; 603 // fetch the sequential msg # 604 cmsID = this.cmsid; 605 // Assign to the hidden field 606 document.getElementById('cmsID').value = cmsID; 607 showMessage(cmsID); // note: this is async 608 document.getElementById('cms-info-label').innerHTML = "CMS ID: " + 609 cmsID + " LOCATION: " + this.location; 610 // clear input fields 611 document.getElementById('msgcontent1').value = ""; 612 document.getElementById('msgcontent2').value = ""; 613 document.getElementById('msgcontent3').value = ""; 614 document.getElementById('msgcontent1').focus(); 615 var span = document.getElementsByClassName("close")[0] 616 // When the user clicks on <span> (x), close the modal 617 span.onclick = function() 618 { 619 handleClose(); 620 } 621 }); 622 } 623 }); 624 } 625 626 function setCCTVmarkers() 627 { 628 loadJSON(kCCTVfile, function(response) 629 { 630 var imgTag = '<IMG WIDTH="700" SRC="images/CPTMSImages/'; 631 // Parse JSON string into object 632 cctv_info = JSON.parse(response); 633 // Process each new marker 634 for (var i = 0; i < cctv_info.data.length; i++) 635 { 636 var cctv = cctv_info.data[i].cctv; 637 var currLat = Number(cctv.location.latitude); 638 var currLong = Number(cctv.location.longitude); 639 var locationInfo = cctv.location.locationName; 640 var imgIcon = cctvIcon 641 if ((typeof map.data.getFeatureById(cctv.location.nearVDS)) == "undefined") 642 { 643 imgIcon = cctvIconWhite; 644 } 645 646 var vdsResult = map.data.getFeatureById(cctv.location.nearVDS) 647 //console.log("building "+locationInfo+" near "+cctv.location.nearVDS + " found "+vdsResult); 648 cctvList[i] = new google.maps.Marker( 649 { 650 position: 651 { 652 lat: currLat, 653 lng: currLong 654 }, 655 map: map, 656 icon: imgIcon, 657 title: "#" + i + " " + locationInfo, 658 cctvid: "" + i, 659 location: locationInfo, 660 index: cctv.index, 661 nearVDS: cctv.location.nearVDS 662 }); 663 cctvList[i].info = new google.maps.InfoWindow( 664 { 665 content: locationInfo 666 }); 667 668 cctvList[i].setVisible(false); // initially hidden 669 cctvList[i].addListener('click', 670 function() 671 { 672 cctvIndex = this.index; 673 //console.log(this.title + " is looking for " + this.nearVDS); 674 currentFeature = map.data.getFeatureById(this.nearVDS); 675 currentColor = currentFeature.getProperty("color"); 676 var imgDir = "CCTVFast/"; 677 if (currentColor == "red" || currentColor == "yellow") 678 { 679 imgDir = "CCTVSlow/" 680 } 681 //console.log(currentFeature.getId() + ' ' + currentColor + " " + cctvIndex); 682 this.info.setContent('<div style="font-weight:bold;font-family: monospace">' + this.location + " nearVDS:" + 683 this.nearVDS + " " + currentColor + "<BR>" + imgTag + imgDir + cctvIndex + '.jpg">' + "</div>"); 684 this.info.open(map, this); 685 }); 686 } 687 }); 688 } 689 690 691 // Center justify message text in a 16 column field 692 function justifyText(message) 693 { 694 var kBlanks = " "; 695 var padLen = (16 - message.length) / 2; 696 var padding = kBlanks.substring(0, padLen); 697 return padding + message; 698 } 699 700 function handleSubmit() 701 { 702 // recover the user's response 703 var response1 = justifyText(document.getElementById('msgcontent1').value.trim()); 704 var response2 = justifyText(document.getElementById('msgcontent2').value.trim()); 705 var response3 = justifyText(document.getElementById('msgcontent3').value.trim()); 706 var newMsg = response1 + response2 + response3; 707 if (newMsg.length == 0) 708 { 709 alert("Nothing to Send ... Proposed is empty."); 710 } 711 else 712 { 713 document.getElementById('msgdisplay1').value = response1; 714 document.getElementById('msgdisplay2').value = response2; 715 document.getElementById('msgdisplay3').value = response3; 716 saveMessage(response1 + "|" + response2 + "|" + response3); 717 } 718 } 719 720 function handleClose() 721 { 722 // hide the display 723 document.getElementById('dialog').style.display = 'none' 724 } 725 726 function handleClear() 727 { 728 document.getElementById('msgdisplay1').value = ""; 729 document.getElementById('msgdisplay2').value = ""; 730 document.getElementById('msgdisplay3').value = ""; 731 saveMessage("||"); 732 } 733 // retrieve the current cms message file 734 function showMessage(cmsID) 735 { 736 loadAllMessages(); // because someone else may have made a recent update 737 // lookup the message for this cms ID 738 var message = messageDict[cmsID].cms.message; 739 // show the message in the display 740 document.getElementById('msgdisplay1').value = message.phase1.Line1; 741 document.getElementById('msgdisplay2').value = message.phase1.Line2; 742 document.getElementById('msgdisplay3').value = message.phase1.Line3; 743 } 744 function loadAllMessages() 745 { 746 loadJSON("cms_messages.json", function(response) 747 { 748 // Parse JSON string into object 749 messagejson = JSON.parse(response); 750 // Add each message to a lookup dictionary 751 for (var i = 0; i < messagejson.data.length; i++) 752 { 753 var item = messagejson.data[i]; 754 messageDict[item.cms.index] = item; 755 } 756 }); 757 } 758 function refreshCMSicons() 759 { 760 loadAllMessages(); 761 // Examine each CMS's message 762 for (var idx in cmsList) 763 { 533 764 // load a yellow flag if there's currently no message 534 if (messageList[i] == "||") 535 simpleImage = yellowFlag; 765 if (messageDict[idx].cms.message.phase1.Line1 + 766 messageDict[idx].cms.message.phase1.Line2 + 767 messageDict[idx].cms.message.phase1.Line3 == "") 768 cmsList[idx].setIcon(yellowFlag); 536 769 else 537 simpleImage = blueFlag; 538 var directionCode = cms.location.direction.charAt(0); 539 var locationInfo = directionCode + " " + cms.location 540 .route + " " + cms.location.postmile + " " + cms 541 .location.locationName 542 cmsList[i] = new google.maps.Marker( 543 { 544 position: 545 { 546 lat: currLat, 547 lng: currLong 548 }, 549 map: map, 550 icon: simpleImage, 551 title: "#"+i+" " +locationInfo, 552 cmsid: "" + i, 553 location: locationInfo 554 }); 555 cmsList[i].setVisible(false); // initially hidden 556 google.maps.event.addListener(cmsList[i], 'click', 557 function() 558 { 559 var dialog = document.getElementById('dialog'); 560 dialog.style.display = 'block'; 561 // fetch the sequential msg # 562 cmsID = Number(this.cmsid); 563 // Assign to the hidden field 564 document.getElementById('cmsID').value = cmsID; 565 getMessage(cmsID); // note: this is async 566 document.getElementById('cms-info-label').innerHTML = "CMS ID: " + 567 cmsID + " LOCATION: " + this.location; 568 // clear input fields 569 document.getElementById('msgcontent1').value = ""; 570 document.getElementById('msgcontent2').value = ""; 571 document.getElementById('msgcontent3').value = ""; 572 document.getElementById('msgcontent1').focus(); 573 var span = document.getElementsByClassName("close")[0] 574 // When the user clicks on <span> (x), close the modal 575 span.onclick = function() { 576 handleClose(); 577 } 578 }); 770 cmsList[idx].setIcon(blueFlag); 579 771 } 580 }); 581 } 582 function setCCTVmarkers() 583 { 584 loadJSON(kCCTVfile, function(response) 585 { 586 var imgTag = '<IMG WIDTH="700" SRC="images/CPTMSImages/'; 587 // Parse JSON string into object 588 cctv_info = JSON.parse(response); 589 // Process each new marker 590 for (var i = 0; i < cctv_info.data.length; i++) 591 { 592 var cctv = cctv_info.data[i].cctv; 593 var currLat = Number(cctv.location.latitude); 594 var currLong = Number(cctv.location.longitude); 595 var locationInfo = cctv.location.locationName; 596 var imgIcon = cctvIcon 597 if ((typeof map.data.getFeatureById(cctv.location.nearVDS)) == "undefined") 598 { 599 imgIcon = cctvIconWhite; 600 } 601 602 var vdsResult = map.data.getFeatureById(cctv.location.nearVDS) 603 //console.log("building "+locationInfo+" near "+cctv.location.nearVDS + " found "+vdsResult); 604 cctvList[i] = new google.maps.Marker( 605 { 606 position: 607 { 608 lat: currLat, 609 lng: currLong 610 }, 611 map: map, 612 icon: imgIcon, 613 title: "#"+i+" " +locationInfo, 614 cctvid: "" + i, 615 location: locationInfo, 616 index: cctv.index, 617 nearVDS: cctv.location.nearVDS 618 }); 619 cctvList[i].info=new google.maps.InfoWindow({ 620 content: locationInfo 621 }); 622 623 cctvList[i].setVisible(false); // initially hidden 624 cctvList[i].addListener('click', 625 function() 626 { 627 cctvIndex = this.index; 628 //console.log(this.title + " is looking for " + this.nearVDS); 629 currentFeature = map.data.getFeatureById(this.nearVDS); 630 currentColor = currentFeature.getProperty("color"); 631 var imgDir = "CCTVFast/"; 632 if (currentColor == "red" || currentColor == "yellow") 633 { 634 imgDir = "CCTVSlow/" 635 } 636 //console.log(currentFeature.getId() + ' ' + currentColor + " " + cctvIndex); 637 this.info.setContent('<div>' + this.location + " nearVDS:" 638 + this.nearVDS + " " + currentColor + "<BR>"+ imgTag + imgDir + cctvIndex + '.jpg">' + "</div>"); 639 this.info.open(map, this); 640 }); 641 } 642 }); 643 } 644 645 646 // Center justify message text in a 16 column field 647 function justifyText(message) 648 { 649 var kBlanks = " "; 650 var padLen = (16 - message.length)/2; 651 var padding = kBlanks.substring(0,padLen); 652 return padding + message; 653 } 654 655 function handleSubmit() 656 { 657 // recover the user's response 658 var response1 = justifyText(document.getElementById('msgcontent1').value.trim()); 659 var response2 = justifyText(document.getElementById('msgcontent2').value.trim()); 660 var response3 = justifyText(document.getElementById('msgcontent3').value.trim()); 661 var newMsg = response1+response2+response3; 662 if (newMsg.length == 0) 663 { 664 alert("Nothing to Send ... Proposed is empty."); 665 } 666 else 667 { 668 document.getElementById('msgdisplay1').value = response1; 669 document.getElementById('msgdisplay2').value = response2; 670 document.getElementById('msgdisplay3').value = response3; 671 saveMessage(response1 + "|" + response2 + "|" + response3); 672 } 673 } 674 675 function handleClose() 676 { 677 // hide the display 678 document.getElementById('dialog').style.display = 'none' 679 } 680 681 function handleClear() 682 { 683 document.getElementById('msgdisplay1').value = ""; 684 document.getElementById('msgdisplay2').value = ""; 685 document.getElementById('msgdisplay3').value = ""; 686 saveMessage("||"); 687 } 688 // retrieve the current cms message file 689 function getMessage(cmsID) 690 { 691 loadJSON("messagefile.txt", function(response) 692 { 693 // Parse JSON string into object 694 messageList = JSON.parse(response); 695 // select a message from json for the given cmsID 696 console.log("get by cmsID=" + cmsID); 697 var cmsSign = document.getElementById('msgdisplay1'); 698 messageparts = messageList[cmsID].split("|"); 699 cmsSign.value = messageparts[0]; 700 document.getElementById('msgdisplay2').value = messageparts[1]; 701 document.getElementById('msgdisplay3').value = messageparts[2]; 702 }); 703 } 704 // Save an updated cms message to the file 705 // NB: cms id's are one-based, json array is zero-based. 706 function saveMessage(outMessage, cmsID) 707 { 708 var cmsID = document.getElementById('cmsID').value; 709 console.log("Saving " + outMessage + " for cmsID " + cmsID) 710 messageList[cmsID] = outMessage; 711 // Change icon if something was saved 712 if (outMessage == "||") 713 cmsList[cmsID].setIcon(yellowFlag); 714 else 715 cmsList[cmsID].setIcon(blueFlag); 716 717 var xhttp = new XMLHttpRequest(); 718 xhttp.open("GET", "http://localhost:8080/cgi-bin/saveMessage.py?msg=" + JSON 719 .stringify(messageList), true); 720 xhttp.send(); 721 // Using POST might be a better idea ... haven't tried this yet 722 // var xhr = new XMLHttpRequest(); 723 // xhr.open("POST", "/cgi-bin/saveMessage.py?", true); 724 // xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); 725 // send the collected data as JSON 726 // xhr.send(JSON.stringify(messageList)); 727 } 772 } 773 // Save an updated cms message to the file 774 function saveMessage(outMessage, cmsID) 775 { 776 var cmsID = document.getElementById('cmsID').value; 777 console.log("Saving " + outMessage + " for cmsID " + cmsID) 778 msgParts = outMessage.split("|"); 779 messageDict[cmsID].cms.message.phase1.Line1 = msgParts[0]; 780 messageDict[cmsID].cms.message.phase1.Line2 = msgParts[1]; 781 messageDict[cmsID].cms.message.phase1.Line3 = msgParts[2]; 782 // Change icon if something was saved 783 if (outMessage == "||") 784 cmsList[cmsID].setIcon(yellowFlag); 785 else 786 cmsList[cmsID].setIcon(blueFlag); 787 outString = "{\n\t\"data\":\n\t\t" + JSON.stringify(Object.values(messageDict)) + "}"; 788 789 var xhttp = new XMLHttpRequest(); 790 xhttp.open("GET", "cgi-bin/saveMessage.py?msg=" + outString, true); 791 xhttp.send(); 792 // Using POST might be a better idea ... haven't tried this yet 793 // var xhr = new XMLHttpRequest(); 794 // xhr.open("POST", "/cgi-bin/saveMessage.py?", true); 795 // xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); 796 // send the collected data as JSON 797 // xhr.send(JSON.stringify(messageList)); 798 } 728 799 729 800 // Initialize the map and load the points 730 function initMap() 801 function initMap() 731 802 { 732 803 // Declare the map and where it belongs on the page 733 map = new google.maps.Map( document.getElementById('mapdiv'),734 { 735 zoom: initZoom, 804 map = new google.maps.Map(document.getElementById('mapdiv'), 805 { 806 zoom: initZoom, 736 807 center: centerPoint, 737 808 styles: night_mode, 738 809 mapTypeControl: false, 739 streetViewControl: false 740 }); 741 loadMapData(); // go load the map data810 streetViewControl: false 811 }); 812 loadMapData(); // go load the map data 742 813 // setup the search box and center button 743 814 initSearch(); 744 815 initCenter(); 816 loadAllMessages(); // load the current message file 817 var startTime = setTimeout(setCMSmarkers, 2000); 818 var startTime = setTimeout(setCCTVmarkers, 3000); 745 819 initButton(); 746 getMessage(1); // load the current message file747 var startTime = setTimeout(setCMSmarkers,2000);748 var startTime = setTimeout(setCCTVmarkers, 3000);749 820 750 821 // Start a timer to refresh the map every 10 seconds 751 822 var myTimer = setInterval(updateMap, 10000); 823 // start an interval timer to refresh the cms icons every 10 seconds 824 var cmsTimer = setInterval(refreshCMSicons, 10000); 752 825 // Listen for zoom changes and move the placePins so as to keep a nice 753 826 // visual distance between them appropriate to the zoom factor 754 map.addListener('zoom_changed', function() { 827 map.addListener('zoom_changed', function() 828 { 755 829 // fetch how much the map is currently zoomed 756 currentZoom = map.getZoom(); 830 currentZoom = map.getZoom(); 757 831 // only bother adjusting within this range 758 if ((currentZoom < 16) && (currentZoom>10))832 if ((currentZoom < 16) && (currentZoom > 10)) 759 833 { 760 834 // magic formula controls distance between dots … … 764 838 765 839 } 766 767 840 // Styles array for Night Mode map 768 841 // Ref: https://developers.google.com/maps/documentation/javascript/styling
Note: See TracChangeset
for help on using the changeset viewer.
