Edit on
<body>
    <div class="panel-overlay"></div>
    <!-- Left panel with reveal effect -->
    <div class="panel panel-left panel-reveal">
      <div class="content-block">
        <div class="content-block-title">Fences:</div>
        <div class="list-block">
          <ul id="fence-btns">
            <li><a href="#" class="list-button item-link fence-btn" data-center="[43.515653, -80.513976]" data-points="[[43.515724, -80.518633], [43.517735, -80.517329], [43.517451, -80.516406], [43.517416, -80.516235], [43.517385, -80.515918], [43.517397, -80.515468], [43.517470, -80.515001], [43.517470, -80.514883], [43.517451, -80.514722], [43.517404, -80.514582], [43.517397, -80.514523], [43.517432, -80.514379], [43.517451, -80.514325], [43.517517, -80.514277], [43.517774, -80.513697], [43.517894, -80.513397], [43.518128, -80.512678], [43.518023, -80.512603], [43.516272, -80.510586], [43.515440, -80.509631], [43.515397, -80.509701], [43.515292, -80.510114], [43.514848, -80.511305], [43.514603, -80.512115], [43.514506, -80.512201], [43.514685, -80.512356], [43.514459, -80.512624], [43.514277, -80.512914], [43.514245, -80.512995], [43.514098, -80.513177], [43.514090, -80.513247], [43.514113, -80.513279], [43.513331, -80.514877], [43.513277, -80.514915], [43.513191, -80.514899], [43.513090, -80.515113], [43.513059, -80.515221], [43.513071, -80.515403], [43.512981, -80.515602]]">A-D</a></li>
            <li><a href="#" class="list-button item-link fence-btn" data-center="[43.451112, -80.498222]" data-points="[[43.450999, -80.499600], [43.451867, -80.498720], [43.451314, -80.497003], [43.450298, -80.497534]]">Hub</a></li>
            <li><a href="#" class="list-button item-link fence-btn" data-center="[43.657372, -79.603415]" data-points="[[43.658003, -79.603554], [43.657576, -79.602964], [43.657289, -79.602460], [43.656703, -79.603136], [43.657483, -79.604155]]">Matheson</a></li>
            <li><a href="#" class="list-button item-link fence-btn" data-center="[43.639933, -79.608959]" data-points="[[43.644631, -79.610453], [43.644290, -79.609884], [43.644189, -79.609766], [43.644034, -79.609605], [43.643886, -79.609498], [43.643731, -79.609390], [43.643374, -79.609219], [43.643211, -79.609101], [43.643055, -79.608951], [43.642838, -79.608639], [43.642659, -79.608296], [43.642504, -79.607824], [43.642434, -79.607416], [43.642395, -79.606998], [43.642333, -79.606622], [43.642201, -79.606279], [43.642046, -79.606032], [43.641875, -79.605861], [43.641650, -79.605721], [43.641394, -79.605668], [43.641208, -79.605689], [43.640998, -79.605764], [43.640796, -79.605914], [43.640641, -79.606075], [43.640516, -79.606279], [43.640408, -79.606547], [43.640338, -79.606891], [43.640097, -79.606655], [43.639235, -79.605206], [43.638987, -79.605056], [43.637473, -79.606966], [43.637814, -79.607320], [43.637900, -79.607491], [43.637962, -79.607695], [43.637970, -79.607899], [43.637939, -79.608092], [43.637884, -79.608253], [43.637566, -79.608704], [43.638933, -79.610935], [43.641044, -79.614036], [43.641386, -79.614176]]">Tahoe</a></li>
            <li><a href="#" class="list-button item-link fence-btn" data-center="[43.642562, -79.387060]" data-points="[[43.642690, -79.393687], [43.645206, -79.382572], [43.641076, -79.380898], [43.640827, -79.381928], [43.640672, -79.383430], [43.639088, -79.392314]]">CN Tower</a></li>
            <li>
              <a href="#" class="list-button item-link fence-btn">Custom:</a>
              <label class="fenceFieldName">Center:</label>
              <input type="text" class="fenceFieldValue" id="custom-center" value="[38.871017, -77.055893]"><br>
              <label class="fenceFieldName">Points:</label>
              <textarea class="fenceFieldValue" id="custom-points">[[38.872976, -77.054662], [38.870621, -77.053181], [38.868816, -77.055563], [38.870053, -77.058513], [38.872600, -77.057955]]</textarea>
              <br>
            </li>
          </ul>
        </div>
      </div>
    </div>

    <!-- Right panel with cover effect -->
    <div class="panel panel-right panel-cover">
      <div class="content-block">
        <div id="log"></div>
      </div>
    </div>

    <!-- Views -->
    <div class="views">
      <div class="view view-main">
        <div class="navbar">
          <div class="navbar-inner">
            <div class="center sliding">Geofence</div>
          </div>
        </div>

        <div class="pages navbar-through toolbar-through">
          <div data-page="index" class="page">
            <div class="page-content">
              <div id="map"></div>

              <div class="content-block-title"></div>

              <div class="content-block">
                <div class="content-block">
                  <div class="buttons-row">
                    <a href="#" class="button" id="watch">Start</a>
                    <a href="#" class="button" id="clear">Clear</a>
                    <a href="#" class="button open-popup" data-popup=".popup" id="export">Export</a>
                  </div>

                  <table class="stats">
                    <tr>
                      <td class="field">Timestamp:</td>
                      <td class="value" colspan="4"><span id="stat_timestamp"></span></td>
                    </tr>
                    <tr>
                      <td class="field">Latitude:</td>
                      <td class="value"><span id="stat_latitude"></span></td>
                      <td class="gutter"></td>
                      <td class="field">Accuracy:</td>
                      <td class="value"><span id="stat_accuracy"></span></td>
                    </tr>
                    <tr>
                      <td class="field">Longitude:</td>
                      <td class="value"><span id="stat_longitude"></span></td>
                      <td class="gutter"></td>
                      <td class="field">Altitude:</td>
                      <td class="value"><span id="stat_altitude"></span></td>
                    </tr>
                    <tr>
                      <td class="field">Speed:</td>
                      <td class="value"><span id="stat_speed"></span></td>
                      <td class="gutter"></td>
                      <td class="field">Heading:</td>
                      <td class="value"><span id="stat_heading"></span></td>
                    </tr>
                    <tr>
                      <td class="field">Distance:</td>
                      <td class="value"><span id="stat_distance"></span></td>
                      <td class="gutter"></td>
                      <td class="field">Time:</td>
                      <td class="value"><span id="stat_elapsed"></span></td>
                    </tr>
                    <tr>
                      <td class="field">Zoom:</td>
                      <td class="value"><span id="stat_zoom"></span></td>
                      <td class="gutter"></td>
                      <td class="field">Geofence:</td>
                      <td class="value"><span id="stat_geofence"></span></td>
                    </tr>
                    <tr>
                      <td class="field">Screen:</td>
                      <td class="value"><span id="stat_screen"></span></td>
                      <td class="gutter"></td>
                      <td class="field"></td>
                      <td class="value"></td>
                    </tr>
                    <tr>
                      <td class="field"></td>
                      <td class="value"></td>
                      <td class="gutter"></td>
                      <td class="field"></td>
                      <td class="value"></td>
                    </tr>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- Bottom Toolbar 
        <div class="toolbar">
          <div class="toolbar-inner">
            <a href="#" class="open-panel">Options</a>
            <a href="#" class="open-panel" data-panel="right">Debug</a>
        </div>
