X-Git-Url: https://git-public.kairo.at/?p=lantea.git;a=blobdiff_plain;f=js%2Fmap.js;h=f6b9d86200761cff1e12d65afb1d2b0f9bc661ea;hp=926177646f9a2f525f293d423fc3cf521eeef1a4;hb=8f63227ba50180ec312ec822c09bb789fb0be3f2;hpb=bb752fc4f4a183177fe8ac6ea3e5bf6e061a9bb4 diff --git a/js/map.js b/js/map.js index 9261776..f6b9d86 100644 --- a/js/map.js +++ b/js/map.js @@ -72,11 +72,19 @@ function initMap() { gGLMapCanvas.getContext("experimental-webgl", {depth: false}); } catch(e) {} - // If we don't have a GL context, give up now if (!gMap.gl) { + // If we don't have a GL context, give up now showGLWarningDialog(); gMap.gl = null; } + else { + // GL context can be lost at any time, handle that. + // See http://www.khronos.org/webgl/wiki/HandlingContextLost + gGLMapCanvas.addEventListener("webglcontextlost", + gMap.handleContextLost, false); + gGLMapCanvas.addEventListener("webglcontextrestored", + gMap.handleContextRestored, false); + } gTrackCanvas = document.getElementById("track"); gTrackContext = gTrackCanvas.getContext("2d"); if (!gMap.activeMap) @@ -121,6 +129,8 @@ function loadPrefs(aEvent) { document.getElementById("body").addEventListener("keydown", mapEvHandler, false); + document.addEventListener("visibilitychange", visibilityEvHandler, false); + console.log("Events added."); document.getElementById("copyright").innerHTML = gMapStyles[gMap.activeMap].copyright; @@ -177,11 +187,14 @@ function loadPrefs(aEvent) { if (aTPoint) { // Add in front and return new length. var tracklen = gTrack.unshift(aTPoint); - // Redraw track periodically, larger distance the longer it gets. + // Redraw track periodically, larger distance the longer it gets + // (but clamped to the first value over a certain limit). // Initial paint will do initial track drawing. if (tracklen % redrawBase == 0) { drawTrack(); - redrawBase = tracklen; + if (redrawBase < 1000) { + redrawBase = tracklen; + } } } else { @@ -321,8 +334,13 @@ var gMap = { gMap.glTxCleanIntervalID = window.setInterval(gMap.cleanTextures, 30 * 1000); } - var throwEv = new CustomEvent("mapinit-done"); - gAction.dispatchEvent(throwEv); + if (!gAppInitDone) { + // We may be called when context was lost and destroyed, + // only send event when we are in app startup + // (gAppInitDone is set to true right after we return this event). + var throwEv = new CustomEvent("mapinit-done"); + gAction.dispatchEvent(throwEv); + } }, draw: function() { @@ -364,7 +382,9 @@ var gMap = { var imgObj = new Image(); imgObj.onload = function() { gMap.loadImageToTexture(imgObj, aTileKey); - window.requestAnimationFrame(function(aTimestamp) { gMap.drawGL() }); + if (document.hidden != true) { // Only draw if we're actually visible. + window.requestAnimationFrame(function(aTimestamp) { gMap.drawGL() }); + } URL.revokeObjectURL(imgURL); } imgObj.src = imgURL; @@ -373,7 +393,9 @@ var gMap = { } } } - window.requestAnimationFrame(function(aTimestamp) { gMap.drawGL() }); + if (document.hidden != true) { // Only draw if we're actually visible. + window.requestAnimationFrame(function(aTimestamp) { gMap.drawGL() }); + } }, drawGL: function() { @@ -512,9 +534,21 @@ var gMap = { } } console.log("Cleaning complete, " + Object.keys(gMap.glTextures).length + " textures left)"); - //clearInterval(gMap.glTxCleanIntervalID); } }, + + handleContextLost: function(event) { + event.preventDefault(); + // GL context is gone, let's reset everything that depends on it. + clearInterval(gMap.glTxCleanIntervalID); + gMap.glTextures = {}; + }, + + handleContextRestored: function(event) { + // When GL context is back, init GL again and draw. + gMap.initGL(); + gMap.draw(); + }, } // Using scale(x, y) together with drawing old data on scaled canvas would be an improvement for zooming. @@ -620,13 +654,15 @@ function decodeIndex(encodedIdx) { } function drawTrack() { - gLastDrawnPoint = null; - gCurPosMapCache = undefined; - gTrackContext.clearRect(0, 0, gTrackCanvas.width, gTrackCanvas.height); - if (gTrack.length) { - for (var i = 0; i < gTrack.length; i++) { - drawTrackPoint(gTrack[i].coords.latitude, gTrack[i].coords.longitude, - (i + 1 >= gTrack.length)); + if (gTrackContext && (document.hidden != true)) { // Only draw if we're actually visible. + gLastDrawnPoint = null; + gCurPosMapCache = undefined; + gTrackContext.clearRect(0, 0, gTrackCanvas.width, gTrackCanvas.height); + if (gTrack.length) { + for (var i = 0; i < gTrack.length; i++) { + drawTrackPoint(gTrack[i].coords.latitude, gTrack[i].coords.longitude, + (i + 1 >= gTrack.length)); + } } } } @@ -704,6 +740,54 @@ function undrawCurrentLocation() { } } +function calcTrackDuration() { + // Get the duration of the track in s. + var tDuration = 0; + if (gTrack.length > 1) { + for (var i = 1; i < gTrack.length; i++) { + if (!gTrack[i].beginSegment) { + tDuration += (gTrack[i].time - gTrack[i-1].time); + } + } + } + return Math.round(tDuration / 1000); // The timestamps are in ms but we return seconds. +} + +function calcTrackLength() { + // Get the length of the track in km. + var tLength = 0; + if (gTrack.length > 1) { + for (var i = 1; i < gTrack.length; i++) { + if (!gTrack[i].beginSegment) { + tLength += getPointDistance(gTrack[i-1].coords, gTrack[i].coords); + } + } + } + return tLength; +} + +function getPointDistance(aGPSPoint1, aGPSPoint2) { + // Get the distance in km between the two given GPS points. + // See http://stackoverflow.com/questions/365826/calculate-distance-between-2-gps-coordinates + // Earth is almost exactly a sphere and we calculate small distances on the surface, so we can do spherical great-circle math. + // Also see http://en.wikipedia.org/wiki/Great-circle_distance + var R = 6371; // km + var dLat = deg2rad(aGPSPoint2.latitude - aGPSPoint1.latitude); + var dLon = deg2rad(aGPSPoint2.longitude - aGPSPoint1.longitude); + var lat1 = deg2rad(aGPSPoint1.latitude); + var lat2 = deg2rad(aGPSPoint2.latitude); + + var a = Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + return R * c; +} + +function deg2rad(aDegreeValue) { + // Convert an angle in degrees to radiants. + return aDegreeValue * (Math.PI / 180); +} + var mapEvHandler = { handleEvent: function(aEvent) { var touchEvent = aEvent.type.indexOf('touch') != -1; @@ -935,6 +1019,15 @@ var mapEvHandler = { } }; +function visibilityEvHandler() { + // Immediately draw if we just got visible. + if (document.hidden != true) { + gMap.draw(); + } + // No need to handle the event where we become invisible as we care only draw + // when we are visible anyhow. +} + var geofake = { tracking: false, lastPos: {x: undefined, y: undefined}, @@ -1078,8 +1171,8 @@ var gTileService = { .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)), + .replace("[a-c]", String.fromCharCode(97 + Math.floor(Math.random() * 3))) + .replace("[1-4]", 1 + Math.floor(Math.random() * 4)), true); XHR.responseType = "blob"; XHR.addEventListener("load", function () {