source: tmcsimulator/trunk/stms_map_v5.html @ 271

Revision 271, 10.8 KB checked in by jdalbey, 7 years ago (diff)

Added stms_map_v5.html That shows google map of highway network without overlapping dots.

Line 
1<!DOCTYPE html>
2<html>
3  <head>
4  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
5    <title>STMS Map </title> 
6    <style>
7      /* Set the size of the div element that contains the map */
8      #mapdiv {
9        height: 100%;
10        width: 100%; 
11       }
12        /* Makes the page fill the window. */
13      html, body {
14        height: 100%;
15        margin: 0;
16        padding: 0;
17      }
18    </style>
19  </head>
20  <body>
21    <h3>STMS Map 0.5</h3>
22    <!--The div element where the map appears -->
23    <div id="mapdiv"></div>
24    <!-- Version 5 uses precomputed perpendicular vector in dot adjustment function
25         Version 4 Adjust the spacing between dots when the map is zoomed.
26         Version 3 does loadGeoJson only once, and subsequently does an ajax load
27         of the highways file, and selectively updates only those markers whose
28         color has changed.
29         @author jdalbey  2019.2.17
30    -->
31    <script>
32    // a global variable for the google map
33    var map; 
34    // Constant name of json data file
35    var kMapPointsFile = "highways.json";
36    // Constant for map center location: The John Wayne Airport
37    var wayne = {lat: 33.687228, lng: -117.872148};
38    // Initial map zoom
39    var initZoom = 12;
40    // Free flowing traffic color (should match what traffic model creates)
41    var freeflowColor = "lime"
42
43    // Build a solid colored icon to use instead of the classic pin
44    // Use a diamond on N and E directions, circle on S and W directions
45    function dotSymbol(color,postmileID) //,direction)
46    {
47        var circle = google.maps.SymbolPath.CIRCLE;
48        var diamond = 'M -1,0 0,-1 1,0 0,1 z';
49        var myShape = circle;
50        // See if postmile name contains N or W letters
51        if ((postmileID.indexOf('N') != -1) || (postmileID.indexOf('W') != -1))
52        {
53           myShape = diamond
54        }
55        return {
56            path: myShape,
57            scale: 5,
58            strokeColor: "black", // the border color
59            strokeWeight: 1,      // the border thickness
60            fillColor: color,
61            fillOpacity: 1.0
62        };
63    }
64
65    // Load the map data from a json file and style all the points
66    function loadMapData()
67    {
68        // Load the map data
69        map.data.loadGeoJson(kMapPointsFile);
70        // Style the map data by applying the desired properties to each feature (marker)
71        map.data.setStyle(function(feature) 
72        {
73            // Get the desired color value
74            var ptColor = feature.getProperty("color");
75            // Get the postmile id
76            var name = feature.getId();
77            var street = feature.getProperty("street");
78            // Build the marker
79            var iconSymbol = dotSymbol(ptColor,name);
80            // return the StyleOptions
81            return {
82                    icon: iconSymbol,
83                    title: name + " @" + street,  // set rollover text
84                    // set zIndex for slowed traffic to a higher value so they overlap
85                    zIndex: ptColor==freeflowColor?10:999
86                   };
87        });
88    }
89
90    // magic formula controls distance between dots proportionate to zoom factor
91    function calcDistanceFactor()
92    {
93        // 15 is maximum zoom, the point at which no adjusment is needed
94        return (.0005*(15-map.getZoom())); 
95    }
96
97    // Adjust the coordinates of dots so they appear side-by-side
98    // The perpendicular vector for each dot has been provided,
99    // so we just need to multiply by a scaling factor (adjAmount)
100    // @param adjAmount amount by which to adjust coordinate
101    function adjustCoords(adjAmount)
102    {
103        //console.log("adjusting coordinates");
104        // Adjust the NB points a slight amount
105        map.data.forEach(function(feature)
106        {
107            // get the name of the current feature
108            var name = feature.getId();
109            // lookup the name in the list of markers
110            var marker = parsed_JSON.features.find(function(element)
111                {
112                    return element.id == name;
113                });
114            // extract the original coordinates
115            origLat = marker.geometry.coordinates[1];
116            origLong = marker.geometry.coordinates[0];
117
118            //retrieve the perpendicular vector (precomputed)
119            var perpx = feature.getProperty("perpx")
120            var perpy = feature.getProperty("perpy")
121            // Make adjustment and save it
122            var myLat = origLat + perpy * adjAmount
123            var myLong = origLong + perpx * adjAmount
124            feature.setGeometry({lat:myLat, lng:myLong});
125        });
126    }
127
128     // update the color (as needed) for a given marker
129     function updateMarker(marker)
130     {
131        target = marker.id;
132        newColor = marker.properties.color;
133        // see if new color is different than current color
134        currentFeature = map.data.getFeatureById(target);
135        currentColor = currentFeature.getProperty("color");
136        //console.log("current color:",currentColor," newColor: ",newColor);
137        // if a new color is desired then assign it to the feature's color property
138        if (currentColor != newColor)
139        {
140            currentFeature.setProperty("color",newColor);
141        }
142     }
143
144    // Load the highways file via ajax
145    // Ref: https://codepen.io/KryptoniteDove/post/load-json-file-locally-using-pure-javascript
146     function loadJSON(callback) {   
147
148        var xobj = new XMLHttpRequest();
149            xobj.overrideMimeType("application/json");
150        xobj.open('GET', kMapPointsFile, true); 
151        xobj.onreadystatechange = function () {
152              if (xobj.readyState == 4 && xobj.status == "200") {
153                // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
154                callback(xobj.responseText);
155              }
156        };
157        xobj.send(null); 
158     }
159
160     var parsed_JSON;
161     // Load the highways json file and update the map
162     function updateMap()
163     {
164        loadJSON(function(response)
165        {
166            // Parse JSON string into object
167            parsed_JSON = JSON.parse(response);
168            // Process each new marker - lookup in current map
169            parsed_JSON.features.forEach(updateMarker);
170        });
171     }
172
173    // Initialize the map and load the points
174    function initMap() 
175    {
176        // Declare the map and where it belongs on the page
177        map = new google.maps.Map( document.getElementById('mapdiv'), 
178        {
179            zoom: initZoom, 
180            center: wayne,
181            styles: night_mode 
182        });
183        loadMapData();  // go load the map data
184        // After a brief pause to let map finish loading ...
185        quiktimer = setTimeout("updateMap()",1000);
186        // go adjust the marker coordinates so dots don't overlap
187        quiktimer = setTimeout("adjustCoords(calcDistanceFactor())",1500); 
188        // Start a time to refresh the map every 30 seconds
189        var myTimer = setInterval(updateMap, 30000);
190        // Listen for zoom changes and move the markers so as to keep a nice
191        // visual distance between them appropriate to the zoom factor
192        map.addListener('zoom_changed', function() {
193            // fetch how much the map is currently zoomed
194            currentZoom = map.getZoom(); 
195            //console.log("Zoom changed to ",currentZoom);
196            // only bother adjusting within this range
197            if ((currentZoom <16) && (currentZoom>10))
198            {
199                // magic formula controls distance between dots
200                factor = (.0005*(15-currentZoom)); 
201                adjustCoords(calcDistanceFactor());
202            }
203        });
204
205    }
206
207    // Styles array for Night Mode map
208    // Ref: https://developers.google.com/maps/documentation/javascript/styling
209    var night_mode = [
210                {elementType: 'geometry', stylers: [{color: '#242f3e'}]},
211                {elementType: 'labels.text.stroke', stylers: [{color: '#242f3e'}]},
212                {elementType: 'labels.text.fill', stylers: [{color: '#746855'}]},
213                {
214                  featureType: 'administrative.locality',
215                  elementType: 'labels.text.fill',
216                  stylers: [{color: '#d59563'}]
217                },
218                {
219                  featureType: 'poi',
220                  elementType: 'labels.text.fill',
221                  stylers: [{color: '#d59563'}]
222                },
223                {
224                  featureType: 'poi.park',
225                  elementType: 'geometry',
226                  stylers: [{color: '#263c3f'}]
227                },
228                {
229                  featureType: 'poi.park',
230                  elementType: 'labels.text.fill',
231                  stylers: [{color: '#6b9a76'}]
232                },
233                {
234                  featureType: 'road',
235                  elementType: 'geometry',
236                  stylers: [{color: '#38414e'}]
237                },
238                {
239                  featureType: 'road',
240                  elementType: 'geometry.stroke',
241                  stylers: [{color: '#212a37'}]
242                },
243                {
244                  featureType: 'road',
245                  elementType: 'labels.text.fill',
246                  stylers: [{color: '#9ca5b3'}]
247                },
248                {
249                  featureType: 'road.highway',
250                  elementType: 'geometry',
251                  stylers: [{color: '#746855'}]
252                },
253                {
254                  featureType: 'road.highway',
255                  elementType: 'geometry.stroke',
256                  stylers: [{color: '#1f2835'}]
257                },
258                {
259                  featureType: 'road.highway',
260                  elementType: 'labels.text.fill',
261                  stylers: [{color: '#f3d19c'}]
262                },
263                {
264                  featureType: 'transit',
265                  elementType: 'geometry',
266                  stylers: [{color: '#2f3948'}]
267                },
268                {
269                  featureType: 'transit.station',
270                  elementType: 'labels.text.fill',
271                  stylers: [{color: '#d59563'}]
272                },
273                {
274                  featureType: 'water',
275                  elementType: 'geometry',
276                  stylers: [{color: '#17263c'}]
277                },
278                {
279                  featureType: 'water',
280                  elementType: 'labels.text.fill',
281                  stylers: [{color: '#515c6d'}]
282                },
283                {
284                  featureType: 'water',
285                  elementType: 'labels.text.stroke',
286                  stylers: [{color: '#17263c'}]
287                }
288              ]
289
290    // Using John's API Key
291    </script>
292    <script async defer
293    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD6iTyN0DjP-9OVkAgicyp4tkC10naE_B8&callback=initMap">
294    </script>
295  </body>
296</html>
Note: See TracBrowser for help on using the repository browser.