-->
        </div>
      </div>
    </div>

    <!-- Popup -->
    <div class="popup">
      <div class="view navbar-fixed">
        <div class="page">
          <div class="navbar">
            <div class="navbar-inner">
              <div class="center">Export CSV</div>
              <div class="right"><a href="#" class="link close-popup">Done</a></div>
            </div>
          </div>
          <div class="page-content">
            <div class="content-block">
              <a href="#" class="button active" id="email">Email</a><br>
              <input type="email" class="exportValue" id="email-to" value="" placeholder="Recipient(s) e.g., user1@domain.com,user2@domain.com"><br>
              <input type="text" class="exportValue" id="email-subject" value="Geofence Export" placeholder="Subject"><br>
              <br>
              <div id="export-csv">
                <!-- dyanmic content -->
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <script src="local:///chrome/webworks.js"></script>
    <script>

    </script>
label {
  font-weight: bold;
}

.exportValue {
  width: 99%;
  height: 29px;
}

#map {
  width: 100%;
  height: 75%;
}

.panel.panel-right.panel-cover {
  font-size: 10pt;
  line-height: 16pt !important;
  opacity: 0.75;
}

.content-block-title {
  margin: 15px 15px -25px;
}

.stats {
  border: 1px solid #CCC;
  width: 100%;
}

