Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hinzufügen von Funktionalitäten der Kartendarstellung auf der Startseite #14

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
54dbc3d
- added: initial commit
THS-LMIS Nov 25, 2024
0d6f013
- removed: unnecessary code
THS-LMIS Nov 25, 2024
9ea2aa0
- added: hello world page
THS-LMIS Nov 25, 2024
4dbefd6
- added: dev dependency for @babel/plugin-proposal-private-property-i…
THS-LMIS Nov 25, 2024
750e2e4
- added: Docker
THS-LMIS Nov 25, 2024
8eebdf2
Create continuous_integration.yml
THS-LMIS Nov 26, 2024
9ea66ea
Create publish-dev-docker-image.yml
THS-LMIS Nov 26, 2024
fc258f9
Create release.yml
THS-LMIS Nov 26, 2024
92d7205
- moved: Dockerfile in .github folder
THS-LMIS Nov 26, 2024
537f6b8
- added: Router package
THS-LMIS Nov 27, 2024
ab2dc77
- added: Router functionality
THS-LMIS Nov 27, 2024
7b2a331
- fixed: dockerfile & README.md
THS-LMIS Nov 27, 2024
aeeca97
Update continuous_integration.yml
THS-LMIS Nov 27, 2024
70cadc5
Rename dockerfile to Dockerfile
THS-LMIS Nov 27, 2024
7f58342
Update publish-dev-docker-image.yml
THS-LMIS Nov 27, 2024
be0d788
Delete .github/workflows/release.yml
THS-LMIS Nov 27, 2024
af9a5d3
- fixed: pr comments
THS-LMIS Nov 27, 2024
1380179
Merge branch '1-aufsetzen-der-infrastruktur' into 7-konzeption-der-se…
THS-LMIS Nov 27, 2024
9fed1c7
- fixed: spelling in README.md
THS-LMIS Nov 27, 2024
d829844
- added: Header, Footer, Impressum
THS-LMIS Nov 27, 2024
ebffdf5
- added: breadcrumb navigation
THS-LMIS Nov 28, 2024
9cf724e
- added: placeholder flex container on homepage
THS-LMIS Nov 28, 2024
7b914a7
- added: OpenLayers module & OpenLayers map
THS-LMIS Nov 28, 2024
02a8bc1
- removed: unnecessary web server in Dockerfile
THS-LMIS Dec 2, 2024
812b279
- added: vector layer with example points
THS-LMIS Dec 4, 2024
7929be8
- added: axios module
THS-LMIS Dec 4, 2024
1f21cd4
WIP
THS-LMIS Dec 4, 2024
2edffbd
Merge branch 'refs/heads/main' into 2-hinzufügen-von-funktionalitäten…
Dec 5, 2024
cb4e35f
Merge branch 'main' into 2-hinzufügen-von-funktionalitäten-der-karten…
Dec 6, 2024
86e6bf9
- removed: index.html
Dec 6, 2024
5f0956d
- added: proxy server for development
Dec 6, 2024
85cea4d
- added: Agvolution and Sentek sensors to map
THS-LMIS Dec 9, 2024
15ed32a
- added: untested agri crop polygon import
THS-LMIS Dec 9, 2024
5091fee
- added: key properties to nav link elements
THS-LMIS Dec 11, 2024
61e6d91
- changed: interface properties to the actual name to make it work
THS-LMIS Dec 11, 2024
35e23a7
- changed: injection of fiware server url with environment variable
THS-LMIS Dec 11, 2024
1d26649
- added: docker environment variable
THS-LMIS Dec 11, 2024
cd68b5f
- changed: tsconfig.json
THS-LMIS Dec 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_FIWARE_SERVER_BASE_URL=
2 changes: 2 additions & 0 deletions .github/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ ADD . /app/
WORKDIR /app

# install app
ARG VITE_FIWARE_SERVER_BASE_URL=localhost
ENV VITE_FIWARE_SERVER_BASE_URL=$VITE_FIWARE_SERVER_BASE_URL
RUN npm install && npm run build

# expose web port
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Getting Started with 5GLa Visualization

## Create .env

Rename/copy `.env.example` to `.env` and change the `.env` with your configuration.

## Scripts

In the project directory, you can run:

### `npm run dev`
Expand All @@ -26,8 +32,8 @@ Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
## Run with Docker

