Skip to content

Commit

Permalink
Merge pull request #474 from bounswe/feature/frontend_add_list_and_fi…
Browse files Browse the repository at this point in the history
…ltering

Enhanced annotation logic for Date and Geographical Data and Additional Metadata
  • Loading branch information
kubraaksux authored Nov 27, 2023
2 parents 01bdaa3 + aa517c5 commit c47a42b
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 101 deletions.
1 change: 0 additions & 1 deletion resq/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"@emotion/styled": "^11.11.0",
"@fontsource/inter": "^5.0.15",
"@mui/icons-material": "^5.14.14",
"@mui/joy": "^5.0.0-beta.15",
"@mui/material": "^5.14.14",
"@mui/styled-engine": "^5.14.14",
"@mui/x-data-grid": "^6.18.1",
Expand Down
84 changes: 84 additions & 0 deletions resq/frontend/src/components/AnnotationCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { useEffect, useState } from 'react';
import { Box, Typography, Button, Chip, Dialog, DialogTitle, DialogContent, DialogContentText } from '@mui/material';
import reverseGeocode from './Geolocation';

const AnnotationCard = ({ annotation }) => {
const [locationName, setLocationName] = useState('Unknown Location');
const [open, setOpen] = useState(false); // Added for Dialog control
const [longDescription, setLongDescription] = useState(''); // State to hold long description

useEffect(() => {
if (annotation.latitude && annotation.longitude) {
reverseGeocode(annotation.latitude, annotation.longitude)
.then((name) => setLocationName(name))
.catch((error) => console.error('Error fetching location name:', error));
}
}, [annotation.latitude, annotation.longitude]);

const handleViewMore = () => {
setLongDescription(annotation.long_description || 'Long description not available.');
setOpen(true); // Open the dialog
};


const handleClose = () => {
setOpen(false); // Close the dialog
};

// Dialog component to show long description
const LongDescriptionDialog = () => (
<Dialog open={open} onClose={handleClose}>
<DialogTitle>{annotation.title}</DialogTitle>
<DialogContent>
<DialogContentText>
{longDescription || 'Long description not available.'}
</DialogContentText>
</DialogContent>
</Dialog>
);


return (
<Box
padding={2}
border={1}
borderColor="grey.300"
borderRadius={4}
marginY={2}
display="flex"
flexDirection="column"
>
<Typography variant="h6">{annotation.title}</Typography>
<Typography variant="subtitle1" color="textSecondary">
{annotation.category}
</Typography>
<Typography variant="body1">{annotation.short_description}</Typography>

{/* Date and Location Data */}
{annotation.date && (
<Typography variant="body2">Date: {new Date(annotation.date).toLocaleDateString()}</Typography>
)}
{locationName !== 'Unknown Location' && (
<Typography variant="body2">Location: {locationName}</Typography>
)}

{/* Additional Metadata */}
{annotation.additionalMetadata && (
<Box marginTop={1}>
{Object.entries(annotation.additionalMetadata).map(([key, value]) => (
<Chip key={key} label={`${key}: ${value}`} variant="outlined" size="small" />
))}
</Box>
)}

<Button color="primary" onClick={() => handleViewMore(annotation)}>
View More
</Button>

{/* Long Description Dialog */}
<LongDescriptionDialog />
</Box>
);
};

export default AnnotationCard;
99 changes: 65 additions & 34 deletions resq/frontend/src/components/DisasterMap.js
Original file line number Diff line number Diff line change
@@ -1,70 +1,101 @@
import * as React from 'react';
import {useState} from 'react';
import {Map, Marker, ZoomControl} from 'pigeon-maps';
import {type_colors} from "../Colors";
import {AnnotationIcon, MarkerIcon} from "./MapIcons";
import React, { useState, useEffect } from 'react';
import { Map, Marker, ZoomControl } from 'pigeon-maps';
import { type_colors } from "../Colors";
import { AnnotationIcon, MarkerIcon } from "./MapIcons";

const MAPBOX_TOKEN = "pk.eyJ1IjoiaWxnYXplciIsImEiOiJjbG80Nzg4Z3gwMjZ4MmtxcTR3bGI5enR3In0.QdNftxZYpJ79K0M0DfYHUw"
const MAPBOX_STYLE = "mapbox/streets-v12"
const MAPBOX_TOKEN = "pk.eyJ1IjoiaWxnYXplciIsImEiOiJjbG80Nzg4Z3gwMjZ4MmtxcTR3bGI5enR3In0.QdNftxZYpJ79K0M0DfYHUw";
const MAPBOX_STYLE = "mapbox/streets-v12";

