X-Git-Url: https://git-public.kairo.at/?p=lantea.git;a=blobdiff_plain;f=js%2Fmap.js;h=d07cd743682289b924cc6142399eee4c5b688291;hp=8e8ef55b0bff17c6a129e243b253ac0e63133bc9;hb=7a54914850a97c86e9fb4a550a88ce5744d3e7eb;hpb=3610c22d8eb34e6472073da446a20f2772184145 diff --git a/js/map.js b/js/map.js index 8e8ef55..d07cd74 100644 --- a/js/map.js +++ b/js/map.js @@ -1,41 +1,9 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Lantea mapping/tracking web app. - * - * The Initial Developer of the Original Code is - * Robert Kaiser . - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Robert Kaiser - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -var gCanvas, gContext; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var gCanvas, gContext, gGeolocation; +var gDebug = false; var gTileSize = 256; var gMaxZoom = 18; // The minimum is 0. @@ -47,9 +15,13 @@ var gMapStyles = { {name: "OpenStreetMap (Mapnik)", url: "http://tile.openstreetmap.org/{z}/{x}/{y}.png", copyright: 'Map data and imagery © OpenStreetMap contributors, CC-BY-SA'}, - osm_tilesathome: - {name: "OpenStreetMap (OSMarender)", - url: "http://tah.openstreetmap.org/Tiles/tile/{z}/{x}/{y}.png", + osm_cyclemap: + {name: "Cycle Map (OSM)", + url: "http://[a-c].tile.opencyclemap.org/cycle/{z}/{x}/{y}.png", + copyright: 'Map data and imagery © OpenStreetMap contributors, CC-BY-SA'}, + osm_transmap: + {name: "Transport Map (OSM)", + url: "http://[a-c].tile2.opencyclemap.org/transport/{z}/{x}/{y}.png", copyright: 'Map data and imagery © OpenStreetMap contributors, CC-BY-SA'}, mapquest_open: {name: "MapQuest OSM", @@ -82,19 +54,30 @@ var gLoadingTile; var gMapPrefsLoaded = false; var gDragging = false; -var gZoomTouchID; +var gDragTouchID; var gGeoWatchID; var gTrack = []; -var gLastTrackPoint; +var gLastTrackPoint, gLastDrawnPoint; var gCenterPosition = true; function initMap() { + gGeolocation = navigator.geolocation; gCanvas = document.getElementById("map"); gContext = gCanvas.getContext("2d"); if (!gActiveMap) gActiveMap = "osm_mapnik"; + //gDebug = true; + if (gDebug) { + gGeolocation = geofake; + var hiddenList = document.getElementsByClassName("debugHide"); + // last to first - list of elements with that class is changing! + for (var i = hiddenList.length - 1; i >= 0; i--) { + hiddenList[i].classList.remove("debugHide"); + } + } + var loopCnt = 0; var getPersistentPrefs = function() { if (mainDB) { @@ -141,6 +124,7 @@ function initMap() { gCanvas.addEventListener("touchcancel", mapEvHandler, false); gCanvas.addEventListener("touchleave", mapEvHandler, false); + // XXX deprecated? see https://groups.google.com/forum/?fromgroups#!topic/mozilla.dev.planning/kuhrORubaRY[1-25] gCanvas.addEventListener("DOMMouseScroll", mapEvHandler, false); gCanvas.addEventListener("mousewheel", mapEvHandler, false); @@ -152,15 +136,16 @@ function initMap() { } function resizeAndDraw() { - var viewportWidth = window.innerWidth; - var viewportHeight = window.innerHeight; + var viewportWidth = Math.min(window.innerWidth, window.outerWidth); + var viewportHeight = Math.min(window.innerHeight, window.outerHeight); - var canvasWidth = viewportWidth * 0.98; - var canvasHeight = (viewportHeight - 100) * 0.98; + var canvasWidth = viewportWidth - 2; + var canvasHeight = viewportHeight - 2; gCanvas.style.position = "fixed"; gCanvas.width = canvasWidth; gCanvas.height = canvasHeight; drawMap(); + showUI(); } function zoomIn() { @@ -200,6 +185,8 @@ function setMapStyle() { if (mapSel.selectedIndex >= 0 && gActiveMap != mapSel.value) { gActiveMap = mapSel.value; gTiles = {}; + document.getElementById("copyright").innerHTML = + gMapStyles[gActiveMap].copyright; drawMap(); } } @@ -219,9 +206,11 @@ function normaliseIndices(x, y, z) { function tileURL(x, y, z) { var norm = normaliseIndices(x, y, z); - return gMapStyles[gActiveMap].url.replace("{x}", norm.x) - .replace("{y}", norm.y) - .replace("{z}", norm.z); + return gMapStyles[gActiveMap].url + .replace("{x}", norm.x) + .replace("{y}", norm.y) + .replace("{z}", norm.z) + .replace("[a-c]", String.fromCharCode(97 + Math.floor(Math.random() * 2))); } // Returns true if the tile is outside the current view. @@ -277,7 +266,7 @@ function drawMap() { // Go through all the tiles we want. // If any of them aren't loaded or being loaded, do so. 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++) { + for (var y = Math.floor(yMin / size); y < Math.ceil(yMax / size); y++) { // slow script warnings on the tablet appear here! var xoff = (x * size - xMin) / gZoomFactor; var yoff = (y * size - yMin) / gZoomFactor; var tileKey = encodeIndex(x, y, gPos.z); @@ -300,34 +289,50 @@ function drawMap() { } } } - if (gTrack.length) + if (gTrack.length) { + gLastDrawnPoint = null; for (var i = 0; i < gTrack.length; i++) { - drawTrackPoint(gTrack[i].coords.latitude, gTrack[i].coords.longitude); + drawTrackPoint(gTrack[i].coords.latitude, gTrack[i].coords.longitude, + (i + 1 >= gTrack.length)); } + } } -function drawTrackPoint(aLatitude, aLongitude) { +function drawTrackPoint(aLatitude, aLongitude, lastPoint) { var trackpoint = gps2xy(aLatitude, aLongitude); - gContext.strokeStyle = "#FF0000"; - gContext.fillStyle = gContext.strokeStyle; - gContext.lineWidth = 2; - gContext.lineCap = "round"; - gContext.lineJoin = "round"; - gContext.beginPath(); - if (!gLastTrackPoint || gLastTrackPoint == trackpoint) { - gContext.arc((trackpoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2, - (trackpoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2, + // lastPoint is for optimizing (not actually executing the draw until the last) + trackpoint.optimized = (lastPoint === false); + + if (!gLastDrawnPoint || !gLastDrawnPoint.optimized) { + gContext.strokeStyle = "#FF0000"; + gContext.fillStyle = gContext.strokeStyle; + gContext.lineWidth = 2; + gContext.lineCap = "round"; + gContext.lineJoin = "round"; + } + if (!gLastDrawnPoint || gLastDrawnPoint == trackpoint) { + // This breaks optimiziation, so make sure to close path and reset optimization. + if (gLastDrawnPoint && gLastDrawnPoint.optimized) + gContext.stroke(); + gContext.beginPath(); + trackpoint.optimized = false; + gContext.arc(Math.round((trackpoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2), + Math.round((trackpoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2), gContext.lineWidth, 0, Math.PI * 2, false); gContext.fill(); } else { - gContext.moveTo((gLastTrackPoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2, - (gLastTrackPoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2); - gContext.lineTo((trackpoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2, - (trackpoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2); - gContext.stroke(); + if (!gLastDrawnPoint || !gLastDrawnPoint.optimized) { + gContext.beginPath(); + gContext.moveTo(Math.round((gLastDrawnPoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2), + Math.round((gLastDrawnPoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2)); + } + gContext.lineTo(Math.round((trackpoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2), + Math.round((trackpoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2)); + if (!trackpoint.optimized) + gContext.stroke(); } - gLastTrackPoint = trackpoint; + gLastDrawnPoint = trackpoint; } var mapEvHandler = { @@ -341,21 +346,21 @@ var mapEvHandler = { return; // Bail out if the started touch can't be found. - if (touchEvent && zoomstart && - !aEvent.changedTouches.identifiedTouch(gZoomTouchID)) + if (touchEvent && gDragging && + !aEvent.changedTouches.identifiedTouch(gDragTouchID)) return; } var coordObj = touchEvent ? - aEvent.changedTouches.identifiedTouch(gZoomTouchID) : + aEvent.changedTouches.identifiedTouch(gDragTouchID) : aEvent; switch (aEvent.type) { case "mousedown": case "touchstart": if (touchEvent) { - zoomTouchID = aEvent.changedTouches.item(0).identifier; - coordObj = aEvent.changedTouches.identifiedTouch(gZoomTouchID); + gDragTouchID = aEvent.changedTouches.item(0).identifier; + coordObj = aEvent.changedTouches.identifiedTouch(gDragTouchID); } var x = coordObj.clientX - gCanvas.offsetLeft; var y = coordObj.clientY - gCanvas.offsetTop; @@ -365,6 +370,7 @@ var mapEvHandler = { } gLastMouseX = x; gLastMouseY = y; + showUI(); break; case "mousemove": case "touchmove": @@ -376,6 +382,7 @@ var mapEvHandler = { gPos.x -= dX * gZoomFactor; gPos.y -= dY * gZoomFactor; drawMap(); + showUI(); } gLastMouseX = x; gLastMouseY = y; @@ -383,6 +390,7 @@ var mapEvHandler = { case "mouseup": case "touchend": gDragging = false; + showUI(); break; case "mouseout": case "touchcancel": @@ -433,14 +441,24 @@ var mapEvHandler = { var geofake = { tracking: false, + lastPos: {x: undefined, y: undefined}, watchPosition: function(aSuccessCallback, aErrorCallback, aPrefObject) { this.tracking = true; var watchCall = function() { + // calc new position in lat/lon degrees + // 90° on Earth surface are ~10,000 km at the equator, + // so try moving at most 10m at a time + if (geofake.lastPos.x) + geofake.lastPos.x += (Math.random() - .5) * 90 / 1000000 + else + geofake.lastPos.x = 48.208174 + if (geofake.lastPos.y) + geofake.lastPos.y += (Math.random() - .5) * 90 / 1000000 + else + geofake.lastPos.y = 16.373819 aSuccessCallback({timestamp: Date.now(), - coords: {latitude: 48.208174 + - (Math.random() - .5) / 5, - longitude: 16.373819 + - (Math.random() - .5) / 5, + coords: {latitude: geofake.lastPos.x, + longitude: geofake.lastPos.y, accuracy: 20}}); if (geofake.tracking) setTimeout(watchCall, 1000); @@ -473,7 +491,8 @@ function startTracking() { var getStoredTrack = function() { if (mainDB) gTrackStore.getList(function(aTPoints) { - //document.getElementById("debug").textContent = aTPoints.length + " points loaded."; + if (gDebug) + document.getElementById("debug").textContent = aTPoints.length + " points loaded."; if (aTPoints.length) { gTrack = aTPoints; } @@ -485,17 +504,23 @@ function startTracking() { return; }; getStoredTrack(); - if (navigator.geolocation) { - //gGeoWatchID = geofake.watchPosition( - gGeoWatchID = navigator.geolocation.watchPosition( + if (gGeolocation) { + gGeoWatchID = gGeolocation.watchPosition( function(position) { // Coords spec: https://developer.mozilla.org/en/XPCOM_Interface_Reference/NsIDOMGeoPositionCoords var tPoint = {time: position.timestamp, - coords: position.coords, + coords: {latitude: position.coords.latitude, + longitude: position.coords.longitude, + altitude: position.coords.altitude, + accuracy: position.coords.accuracy, + altitudeAccuracy: position.coords.altitudeAccuracy, + heading: position.coords.heading, + speed: position.coords.speed}, beginSegment: !gLastTrackPoint}; + gLastTrackPoint = tPoint; gTrack.push(tPoint); - gTrackStore.push(tPoint); - drawTrackPoint(position.coords.latitude, position.coords.longitude); + try { gTrackStore.push(tPoint); } catch(e) {} + var redrawn = false; if (gCenterPosition) { var posCoord = gps2xy(position.coords.latitude, position.coords.longitude); @@ -503,9 +528,12 @@ function startTracking() { Math.abs(gPos.y - posCoord.y) > gCanvas.height * gZoomFactor / 4) { gPos.x = posCoord.x; gPos.y = posCoord.y; - drawMap(); + drawMap(); // This draws the current point as well. + redrawn = true; } } + if (!redrawn) + drawTrackPoint(position.coords.latitude, position.coords.longitude, true); }, function(error) { // Ignore erros for the moment, but this is good for debugging. @@ -519,8 +547,7 @@ function startTracking() { function endTracking() { if (gGeoWatchID) { - //geofake.clearWatch(gGeoWatchID); - navigator.geolocation.clearWatch(gGeoWatchID); + gGeolocation.clearWatch(gGeoWatchID); } }