```shell
docker build -f ./.github/Dockerfile -t 5gla-react-visualization .
docker run --name 5gla-react-visualization -p 3000:3000 5gla-react-visualization
docker build --build-arg VITE_FIWARE_SERVER_BASE_URL=<url of Fiware server> -f ./.github/Dockerfile -t 5gla-react-visualization .
docker run --name 5gla-react-visualization -p 3000:3000 5gla-react-visualization
```

Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
16 changes: 8 additions & 8 deletions app/components/Breadcrumbs.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
color: white;
font-size: large;
text-decoration: none;
& + &:before {
content: '>';
font-weight: normal;
margin: 0 15px;
}
&.active {
font-weight: bold;
}
}
a + a:before {
content: '>';
font-weight: normal;
margin: 0 15px;
}
a.active {
font-weight: bold;
}
}
8 changes: 6 additions & 2 deletions app/components/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ function Breadcrumbs() {
<nav aria-label="breadcrumb" className={styles.breadcrumbs}>
<NavLink
to="/"
className={({ isActive }) => (isActive ? styles.active : undefined)}>
className={({ isActive }) => (isActive ? styles.active : undefined)}
key="home"
>
Startseite
</NavLink>
{pathnames.map((pathname, index) => {
const to = `/${pathnames.slice(0, index + 1).join('/')}`;
const label: string = routeLabels[pathname] || pathname;
return <NavLink
to={to}
className={({ isActive }) => (isActive ? styles.active : undefined)}>
className={({ isActive }) => (isActive ? styles.active : undefined)}
key={pathname}
>
{decodeURIComponent(label)}
</NavLink>;
})}
Expand Down
186 changes: 177 additions & 9 deletions app/components/OpenLayers.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,199 @@
import React, { useEffect } from 'react';
import React, {useEffect} from 'react';

import {Feature, Map, View} from 'ol';
import {Coordinate} from 'ol/coordinate';
import {Extent} from "ol/extent";
import {Point, Polygon} from 'ol/geom';
import TileLayer from 'ol/layer/Tile';
import { OSM } from 'ol/source';
import { Map, View } from 'ol';
import VectorLayer from "ol/layer/Vector";
import {fromLonLat} from 'ol/proj';
import {OSM} from 'ol/source';
import VectorSource from 'ol/source/Vector';
import {Fill, Stroke, Style} from 'ol/style';

import 'ol/ol.css';
import styles from './OpenLayers.module.css';
import {getAgriCropPolygon, getAgvolutionSensorsLocations, getSentekSensorsLocations} from '../services/fiwareService';

interface Props {
id: string
}

function OpenLayers({ id }: Props) {
useEffect(() => {
const osmLayer = new TileLayer({
preload: Infinity,
source: new OSM(),
interface SensorResponse {
id: string,
type: string,
location: {
type: string,
coordinates: Coordinate
} | null
}

interface Sensor {
id: string,
type: string,
coordinates: Coordinate
}

interface AgriCropResponse {
id: string,
type: string,
location: {
type: string,
coordinates: Coordinate[]
}
}

interface AgriCrop {
id: string,
coordinates: Coordinate[]
}

function removeSensorByIdAndType(sensors: Sensor[], id: string, type: string) {
const index: number = sensors
.findIndex((sensor: Sensor): boolean => sensor.id === id && sensor.type === type);
if (index >= 0) {
delete sensors[index];
}
}

function removeAgriCropById(agriCrops: AgriCrop[], id: string) {
const index: number = agriCrops.findIndex((agriCrop: AgriCrop) => agriCrop.id === id);
if (index > 0) {
delete agriCrops[index];
}
}

function updateSensors(map: Map, vectorSource: VectorSource<Feature<Point>>, sensors: Sensor[]) {
const features: Feature<Point>[] = [];
sensors.map((sensor: Sensor) => {
features.push(new Feature({ geometry: new Point(fromLonLat(sensor.coordinates)) }));
});
vectorSource.clear();
vectorSource.addFeatures(features);
}

function updateAgriCrops(map: Map, vectorSource: VectorSource<Feature<Polygon>>, agriCrops: AgriCrop[]) {
const features: Feature<Polygon>[] = [];
agriCrops.map((agriCrop: AgriCrop) => {
const lonLatCoordinates: Coordinate[] = [];
agriCrop.coordinates.map((coordinate) => {
lonLatCoordinates.push(fromLonLat(coordinate));
})
const polygonFeature = new Feature({ geometry: new Polygon([lonLatCoordinates]) });
polygonFeature.setStyle(style);
features.push(polygonFeature);
});
vectorSource.clear();
vectorSource.addFeatures(features);
fitMap(map, vectorSource.getExtent());
}

function fitMap(map: Map, extent: Extent | undefined) {
if (extent && extent.length === 4 && extent.every((element: number): boolean => isFinite(element))) {
map.getView().fit(extent, { padding: [50, 50, 50, 50] });
}
}

function handleSensorsResponse(_sensors: SensorResponse[], map: Map, vectorSource: VectorSource<Feature<Point>>, sensors: Sensor[]) {
if (Array.isArray(_sensors)) {
_sensors.map((_sensor: SensorResponse) => {
removeSensorByIdAndType(sensors, _sensor.id, _sensor.type);
if (_sensor.location !== null) {
sensors.push({
id: _sensor.id,
type: _sensor.type,
coordinates: _sensor.location.coordinates
});
}
updateSensors(map, vectorSource, sensors);
});
}
}

function handleAgriCropResponse(_agriCrops: AgriCropResponse[], map: Map, vectorSource: VectorSource<Feature<Polygon>>, agriCrops: AgriCrop[]) {
if (Array.isArray(_agriCrops)) {
_agriCrops.map((_agriCrop: AgriCropResponse) => {
removeAgriCropById(agriCrops, _agriCrop.id)
agriCrops.push({
id: _agriCrop.id,
coordinates: _agriCrop.location.coordinates
});
});
updateAgriCrops(map, vectorSource, agriCrops);
}
}

const style = new Style({
fill: new Fill({
color: 'rgba(0, 128, 255, 0.4)',
}),
stroke: new Stroke({
color: 'blue',
width: 2,
}),
});

function OpenLayers({ id }: Props) {

const osmLayer = new TileLayer({
preload: Infinity,
source: new OSM(),
});

const pointFeatures: Feature<Point>[] = [];
const polygonFeatures: Feature<Polygon>[] = [];
const sensors: Sensor[] = [];
const agriCrops: AgriCrop[] = [];

const pointVectorSource = new VectorSource({ features: pointFeatures });
const polygonVectorSource = new VectorSource({ features: polygonFeatures });

const pointVectorLayer = new VectorLayer({ source: pointVectorSource });
const polygonVectorLayer = new VectorLayer({ source: polygonVectorSource });

useEffect(() => {
const map = new Map({
target: id,
layers: [ osmLayer ],
layers: [ osmLayer, polygonVectorLayer, pointVectorLayer ],
view: new View({
center: [0, 0],
zoom: 0,
}),
});

getAgvolutionSensorsLocations()
.then((response) => handleSensorsResponse(
response.data,
map,
pointVectorSource,
sensors
))
.catch((error) => {
console.debug(error);
});

getSentekSensorsLocations()
.then((response) => handleSensorsResponse(
response.data,
map,
pointVectorSource,
sensors
))
.catch((error) => {
console.debug(error);
});

getAgriCropPolygon()
.then((response) => handleAgriCropResponse(
response.data,
map,
polygonVectorSource,
agriCrops
))
.catch((error) => {
console.debug(error);
});

return () => map.setTarget(undefined)
});

Expand Down
39 changes: 39 additions & 0 deletions app/services/fiwareService.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import axios, {AxiosInstance} from 'axios';

const baseUrlFiwareServer: string = process.env.NODE_ENV === 'development' ? 'http://localhost:5173' : import.meta.env.VITE_FIWARE_SERVER_BASE_URL;
const entitiesApiUrlFiwareServer: string = baseUrlFiwareServer + '/v2/entities/';

function getRequestInstanceFromFiwareServer(): AxiosInstance {
return axios.create({
baseURL: entitiesApiUrlFiwareServer,
headers: { 'fiware-service': 'dev' }
});
}

function getRequestFromFiwareServer(params = {}, headers = {}) {
return getRequestInstanceFromFiwareServer().get(entitiesApiUrlFiwareServer, { headers: headers, params: params });
}

export function getAgvolutionSensorsLocations() {
return getRequestFromFiwareServer({
type: 'AgvolutionSensor',
attrs: 'location',
options: 'keyValues'
});
}

export function getSentekSensorsLocations() {
return getRequestFromFiwareServer({
type: 'SentekSensor',
attrs: 'location',
options: 'keyValues'
});
}

export function getAgriCropPolygon() {
return getRequestFromFiwareServer({
type: 'AgriCrop',
attrs: 'location',
options: 'keyValues'
});
}
Loading
Loading