Changeset 312 in tmcsimulator for trunk/src/cptms/cptms.html
- Timestamp:
- 03/16/2019 03:10:50 PM (7 years ago)
- File:
-
- 1 edited
-
trunk/src/cptms/cptms.html (modified) (23 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/cptms/cptms.html
r311 r312 3 3 <head> 4 4 <!-- Launch with python -m CGIHTTPServer 80 --> 5 <!-- map center button icon from http://icons8.com/. (Obligatory backlink, don't remove ) --> 5 6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> 6 <title>CPTMS Map v0.6. 1</title>7 <title>CPTMS Map v0.6.2</title> 7 8 <style> 8 9 @font-face { … … 36 37 font-size: medium; 37 38 } 38 /*img.resize {39 max-width:auto;40 max-height:500px;41 }*/42 39 #search-input { 43 40 background-color: #17263c; /* #CD853F; /*#E6E6FA; /* lavender */ … … 56 53 border-color: #E6E6FA; 57 54 } 58 59 55 #ctrButton { 60 font-size: 40px; 61 margin-right: 9px; 56 cursor: pointer; 62 57 background-color: #fff; 63 color: #47476b;64 cursor: pointer;58 margin-right: 7px; 59 border: thick solid white; 65 60 } 66 61 #cms-info-label { … … 95 90 position: relative;\ 96 91 } 97 .gm-style-iw {98 background-color: #729FFF;99 border-color: #729FFF;100 }101 92 #dialog { 102 93 position: absolute; … … 116 107 cursor: pointer; 117 108 } 118 /* The Close Button */109 /* The Close Button in the CMS Dialog */ 119 110 .close { 120 111 color: #2E2E2E; … … 134 125 <body> 135 126 <!-- 127 Version 6.2 puts cctv and cms and vds in separate data layers. 136 128 Version 6.1 Puts cms messages in json formatted file. Polls for updates. 137 129 Version 6.0 Adds speed-dependent images to infowindow for cctv icons … … 156 148 <!--The div element where the map appears --> 157 149 <div id="mapdiv"></div> 158 <!--The div element where the buttons appears -->159 <div id="ctrButton" class="unstyled-button">⊕</div>160 <button id="cctvButton" class="unstyled-button"><img id="cctvBtnImg" src="images/CPTMSImages/btnReady_CCTV.png"></button>161 <button id="cmsButton" class="unstyled-button"><img id="cmsBtnImg" src="images/CPTMSImages/btnReady_CMS.png"></button>162 <button id="vdsButton" class="unstyled-button"><img id="vdsBtnImg" src="images/CPTMSImages/btnDepressed_VDS.png"></button>163 150 <!-- The div element for the popup dialog --> 164 151 <div id="dialog" style="display:none;"> … … 174 161 </div> 175 162 <div id="buttonPanel" style="display: block;"> 176 <button onclick="handle Submit();">Send >></button><br>177 <button onclick="handleC lear();">Clear >></button><br>178 <button onclick="handle Close();">Close </button>163 <button onclick="handleCMSsubmit();">Send >></button><br> 164 <button onclick="handleCMSclear();">Clear >></button><br> 165 <button onclick="handleDialogClose();">Close </button> 179 166 </div> 180 167 <div id="message-display" style="display: block;">Current: … … 184 171 </div> 185 172 </div> 173 <!--The div elements where the buttons appear --> 174 <div id="ctrButton"><img width="30" src="images/CPTMSImages/btn_mapcenter.png"</div> 175 <button id="cctvButton" class="unstyled-button"><img id="cctvBtnImg" src="images/CPTMSImages/btnReady_CCTV.png"></button> 176 <button id="cmsButton" class="unstyled-button"><img id="cmsBtnImg" src="images/CPTMSImages/btnReady_CMS.png"></button> 177 <button id="vdsButton" class="unstyled-button"><img id="vdsBtnImg" src="images/CPTMSImages/btnDepressed_VDS.png"></button> 186 178 187 179 <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. 180 //TODO: 192 181 // Add phase 2 to messages. 193 182 // cms set visible gets undefined error after last icon is processed. 194 // have we solved the duplicate cms defect?195 183 196 184 // a global variable for the google map … … 228 216 var cctvIcon = "images/CPTMSImages/icon_cctvCyan.png"; 229 217 var cctvIconWhite = "images/CPTMSImages/icon_cctvWhite.png"; 230 218 var vdsIconGreen = "images/CPTMSImages/circle-green.png" 219 var vdsIconYellow = "images/CPTMSImages/circle-yellow.png" 220 var vdsIconRed = "images/CPTMSImages/circle-red.png" 231 221 var cms_info; 232 var cmsList = [];233 222 var messageDict = {}; 234 var cctvList = [];235 223 var cms_showing = false; 236 224 var vds_showing = true; 237 225 var cctv_showing = false; 226 var cctv_infowindow; // We create just a single instance of info window. 227 238 228 // Build a solid colored icon to use instead of the classic pin 239 229 // Use a diamond on N and E directions, circle on S and W directions 240 function dotSymbol(color, postmileID) //,direction) 241 { 242 var circle = google.maps.SymbolPath.CIRCLE; 243 var diamond = 'M -1,0 0,-1 1,0 0,1 z'; 244 var myShape = circle; 245 // See if postmile name contains N or W letters 246 //if ((postmileID.indexOf('N') != -1) || (postmileID.indexOf('W') != -1)) 247 //{ 248 // myShape = diamond 249 //} 230 function dotSymbol(color) //,direction) 231 { 232 // var circle = google.maps.SymbolPath.CIRCLE; 233 // var diamond = 'M -1,0 0,-1 1,0 0,1 z'; 234 // var myShape = circle; 235 var iconPath = vdsIconGreen; 236 if (color == 'red') 237 { 238 iconPath = vdsIconRed; 239 } 240 else if (color == 'yellow') 241 { 242 iconPath = vdsIconYellow; 243 } 250 244 return { 251 path: myShape, 252 scale: 5, 253 strokeColor: "black", // the border color 254 strokeWeight: 1, // the border thickness 255 fillColor: color, 256 fillOpacity: 1.0 245 // path: iconPath, 246 // icon: 247 // { 248 url: iconPath, 249 anchor: new google.maps.Point(6, 6) 250 // }; 251 // anchor: new google.maps.Point(6, 6), 252 // scale: 5, 253 // strokeColor: "black", // the border color 254 // strokeWeight: 1, // the border thickness 255 // fillColor: color, 256 // fillOpacity: 1.0 257 257 }; 258 258 } 259 259 260 260 // Load the map data from a json file and style all the points 261 function load MapData()261 function loadVDSlayer() 262 262 { 263 263 // Load the static map data and call saveCoords when done 264 264 map.data.loadGeoJson(kMapStartupFile, null, saveCoords) 265 265 // var d = new Date(); 266 // var start = d.getTime(); 266 267 // Style the map data by applying the desired properties to each feature (marker) 267 268 // The function will be called every time a feature's properties are updated. … … 274 275 var street = feature.getProperty("street"); 275 276 // Build the marker 276 var iconSymbol = dotSymbol(ptColor , name);277 var iconSymbol = dotSymbol(ptColor); 277 278 // return the StyleOptions 278 279 return { 279 280 icon: iconSymbol, 281 /* icon: 282 { 283 url: vdsIconGreen, 284 anchor: new google.maps.Point(6, 6) 285 }, */ 280 286 title: name + " @" + street, // set rollover text 281 287 // set zIndex for slowed traffic to a higher value so they overlap … … 295 301 }); 296 302 // update the dot colors from the dynamic json data 297 update Map();303 updateVDSlayer(); 298 304 // go adjust the marker coordinates so dots don't overlap 299 305 adjustCoords(calcDistanceFactor()); … … 371 377 } 372 378 // Load the highways dynamic json file and update the map 373 function update Map()379 function updateVDSlayer() 374 380 { 375 381 var parsed_JSON; … … 483 489 } 484 490 // Initialize the view/hide buttons 485 function init Button()491 function initLayerButtons() 486 492 { 487 493 var cctvBtnDiv = document.getElementById('cctvButton'); … … 493 499 cctv_showing = !cctv_showing; 494 500 // reveal or hide all the icons 495 for (var key in cctvList) 496 { 497 cctvList[key].setVisible(cctv_showing); 498 } 501 cctvLayer.forEach(function(feature) 502 { 503 cctvLayer.overrideStyle(feature, 504 { 505 visible: cctv_showing 506 }); 507 }); 499 508 // Determine which button image to show 500 509 if (cctv_showing) … … 516 525 { 517 526 cms_showing = !cms_showing; 518 // reveal or hide all the icons519 for (var key in cmsList)520 {521 //key = Object.keys(cmsList)[i];522 cmsList[key].setVisible(cms_showing);523 }524 527 // Determine which button image to show 525 528 if (cms_showing) 526 529 { 527 530 pic = "images/CPTMSImages/btnDepressed_CMS.png" 531 // It's nice when icons become visible that the messages have been refreshed. 532 loadAllMessages(); 528 533 } 529 534 else … … 532 537 } 533 538 document.getElementById('cmsBtnImg').src = pic; 539 // reveal or hide all the icons 540 cmsLayer.forEach(function(feature) 541 { 542 cmsLayer.overrideStyle(feature, 543 { 544 visible: cms_showing 545 }); 546 }); 534 547 }); 535 548 … … 563 576 } 564 577 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 578 function loadCMSlayer() 579 { 580 cmsLayer = new google.maps.Data(); 581 cmsLayer.setMap(map); 582 cmsLayer.loadGeoJson("cms_locations_D12.gjson"); 583 cmsLayer.setStyle(function(feature) 584 { 585 // return the StyleOptions 586 return { 587 icon: yellowFlag, 588 title: feature.getId()+ " " +feature.getProperty("location"), 589 visible: false 590 }; 591 }); 592 593 cmsLayer.addListener('click', function(event) 594 { 595 var dialog = document.getElementById('dialog'); 596 // Note: If the dialog is already being displayed when someone else 597 // updates the message, it won't be reflected in the dialog, until 598 // you close and reopen it. 599 dialog.style.display = 'block'; 600 cmsID = event.feature.getId(); 601 // Assign to the hidden field 602 document.getElementById('cmsID').value = cmsID; 603 showMessage(cmsID); // note: this is async 604 document.getElementById('cms-info-label').innerHTML = "CMS ID: " + 605 cmsID + " LOCATION: " + event.feature.getProperty("location"); 606 // clear input fields 607 document.getElementById('msgcontent1').value = ""; 608 document.getElementById('msgcontent2').value = ""; 609 document.getElementById('msgcontent3').value = ""; 610 document.getElementById('msgcontent1').focus(); 611 var span = document.getElementsByClassName("close")[0] 612 // When the user clicks on <span> (x), close the modal 613 span.onclick = function() 614 { 615 handleDialogClose(); 616 } 617 }); 618 } 619 function makecctvIcon(nearVDS) 620 { 621 var imgIcon = cctvIcon 622 if ((typeof map.data.getFeatureById(nearVDS)) == "undefined") 623 { 624 imgIcon = cctvIconWhite; 625 } 626 return imgIcon 627 } 628 function loadCCTVlayer() 629 { 630 var imgTag = '<IMG WIDTH="700" SRC="images/CPTMSImages/'; 631 cctv_infowindow = new google.maps.InfoWindow(); 632 cctvLayer = new google.maps.Data(); 633 cctvLayer.loadGeoJson("cctv_locations_D12.gjson"); 634 cctvLayer.setStyle(function(feature) 635 { 636 // return the StyleOptions 637 return { 638 icon: makecctvIcon(feature.getProperty("nearVDS")), 639 title: feature.getId() + " " +feature.getProperty('locationName'), 640 visible: false 641 }; 642 }); 643 cctvLayer.addListener('click', function(event) 644 { 645 //console.log("cctv layer was clicked at " + event.feature.getId()); 646 cctvIndex = event.feature.getId(); 647 //console.log(this.title + " is looking for " + this.nearVDS); 648 nearVDS = map.data.getFeatureById(event.feature.getProperty("nearVDS")); 649 currentColor = nearVDS.getProperty("color"); 650 var imgDir = "CCTVFast/"; 651 if (currentColor == "red" || currentColor == "yellow") 652 { 653 imgDir = "CCTVSlow/" 654 } 655 656 cctv_infowindow.setContent('<div style="font-weight:bold;font-family: monospace">' + nearVDS.getId() + " " + currentColor + "<BR>" + imgTag + imgDir + cctvIndex + '.jpg">' + "</div>"); 657 cctv_infowindow.setPosition(event.feature.getGeometry().get()); 658 cctv_infowindow.open(map); 659 660 }); 661 cctvLayer.setMap(map); 662 } 690 663 691 664 // Center justify message text in a 16 column field 692 function justify Text(message)665 function justifyCMStext(message) 693 666 { 694 667 var kBlanks = " "; … … 698 671 } 699 672 700 function handle Submit()673 function handleCMSsubmit() 701 674 { 702 675 // recover the user's response 703 var response1 = justify Text(document.getElementById('msgcontent1').value.trim());704 var response2 = justify Text(document.getElementById('msgcontent2').value.trim());705 var response3 = justify Text(document.getElementById('msgcontent3').value.trim());676 var response1 = justifyCMStext(document.getElementById('msgcontent1').value.trim()); 677 var response2 = justifyCMStext(document.getElementById('msgcontent2').value.trim()); 678 var response3 = justifyCMStext(document.getElementById('msgcontent3').value.trim()); 706 679 var newMsg = response1 + response2 + response3; 707 680 if (newMsg.length == 0) … … 718 691 } 719 692 720 function handle Close()693 function handleDialogClose() 721 694 { 722 695 // hide the display … … 724 697 } 725 698 726 function handleC lear()699 function handleCMSclear() 727 700 { 728 701 document.getElementById('msgdisplay1').value = ""; … … 753 726 var item = messagejson.data[i]; 754 727 messageDict[item.cms.index] = item; 728 // Set the appropriate icon on the cms icon 729 // set a yellow flag if there's currently no message 730 if (item.cms.message.phase1.Line1 + 731 item.cms.message.phase1.Line2 + 732 item.cms.message.phase1.Line3 == "") 733 { 734 cmsLayer.overrideStyle(cmsLayer.getFeatureById(item.cms.index), {icon: yellowFlag}) 735 } 736 else 737 { 738 cmsLayer.overrideStyle(cmsLayer.getFeatureById(item.cms.index), {icon: blueFlag}) 739 } 755 740 } 756 741 }); 757 742 } 758 function refreshCMSicons() 759 { 760 loadAllMessages(); 761 // Examine each CMS's message 762 for (var idx in cmsList) 763 { 764 // load a yellow flag if there's currently no message 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); 769 else 770 cmsList[idx].setIcon(blueFlag); 771 } 772 } 743 773 744 // Save an updated cms message to the file 774 function saveMessage(outMessage, cmsID) 775 { 745 function saveMessage(outMessage) 746 { 747 // Fetch cmsID from hidden field where it was put when dialog opened. 776 748 var cmsID = document.getElementById('cmsID').value; 777 console.log("Saving " + outMessage + " for cmsID " + cmsID)749 //console.log("Saving " + outMessage + " for cmsID " + cmsID) 778 750 msgParts = outMessage.split("|"); 779 751 messageDict[cmsID].cms.message.phase1.Line1 = msgParts[0]; 780 752 messageDict[cmsID].cms.message.phase1.Line2 = msgParts[1]; 781 753 messageDict[cmsID].cms.message.phase1.Line3 = msgParts[2]; 782 // Change icon if something was saved754 // Set icon to reflect message state 783 755 if (outMessage == "||") 784 cmsList[cmsID].setIcon(yellowFlag); 756 { 757 currentIcon = {icon: yellowFlag}; 758 } 785 759 else 786 cmsList[cmsID].setIcon(blueFlag); 760 { 761 currentIcon = {icon: blueFlag}; 762 } 763 cmsLayer.overrideStyle(cmsLayer.getFeatureById(cmsID), currentIcon) 787 764 outString = "{\n\t\"data\":\n\t\t" + JSON.stringify(Object.values(messageDict)) + "}"; 788 765 … … 810 787 streetViewControl: false 811 788 }); 812 load MapData(); // go load the map data789 loadVDSlayer(); // go load the map data 813 790 // setup the search box and center button 814 791 initSearch(); 815 792 initCenter(); 816 loadAllMessages(); // load the current message file 817 var startTime = setTimeout(setCMSmarkers, 2000); 818 var startTime = setTimeout(setCCTVmarkers, 3000); 819 initButton(); 820 821 // Start a timer to refresh the map every 10 seconds 822 var myTimer = setInterval(updateMap, 10000); 793 794 loadCMSlayer(); 795 796 loadCCTVlayer(); 797 798 initLayerButtons(); 799 800 // Start a timer to refresh the vds dots every 10 seconds 801 var myTimer = setInterval(updateVDSlayer, 10000); 823 802 // start an interval timer to refresh the cms icons every 10 seconds 824 var cmsTimer = setInterval( refreshCMSicons, 10000);803 var cmsTimer = setInterval(loadAllMessages, 10000); 825 804 // Listen for zoom changes and move the placePins so as to keep a nice 826 805 // visual distance between them appropriate to the zoom factor
Note: See TracChangeset
for help on using the changeset viewer.
