opengeoguess
small client-side geoguessr clone
by John Doe
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/5.1.6/turf.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!DOCTYPE html>
<html>
<head>
<title>OpenGeoGuess</title>
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initPano&libraries=&v=weekly"
defer
></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div id="wrapper">
<div id="spinner" >
<div class="lds-dual-ring"></div>
</div>
<div id="controls">
<div class="btn" id="next">New location</div>
</div>
<div id="pano"></div>
<div id="map-overlay-wrap">
<div class="btn" id="guess">Guess Location</div>
<div id="map"></div>
</div>
</div>
</body>
</html>
CSS
/* globals */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
/* game window */
#wrapper {
height: 100%;
margin: 0;
padding: 0;
}
/* google street view */
#pano {
height: 100%;
z-index: 1000;
background-color: black;
}
/* ***************** */
/* map related stuff */
/* ***************** */
#map-overlay-wrap {
cursor: pointer;
position: absolute;
bottom: 2rem;
right: 3rem;
opacity: 1;
transform: scale(.8);
transform-origin: bottom right;
visibility: visible;
transition: all 1s;
z-index: 1001;
}
#map-overlay-wrap:hover {
transform: scale(1);
}
#map {
position: relative;
overflow: hidden;
height: 300px;
width: 420px;
}
/* ******** */
/* Controls */
/* ******** */
#controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 1001;
}
.btn {
color: #fff;
display: inline-block;
font-weight: 700;
letter-spacing: .025em;
width: 100%;
text-align: center;
border-radius: .5rem;
margin-bottom: .75rem;
}
#next {
background-color: #2196f3;
}
#guess {
background-color: #66cc00;
}
/* ********************* */
/* spinner loader thingy */
/* ********************* */
#spinner {
display: none;
background-color: #000000aa;
position: absolute;
height: 100%;
width: 100%;
z-index: 1010;
}
.lds-dual-ring {
display: inline-block;
width: 80px;
height: 80px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.lds-dual-ring:after {
content: " ";
display: block;
width: 64px;
height: 64px;
margin: 8px;
border-radius: 50%;
border: 6px solid #fff;
border-color: #fff transparent #fff transparent;
animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
JavaScript
/*
TODO:
- better random coordinates
- show distance difference
*/
/* spinner */
class Spinner {
constructor() {
this.block = document.getElementById('spinner');
}
show() {
this.block.style.display = 'block';
}
hide() {
this.block.style.display = 'none';
}
}
/* control buttons */
class Controls {
constructor() {
this.nextButton = document.getElementById('next');
this.guessButton = document.getElementById('guess');
}
setEvents(props) {
this.onNext = props.onNext;
this.onGuess = props.onGuess;
this.nextButton.addEventListener('click', () => {
this.onNext();
})
this.guessButton.addEventListener('click', () => {
this.onGuess();
})
}
}
/* leaflet map for guessing*/
class GuessMap {
constructor() {
// create a slippy map and show the basemap
this.mapDOM = document.getElementById('map');
this.map = new L.map(this.mapDOM).setView([0, 0], 2)
this.basemap = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map);
// default functions
this.addMarker();
}
addMarker() {
// add user marker
this.userMarker = L.marker(this.map.getCenter(), {draggable: true});
this.userMarker.addTo(this.map);
// move marker on map click
this.map.on('click', (e) => {
this.userMarker.setLatLng([e.latlng.lat, e.latlng.lng]);
});
}
showRealPlace(coordinates) {
this.resetElements();
// show real place
this.realMarker = L.circleMarker(coordinates, {
"radius": 5,
"fillColor": "#03a9f4",
"fillOpacity": 0.8,
"color": "#03a9f4",
"weight": 1,
"opacity": 1
}).addTo(this.map);
// show polyline between your guess and a real place
let polylineCoords = [this.realMarker.getLatLng(), this.userMarker.getLatLng()];
this.polyline = L.polyline(polylineCoords, {color: 'red'}).addTo(this.map);
this.map.fitBounds(this.polyline.getBounds());
}
resetElements() {
// remove...