Compare commits

...
Author SHA1 Message Date
bence 398204c5d5 Merge pull request 'feature/place-streetview-cover-to-the-map' (#35) from feature/place-streetview-cover-to-the-map into develop
default-pipeline default-pipeline #162
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/35
2021-05-02 16:27:41 +02:00
bence aaa5a1daba Merge pull request 'bugfix/streetviewcontrol-is-still-visible' (#34) from bugfix/streetviewcontrol-is-still-visible into develop
default-pipeline default-pipeline #161
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/34
2021-05-02 16:27:34 +02:00
bence c112a25409 move street view cover button to the map as circleControl
default-pipeline default-pipeline #160
2021-05-02 15:04:14 +02:00
bence 35cab17c21 make circle control items more general 2021-05-02 15:04:14 +02:00
bence f9c1829a00 enable zoomControl for Leaflet map to be consistent with Google map
default-pipeline default-pipeline #157
2021-05-02 13:45:34 +02:00
bence e03850ce05 switch off streetViewControl explicitly 2021-05-02 13:42:46 +02:00
bence 55ec226407 Merge pull request 'feature/google-maps-in-mapeditor-added' (#33) from feature/google-maps-in-mapeditor-added into develop
default-pipeline default-pipeline #155
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/33
Reviewed-by: Pőcze Bence <bence@pocze.ch>
2021-05-02 13:38:17 +02:00
bence 6ef04fcd4e fit both google and leaflet map to bounds if map already exists
default-pipeline default-pipeline #154
2021-05-02 13:29:48 +02:00
bence 3045d8acbb remove builtin streetViewControl from google map 2021-05-02 13:13:11 +02:00
balazs 19a1b79b0a toggling of street view cover added
default-pipeline default-pipeline #153
2021-05-02 12:56:25 +02:00
balazs d432a5b584 cleaned up the comment 2021-05-02 12:34:57 +02:00
balazs 8b9345eb36 removed unused css declarations; renamed invalidateSize to resize 2021-05-02 12:34:57 +02:00
balazs e1eb0077b1 hide the map selection and jump to location elements on mobile view 2021-05-02 12:34:57 +02:00
balazs 745bda11c0 refactoring and bug fixing related to the map switching 2021-05-02 12:34:57 +02:00
balazs 0bb31cbe14 added switching functionality between maps in mapeditor 2021-05-02 12:34:57 +02:00
balazs ef8ad69506 organised Leaflet map and Google Maps into wrappers 2021-05-02 12:23:37 +02:00
bence f10ad37a74 Merge pull request 'update readme' (#32) from feature/update-readme into develop
default-pipeline default-pipeline #152
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/32
2021-04-29 20:03:19 +02:00
bence 70b60d2fb8 create the first user during installation in development mode 2021-04-29 20:02:00 +02:00
bence 7e68580db6 update readme 2021-04-29 20:01:42 +02:00
balazs 8218883faf Merge pull request 'Feature In-Game Compass' (#27) from feature/in-game-compass into develop
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/27
Reviewed-by: Pőcze Bence <bence@pocze.ch>
2021-04-29 19:15:44 +02:00
balazs 145cb5f637 Merge branch 'develop' into feature/in-game-compass
default-pipeline default-pipeline #151
2021-04-29 19:00:11 +02:00
balazs 6d3f74f911 increased the left margin for mobile view
default-pipeline default-pipeline #150
2021-04-29 18:59:24 +02:00
balazs 3d663fb5d6 Merge pull request 'Quickfix for single player game cannot be restarted' (#30) from bugfix/quickfix-for-single-play-cannot-be-restarted into develop
default-pipeline default-pipeline #149
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/30
Reviewed-by: Pőcze Bence <bence@pocze.ch>
2021-04-29 18:55:58 +02:00
balazs 759f654a0d Merge pull request 'feature/return-to-starting-point-button' (#26) from feature/return-to-starting-point-button into develop
default-pipeline default-pipeline #148
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/26
Reviewed-by: Pőcze Bence <bence@pocze.ch>
2021-04-29 18:55:22 +02:00
bence c09cce3c97 Merge pull request 'MAPG-167 set background color' (#31) from feature/MAPG-167-set-background-color into develop
default-pipeline default-pipeline #147
Reviewed-on: https://gitea.e5tv.hu/esoko/mapguesser/pulls/31
2021-04-29 18:46:26 +02:00
bence 276e331a47 MAPG-167 set background color
default-pipeline default-pipeline #146
2021-04-29 18:43:30 +02:00
balazs 62f4fd7b84 readyToContinue is true by default and set to false only in the multigame initializing
default-pipeline default-pipeline #145
2021-04-29 13:57:32 +02:00
balazs b22f13887f clicking on compass sets the heading direction to north
default-pipeline default-pipeline #144
2021-04-29 12:39:44 +02:00
balazs 2a3f2212a7 replaced span with div for the compass item
default-pipeline default-pipeline #143
2021-04-29 12:12:17 +02:00
balazs 98df08e5fa Merge branch 'feature/return-to-starting-point-button' into feature/in-game-compass 2021-04-29 12:10:02 +02:00
balazs 8f0cfd4489 replaced spans with divs again and fixed the css issue
default-pipeline default-pipeline #142
2021-04-29 12:08:04 +02:00
balazs d42280eb10 only the image is rotated, not the whole div
default-pipeline default-pipeline #141
2021-04-29 09:18:24 +02:00
balazs 0739c65961 Merge branch 'feature/return-to-starting-point-button' into feature/in-game-compass 2021-04-29 09:11:32 +02:00
balazs 3122696364 added the visibility reset to resetRound and reverted the span div replacement in the view
default-pipeline default-pipeline #140
2021-04-29 09:07:44 +02:00
balazs 462f6cde80 Merge branch 'feature/return-to-starting-point-button' of gitea.e5tv.hu:esoko/mapguesser into feature/return-to-starting-point-button
default-pipeline default-pipeline #139
2021-04-29 09:05:32 +02:00
balazs 3f4fa83d87 reverted replacing spans with divs 2021-04-29 09:04:50 +02:00
balazs ea599809b8 Merge branch 'feature/return-to-starting-point-button' into feature/in-game-compass 2021-04-29 08:34:39 +02:00
balazs f0b0de405c Merge branch 'develop' into feature/return-to-starting-point-button
default-pipeline default-pipeline #138
2021-04-29 08:25:52 +02:00
balazs ffc4aaf110 fixed findings
default-pipeline default-pipeline #137
2021-04-29 08:24:20 +02:00
balazs 08c38c6374 reverted style tailoring for guess
default-pipeline default-pipeline #129
2021-04-28 20:46:52 +02:00
balazs 854775011c tailored the style for the navigation buttons
default-pipeline default-pipeline #128
2021-04-28 20:42:42 +02:00
balazs e33d8c02e9 added compass button and coupled its transform:rotate style attribute with the POV heading value 2021-04-28 20:33:17 +02:00
balazs 3d52c967b6 reformatted: added new line breaks to the game.css
default-pipeline default-pipeline #127
2021-04-28 18:30:58 +02:00
balazs 5c8f3d6fb9 returns to start when clicked on home symbol
default-pipeline default-pipeline #126
2021-04-28 18:26:46 +02:00
balazs b9927f79fc added a new button to the view for the return to starting point feature 2021-04-28 17:58:48 +02:00
19 changed files with 530 additions and 96 deletions

No files matched your search

+36 -9
View File
@@ -14,7 +14,7 @@ git clone https://gitea.e5tv.hu/esoko/mapguesser.git
All the commands listed here should be executed from the repository root.
### (Optional) Setup Docker stack
### Setup Docker stack (recommended)
The easiest way to build up a fully working application with web server and database is to use Docker Compose with the included `docker-compose.yml`.
@@ -24,9 +24,17 @@ All you have to do is executing the following command:
docker-compose up -d
```
Attach shell to the container of `mapguesser_app`. All of the following commands should be executed there.
Attach shell to the container of `mapguesser_app`:
**If you don't use the Docker stack you need to install your environment manually. Check `docker-compose.yml` and `docker/Dockerfile` to see the system requirements.**
```
docker exec -it mapguesser_app_1 bash
```
All of the following commands should be executed there.
### Manual setup (alternative)
If you don't use the Docker stack you need to install your environment manually. Check `docker-compose.yml` and `docker/Dockerfile` to see the system requirements.
### Initialize project
@@ -40,15 +48,28 @@ composer create-project
The `.env` file contains several environment variables that are needed by the application to work properly. These should be configured for your environment.
**You should set here the API keys that enable playing the game. Without these API keys the application cannot work well. To get Google API keys visit this page: https://console.developers.google.com/**
One very important variable is `DEV`. This indicates that the application operates in development (staging) and not in production mode.
One very important variable is `DEV`. This indicates that the application operates in development (staging) and not in produciton mode.
**Hint:** If you install the application in the Docker stack for development (staging) environment, only the variables for external dependencies (API keys, map attribution, etc.) should be adapted. All other variables (for DB connection, static root, mailing, multiplayer, etc.) are fine with the default value.
If you install the application in the Docker stack for development (staging) environment, only the variables for external dependencies (API keys, map attribution, etc.) should be adapted. All other variables (for DB connection, static root, mailing, etc.) are fine with the default value.
#### API keys
**You should set the API keys that enable playing the game. Without these API keys the application cannot work well. To get Google API keys visit this page: https://console.developers.google.com/**
Required Google APIs:
* **Maps JavaScript API**: for the interactive maps and street views
* **Maps Static API**: for the static map images
* **Street View Static API**: for the backend metadata requests
Required API keys:
* **GOOGLE_MAPS_SERVER_API_KEY**: this it used by the backend and should have access to **Street View Static API**
* **GOOGLE_MAPS_JS_API_KEY**: this is used by the frontend and should have access to **Maps JavaScript API** and **Maps Static API**
Additionally, a tile provider is also needed for map editor. This should be configured by `LEAFLET_TILESERVER_URL` and `LEAFLET_TILESERVER_ATTRIBUTION`. You can find some providers here: https://wiki.openstreetmap.org/wiki/Tile_servers. OpenStreetMap's tile server is fine for testing.
### (Production only) Create cron job
To maintain database (delete inactive users, old sessions etc.), the command `db:maintain` should be regularly executed. It is recommened to create a cron job that runs every hour:
To maintain database (delete inactive users, old sessions etc.), the command `db:maintain` should be regularly executed. It is recommended to create a cron job that runs every hour:
```
0 * * * * /path/to/your/installation/mapg db:maintain >>/var/log/cron-mapguesser.log 2>&1
@@ -56,13 +77,19 @@ To maintain database (delete inactive users, old sessions etc.), the command `db
### Finalize installation
After you set the environment variables in the `.env` file, execute the following command:
After you followed the above steps, execute the following command:
```
scripts/install.sh
```
**And you are done!** The application is ready to use and develop.
**Warning: Because of a known issue the image `mapguesser_multi` fails to run without the installation steps. You have to relauch `docker-compose up -d` after you finished the installation process.**
**And you are done!** The application is ready to use and develop. In development mode an administrative user is also created by the installation script, email is **mapg@mapg.dev**, password is **123456**. In production mode you should create the first administrative user with the following command:
```
./mapg user:add EMAIL PASSWORD admin
```
If you installed it in the Docker stack, you can reach it on http://localhost. The mails that are sent by the application can be found on http://localhost:8080/. If needed, the database server can be directly reached on localhost:3306.
+17 -1
View File
@@ -149,13 +149,17 @@
color: #701919;
}
#navigation {
z-index: 2;
}
@media screen and (max-width: 599px) {
#mapName {
display: none;
}
#showGuessButtonContainer {
position: absolute;
left: 20px;
left: 65px;
bottom: 30px;
right: 20px;
z-index: 2;
@@ -172,6 +176,10 @@
#scoreBarBase {
width: 100%;
}
#navigation {
bottom: 25px;
left: 10px;
}
}
@media screen and (min-width: 600px) {
@@ -215,6 +223,10 @@
#scoreBarBase {
width: 60%;
}
#navigation {
bottom: 50px;
left: 20px;
}
@media screen and (max-height: 424px) {
#guess {
top: 10px;
@@ -229,5 +241,9 @@
right: 20px;
bottom: 30px;
}
#navigation {
bottom: 30px;
left: 10px;
}
}
}
+17 -1
View File
@@ -1,4 +1,4 @@
#map {
.map {
position: absolute;
top: 0;
left: 0;
@@ -7,6 +7,13 @@
z-index: 1;
}
#mapSelection img {
display: inline;
width: 1em;
height: 1em;
vertical-align: -0.15em;
}
/* modify the cursor for the Leaflet map */
.leaflet-container {
cursor: crosshair;
@@ -48,6 +55,12 @@
visibility: hidden;
}
#overlayControl {
bottom: 20px;
right: 10px;
z-index: 3;
}
#deleteButton {
display: none;
}
@@ -65,6 +78,9 @@
#placeControl {
top: calc(50% + 10px);
}
.hideOnMobile {
display: none;
}
}
@media screen and (min-width: 1000px), (max-height: 599px) {
+54
View File
@@ -12,6 +12,10 @@ html, body {
padding: 0;
}
body {
background-color: #cccccc;
}
button::-moz-focus-inner, input::-moz-focus-inner {
padding: 0;
border: 0;
@@ -374,6 +378,7 @@ header>p>span:not(:last-child) {
}
main {
background-color: #ffffff;
padding: 6px 12px;
}
@@ -438,6 +443,43 @@ div.box {
box-sizing: border-box;
}
.circleControl {
position: absolute;
width: 60px;
bottom: 20px;
right: 10px;
}
.circleControl .controlItem {
height: 60px;
margin-top: 10px;
opacity: 70%;
cursor: pointer;
}
.circleControl .controlItem:hover {
opacity: 100%;
}
.circleControl .controlItem div {
position: absolute;
}
.circleControl .controlBackground {
width: 100%;
height: 100%;
opacity: 50%;
}
.circleControl .controlIcon {
width: 75%;
height: 75%;
margin: auto;
margin-top: 50%;
transform: translateY(-50%);
-ms-transform: translateY(-50%);
}
@media screen and (max-width: 599px) {
header h1 span {
display: none;
@@ -464,6 +506,12 @@ div.box {
div.box {
width: initial;
}
.circleControl {
width: 45px;
}
.circleControl .controlItem {
height: 45px;
}
}
@media screen and (min-width: 600px) {
@@ -493,6 +541,12 @@ div.box {
padding-top: 10px;
padding-bottom: 10px;
}
.circleControl {
width: 45px;
}
.circleControl .controlItem {
height: 45px;
}
}
@media screen and (min-height: 400px) and (max-height: 499px) {
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 16 16">
<circle cx="50%" cy="50%" r="50%" fill="black" />
</svg>

After

Width:  |  Height:  |  Size: 146 B

+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<polygon id="needleNorth" points="50,0 33,50 66,50" style="fill:red;stroke:black;stroke-width:1" />
<polygon id="needleSouth" points="50,100 33,50 66,50" style="fill:white;stroke:black;stroke-width:1" />
Sorry, your browser does not support inline SVG.
</svg>

After

Width:  |  Height:  |  Size: 328 B

+5
View File
@@ -0,0 +1,5 @@
<!-- Original image: Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="#3183ce" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="m8 3.293 6 6V13.5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5V9.293l6-6zm5-.793V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"/>
<path fill-rule="evenodd" d="M7.293 1.5a1 1 0 0 1 1.414 0l6.647 6.646a.5.5 0 0 1-.708.708L8 2.207 1.354 8.854a.5.5 0 1 1-.708-.708L7.293 1.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 556 B

+4
View File
@@ -0,0 +1,4 @@
<!-- Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
<svg xmlns="http://www.w3.org/2000/svg" fill="#ffffff" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15.817.113A.5.5 0 0 1 16 .5v14a.5.5 0 0 1-.402.49l-5 1a.502.502 0 0 1-.196 0L5.5 15.01l-4.902.98A.5.5 0 0 1 0 15.5v-14a.5.5 0 0 1 .402-.49l5-1a.5.5 0 0 1 .196 0L10.5.99l4.902-.98a.5.5 0 0 1 .415.103zM10 1.91l-4-.8v12.98l4 .8V1.91zm1 12.98 4-.8V1.11l-4 .8v12.98zm-6-.8V1.11l-4 .8v12.98l4-.8z"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
<!-- Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
<svg xmlns="http://www.w3.org/2000/svg" fill="#ffffff" viewBox="0 0 16 16">
<path d="m14.12 10.163 1.715.858c.22.11.22.424 0 .534L8.267 15.34a.598.598 0 0 1-.534 0L.165 11.555a.299.299 0 0 1 0-.534l1.716-.858 5.317 2.659c.505.252 1.1.252 1.604 0l5.317-2.66zM7.733.063a.598.598 0 0 1 .534 0l7.568 3.784a.3.3 0 0 1 0 .535L8.267 8.165a.598.598 0 0 1-.534 0L.165 4.382a.299.299 0 0 1 0-.535L7.733.063z"/>
<path d="m14.12 6.576 1.715.858c.22.11.22.424 0 .534l-7.568 3.784a.598.598 0 0 1-.534 0L.165 7.968a.299.299 0 0 1 0-.534l1.716-.858 5.317 2.659c.505.252 1.1.252 1.604 0l5.317-2.659z"/>
</svg>

After

Width:  |  Height:  |  Size: 718 B

+27 -2
View File
@@ -17,7 +17,7 @@
adaptGuess: false,
googleLink: null,
readyToContinue: false,
readyToContinue: true,
timeoutEnd: null,
countdownHandler: null,
@@ -97,6 +97,8 @@
},
initialize: function (data) {
Game.readyToContinue = false;
if (data.history.length === 0 && !data.place) {
var div = document.getElementById('players');
@@ -334,6 +336,9 @@
document.getElementById('guess').style.visibility = null;
document.getElementById('guess').classList.remove('result');
// needs to be set visible after the show guess map hid it in mobile view
document.getElementById("navigation").style.visibility = 'visible';
Game.initialize();
},
@@ -358,7 +363,10 @@
document.getElementById('panoCover').style.visibility = 'hidden';
document.getElementById('showGuessButton').style.visibility = null;
document.getElementById('guess').style.visibility = null;
document.getElementById('guess').classList.remove('result')
document.getElementById('guess').classList.remove('result');
// needs to be set visible after the show guess map hid it in mobile view
document.getElementById("navigation").style.visibility = 'visible';
Game.map.setOptions({
draggableCursor: 'crosshair'
@@ -379,6 +387,10 @@
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
Game.loadPano(Game.panoId, Game.pov);
// update the compass
const heading = Game.panorama.getPov().heading;
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
},
handleErrorResponse: function (error) {
@@ -855,6 +867,9 @@
Game.panorama.addListener('pov_changed', function () {
Game.rewriteGoogleLink();
const heading = Game.panorama.getPov().heading;
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
});
if (COOKIES_CONSENT) {
@@ -864,11 +879,13 @@
document.getElementById('showGuessButton').onclick = function () {
this.style.visibility = 'hidden';
document.getElementById('guess').style.visibility = 'visible';
document.getElementById('navigation').style.visibility = 'hidden';
}
document.getElementById('closeGuessButton').onclick = function () {
document.getElementById('showGuessButton').style.visibility = null;
document.getElementById('guess').style.visibility = null;
document.getElementById('navigation').style.visibility = 'visible';
}
document.getElementById('guessButton').onclick = function () {
@@ -936,4 +953,12 @@
}
});
}
document.getElementById('returnToStart').onclick = function () {
Game.loadPano(Game.panoId, Game.pov);
}
document.getElementById('compassContainer').onclick = function () {
Game.panorama.setPov({ heading: 0, pitch: Game.panorama.getPov().pitch });
}
})();
+300 -81
View File
@@ -7,7 +7,6 @@
description: null
},
map: null,
markers: null,
panorama: null,
selectedMarker: null,
added: {},
@@ -118,16 +117,13 @@
MapEditor.resetSelected();
MapEditor.selectedMarker = marker;
MapEditor.map.invalidateSize(true);
MapEditor.map.resize();
MapEditor.map.panTo(marker.getLatLng());
MapEditor.panorama.setVisible(false);
if (marker.placeId) {
MapEditor.markers.removeLayer(MapEditor.selectedMarker);
MapEditor.map.addLayer(MapEditor.selectedMarker);
marker.setIcon(IconCollection.iconBlue);
marker.setZIndexOffset(2000);
MapEditor.map.changeMarkerIcon(marker, MapEditor.map.iconCollection.iconBlue);
document.getElementById('deleteButton').style.display = 'block';
@@ -165,13 +161,13 @@
var placeId = MapEditor.selectedMarker.placeId
if (places[placeId].id && !del) {
MapEditor.map.removeLayer(MapEditor.selectedMarker);
MapEditor.markers.addLayer(MapEditor.selectedMarker);
MapEditor.selectedMarker.setIcon(places[placeId].noPano ? IconCollection.iconRed : IconCollection.iconGreen);
MapEditor.selectedMarker.setZIndexOffset(1000);
MapEditor.map.changeMarkerIcon(
MapEditor.selectedMarker,
places[placeId].noPano ? MapEditor.map.iconCollection.iconRed : MapEditor.map.iconCollection.iconGreen
);
} else {
delete places[placeId];
MapEditor.map.removeLayer(MapEditor.selectedMarker);
MapEditor.map.removeMarker(MapEditor.selectedMarker);
}
document.getElementById('deleteButton').style.display = 'none';
@@ -223,7 +219,7 @@
MapEditor.resetSelected(del);
MapEditor.selectedMarker = null;
MapEditor.map.invalidateSize(true);
MapEditor.map.resize();
},
deletePlace: function () {
@@ -239,6 +235,7 @@
delete MapEditor.added[placeId];
delete MapEditor.edited[placeId];
delete places[placeId];
document.getElementById('added').innerHTML = String(Object.keys(MapEditor.added).length);
document.getElementById('edited').innerHTML = String(Object.keys(MapEditor.edited).length);
@@ -310,42 +307,9 @@
var placeId = addedPlaces[i].id;
places[tempId].id = placeId;
}
},
// TODO: check whether marker is already existing on the map for the coordinates
// or alternatively block saving for matching coordinates
placeMarker: function (latlng) {
var marker = L.marker(latlng, {
icon: IconCollection.iconBlue,
zIndexOffset: 2000
})
.addTo(MapEditor.map)
.on('click', function () {
MapEditor.select(this);
});
MapEditor.select(marker);
}
};
var IconCollection = {
iconGreen: L.icon({
iconUrl: STATIC_ROOT + '/img/markers/marker-green.svg?rev' + REVISION,
iconSize: [24, 32],
iconAnchor: [12, 32]
}),
iconRed: L.icon({
iconUrl: STATIC_ROOT + '/img/markers/marker-red.svg?rev=' + REVISION,
iconSize: [24, 32],
iconAnchor: [12, 32]
}),
iconBlue: L.icon({
iconUrl: STATIC_ROOT + '/img/markers/marker-blue.svg?rev=' + REVISION,
iconSize: [24, 32],
iconAnchor: [12, 32]
}),
};
var Util = {
getHighResData: function () {
if (window.devicePixelRatio >= 4) {
@@ -384,52 +348,290 @@
}
};
MapEditor.map = L.map('map', {
zoomControl: false
});
var LMapWrapper = {
map: null,
markers: null,
divId: null,
iconCollection: {
iconGreen: L.icon({
iconUrl: STATIC_ROOT + '/img/markers/marker-green.svg?rev' + REVISION,
iconSize: [24, 32],
iconAnchor: [12, 32]
}),
iconRed: L.icon({
iconUrl: STATIC_ROOT + '/img/markers/marker-red.svg?rev=' + REVISION,
iconSize: [24, 32],
iconAnchor: [12, 32]
}),
iconBlue: L.icon({
iconUrl: STATIC_ROOT + '/img/markers/marker-blue.svg?rev=' + REVISION,
iconSize: [24, 32],
iconAnchor: [12, 32]
})
},
MapEditor.map.on('click', function (e) {
MapEditor.placeMarker(e.latlng);
});
init: function (divId, places) {
document.getElementById(divId).style.display = "block";
var highResData = Util.getHighResData();
if (!LMapWrapper.map) {
LMapWrapper.divId = divId;
LMapWrapper.map = L.map(LMapWrapper.divId, {
center: { lat: 0., lng: 0. },
zoom: 2
});
L.tileLayer(tileUrl, {
attribution: tileAttribution,
subdomains: '1234',
ppi: highResData.ppi,
tileSize: highResData.tileSize,
zoomOffset: highResData.zoomOffset,
minZoom: highResData.minZoom,
maxZoom: highResData.maxZoom
}).addTo(MapEditor.map);
LMapWrapper.map.on('click', function (e) {
LMapWrapper.placeMarker(e.latlng);
});
MapEditor.map.fitBounds(L.latLngBounds({ lat: mapBounds.south, lng: mapBounds.west }, { lat: mapBounds.north, lng: mapBounds.east }));
var highResData = Util.getHighResData();
MapEditor.markers = L.markerClusterGroup({
maxClusterRadius: 50
});
L.tileLayer(tileUrl, {
attribution: tileAttribution,
subdomains: '1234',
ppi: highResData.ppi,
tileSize: highResData.tileSize,
zoomOffset: highResData.zoomOffset,
minZoom: highResData.minZoom,
maxZoom: highResData.maxZoom
}).addTo(LMapWrapper.map);
for (var placeId in places) {
if (!places.hasOwnProperty(placeId)) {
continue;
}
if (mapId) {
LMapWrapper.map.fitBounds(L.latLngBounds({ lat: mapBounds.south, lng: mapBounds.west }, { lat: mapBounds.north, lng: mapBounds.east }));
}
}
var place = places[placeId];
LMapWrapper.loadMarkers(places);
var marker = L.marker({ lat: place.lat, lng: place.lng }, {
icon: place.noPano ? IconCollection.iconRed : IconCollection.iconGreen,
zIndexOffset: 1000
})
.addTo(MapEditor.markers)
.on('click', function () {
document.getElementById('streetViewCoverSelector').style.display = 'none';
},
hide: function () {
document.getElementById(LMapWrapper.divId).style.display = 'none';
},
loadMarkers: function (places) {
if (!LMapWrapper.markers) {
LMapWrapper.markers = L.markerClusterGroup({
maxClusterRadius: 50
});
} else {
LMapWrapper.markers.clearLayers();
}
for (var placeId in places) {
if (!places.hasOwnProperty(placeId)) {
continue;
}
var place = places[placeId];
var marker = L.marker({ lat: place.lat, lng: place.lng }, {
icon: place.noPano ? LMapWrapper.iconCollection.iconRed : LMapWrapper.iconCollection.iconGreen,
zIndexOffset: 1000
})
.addTo(LMapWrapper.markers)
.on('click', function () {
MapEditor.select(this);
});
marker.placeId = placeId;
}
LMapWrapper.map.addLayer(LMapWrapper.markers);
},
// TODO: check whether marker is already existing on the map for the coordinates
// or alternatively block saving for matching coordinates
placeMarker: function (latLng) {
var marker = L.marker(latLng, {
icon: LMapWrapper.iconCollection.iconBlue,
zIndexOffset: 2000
})
.addTo(LMapWrapper.markers)
.on('click', function () {
MapEditor.select(this);
});
MapEditor.select(marker);
},
panTo: function (latLng) {
LMapWrapper.map.panTo(latLng);
},
resize: function () {
LMapWrapper.map.invalidateSize(true);
},
changeMarkerIcon: function (marker, icon) {
marker.setIcon(icon);
marker.setZIndexOffset(2000);
},
removeMarker: function (marker) {
LMapWrapper.markers.removeLayer(marker);
},
toggleStreetViewCover: function () { }
};
var GMapWrapper = {
map: null,
markers: null,
divId: null,
streetViewCover: null,
streetViewCoverOn: false,
iconCollection: {
iconGreen: {
url: STATIC_ROOT + '/img/markers/marker-green.svg?rev' + REVISION,
scaledSize: new google.maps.Size(24, 32), // scaled size
origin: new google.maps.Point(0, 0), // origin
anchor: new google.maps.Point(12, 32) // anchor
},
iconRed: {
url: STATIC_ROOT + '/img/markers/marker-red.svg?rev' + REVISION,
scaledSize: new google.maps.Size(24, 32), // scaled size
origin: new google.maps.Point(0, 0), // origin
anchor: new google.maps.Point(12, 32) // anchor
},
iconBlue: {
url: STATIC_ROOT + '/img/markers/marker-blue.svg?rev' + REVISION,
scaledSize: new google.maps.Size(24, 32), // scaled size
origin: new google.maps.Point(0, 0), // origin
anchor: new google.maps.Point(12, 32) // anchor
}
},
init: function (divId, places) {
document.getElementById(divId).style.display = "block";
if (!GMapWrapper.map) {
GMapWrapper.divId = divId;
GMapWrapper.map = new google.maps.Map(document.getElementById(GMapWrapper.divId), {
center: { lat: 0., lng: 0. },
zoom: 2,
fullscreenControl: false,
zoomControl: true,
zoomControlOptions: {
position: google.maps.ControlPosition.LEFT_BOTTOM
},
streetViewControl: false,
draggableCursor: 'crosshair'
});
GMapWrapper.streetViewCover = new google.maps.StreetViewCoverageLayer();
GMapWrapper.map.addListener('click', function (mapsMouseEvent) {
GMapWrapper.placeMarker({
lat: mapsMouseEvent.latLng.lat(),
lng: mapsMouseEvent.latLng.lng()
});
});
if (mapId) {
GMapWrapper.map.fitBounds({ south: mapBounds.south, west: mapBounds.west, north: mapBounds.north, east: mapBounds.east });
}
}
GMapWrapper.loadMarkers(places);
document.getElementById('streetViewCoverSelector').style.display = 'block'
},
hide: function () {
document.getElementById(GMapWrapper.divId).style.display = 'none';
},
loadMarkers: function (places) {
if (!GMapWrapper.markers) {
GMapWrapper.markers = new MarkerClusterer(GMapWrapper.map, [], {
imagePath: STATIC_ROOT + '/img/markers/m',
imageExtension: 'png?rev' + REVISION
});
} else {
GMapWrapper.markers.clearMarkers();
}
for (var placeId in places) {
if (!places.hasOwnProperty(placeId)) {
continue;
}
var place = places[placeId];
var marker = new google.maps.Marker({
position: {
lat: place.lat,
lng: place.lng
},
icon: place.noPano ? GMapWrapper.iconCollection.iconRed : GMapWrapper.iconCollection.iconGreen
});
marker.getLatLng = function () { return { lat: this.getPosition().lat(), lng: this.getPosition().lng() } };
marker.setLatLng = function (coords) { this.setPosition(coords) };
marker.addListener('click', function () {
MapEditor.select(this);
});
marker.placeId = placeId;
GMapWrapper.markers.addMarker(marker);
}
},
// TODO: check whether marker is already existing on the map for the coordinates
// or alternatively block saving for matching coordinates
placeMarker: function (latLng) {
var marker = new google.maps.Marker({
map: GMapWrapper.map,
position: latLng,
icon: GMapWrapper.iconCollection.iconBlue,
});
marker.getLatLng = function () { return { lat: this.getPosition().lat(), lng: this.getPosition().lng() } };
marker.setLatLng = function (coords) { this.setPosition(coords) };
marker.addListener('click', function () {
MapEditor.select(this);
});
marker.placeId = place.id;
}
GMapWrapper.markers.addMarker(marker);
MapEditor.map.addLayer(MapEditor.markers);
MapEditor.select(marker);
},
panTo: function (latLng) {
GMapWrapper.map.panTo(latLng);
},
resize: function () {
google.maps.event.trigger(GMapWrapper.map, 'resize');
},
changeMarkerIcon: function (marker, icon) {
marker.setIcon(icon);
},
removeMarker: function (marker) {
GMapWrapper.markers.removeMarker(marker);
},
toggleStreetViewCover: function () {
if (GMapWrapper.streetViewCoverOn) {
GMapWrapper.streetViewCover.setMap(null);
GMapWrapper.streetViewCoverOn = false;
} else {
GMapWrapper.streetViewCover.setMap(GMapWrapper.map);
GMapWrapper.streetViewCoverOn = true;
}
}
};
// initialize content of #map with google maps
MapEditor.map = GMapWrapper;
MapEditor.map.init('gmap', places);
MapEditor.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
// switch off fullscreenControl because positioning doesn't work
@@ -478,7 +680,7 @@
var coordinates = Util.extractCoordinates(coordinatesStr);
if (coordinates.valid) {
MapEditor.placeMarker(coordinates.latlng);
MapEditor.map.placeMarker(coordinates.latlng);
}
};
@@ -491,7 +693,7 @@
jumpButton.disabled = false;
if (e.key == 'Enter') {
MapEditor.placeMarker(coordinates.latlng);
MapEditor.map.placeMarker(coordinates.latlng);
}
}
else {
@@ -499,4 +701,21 @@
}
};
document.getElementById('mapSelector').onclick = function () {
MapEditor.closePlace();
MapEditor.map.hide();
if (MapEditor.map === GMapWrapper) {
MapEditor.map = LMapWrapper;
MapEditor.map.init('lmap', places);
} else {
MapEditor.map = GMapWrapper;
MapEditor.map.init('gmap', places);
}
}
document.getElementById('streetViewCoverSelector').onclick = function () {
MapEditor.map.toggleStreetViewCover();
}
})();
+3
View File
@@ -27,6 +27,9 @@ if [ -z "${DEV}" ] || [ "${DEV}" -eq "0" ]; then
echo "Linking view files..."
(cd ${ROOT_DIR} && ./mapg view:link)
else
echo "Creating the first user..."
(cd ${ROOT_DIR} && ./mapg user:add mapg@mapg.dev 123456 admin)
fi
touch ${ROOT_DIR}/installed
+21 -2
View File
@@ -6,13 +6,19 @@
@js(node_modules/leaflet/dist/leaflet.js)
@js(node_modules/leaflet.markercluster/dist/leaflet.markercluster.js)
@js(https://maps.googleapis.com/maps/api/js?key=<?= $_ENV['GOOGLE_MAPS_JS_API_KEY'] ?>)
@js(https://unpkg.com/@googlemaps/markerclustererplus/dist/index.min.js)
@js(js/map_editor.js)
@extends(templates/layout_full)
@section(subheader)
<span><a href="javascript:;" id="mapName" title="Edit map data"><?= $mapName ?></a></span><!--
--><span>
--><span class="inline hideOnMobile" id="mapSelection">
<button id="mapSelector">
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/map.svg?rev=<?= REVISION ?>" alt="Map Selector" />
</button>
</span><!--
--><span class="inline hideOnMobile">
<input type="text" id="jumpCoordinates" placeholder="Insert coordinates here" />
<button id="jumpButton" disabled >Jump</button>
</span><!--
@@ -57,7 +63,20 @@
@endsection
@section(main)
<div id="map"></div>
<div id="map" class="map">
<div id="lmap" class="map"></div>
<div id="gmap" class="map"></div>
<div id="overlayControl" class="circleControl">
<div id="streetViewCoverSelector" class="controlItem" title="Toggle Street View Cover">
<div>
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="controlBackground" />
</div>
<div>
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/street-view-cover.svg?rev=<?= REVISION ?>" alt="Street View Cover" class="controlIcon" />
</div>
</div>
</div>
</div>
<div id="panorama"></div>
<div id="noPano">
<p class="bold">No panorama is available for this location.</p>
+18
View File
@@ -59,6 +59,24 @@
<button id="startNewGameButton" class="fullWidth">Play this map again</button>
</div>
</div>
<div id="navigation" class="circleControl">
<div id="compassContainer" class="controlItem">
<div>
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="controlBackground" />
</div>
<div>
<img id="compass" src="<?= $_ENV['STATIC_ROOT'] ?>/img/compass.svg?rev=<?= REVISION ?>" alt="compass icon" class="controlIcon" />
</div>
</div>
<div id="returnToStart" class="controlItem">
<div>
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="controlBackground" />
</div>
<div>
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/house-fill.svg?rev=<?= REVISION ?>" alt="Return to Start icon" class="controlIcon" />
</div>
</div>
</div>
@endsection
@section(pageScript)