Traffic Mapping Fun
I am working on a little, crude, traffic mapping system for Nassau. (Anywhere really, but I am doing it for Nassau.)
It started out this way...
I developed a little android app that used its location, speed, time, etc. to build a fake URL that contains this information and then requests this fake URL from a web server that I have access to the logs for. Since this is a fake URL, it never gets back what it asks for but this is intended. The information I need is now in the logs.
I can then scan web server logs and look for lines that the app created. I have a script that puts these lines into a format that I want to parse for the web map.
I can then scan web server logs and look for lines that the app created. I have a script that puts these lines into a format that I want to parse for the web map.
I am making the web map using openlayers and openstreetmap stuff. Oh, javascript, jquery, and bootstrap too.
Not that I really know how to use this stuff fit a kick. My ignorance is vast.
So. This is the html page: wblogger.html
And this is the datafile: systemlines.txt
<pre style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPZbQrgON51ozgHamH6U62pP4MEB2zPxKNd_-VVsztA2Gt3v37erG_1WWh_UxDN3e5lH6H19E88ji2CRQJfh4sB6yfmvvWHVko2N3z-oHlnqXq9-78TAGFJhiiLac_0dJSsPc6rQj8_Ceg/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"><code style="color:#000000;word-wrap:normal;"> <!doctype html> <html lang="en"> <head> <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css"> <style> .map { height: 400px; width: 100%; } #map { position: relative; } #popup { padding-bottom: 45px; } </style> <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script> <script type = "text/javascript" src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script> <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"> <script type="text/javascript"> // $( document ).ready(function() { console.log( "ready!" ); }); </script> <title>OpenLayers example</title> </head> <body> <h2>zotzBrothers Traffic Map</h2> <div id="map" style="width:1200px;height:800px" class="map"></div> <div id="popup"></div> <script type="text/javascript"> window.carLocs = new Array(); $.get('systemlines.txt', function(data){ window.carLocs = data.split('\n'); //console.log(window.carLocs); mymap(); }); function mymap(){ var vectorSource = new ol.source.Vector({ //create empty vector }); //create the style var iconStyle = new ol.style.Style({ image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ anchor: [0, 0], anchorXUnits: 'fraction', anchorYUnits: 'pixels', opacity: 0.75, color: [113, 140, 0], src: 'ol_icon.png' })) }); //create a bunch of icons and add to source vector for (var i=0;i<(carLocs.length-1);i++){ var myrecs = carLocs[i].split('/'); //console.log("lat ",mypos[0]," long ",mypos[1], " speed ", mypos[2]); //console.log(myrecs[0],myrecs[1],myrecs[2],myrecs[3],myrecs[4],myrecs[5]) var mypos = myrecs[4].split('||'); //console.log("lat ",mypos[0]," long ",mypos[1], " speed ", mypos[2]); //console.log(mypos); var myspeed = myrecs[5].split(':'); //console.log("Only speed: ",myspeed[1]); var dauser = myrecs[2]; //console.log("user ",dauser); var dalat = Number(mypos[1]); //console.log("lat ",dalat); var dalong = Number(mypos[0]); //console.log("long ",dalong); //console.log("speed bit: ", myrecs[5]); var daspeed = Math.round( Number(myspeed[1]) * 10 ) / 10; //console.log("speed ",daspeed); //console.log(dalat,dalong,daspeed); var iconFeature = new ol.Feature({ geometry: new ol.geom.Point(ol.proj.transform([dalat, dalong], 'EPSG:4326', 'EPSG:3857')), name: 'daInstance_' + i + " Speed: " + daspeed, speed: daspeed }); if (daspeed < 10) { iconFeature.setStyle(new ol.style.Style({ image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ anchor: [0, 0], anchorXUnits: 'fraction', anchorYUnits: 'pixels', opacity: 0.75, color: '#DC143C', src: 'ol_icon.png', scale: 0.5 })) })); } vectorSource.addFeature(iconFeature); } //add the feature vector to the layer vector, and apply a style to whole layer var vectorLayer = new ol.layer.Vector({ source: vectorSource, style: iconStyle }); var map = new ol.Map({ layers: [new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer], target: document.getElementById('map'), view: new ol.View({ center: ol.proj.fromLonLat([-77.353011, 25.0785398]), zoom: 12 }) }); var element = document.getElementById('popup'); var popup = new ol.Overlay({ element: element, positioning: 'bottom-center', stopEvent: false }); map.addOverlay(popup); // display popup on click map.on('click', function(evt) { var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature, layer) { return feature; }); if (feature) { var geometry = feature.getGeometry(); var coord = geometry.getCoordinates(); popup.setPosition(coord); $(element).popover({ 'placement': 'top', 'html': true }); $(element).data("bs.popover").options.content= feature.get('name'); $(element).popover("show"); //document.getElementsByClassName("popover-content")[0].innerHTML = feature.get('name'); //$(element).popover('show'); } else { $(element).popover('destroy'); } }); // change mouse cursor when over marker map.on('pointermove', function(e) { if (e.dragging) { $(element).popover('destroy'); return; } var pixel = map.getEventPixel(e.originalEvent); var hit = map.hasFeatureAtPixel(pixel); map.getTarget().style.cursor = hit ? 'pointer' : ''; }); } </script> </body> </html> </code></pre>
And this is the datafile: systemlines.txt
/zbloc/U999999/Speed_OK:13.93651/25.07857||-77.34838||-20.33905/Current_Speed:13.93651 /zbloc/U999999/Speed_OK:21.58705/25.07843||-77.35162||-27.1488/Current_Speed:21.58705 /zbloc/U999999/Speed_OK:29.55077/25.07976||-77.36289||-31.21094/Current_Speed:29.55077 /zbloc/U999999/Speed_OK:30.40083/25.07899||-77.35873||-31.58047/Current_Speed:30.40083 /zbloc/U999999/Speed_OK:31.63118/25.07833||-77.35521||-21.68082/Current_Speed:31.63118 /zbloc/U999999/Speed_OK:9.19407/25.0782||-77.34737||-31.22083/Current_Speed:9.19407 /zbloc/U999999/Speed_Slow:0/25.07853||-77.35114||-42.20892/Current_Speed:0 /zbloc/U999999/Speed_Slow:11.94558/25.07862||-77.34995||-18.98419/Current_Speed:11.94558 /zbloc/U999999/Speed_Slow:13.93651/25.07857||-77.34838||-20.33905/Current_Speed:13.93651 /zbloc/U999999/Speed_Slow:14.11547/25.07856||-77.34897||-27.05417/Current_Speed:14.11547 /zbloc/U999999/Speed_Slow:1.45405/25.07847||-77.35113||-20.47964/Current_Speed:1.45405 /zbloc/U999999/Speed_Slow:1.54353/25.07853||-77.35106||-30.974/Current_Speed:1.54353 /zbloc/U999999/Speed_Slow:1.54353/25.07853||-77.35106||-30.974/Current_Speed:1.54353 /zbloc/U999999/Speed_Slow:21.58705/25.07843||-77.35162||-27.1488/Current_Speed:21.58705 /zbloc/U999999/Speed_Slow:24.11486/25.07878||-77.35756||-29.90512/Current_Speed:24.11486 /zbloc/U999999/Speed_Slow:25.61365/25.07832||-77.35262||-30.26508/Current_Speed:25.61365 /zbloc/U999999/Speed_Slow:27.11244/25.07859||-77.35653||-33.70917/Current_Speed:27.11244 /zbloc/U999999/Speed_Slow:29.55077/25.07976||-77.36289||-31.21094/Current_Speed:29.55077 /zbloc/U999999/Speed_Slow:29.66262/25.07818||-77.35385||-27.67673/Current_Speed:29.66262 /zbloc/U999999/Speed_Slow:30.40083/25.07899||-77.35873||-31.58047/Current_Speed:30.40083 /zbloc/U999999/Speed_Slow:31.63118/25.07833||-77.35521||-21.68082/Current_Speed:31.63118 /zbloc/U999999/Speed_Slow:32.4365/25.07932||-77.36005||-27.33765/Current_Speed:32.4365 /zbloc/U999999/Speed_Slow:33.37604/25.07954||-77.3615||-28.73572/Current_Speed:33.37604 /zbloc/U999999/Speed_Slow:3.3555/25.07801||-77.34728||-24.91364/Current_Speed:3.3555 /zbloc/U999999/Speed_Slow:3.48972/25.07852||-77.34784||-7.2254/Current_Speed:3.48972 /zbloc/U999999/Speed_Slow:4.38452/25.07796||-77.34716||-26.48145/Current_Speed:4.38452 /zbloc/U999999/Speed_Slow:5.54776/25.07856||-77.35069||-15.47156/Current_Speed:5.54776 /zbloc/U999999/Speed_Slow:8.67956/25.07847||-77.3476||-11.89642/Current_Speed:8.67956 /zbloc/U999999/Speed_Slow:9.19407/25.0782||-77.34737||-31.22083/Current_Speed:9.19407
So this was my first take. What this shows...
- The ability to place "cars" on the map based on external data in a file.
- The ability to change the colour of the cars based on the car's speed.
- The ability to change the size of the cars. (Again based on the car's speed but this in not the final purpose for setting the size.)
- The ability to popup information about the car by clicking on its icon.
Desired improvements...
- Automatically put app data into a database. (mysql/mariadb with geo features.)
- Ability of web page to pull in data from the database instead of a text file.
- Ability to change the size of the car icons in an intelligent way so that they scale with the size of the roads they are on as the map zoom changes.
- Fix the problem with the car icons being "offset" from the roads. Unless this turns out to be an issue with the data being inaccurate...
- (I don't think the problem mentioned in 4 can be the whole issue) Fix the fact that the car icon's position with respect to the map roads changes on zooming.
- It would be nice if the choice of when to consider a car slow could be based on the speed limit of the road but that is not 100% necessary at this point.
- It would be nice to change the orientation of the car to match the road so that it does not sit sideways on north/south roads. (Perhaps it would be better to represent the car as a point if this is not possible?)
- perhaps add a few more colour coded speed "bands" rather than just red for slow and green for normal.
I have made progress on some of the above and will post improvements when I can.
I am looking for people who would like to discuss this and people who have a bit more expertise with openlayers/javascript/etc.