diff --git a/.gitignore b/.gitignore index 2c7be4d..43d38dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target /db +node_modules +build diff --git a/ts-client/client.ts b/ts-client/client.ts new file mode 100644 index 0000000..b0df9e6 --- /dev/null +++ b/ts-client/client.ts @@ -0,0 +1,109 @@ +import * as L from 'leaflet'; +import { Feature, FeatureCollection, GeoJSON } from 'geojson'; + +interface PlaceModel { + name: string; + address: string; + open_hours: string; + icon: string; + description: string; + latitude: number; + longitude: number; + +} + +async function loadPlaces(): Promise> { + return await fetch('places/').then(response => response.json()); +} + +function toLeafletPlaces(backendPlaces: Array): GeoJSON { + let result: FeatureCollection; + 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] + } + }); + } + return result; +} + +export default async function setupMap(): Promise { + const backendPlaces = await loadPlaces(); + const leafletPlaces = toLeafletPlaces(backendPlaces); + + /* Set up the map*/ + const map = new L.Map('map'); + + /* Create the tile layer with correct attribution*/ + const osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; + const osmAttrib = 'Mapa © OpenStreetMap'; + const osm = new L.TileLayer(osmUrl, { minZoom: 4, maxZoom: 20, attribution: osmAttrib }); + + /* Start the map in Santiago */ + map.setView(new L.LatLng(-33.45, -70.666667), 13); + /* Try to get user position, if not, put the map in Santiago again */ + map.locate({ setView: true, maxZoom: 16 }) + .on('locationerror', function(_event: L.LocationEvent) { + map.setView(new L.LatLng(-33.45, -70.666667), 13); + }); + map.addLayer(osm); + + function onEachFeature(feature: Feature, layer: L.Layer) { + if (feature.properties) { + let popupStr = "

" + feature.properties.name + "

"; + popupStr += "
    " + if (feature.properties.address) + popupStr += "
  • Dirección: " + feature.properties.address + "
  • "; + if (feature.properties.open_hours) + popupStr += "
  • Horario: " + feature.properties.open_hours + "
  • "; + if (feature.properties.description) + popupStr += "
  • " + feature.properties.description + "
  • "; + popupStr += "
"; + + layer.bindPopup(popupStr); + } + } + + /* Icons */ + const icons = new Map(); + icons.set('bar', new L.Icon({ iconUrl: 'icons/bar.svg' })); + icons.set('coffe', new L.Icon({ iconUrl: 'icons/coffe.svg' })); + icons.set('dining', new L.Icon({ iconUrl: 'icons/dining.svg' })); + icons.set('food', new L.Icon({ iconUrl: 'icons/food.svg' })); + icons.set('jazz', new L.Icon({ iconUrl: 'icons/saxophone.svg' })); + icons.set('library', new L.Icon({ iconUrl: 'icons/book.svg' })); + icons.set('marker', new L.Icon({ iconUrl: 'icons/marker.svg' })); + icons.set('museum', new L.Icon({ iconUrl: 'icons/museum.svg' })); + icons.set('shop', new L.Icon({ iconUrl: 'icons/store.svg' })); + + for (let [name, icon] of icons) { + icon.options.iconSize = [36, 36]; + icon.options.popupAnchor = [0, -18]; + } + + function pointToLayer(feature: Feature, latlng: L.LatLng) { + let markerIcon = null; + if (feature.properties && feature.properties.icon) { + markerIcon = icons.get(feature.properties.icon); + } + if (markerIcon !== null && markerIcon !== undefined) + return L.marker(latlng, { icon: markerIcon }); + else + return L.marker(latlng); + } + + map.addLayer(L.geoJSON(leafletPlaces, { + onEachFeature: onEachFeature, + pointToLayer: pointToLayer + })); +} diff --git a/ts-client/package-lock.json b/ts-client/package-lock.json new file mode 100644 index 0000000..f672795 --- /dev/null +++ b/ts-client/package-lock.json @@ -0,0 +1,71 @@ +{ + "name": "ts-client", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "geojson": "^0.5.0", + "leaflet": "^1.8.0" + }, + "devDependencies": { + "@types/leaflet": "^1.7.11" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.10", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==", + "dev": true + }, + "node_modules/@types/leaflet": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.11.tgz", + "integrity": "sha512-VwAYom2pfIAf/pLj1VR5aLltd4tOtHyvfaJlNYCoejzP2nu52PrMi1ehsLRMUS+bgafmIIKBV1cMfKeS+uJ0Vg==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/geojson": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/geojson/-/geojson-0.5.0.tgz", + "integrity": "sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/leaflet": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz", + "integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA==" + } + }, + "dependencies": { + "@types/geojson": { + "version": "7946.0.10", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", + "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==", + "dev": true + }, + "@types/leaflet": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.11.tgz", + "integrity": "sha512-VwAYom2pfIAf/pLj1VR5aLltd4tOtHyvfaJlNYCoejzP2nu52PrMi1ehsLRMUS+bgafmIIKBV1cMfKeS+uJ0Vg==", + "dev": true, + "requires": { + "@types/geojson": "*" + } + }, + "geojson": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/geojson/-/geojson-0.5.0.tgz", + "integrity": "sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==" + }, + "leaflet": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz", + "integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA==" + } + } +} diff --git a/ts-client/package.json b/ts-client/package.json new file mode 100644 index 0000000..6e0f652 --- /dev/null +++ b/ts-client/package.json @@ -0,0 +1,9 @@ +{ + "devDependencies": { + "@types/leaflet": "^1.7.11" + }, + "dependencies": { + "geojson": "^0.5.0", + "leaflet": "^1.8.0" + } +} diff --git a/ts-client/tsconfig.json b/ts-client/tsconfig.json new file mode 100644 index 0000000..13bf64f --- /dev/null +++ b/ts-client/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "typeRoots": ["node_modules/@types"], + "rootDir": ".", + "outDir": "build", + "target": "es2020", + "lib": [ + "es2020", + "dom", + ], + "types": [ + "leaflet", + "geojson", + ], + "moduleResolution": "node" + }, + "include": [ + "*.ts" + ], + "exclude": [ + "node_modules" + ] +}