function mapboxProvider(x, y, z, dpr) {
return `https://api.mapbox.com/styles/v1/${
MAPBOX_STYLE
}/tiles/512/${z}/${x}/${y}${dpr >= 2 ? '@2x' : ''}?access_token=${
MAPBOX_TOKEN
}`;
return `https://api.mapbox.com/styles/v1/${MAPBOX_STYLE}/tiles/512/${z}/${x}/${y}${dpr >= 2 ? '@2x' : ''}?access_token=${MAPBOX_TOKEN}`;
}

const marker_order = ["Annotation", "Request", "Resource"]
const marker_order = ["Annotation", "Request", "Resource"];

export default function DisasterMap({onPointSelected, markers = [], mapCenter, setMapCenter, onBoundsChanged}) {
export default function DisasterMap({ onPointSelected, markers = [], mapCenter, setMapCenter }) {
const [zoom, setZoom] = useState(6.5);

useEffect(() => {
// Calculate bounds to encompass all markers
if (markers.length > 0) {
const bounds = markers.reduce((acc, marker) => {
return [
Math.min(acc[0], marker.latitude),
Math.min(acc[1], marker.longitude),
Math.max(acc[2], marker.latitude),
Math.max(acc[3], marker.longitude),
];
}, [markers[0].latitude, markers[0].longitude, markers[0].latitude, markers[0].longitude]);

// Calculate center and zoom level based on bounds
const center = [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2];
const zoom = getZoomLevel(bounds);

// Set map center and zoom
setMapCenter(center);
setZoom(zoom);
}
}, [markers]);

const renderMarker = (marker) => {
return (
<Marker
width={33}
anchor={[marker.latitude, marker.longitude]}
key={marker.id}
onClick={({event}) => {
onClick={({ event }) => {
onPointSelected(marker);
event.preventDefault()
event.preventDefault();
}}
>
{marker.type === "Annotation" ? <AnnotationIcon icon={marker.category}/> :
<MarkerIcon color={type_colors[marker.type]}/>}
{marker.type === "Annotation" ? <AnnotationIcon icon={marker.category} /> :
<MarkerIcon color={type_colors[marker.type]} />}
</Marker>
);
};

// noinspection JSValidateTypes
const getZoomLevel = (bounds) => {
// Calculate zoom level based on the bounds and map size
const WORLD_DIM = { height: 256, width: 256 };
const ZOOM_MAX = 19;

const latRad1 = (bounds[0] * Math.PI) / 180;
const latRad2 = (bounds[2] * Math.PI) / 180;
const lngRad1 = (bounds[1] * Math.PI) / 180;
const lngRad2 = (bounds[3] * Math.PI) / 180;

const x1 = lngRad1;
const y1 = Math.log(Math.tan(Math.PI / 4 + latRad1 / 2));
const x2 = lngRad2;
const y2 = Math.log(Math.tan(Math.PI / 4 + latRad2 / 2));

const scaleX = WORLD_DIM.width / (x2 - x1);
const scaleY = WORLD_DIM.height / (y2 - y1);
const scale = Math.min(scaleX, scaleY);
const zoom = ZOOM_MAX - Math.log(scale) / Math.log(2);

return zoom;
};

return (
<div style={{display: "flex", height: "100%"}}>
<div style={{flexGrow: 100, height: "100%"}}>
<div style={{ display: "flex", height: "100%" }}>
<div style={{ flexGrow: 100, height: "100%" }}>
<Map
provider={mapboxProvider}
dprs={[1, 2]}
//height={window.innerHeight - (ref?.y || 48)}
//width={ref?.offsetWidth || 100}
center={mapCenter}
zoom={zoom}
onClick={({event}) => {
onClick={({ event }) => {
onPointSelected(null);
event.preventDefault()
event.preventDefault();
}}
onBoundsChanged={({center, zoom, bounds}) => {
setMapCenter(center)
setZoom(zoom)
onBoundsChanged(bounds)
}}>
<ZoomControl/>
>
<ZoomControl />
{markers
.sort(({type}) => -marker_order.indexOf(type))
.sort(({ type }) => -marker_order.indexOf(type))
.map(renderMarker)}
</Map>
</div>
</div>
);
}


18 changes: 18 additions & 0 deletions resq/frontend/src/components/Geolocation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// geocode.js
import axios from 'axios';

const GOOGLE_API_KEY = "AIzaSyCehlfJwJ-V_xOWZ9JK3s0rcjkV2ga0DVg";

// Function to perform reverse geocoding
const reverseGeocode = async (latitude, longitude) => {
try {
const response = await axios.get(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=AIzaSyCehlfJwJ-V_xOWZ9JK3s0rcjkV2ga0DVg`);
const cityName = response.data.results[0]?.formatted_address || 'Unknown Location';
return cityName;
} catch (error) {
console.error('Error fetching location name:', error);
return 'Unknown Location';
}
};

export default reverseGeocode;
Loading

0 comments on commit c47a42b

Please sign in to comment.