From a9f26735928db97e667ce604e9cf260a3b92a8cb Mon Sep 17 00:00:00 2001 From: "Begerad, Stefan" Date: Fri, 21 Apr 2023 15:18:02 +0200 Subject: [PATCH] feat: add Map component to Home page --- app/assets/Logo_SIB_electricindigo.svg | 35 ++++ app/components/map.jsx | 12 +- app/components/map/entities-map.css | 4 + app/components/map/entities-map.jsx | 46 +++++ app/components/map/entities-marker-plus.jsx | 48 +++++ app/components/map/entities-marker.jsx | 26 +++ app/components/map/entities-popup.jsx | 20 ++ app/components/map/icon.js | 28 +++ config/webpack.common.js | 12 ++ package-lock.json | 196 +++++++++++++++++++- package.json | 3 + 11 files changed, 425 insertions(+), 5 deletions(-) create mode 100644 app/assets/Logo_SIB_electricindigo.svg create mode 100644 app/components/map/entities-map.css create mode 100644 app/components/map/entities-map.jsx create mode 100644 app/components/map/entities-marker-plus.jsx create mode 100644 app/components/map/entities-marker.jsx create mode 100644 app/components/map/entities-popup.jsx create mode 100644 app/components/map/icon.js diff --git a/app/assets/Logo_SIB_electricindigo.svg b/app/assets/Logo_SIB_electricindigo.svg new file mode 100644 index 0000000..458e73e --- /dev/null +++ b/app/assets/Logo_SIB_electricindigo.svg @@ -0,0 +1,35 @@ + + + + + + + + + diff --git a/app/components/map.jsx b/app/components/map.jsx index fff0a12..52f991b 100644 --- a/app/components/map.jsx +++ b/app/components/map.jsx @@ -1,10 +1,18 @@ import React from 'react'; +import PropTypes from 'prop-types'; + +import EntitiesMap from './map/entities-map'; //destructure props -export default function Map(){ +export default function Map({entities}){ return ( <> -

Map

+

Map

+

Entity Map

