diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 42f943e6..9d037343 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,8 @@ "@mui/material": "^5.15.17", "@mui/x-data-grid": "^7.4.0", "@phosphor-icons/react": "^2.1.5", + "@types/geojson": "^7946.0.14", + "geojson": "^0.5.0", "leaflet": "^1.9.4", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -1775,8 +1777,7 @@ "node_modules/@types/geojson": { "version": "7946.0.14", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", - "dev": true + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" }, "node_modules/@types/leaflet": { "version": "1.9.12", @@ -2848,6 +2849,14 @@ "node": ">=6.9.0" } }, + "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/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index b0fbe53d..fa36e081 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,16 +12,18 @@ "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", + "@fontsource/roboto": "^5.0.13", "@mui/icons-material": "^5.15.17", + "@mui/lab": "^5.0.0-alpha.170", "@mui/material": "^5.15.17", - "leaflet": "^1.9.4", - "react-leaflet": "^4.2.1", - "@fontsource/roboto": "^5.0.13", "@mui/x-data-grid": "^7.4.0", - "@mui/lab": "^5.0.0-alpha.170", "@phosphor-icons/react": "^2.1.5", + "@types/geojson": "^7946.0.14", + "geojson": "^0.5.0", + "leaflet": "^1.9.4", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-leaflet": "^4.2.1" }, "devDependencies": { "@types/leaflet": "^1.9.12", diff --git a/frontend/src/components/MapView/DataFetch.tsx b/frontend/src/components/MapView/DataFetch.tsx new file mode 100644 index 00000000..57cf8615 --- /dev/null +++ b/frontend/src/components/MapView/DataFetch.tsx @@ -0,0 +1,32 @@ +import { FeatureCollection, Geometry } from "geojson"; +import data from "./FeatureCollection.json"; +import { LatLngBounds } from "leaflet"; +import { useEffect, useState } from "react"; +const geojsonData: FeatureCollection = data as FeatureCollection; + +const useGeoData = ( + bounds: LatLngBounds, + zoom: number +): FeatureCollection | undefined => { + const [data, setData] = useState>(); + + useEffect(() => { + /* eslint-disable */ const fetchData = async (_bounds: LatLngBounds) => { + /* eslint-enable */ + // Uncomment and adjust the following lines to fetch data from an API + // const url = `https://example.com/api/geo?bounds=${bounds.toBBoxString()}&zoom=${zoom}`; + // const response = await fetch(url); + // const result = await response.json(); + setData(geojsonData as FeatureCollection); + }; + + fetchData(bounds); + console.log( + `Data fetched for bounds: ${bounds.toBBoxString()} and zoom: ${zoom}` + ); + }, [bounds, zoom]); + + return data; +}; + +export default useGeoData; diff --git a/frontend/src/components/MapView/FeatureCollection.json b/frontend/src/components/MapView/FeatureCollection.json new file mode 100644 index 00000000..149c82fe --- /dev/null +++ b/frontend/src/components/MapView/FeatureCollection.json @@ -0,0 +1,121 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "name": "Berlin", + "amenity": "Capital City", + "popupContent": "This is Berlin, the capital of Germany!" + }, + "geometry": { + "type": "Point", + "coordinates": [13.4050, 52.5200] + } + }, + { + "type": "Feature", + "properties": { + "name": "Munich", + "amenity": "City", + "popupContent": "This is Munich, known for Oktoberfest!" + }, + "geometry": { + "type": "Point", + "coordinates": [11.5820, 48.1351] + } + }, + { + "type": "Feature", + "properties": { + "name": "Hamburg", + "amenity": "City", + "popupContent": "This is Hamburg, a major port city in northern Germany!" + }, + "geometry": { + "type": "Point", + "coordinates": [9.9937, 53.5511] + } + }, + { + "type": "Feature", + "properties": { + "name": "Frankfurt", + "amenity": "City", + "popupContent": "This is Frankfurt, a major financial hub in Germany!" + }, + "geometry": { + "type": "Point", + "coordinates": [8.6821, 50.1109] + } + }, + { + "type": "Feature", + "properties": { + "name": "Dortmund", + "amenity": "City", + "popupContent": "This is Dortmund, known for its football team!" + }, + "geometry": { + "type": "Point", + "coordinates": [7.4660, 51.5149] + } + }, + { + "type": "Feature", + "properties": { + "name": "Cologne", + "amenity": "City", + "popupContent": "This is Cologne, known for its impressive cathedral!" + } + }, + { + "type": "Feature", + "properties": { + "name": "Leipzig", + "amenity": "City", + "popupContent": "This is Leipzig, known for its vibrant cultural scene!" + }, + "geometry": { + "type": "Point", + "coordinates": [12.3731, 51.3397] + } + }, + { + "type": "Feature", + "properties": { + "name": "Hannover", + "amenity": "City", + "popupContent": "This is Hannover, known for its trade fairs!" + }, + "geometry": { + "type": "Point", + "coordinates": [9.7320, 52.3759] + } + }, + { + "type": "Feature", + "properties": { + "name": "Würzburg", + "amenity": "City", + "popupContent": "This is Würzburg, known for its baroque and rococo architecture!" + }, + "geometry": { + "type": "Point", + "coordinates": [9.9937, 49.7945] + } + }, + { + "type": "Feature", + "properties": { + "name": "Augsburg", + "amenity": "City", + "popupContent": "This is Augsburg, one of Germany's oldest cities!" + }, + "geometry": { + "type": "Point", + "coordinates": [10.8983, 48.3715] + } + } + ] +} diff --git a/frontend/src/components/MapView/MapView.tsx b/frontend/src/components/MapView/MapView.tsx index 856076bf..ac9acb73 100644 --- a/frontend/src/components/MapView/MapView.tsx +++ b/frontend/src/components/MapView/MapView.tsx @@ -7,10 +7,11 @@ import "leaflet/dist/leaflet.css"; import "./MapView.css"; import { useMap, useMapEvents } from "react-leaflet/hooks"; import L from "leaflet"; -import Button from "@mui/material/Button"; import icon from "leaflet/dist/images/marker-icon.png"; import iconShadow from "leaflet/dist/images/marker-shadow.png"; import MapOptions from "./MapOptions"; +import useGeoData from "./DataFetch"; +import { GeoJSON } from "react-leaflet"; import { MapContext } from "../../contexts/MapContext"; const DefaultIcon = L.icon({ @@ -21,24 +22,22 @@ const DefaultIcon = L.icon({ L.Marker.prototype.options.icon = DefaultIcon; -function Btn() { - const map = useMap(); - return ( - - ); -} +const svgIcon = L.divIcon({ + html: ` + + + + + + `, + className: "", // Optional: add a custom class name + iconSize: [34, 34], + iconAnchor: [17, 17], // Adjust the anchor point as needed +}); const MapView: React.FC = () => { const { currentMapCache, setCurrentMapCache } = useContext(MapContext); + const geoData = useGeoData(currentMapCache.mapBounds, currentMapCache.zoom); const MapEventsHandler = () => { const map = useMap(); @@ -50,21 +49,17 @@ const MapView: React.FC = () => { selectedCoordinates: event.latlng, }); }, - zoomend: (event) => { - setCurrentMapCache({ - ...currentMapCache, - zoom: event.target.getZoom(), - }); - }, - dragend: (event) => { + moveend: (event) => { setCurrentMapCache({ ...currentMapCache, mapCenter: event.target.getCenter(), + mapBounds: event.target.getBounds(), + zoom: event.target.getZoom(), }); }, }); return ( - + { zoom={currentMapCache.zoom} className="map" > + {geoData && } + - ); diff --git a/frontend/src/contexts/MapContext.tsx b/frontend/src/contexts/MapContext.tsx index f605c097..0908c45e 100644 --- a/frontend/src/contexts/MapContext.tsx +++ b/frontend/src/contexts/MapContext.tsx @@ -1,4 +1,4 @@ -import L, { LatLng } from "leaflet"; +import L, { LatLng, LatLngBounds } from "leaflet"; import React, { createContext, useState, ReactNode } from "react"; //// TYPES //// @@ -7,6 +7,7 @@ import React, { createContext, useState, ReactNode } from "react"; export type MapCacheProps = { selectedCoordinates: LatLng; mapCenter: LatLng; + mapBounds: LatLngBounds; zoom: number; }; @@ -27,6 +28,7 @@ type MapContextProviderProps = { const defaultMapCache: MapCacheProps = { selectedCoordinates: L.latLng([49.5732, 11.0288]), mapCenter: L.latLng([49.5732, 11.0288]), + mapBounds: L.latLngBounds([49.5732, 11.0288], [49.5732, 11.0288]), zoom: 13, }; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..0265cfb2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "amos2024ss04-building-information-enhancer", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "amos2024ss04-building-information-enhancer", + "version": "1.0.0", + "dependencies": { + "@types/geojson": "^7946.0.14", + "geojson": "^0.5.0" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + }, + "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" + } + } + } +}