var postmileList = []; // the list of postmiles saved from the json file. var chosenColor = "yellow"; // stores color that user picks, initial default yellow // function to find differences between two arrays Array.prototype.diff = function(a) { return this.filter(function(i) {return a.indexOf(i) < 0;}); }; // Build a solid colored icon to use instead of the classic pin function dotSymbol(color) { var iconPath = iconVDSwhite; if (color == 'red') { iconPath = iconVDSred; } else if (color == 'yellow') { iconPath = iconVDSyellow; } else if (color == 'lime') { iconPath = iconVDSgreen; } return { url: iconPath, anchor: new google.maps.Point(6, 6) }; } // Load the map data from a json file and style all the points function loadVDSlayer() { // Load the static map data and call saveCoords when done map.data.loadGeoJson(kMapStartupFile, null, saveCoords) // Style the map data by applying the desired properties to each feature (marker) // The function will be called every time a feature's properties are updated. map.data.setStyle(function(feature) { // Get the postmile id var name = feature.getId(); // Get the desired color value var ptColor = feature.getProperty("color"); var street = feature.getProperty("street"); // Build the marker var iconSymbol = dotSymbol(ptColor); // return the StyleOptions return { icon: iconSymbol, title: name + " @" + street, // set rollover text // set zIndex for slowed traffic to a higher value so they overlap zIndex: colorZvalues[ptColor] }; }); var clicked = false; var first = []; // stores first dot var asc = false; //ascending //var color_arr = []; var white_arr = []; //stores all white dots // Initialize the current time to zero var currentTime = new Date(0); currentTime.setHours(0); currentTime.setMinutes(0); currentTime.setSeconds(0); map.data.addListener('click', function(event) { var event_arr = event.feature.getId().split(/[ ,]+/); // if user has already made the first click and the second click is // on the same highway and same direction if (clicked && event_arr[0] === first[0] && event_arr[1] === first[1]) { // compute range between the two clicked dots var range = Math.abs(parseFloat(event_arr[2]) - parseFloat(first[2])); var clicked_dots = []; // checks highway direction to determine if postmiles are ascending or descending if (parseFloat(event_arr[2]) < parseFloat(first[2])) { asc = false; } else { asc = true; } // searches map for all dots between the two clicked dots and adds it to list "clicked_dots" map.data.forEach(function (marker) { var marker_arr = marker.getId().split(/[ ,]+/); // if the dot in the map matches the highway and direction of the clicked dot if (marker_arr[0] === event_arr[0] && marker_arr[1] === event_arr[1]) { // compute distance based on direction of highway if (asc) { var dist = parseFloat(marker_arr[2]) - parseFloat(first[2]); } else { var dist = parseFloat(parseFloat(first[2]) - (marker_arr[2])); } // if dist within range of the two clicked dots, add to list "clicked_dots" if (dist <= range && dist >= 0) { clicked_dots.push(marker); } } }); //color_arr.push(clicked_dots); //console.log(clicked_dots); //console.log(range); // extracts ids for all the white dots var white_arr_ids = white_arr.map(function (marker) { return marker.id; }); // extracts ids for all the clicked dots var clicked_dots_ids = clicked_dots.map(function (marker) { return marker.getId(); }); // computes difference between the white dots and clicked dots to find the unused dots var unused_ids = white_arr_ids.diff(clicked_dots_ids); //console.log("Unused: ",unused_ids, "White: ",white_arr_ids); // change the dot color of all the unused white dots back to their previous color unused_ids.forEach(function (id){ var marker = white_arr.filter(function (dot) { return dot.id === id; })[0]; var feature = map.data.getFeatureById(marker.id); feature.setProperty("color", marker.color); }); white_arr = []; // change the color of all the dots between the two clicked dots to the user picked color if (chosenColor) { clicked_dots.forEach(function (dot) { dot.setProperty("color", chosenColor); }); } // Increment the time by one-half minute (30 seconds) var millisecs = currentTime.getTime(); millisecs += 30000; currentTime = new Date(millisecs); // Create a printable string for the time (HH:MM:SS) var printableTime = currentTime.toLocaleTimeString('it-IT'); // Assemble the line to be written to the events file var lineOut = "101 " + printableTime + "\t" + first[0] + "\t" + first[1] + "\t" + first[2] + "\t" + range.toFixed(3) + "\t" + getColorAbbr(chosenColor); console.log(lineOut); // Using Ajax POST to send the data var xhr = new XMLHttpRequest(); xhr.open("POST", "../../cgi-bin/saveTrafficEvent.py", true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); // send the collected data xhr.send("msg="+lineOut + "\n") } // if user has not yet clicked on a dot else if (!clicked) { first = event_arr; // turns relevant dots white selectedID = event.feature.getId(); // get the id of the clicked dot curr = postmileList.indexOf(selectedID); // find the id in the postmile list var firstBlank = postmileList[curr].indexOf(" ", 0); // find direction substring var secondBlank = firstBlank+2; var direction = postmileList[curr].charAt(firstBlank+1); // extract direction target = event.feature.getId().substring(0,secondBlank); // extract target string //console.log("making white dots from " + selectedID + " in direction "+direction) // Decide whether to increment or decrement based on direction of hwy; // N and E increment, S and W decrement if (direction == 'N' || direction == 'E') { // Process all dots with same hwy and direction while (postmileList[curr].startsWith(target) && curr < postmileList.length) { // turn the dot white currFeat = map.data.getFeatureById(postmileList[curr]); white_arr.push({id : currFeat.getId(), color : currFeat.getProperty("color")}); currFeat.setProperty("color", "white"); curr++; } } else { // Process all dots with same hwy and direction while (postmileList[curr].startsWith(target) && curr > 0) { currFeat = map.data.getFeatureById(postmileList[curr]); white_arr.push({id : currFeat.getId(), color : currFeat.getProperty("color")}); // turn the dot white currFeat.setProperty("color", "white"); curr--; } } } // if the user's second click is made on a dot not on the first dot's highway else { console.log('wrong choice'); clicked = !clicked; } clicked = !clicked; }); } // callback when load GeoJson completes // save each feature's Point as the original coordinates for later reference function saveCoords(features) { // Iterate over all the features in the map features.forEach(function(feature) { var pt = feature.getGeometry().get(); vds_coords[feature.getId()] = pt; // save the Point in a dictionary postmileList.push(feature.getId()); // save the postmile in a list }); // update the dot colors from the dynamic json data updateVDSlayer(); // go adjust the marker coordinates so dots don't overlap adjustCoords(calcDistanceFactor()); } // magic formula controls distance between dots proportionate to zoom factor function calcDistanceFactor() { // 15 is maximum zoom, the point at which no adjustment is needed return (.0005 * (15 - map.getZoom())); } // Adjust the coordinates of dots so they appear side-by-side // The perpendicular vector for each dot has been provided, // so we just need to multiply by a scaling factor (adjAmount) // @param adjAmount amount by which to adjust coordinate function adjustCoords(adjAmount) { // Adjust the NB points a slight amount map.data.forEach(function(feature) { // get the name of the current feature var name = feature.getId(); // lookup the original coordinates for this feature var coords = vds_coords[name]; //retrieve the perpendicular vector (precomputed) var perpx = feature.getProperty("perpx") var perpy = feature.getProperty("perpy") // Make adjustment and save it var myLat = coords.lat() + perpy * adjAmount var myLong = coords.lng() + perpx * adjAmount feature.setGeometry( { lat: myLat, lng: myLong }); }); } // update the color (as needed) for a given marker function updateMarker(marker) { target = marker.id; newColor = marker.properties.color; // see if new color is different than current color currentFeature = map.data.getFeatureById(target); if (currentFeature) { currentColor = currentFeature.getProperty("color"); // if a new color is desired then assign it to the feature's color property if (currentColor != newColor) { currentFeature.setProperty("color", newColor); // set zIndex for slowed traffic to a higher value so they overlap currentFeature.setProperty("zIndex", colorZvalues[newColor]); } } } // Load the highways dynamic json file and update the map function updateVDSlayer() { eventIndex = -1; var parsed_JSON; loadJSON(kVDSstatusFile, function(response) { // Parse JSON string into object parsed_JSON = JSON.parse(response); // Process each new marker - lookup in current map parsed_JSON.features.forEach(updateMarker); }); } function getColorName(str){ if (str === "R\r" || str === "R") return "red"; else if (str === "Y\r" || str === "Y") return "yellow"; else if (str === "G\r" || str === "G") return "lime"; } // gets the starting letter of a given color function getColorAbbr(str){ if (str === "red") return "R"; else if (str === "yellow") return "Y"; else if (str === "lime") return "G"; } function initColorButtons() { // add the respective color buttons onto the map var redColor = document.getElementById('redButton'); var greenColor = document.getElementById('greenButton'); var yellowColor = document.getElementById('yellowButton'); map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(redColor); map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(greenColor); map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(yellowColor); // store the user picked color in "chosenColor" redColor.addEventListener('click', function() { chosenColor = "red"; redColor.style.background = "red"; greenColor.style.background = "gray"; yellowColor.style.background = "gray"; }); greenColor.addEventListener('click', function() { chosenColor = "lime"; greenColor.style.background = "green"; redColor.style.background = "gray"; yellowColor.style.background = "gray"; }); yellowColor.addEventListener('click', function(){ chosenColor = "yellow"; yellowColor.style.background = "yellow"; redColor.style.background = "gray"; greenColor.style.background = "gray"; }); // set default button on yellowColor.style.background = "yellow"; }