From 92c35a208713d611b6cd0976cc8f4158efff3353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sat, 30 May 2020 15:33:28 +0200 Subject: [PATCH 1/9] MAPG-73 pass mapId to GameController and PositionController adapt JS to send mapId make separate JS for the game --- public/index.php | 11 +++-- public/static/js/{mapguesser.js => game.js} | 6 +-- src/Controller/GameController.php | 10 ++--- src/Controller/PositionController.php | 10 +++-- src/Util/Geo/Bounds.php | 49 ++++++--------------- views/game.php | 3 +- 6 files changed, 38 insertions(+), 51 deletions(-) rename public/static/js/{mapguesser.js => game.js} (98%) diff --git a/public/index.php b/public/index.php index aa06a8a..a4cc7f8 100644 --- a/public/index.php +++ b/public/index.php @@ -3,20 +3,23 @@ require '../main.php'; // very basic routing -$host = $_SERVER["REQUEST_SCHEME"] . '://' . $_SERVER["SERVER_NAME"]; +$host = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME']; $url = $_SERVER['REQUEST_URI']; if (($pos = strpos($url, '?')) !== false) { $url = substr($url, 0, $pos); } switch($url) { case '/game': - $controller = new MapGuesser\Controller\GameController(); + $mapId = isset($_GET['map']) ? (int) $_GET['map'] : 0; + $controller = new MapGuesser\Controller\GameController($mapId); break; case '/game.json': - $controller = new MapGuesser\Controller\GameController(true); + $mapId = isset($_GET['map']) ? (int) $_GET['map'] : 0; + $controller = new MapGuesser\Controller\GameController($mapId, true); break; case '/position.json': - $controller = new MapGuesser\Controller\PositionController(); + $mapId = isset($_GET['map']) ? (int) $_GET['map'] : 0; + $controller = new MapGuesser\Controller\PositionController($mapId); break; case '/': header('Location: ' . $host . '/game', true, 302); diff --git a/public/static/js/mapguesser.js b/public/static/js/game.js similarity index 98% rename from public/static/js/mapguesser.js rename to public/static/js/game.js index e31507e..20a5c4b 100644 --- a/public/static/js/mapguesser.js +++ b/public/static/js/game.js @@ -51,7 +51,7 @@ Core.startNewRound(); }; - xhr.open('GET', 'position.json', true); + xhr.open('GET', 'position.json?map=' + mapId, true); xhr.send(); }, @@ -127,7 +127,7 @@ Core.resetGame(); }; - xhr.open('GET', 'game.json', true); + xhr.open('GET', 'game.json?map=' + mapId, true); xhr.send(); }, @@ -200,7 +200,7 @@ Core.panoId = this.response.panoId; }; - xhr.open('POST', 'position.json', true); + xhr.open('POST', 'position.json?map=' + mapId, true); xhr.send(data); }, diff --git a/src/Controller/GameController.php b/src/Controller/GameController.php index 9f38af2..c1174f4 100644 --- a/src/Controller/GameController.php +++ b/src/Controller/GameController.php @@ -10,13 +10,13 @@ use MapGuesser\Interfaces\View\IView; class GameController implements IController { + private int $mapId; + private bool $jsonResponse; - // demo map - private int $mapId = 1; - - public function __construct($jsonResponse = false) + public function __construct(int $mapId, $jsonResponse = false) { + $this->mapId = $mapId; $this->jsonResponse = $jsonResponse; } @@ -32,7 +32,7 @@ class GameController implements IController ]; } - $data = ['bounds' => $bounds->toArray()]; + $data = ['mapId' => $this->mapId, 'bounds' => $bounds->toArray()]; if ($this->jsonResponse) { return new JsonView($data); diff --git a/src/Controller/PositionController.php b/src/Controller/PositionController.php index eca8311..cddee8d 100644 --- a/src/Controller/PositionController.php +++ b/src/Controller/PositionController.php @@ -13,8 +13,12 @@ class PositionController implements IController const NUMBER_OF_ROUNDS = 5; const MAX_SCORE = 1000; - // demo map - private int $mapId = 1; + private int $mapId; + + public function __construct(int $mapId) + { + $this->mapId = $mapId; + } public function run(): IView { @@ -120,7 +124,7 @@ class PositionController implements IController $select->where('id', 'NOT IN', $exclude); $select->where('map_id', '=', $this->mapId); - $numberOfPlaces = $select->count(); + $numberOfPlaces = $select->count();// TODO: what if 0 $randomOffset = random_int(0, $numberOfPlaces - 1); $select->orderBy('id'); diff --git a/src/Util/Geo/Bounds.php b/src/Util/Geo/Bounds.php index 7b448be..1edfb8b 100644 --- a/src/Util/Geo/Bounds.php +++ b/src/Util/Geo/Bounds.php @@ -4,21 +4,25 @@ class Bounds { const ONE_DEGREE_OF_LATITUDE_IN_METER = 111132.954; - private float $southLat; - private float $westLng; + private float $southLat = 90.0; + private float $westLng = 180.0; - private float $northLat; - private float $eastLng; + private float $northLat = -90.0; + private float $eastLng = -180.0; - private bool $initialized = false; - - public static function createWithPosition(Position $position): Bounds + public function __construct(Position $position = null) { - $instance = new static(); + if ($position === null) { + return; + } - $instance->initialize($position); + $lat = $position->getLat(); + $lng = $position->getLng(); - return $instance; + $this->northLat = $lat; + $this->westLng = $lng; + $this->southLat = $lat; + $this->eastLng = $lng; } public static function createDirectly(float $southLat, float $westLng, float $northLat, float $eastLng): Bounds @@ -30,19 +34,11 @@ class Bounds $instance->northLat = $northLat; $instance->eastLng = $eastLng; - $instance->initialized = true; - return $instance; } public function extend(Position $position): void { - if (!$this->initialized) { - $this->initialize($position); - - return; - } - $lat = $position->getLat(); $lng = $position->getLng(); @@ -77,10 +73,6 @@ class Bounds public function toArray(): array { - if (!$this->initialized) { - throw new \Exception("Bounds are not initialized!"); - } - return [ 'south' => $this->southLat, 'west' => $this->westLng, @@ -93,17 +85,4 @@ class Bounds { return json_encode($this->toArray()); } - - private function initialize(Position $position) - { - $lat = $position->getLat(); - $lng = $position->getLng(); - - $this->northLat = $lat; - $this->westLng = $lng; - $this->southLat = $lat; - $this->eastLng = $lng; - - $this->initialized = true; - } } diff --git a/views/game.php b/views/game.php index fee7284..49447d3 100644 --- a/views/game.php +++ b/views/game.php @@ -48,9 +48,10 @@ - + From 9ffedf60305c68f25d9db9be8e49fc9f680016bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sat, 30 May 2020 15:37:26 +0200 Subject: [PATCH 2/9] MAPG-73 introduce map selection unify CSS --- public/index.php | 5 +- public/static/css/mapguesser.css | 188 ++++++++++++++++++++++++------ src/Controller/MapsController.php | 60 ++++++++++ views/game.php | 8 +- views/maps.php | 57 +++++++++ 5 files changed, 275 insertions(+), 43 deletions(-) create mode 100644 src/Controller/MapsController.php create mode 100644 views/maps.php diff --git a/public/index.php b/public/index.php index a4cc7f8..0d592cc 100644 --- a/public/index.php +++ b/public/index.php @@ -9,6 +9,9 @@ if (($pos = strpos($url, '?')) !== false) { $url = substr($url, 0, $pos); } switch($url) { + case '/maps': + $controller = new MapGuesser\Controller\MapsController(); + break; case '/game': $mapId = isset($_GET['map']) ? (int) $_GET['map'] : 0; $controller = new MapGuesser\Controller\GameController($mapId); @@ -22,7 +25,7 @@ switch($url) { $controller = new MapGuesser\Controller\PositionController($mapId); break; case '/': - header('Location: ' . $host . '/game', true, 302); + header('Location: ' . $host . '/maps', true, 302); die; default: echo 'Error 404'; diff --git a/public/static/css/mapguesser.css b/public/static/css/mapguesser.css index 2d09895..e80aba9 100644 --- a/public/static/css/mapguesser.css +++ b/public/static/css/mapguesser.css @@ -12,13 +12,35 @@ html, body { padding: 0; } -p, button { +p, h1, h2, button, a { font-family: 'Roboto', sans-serif; } +h1, h2 { + font-weight: 500; +} + +h1 { + font-size: 32px; + line-height: inherit; +} + +h2 { + font-size: 24px; +} + +p, h2 { + line-height: 150%; +} + p { font-weight: 300; - font-size: 12px; + font-size: 16px; +} + +img { + display: block; + max-width: 100%; } .mono { @@ -29,7 +51,37 @@ p { font-weight: 500; } -button { +.small { + font-size: 12px; +} + +.justify { + text-align: justify; +} + +.marginTop { + margin-top: 10px; +} + +.marginBottom { + margin-bottom: 10px; +} + +svg.inline { + vertical-align: -0.15em; +} + +a:link, a:visited { + color: #3b5998; + font-weight: 500; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +button, a.button { cursor: pointer; font-size: 16px; font-weight: 500; @@ -39,11 +91,15 @@ button { height: 35px; border: none; border-radius: 3px; + display: inline-block; + text-align: center; + line-height: 35px; } -button:enabled:hover, button:enabled:focus { +button:enabled:hover, button:enabled:focus, a.button:hover, a.button:focus { background-color: #29457f; outline: none; + text-decoration: none; } button:disabled { @@ -52,33 +108,78 @@ button:disabled { opacity: 0.7; } -button.fullWidth { +button.fullWidth, a.button.fullWidth { padding: 0; width: 100%; } -button.gray { +button.gray, a.button.gray { background-color: #808080; } -button.gray:hover, button.gray:focus { +button.gray:hover, button.gray:focus, a.button.gray:hover, a.button.gray:focus { background-color: #555555; } +div.header { + background-color: #333333; + height: 50px; + line-height: 50px; + padding: 0 12px; + color: white; +} + +div.main { + padding: 6px 12px; +} + div.buttonContainer { height: 35px; } -div.buttonContainer > button { +div.buttonContainer>button { margin: 0 auto; } -div.buttonContainer.top { - margin-bottom: 10px; +div.mapContainer { + display: grid; } -div.buttonContainer.bottom { - margin-top: 10px; +div.mapItem { + width: 375px; + background-color: #eeeeee; + border-radius: 3px; + margin: 10px auto; +} + +div.mapItem>div.title { + background-color: #28a745; + color: white; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + padding: 4px 8px; +} + +div.mapItem>div.title>p.title { + font-weight: 500; + font-size: 18px; +} + +div.mapItem>div.inner { + padding: 8px; +} + +div.mapItem>div.inner>div.info { + display: grid; + grid-template-columns: auto auto; +} + +div.mapItem>div.inner>div.info>p:nth-child(1) { + text-align: left; +} + +div.mapItem>div.inner>div.info>p:nth-child(2) { + text-align: right; } #loading { @@ -108,11 +209,12 @@ div.buttonContainer.bottom { #roundInfo p { font-size: 16px; + line-height: inherit; } #panorama { - height: 100%; width: 100%; + height: 100%; z-index: 1; } @@ -123,16 +225,15 @@ div.buttonContainer.bottom { z-index: 2; } -#guess > #continueButtonContainer { +#guess>#continueButtonContainer { display: none; } -#guess.result > #closeGuessButtonContainer, -#guess.result > #guessButtonContainer { +#guess.result>#closeGuessButtonContainer, #guess.result>#guessButtonContainer { display: none; } -#guess.result > #continueButtonContainer { +#guess.result>#continueButtonContainer { display: block; } @@ -141,14 +242,14 @@ div.buttonContainer.bottom { border-radius: 3px; } -#guess.result > #map { +#guess.result>#map { height: calc(100% - 170px); } #resultInfo { margin-top: 5px; - height: 120px; width: 100%; + height: 120px; padding: 5px 20px; text-align: center; box-sizing: border-box; @@ -157,13 +258,13 @@ div.buttonContainer.bottom { display: none; } -#guess.result > #resultInfo { +#guess.result>#resultInfo { display: block; } -#resultInfo > div { - height: 33.33%; +#resultInfo>div { width: 100%; + height: 33.33%; display: flex; justify-content: center; align-items: center; @@ -171,9 +272,10 @@ div.buttonContainer.bottom { #resultInfo p { font-size: 24px; + line-height: 1; } -#distanceInfo > p:nth-child(2), #scoreInfo > p:nth-child(2) { +#distanceInfo>p:nth-child(2), #scoreInfo>p:nth-child(2) { display: none; } @@ -185,8 +287,8 @@ div.buttonContainer.bottom { } #scoreBar { - height: 100%; width: 0; + height: 100%; border-radius: 3px; transition-property: width; transition-duration: 2.0s; @@ -196,12 +298,35 @@ div.buttonContainer.bottom { display: none; } +@media screen and (min-width: 1600px) { + div.mapContainer { + grid-template-columns: auto auto auto auto; + } +} + +@media screen and (min-width: 1200px) and (max-width: 1599px) { + div.mapContainer { + grid-template-columns: auto auto auto; + } +} + +@media screen and (min-width: 800px) and (max-width: 1199px) { + div.mapContainer { + grid-template-columns: auto auto; + } +} + +@media screen and (max-width: 799px) { + div.mapContainer { + grid-template-columns: auto; + } +} + @media screen and (max-width: 599px) { button { padding: 0; width: 100%; } - #showGuessButtonContainer { position: absolute; left: 20px; @@ -209,18 +334,15 @@ div.buttonContainer.bottom { right: 20px; z-index: 2; } - #guess { left: 20px; top: 40px; opacity: 0.95; visibility: hidden; } - #map { height: calc(100% - 90px); } - #scoreBarBase { width: 100%; } @@ -230,13 +352,11 @@ div.buttonContainer.bottom { #showGuessButtonContainer { display: none; } - #guess { width: 500px; height: 375px; opacity: 0.95; } - #guess.adapt { top: initial; width: 250px; @@ -246,22 +366,18 @@ div.buttonContainer.bottom { transition-duration: 0.1s; transition-delay: 0.8s; } - #guess.adapt:hover { width: 500px; height: 375px; opacity: 0.95; transition-delay: 0s; } - #closeGuessButtonContainer { display: none; } - #map { height: calc(100% - 45px); } - #guess.result { width: initial; height: initial; @@ -270,22 +386,18 @@ div.buttonContainer.bottom { right: 50px; bottom: 50px; } - #scoreBarBase { width: 60%; } - @media screen and (max-height: 424px) { #guess { top: 40px; height: initial; } - #guess.adapt:hover { top: 40px; height: initial; } - #guess.result { left: 20px; right: 20px; diff --git a/src/Controller/MapsController.php b/src/Controller/MapsController.php new file mode 100644 index 0000000..f6c46c3 --- /dev/null +++ b/src/Controller/MapsController.php @@ -0,0 +1,60 @@ +columns([ + ['maps', 'id'], + ['maps', 'name'], + ['maps', 'description'], + ['maps', 'bound_south_lat'], + ['maps', 'bound_west_lng'], + ['maps', 'bound_north_lat'], + ['maps', 'bound_east_lng'], + new RawExpression('COUNT(places.id) AS num_places') + ]); + $select->leftJoin('places', ['places', 'map_id'], '=', ['maps', 'id']); + $select->orderBy('name'); + + $result = $select->execute(); + + $maps = []; + while ($map = $result->fetch(IResultSet::FETCH_ASSOC)) { + $bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']); + + $map['area'] = $this->formatMapArea($bounds->calculateApproximateArea()); + + $maps[] = $map; + } + + $data = ['maps' => $maps]; + return new HtmlView('maps', $data); + } + + private function formatMapArea(float $area): string + { + //TODO: this should be formatted more properly + + if ($area < 100000.0) { + return round($area, 0) . ' m^2'; + } elseif ($area < 100000000.0) { + return round($area / 1000000.0, 0) . ' km^2'; + } elseif ($area < 10000000000.0) { + return round($area / 1000000.0, -2) . ' km^2'; + } else { + return round($area / 1000000.0, -4) . ' km^2'; + } + } +} diff --git a/views/game.php b/views/game.php index 49447d3..16a387c 100644 --- a/views/game.php +++ b/views/game.php @@ -19,11 +19,11 @@
-
+
-
+
@@ -41,10 +41,10 @@
-
+
- +
From 77238a6ead66bef98ddd4cca2fb53ac60590c855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sat, 30 May 2020 20:39:15 +0200 Subject: [PATCH 9/9] MAPG-83 format area value with decimal separator and superscript in unit --- public/static/css/mapguesser.css | 15 +++++++++++++++ src/Controller/MapsController.php | 28 +++++++++++++++++----------- views/maps.php | 2 +- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/public/static/css/mapguesser.css b/public/static/css/mapguesser.css index 56bd909..1effcbd 100644 --- a/public/static/css/mapguesser.css +++ b/public/static/css/mapguesser.css @@ -54,6 +54,21 @@ img { display: block; } +sup, sub { + position: relative; + font-size: smaller; +} + +sup { + vertical-align: top; + top: -0.4em; +} + +sub { + vertical-align: bottom; + bottom: -0.4em; +} + .mono { font-family: 'Roboto Mono', monospace; } diff --git a/src/Controller/MapsController.php b/src/Controller/MapsController.php index f6c46c3..569d667 100644 --- a/src/Controller/MapsController.php +++ b/src/Controller/MapsController.php @@ -1,6 +1,4 @@ -fetch(IResultSet::FETCH_ASSOC)) { $bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']); - $map['area'] = $this->formatMapArea($bounds->calculateApproximateArea()); + $map['area'] = $this->formatMapAreaForHuman($bounds->calculateApproximateArea()); $maps[] = $map; } @@ -43,18 +41,26 @@ class MapsController implements IController return new HtmlView('maps', $data); } - private function formatMapArea(float $area): string + private function formatMapAreaForHuman(float $area): array { - //TODO: this should be formatted more properly - if ($area < 100000.0) { - return round($area, 0) . ' m^2'; + $digits = 0; + $rounded = round($area, 0); + $unit = 'm'; } elseif ($area < 100000000.0) { - return round($area / 1000000.0, 0) . ' km^2'; + $digits = 0; + $rounded = round($area / 1000000.0, 0); + $unit = 'km'; } elseif ($area < 10000000000.0) { - return round($area / 1000000.0, -2) . ' km^2'; + $digits = 0; + $rounded = round($area / 1000000.0, -2); + $unit = 'km'; } else { - return round($area / 1000000.0, -4) . ' km^2'; + $digits = 0; + $rounded = round($area / 1000000.0, -4); + $unit = 'km'; } + + return [number_format($rounded, $digits, '.', ' '), $unit]; } } diff --git a/views/maps.php b/views/maps.php index 5367c8d..2df5482 100644 --- a/views/maps.php +++ b/views/maps.php @@ -44,7 +44,7 @@ - ~ + ~ 2