Visual Studio web projects: HTML5 Geolocation custom class
Introduction
This article will provide a JavaScript class, no external dependencies like Google API or Bing API to prompt for the location of a user visiting a web page using HTML5 Geolocation API specifications to assist with things like a job posting site to target visitors to the site for jobs in their current location, movie theaters promoting movies nearby or perhaps a travel agency providing better information dependent on current location and season of the year are a few reasons for implementing geo location. The JavaScript class presented is self-contained, easy to use in any web application and is better than simply placing code into a backend JavaScript file specific to one application.
Note: This class can be used in any web project created with Microsoft Visual Studio which presents with a HTML user interface.
Note that working with Geolocation can be done in C# mobile applications using windows.devices.geolocation class but this article focuses on working with Geolocation so working with C# will not be covered. If interested in C# check out the code sample in the solution along with reading the following on sensors.
How does Geolocation work
"Technically speaking, a PC or a mobile device has several ways to find out its own location (hopefully, in the same place as the user).
- GPS is the most accurate way to determine positioning, but it’s less energy efficient than other options and sometimes requires a lengthy startup time.
- A-GPS (assistive GPS) uses triangulation between mobile phone towers and public masts to determine location. Although not as precise as GPS, A-GPS is sufficient for many scenarios.
- Mobile devices that support Wi-Fi access points can use hotspots to determine the user’s location.
- Stationary computers without wireless devices can obtain rough location information using known IP address ranges." [www.sitepoint.com]
Privacy
"When it comes to sharing the physical location of users, privacy is a serious concern. According to the Geolocation API, “user agents must not send location information to Web sites without the express permission of the user.” In other words, a user must always opt in to share location information with a Web site." *[www.sitepoint.com] *In the code presented callbacks are presented to capture a user decision to allow or block acquiring permissions to get their location.
Implementing Geolocation
Before continuing knowing which browsers are capable of using geolocation check out the following table and while reviewing the information presented be sure to read “known issues”.
Create a JavaScript function which calls navigator.geolocation.getCurrentPosition where the first callback is for successfully obtaining permission to get location information and the second callback when there is a failure or when the user decides to block their location. Besides a user blocking their location there could be a timeout for various reasons, failure to get data from the device which may happen when there is a weak WIFI signal, location service off or low battery are a few reasons for having a callback for failures which is optional but highly recommended for completeness as this can be remembered in a database table, same as remembering success.
Typical example from the web
navigator.geolocation.getCurrentPosition(locationSuccess, locationFail);
function locationSuccess(position) {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
}
function locationFail() {
alert("Oops, could not find you.");
}
In the above code block a developer may simply write this into a web page or an included JavaScript file then realize that as they test there is more to obtaining locations from users then the code presented above. Trap number 1, the above code is implemented and the tester (you or someone else) displays the page in a web browser, a prompt appears to allow or block the current location. Select either one then refresh the page, you will not be prompted again, try this out here. This means you can test the opposite choice e.g. allow was selected and now block needs to be tested.
The solution (on a desktop computer) to testing the opposite choice is to remove the choice from the cache of the browser. Example, using Chrome browser, open a new tab, in the address bar paste in chrome://settings/content/location were the page shows allowed and blocked sites. Find the site and click the trashcan to remove the site then retry the code which will now prompt again for your location. Also on the same page there is a slider titled ask before accessing (recommended), if not turned on then this results in permissions blocked. This is a catch 22 but as stated above “user agents must not send location information to Web sites without the express permission of the user. So some users may simple not get remembers in regards to location but when writing this to the database or log a query can be run to determine who’s coordinates were not read and from the error code the reason why, permission denied, error on a device or timeout. This is also blocked or not in a mobile device where if “Ask Websites Not to Track Me” is set. In the screenshot below the user allows tracking.
The solution for a mobile device is to go into settings, for an iPhone, open settings, search for “location” and then select either “reset location and privacy” or go directly to Location which also shows up. Another option is to reset location data in a specific browser e.g. Safari, under settings search for Safari, find “Clear history and Website data” which is extreme so working with “reset location and privacy” in Location settings is a better idea.
JavaScript class for Geolocation
Responsibilities
- Prompt for current location.
- Start a watch which polls the location periodically during the visit to a web page.
- Stop the watch.
- Success and failure callbacks for working with location services.
- Success and failure codes suitable for storing within a database or log.
- Stub Methods for writing to a database or log.
Storing Geolocation information
Geolocation provides longitude and latitude coordinates along with status/error code. These can be written to a database table with fields for longitude and latitude coordinates and status/error code in SQL-Server using ASP.NET/ASP.NET Core coupled with a web service using Web API. For example, you could store the codes which are numeric in a database reference table with a textual description or have a container that has code and English (or your native language) description so that in a failure callback you can get the description to store in a table record. Which way a developer goes is dependent on recourses and business requirements. In the class presented codes and their descriptions are mocked up and information is written to the test page where in the wild this information would be written to a database or log.
Using the class
Add the class to your project in a folder for your JavaScript files, include this JavaScript file in you index page. In document ready call the execute method.
$(document).ready(function () {
$geoLocation.Execute();
});
In the Execute method a request is made to ask permission to allow or block for the current location which uses a success and failure callbacks to get the current location or to handle block as a response and if there was a timeout or failure from the device (phone, tablet etc) to obtain location coordinates. The else has an alert, in the wild this can be eliminated or still remembered to a database or log file.
var execute = function () {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getCurrentLocation, handleLocationError);
this.response = 'Y';
this.responseText = responseCodes.get($geoLocation.response);
} else {
document.getElementById("watchLocation").innerHTML = ("<strong>This browser does not support geolocation</strong>");
}
return;
};
For better control over obtaining geolocation another parameter can be used (which is optional) to specify timeout, maximumAge and enableHighAccuracy. In the revised example these options are passed into the class in the constructor as they will be used in two separate methods.
$(document).ready(function () {
var positionOptions = {
timeout: Infinity,
maximumAge: 0,
enableHighAccuracy: true
};
$geoLocation.Init(positionOptions);
$geoLocation.Execute();
});
Then in the class constructor
var $geoLocation = $geoLocation || {};
$geoLocation = function () {
var _positionOptions;
The parameters are then passed to getCurrentPosition.
var execute = function () {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getCurrentLocation, handleLocationError, $geoLocation._positionOptions);
this.response = 'Y';
this.responseText = responseCodes.get($geoLocation.response);
} else {
document.getElementById("watchLocation").innerHTML = ("<strong>This browser does not support geolocation</strong>");
}
return;
};
When successful obtaining coordinates (user selected allow in the prompt for their location) getCurrentLocation sets latitude and longitude properties of this class for use in remembering coordinates to a database or log.
To get changes in a user’s location call which provides access to their current coordinates.
$geoLocation.stopWatch();
Caveat: when writing to a database or log, an identifier should be remembered also if the user is “known” to the application by a registered customer or a transaction identifier embedded in the href. This can assist with marketing for instance to send customers special email messages perhaps for special offers for their specific location as discussed in the introduction of this article.
Working with watches
This is implemented via Geolocation.watchPosition() which is only available for secure content (HTTPS).
The Geolocation method watchPosition() method is used to register a handler function that will be called automatically each time the position of the device changes. You can also, optionally, specify an error handling callback function. This method returns a watch ID value that then can be used to unregister the handler by passing it to the Geolocation.clearWatch() method.
The following code is responsible for starting a watch, stopping a watch along with handling obtaining coordinates and handling exceptions via callbacks
// get geo location and start watch
var getLocation = function () {
// Check whether browser supports Geolocation API or not
if (navigator.geolocation) // Supported
{
// Set the watchID
watchIDmain = navigator.geolocation.watchPosition(
getPositionForWatch,
catchErrorForWatch,
$geoLocation._positionOptions
);
}
else // Not supported - either alert the user or simply accept the fact.
{
document.getElementById("watchLocation").innerHTML ="This browser does not support HTML5 Geolocation.";
}
}
/*
* cancel watchPosition call
*/
var stopWatch = function () {
if (watchIDmain !== undefined) {
navigator.geolocation.clearWatch(watchIDmain);
watchIDmain = null;
document.getElementById("watchLocation").innerHTML = '';
}
};
// callback for watch success when user is sharing their location
var getPositionForWatch = function (position) {
var today = new Date();
document.getElementById("watchLocation").innerHTML = "<strong>Latitude:</strong> " +
position.coords.latitude.toPrecision(6) + "<br>" + "<strong>Longitude:</strong> " +
position.coords.longitude.toPrecision(6) + "<br><strong>Tiggered at</strong> " + " " +
today.toLocaleTimeString();
}
// callback for errors when obtaining permission to allow or block location for when watch is active
// this is the very basics, you may have some type of identifier pass in to the page like a transaction number
// that can be used to identify the person e.g. they are a login shopper with a customer number.
var catchErrorForWatch = function (error) {
switch (error.code) {
case error.TIMEOUT:
writeWatchExceptions("The request to get user location has aborted as it has taken too long.", error.code);
break;
case error.POSITION_UNAVAILABLE:
writeWatchExceptions("Location information is not available.", error.code);
break;
case error.PERMISSION_DENIED:
writeWatchExceptions("Permission to share location information has been denied!", error.code);
break;
default:
writeWatchExceptions("An unknown error occurred.", -1);
}
}
Demonstration page for using the geolocation class
Figure 1, accepted tracking location
Figure 2, user decided to not allow tracking their location
Implementing in a Visual Studio web project
- Add to your include/scripts folder jQuery, version is dependent on if you are currently using jQuery or not. If not currently using jQuery don’t simply add the current version but figure out if your clients can handle the current version, if not research is needed to determine which version to use.
- Add geolocation.js to your include/scripts folder.
- Open your index page.
- Navigate to the head section of the page.
- Create an empty line after your jQuery include statement.
- From Solution Explorer single click on geolocation.js, while holding the mouse down drag geolocation.js to the empty line and release.
- In your document ready event add the following two lines (along with as shown in the sample code, options which are optional but should be configured as shown).
- $geoLocation.Init(positionOptions);
- $geoLocation.Execute();
- In geolocation.js writeResults method, add code to write to a database or log file to record the current user’s current location. There should be an identifier that represents the user e.g. customer id, transaction number that associates back to the person login or perhaps this is someone who has not registered and is anonymous which means your database table or log needs to consider this.
- In geolocation.js writeWatchExceptions method is where your application records failures which are presented in the errorCode in a similar fashion as with the last operation for successful operation where the user allows tracking their current location.
Summary
In this article a class has been presented to collect geolocation data, configure optional parameters, how to test and stub methods for writing to a database or log. There are various permutations of the code which can be done easily rather than how many examples are done directly in either a web page or in a JavaScript file that does other operations also while the class presented is separated from other options.
See also
TechNet C#: Getting longitude, latitude using geolocation API.
Source code
https://github.com/karenpayneoregon/geolocation