.field {
  text-align: right;
  font-weight: bold;
  white-space: nowrap;
}

.value {
  width: 40%;
  background-color: #FFF;
}

.gutter {
  width: 5%;
}

.fenceFieldName {
  font-size: 10pt;
}

.fenceFieldValue {
  width: 100%;
  border: 1px solid #CCC !important;
  border-radius: 5px !important;
  font-size: 9pt !important;
}
var app = {
    history: [], // auto
    history2: [], // manual

    geodataID: 'geofence-data', // localStorage
    watchID: null, // watchPosition

    pt: [], // center
    pts: [], // polygon

    map: null,

    layer1: null,
    layer2: null,
    marker: null,
    polygon: null,
    polyline: null,
    //rectangle: null,

    lastStatus: '',
    startTime: 0,
    endTime: 0,

    dist: 0.0, // total distance travelled

    accuracyThreshold: 60, // meters

    serverAlert: false,
    serverUrl: 'http://ings.ca/post.php'
};

app.init = function () {
    console.info('app.init:');
    console.log('Leaflet ' + L.version);

    FlyJSONP.init({
        debug: false
    });

    var txt = 'DateTime,Latitude,Longitude,Accuracy,Heading,Speed,Distance,Altitude,Geofence' + "\n";

    localStorage.setItem(app.geodataID, txt);

    // Mississauga (Buckhorn and Tahoe) Campus
    app.pt = [43.639933, -79.608959];
    app.pts = [
        [43.644631, -79.610453],
        [43.644290, -79.609884],
        [43.644189, -79.609766],
        [43.644034, -79.609605],
        [43.643886, -79.609498],
        [43.643731, -79.609390],
        [43.643374, -79.609219],
        [43.643211, -79.609101],
        [43.643055, -79.608951],
        [43.642838, -79.608639],
        [43.642659, -79.608296],
        [43.642504, -79.607824],
        [43.642434, -79.607416],
        [43.642395, -79.606998],
        [43.642333, -79.606622],
        [43.642201, -79.606279],
        [43.642046, -79.606032],
        [43.641875, -79.605861],
        [43.641650, -79.605721],
        [43.641394, -79.605668],
        [43.641208, -79.605689],
        [43.640998, -79.605764],
        [43.640796, -79.605914],
        [43.640641, -79.606075],
        [43.640516, -79.606279],
        [43.640408, -79.606547],
        [43.640338, -79.606891],
        [43.640097, -79.606655],
        [43.639235, -79.605206],
        [43.638987, -79.605056],
        [43.637473, -79.606966],
        [43.637814, -79.607320],
        [43.637900, -79.607491],
        [43.637962, -79.607695],
        [43.637970, -79.607899],
        [43.637939, -79.608092],
        [43.637884, -79.608253],
        [43.637566, -79.608704],
        [43.638933, -79.610935],
        [43.641044, -79.614036],
        [43.641386, -79.614176]
    ];

    app.map = L.map('map').setView(app.pt, 15);

	/*
    L.tileLayer('http://{s}.tile.cloudmade.com/d4fc77ea4a63471cab2423e66626cbb6/997/256/{z}/{x}/{y}.png', {
        //attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery &copy; <a href="http://cloudmade.com">CloudMade</a>',
        maxZoom: 18
    }).addTo(app.map);
*/

    L.tileLayer('http://{s}.googleapis.com/vt?lyrs=m@174225136&src=apiv3&hl=en-US&x={x}&y={y}&z={z}&s=Galile&style=api%7Csmartmaps', {
        attribution: 'Map data &copy; 2014 Google',
        maxZoom: 22,
        subdomains: ['mt0', 'mt1']
    }).addTo(app.map);

    L.control.scale().addTo(app.map);

    app.updateZoom();

    app.map.on('zoomend', app.updateZoom);

    app.map.on('move', function () {
        crosshair.setLatLng(app.map.getCenter());
    });

    app.polygon = L.polygon(app.pts, {
        color: '#4A90E2',
        opacity: 0.4,
        fillOpacity: 0.2
    });

    // Draw a bounding box around polygon
    // app.rectangle = L.rectangle(app.polygon.getBounds(), {
    //     color: "#FF0000",
    //     dashArray: '5,5',
    //     fill: false,
    //     opacity: 0.4,
    //     weight: 2
    // });

    app.marker = L.marker(app.pt, {
        draggable: true
    });

    //app.layer1 = L.layerGroup([app.polygon, app.rectangle]);
    app.layer1 = L.layerGroup([app.polygon]);

    app.layer1.addLayer(app.marker);
    app.layer1.addTo(app.map);

    app.marker.bindPopup('<b>' + app.marker.getLatLng().lat.toFixed(6) + ', ' + app.marker.getLatLng().lng.toFixed(6) + '</b><br>');

    app.history2.push({lat: app.pt[0], lng: app.pt[1]});

    // Add listeners

    app.marker.on('dragend', function (ev) {
        var timestamp = new Date();
        var timestr = app.leftPad(timestamp.getHours(), 2) + ':' + app.leftPad(timestamp.getMinutes(), 2) + ':' + app.leftPad(timestamp.getSeconds(), 2);
        var coords = ev.target._latlng;

        app.handleMove(coords);
    });

    var touch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
    var evt = (touch) ? 'touchstart' : 'click';
    console.log('touch =', touch, 'evt =', evt);

    document.getElementById('fence-btns').addEventListener(evt, app.updateFence);
    document.getElementById('watch').addEventListener(evt, app.toggleWatch);
    document.getElementById('clear').addEventListener(evt, app.clearHistory);
    document.getElementById('export').addEventListener(evt, app.exportCSV);
    document.getElementById('email').addEventListener(evt, app.emailCSV);

    document.getElementById('log').addEventListener('click', function (ev) {
        if (ev.target.dataset['lat'] && ev.target.dataset['lng']) {
            app.map.panTo([ev.target.dataset['lat'], ev.target.dataset['lng']]);
        }
    });
};

