From fe63377c26224e9abdd027b115f8a806dc10c9cd Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Mon, 21 Nov 2022 00:46:39 -0300 Subject: [PATCH] draft: add places through Leaflet.contextmenu --- Cargo.lock | 2 +- static/index.html | 113 +++++++++++++++++++++++++++++++-- ts-client/client.ts | 151 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 241 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f959e15..3937e76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -654,7 +654,7 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "huellas" -version = "0.1.0" +version = "0.1.1" dependencies = [ "rocket", "rocket_db_pools", diff --git a/static/index.html b/static/index.html index 9d957b6..d038ddf 100644 --- a/static/index.html +++ b/static/index.html @@ -4,12 +4,18 @@ 👣 Huellas 🐾 - - +
+ diff --git a/ts-client/client.ts b/ts-client/client.ts index c2fce1a..ca4f8fd 100644 --- a/ts-client/client.ts +++ b/ts-client/client.ts @@ -1,7 +1,8 @@ -import * as L from 'leaflet'; +import * as L from 'leaflet-contextmenu'; import { Feature, FeatureCollection, GeoJSON } from 'geojson'; interface PlaceModel { + id: number | null; name: string; address: string; open_hours: string; @@ -9,11 +10,27 @@ interface PlaceModel { description: string; latitude: number; longitude: number; - } async function loadPlaces(): Promise> { - return await fetch('places/').then(response => response.json()); + return await fetch('places').then(response => response.json()); +} + +function toFeature(place: PlaceModel): Feature { + return { + "type": "Feature", + "properties": { + "name": place.name, + "address": place.address, + "open_hours": place.open_hours, + "icon": place.icon, + "description": place.description + }, + "geometry": { + "type": "Point", + "coordinates": [place.latitude, place.longitude] + } + } } function toLeafletPlaces(backendPlaces: Array): GeoJSON { @@ -22,30 +39,116 @@ function toLeafletPlaces(backendPlaces: Array): GeoJSON { features: new Array(), } for (const place of backendPlaces) { - result.features.push({ - "type": "Feature", - "properties": { - "name": place.name, - "address": place.address, - "open_hours": place.open_hours, - "icon": place.icon, - "description": place.description - }, - "geometry": { - "type": "Point", - "coordinates": [place.latitude, place.longitude] - } - }); + result.features.push(toFeature(place)); } return result; } +let placesLayer: L.GeoJSON; +let places = new Map(); + +async function createPlace(): Promise { + const name = + (document.getElementById("name") as HTMLInputElement).value; + const address = + (document.getElementById("address") as HTMLInputElement).value; + const open_hours = + (document.getElementById("open_hours") as HTMLTextAreaElement).value; + const icon = + (document.getElementById("icon") as HTMLSelectElement).value; + const description = + (document.getElementById("description") as HTMLTextAreaElement).value; + const latitude = parseFloat( + (document.getElementById("lat") as HTMLInputElement).value); + const longitude = parseFloat( + (document.getElementById("long") as HTMLSelectElement).value); + + const newPlace: PlaceModel = { + id: null, + name: name, + address: address, + open_hours: open_hours, + icon: icon, + description: description, + latitude: latitude, + longitude: longitude, + }; + + await fetch('places', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(newPlace), + }) + .then((response) => response.json()) + .then((place: PlaceModel) => { + places.set( + { lat: place.latitude, lng: place.longitude }, + place + ); + placesLayer.addData(toFeature(place)); + }) + .catch((error) => alert(error)); +} + +interface MapEvent { + latlng: L.latlng; +} + async function setupMap(): Promise { + /* Create/Edit form */ + const modal = document.getElementById("modal"); + const closeButton = document.getElementById("close"); + + closeButton.onclick = function() { + modal.style.display = "none"; + } + + window.onclick = function(e: Event) { + if (e.target == modal) { + modal.style.display = "none"; + } + } + + function openForm(title: string, lat: number, long: number): void { + const h1 = modal.getElementsByTagName("h1")[0]; + h1.innerText = title; + const latInput = (document.getElementById("lat") as HTMLInputElement); + latInput.value = lat.toString(); + const longInput = (document.getElementById("long") as HTMLInputElement); + longInput.value = long.toString(); + + modal.style.display = "block"; + } + + function openCreateForm(e: MapEvent) { + const lat = e.latlng.lat; + const long = e.latlng.lng; + openForm("Añadir lugar nuevo", lat, long); + } + + /* Get places from backend */ const backendPlaces = await loadPlaces(); const leafletPlaces = toLeafletPlaces(backendPlaces); + for (const place of backendPlaces) { + places.set( + { lat: place.latitude, lng: place.longitude }, + place + ); + } /* Set up the map*/ - const map = new L.Map('map'); + const map = new L.Map('map', { + contextmenu: true, + contextmenuWidth: 140, + contextmenuItems: [ + { + text: 'Añadir lugar', + callback: openCreateForm + } + ] + }); /* Create the tile layer with correct attribution*/ const osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; @@ -74,6 +177,13 @@ async function setupMap(): Promise { popupStr += ""; layer.bindPopup(popupStr); + layer.bindContextMenu({ + contextmenu: true, + contextmenuInheritItems: false, + contextmenuItems: [{ + text: 'Marker item' + }] + }); } } @@ -107,8 +217,9 @@ async function setupMap(): Promise { return L.marker(latlng); } - map.addLayer(L.geoJSON(leafletPlaces, { + placesLayer = L.geoJSON(leafletPlaces, { onEachFeature: onEachFeature, pointToLayer: pointToLayer - })); + }) + map.addLayer(placesLayer); }