source: tmcsimulator/trunk/webapps/visualizer/js/vdsLayer.js @ 530

Revision 530, 12.6 KB checked in by jdalbey, 6 years ago (diff)

Visualizer updated with Back button and code comments added

Line 
1    // Load the map data from a json file and style all the points
2    function initializeVDSlayer()
3    {
4        // Load the static map data and call saveCoords when done
5        map.data.loadGeoJson(kMapStartupFile, null, saveCoords)
6        // Style the map data by applying the desired properties to each feature (marker)
7        // The function will be called every time a feature's properties are updated.
8        map.data.setStyle(function(feature)
9        {
10            // Get the postmile id
11            var name = feature.getId();
12            // Get the desired color value
13            var ptColor = feature.getProperty("color");
14            var street = feature.getProperty("street");
15            // Build the marker
16            var iconSymbol = dotSymbol(ptColor);
17            // return the StyleOptions
18            return {
19                icon: iconSymbol,
20                title: name + " @" + street, // set rollover text
21                // set zIndex for slowed traffic to a higher value so they overlap
22                zIndex: colorZvalues[ptColor]
23            };
24        });
25    }
26
27    // Build a solid colored icon to use instead of the classic pin
28    function dotSymbol(color) 
29    {
30        var iconPath = iconVDSwhite;
31        if (color == 'red')
32        {
33           iconPath = iconVDSred;
34        }
35        else if (color == 'yellow')
36        {
37            iconPath = iconVDSyellow;
38        }
39        else if (color == 'lime')
40        {
41            iconPath = iconVDSgreen;
42        }
43        return {
44            url: iconPath, 
45            anchor: new google.maps.Point(6, 6)
46        };
47    }
48
49    // callback when load GeoJson completes
50    // save each feature's Point as the original coordinates for later reference
51    function saveCoords(features)
52    {
53        // Iterate over all the features in the map
54        features.forEach(function(feature)
55        {
56            var pt = feature.getGeometry().get();
57            vds_coords[feature.getId()] = pt; // save the Point in a dictionary
58        });
59        // go adjust the marker coordinates so dots don't overlap
60        adjustCoords(calcDistanceFactor());
61        processVDS();
62    } 
63
64    // magic formula controls distance between dots proportionate to zoom factor
65    function calcDistanceFactor()
66    {
67        // 15 is maximum zoom, the point at which no adjustment is needed
68        return (.0005 * (15 - map.getZoom()));
69    }
70
71    // Adjust the coordinates of dots so they appear side-by-side
72    // The perpendicular vector for each dot has been provided,
73    // so we just need to multiply by a scaling factor (adjAmount)
74    // @param adjAmount amount by which to adjust coordinate
75    function adjustCoords(adjAmount)
76    {
77        // Adjust the NB points a slight amount
78        map.data.forEach(function(feature)
79        {
80            // get the name of the current feature
81            var name = feature.getId();
82            // lookup the original coordinates for this feature
83            var coords = vds_coords[name];
84
85            //retrieve the perpendicular vector (precomputed)
86            var perpx = feature.getProperty("perpx")
87            var perpy = feature.getProperty("perpy")
88                // Make adjustment and save it
89            var myLat = coords.lat() + perpy * adjAmount
90            var myLong = coords.lng() + perpx * adjAmount
91            feature.setGeometry(
92            {
93                lat: myLat,
94                lng: myLong
95            });
96        });
97    }
98
99    // update the color (as needed) for a given marker
100    function updateMarker(marker)
101    {
102        target = marker.id;
103        newColor = marker.properties.color;
104        // see if new color is different than current color
105        currentFeature = map.data.getFeatureById(target);
106        currentColor = currentFeature.getProperty("color");
107        // if a new color is desired then assign it to the feature's color property
108        if (currentColor != newColor)
109        {
110            currentFeature.setProperty("color", newColor);
111            // set zIndex for slowed traffic to a higher value so they overlap
112            currentFeature.setProperty("zIndex", colorZvalues[newColor]);
113        }
114    }
115
116    // Load the highways static json file and update the map
117    function resetVDSlayer()
118    {
119        eventIndex = -1;
120        loadJSON(kMapStartupFile, function(response)
121        {
122            // Parse JSON string into object
123            //initialVDSjson = JSON.parse(response);
124            // Process each new marker - lookup in current map
125            var initialVDSjsonFeatures = JSON.parse(response).features
126            initialVDSjsonFeatures.forEach(updateMarker);
127        });
128    }
129
130    function getColorName(str){
131        if (str === "R\r" || str === "R")
132            return "red";
133        else if (str === "Y\r" || str === "Y")
134            return "yellow";
135        else if (str === "G\r" || str === "G")
136            return "lime";
137    }
138
139// Parses the traffic events file and builds an array of target dots for each line
140    function processVDS() {
141        //var parsed_JSON;
142        loadJSON(kMapStartupFile, function(response)
143        { 
144            // Parse JSON string into object
145            parsed_JSON = JSON.parse(response);
146            // Process each new marker - lookup in current map
147            var parsed_features =  parsed_JSON.features;
148            parsed_features.forEach(updateMarker);
149            var eventsFile = '';
150            // Request the traffic events data file
151            var xmlhttp = new XMLHttpRequest();
152            xmlhttp.open("GET",trafficEventsFile,true); // Ask the server for the traffic events file
153            // Establish listener for handling the traffic events once file is read
154            xmlhttp.onreadystatechange = function()
155            {
156                if(xmlhttp.status == 200 && xmlhttp.readyState == 4)
157                {
158                    eventsFile = xmlhttp.responseText;
159                    // Process the traffic events file
160                    var lines = eventsFile.toString().split("\n");
161                    // For each line in the events file
162                    for (var line = 1; line < lines.length; line++) 
163                    {
164                        var trimmedLine = lines[line].trim();
165                        if (trimmedLine[0] !== '#') //ignores lines with #
166                        {
167                            var dots = [];                           
168                            var event = trimmedLine.split(/[ ,]+/);
169                            var start = parseFloat(event[4]); // extract postmile field
170                            var range = parseFloat(event[5]); // extract distance
171                            var newColor = getColorName(event[6]); // extract DotColor
172                            eventTimes.push(event[1]);  // extract the event time
173                            // Process each VDS in the highway network
174                            parsed_features.forEach(function (marker) {
175                                var marker_fields = marker.id.split(" ");
176                                // See if this marker's highway and direction match to this event
177                                if (marker_fields[0] === event[2] && marker_fields[1] === event[3])
178                                {   //computes difference in postmiles
179                                    var dist = parseFloat(marker_fields[2]) - start; 
180                                    // If this marker is within computed range
181                                    if (dist <= range && dist >= 0) 
182                                    {
183                                        // Add the marker to the dots representing this event
184                                        dots.push({"marker": marker, "color": newColor});
185                                    }
186                                }
187                            });
188                            targetDots.push(dots); // add this events dots to the list of targetdots
189                        } // end if
190                    }  // end for             
191                    // After the traffic events are processed,  go build the differences array
192                    buildDiff();      // side effect: leaves map with last event showing
193                    resetVDSlayer();  // restore the map to initial state
194                }
195            };
196            xmlhttp.send();
197        });
198    }
199
200    // Calls updateMarker for all targetDots after storing the previous marker in diff_arr
201    // This function only needs to be done once, during startup.
202    function buildDiff() 
203    {
204        for (var i = 0; i <= targetDots.length; i++)
205        {
206            if  (targetDots[i] !== undefined)
207            {
208                var targetMarkers = new Array();
209                targetDots[i].forEach(function(item)
210                {
211                    item.marker.properties.color = item.color;
212                    storePrev(item.marker, targetMarkers);
213                    updateMarker(item.marker);
214                });
215                diff_arr.push(targetMarkers);
216            }
217        }
218    }
219    // Helper function for BuildDiff
220    // Store the previous colors of the targetDots
221    // so it will available if the user goes "back".
222    function storePrev(marker, targetMarkers) 
223    {
224        target = marker.id;
225        newColor = marker.properties.color;
226        // see if new color is different than current color
227        currentFeature = map.data.getFeatureById(target);
228        currentColor = currentFeature.getProperty("color");
229        // if a new color is desired then assign it to the feature's color property
230        if (currentColor != newColor)
231        {
232            targetMarkers.push({"id" : currentFeature.getId(),
233                "properties" : {"color" : currentColor}});
234        }
235    }
236
237
238
239    // Increments the eventIndex from and updates all the targetDots on map
240    function updateForwards() {
241        eventIndex++;
242        // limit eventIndex to length of targetDots
243        if (eventIndex >= targetDots.length) 
244        {
245            eventIndex = targetDots.length - 1;
246        }
247        // update all the target dots
248        if  (targetDots[eventIndex] !== undefined) {
249            targetDots[eventIndex].forEach(function(item){
250                item.marker.properties.color = item.color;
251                updateMarker(item.marker);
252            });
253        }
254    }
255
256    // Decrements the eventIndex and updates all the targetDots from diff_arr on map
257    function updateBackwards() {
258        //update each target dot in order to revert to previous color
259        if  (diff_arr[eventIndex] !== undefined) {
260            diff_arr[eventIndex].forEach(function(item){
261                updateMarker(item);
262            });
263        }
264        eventIndex--; 
265        // restrict eventIndex to -1
266        if (eventIndex < -1)
267        {
268            eventIndex = -1;
269        }
270    }
271   
272
273// init beginning, forward and back buttons as well as time display on map
274function initControlButtons()
275{
276    var i = 0;
277    // setup the time display
278    var time = document.getElementById('time');
279    map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(time)
280    // set up the "beginning" button
281    var beginning = document.getElementById('beginning');
282    map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(beginning)
283    beginning.title = 'Click to see the first event';
284    // set up the "next" button
285    var forward = document.getElementById('forward');
286    map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(forward)
287    // set up the "back" button
288        var backward = document.getElementById('backward');
289        map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(backward)
290    forward.title = 'Click to see the next event';
291    //console.log(targetDots, eventTimes);
292    // Establish the listeners for each button
293    forward.addEventListener('click', function() {
294        updateForwards();
295        backward.disabled = false;
296        if (i < eventTimes.length - 1) // get the next eventTime
297        {
298            ++i;
299            time.innerHTML = eventTimes[i];
300        }
301        if (eventIndex === targetDots.length - 1) // disable next button if last event reached
302        {
303            forward.disabled = true;
304        }
305    });
306        backward.addEventListener('click', function() {
307        updateBackwards();
308        forward.disabled = false;
309        if (i > 0)  // get the prev eventTime
310        {
311            --i;
312            time.innerHTML = eventTimes[i];
313        }
314        if (eventIndex < 0) // disable back button if at first event
315        {
316            backward.disabled = true;
317        }
318        });
319    beginning.addEventListener('click', function() {
320        resetVDSlayer(); // redraw markers on map from startup file
321        i = 0;
322        time.innerHTML = "00:00:00";
323    });
324}
325
Note: See TracBrowser for help on using the repository browser.