app.updateFence = function (ev) {
    console.info('app.updateFence:');

    if (ev.target.tagName != 'A') {
        return;
    }

    var pt, pts;
    if (ev.target.dataset['center'] && ev.target.dataset['points']) {
        pt = JSON.parse(ev.target.dataset['center']);
        pts = JSON.parse(ev.target.dataset['points']);
    }
    else {
        pt = JSON.parse(document.getElementById('custom-center').value);
        pts = JSON.parse(document.getElementById('custom-points').value);
    }

    app.polygon.setLatLngs(pts);
    //app.rectangle.setLatLngs(app.polygon.getBounds()); // BUG: rectangle disappears!
    app.marker.setLatLng(pt);
    app.map.panTo(pt);

    app.map.fitBounds(app.polygon.getBounds());
/*
    if (app.layer2) {
        app.layer2.clearLayers();
    }
*/
    app.lastStatus = '';

    app.history2 = [];
    app.history2.push({lat: pt[0], lng: pt[1]});
};

app.clearHistory = function () {
    console.info('app.clearHistory:');

    app.history = [];
    app.history2 = [];
    app.lastStatus = '';

    document.getElementById('stat_timestamp').innerHTML = '';
    document.getElementById('stat_latitude').innerHTML = '';
    document.getElementById('stat_longitude').innerHTML = '';
    document.getElementById('stat_speed').innerHTML = '';
    document.getElementById('stat_distance').innerHTML = '';
    document.getElementById('stat_altitude').innerHTML = '';
    document.getElementById('stat_heading').innerHTML = '';
    document.getElementById('stat_accuracy').innerHTML = '';
    document.getElementById('stat_geofence').innerHTML = '';

    document.getElementById('log').innerHTML = '';

    //localStorage.setItem(app.geodataID, '');

    if (app.layer2) {
        app.layer2.clearLayers();
    }
};

