MAPG-97 add initial map editor with Leaflet (works as map viewer now)
This commit is contained in:
parent
a82b27cb90
commit
9085793c9f
@ -19,6 +19,10 @@ Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCol
|
|||||||
$routeCollection->get('position-json', '{mapId}/position.json', [MapGuesser\Controller\PositionController::class, 'getPosition']);
|
$routeCollection->get('position-json', '{mapId}/position.json', [MapGuesser\Controller\PositionController::class, 'getPosition']);
|
||||||
$routeCollection->post('guess-json', '{mapId}/guess.json', [MapGuesser\Controller\PositionController::class, 'evaluateGuess']);
|
$routeCollection->post('guess-json', '{mapId}/guess.json', [MapGuesser\Controller\PositionController::class, 'evaluateGuess']);
|
||||||
});
|
});
|
||||||
|
Container::$routeCollection->group('admin', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||||
|
$routeCollection->get('admin.maps', 'maps', [MapGuesser\Controller\MapAdminController::class, 'getMaps']);
|
||||||
|
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
||||||
|
});
|
||||||
|
|
||||||
$match = Container::$routeCollection->match($method, explode('/', $url));
|
$match = Container::$routeCollection->match($method, explode('/', $url));
|
||||||
|
|
||||||
|
49
public/static/css/map_editor.css
Normal file
49
public/static/css/map_editor.css
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#map {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map.selected {
|
||||||
|
height: calc(50% - 25px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#panorama {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(50% - 25px);
|
||||||
|
display: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#noPano {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
height: calc(50% - 25px);
|
||||||
|
z-index: 2;
|
||||||
|
visibility: hidden;
|
||||||
|
background: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#noPano>p {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#control {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 60px;
|
||||||
|
width: 125px;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placeControl {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: calc(50% + 35px);
|
||||||
|
width: 100px;
|
||||||
|
z-index: 3;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
108
public/static/js/map_editor.js
Normal file
108
public/static/js/map_editor.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
(function () {
|
||||||
|
var MapEditor = {
|
||||||
|
map: null,
|
||||||
|
panorama: null,
|
||||||
|
selectedMarker: null,
|
||||||
|
|
||||||
|
loadPano: function (data, status) {
|
||||||
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
if (status !== google.maps.StreetViewStatus.OK) {
|
||||||
|
document.getElementById('noPano').style.visibility = 'visible';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapEditor.panorama.setVisible(true);
|
||||||
|
MapEditor.panorama.setPov({ heading: 0, pitch: 0 });
|
||||||
|
MapEditor.panorama.setZoom(0);
|
||||||
|
MapEditor.panorama.setPano(data.location.pano);
|
||||||
|
},
|
||||||
|
|
||||||
|
select: function (marker) {
|
||||||
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
|
document.getElementById('map').classList.add('selected');
|
||||||
|
document.getElementById('noPano').style.visibility = 'hidden';
|
||||||
|
document.getElementById('panorama').style.display = 'block';
|
||||||
|
document.getElementById('placeControl').style.visibility = 'visible';
|
||||||
|
|
||||||
|
MapEditor.resetSelected();
|
||||||
|
MapEditor.selectedMarker = marker;
|
||||||
|
|
||||||
|
marker.setIcon(L.icon({
|
||||||
|
iconUrl: '/static/img/markers/marker-blue.svg',
|
||||||
|
iconSize: [24, 32],
|
||||||
|
iconAnchor: [12, 32]
|
||||||
|
}));
|
||||||
|
marker.setZIndexOffset(2000);
|
||||||
|
|
||||||
|
MapEditor.map.invalidateSize(true);
|
||||||
|
MapEditor.map.panTo(marker.getLatLng());
|
||||||
|
|
||||||
|
MapEditor.panorama.setVisible(false);
|
||||||
|
|
||||||
|
var sv = new google.maps.StreetViewService();
|
||||||
|
sv.getPanorama({ location: marker.getLatLng(), preference: google.maps.StreetViewPreference.NEAREST, source: google.maps.StreetViewSource.OUTDOOR }, MapEditor.loadPano);
|
||||||
|
},
|
||||||
|
|
||||||
|
resetSelected: function () {
|
||||||
|
if (!MapEditor.selectedMarker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapEditor.selectedMarker.setIcon(L.icon({
|
||||||
|
iconUrl: '/static/img/markers/marker-green.svg',
|
||||||
|
iconSize: [24, 32],
|
||||||
|
iconAnchor: [12, 32]
|
||||||
|
}));
|
||||||
|
MapEditor.selectedMarker.setZIndexOffset(1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MapEditor.map = L.map('map', {
|
||||||
|
attributionControl: false,
|
||||||
|
zoomControl: false
|
||||||
|
});
|
||||||
|
|
||||||
|
L.tileLayer(tileUrl, {
|
||||||
|
minZoom: 0,
|
||||||
|
maxZoom: 20
|
||||||
|
}).addTo(MapEditor.map);
|
||||||
|
|
||||||
|
MapEditor.map.fitBounds(L.latLngBounds({ lat: mapBounds.south, lng: mapBounds.west }, { lat: mapBounds.north, lng: mapBounds.east }));
|
||||||
|
|
||||||
|
for (var i = 0; i < places.length; ++i) {
|
||||||
|
var marker = L.marker({ lat: places[i].lat, lng: places[i].lng }, {
|
||||||
|
icon: L.icon({
|
||||||
|
iconUrl: '/static/img/markers/marker-green.svg',
|
||||||
|
iconSize: [24, 32],
|
||||||
|
iconAnchor: [12, 32]
|
||||||
|
}),
|
||||||
|
zIndexOffset: 1000
|
||||||
|
})
|
||||||
|
.addTo(MapEditor.map)
|
||||||
|
.on('click', function () {
|
||||||
|
MapEditor.select(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
MapEditor.panorama = new google.maps.StreetViewPanorama(document.getElementById('panorama'), {
|
||||||
|
// switch off fullscreenControl because positioning doesn't work
|
||||||
|
fullscreenControl: false,
|
||||||
|
fullscreenControlOptions: {
|
||||||
|
position: google.maps.ControlPosition.LEFT_TOP
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('cancelButton').onclick = function () {
|
||||||
|
document.getElementById('map').classList.remove('selected');
|
||||||
|
document.getElementById('noPano').style.visibility = 'hidden';
|
||||||
|
document.getElementById('panorama').style.display = 'none';
|
||||||
|
document.getElementById('placeControl').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
MapEditor.resetSelected();
|
||||||
|
MapEditor.selectedMarker = null;
|
||||||
|
|
||||||
|
MapEditor.map.invalidateSize(true);
|
||||||
|
};
|
||||||
|
})();
|
53
src/Controller/MapAdminController.php
Normal file
53
src/Controller/MapAdminController.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
|
use MapGuesser\Database\Query\Select;
|
||||||
|
use MapGuesser\Interfaces\Database\IResultSet;
|
||||||
|
use MapGuesser\Interfaces\Response\IContent;
|
||||||
|
use MapGuesser\Response\HtmlContent;
|
||||||
|
use MapGuesser\Util\Geo\Bounds;
|
||||||
|
|
||||||
|
class MapAdminController
|
||||||
|
{
|
||||||
|
public function getMaps(): IContent {
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
return new HtmlContent('admin/maps');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMapEditor(array $parameters): IContent {
|
||||||
|
$mapId = (int) $parameters['mapId'];
|
||||||
|
|
||||||
|
$bounds = $this->getMapBounds($mapId);
|
||||||
|
|
||||||
|
$places = $this->getPlaces($mapId);
|
||||||
|
|
||||||
|
$data = ['mapId' => $mapId, 'bounds' => $bounds->toArray(), 'places' => &$places];
|
||||||
|
return new HtmlContent('admin/map_editor', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMapBounds(int $mapId): Bounds
|
||||||
|
{
|
||||||
|
$select = new Select(\Container::$dbConnection, 'maps');
|
||||||
|
$select->columns(['bound_south_lat', 'bound_west_lng', 'bound_north_lat', 'bound_east_lng']);
|
||||||
|
$select->whereId($mapId);
|
||||||
|
|
||||||
|
$map = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']);
|
||||||
|
|
||||||
|
return $bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function &getPlaces(int $mapId): array
|
||||||
|
{
|
||||||
|
$select = new Select(\Container::$dbConnection, 'places');
|
||||||
|
$select->columns(['id', 'lat', 'lng']);
|
||||||
|
$select->where('map_id', '=', $mapId);
|
||||||
|
$select->orderBy('lng');
|
||||||
|
//$select->limit(100);
|
||||||
|
|
||||||
|
$places = $select->execute()->fetchAll(IResultSet::FETCH_ASSOC);
|
||||||
|
|
||||||
|
return $places;
|
||||||
|
}
|
||||||
|
}
|
27
views/admin/map_editor.php
Normal file
27
views/admin/map_editor.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php $cssFiles = ['/static/node_modules/leaflet/dist/leaflet.css', '/static/css/map_editor.css']; ?>
|
||||||
|
<?php require ROOT . '/views/templates/main_header.php'; ?>
|
||||||
|
<?php require ROOT . '/views/templates/header.php'; ?>
|
||||||
|
<div id="map"></div>
|
||||||
|
<div id="control">
|
||||||
|
<button id="saveButton" class="fullWidth">Save</button>
|
||||||
|
<a class="button gray fullWidth marginTop" href="/admin/maps" title="Back to maps">Back to maps</a>
|
||||||
|
</div>
|
||||||
|
<div id="panorama"></div>
|
||||||
|
<div id="noPano">
|
||||||
|
<p class="bold">No panorama is available for this location.</p>
|
||||||
|
</div>
|
||||||
|
<div id="placeControl">
|
||||||
|
<button id="applyButton" class="fullWidth">Apply</button>
|
||||||
|
<button id="cancelButton" class="gray fullWidth marginTop">Cancel</button>
|
||||||
|
<button id="deleteButton" class="red fullWidth marginTop">Delete</button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var tileUrl = '<?= $_ENV['LEAFLET_TILESERVER_URL'] ?>';
|
||||||
|
var mapId = '<?= $mapId ?>';
|
||||||
|
var mapBounds = <?= json_encode($bounds) ?>;
|
||||||
|
var places = <?= json_encode($places) ?>;
|
||||||
|
</script>
|
||||||
|
<script src="/static/node_modules/leaflet/dist/leaflet.js"></script>
|
||||||
|
<script src="https://maps.googleapis.com/maps/api/js?key=<?= $_ENV['GOOGLE_MAPS_JS_API_KEY'] ?>"></script>
|
||||||
|
<script src="/static/js/map_editor.js"></script>
|
||||||
|
<?php require ROOT . '/views/templates/main_footer.php'; ?>
|
7
views/admin/maps.php
Normal file
7
views/admin/maps.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php require ROOT . '/views/templates/main_header.php'; ?>
|
||||||
|
<?php require ROOT . '/views/templates/header.php'; ?>
|
||||||
|
<div class="main">
|
||||||
|
<h2>Maps</h2>
|
||||||
|
<p>TODO</p>
|
||||||
|
</div>
|
||||||
|
<?php require ROOT . '/views/templates/main_footer.php'; ?>
|
Loading…
Reference in New Issue
Block a user