diff --git a/.env.example b/.env.example
index 4cd7025..097e309 100644
--- a/.env.example
+++ b/.env.example
@@ -1,4 +1,4 @@
-DEV=true
+DEV=1
DB_HOST=mariadb
DB_USER=mapguesser
DB_PASSWORD=mapguesser
diff --git a/.gitignore b/.gitignore
index 226ca36..9bdf82a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
.env
+installed
vendor
diff --git a/install/db.sql b/db/mapguesser.sql
similarity index 100%
rename from install/db.sql
rename to db/mapguesser.sql
diff --git a/docker-compose.yml b/docker-compose.yml
index e00f9aa..3effcfe 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,7 +13,6 @@ services:
volumes:
- mysql:/var/lib/mysql
environment:
- #TZ: Europe/Budapest
MYSQL_ROOT_PASSWORD: 'root'
MYSQL_DATABASE: 'mapguesser'
MYSQL_USER: 'mapguesser'
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 16f7048..1d55371 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -4,13 +4,9 @@ ENV DEBIAN_FRONTEND noninteractive
# Install Apache, PHP and further necessary packages
RUN apt update
-RUN apt install -y curl git apache2 \
+RUN apt install -y curl git mariadb-client apache2 \
php-apcu php-xdebug php7.4-cli php7.4-fpm php7.4-mbstring php7.4-mysql php7.4-zip
-# Configure tzdata
-#RUN ln -fs /usr/share/zoneinfo/Europe/Budapest /etc/localtime
-#RUN dpkg-reconfigure --frontend noninteractive tzdata
-
# Configure Apache with PHP
RUN mkdir -p /run/php
RUN a2enmod proxy_fcgi rewrite
@@ -24,6 +20,12 @@ RUN echo "xdebug.remote_connect_back = 1" >> /etc/php/7.4/mods-available/xdebug.
COPY scripts/install-composer.sh install-composer.sh
RUN ./install-composer.sh
+# Install Node.js and required packages
+RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
+RUN apt install -y nodejs
+RUN npm install -g uglify-js
+RUN npm install -g clean-css-cli
+
EXPOSE 80
VOLUME /var/www/mapguesser
WORKDIR /var/www/mapguesser
diff --git a/docker/scripts/install-composer.sh b/docker/scripts/install-composer.sh
index f55d62e..65dbc88 100755
--- a/docker/scripts/install-composer.sh
+++ b/docker/scripts/install-composer.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-EXPECTED_CHECKSUM="$(curl -s https://composer.github.io/installer.sig)"
+EXPECTED_CHECKSUM="$(curl -sL https://composer.github.io/installer.sig)"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
diff --git a/public/index.php b/public/index.php
index 6f246a3..ee4c162 100644
--- a/public/index.php
+++ b/public/index.php
@@ -3,6 +3,7 @@
require '../main.php';
// very basic routing
+$host = $_SERVER["REQUEST_SCHEME"] . '://' . $_SERVER["SERVER_NAME"];
$url = $_SERVER['REQUEST_URI'];
switch($url) {
case '/game':
@@ -11,6 +12,9 @@ switch($url) {
case '/getNewPosition.json':
$controller = new MapGuesser\Controller\GetNewPosition();
break;
+ case '/':
+ header('Location: ' . $host . '/game', true, 302);
+ die;
default:
echo 'Error 404';
die;
diff --git a/public/static/js/mapguesser.js b/public/static/js/mapguesser.js
index 3e29009..759f25c 100644
--- a/public/static/js/mapguesser.js
+++ b/public/static/js/mapguesser.js
@@ -1,109 +1,134 @@
-Math.deg2rad = function (deg) {
- return deg * (this.PI / 180.0);
-};
+(function () {
+ var Core = {
+ MAX_SCORE: 1000,
-var Util = {
- EARTH_RADIUS_IN_METER: 6371000,
+ realPosition: null,
+ panorama: null,
+ guessMap: null,
+ guessMarker: null,
+ resultMap: null,
+ resultMarkers: { guess: null, real: null },
+ googleLink: null,
- MAX_SCORE: 1000,
+ getNewPosition: function () {
+ var xhr = new XMLHttpRequest();
+ xhr.responseType = 'json';
+ xhr.onreadystatechange = function () {
+ if (this.readyState == 4 && this.status == 200) {
+ Core.realPosition = this.response.position;
- calculateDistance: function (position1, position2) {
- var lat1 = Math.deg2rad(position1.lat);
- var lng1 = Math.deg2rad(position1.lng);
- var lat2 = Math.deg2rad(position2.lat);
- var lng2 = Math.deg2rad(position2.lng);
+ var sv = new google.maps.StreetViewService();
+ sv.getPanorama({ location: this.response.position, preference: google.maps.StreetViewPreference.NEAREST }, Core.loadPano);
+ }
+ };
+ xhr.open('GET', 'getNewPosition.json', true);
+ xhr.send();
+ },
- var angleCos = Math.cos(lat1) * Math.cos(lat2) * Math.cos(lng2 - lng1) +
- Math.sin(lat1) * Math.sin(lat2);
+ loadPano: function (data, status) {
+ if (status !== google.maps.StreetViewStatus.OK) {
+ Core.getNewPosition();
+ return;
+ }
- if (angleCos > 1.0) {
- angleCos = 1.0;
- }
+ Core.panorama.setPov({ heading: 0, pitch: 0, zoom: 1 });
+ Core.panorama.setPano(data.location.pano);
+ },
- var angle = Math.acos(angleCos);
+ calculateScore: function (distance) {
+ var goodness = 1.0 - distance / Math.sqrt(mapArea);
- return angle * Util.EARTH_RADIUS_IN_METER;
- },
+ return Math.pow(Core.MAX_SCORE, goodness);
+ },
- 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';
- }
- },
+ calculateScoreBarProperties: function (score) {
+ var percent = Math.round((score / Core.MAX_SCORE) * 100);
- calculateScore: function (distance) {
- var goodness = 1.0 - distance / Math.sqrt(mapArea);
+ var color;
+ if (percent >= 90) {
+ color = '#11ca00';
+ } else if (percent >= 10) {
+ color = '#ea9000';
+ } else {
+ color = '#ca1100';
+ }
- return Math.pow(this.MAX_SCORE, goodness);
- },
+ return { width: percent + '%', backgroundColor: color };
+ },
- calculateScoreBarProperties: function (score) {
- var percent = Math.round((score / this.MAX_SCORE) * 100);
-
- var color;
- if (percent >= 90) {
- color = '#11ca00';
- } else if (percent >= 10) {
- color = '#ea9000';
- } else {
- color = '#ca1100';
- }
-
- return { width: percent + '%', backgroundColor: color };
- }
-};
-
-var MapManipulator = {
- rewriteGoogleLink: function () {
- if (!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) {
- googleLink = a;
- break;
+ 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 () {
+ Core.googleLink.title = 'Google Maps'
+ Core.googleLink.href = 'https://maps.google.com/maps'
+ }, 1);
}
+ };
- setTimeout(function () {
- googleLink.title = 'Google Maps'
- googleLink.href = 'https://maps.google.com/maps'
- }, 1);
- }
-};
+ var Util = {
+ EARTH_RADIUS_IN_METER: 6371000,
-var realPosition;
-var panorama;
-var guessMap;
-var guessMarker;
-var resultMap;
-var resultMarkers = { guess: null, real: null };
-var googleLink;
+ deg2rad: function (deg) {
+ return deg * (Math.PI / 180.0);
+ },
-function initialize() {
- guessMap = new google.maps.Map(document.getElementById('guessMap'), {
+ calculateDistance: function (position1, position2) {
+ var lat1 = Util.deg2rad(position1.lat);
+ var lng1 = Util.deg2rad(position1.lng);
+ var lat2 = Util.deg2rad(position2.lat);
+ var lng2 = Util.deg2rad(position2.lng);
+
+ var angleCos = Math.cos(lat1) * Math.cos(lat2) * Math.cos(lng2 - lng1) +
+ Math.sin(lat1) * Math.sin(lat2);
+
+ if (angleCos > 1.0) {
+ angleCos = 1.0;
+ }
+
+ var angle = Math.acos(angleCos);
+
+ return angle * Util.EARTH_RADIUS_IN_METER;
+ },
+
+ 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';
+ }
+ }
+ };
+
+ Core.guessMap = new google.maps.Map(document.getElementById('guessMap'), {
disableDefaultUI: true,
clickableIcons: false,
draggableCursor: 'crosshair'
});
- guessMap.fitBounds(guessMapBounds);
+ Core.guessMap.fitBounds(guessMapBounds);
- guessMap.addListener('click', function (e) {
- if (guessMarker) {
- guessMarker.setPosition(e.latLng);
+ Core.guessMap.addListener('click', function (e) {
+ if (Core.guessMarker) {
+ Core.guessMarker.setPosition(e.latLng);
return;
}
- guessMarker = new google.maps.Marker({
- map: guessMap,
+ Core.guessMarker = new google.maps.Marker({
+ map: Core.guessMap,
position: e.latLng,
clickable: false,
draggable: true,
@@ -119,123 +144,98 @@ function initialize() {
document.getElementById('guessButton').disabled = false;
});
- panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
+ Core.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
disableDefaultUI: true,
linksControl: true,
showRoadLabels: false
});
- panorama.addListener('position_changed', function () {
- MapManipulator.rewriteGoogleLink();
+ Core.panorama.addListener('position_changed', function () {
+ Core.rewriteGoogleLink();
});
- panorama.addListener('pov_changed', function () {
- MapManipulator.rewriteGoogleLink();
+ Core.panorama.addListener('pov_changed', function () {
+ Core.rewriteGoogleLink();
});
- resultMap = new google.maps.Map(document.getElementById('resultMap'), {
+ Core.resultMap = new google.maps.Map(document.getElementById('resultMap'), {
disableDefaultUI: true,
clickableIcons: false,
});
- getNewPosition();
-}
+ Core.getNewPosition();
-function getNewPosition() {
- var xhr = new XMLHttpRequest();
- xhr.responseType = 'json';
- xhr.onreadystatechange = function () {
- if (this.readyState == 4 && this.status == 200) {
- realPosition = this.response.position;
-
- var sv = new google.maps.StreetViewService();
- sv.getPanorama({ location: this.response.position, preference: google.maps.StreetViewPreference.NEAREST }, loadPano);
+ document.getElementById('guessButton').onclick = function () {
+ if (!Core.guessMarker) {
+ return;
}
- };
- xhr.open('GET', 'getNewPosition.json', true);
- xhr.send();
-}
-function loadPano(data, status) {
- if (status !== google.maps.StreetViewStatus.OK) {
- getNewPosition();
- return;
+ var guessedPosition = Core.guessMarker.getPosition();
+
+ this.disabled = true;
+ Core.guessMarker.setMap(null);
+ Core.guessMarker = null;
+
+ var distance = Util.calculateDistance(Core.realPosition, { lat: guessedPosition.lat(), lng: guessedPosition.lng() });
+
+ document.getElementById('guess').style.visibility = 'hidden';
+ document.getElementById('result').style.visibility = 'visible';
+
+ var resultBounds = new google.maps.LatLngBounds();
+ resultBounds.extend(Core.realPosition);
+ resultBounds.extend(guessedPosition);
+
+ Core.resultMap.fitBounds(resultBounds);
+
+ Core.resultMarkers.real = new google.maps.Marker({
+ map: Core.resultMap,
+ position: Core.realPosition,
+ clickable: true,
+ draggable: false
+ });
+ Core.resultMarkers.guess = new google.maps.Marker({
+ map: Core.resultMap,
+ position: guessedPosition,
+ clickable: false,
+ draggable: false,
+ label: {
+ color: '#ffffff',
+ fontFamily: 'Roboto',
+ fontSize: '18px',
+ fontWeight: '500',
+ text: '?'
+ }
+ });
+
+ Core.resultMarkers.real.addListener('click', function () {
+ window.open('https://www.google.com/maps/search/?api=1&query=' + Core.realPosition.lat + ',' + Core.realPosition.lng, '_blank');
+ });
+
+ document.getElementById('distance').innerHTML = Util.printDistanceForHuman(distance);
+
+ var score = Core.calculateScore(distance);
+ var scoreBarProperties = Core.calculateScoreBarProperties(score);
+
+ document.getElementById('score').innerHTML = Number.parseFloat(score).toFixed(0);
+
+ var scoreBar = document.getElementById('scoreBar');
+ scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
+ scoreBar.style.width = scoreBarProperties.width;
}
- panorama.setPov({heading: 0, pitch: 0, zoom: 1});
- panorama.setPano(data.location.pano);
-}
+ document.getElementById('continueButton').onclick = function () {
+ document.getElementById('scoreBar').style.width = '0';
-document.getElementById('guessButton').onclick = function () {
- if (!guessMarker) {
- return;
+ Core.resultMarkers.real.setMap(null);
+ Core.resultMarkers.real = null;
+ Core.resultMarkers.guess.setMap(null);
+ Core.resultMarkers.guess = null;
+
+ document.getElementById('guess').style.visibility = 'visible';
+ document.getElementById('result').style.visibility = 'hidden';
+
+ Core.guessMap.fitBounds(guessMapBounds);
+
+ Core.getNewPosition();
}
-
- var guessedPosition = guessMarker.getPosition();
-
- this.disabled = true;
- guessMarker.setMap(null);
- guessMarker = null;
-
- var distance = Util.calculateDistance(realPosition, { lat: guessedPosition.lat(), lng: guessedPosition.lng() });
-
- document.getElementById('guess').style.visibility = 'hidden';
- document.getElementById('result').style.visibility = 'visible';
-
- var resultBounds = new google.maps.LatLngBounds();
- resultBounds.extend(realPosition);
- resultBounds.extend(guessedPosition);
-
- resultMap.fitBounds(resultBounds);
-
- resultMarkers.real = new google.maps.Marker({
- map: resultMap,
- position: realPosition,
- clickable: true,
- draggable: false
- });
- resultMarkers.guess = new google.maps.Marker({
- map: resultMap,
- position: guessedPosition,
- clickable: false,
- draggable: false,
- label: {
- color: '#ffffff',
- fontFamily: 'Roboto',
- fontSize: '18px',
- fontWeight: '500',
- text: '?'
- }
- });
-
- resultMarkers.real.addListener('click', function () {
- window.open('https://www.google.com/maps/search/?api=1&query=' + realPosition.lat + ',' + realPosition.lng, '_blank');
- });
-
- document.getElementById('distance').innerHTML = Util.printDistanceForHuman(distance);
-
- var score = Util.calculateScore(distance);
- var scoreBarProperties = Util.calculateScoreBarProperties(score);
-
- document.getElementById('score').innerHTML = Number.parseFloat(score).toFixed(0);
-
- var scoreBar = document.getElementById('scoreBar');
- scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
- scoreBar.style.width = scoreBarProperties.width;
-}
-
-document.getElementById('continueButton').onclick = function () {
- document.getElementById('scoreBar').style.width = '0';
-
- resultMarkers.real.setMap(null);
- resultMarkers.real = null;
- resultMarkers.guess.setMap(null);
- resultMarkers.guess = null;
-
- document.getElementById('guess').style.visibility = 'visible';
- document.getElementById('result').style.visibility = 'hidden';
-
- guessMap.fitBounds(guessMapBounds);
-
- getNewPosition();
-}
+})();
diff --git a/scripts/install.sh b/scripts/install.sh
new file mode 100755
index 0000000..ce97ff9
--- /dev/null
+++ b/scripts/install.sh
@@ -0,0 +1,23 @@
+#/bin/bash
+
+ROOT_DIR=$(dirname $(readlink -f "$0"))/..
+
+. ${ROOT_DIR}/.env
+
+if [ -f ${ROOT_DIR}/installed ]; then
+ echo "Mapguesser is already installed! To force reinstall, delete file 'installed' from the root directory!"
+ exit 1
+fi
+
+echo "Installing MapGuesser DB..."
+
+mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/db/mapguesser.sql
+
+if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
+ echo "Uglifying JS and CSS files..."
+
+ uglifyjs ${ROOT_DIR}/public/static/js/mapguesser.js -c -m -o ${ROOT_DIR}/public/static/js/mapguesser.js
+ cleancss ${ROOT_DIR}/public/static/css/mapguesser.css -o ${ROOT_DIR}/public/static/css/mapguesser.css
+fi
+
+touch ${ROOT_DIR}/installed
diff --git a/scripts/update.sh b/scripts/update.sh
new file mode 100755
index 0000000..56e2c1d
--- /dev/null
+++ b/scripts/update.sh
@@ -0,0 +1,12 @@
+#/bin/bash
+
+ROOT_DIR=$(dirname $(readlink -f "$0"))/..
+
+. ${ROOT_DIR}/.env
+
+if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
+ echo "Uglifying JS and CSS files..."
+
+ uglifyjs ${ROOT_DIR}/public/static/js/mapguesser.js -c -m -o ${ROOT_DIR}/public/static/js/mapguesser.js
+ cleancss ${ROOT_DIR}/public/static/css/mapguesser.css -o ${ROOT_DIR}/public/static/css/mapguesser.css
+fi
diff --git a/views/game.php b/views/game.php
index 333ce16..ee1fb8b 100644
--- a/views/game.php
+++ b/views/game.php
@@ -35,7 +35,7 @@
var mapArea = = $bounds->calculateApproximateArea() ?>;
var guessMapBounds = = $bounds->toJson() ?>;
+
-