app.emailCSV = function () {
    var email = document.getElementById('email-to').value,
        emailList = email.split(','),
        subject = document.getElementById('email-subject').value,
        body = document.getElementById('export-csv').innerHTML;

    console.log(email, emailList, subject, body);

    if (window.blackberry) {
        blackberry.invoke.card.invokeEmailComposer({
            subject: subject,
            body: body,
            to: emailList
            //cc: ["c@c.ca, d@d.com"],
            //attachment: ["/path/to/an/attachment.txt", "path/to/another/attachment.txt"]
        }, function (done) {
            console.log(done);
        }, function (cancel) {
            console.log(cancel);
        }, function (invokeError) {
            console.log(invokeError);
        });
    }
    else {
        window.location = "mailto:" + email + "?subject=" + encodeURIComponent(subject) + "&body=" + encodeURIComponent(body);
    }
};

app.exportCSV = function () {
    console.info('app.exportCSV:');
    document.getElementById('export-csv').innerHTML = localStorage.getItem(app.geodataID);
};

app.sendAlert = function (str) {
    if (app.serverAlert !== true) {
        return;
    }

    console.info('app.sendAlert:', str);

    // Use Ajax if this is a WebWorks app
    if (window.blackberry) {
        console.log('Using Ajax...');
        var xhr = new XMLHttpRequest();

        xhr.onload = function () {
            if (xhr.readyState === xhr.DONE) {
                if (xhr.status === 200 && xhr.response) {
                    console.log('Server response:', xhr.response);
                }
            }
        };

        xhr.onerror = function (err) {
            console.warn(err.target.status);
        };

        xhr.open('POST', app.serverUrl, true);
        //xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xhr.send('?data=' + str);
    }
    // Use JSONP to get around cross-site scripting
    else {
        console.log('Using JSONP...');
        FlyJSONP.post({
            url: app.serverUrl,
            parameters: {
                data: str
            },
            success: function (data) {
                console.log('Server response:', data);
            }
        });
    }
};

app.checkGeoFence = function (lat, lng, timestamp) {
    console.info('app.checkGeoFence:');

    var res;

    // use "contains" method -- not accurate -- returns bounding box of polygon
    //res = app.polygon.getBounds().contains(L.latLng(lat, lng));

    // use "leafletPip" library -- accurate
    var gjLayer = L.geoJson(app.polygon.toGeoJSON());
    res = leafletPip.pointInLayer([lng, lat], gjLayer);

    var status = 'inside';
    var statusColor = 'green';

    if (res.length === 0 || res === false) {
        status = 'outside';
        statusColor = 'red';
    }

    document.getElementById('stat_geofence').innerHTML = '<span style="color: ' + statusColor + '">' + status + '</span>';

    if (status !== app.lastStatus) {

        // Send alert text
        var jsonStr = '{';
        jsonStr += 'id:' + 'demo' + ',';
        jsonStr += 'timestamp:' + timestamp.getTime() + ',';
        jsonStr += 'status:' + status + ',';
        jsonStr += 'latitude:' + lat + ',';
        jsonStr += 'longitude:' + lng + '';
        jsonStr += '}';

        app.sendAlert(jsonStr);
    }

    console.log(status);
    return status;
};