+ ); } +Map.propTypes = { + entities: PropTypes.array, +}; diff --git a/app/components/map/entities-map.css b/app/components/map/entities-map.css new file mode 100644 index 0000000..747a5bb --- /dev/null +++ b/app/components/map/entities-map.css @@ -0,0 +1,4 @@ +/*set up the height of*/ +.leaflet-container { + height: 85vh; +} diff --git a/app/components/map/entities-map.jsx b/app/components/map/entities-map.jsx new file mode 100644 index 0000000..8a9ce5a --- /dev/null +++ b/app/components/map/entities-map.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {MapContainer,TileLayer} from 'react-leaflet'; + +/*JS module import (vs cdn or style link)*/ +import 'leaflet/dist/leaflet.css' +import './entities-map.css'; + +import EntitiesMarker from './entities-marker'; + +export default function EntitiesMap({entities}) { + /*lat and lon of Braunschweig,DE*/ + const position = [52.26594, 10.52673] + //TODO make this switch available via configuration! + const hasGtfs = false; + return ( + <> + + + { + entities.map(function(value,key) { + //console.log(`key: ${key}, tripId: ${value.tripId}`); + return ; + }) + } + + + ); +} +EntitiesMap.propTypes = { + entities: PropTypes.array +}; diff --git a/app/components/map/entities-marker-plus.jsx b/app/components/map/entities-marker-plus.jsx new file mode 100644 index 0000000..b8bc570 --- /dev/null +++ b/app/components/map/entities-marker-plus.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Marker} from 'react-leaflet'; + +import PopupElem from './entities-popup'; +import getIcon from './icon'; + +export default function EntitiesMarkerPlus({name,lat,lon}){ + if(lat===undefined || lat===null || lon===undefined || lon===null){ + console.error('lat or lon undefined or null'); + return null; + }else{ + const markerIcon=getIcon(); + if(markerIcon===null){ + //TODO Handle issue! + console.error('ERROR: icon null'); + return null; + }else if(lat===undefined||lat===null){ + //TODO Handle issue! + console.error('ERROR: lat undefined or null'); + return null; + }else if(lon===undefined||lon===null){ + //TODO Handle issue! + console.error('ERROR: lon undefined or null'); + return null; + }else{ + return( + <> + + + + + ); + } + } +}; +EntitiesMarkerPlus.propTypes = { + name: PropTypes.string, + lat: PropTypes.string, + lon: PropTypes.string +}; diff --git a/app/components/map/entities-marker.jsx b/app/components/map/entities-marker.jsx new file mode 100644 index 0000000..cf7a4a7 --- /dev/null +++ b/app/components/map/entities-marker.jsx @@ -0,0 +1,26 @@ +import React, {useEffect,useState} from 'react'; +import PropTypes from 'prop-types'; + +import EntitiesMarkerPlus from './entities-marker-plus'; + +export default function EntitiesMarker({name,lat,lon}){ + if(lat===undefined || lat===null || lon===undefined || lon===null){ + console.error('lat or lon undefined or null'); + return null; + }else{ + return( + <> + + + ); + } +}; +EntitiesMarker.propTypes = { + name: PropTypes.string, + lat: PropTypes.string, + lon: PropTypes.string +}; diff --git a/app/components/map/entities-popup.jsx b/app/components/map/entities-popup.jsx new file mode 100644 index 0000000..311e13e --- /dev/null +++ b/app/components/map/entities-popup.jsx @@ -0,0 +1,20 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Popup} from 'react-leaflet'; + +export default function EntitiesPopup({name,lat,lon}){ + return ( + <> + + name: {name}
+ lat: {lat}
+ lon: {lon} +
+ + ); +}; +EntitiesPopup.propTypes = { + name: PropTypes.string, + lat: PropTypes.string, + lon: PropTypes.string +}; diff --git a/app/components/map/icon.js b/app/components/map/icon.js new file mode 100644 index 0000000..3b24a5e --- /dev/null +++ b/app/components/map/icon.js @@ -0,0 +1,28 @@ +import bfly from '../../assets/Logo_SIB_electricindigo.svg'; + +/*return icon object*/ +export default function getIcon(){ + //console.log('getIcon(): ptByIfleet available') + const icon = new L.Icon({ + /*path to icon graphic*/ + iconUrl: bfly, + /*path to graphic used for high resolution monitors*/ + iconRetinaUrl: bfly, + popupAnchor: [-0, -0], + /*size of the icon in width and hight*/ + iconSize: [32,32], + /*determine how the popup is positions relative to the actual point on the map*/ + popupAnchor:[0,-10], + /*determine how the image is positions relative to the actual point on the map*/ + iconAnchor: null, + /*path to shadow graphic*/ + shadowUrl: null, + /*size of the shadow in width and hight*/ + shadowSize: null, + /*determine how the mage is positions relative to the actual point on the map*/ + shadowAnchor: null, + className: 'marker-msg' + }); + //console.log('getIcon(): icon available') + return icon; +} diff --git a/config/webpack.common.js b/config/webpack.common.js index 5038060..0337ff7 100644 --- a/config/webpack.common.js +++ b/config/webpack.common.js @@ -26,6 +26,18 @@ module.exports = { test: /\.css$/i, use: ["style-loader", "css-loader"], }, + { + //test all *.svg using svg-loader + test: /\.svg$/, + use: [ + { + loader: 'svg-url-loader', + options: { + limit: 10000, + }, + }, + ], + }, ] }, resolve: { diff --git a/package-lock.json b/package-lock.json index 6e7326c..eac5253 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,12 @@ "version": "0.1.0", "license": "GPL-3.0-or-later", "dependencies": { - "axios": "^1.3.6", + "axios": "1.3.6", + "leaflet": "^1.9.3", "prop-types": "15.8.1", "react": "18.2.0", "react-dom": "18.2.0", + "react-leaflet": "^4.2.1", "react-router-dom": "^6.10.0" }, "devDependencies": { @@ -20,9 +22,10 @@ "@babel/preset-env": "7.21.4", "@babel/preset-react": "7.18.6", "babel-loader": "9.1.2", - "css-loader": "^6.7.3", + "css-loader": "6.7.3", "html-webpack-plugin": "5.5.1", - "style-loader": "^3.3.2", + "style-loader": "3.3.2", + "svg-url-loader": "^8.0.0", "webpack": "5.80.0", "webpack-cli": "5.0.1", "webpack-dev-server": "4.13.3", @@ -1840,6 +1843,16 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@react-leaflet/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", + "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/@remix-run/router": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", @@ -2458,6 +2471,15 @@ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -3178,6 +3200,15 @@ "integrity": "sha512-e2aeCAixCj9M7nJxdB/wDjO6mbYX+lJJxSJCXDzlr5YPGYVofuJwGN9nKg2o6wWInjX6XmxRinn3AeJMK81ltw==", "dev": true }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3466,6 +3497,44 @@ "node": ">=0.8.0" } }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -4252,6 +4321,11 @@ "shell-quote": "^1.7.3" } }, + "node_modules/leaflet": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz", + "integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==" + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -4261,6 +4335,20 @@ "node": ">=6.11.5" } }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -5040,6 +5128,19 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-leaflet": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", + "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", + "dependencies": { + "@react-leaflet/core": "^2.1.0" + }, + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/react-router": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", @@ -5761,6 +5862,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-url-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/svg-url-loader/-/svg-url-loader-8.0.0.tgz", + "integrity": "sha512-5doSXvl18hY1fGsRLdhWAU5jgzgxJ06/gc/26cpuDnN0xOz1HmmfhkpL29SSrdIvhtxQ1UwGzmk7wTT/l48mKw==", + "dev": true, + "dependencies": { + "file-loader": "~6.2.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -7625,6 +7741,12 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "@react-leaflet/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", + "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", + "requires": {} + }, "@remix-run/router": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", @@ -8159,6 +8281,12 @@ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -8694,6 +8822,12 @@ "integrity": "sha512-e2aeCAixCj9M7nJxdB/wDjO6mbYX+lJJxSJCXDzlr5YPGYVofuJwGN9nKg2o6wWInjX6XmxRinn3AeJMK81ltw==", "dev": true }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -8915,6 +9049,29 @@ "websocket-driver": ">=0.5.1" } }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -9485,12 +9642,28 @@ "shell-quote": "^1.7.3" } }, + "leaflet": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz", + "integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==" + }, "loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -10066,6 +10239,14 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-leaflet": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", + "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", + "requires": { + "@react-leaflet/core": "^2.1.0" + } + }, "react-router": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", @@ -10635,6 +10816,15 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "svg-url-loader": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/svg-url-loader/-/svg-url-loader-8.0.0.tgz", + "integrity": "sha512-5doSXvl18hY1fGsRLdhWAU5jgzgxJ06/gc/26cpuDnN0xOz1HmmfhkpL29SSrdIvhtxQ1UwGzmk7wTT/l48mKw==", + "dev": true, + "requires": { + "file-loader": "~6.2.0" + } + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", diff --git a/package.json b/package.json index bf31430..0118e3d 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "css-loader": "6.7.3", "html-webpack-plugin": "5.5.1", "style-loader": "3.3.2", + "svg-url-loader": "^8.0.0", "webpack": "5.80.0", "webpack-cli": "5.0.1", "webpack-dev-server": "4.13.3", @@ -32,9 +33,11 @@ }, "dependencies": { "axios": "1.3.6", + "leaflet": "^1.9.3", "prop-types": "15.8.1", "react": "18.2.0", "react-dom": "18.2.0", + "react-leaflet": "^4.2.1", "react-router-dom": "^6.10.0" } }