X-Git-Url: https://git-public.kairo.at/?p=lantea.git;a=blobdiff_plain;f=js%2Fmap.js;h=c23d46827eab5d696893fbb195002f74d2680589;hp=d59d06020c758d13c321fc7496dbdf676672d714;hb=8e901dce32e1d203d8400a0be806dc0c36b67665;hpb=321359cd7503f05c9b8ad282ef2336366dda4ef6 diff --git a/js/map.js b/js/map.js index d59d060..c23d468 100644 --- a/js/map.js +++ b/js/map.js @@ -8,25 +8,39 @@ var gDebug = false; var gTileSize = 256; var gMaxZoom = 18; // The minimum is 0. +var gMinTrackAccuracy = 1000; // meters +var gTrackWidth = 2; // pixels +var gTrackColor = "#FF0000"; +var gCurLocSize = 5; // pixels +var gCurLocColor = "#800000"; + var gMapStyles = { // OSM tile usage policy: http://wiki.openstreetmap.org/wiki/Tile_usage_policy // Find some more OSM ones at http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers osm_mapnik: {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", - copyright: 'Map data and imagery © OpenStreetMap contributors, CC-BY-SA'}, + copyright: 'Map data and imagery © OpenStreetMap contributors, ODbL/CC-BY-SA'}, + 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, ODbL/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, ODbL/CC-BY-SA'}, mapquest_open: {name: "MapQuest OSM", - url: "http://otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png", - copyright: 'Data, imagery and map information provided by MapQuest, OpenStreetMap and contributors, CC-BY-SA.'}, + url: "http://otile[1-4].mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png", + copyright: 'Map data © OpenStreetMap and contributors (ODbL/CC-BY-SA), tiles Courtesy of MapQuest.'}, mapquest_aerial: {name: "MapQuest Open Aerial", - url: "http://oatile1.mqcdn.com/naip/{z}/{x}/{y}.png", - copyright: 'Data, imagery and map information provided by MapQuest, OpenStreetMap and contributors, CC-BY-SA.'}, + url: "http://oatile[1-4].mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg", + copyright: 'Tiles Courtesy of MapQuest, portions Courtesy NASA/JPL-Caltech and U.S. Depart. of Agriculture, Farm Service Agency.'}, + opengeoserver_arial: + {name: "OpenGeoServer Aerial", + url: "http://services.opengeoserver.org/tiles/1.0.0/globe.aerial_EPSG3857/{z}/{x}/{y}.png?origin=nw", + copyright: 'Tiles by OpenGeoServer.org, CC-BY 3.0 AT.'}, google_map: {name: "Google Maps", url: " http://mt1.google.com/vt/x={x}&y={y}&z={z}", @@ -54,9 +68,11 @@ var gDragTouchID; var gGeoWatchID; var gTrack = []; -var gLastTrackPoint; +var gLastTrackPoint, gLastDrawnPoint; var gCenterPosition = true; +var gCurPosMapCache; + function initMap() { gGeolocation = navigator.geolocation; gCanvas = document.getElementById("map"); @@ -120,6 +136,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); @@ -134,12 +151,13 @@ function resizeAndDraw() { 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() { @@ -179,6 +197,9 @@ function setMapStyle() { if (mapSel.selectedIndex >= 0 && gActiveMap != mapSel.value) { gActiveMap = mapSel.value; gTiles = {}; + document.getElementById("copyright").innerHTML = + gMapStyles[gActiveMap].copyright; + showUI(); drawMap(); } } @@ -198,9 +219,12 @@ 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))) + .replace("[1-4]", 1 + Math.floor(Math.random() * 3)); } // Returns true if the tile is outside the current view. @@ -256,7 +280,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); @@ -279,34 +303,77 @@ 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); + var mappos = {x: Math.round((trackpoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2), + y: Math.round((trackpoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2)}; + + if (!gLastDrawnPoint || !gLastDrawnPoint.optimized) { + gContext.strokeStyle = gTrackColor; + gContext.fillStyle = gContext.strokeStyle; + gContext.lineWidth = gTrackWidth; + 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(mappos.x, mappos.y, 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(mappos.x, mappos.y); + if (!trackpoint.optimized) + gContext.stroke(); } - gLastTrackPoint = trackpoint; + gLastDrawnPoint = trackpoint; +} + +function drawCurrentLocation(trackPoint) { + var locpoint = gps2xy(trackPoint.coords.latitude, trackPoint.ccords.longitude); + var circleSize = gCurLocSize; + var mappos = {x: Math.round((locpoint.x - gPos.x) / gZoomFactor + gCanvas.width / 2), + y: Math.round((locpoint.y - gPos.y) / gZoomFactor + gCanvas.height / 2)}; + + // Initialize or draw cache. + if (!gCurPosMapCache) + gCurPosMapCache = {point: locpoint, + data: context.createImageData(circleSize, circleSize)}; + else + gContext.putImageData(gCurPosMapCache, mappos.x - circleSize / 2, + mappos.y - circleSize / 2); + + // Cache overdrawn area. + gCurPosMapCache = gContext.getImageData(mappos.x - circleSize / 2, + mappos.y - circleSize / 2, + circleSize, circleSize); + + gContext.strokeStyle = gCurLocColor; + gContext.fillStyle = gContext.strokeStyle; + gContext.beginPath(); + gContext.arc(mappos.x, mappos.y, + circleSize, 0, Math.PI * 2, false); + gContext.fill(); } var mapEvHandler = { @@ -344,6 +411,7 @@ var mapEvHandler = { } gLastMouseX = x; gLastMouseY = y; + showUI(); break; case "mousemove": case "touchmove": @@ -355,6 +423,7 @@ var mapEvHandler = { gPos.x -= dX * gZoomFactor; gPos.y -= dY * gZoomFactor; drawMap(); + showUI(); } gLastMouseX = x; gLastMouseY = y; @@ -362,6 +431,7 @@ var mapEvHandler = { case "mouseup": case "touchend": gDragging = false; + showUI(); break; case "mouseout": case "touchcancel": @@ -475,26 +545,40 @@ function startTracking() { return; }; getStoredTrack(); - if (navigator.geolocation) { + 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}; - gTrack.push(tPoint); - gTrackStore.push(tPoint); - drawTrackPoint(position.coords.latitude, position.coords.longitude); - if (gCenterPosition) { - var posCoord = gps2xy(position.coords.latitude, - position.coords.longitude); - if (Math.abs(gPos.x - posCoord.x) > gCanvas.width * gZoomFactor / 4 || - Math.abs(gPos.y - posCoord.y) > gCanvas.height * gZoomFactor / 4) { - gPos.x = posCoord.x; - gPos.y = posCoord.y; - drawMap(); + // Only add point to track is accuracy is good enough. + if (tPoint.coords.accuracy < gMinTrackAccuracy) { + gLastTrackPoint = tPoint; + gTrack.push(tPoint); + try { gTrackStore.push(tPoint); } catch(e) {} + var redrawn = false; + if (gCenterPosition) { + var posCoord = gps2xy(position.coords.latitude, + position.coords.longitude); + if (Math.abs(gPos.x - posCoord.x) > gCanvas.width * gZoomFactor / 4 || + Math.abs(gPos.y - posCoord.y) > gCanvas.height * gZoomFactor / 4) { + gPos.x = posCoord.x; + gPos.y = posCoord.y; + drawMap(); // This draws the current point as well. + redrawn = true; + } } + if (!redrawn) + drawTrackPoint(position.coords.latitude, position.coords.longitude, true); } + drawCurrentLocation(tPoint); }, function(error) { // Ignore erros for the moment, but this is good for debugging.