app.handleMove = function (coords) {
    console.info('app.handleMove:');

    var timestamp = new Date();
    var timestr = app.leftPad(timestamp.getHours(), 2) + ':' + app.leftPad(timestamp.getMinutes(), 2) + ':' + app.leftPad(timestamp.getSeconds(), 2);
    var ts = timestamp.getFullYear() + '/' + app.leftPad(timestamp.getMonth() + 1, 2) + '/' + app.leftPad(timestamp.getDate(), 2) + ' ' + app.leftPad(timestamp.getHours(), 2) + ':' + app.leftPad(timestamp.getMinutes(), 2) + ':' + app.leftPad(timestamp.getSeconds(), 2);

    document.getElementById('stat_timestamp').innerHTML = ts;
    document.getElementById('stat_latitude').innerHTML = coords.lat.toFixed(6);
    document.getElementById('stat_longitude').innerHTML = coords.lng.toFixed(6);

    var status = app.checkGeoFence(coords.lat, coords.lng, timestamp);
    var statusColor = (status == 'inside') ? 'green' : 'red';

    app.lastStatus = status;

    if (app.history2.length > 0) {
        var d = app.calculateDistance(app.history2[app.history2.length - 1].lat, app.history2[app.history2.length - 1].lng, coords.lat, coords.lng);
        app.dist += parseFloat(d);
        document.getElementById('stat_distance').innerHTML = app.dist.toFixed(2) + ' km';
    }

    if (app.history2.length === 1) {
        var lastItem = app.history2[app.history2.length - 1];
        var latlngs = [L.latLng(lastItem.lat, lastItem.lng), L.latLng(coords.lat, coords.lng)];

        app.polyline = L.polyline(latlngs, {
            color: '#0000FF',
            opacity: 0.8
        });

        app.layer2 = L.layerGroup([app.polyline]);
        app.layer2.addTo(app.map);
    }
    else if (app.history2.length > 1) {
        app.polyline.addLatLng(L.latLng(coords.lat, coords.lng), {
            color: '#0000FF',
            opacity: 0.8
        });

        app.layer2 = L.layerGroup([app.polyline]);
        app.layer2.addTo(app.map);
    }

    app.history2.push({
        lat: coords.lat,
        lng: coords.lng
    });

    document.getElementById('log').innerHTML += '<span data-lat="' + coords.lat + '" data-lng="' + coords.lng + '">' + timestr + ': <span style="color: ' + statusColor + '">[' + coords.lat.toFixed(6) + ', ' + coords.lng.toFixed(6) + ']</span></span><br>';

    app.marker.setPopupContent('<b>' + app.marker.getLatLng().lat.toFixed(6) + ', ' + app.marker.getLatLng().lng.toFixed(6) + '</b><br>');
};

app.handleWatch = function (position) {
    console.info('app.handleWatch:');

    var txt = '';
    var log = '';
    var timestamp = new Date();
    var timestr = app.leftPad(timestamp.getHours(), 2) + ':' + app.leftPad(timestamp.getMinutes(), 2) + ':' + app.leftPad(timestamp.getSeconds(), 2);

    var coords = position.coords;

    if (coords.accuracy > app.accuracyThreshold) {
        console.warn('Poor accuracy!', coords.accuracy);
        log += '<span data-lat="' + coords.latitude + '" data-lng="' + coords.longitude + '" style="color: red; text-decoration: line-through;">' + timestr + ': ' + coords.latitude.toFixed(6) + ', ' + coords.longitude.toFixed(6) + ' (' + coords.accuracy + ')' + '</span><br>';
        document.getElementById('log').innerHTML += log;
        return;
    }

    var status = app.checkGeoFence(coords.latitude, coords.longitude, timestamp);

    app.lastStatus = status;

    if (app.history.length === 1) {
        var lastItem = app.history[app.history.length - 1].coords;
        var latlngs = [L.latLng(lastItem.latitude, lastItem.longitude), L.latLng(coords.latitude, coords.longitude)];

        app.polyline = L.polyline(latlngs, {
            color: '#0000FF',
            opacity: 0.8
        });

        app.layer2 = L.layerGroup([app.polyline]);
        app.layer2.addTo(app.map);
    }
    else if (app.history.length > 1) {
        app.polyline.addLatLng(L.latLng(coords.latitude, coords.longitude), {
            color: '#0000FF',
            opacity: 0.8
        });

        app.layer2 = L.layerGroup([app.polyline]);
        app.layer2.addTo(app.map);
    }

    app.marker.setLatLng([coords.latitude, coords.longitude]);

    app.map.panTo([coords.latitude, coords.longitude]);

    if (app.history.length > 0) {
        var d = app.calculateDistance(app.history[app.history.length - 1].coords.latitude, app.history[app.history.length - 1].coords.longitude, coords.latitude, coords.longitude);
        app.dist += parseFloat(d);
    }

    var ts = timestamp.getFullYear() + '/' + app.leftPad(timestamp.getMonth() + 1, 2) + '/' + app.leftPad(timestamp.getDate(), 2) + ' ' + app.leftPad(timestamp.getHours(), 2) + ':' + app.leftPad(timestamp.getMinutes(), 2) + ':' + app.leftPad(timestamp.getSeconds(), 2);

    var lat = coords.latitude.toFixed(6);
    var lng = coords.longitude.toFixed(6);
    var accuracy = (coords.accuracy) ? coords.accuracy : ''; // accuracy is in meters
    var heading = (coords.heading) ? coords.heading.toFixed(0) : '';
    var speed = (coords.speed) ? (coords.speed * 3.6).toFixed(0) : 0; // speed is m/s, multiply by 3.6 for km/h or 2.23693629 for mph
    var speed_km = (coords.speed) ? speed + ' km/h' : '';
    var distance = (app.dist) ? app.dist.toFixed(2) : 0;
    var distance_km = (app.dist) ? distance + ' km' : '';
    var altitude = (coords.altitude) ? coords.altitude.toFixed(0) : '';

    var elapsedTime = app.msToTime(timestamp - app.startTime);

    document.getElementById('stat_timestamp').innerHTML = ts;
    document.getElementById('stat_latitude').innerHTML = lat;
    document.getElementById('stat_longitude').innerHTML = lng;
    document.getElementById('stat_speed').innerHTML = speed_km;
    document.getElementById('stat_distance').innerHTML = distance;
    document.getElementById('stat_altitude').innerHTML = altitude;
    document.getElementById('stat_heading').innerHTML = heading;
    document.getElementById('stat_accuracy').innerHTML = accuracy;
    document.getElementById('stat_elapsed').innerHTML = elapsedTime;

    // Adjust zoom level based on speed
    if (speed === 0) {
        // do nothing
    }
    else if (speed > 0 && speed < 15) {
        app.map.setZoom(18); // ~30m
    }
    else if (speed >= 15 && speed < 30) {
        app.map.setZoom(17); // ~50m
    }
    else if (speed >= 30 && speed < 60) {
        app.map.setZoom(16); // ~100m
    }
    else if (speed >= 60 && speed < 90) {
        app.map.setZoom(15); // ~300m
    }
    else if (speed >= 90 && speed < 120) {
        app.map.setZoom(14); // ~500m
    }
    else if (speed >= 120 && speed < 150) {
        app.map.setZoom(13); // ~1km
    }
    else if (speed >= 150 && speed < 180) {
        app.map.setZoom(12); // ~2km
    }
    else if (speed >= 180 && speed < 260) {
        app.map.setZoom(11); // ~5km
    }
    else {
        app.map.setZoom(10); // ~10km
    }

    log += '<span data-lat="' + lat + '" data-lng="' + lng + '">' + timestr + ': ' + lat + ', ' + lng + ' (' + accuracy + ')' + '</span><br>';

    document.getElementById('log').innerHTML += log;

    //txt = timestamp.getTime() + ',' + coords.latitude + ',' + coords.longitude + ',' + coords.accuracy + ',' + coords.heading + ',' + coords.speed + ',' + app.dist + ',' + coords.altitude  + ',' + status + "\n";
    txt = timestamp.getTime() + ',' + lat + ',' + lng + ',' + accuracy + ',' + heading + ',' + speed + ',' + distance + ',' + altitude  + ',' + status + "\n";
    app.appendToStorage(app.geodataID, txt);

    app.marker.setPopupContent('<b>' + app.marker.getLatLng().lat.toFixed(6) + ', ' + app.marker.getLatLng().lng.toFixed(6) + '</b><br>');

    app.history.push(position);
};

app.toggleWatch = function (ev) {
    console.info('app.toggleWatch:');

    app.history = [];
    app.history2 = [];
    app.dist = 0.0;

    var res;

    if (ev.target.innerText == 'Start') {
        var timestamp = new Date();
        var timestr = timestamp.getFullYear() + '' + app.leftPad(timestamp.getMonth() + 1, 2) + '' + app.leftPad(timestamp.getDate(), 2) + '-' + app.leftPad(timestamp.getHours(), 2) + '' + app.leftPad(timestamp.getMinutes(), 2) + '' + app.leftPad(timestamp.getSeconds(), 2);

        app.startTime = timestamp;

        if (window.blackberry && community && community.preventsleep) {
            res = community.preventsleep.setPreventSleep(true);
            console.log(res);
            document.getElementById('stat_screen').innerHTML = 'on';
        }
        else {
            document.getElementById('stat_screen').innerHTML = '';
        }

        app.watchID = navigator.geolocation.watchPosition(app.handleWatch, function (err) {
            console.warn('watchPosition error:', err);
        }, {
            enableHighAccuracy: true,
            maximumAge: 1500,
            timeout: 3000
        });

        ev.target.innerText = 'Stop';
    }
    else {
        if (window.blackberry && community && community.preventsleep) {
            res = community.preventsleep.setPreventSleep(false);
            console.log(res);
            document.getElementById('stat_screen').innerHTML = 'timeout';
        }

        navigator.geolocation.clearWatch(app.watchID);

        ev.target.innerText = 'Start';
    }
};

