diff --git a/src/components/Index.tsx b/src/components/Index.tsx
index 1ebf8e9..ab1c37d 100644
--- a/src/components/Index.tsx
+++ b/src/components/Index.tsx
@@ -1,5 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { useEffect, useState } from "react";
+import { radius } from "../constants";
import { getLocation } from "../functions/getLocation";
import BirdCard from "./BirdCard";
import InteractiveMap from "./InteractiveMap";
@@ -43,7 +44,7 @@ const Index: React.FC = () => {
longitude,
}) => {
const response = await fetch(
- `https://api.ebird.org/v2/data/obs/geo/recent?dist=15&back=3&lat=${Number(latitude)}&lng=${Number(longitude)}`,
+ `https://api.ebird.org/v2/data/obs/geo/recent?dist=${radius}&back=30&includeProvisional=true&lat=${Number(latitude)}&lng=${Number(longitude)}`,
{
headers: {
"X-eBirdApiToken": import.meta.env.VITE_API_KEY_EBIRD,
@@ -72,8 +73,8 @@ const Index: React.FC = () => {
return (
-
Birds around you
+
= ({
+ latitude,
+ longitude,
+ setLatitude,
+ setLongitude,
+ data,
+}) => {
+
+ const [modalOpen, setModalOpen] = useState(false);
+ const [modalContent, setModalContent] = useState("");
-const InteractiveMap: React.FC = ({ latitude, longitude }) => {
const mapRef = useRef(null);
- // create map when latitude and longitude are set
useEffect(() => {
if (!latitude || !longitude) return;
@@ -26,17 +45,106 @@ const InteractiveMap: React.FC = ({ latitude, longitude })
}),
],
view: new View({
- center: [0, 0],
+ center: coordinates,
zoom: 12,
}),
});
- map.getView().setCenter(coordinates);
+ // Add main marker for the central location
+ const marker = new Feature({
+ geometry: new Point(coordinates),
+ });
+
+ marker.setStyle(
+ new Style({
+ image: new Icon({
+ src: "https://openlayers.org/en/latest/examples/data/icon.png",
+ scale: 0.75,
+ }),
+ })
+ );
+
+ const circleFeature = new Feature({
+ geometry: new Circle(coordinates, radius * 1000),
+ });
+
+ circleFeature.setStyle(
+ new Style({
+ stroke: new Stroke({
+ color: "rgba(0, 128, 0, 0.8)",
+ width: 2,
+ }),
+ fill: new Fill({
+ color: "rgba(0, 255, 0, 0.2)",
+ }),
+ })
+ );
+
+ const vectorSource = new VectorSource({
+ features: [marker, circleFeature],
+ });
+
+ data?.forEach((bird) => {
+ const birdCoordinates = fromLonLat([bird.lng, bird.lat]);
+ const birdMarker = new Feature({
+ geometry: new Point(birdCoordinates),
+ });
+
+ birdMarker.setStyle(
+ new Style({
+ image: new Icon({
+ src: birdIcon,
+ scale: 0.75,
+ color: "rgba(255, 0, 0, 0.8)",
+ }),
+ })
+ );
+
+ birdMarker.set("description", `Bird Name: ${bird.comName}`);
+ vectorSource.addFeature(birdMarker);
+ });
+
+ const markerLayer = new VectorLayer({
+ source: vectorSource,
+ });
+
+ map.addLayer(markerLayer);
+
+ // Add click event listener to the map
+ map.on("singleclick", (event) => {
+ const clickedFeature = map.forEachFeatureAtPixel(
+ event.pixel,
+ (feature) => {
+ return feature;
+ }
+ );
+
+ if (clickedFeature) {
+ const description = clickedFeature.get("description");
+ if (description) {
+ setModalContent(description); // Set the content for the modal
+ setModalOpen(true); // Open the modal
+ }
+ } else {
+ const clickedCoordinate = toLonLat(event.coordinate); // Convert to longitude/latitude
+ setLatitude(clickedCoordinate[1].toFixed(2));
+ setLongitude(clickedCoordinate[0].toFixed(2));
+ }
+ });
return () => map.setTarget(undefined);
- }, [latitude, longitude]);
+ }, [latitude, longitude, data, setLatitude, setLongitude]);
- return ;
+ return (
+
+
+
setModalOpen(false)}
+ content={modalContent}
+ />
+
+ );
};
export default InteractiveMap;
diff --git a/src/components/MapModal.tsx b/src/components/MapModal.tsx
new file mode 100644
index 0000000..553dbb9
--- /dev/null
+++ b/src/components/MapModal.tsx
@@ -0,0 +1,24 @@
+
+
+import { MapModalProps } from "../types";
+
+const MapModal: React.FC = ({ isOpen, onClose, content }) => {
+ if (!isOpen) return null;
+
+ return (
+
+
+
Info
+
{content}
+
+
+
+ );
+};
+
+export default MapModal;
diff --git a/src/constants.ts b/src/constants.ts
new file mode 100644
index 0000000..439d407
--- /dev/null
+++ b/src/constants.ts
@@ -0,0 +1 @@
+export const radius = 5;
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
index 2f1e94f..ce1b7f4 100644
--- a/src/index.css
+++ b/src/index.css
@@ -3,5 +3,5 @@
@tailwind utilities;
.h-32rem {
- height: 20rem;
+ height: 32rem;
}
\ No newline at end of file
diff --git a/src/types.tsx b/src/types.tsx
index 587f33e..ba3a8fd 100644
--- a/src/types.tsx
+++ b/src/types.tsx
@@ -21,6 +21,8 @@ export type Bird = {
howMany: number;
locName: string;
obsDt: string;
+ lat: number;
+ lng: number;
};
export type BirdCardProps = {
@@ -91,4 +93,13 @@ export type ErrorProps = {
export type InteractiveMapProps = {
latitude: string;
longitude: string;
-};
\ No newline at end of file
+ setLatitude: (value: string) => void;
+ setLongitude: (value: string) => void;
+ data: Bird[] | undefined;
+};
+
+export type MapModalProps = {
+ isOpen: boolean;
+ onClose: () => void;
+ content: string;
+}
\ No newline at end of file