'use strict'; (function () { var Core = { NUMBER_OF_ROUNDS: 5, MAX_SCORE: 1000, rounds: [], scoreSum: 0, panoId: null, panorama: null, map: null, guessMarker: null, adaptGuess: false, googleLink: null, initialize: function () { document.getElementById('loading').style.visibility = 'visible'; document.getElementById('cover').style.visibility = 'visible'; document.getElementById('currentRound').innerHTML = '1/' + String(Core.NUMBER_OF_ROUNDS); document.getElementById('currentScoreSum').innerHTML = '0/0'; Core.map.setOptions({ draggableCursor: 'crosshair' }); Core.map.fitBounds(mapBounds); var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.onload = function () { if (this.response.error) { //TODO: handle this error return; } document.getElementById('loading').style.visibility = 'hidden'; document.getElementById('cover').style.visibility = 'hidden'; Core.panoId = this.response.panoId; if (this.response.history) { for (var i = 0; i < this.response.history.length; ++i) { var round = this.response.history[i]; Core.rounds.push({ position: round.position, guessPosition: round.guessPosition, realMarker: null, guessMarker: null, line: null }); Core.addRealGuessPair(round.position, round.guessPosition, true); Core.scoreSum += round.score; } document.getElementById('currentRound').innerHTML = String(Core.rounds.length) + '/' + String(Core.NUMBER_OF_ROUNDS); document.getElementById('currentScoreSum').innerHTML = String(Core.scoreSum) + '/' + String(Core.rounds.length * Core.MAX_SCORE); } Core.startNewRound(); }; xhr.open('GET', '/game/' + mapId + '/position.json', true); xhr.send(); }, resetGame: function () { if (Core.guessMarker) { Core.guessMarker.setMap(null); Core.guessMarker = null; } for (var i = 0; i < Core.rounds.length; ++i) { var round = Core.rounds[i]; if (round.realMarker && round.guessMarker && round.line) { round.realMarker.setMap(null); round.guessMarker.setMap(null); round.line.setMap(null); } } Core.rounds = []; Core.scoreSum = 0; var distanceInfo = document.getElementById('distanceInfo'); distanceInfo.children[0].style.display = null; distanceInfo.children[1].style.display = null; var scoreInfo = document.getElementById('scoreInfo'); scoreInfo.children[0].style.display = null; scoreInfo.children[1].style.display = null; document.getElementById('continueButton').style.display = null; document.getElementById('startNewGameButton').style.display = null; document.getElementById('showGuessButton').style.visibility = null; document.getElementById('guess').style.visibility = null; document.getElementById('guess').classList.remove('result'); Core.initialize(); }, resetRound: function () { document.getElementById('scoreBar').style.width = null; if (Core.rounds.length > 0) { var lastRound = Core.rounds[Core.rounds.length - 1]; lastRound.realMarker.setVisible(false); lastRound.guessMarker.setVisible(false); lastRound.line.setVisible(false); } document.getElementById('cover').style.visibility = 'hidden'; document.getElementById('showGuessButton').style.visibility = null; document.getElementById('guess').style.visibility = null; document.getElementById('guess').classList.remove('result') Core.map.setOptions({ draggableCursor: 'crosshair' }); Core.map.fitBounds(mapBounds); Core.startNewRound(); }, startNewRound: function () { Core.rounds.push({ position: null, guessPosition: null, realMarker: null, guessMarker: null, line: null }); document.getElementById('currentRound').innerHTML = String(Core.rounds.length) + '/' + String(Core.NUMBER_OF_ROUNDS); Core.loadPano(Core.panoId); }, handleErrorResponse: function (error) { // for the time being we only handle the "no_session_found" error and reset the game var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.onload = function () { mapBounds = this.response.bounds; Core.resetGame(); }; xhr.open('GET', '/game/' + mapId + '/json', true); xhr.send(); }, loadPano: function (panoId) { if (Core.adaptGuess) { document.getElementById('guess').classList.add('adapt'); } Core.panorama.setPov({ heading: 0, pitch: 0 }); Core.panorama.setZoom(0); Core.panorama.setPano(panoId); }, evaluateGuess: function () { var guessPosition = Core.guessMarker.getPosition().toJSON(); Core.rounds[Core.rounds.length - 1].guessPosition = guessPosition; if (Core.adaptGuess) { document.getElementById('guess').classList.remove('adapt'); } document.getElementById('loading').style.visibility = 'visible'; document.getElementById('cover').style.visibility = 'visible'; var data = new FormData(); data.append('lat', String(guessPosition.lat)); data.append('lng', String(guessPosition.lng)); var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.onload = function () { if (this.response.error) { Core.handleErrorResponse(this.response.error); return; } Core.guessMarker.setMap(null); Core.guessMarker = null; document.getElementById('loading').style.visibility = 'hidden'; document.getElementById('guess').classList.add('result'); Core.scoreSum += this.response.result.score; document.getElementById('currentScoreSum').innerHTML = String(Core.scoreSum) + '/' + String(Core.rounds.length * Core.MAX_SCORE); Core.rounds[Core.rounds.length - 1].position = this.response.result.position; Core.addRealGuessPair(this.response.result.position, guessPosition); var resultBounds = new google.maps.LatLngBounds(); resultBounds.extend(this.response.result.position); resultBounds.extend(guessPosition); Core.map.setOptions({ draggableCursor: 'grab' }); Core.map.fitBounds(resultBounds); document.getElementById('distance').innerHTML = Util.printDistanceForHuman(this.response.result.distance); document.getElementById('score').innerHTML = this.response.result.score; var scoreBarProperties = Core.calculateScoreBarProperties(this.response.result.score, Core.MAX_SCORE); var scoreBar = document.getElementById('scoreBar'); scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor; scoreBar.style.width = scoreBarProperties.width; if (Core.rounds.length === Core.NUMBER_OF_ROUNDS) { document.getElementById('continueButton').style.display = 'none'; document.getElementById('showSummaryButton').style.display = 'block'; } Core.panoId = this.response.panoId; }; xhr.open('POST', '/game/' + mapId + '/guess.json', true); xhr.send(data); }, addRealGuessPair: function (position, guessPosition, hidden) { var round = Core.rounds[Core.rounds.length - 1]; round.realMarker = new google.maps.Marker({ map: Core.map, visible: !hidden, position: position, title: 'Open in Google Maps', zIndex: Core.rounds.length * 2, clickable: true, draggable: false, icon: { url: '/static/img/markers/marker-green.svg', size: new google.maps.Size(24, 32), scaledSize: new google.maps.Size(24, 32), anchor: new google.maps.Point(12, 32) }, }); round.realMarker.addListener('click', function () { window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank'); }); round.guessMarker = new google.maps.Marker({ map: Core.map, visible: !hidden, position: guessPosition, zIndex: Core.rounds.length, clickable: false, draggable: false, icon: { url: '/static/img/markers/marker-gray-empty.svg', size: new google.maps.Size(24, 32), scaledSize: new google.maps.Size(24, 32), anchor: new google.maps.Point(12, 32), labelOrigin: new google.maps.Point(12, 14) }, label: { color: '#ffffff', fontFamily: 'Roboto', fontSize: '16px', fontWeight: '500', text: '?' } }); round.line = new google.maps.Polyline({ map: Core.map, visible: !hidden, path: [ position, guessPosition ], geodesic: true, strokeOpacity: 0, icons: [{ icon: { path: 'M 0,-1 0,1', strokeOpacity: 1, strokeWeight: 2, scale: 2 }, offset: '0', repeat: '10px' }], clickable: false, draggable: false, editable: false }); }, calculateScoreBarProperties: function (score, maxScore) { var percent = Math.floor((score / maxScore) * 100); var color; if (percent >= 90) { color = '#11ca00'; } else if (percent >= 10) { color = '#ea9000'; } else { color = '#ca1100'; } return { width: percent + '%', backgroundColor: color }; }, showSummary: function () { var distanceInfo = document.getElementById('distanceInfo'); distanceInfo.children[0].style.display = 'none'; distanceInfo.children[1].style.display = 'block'; var scoreInfo = document.getElementById('scoreInfo'); scoreInfo.children[0].style.display = 'none'; scoreInfo.children[1].style.display = 'block'; document.getElementById('showSummaryButton').style.display = null; document.getElementById('startNewGameButton').style.display = 'block'; var resultBounds = new google.maps.LatLngBounds(); for (var i = 0; i < Core.rounds.length; ++i) { var round = Core.rounds[i]; round.realMarker.setIcon({ url: '/static/img/markers/marker-green-empty.svg', size: new google.maps.Size(24, 32), scaledSize: new google.maps.Size(24, 32), anchor: new google.maps.Point(12, 32), labelOrigin: new google.maps.Point(12, 14) }); round.realMarker.setLabel({ color: '#285624', fontFamily: 'Roboto', fontSize: '16px', fontWeight: '500', text: String(i + 1) }); round.realMarker.setVisible(true); round.guessMarker.setVisible(true); round.line.setVisible(true); resultBounds.extend(round.position); resultBounds.extend(round.guessPosition); } Core.map.fitBounds(resultBounds); document.getElementById('scoreSum').innerHTML = String(Core.scoreSum); var scoreBarProperties = Core.calculateScoreBarProperties(Core.scoreSum, Core.NUMBER_OF_ROUNDS * Core.MAX_SCORE); var scoreBar = document.getElementById('scoreBar'); scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor; scoreBar.style.width = scoreBarProperties.width; }, rewriteGoogleLink: function () { if (!Core.googleLink) { var anchors = document.getElementById('panorama').getElementsByTagName('a'); for (var i = 0; i < anchors.length; i++) { var a = anchors[i]; if (a.href.indexOf('maps.google.com/maps') !== -1) { Core.googleLink = a; break; } } } setTimeout(function () { if (Core.googleLink) { Core.googleLink.title = 'Google Maps'; Core.googleLink.href = 'https://maps.google.com/maps'; } }, 1); } }; var Util = { printDistanceForHuman: function (distance) { if (distance < 1000) { return Number.parseFloat(distance).toFixed(0) + ' m'; } else if (distance < 10000) { return Number.parseFloat(distance / 1000).toFixed(2) + ' km'; } else if (distance < 100000) { return Number.parseFloat(distance / 1000).toFixed(1) + ' km'; } else { return Number.parseFloat(distance / 1000).toFixed(0) + ' km'; } } }; if (!('ontouchstart' in document.documentElement)) { Core.adaptGuess = true; } Core.map = new google.maps.Map(document.getElementById('map'), { disableDefaultUI: true, clickableIcons: false, draggingCursor: 'grabbing' }); Core.map.addListener('click', function (e) { if (Core.rounds[Core.rounds.length - 1].guessPosition) { return; } if (Core.guessMarker) { Core.guessMarker.setPosition(e.latLng); return; } Core.guessMarker = new google.maps.Marker({ map: Core.map, position: e.latLng, clickable: false, draggable: true, icon: { url: '/static/img/markers/marker-gray-empty.svg', size: new google.maps.Size(24, 32), scaledSize: new google.maps.Size(24, 32), anchor: new google.maps.Point(12, 32), labelOrigin: new google.maps.Point(12, 14) }, label: { color: '#ffffff', fontFamily: 'Roboto', fontSize: '16px', fontWeight: '500', text: '?' } }); document.getElementById('guessButton').disabled = false; }); Core.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), { disableDefaultUI: true, linksControl: true, showRoadLabels: false, motionTracking: false }); Core.panorama.addListener('position_changed', function () { Core.rewriteGoogleLink(); }); Core.panorama.addListener('pov_changed', function () { Core.rewriteGoogleLink(); }); Core.initialize(); document.getElementById('showGuessButton').onclick = function () { this.style.visibility = 'hidden'; document.getElementById('guess').style.visibility = 'visible'; } document.getElementById('closeGuessButton').onclick = function () { document.getElementById('showGuessButton').style.visibility = null; document.getElementById('guess').style.visibility = null; } document.getElementById('guessButton').onclick = function () { if (!Core.guessMarker) { return; } this.disabled = true; Core.evaluateGuess(); } document.getElementById('continueButton').onclick = function () { Core.resetRound(); } document.getElementById('showSummaryButton').onclick = function () { Core.showSummary(); } document.getElementById('startNewGameButton').onclick = function () { Core.resetGame(); } })();