app.updateZoom = function () {
    //console.info('app.updateZoom:');
    document.getElementById('stat_zoom').innerHTML = app.map.getZoom() + ' / ' + app.map.getMaxZoom();
};

//----------------------------------------------------------------------------

Number.prototype.toRad = function () {
    return this * Math.PI / 180;
};

app.calculateDistance = function (lat1, lng1, lat2, lng2) {
    //console.info('app.calculateDistance:');
    //console.log('lat1=', lat1, 'lng1=', lng1, 'lat2=', lat2, 'lng2=', lng2);

    var R = 6371; // radius of the Earth in km
    var dLat = (lat2 - lat1).toRad();
    var dLng = (lng2 - lng1).toRad();
    var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
        Math.sin(dLng / 2) * Math.sin(dLng / 2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    var d = R * c;

    //console.log(d);
    return d;
};

app.msToTime = function (duration) {
    var milliseconds = parseInt((duration % 1000) / 100, 10),
        seconds = parseInt((duration / 1000) % 60, 10),
        minutes = parseInt((duration / (1000 * 60)) % 60, 10),
        hours = parseInt((duration / (1000 * 60 * 60)) % 24, 10);

    hours = (hours < 10) ? "0" + hours : hours;
    minutes = (minutes < 10) ? "0" + minutes : minutes;
    seconds = (seconds < 10) ? "0" + seconds : seconds;

    return hours + ":" + minutes + ":" + seconds + "." + milliseconds;
};

app.appendToStorage = function (name, data) {
    console.info('app.appendToStorage:');

    try {
        var item = localStorage.getItem(name);
        if (item === null) {
            item = "";
        }

        localStorage.setItem(name, item + data);
    }
    catch (ex) {
        console.warn(ex.message);
        for (var p in ex) {
            console.log("\t" + p + ': ' + ex[p]);
        }
    }
};

app.leftPad = function (value, padding) {
    //console.info('app.leftPad:');

    var zeroes = "0";

    for (var i = 0; i < padding; i++) {
        zeroes += "0";
    }

    return (zeroes + value).slice(padding * -1);
};

// Initialize your app
var myApp = new Framework7();

// Add view
var mainView = myApp.addView('.view-main', {
    // Because we use fixed-through navbar we can enable dynamic navbar
    dynamicNavbar: true
});

// Generate dynamic page
var dynamicPageIndex = 0;
function createContentPage(){
	mainView.loadContent(
        '<!-- Top Navbar-->' +
        '<div class="navbar">' +
        '  <div class="navbar-inner">' +
        '    <div class="left"><a href="#" class="back link">Back</a></div>' +
        '    <div class="center sliding">Dynamic Page ' + (++dynamicPageIndex) + '</div>' +
        '  </div>' +
        '</div>' +
        '<div class="pages">' +
        '  <!-- Page, data-page contains page name-->' +
        '  <div data-page="page2" class="page">' +
        '    <!-- Scrollable page content-->' +
        '    <div class="page-content">' +
        '      <div class="content-block">' +
        '        <div class="content-block-inner">' +
        '          <p>Here is a dynamic page created on ' + new Date() + ' !</p>' +
        '          <p>Go <a href="#" class="back">back</a> or go to <a href="page2.html">Page 2</a>.</p>' +
        '        </div>' +
        '      </div>' +
        '    </div>' +
        '  </div>' +
        '</div>'
    );
	return;
}

// add load events
if (navigator.userAgent.match(/WebWorks-BB10/)) {
    window.addEventListener('load', function(e) {
        document.addEventListener('webworksready', app.init);
    }, false);
}

else {
    window.addEventListener('load', app.init);
}
Rerun