Changeset 311 in tmcsimulator for trunk


Ignore:
Timestamp:
03/14/2019 01:45:00 PM (7 years ago)
Author:
jdalbey
Message:

cptms renamed, added cms message polling to update icon color

Location:
trunk/src/cptms
Files:
1 added
1 deleted
1 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/cptms/cgi-bin/saveMessage.py

    r295 r311  
    1111    
    1212# write message to file 
    13 text_file = open("messagefile.txt", "w") 
     13text_file = open("cms_messages.json", "w") 
    1414text_file.write(outMessage) 
    1515text_file.close() 
  • trunk/src/cptms/cptms.html

    r307 r311  
    22<html> 
    33  <head> 
    4 <!-- Launch with  python -m CGIHTTPServer 8080  --> 
     4<!-- Launch with  python -m CGIHTTPServer 80  --> 
    55  <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>  
    77    <style> 
    88        @font-face { 
     
    9595           position: relative;\ 
    9696        } 
     97.gm-style-iw { 
     98background-color: #729FFF; 
     99border-color: #729FFF; 
     100} 
    97101       #dialog { 
    98102          position: absolute; 
     
    114118    /* The Close Button */ 
    115119    .close { 
    116       color: orange; 
     120      color: #2E2E2E; 
    117121      float: right; 
    118       font-size: 20px; 
     122      font-size: 30px; 
    119123      font-weight: bold; 
    120124    } 
    121125    .close:hover, 
    122126    .close:focus { 
    123       color: red; 
     127      color: black; 
    124128      text-decoration: none; 
    125129      cursor: pointer; 
     
    130134  <body> 
    131135    <!--  
     136         Version 6.1 Puts cms messages in json formatted file.  Polls for updates. 
    132137         Version 6.0 Adds speed-dependent images to infowindow for cctv icons 
    133138         Version 5.8 Adds an infowindow with a static image for all cctv icons 
     
    158163    <!-- The div element for the popup dialog --> 
    159164    <div id="dialog" style="display:none;"> 
    160         <span class="close">&times;</span> 
     165        <span class="close">&#x2612;</span>  <!-- close button symbol --> 
    161166        <br> 
    162167        <div id="cms-info-label" style="font-family:'Courier New'">CMS ID: xxx LOCATION: </div> 
     
    181186 
    182187    <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 
    183196    // a global variable for the google map 
    184     var map;   
     197    var map; 
    185198    // a global dictionary to lookup a station's original coordinates 
    186199    var vds_coords = {}; 
     
    194207    //var centerPoint = {lat: 33.687228, lng: -117.872148}; 
    195208    // 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    }; 
    197213    // Initial map zoom 
    198214    var initZoom = 11; 
     
    200216    // and their associated zvalues so slower traffic dots are more visible. 
    201217    // 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; 
    216238    // Build a solid colored icon to use instead of the classic pin 
    217239    // 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) 
    219241    { 
    220242        var circle = google.maps.SymbolPath.CIRCLE; 
     
    230252            scale: 5, 
    231253            strokeColor: "black", // the border color 
    232             strokeWeight: 1,      // the border thickness 
     254            strokeWeight: 1, // the border thickness 
    233255            fillColor: color, 
    234256            fillOpacity: 1.0 
     
    240262    { 
    241263        // Load the static map data and call saveCoords when done 
    242         map.data.loadGeoJson(kMapStartupFile,null,saveCoords) 
     264        map.data.loadGeoJson(kMapStartupFile, null, saveCoords) 
    243265 
    244266        // Style the map data by applying the desired properties to each feature (marker) 
    245267        // 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) 
    247269        { 
    248270            // Get the postmile id  
     
    252274            var street = feature.getProperty("street"); 
    253275            // Build the marker 
    254             var iconSymbol = dotSymbol(ptColor,name); 
     276            var iconSymbol = dotSymbol(ptColor, name); 
    255277            // return the StyleOptions 
    256278            return { 
    257                     icon: iconSymbol, 
    258                     title: name + " @" + street, // set rollover text 
    259                     // set zIndex for slowed traffic to a higher value so they overlap 
    260                     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            }; 
    262284        }); 
    263285    } 
     
    269291        features.forEach(function(feature) 
    270292        { 
    271             var pt = feature.getGeometry().get();  
    272             vds_coords[feature.getId()] = pt;  // save the Point in a dictionary 
     293            var pt = feature.getGeometry().get(); 
     294            vds_coords[feature.getId()] = pt; // save the Point in a dictionary 
    273295        }); 
    274296        // update the dot colors from the dynamic json data  
     
    282304    { 
    283305        // 15 is maximum zoom, the point at which no adjustment is needed 
    284         return (.0005*(15-map.getZoom()));   
     306        return (.0005 * (15 - map.getZoom())); 
    285307    } 
    286308 
     
    302324            var perpx = feature.getProperty("perpx") 
    303325            var perpy = feature.getProperty("perpy") 
    304             // Make adjustment and save it 
     326                // Make adjustment and save it 
    305327            var myLat = coords.lat() + perpy * adjAmount 
    306328            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    { 
    314340        target = marker.id; 
    315341        newColor = marker.properties.color; 
     
    320346        if (currentColor != newColor) 
    321347        { 
    322             currentFeature.setProperty("color",newColor); 
     348            currentFeature.setProperty("color", newColor); 
    323349            // set zIndex for slowed traffic to a higher value so they overlap 
    324350            currentFeature.setProperty("zIndex", colorZvalues[newColor]); 
    325351        } 
    326      } 
     352    } 
    327353 
    328354    // Load the dynamic json file for highways, etc. 
    329355    // 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 responses 
    343     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 map 
    347      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    { 
    349375        var parsed_JSON; 
    350         loadJSON(kMapPointsFile,function(response) 
     376        loadJSON(kMapPointsFile, function(response) 
    351377        { 
    352378            // Parse JSON string into object 
     
    355381            parsed_JSON.features.forEach(updateMarker); 
    356382        }); 
    357      } 
     383    } 
    358384 
    359385    // Initialize the center button (to re-center the map) 
     
    365391 
    366392        // 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(); 
    371398        }); 
    372399    } 
     
    381408 
    382409        // 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()); 
    385413        }); 
    386414 
    387415        // Listen for the event fired when the user selects a prediction and retrieve 
    388416        // 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                } 
    418467            }); 
    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()); 
    435472        }); 
    436473    } 
     
    439476    function clearPlacePins() 
    440477    { 
    441           placePins.forEach(function(marker) { 
     478        placePins.forEach(function(marker) 
     479        { 
    442480            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        { 
    454493            cctv_showing = !cctv_showing; 
    455494            // 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); 
    459498            } 
    460499            // Determine which button image to show 
     
    467506                pic = "images/CPTMSImages/btnReady_CCTV.png" 
    468507            } 
    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        { 
    477517            cms_showing = !cms_showing; 
    478518            // 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); 
    482523            } 
    483524            // Determine which button image to show 
     
    490531                pic = "images/CPTMSImages/btnReady_CMS.png" 
    491532            } 
    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        { 
    501543            vds_showing = !vds_showing; 
    502544            // reveal or hide all the dots 
    503545            map.data.forEach(function(feature) 
    504546            { 
    505                 map.data.overrideStyle(feature, {visible:vds_showing}); 
     547                map.data.overrideStyle(feature, 
     548                { 
     549                    visible: vds_showing 
     550                }); 
    506551            }); 
    507552            // Determine which button image to show 
     
    514559                pic = "images/CPTMSImages/btnReady_VDS.png" 
    515560            } 
    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 + "&nbsp;&nbsp;&nbsp;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 + "&nbsp;nearVDS:" + 
     683                            this.nearVDS + "&nbsp;" + 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        { 
    533764            // 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); 
    536769            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 + "&nbsp;&nbsp;&nbsp;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); 
    579771        } 
    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 + "&nbsp;nearVDS:"  
    638          + this.nearVDS + "&nbsp;" + 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    } 
    728799 
    729800    // Initialize the map and load the points 
    730     function initMap()  
     801    function initMap() 
    731802    { 
    732803        // 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, 
    736807            center: centerPoint, 
    737808            styles: night_mode, 
    738809            mapTypeControl: false, 
    739             streetViewControl: false   
    740         }); 
    741         loadMapData();  // go load the map data 
     810            streetViewControl: false 
     811        }); 
     812        loadMapData(); // go load the map data 
    742813        // setup the search box and center button 
    743814        initSearch(); 
    744815        initCenter(); 
     816        loadAllMessages(); // load the current message file 
     817        var startTime = setTimeout(setCMSmarkers, 2000); 
     818        var startTime = setTimeout(setCCTVmarkers, 3000); 
    745819        initButton(); 
    746         getMessage(1); // load the current message file 
    747         var startTime = setTimeout(setCMSmarkers,2000); 
    748         var startTime = setTimeout(setCCTVmarkers, 3000); 
    749820 
    750821        // Start a timer to refresh the map every 10 seconds 
    751822        var myTimer = setInterval(updateMap, 10000); 
     823        // start an interval timer to refresh the cms icons every 10 seconds 
     824        var cmsTimer = setInterval(refreshCMSicons, 10000); 
    752825        // Listen for zoom changes and move the placePins so as to keep a nice 
    753826        // visual distance between them appropriate to the zoom factor 
    754         map.addListener('zoom_changed', function() { 
     827        map.addListener('zoom_changed', function() 
     828        { 
    755829            // fetch how much the map is currently zoomed 
    756             currentZoom = map.getZoom();  
     830            currentZoom = map.getZoom(); 
    757831            // only bother adjusting within this range 
    758             if ((currentZoom <16) && (currentZoom>10)) 
     832            if ((currentZoom < 16) && (currentZoom > 10)) 
    759833            { 
    760834                // magic formula controls distance between dots 
     
    764838 
    765839    } 
    766  
    767840    // Styles array for Night Mode map 
    768841    // Ref: https://developers.google.com/maps/documentation/javascript/styling 
Note: See TracChangeset for help on using the changeset viewer.