add an if to make it possible to turn off the optimized path for debugging
[lantea.git] / js / map.js
index a8105ae48f0bbb0845162a32ec85bc97e2b655dd..22307dc751ccbc78b1dcfa04fc4fb6c45949be45 100644 (file)
--- a/js/map.js
+++ b/js/map.js
@@ -35,7 +35,7 @@ var gMapStyles = {
      copyright: 'Map data &copy; <a href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors (<a href="http://www.openstreetmap.org/copyright">ODbL/CC-BY-SA</a>), tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a>.'},
   mapquest_aerial:
     {name: "MapQuest Open Aerial",
-     url: "http://oatile[1-4].mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg",
+     url: "http://otile[1-4].mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg",
      copyright: 'Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a>, portions Courtesy NASA/JPL-Caltech and U.S. Depart. of Agriculture, Farm Service Agency.'},
   opengeoserver_arial:
     {name: "OpenGeoServer Aerial",
@@ -146,9 +146,7 @@ function initMap() {
   gTrackCanvas.addEventListener("touchcancel", mapEvHandler, false);
   gTrackCanvas.addEventListener("touchleave", mapEvHandler, false);
 
-  // XXX deprecated? see https://groups.google.com/forum/?fromgroups#!topic/mozilla.dev.planning/kuhrORubaRY[1-25]
-  gTrackCanvas.addEventListener("DOMMouseScroll", mapEvHandler, false);
-  gTrackCanvas.addEventListener("mousewheel", mapEvHandler, false);
+  gTrackCanvas.addEventListener("wheel", mapEvHandler, false);
 
   document.getElementById("copyright").innerHTML =
       gMapStyles[gActiveMap].copyright;
@@ -297,13 +295,16 @@ function drawMap(aPixels, aOverdraw) {
   for (var x = Math.floor(xMin / size); x < Math.ceil(xMax / size); x++) {
     for (var y = Math.floor(yMin / size); y < Math.ceil(yMax / size); y++) { // slow script warnings on the tablet appear here!
       // Only go to the drawing step if we need to draw this tile.
-      if (x < tiles.left || x > tiles.right || y < tiles.top || y > tiles.bottom) {
+      if (x < tiles.left || x > tiles.right ||
+          y < tiles.top || y > tiles.bottom) {
         // Round here is **CRUCIAL** otherwise the images are filtered
         // and the performance sucks (more than expected).
         var xoff = Math.round((x * size - xMin) / gZoomFactor);
         var yoff = Math.round((y * size - yMin) / gZoomFactor);
         // Draw placeholder tile unless we overdraw.
-        if (!aOverdraw)
+        if (!aOverdraw &&
+            (x < tiles.left -1  || x > tiles.right + 1 ||
+             y < tiles.top -1 || y > tiles.bottom + 1))
           gMapContext.drawImage(gLoadingTile, xoff, yoff);
 
         // Initiate loading/drawing of the actual tile.
@@ -458,13 +459,20 @@ var mapEvHandler = {
           var dY = y - gLastMouseY;
           gPos.x -= dX * gZoomFactor;
           gPos.y -= dY * gZoomFactor;
-          var mapData = gMapContext.getImageData(0, 0, gMapCanvas.width, gMapCanvas.height);
-          gMapContext.clearRect(0, 0, gMapCanvas.width, gMapCanvas.height);
-          gMapContext.putImageData(mapData, dX, dY);
-          drawMap({left: (dX > 0) ? dX : 0,
-                   right: (dX < 0) ? -dX : 0,
-                   top: (dY > 0) ? dY : 0,
-                   bottom: (dY < 0) ? -dY : 0});
+          if (true) { // use optimized path
+            var mapData = gMapContext.getImageData(0, 0,
+                                                   gMapCanvas.width,
+                                                   gMapCanvas.height);
+            gMapContext.clearRect(0, 0, gMapCanvas.width, gMapCanvas.height);
+            gMapContext.putImageData(mapData, dX, dY);
+            drawMap({left: (dX > 0) ? dX : 0,
+                     right: (dX < 0) ? -dX : 0,
+                     top: (dY > 0) ? dY : 0,
+                     bottom: (dY < 0) ? -dY : 0});
+          }
+          else {
+            drawMap(false, true);
+          }
           showUI();
         }
         gLastMouseX = x;
@@ -480,17 +488,13 @@ var mapEvHandler = {
       case "touchleave":
         //gDragging = false;
         break;
-      case "DOMMouseScroll":
-      case "mousewheel":
-        var delta = 0;
-        if (aEvent.wheelDelta) {
-          delta = aEvent.wheelDelta / 120;
-          if (window.opera)
-            delta = -delta;
-        }
-        else if (aEvent.detail) {
-          delta = -aEvent.detail / 3;
-        }
+      case "wheel":
+        // If we'd want pixels, we'd need to calc up using aEvent.deltaMode.
+        // See https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/wheel
+
+        // Only accept (non-null) deltaY values
+        if (!aEvent.deltaY)
+          break;
 
         // Debug output: "coordinates" of the point the mouse was over.
         /*
@@ -503,7 +507,7 @@ var mapEvHandler = {
                     pt2Coord.x + "/" + pt2Coord.y);
         */
 
-        var newZoomLevel = gPos.z + (delta > 0 ? 1 : -1);
+        var newZoomLevel = gPos.z + (aEvent.deltaY < 0 ? 1 : -1);
         if ((newZoomLevel >= 0) && (newZoomLevel <= gMaxZoom)) {
           // Calculate new center of the map - same point stays under the mouse.
           // This means that the pixel distance between the old center and point
@@ -516,9 +520,9 @@ var mapEvHandler = {
           gPos.x -= (x - gMapCanvas.width / 2) * (newZoomFactor - gZoomFactor);
           gPos.y -= (y - gMapCanvas.height / 2) * (newZoomFactor - gZoomFactor);
 
-          if (delta > 0)
+          if (aEvent.deltaY < 0)
             zoomIn();
-          else if (delta < 0)
+          else
             zoomOut();
         }
         break;
@@ -575,8 +579,14 @@ function setTracking(aCheckbox) {
 
 function startTracking() {
   if (gGeolocation) {
+    gActionLabel.textContent = "Establishing Position";
+    gAction.style.display = "block";
     gGeoWatchID = gGeolocation.watchPosition(
       function(position) {
+        if (gActionLabel.textContent) {
+          gActionLabel.textContent = "";
+          gAction.style.display = "none";
+        }
         // Coords spec: https://developer.mozilla.org/en/XPCOM_Interface_Reference/NsIDOMGeoPositionCoords
         var tPoint = {time: position.timestamp,
                       coords: {latitude: position.coords.latitude,
@@ -622,6 +632,10 @@ function startTracking() {
 }
 
 function endTracking() {
+  if (gActionLabel.textContent) {
+    gActionLabel.textContent = "";
+    gAction.style.display = "none";
+  }
   if (gGeoWatchID) {
     gGeolocation.clearWatch(gGeoWatchID);
   }
@@ -630,42 +644,47 @@ function endTracking() {
 function clearTrack() {
   gTrack = [];
   gTrackStore.clear();
-  drawMap();
+  drawMap({left: 0, right: 0, top: 0, bottom: 0});
 }
 
 var gTileService = {
   objStore: "tilecache",
 
+  ageLimit: 14 * 86400 * 1000, // 2 weeks (in ms)
+
   get: function(aStyle, aCoords, aCallback) {
     var norm = normalizeCoords(aCoords);
     var dbkey = aStyle + "::" + norm.x + "," + norm.y + "," + norm.z;
     this.getDBCache(dbkey, function(aResult, aEvent) {
       if (aResult) {
         // We did get a cached object.
-        // TODO: Look at the timestamp and trigger a reload when it's too old.
         aCallback(aResult.image, aStyle, aCoords);
+        // Look at the timestamp and return if it's not too old.
+        if (aResult.timestamp + gTileService.ageLimit > Date.now())
+          return;
+        // Reload cached tile otherwise.
+        var oldDate = new Date(aResult.timestamp);
+        console.log("reload cached tile: " + dbkey + " - " + oldDate.toUTCString());
       }
-      else {
-        // Retrieve image from the web and store it in the cache.
-        var XHR = new XMLHttpRequest();
-        XHR.open("GET",
-                 gMapStyles[aStyle].url
-                   .replace("{x}", norm.x)
-                   .replace("{y}", norm.y)
-                   .replace("{z}", norm.z)
-                   .replace("[a-c]", String.fromCharCode(97 + Math.floor(Math.random() * 2)))
-                   .replace("[1-4]", 1 + Math.floor(Math.random() * 3)),
-                 true);
-        XHR.responseType = "blob";
-        XHR.addEventListener("load", function () {
-          if (XHR.status === 200) {
-            var blob = XHR.response;
-            gTileService.setDBCache(dbkey, {image: blob, timestamp: Date.now()});
-            aCallback(blob, aStyle, aCoords);
-          }
-        }, false);
-        XHR.send();
-      }
+      // Retrieve image from the web and store it in the cache.
+      var XHR = new XMLHttpRequest();
+      XHR.open("GET",
+                gMapStyles[aStyle].url
+                  .replace("{x}", norm.x)
+                  .replace("{y}", norm.y)
+                  .replace("{z}", norm.z)
+                  .replace("[a-c]", String.fromCharCode(97 + Math.floor(Math.random() * 2)))
+                  .replace("[1-4]", 1 + Math.floor(Math.random() * 3)),
+                true);
+      XHR.responseType = "blob";
+      XHR.addEventListener("load", function () {
+        if (XHR.status === 200) {
+          var blob = XHR.response;
+          aCallback(blob, aStyle, aCoords);
+          gTileService.setDBCache(dbkey, {image: blob, timestamp: Date.now()});
+        }
+      }, false);
+      XHR.send();
     });
   },
 
@@ -718,5 +737,23 @@ var gTileService = {
       if (aCallback)
         aCallback(success, event);
     }
+  },
+
+  clearDB: function(aCallback) {
+    if (!mainDB)
+      return;
+    var success = false;
+    var transaction = mainDB.transaction([this.objStore], "readwrite");
+    var request = transaction.objectStore(this.objStore).clear();
+    request.onsuccess = function(event) {
+      success = true;
+      if (aCallback)
+        aCallback(success, event);
+    };
+    request.onerror = function(event) {
+      // Errors can be handled here.
+      if (aCallback)
+        aCallback(success, event);
+    }
   }
 };