diff --git a/public/static/css/map_editor.css b/public/static/css/map_editor.css index 59f2315..1b46865 100644 --- a/public/static/css/map_editor.css +++ b/public/static/css/map_editor.css @@ -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; @@ -65,6 +72,9 @@ #placeControl { top: calc(50% + 10px); } + .hideOnMobile { + display: none; + } } @media screen and (min-width: 1000px), (max-height: 599px) { diff --git a/public/static/img/map.svg b/public/static/img/map.svg new file mode 100644 index 0000000..c4edd4f --- /dev/null +++ b/public/static/img/map.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/static/img/markers/m1.png b/public/static/img/markers/m1.png new file mode 100644 index 0000000..82878cb --- /dev/null +++ b/public/static/img/markers/m1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5118720be739d6eaaa6c5e9dfce3c6ba3f15838ba5aa5dfec6687bc24bc4413e +size 3003 diff --git a/public/static/img/markers/m2.png b/public/static/img/markers/m2.png new file mode 100644 index 0000000..496bb3a --- /dev/null +++ b/public/static/img/markers/m2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1ce96fbdfb658c7f14701d93e70b8c7f46cdf10ea8e797b016234fffccbc0171 +size 3259 diff --git a/public/static/img/markers/m3.png b/public/static/img/markers/m3.png new file mode 100644 index 0000000..2ff0fe7 --- /dev/null +++ b/public/static/img/markers/m3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c96a9b48cf0552997f5441b091c62a4389169af4d73f986b3d59c3d938e7a787 +size 3956 diff --git a/public/static/img/markers/m4.png b/public/static/img/markers/m4.png new file mode 100644 index 0000000..af756d0 --- /dev/null +++ b/public/static/img/markers/m4.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c01ee5f7e1f833c80f2404f95b90840a702f12db8ae7fa8e8dbb0dec7e73a42 +size 5705 diff --git a/public/static/img/markers/m5.png b/public/static/img/markers/m5.png new file mode 100644 index 0000000..af50f44 --- /dev/null +++ b/public/static/img/markers/m5.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67835702e2a302a178bb6de042ae860e30df5bb41d6f6853902d879ad8bd4ac6 +size 6839 diff --git a/public/static/img/street-view-cover.svg b/public/static/img/street-view-cover.svg new file mode 100644 index 0000000..393ff4f --- /dev/null +++ b/public/static/img/street-view-cover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/static/js/map_editor.js b/public/static/js/map_editor.js index 097b0d8..f2cfa04 100644 --- a/public/static/js/map_editor.js +++ b/public/static/js/map_editor.js @@ -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, + zoomControl: false + }); - 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').disabled = true; + }, + + 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 + }, + 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').disabled = false; + }, + + 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(); + } + })(); diff --git a/views/admin/map_editor.php b/views/admin/map_editor.php index c6de87b..1510b6d 100644 --- a/views/admin/map_editor.php +++ b/views/admin/map_editor.php @@ -6,13 +6,24 @@ @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=) +@js(https://unpkg.com/@googlemaps/markerclustererplus/dist/index.min.js) @js(js/map_editor.js) @extends(templates/layout_full) @section(subheader) + --> + + + +