Last active
August 16, 2019 18:14
-
-
Save maurice-does-software/4fd0a574ddd74ef7f78a51f84292791a to your computer and use it in GitHub Desktop.
This single page app will store and recall location data. Meant to be invoked via NFC tags or manually.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <script type="text/javascript" defer="defer"> | |
| /** | |
| * @author Maurice Ferguson maurice.does.software@gmail.com | |
| * @version 0.5 | |
| * @since 2019-08-16 | |
| * @see https://gist.github.com/maurice-does-software/4fd0a574ddd74ef7f78a51f84292791a | |
| * @desc | |
| The Intent: | |
| This single page app will store and recall a log of locations, | |
| which can then be copy/pasted or opened in Google maps. | |
| It is meant to be invoked via NFC tags or manually. | |
| I wrote this app rather than use an existing one because I'm protective of my privacy. | |
| This app works entirely offline. | |
| The data is only accessible through the phone on which it was collected, | |
| unless you have some other file syncing service at work. | |
| Setup Steps: | |
| This file and a bookmark to invoke it should be stored on an NFC tag. | |
| From there, save this file to your phone's storage. | |
| Move the file or change the NFC tag's bookmark as needed so the two match. | |
| You only need one copy of this file, no matter how many objects you track. | |
| For log viewing, bookmark "path/to/this/file". | |
| For immediate one-step logging, bookmark "path/to/this/file?objectName=my keys". | |
| Usage: | |
| Scan your movable, tagged object with your phone to log its current location. | |
| Now you'll never misplace your keys or forget where you parked your car! | |
| * @param | |
| string `objectName` - name of the object to log | |
| * @event | |
| -page load with `objectName` in url - calls `start` -> `logObjectNameFromUrlIfAvailable` -> `logNow` | |
| -button click - calls `logNow` | |
| * @todo (possibly): | |
| -options to sort log by different columns | |
| -an easy export to spreadsheet function | |
| -a button to select and copy coordinates in one touch | |
| -option to send locations to a central server, so multiple people/phones can track the same item | |
| */ | |
| function start(){ | |
| checkSupport(); | |
| logObjectNameFromUrlIfAvailable(); | |
| displayPastLog(); | |
| } | |
| function checkSupport() { | |
| var message=''; | |
| if(!navigator.geolocation){ | |
| message+='Your browser does not support geolocation. Try Chrome. '; | |
| } | |
| if(!window.localStorage){ | |
| message+='Your browser does not support localStorage. Try Chrome.'; | |
| } | |
| if(message){ | |
| document.getElementById('notification').innerHTML=message; | |
| } | |
| } | |
| function logObjectNameFromUrlIfAvailable(){ | |
| var urlMatchObject=location.search.match(/objectName=([^=&]+)/), | |
| objectNameFromUrl=null; | |
| if(urlMatchObject){ | |
| objectNameFromUrl=urlMatchObject[1]; | |
| objectNameFromUrl=decodeURIComponent(objectNameFromUrl); | |
| logNow(objectNameFromUrl); | |
| //This prevents page refreshes accidentally saving new entries. | |
| history.pushState({},'Clear name from url.', location.pathname); | |
| } | |
| } | |
| function logNow(objectNameFromUrl){ | |
| var objectNameFromForm=document.getElementById('objectName').value, | |
| objectNameToLog =objectNameFromUrl||objectNameFromForm, | |
| time =( new Date() ).toISOString(), | |
| locationOptions ={enableHighAccuracy:true, maximumAge:10*1000, timeout:5*1000};//times are milliseconds. | |
| if(!objectNameToLog){ return; } | |
| function onLocateSuccess(cPObject){ | |
| var keyToStore ='TouchObjectTracker|'+time, | |
| valueToStore=objectNameToLog+'|'+cPObject.coords.latitude+','+cPObject.coords.longitude+'|'+cPObject.coords.accuracy; | |
| localStorage.setItem(keyToStore,valueToStore); | |
| displayPastLog(); | |
| } | |
| function onLocateError(error){ | |
| var message=''; | |
| switch(error.code) { | |
| case error.PERMISSION_DENIED: | |
| message = "User denied the request for Geolocation." | |
| break; | |
| case error.POSITION_UNAVAILABLE: | |
| message = "Location information is unavailable." | |
| break; | |
| case error.TIMEOUT: | |
| message = "The request to get user location timed out." | |
| break; | |
| case error.UNKNOWN_ERROR: | |
| message = "An unknown error occurred." | |
| break; | |
| } | |
| document.getElementById('notification').innerHTML=time+' '+message; | |
| } | |
| //Success/Error actions will be called when the browser responds to the request for location. | |
| navigator.geolocation.getCurrentPosition( | |
| onLocateSuccess, | |
| onLocateError, | |
| locationOptions | |
| ); | |
| } | |
| function displayPastLog(){ | |
| var logEntries=document.getElementById('logEntries'); | |
| logEntries.innerHTML=''; | |
| for(var key in localStorage){ | |
| let keyHasAppPrefix=key.match(/^TouchObjectTracker\|(.+)/); | |
| if( !keyHasAppPrefix ){ continue; }//skip any keys not related to this app. | |
| let time=key.replace('TouchObjectTracker|',''), | |
| storedValue =localStorage[key], | |
| valuePieces =storedValue.split('|'), | |
| objectName =valuePieces[0], | |
| coordinates =valuePieces[1], | |
| accuracy =valuePieces[2], | |
| coordinatesHTMLString='', | |
| rowHTMLString=''; | |
| coordinatesHTMLString ='<input type="text" value="'+coordinates+'">'; | |
| coordinatesHTMLString+='<a href="http://www.google.com/maps/place/'+coordinates+'">View Map</a>'; | |
| rowHTMLString='<tr><td>'+time+'</td><td>'+objectName+'</td><td>'+coordinatesHTMLString+'</td><td>'+accuracy+'</td></tr>'; | |
| logEntries.innerHTML=logEntries.innerHTML+rowHTMLString; | |
| }; | |
| } | |
| </script> | |
| <style type="text/css"> | |
| th, td{ | |
| padding:0.5em 1em; | |
| border: 1px solid lightgray; | |
| } | |
| </style> | |
| <title>Touch Object Tracker</title> | |
| </head> | |
| <body> | |
| <div id="notification"></div> | |
| <h1>Current</h1> | |
| <div> | |
| <input type="text" | |
| id="objectName" | |
| name="objectName" | |
| placeholder="Object To Track" | |
| required> | |
| <button type="button" | |
| onclick="logNow()"> | |
| Log Location Now | |
| </button> | |
| </div> | |
| <h1>Past</h1> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Time</th> | |
| <th>Object</th> | |
| <th>Location</th> | |
| <th>Accuracy (meters)</th> | |
| </tr> | |
| </thead> | |
| <tbody id="logEntries"> | |
| <!-- This is where log entries show. --> | |
| </tbody> | |
| </table> | |
| <script type="text/javascript"> | |
| //Behavior is defined first, but invoked last, after the whole page has loaded. | |
| start(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment