Skip to content
Snippets Groups Projects
Commit 241c3d16 authored by Lene Wasskog's avatar Lene Wasskog
Browse files

feat: Zoom to me, coordinates for new point

parent c8814797
Branches
No related tags found
1 merge request!191Add map module and Open-Meteo support
...@@ -31,6 +31,13 @@ ...@@ -31,6 +31,13 @@
z-index: 1100; z-index: 1100;
} }
#zoomToMyLocationButton {
position: absolute;
top: 10px;
left: 50px;
z-index: 1100;
}
#confirmButton { #confirmButton {
margin-top: 10px; margin-top: 10px;
} }
...@@ -59,7 +66,7 @@ ...@@ -59,7 +66,7 @@
color: #ddd; color: #ddd;
} }
#pointForm { #newPointForm {
z-index: 1200; z-index: 1200;
position: absolute; position: absolute;
} }
......
...@@ -3,7 +3,9 @@ import { ...@@ -3,7 +3,9 @@ import {
map, map,
tileLayer, tileLayer,
geoJSON, geoJSON,
circleMarker, GeoJSON, circleMarker,
marker,
GeoJSON,
DomEvent DomEvent
} from 'https://unpkg.com/leaflet/dist/leaflet-src.esm.js'; } from 'https://unpkg.com/leaflet/dist/leaflet-src.esm.js';
...@@ -56,7 +58,8 @@ class MapModal { ...@@ -56,7 +58,8 @@ class MapModal {
maxZoom: 19 maxZoom: 19
}).addTo(this.map); }).addTo(this.map);
this.createSelectedPointInfo(); this.setUpSelectedPointInfoPanel();
this.setUpZoomToCurrentLocation();
// Add points to the map // Add points to the map
geoJSON(this.geoJsonData, { geoJSON(this.geoJsonData, {
...@@ -90,7 +93,7 @@ class MapModal { ...@@ -90,7 +93,7 @@ class MapModal {
/** /**
* Create information panel for selected point, initially hidden. * Create information panel for selected point, initially hidden.
*/ */
createSelectedPointInfo() { setUpSelectedPointInfoPanel() {
const selectedPointInfoHtml = ` const selectedPointInfoHtml = `
<div id="selectedPointInfo" style="display: none;"> <div id="selectedPointInfo" style="display: none;">
<div id="infoMessage"></div> <div id="infoMessage"></div>
...@@ -99,6 +102,32 @@ class MapModal { ...@@ -99,6 +102,32 @@ class MapModal {
document.getElementById(this.mapContainerId).insertAdjacentHTML('beforeend', selectedPointInfoHtml); document.getElementById(this.mapContainerId).insertAdjacentHTML('beforeend', selectedPointInfoHtml);
} }
setUpZoomToCurrentLocation() {
const zoomButtonHtml = `<button id="zoomToMyLocationButton" class="btn btn-primary">Zoom til meg</button>`;
document.getElementById(this.mapContainerId).insertAdjacentHTML('beforeend', zoomButtonHtml);
let zoomButton = document.getElementById('zoomToMyLocationButton')
DomEvent.disableClickPropagation(zoomButton);
zoomButton.addEventListener('click', () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
this.map.setView([latitude, longitude], 13);
// Add a marker at the user's location
const userLocationMarker = marker([latitude, longitude]).addTo(this.map);
}, (error) => {
console.error('Geolocation failed: ' + error.message);
alert('Unable to retrieve your location.');
});
} else {
alert('Geolocation is not supported by this browser.');
}
});
}
/** /**
* Display the panel which contains information about the currently selected point, * Display the panel which contains information about the currently selected point,
* and a button to bring you back to the original page. * and a button to bring you back to the original page.
...@@ -129,12 +158,7 @@ class MapModal { ...@@ -129,12 +158,7 @@ class MapModal {
} }
getFeatureById(pointOfInterestId) { getFeatureById(pointOfInterestId) {
let feature = this.geoJsonData.features.find(feature => feature.properties.pointOfInterestId == pointOfInterestId); return this.geoJsonData.features.find(feature => feature.properties.pointOfInterestId == pointOfInterestId);
if (!feature) {
console.info("Feature with id=" + pointOfInterestId + " not found, assume that the user wants the newly created", this.createdPoints[0]);
return this.createdPoints.length > 0 ? this.createdPoints[0] : null;
}
return feature;
} }
getLayerById(pointOfInterestId) { getLayerById(pointOfInterestId) {
...@@ -148,12 +172,6 @@ class MapModal { ...@@ -148,12 +172,6 @@ class MapModal {
}); });
} }
}); });
if (!result) {
console.info("Layer with id=" + pointOfInterestId + " not found, assume that the user wants the newly created", this.createdPointLayer);
this.createdPointLayer.eachLayer((layer) => {
result = layer;
});
}
return result; return result;
} }
...@@ -213,49 +231,41 @@ class MapModal { ...@@ -213,49 +231,41 @@ class MapModal {
// If a form already exists, remove it // If a form already exists, remove it
this.closeNewPointFormIfOpen(); this.closeNewPointFormIfOpen();
// Calculate the pixel position from the map's click event // Calculate the pixel position from the map's click event
const containerPoint = this.map.latLngToContainerPoint(latlng); const containerPoint = this.map.latLngToContainerPoint(latlng);
const newPointFormElement = this.addHtmlElementNewPointForm(containerPoint.x, containerPoint.y, latlng.lat, latlng.lng)
// Show form for creating a new point // Click inside the form should not propagate to underlying map
const formHtml = ` DomEvent.disableClickPropagation(newPointFormElement);
<div id="pointForm" class="panel panel-default" style="top: ${containerPoint.y}px; left: ${containerPoint.x}px;">
<div class="panel-heading">
<h3 class="panel-title">Create new point</h3>
</div>
<div class="panel-body">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" name="name" autofocus>
</div>
<div class="form-group">
<label for="poiTypeSelect">Type:</label>
<select class="form-control" id="poiTypeSelect" name="poiTypeSelect">
<option value="2">${this.typeNameMap[2]}</option>
<option value="3">${this.typeNameMap[3]}</option>
<option value="5">${this.typeNameMap[5]}</option>
</select>
</div>
<div class="form-group text-right">
<button id="savePointButton" class="btn btn-primary">Save</button>
</div>
</div>
</div>`;
document.getElementById(this.mapContainerId).insertAdjacentHTML('beforeend', formHtml);
const formElement = document.getElementById('pointForm');
DomEvent.disableClickPropagation(formElement);
// Add event listener to close the form if clicked outside // Add event listener to close the form if clicked outside
document.addEventListener('click', this.handleClickOutsidePointForm.bind(this), true); document.addEventListener('click', this.handleClickOutsidePointForm.bind(this), true);
document.getElementById('savePointButton').addEventListener('click', () => { const nameInput = newPointFormElement.querySelector('#name');
this.savePoint(latlng.lat, latlng.lng); const latitudeInput = newPointFormElement.querySelector('#latitude');
const longitudeInput = newPointFormElement.querySelector('#longitude');
const typeInput = newPointFormElement.querySelector('#type');
const submitButton = newPointFormElement.querySelector('#submit-button');
const validateInputs = () => {
const isValidLat = !isNaN(parseFloat(latitudeInput.value)) && isFinite(latitudeInput.value);
const isValidLng = !isNaN(parseFloat(longitudeInput.value)) && isFinite(longitudeInput.value);
submitButton.disabled = !(isValidLat && isValidLng);
};
latitudeInput.addEventListener('input', validateInputs);
longitudeInput.addEventListener('input', validateInputs);
validateInputs();
submitButton.addEventListener('click', () => {
this.removeExistingNewPoint();
this.setNewPointAsSelected(nameInput.value, parseFloat(latitudeInput.value), parseFloat(longitudeInput.value), parseInt(typeInput.value, 10));
newPointFormElement.remove();
}); });
}); });
} }
handleClickOutsidePointForm(event) { handleClickOutsidePointForm(event) {
const formElement = document.getElementById('pointForm'); const formElement = document.getElementById('newPointForm');
// If the clicked element is not inside the form, close the form // If the clicked element is not inside the form, close the form
if (formElement && !formElement.contains(event.target)) { if (formElement && !formElement.contains(event.target)) {
...@@ -264,7 +274,7 @@ class MapModal { ...@@ -264,7 +274,7 @@ class MapModal {
} }
closeNewPointFormIfOpen() { closeNewPointFormIfOpen() {
const formElement = document.getElementById('pointForm'); const formElement = document.getElementById('newPointForm');
if (formElement) { if (formElement) {
formElement.remove(); formElement.remove();
} }
...@@ -273,16 +283,17 @@ class MapModal { ...@@ -273,16 +283,17 @@ class MapModal {
document.removeEventListener('click', this.handleClickOutsidePointForm.bind(this), true); document.removeEventListener('click', this.handleClickOutsidePointForm.bind(this), true);
} }
createFeatureForPoint(lng, lat, poiName, poiType) { createFeatureForPoint(longitude, latitude, name, type) {
console.info("Create feature for [" + longitude + "," + latitude + "," + name + "," + type + "]");
return { return {
"type": "Feature", "type": "Feature",
"geometry": { "geometry": {
"type": "Point", "type": "Point",
"coordinates": [lng, lat] "coordinates": [longitude, latitude]
}, },
"properties": { "properties": {
"pointOfInterestName": poiName, "pointOfInterestName": name,
"pointOfInterestTypeId": poiType "pointOfInterestTypeId": type
} }
}; };
} }
...@@ -307,33 +318,21 @@ class MapModal { ...@@ -307,33 +318,21 @@ class MapModal {
}).addTo(this.map); }).addTo(this.map);
} }
savePoint(lat, lng) { setNewPointAsSelected(name, latitude, longitude, type) {
const poiNameElement = document.getElementById('name'); const feature = this.createFeatureForPoint(longitude, latitude, name, type);
const poiTypeElement = document.getElementById("poiTypeSelect") this.createdPoints.push(feature);
this.createdPointLayer = this.addNewPointToMap(feature);
if (poiNameElement && poiTypeElement) { this.createdPointLayer.eachLayer((layer) => {
const poiName = poiNameElement.value; this.selectPoint(feature, layer);
const poiType = parseInt(poiTypeElement.value, 10); });
}
// There should only be one newly created point available
if (this.createdPointLayer) {
this.map.removeLayer(this.createdPointLayer);
}
if (this.createdPoints.length > 0) {
this.createdPoints.pop();
}
const newPoint = this.createFeatureForPoint(lng, lat, poiName, poiType);
this.createdPoints.push(newPoint);
this.createdPointLayer = this.addNewPointToMap(newPoint);
this.createdPointLayer.eachLayer((layer) => {
this.selectPoint(newPoint, layer);
});
const formElement = document.getElementById('pointForm'); removeExistingNewPoint(){
if (formElement) { if (this.createdPointLayer) {
formElement.remove(); this.map.removeLayer(this.createdPointLayer);
} }
if (this.createdPoints.length > 0) {
this.createdPoints.pop();
} }
} }
...@@ -345,6 +344,54 @@ class MapModal { ...@@ -345,6 +344,54 @@ class MapModal {
</div>`; </div>`;
} }
/**
* Creates the HTML form for adding a new point, and add it to the map container.
*
* @param positionX Where to place the form on the x axis
* @param positionY Where to place the form on the y axis
* @param latitude Latitude of the point clicked
* @param longitude Longitude of the point clicked
* @returns {Element}
*/
addHtmlElementNewPointForm(positionX, positionY, latitude, longitude) {
const html = `
<div id="newPointForm" class="panel panel-default" style="top: ${positionY}px; left: ${positionX}px;">
<div class="panel-heading">
<h3 class="panel-title">Opprett nytt sted</h3>
</div>
<div class="panel-body">
<div class="form-group">
<label for="name">Navn:</label>
<input type="text" class="form-control" id="name" name="name">
</div>
<div class="form-group">
<label for="latitude">Breddegrad:</label>
<input type="text" class="form-control" id="latitude" name="latitude" value="${latitude}">
</div>
<div class="form-group">
<label for="longitude">Lengdegrad:</label>
<input type="text" class="form-control" id="longitude" name="longitude" value="${longitude}">
</div>
<div class="form-group">
<label for="poiTypeSelect">Type:</label>
<select class="form-control" id="type" name="type">
<option value="2">${this.typeNameMap[2]}</option>
<option value="3">${this.typeNameMap[3]}</option>
<option value="5">${this.typeNameMap[5]}</option>
</select>
</div>
<div class="form-group text-right">
<button id="submit-button" class="btn btn-primary">Save</button>
</div>
</div>
</div>`;
const tmpContainer = document.createElement("div");
tmpContainer.innerHTML = html;
const htmlElement = tmpContainer.querySelector('#newPointForm');
document.getElementById(this.mapContainerId).appendChild(htmlElement);
return htmlElement;
}
/** /**
* Function is called when newly created point of interest is successfully persisted to database. * Function is called when newly created point of interest is successfully persisted to database.
* @param pointOfInterestId * @param pointOfInterestId
...@@ -368,11 +415,10 @@ class MapModal { ...@@ -368,11 +415,10 @@ class MapModal {
console.info("this.geoJsonData.features", this.geoJsonData.features); console.info("this.geoJsonData.features", this.geoJsonData.features);
} }
setSelectedLocation(selectedValue) { openModal(selectedPointOfInterestId) {
this.selectPointById(selectedValue); if(selectedPointOfInterestId) {
} this.selectPointById(selectedPointOfInterestId);
}
openModal(points) {
document.getElementById('mapModal').style.display = 'block'; document.getElementById('mapModal').style.display = 'block';
this.initMap(); this.initMap();
} }
......
...@@ -101,13 +101,20 @@ ...@@ -101,13 +101,20 @@
const mapModalInstance = new MapModal('mapContainer', typeNameMap, poiGeoJson, true, callbackPersistNewPoint, callbackUpdateLocationPointOfInterest); const mapModalInstance = new MapModal('mapContainer', typeNameMap, poiGeoJson, true, callbackPersistNewPoint, callbackUpdateLocationPointOfInterest);
window.mapModalInstance = mapModalInstance; window.mapModalInstance = mapModalInstance;
// If poi is selected, send id to map modal before opening
window.openModal = () => { window.openModal = () => {
const selectElement = document.querySelector('select[name="locationPointOfInterestId"]'); const selectElement = document.querySelector('select[name="locationPointOfInterestId"]');
const selectedOption = selectElement.options[selectElement.selectedIndex]; const selectedOption = selectElement.options[selectElement.selectedIndex];
if(selectedOption.value && selectedOption.value !== '-1') {
window.mapModalInstance.setSelectedLocation(selectedOption.value); let selectedPointOfInterestId;
const value = selectedOption.value;
if(value) {
const parsedValue = parseInt(value, 10);
if (!isNaN(parsedValue) && parsedValue > 0) {
selectedPointOfInterestId = parsedValue;
}
} }
window.mapModalInstance.openModal(); window.mapModalInstance.openModal(selectedPointOfInterestId);
}; };
window.closeModal = () => window.mapModalInstance && window.mapModalInstance.closeModal(); window.closeModal = () => window.mapModalInstance && window.mapModalInstance.closeModal();
...@@ -362,8 +369,7 @@ ...@@ -362,8 +369,7 @@
<div id="mapModal" class="modal"> <div id="mapModal" class="modal">
<div class="modal-content"> <div class="modal-content">
<span class="close-button" onclick="closeModal()">&times;</span> <span class="close-button" onclick="closeModal()">&times;</span>
<div id="mapContainer" style="height: 100vh; width: 100%; position: relative;"> <div id="mapContainer" style="height: 100vh; width: 100%; position: relative;"></div>
</div>
</div> </div>
</div> </div>
<span class="help-block" id="${formId}_locationPointOfInterestId_validation"></span> <span class="help-block" id="${formId}_locationPointOfInterestId_validation"></span>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment