0

I'm trying to code some JS that calculates the distance a user travels using the Haversine formula.

Now Haversine formula takes in the starting and current coordinates and gives out the separation between those two coordinates. That is however just the DISPLACEMENT and NOT the distance a user might have probably travelled to reach the final point.

I need someone to help me on the code I did below (that gives displacement) and suggest what should I do more so that it calculates distance.

//Geolocation
var startPos;
var watchId;
//Start Tracking Position
function startTracking() {
    if(navigator.geolocation) {
        if (document.getElementById('startBtn').innerHTML === " Stop Tracking?")
        {
            stopTracking();
            stopClock();
            return;
        }
        document.getElementById('startBtn').innerHTML = " Stop Tracking?";
        //Get Position
        navigator.geolocation.getCurrentPosition(showPosition, showError);
        //Watch Position
        watchId = navigator.geolocation.watchPosition(showPositionUpdate, showError);
    }
    else {
        alert('Geolocation is not supported by your browser');
    }
}
//Show Start Position
function showPosition(position) {
    startPos = position;
    document.getElementById('startLat').innerHTML = startPos.coords.latitude;
    document.getElementById('startLon').innerHTML = startPos.coords.longitude;
}
//Updated Position
function showPositionUpdate(position) {
    document.getElementById('currentLat').innerHTML = position.coords.latitude;
    document.getElementById('currentLon').innerHTML = position.coords.longitude;
    var distance = calculateDistance(startPos.coords.latitude, startPos.coords.longitude, position.coords.latitude, position.coords.longitude);
    if (distance < 1) {
        document.getElementById('distance').innerHTML = (Math.round(distance * 1000)) + "m";
    } else {
        document.getElementById('distance').innerHTML = (Math.round(distance * 100) / 100) + "Km";
    }
}
//Error Handler
function showError(error) {
    switch(error.code) {
        case error.PERMISSION_DENIED:
            alert('User denied the request for Geolocation');
            break;
        case error.POSITION_UNAVAILABLE:
            alert('Location Not Available');
            break;
        case error.TIMEOUT:
            alert('The request has timed-out');
            break;
        case error.UNKNOWN_ERROR:
            alert('There was an unknown error');
            break;
    }
}
//Calculate the distance between start and updated, Haversine Formula
function calculateDistance(lat1, lon1, lat2, lon2) {
    var R = 6371; // km  
    var dLat = (lat2-lat1).toRad();  
    var dLon = (lon2-lon1).toRad();   
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +  
            Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *   
            Math.sin(dLon/2) * Math.sin(dLon/2);   
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));   
    var d = R * c;
    return d;
}
Number.prototype.toRad = function() {
    return this * Math.PI / 180;
}
//Stop Tracking
function stopTracking() {
    navigator.geolocation.clearWatch(watchId);
    alert('Tracking has stopped');
    document.getElementById('startBtn').innerHTML = "Start Tracking?";
}
Shubham Mehta
  • 89
  • 2
  • 14
  • What? Haversine calculates the length of a line on the surface of a sphere (e.g. the earth), which gives you the distance from point A to point B. If you're talking about routing, using roads and whatnot, that's an _entirely_ different problem and you're probably best off using a map routing API (google, yahoo, OSM, etc). –  Jul 01 '15 at 09:56
  • I thought about it but that'd be adding a real heavy overhead I believe. I'm someone from a developing nation with not so strong or reliable cellular networks in all parts. Hence I wanted to do it as lightly as possible. – Shubham Mehta Jul 01 '15 at 09:58
  • I don't see what's wrong with your code though. You're subscribing to location info which will give you a stream of co-ordinates, right? Save the last position and calculate the position between the last one and the new one. So total distance = `a->b + b->c + c->d`, not `a->d` –  Jul 01 '15 at 10:00

1 Answers1

0

Just record the displacement every x seconds or so, and sum the displacements. You will have a fairly good approximation. Or just record the points at different times first, and then do the calculation at the end.

var checkpoints = [],
    interval = null;

function record() {
  checkpoints.push( /* current position */ )
}

function distance(a, b) {
  return /* your distance calculation */
}

function start() {
  checkpoints = [];
  interval = setInterval(record, 1000); // record current pos every second
}

function end() {
  clearInterval(interval);

  var distanceTravelled = checkpoints.reduce(function(x, current, i, checkpoints){
    return x + distance(current, checkpoints[i-1]);
  }, 0);

  // do something nice with the distance
}

UPDATE

I just now realized you use watch with a callback. You can use following approach then,

var lastPoint = null,
    travelled = 0;

function update(point) {
  if (lastPoint != null)
    travelled += calculateDistance(lastPoint.long, lastPoint.lat, point.long, point.lat);      

  lastPoint = point;
}

UPDATE 2 Working solution: http://jsfiddle.net/ymz3a5pb/

lordvlad
  • 5,200
  • 1
  • 24
  • 44
  • I did this, inspired by your answer primarily. It has some referencing errors, alas. Can you please look into it? https://jsfiddle.net/sa4m0u1z/ – Shubham Mehta Jul 01 '15 at 11:26
  • what referencing errors? maybe you can post the error messages? Also, which method did you choose? – lordvlad Jul 01 '15 at 11:28
  • https://drive.google.com/file/d/0BwUagjky4-pbdjBuQjZDZU9WXzA/view?usp=sharing errors like these. My HTML entity invokes the startTracking function. So I didnt choose a method. I just clicked on "Start Tracking" on the page and that invokes startTracking function. Sorry I'm new to JS. – Shubham Mehta Jul 01 '15 at 11:34
  • yes thanks! That works perfectly well. you are initializing startPos to currentPos. Yes I get it. I did something similar last day and guess made some syntactical error (comes being new to a language). Thanks a lot! :) – Shubham Mehta Jul 01 '15 at 16:09
  • you could actually repost the fiddle here so that perhaps I could mark it as the accepted solution and have this question closed for future reference. I mean its only my second question, this one, on the forums but I guess that'd be the good practise. – Shubham Mehta Jul 01 '15 at 16:18