-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #474 from bounswe/feature/frontend_add_list_and_fi…
…ltering Enhanced annotation logic for Date and Geographical Data and Additional Metadata
- Loading branch information
Showing
5 changed files
with
314 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
Oops, something went wrong.