/*-----------------------------------------*/ /* Common */ /*-----------------------------------------*/ var cities = {}; var map = null; var current_city = null; var marker = null; var working = false; var cached_cities_status = {}; var Modes = { INDEX: 0, MAP: 1 }; var mode = Modes.INDEX; var measures = { second: 1, minute: 60, hour: 3600, day: 86400, week: 604800, month: 2592000, year: 31536000 }; (function() { var s = document.createElement('script'), t = document.getElementsByTagName('script')[0]; s.type = 'text/javascript'; s.async = true; s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto'; t.parentNode.insertBefore(s, t); })(); function long2tile(lon,zoom) { return ((lon+180)/360*Math.pow(2,zoom)); } function lat2tile(lat,zoom) { return ((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)); } function tile2long(x,z) { return (x/Math.pow(2,z)*360-180); } function tile2lat(y,z) { var n=Math.PI-2*Math.PI*y/Math.pow(2,z); return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))); } function loadCities() { var req = new XMLHttpRequest(); req.open("GET", "cities.json", false); req.send(null); cities = JSON.parse(req.responseText)["cities"]; } function loadStatus(repeat) { var http_request = new XMLHttpRequest(); http_request.open("GET", "status.json?bustCache=" + Math.random(), true); http_request.onreadystatechange = function () { var done = 4, ok = 200; if (http_request.readyState == done && http_request.status == ok) { var cities_status = JSON.parse(http_request.responseText)["cities"]; if (mode == Modes.INDEX) { refreshCityTable(cities_status); } else if (mode == Modes.MAP) { refreshState(cities_status); } if (this.working == true && repeat) { setTimeout("loadStatus(true)",5000); //reload every 5 secs } else { setTimeout("loadStatus(true)",60000); //reload every minute } } }; http_request.send(null); } function getHumanReadableDate(date) { var dateStr, amount, current = new Date().getTime(), diff = (current - date.getTime()) / 1000; if(diff > measures.week) { dateStr = date.getFullYear() + "-"; if (date.getMonth()+1 < 10) dateStr += "0"; dateStr += (date.getMonth()+1) + "-"; if (date.getDate() < 10) dateStr += "0"; dateStr += date.getDate(); } else if(diff > measures.day) { amount = Math.round(diff/measures.day); dateStr = ((amount > 1) ? amount + " " + "days ago":"one day ago"); } else if(diff > measures.hour) { amount = Math.round(diff/measures.hour); dateStr = ((amount > 1) ? amount + " " + "hour" + "s":"an " + "hour") + " ago"; } else if(diff > measures.minute) { amount = Math.round(diff/measures.minute); dateStr = ((amount > 1) ? amount + " " + "minute" + "s":"a " + "minute") + " ago"; } else { dateStr = "a few seconds ago"; } return dateStr; } function showMessage(title, innerHTML) { hideMessage(); var overlay = document.createElement("div"); overlay.setAttribute("id","overlay"); overlay.setAttribute("class", "overlay"); overlay.setAttribute("onClick", "hideMessage()"); var error = document.createElement("div"); error.setAttribute("id","message"); error.setAttribute("class", "message"); error.innerHTML = "

" + title + "

" + innerHTML; document.body.appendChild(error); document.body.appendChild(overlay); } function hideMessage() { try { var error = document.getElementById("message"); document.body.removeChild(error); } catch (err) { } try { var overlay = document.getElementById("overlay"); if (overlay.style.animationName !== undefined) { overlay.addEventListener('animationEnd', function(){ document.body.removeChild(overlay); }, false); overlay.style.animationName = "fadeOut"; } else if (overlay.style.webkitAnimationName !== undefined) { overlay.addEventListener('webkitAnimationEnd', function(){ document.body.removeChild(overlay); }, false); overlay.style.webkitAnimationName = "fadeOut"; } else if (overlay.style.mozAnimationName !== undefined) { overlay.addEventListener('mozAnimationEnd', function(){ document.body.removeChild(overlay); }, false); overlay.style.mozAnimationName = "fadeOut"; } else if (overlay.style.oAnimationName !== undefined) { overlay.addEventListener('oAnimationEnd', function(){ document.body.removeChild(overlay); }, false); overlay.style.oAnimationName = "fadeOut"; } } catch (err) { } } function getStatusByCityId(cities_status, id) { for (var i = 0; i < cities_status.length; i++) { var status = cities_status[i]; if (status.city_id == id) { return status; } } return null; } function getRecentFinishedRenderings(status) { var succesfulRenderings = []; if (status != null) { for (var i = 0; i < status.renderings.length; i++) { var rendering = status.renderings[i]; if (rendering.succesful) { succesfulRenderings.push (rendering); } } } if (succesfulRenderings.length >= 5) { succesfulRenderings = succesfulRenderings.slice (succesfulRenderings.length-6); } return succesfulRenderings; } function getAveragePhaseDuration(status, phase) { var succesfulRenderings = getRecentFinishedRenderings(status); var average = 0; for (var i = 0; i < succesfulRenderings.length; i++) { average += succesfulRenderings[i].durations[phase-1]; } average = average / succesfulRenderings.length; return average; } function getWorkingStatusDiv(status) { var div = document.createElement("div"); var canvas = document.createElement("canvas"); canvas.style.paddingRight = 3; canvas.width = 14; canvas.height = 14; canvas.title = "Step " + status.status.step + "/" + status.status.total_steps; var context = canvas.getContext("2d"); if (window.devicePixelRatio) { var width = canvas.width; var height = canvas.height; canvas.width = canvas.width * window.devicePixelRatio; canvas.height = canvas.height * window.devicePixelRatio; canvas.style.width = width; canvas.style.height = height; context.scale(window.devicePixelRatio, window.devicePixelRatio); } context.fillStyle = "rgb(80,80,80)"; context.beginPath(); context.moveTo(7,7); var endAngle = 1.0*status.status.step/status.status.total_steps*2.0*Math.PI - 0.5*Math.PI; context.arc(7, 7, 6, -0.5*Math.PI, endAngle, false); context.fill(); context.strokeStyle = "rgb(150,150,150)"; context.beginPath(); context.arc(7, 7, 6, 0.0, 2.0*Math.PI, false); context.stroke(); div.appendChild(canvas); div.appendChild(document.createTextNode(status.status.description)); div.appendChild(document.createElement("br")); var timestamp = document.createElement("div"); timestamp.className = "timestamp"; if (getRecentFinishedRenderings(status).length >= 3) { var timeLeft = getAveragePhaseDuration(status, status.status.phase)*(status.status.total_steps-status.status.step)/status.status.total_steps for (var i = status.status.phase + 1; i <= status.status.total_phases; i++) { timeLeft += getAveragePhaseDuration(status, i); } timestamp.title = parseInt(timeLeft/1000/60) + " minutes left" var dateFinished = new Date(new Date().getTime() + timeLeft); timestamp.innerHTML= "New rendering available at " + dateFinished.getHours() + ":"; timestamp.innerHTML+= (dateFinished.getMinutes() < 10 ? "0" + dateFinished.getMinutes(): dateFinished.getMinutes()); } else { var date_state_hr = ""; try { date_state_hr = getHumanReadableDate(new Date(status.status.time)); } catch (err) { date_state_hr = "n/a"; } timestamp.innerHTML = date_state_hr; } div.appendChild(timestamp); div.title ="Phase " + status.status.phase + "/" + status.status.total_phases; return div; } function getFailedStatusDiv(status) { var div = document.createElement("div"); div.appendChild(document.createTextNode(status.status.description)); div.appendChild(document.createElement("br")); var date_state_hr = ""; try { date_state_hr = getHumanReadableDate(new Date(status.status.time)); } catch (err) { date_state_hr = "n/a"; } var timestamp = document.createElement("div"); timestamp.className = "timestamp"; timestamp.innerHTML = date_state_hr; div.appendChild(timestamp); return div; } function getLastRenderingFinishedTime(status) { var last_rendering_finished = 0; if (status != null) { var max_id = -1; for (var j = 0; j < status.renderings.length; j++) { var rendering = status.renderings[j]; if (rendering.rendering_id > max_id) { max_id = rendering.rendering_id if (rendering.succesful) { last_rendering_finished = rendering.end; } } } } return last_rendering_finished; } /*-----------------------------------------*/ /* for index.html */ /*-----------------------------------------*/ function refreshCityTable(cities_status) { this.cached_cities_status = cities_status; //clear table var table = document.getElementById("city_list").getElementsByTagName("tbody")[0]; while (table.firstElementChild) { table.removeChild(table.firstElementChild); } var city = null; for (var i = 0; i"; message += "
  • Number of tiles (total): " + status.stats.total_tiles + "
  • "; message += "
  • Average phase durations: "; var sumDurations = 0; for (var i = 1; i <= 5; i++) { sumDurations += getAveragePhaseDuration(status, i); message += parseInt(getAveragePhaseDuration(status, i)/1000) + "s "; } message += "
  • "; message += "
  • Average update duration: " + parseInt(sumDurations/1000/60) + "min"; message += "
  • Last rendering finished: " + (new Date(getLastRenderingFinishedTime(status))).toUTCString() + "
  • "; message += ""; message += 'Close'; showMessage("Statistics for " + current_city.name, message); } function refreshState(cities_status) { this.cached_cities_status = cities_status; var stateDiv = document.getElementById("state"); stateDiv.innerHTML = '
    ' + "Last update: unkown" + "
    "; var status = getStatusByCityId(cities_status, current_city.city_id); if (status != null) { var last_rendering_finished = getLastRenderingFinishedTime(status); if (status.status.type == "WORKING") { this.working=true; stateDiv.innerHTML = ""; stateDiv.appendChild(getWorkingStatusDiv(status)); } else { this.working = false; if (last_rendering_finished == 0) { stateDiv.innerHTML = '
    ' + "Last update: n/a" + "
    "; } else { var lastUpdateStr = "Last update: " + getHumanReadableDate(new Date(last_rendering_finished)); stateDiv.innerHTML = '
    ' + lastUpdateStr + "
    "; } } } } function loadPermalink() { var center = map.getCenter(); var lat = tile2lat(lat2tile(center.lat,12)* 2.0,12); var lon = center.lng; location.href = "map.html#" + lat + "," + lon + "," + map.getZoom(); } function loadCity() { hideMessage(); if (marker != null) { map.removeLayer(marker); } //set map center and zoom if (location.href.indexOf("#") != -1) { var city_id = location.href.substr(location.href.indexOf("#")+1); var city = getCityById(city_id); if (city != null) { var latlong = new L.LatLng(tile2lat(lat2tile((city.area.top+city.area.bottom)/2.0,12)/2.0,12), (city.area.left+city.area.right)/2.0); map.setView(latlong, 13); current_city = city; } else { var location_str = location.href.substr(location.href.indexOf("#")+1); var position = location_str.split(","); if (position.length == 2 || position.length==3) { //url format: map.html#lat,lon[,zoom] var lat = parseFloat(position[0]); var lon = parseFloat(position[1]); var zoom = 14; //default zoom if (position.length==3) { zoom = parseInt(position[2]); } var latlong = new L.LatLng(tile2lat(lat2tile((lat),12)/2.0,12), lon); map.setView(latlong, zoom); if (zoom >= 15) { marker = new L.Marker(latlong); map.addLayer(marker); } city = getCityByLatLon(lat,lon); if (city == null) { var nearestCity = getNearestCityId(new L.LatLng(lat,lon)); if (nearestCity != null){ var msg = "The position '" + location_str + "' is out of any rendered area. " + '

    Try the following: '; showMessage("Sorry, but you're on a black spot!", msg); } else { var msg = "Sorry, but the position '" + location_str + "' is out of any rendered area or the URL couldn't be parsed. " + '

    Try the following: '; showMessage("Error 404: Not found", msg); } } current_city = city; } else { showMessage("Error 404: Not found", "Sorry, but the city with the ID '" + location.href.substr(location.href.indexOf("#")+1) + "' was not found. " + '

    Try the following: '); } } if (city != null) { //update page title and city list document.title = "3D map of " + city.name; var select=document.getElementById("city_select"); for (var i = 0; i < select.length; i++) { if (select.options[i].value == city.city_id) { select.options[i].selected = true; } else { select.options[i].selected = false; } } loadStatus(false); } else { document.title = "3D map"; } } else { map.locate({maxZoom:15, setView:true, enableHighAccuracy:true}); } } function selectedCity() { var select=document.getElementById("city_select"); var wert = select.options[select.options.selectedIndex].value; location.href = "map.html#" + wert; } function getNearestCityId(position) { var nearestCity = null; var distance = 999999; var city = null; for (var i = 0; i < this.cities.length; i++) { city = this.cities[i]; var center = new L.LatLng(city.area.bottom + (city.area.top - city.area.bottom)/2.0, city.area.left + (city.area.right - city.area.left)/2.0); if (position.distanceTo(center) < distance) { nearestCity = city; distance = position.distanceTo(center); } } return nearestCity; } function locate() { map.locate({maxZoom:15, setView:true, enableHighAccuracy:true}); } function located(e) { location.href = "map.html#" + e.latlng.lat + "," + e.latlng.lng + "," + map.getZoom(); loadCity(); } function locationfailed(e) { var msg = "The geolocation process failed. " + e.message + '

    Try the following: '; showMessage("Sorry, I couldn't find out where you are.", msg); } function initMap(){ mode = Modes.MAP; //initialize map map = new L.Map('map'); var iso3d = new L.TileLayer('tiles/{z}/{x}/{y}.png', { attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA', maxZoom: 15, minZoom: 12 }); map.addLayer(iso3d); //setup event handlers map.on('locationfound', located); map.on('locationerror', locationfailed); loadCities(); var select=document.getElementById("city_select"); var city = null; for (var i = 0; i < this.cities.length; i++) { city = this.cities[i]; newOption = new Option(city.name, city.city_id); select.options[select.length] = newOption; } loadCity(); window.onhashchange = loadCity; loadStatus(true); }