Sorted events in date order and improved Map fitting
This commit is contained in:
parent
3d2b71c768
commit
9124274603
@ -8,6 +8,7 @@ import Sidebar from "@components/Sidebar";
|
|||||||
import { createPoster } from "@utils/axiosHelpers";
|
import { createPoster } from "@utils/axiosHelpers";
|
||||||
import { Earthquake } from "@prismaclient";
|
import { Earthquake } from "@prismaclient";
|
||||||
import { getRelativeDate } from "@utils/formatters";
|
import { getRelativeDate } from "@utils/formatters";
|
||||||
|
import GeologicalEvent from "@appTypes/Event";
|
||||||
|
|
||||||
export default function Earthquakes() {
|
export default function Earthquakes() {
|
||||||
const [selectedEventId, setSelectedEventId] = useState("");
|
const [selectedEventId, setSelectedEventId] = useState("");
|
||||||
@ -18,14 +19,20 @@ export default function Earthquakes() {
|
|||||||
const earthquakeEvents = useMemo(
|
const earthquakeEvents = useMemo(
|
||||||
() =>
|
() =>
|
||||||
data && data.earthquakes
|
data && data.earthquakes
|
||||||
? data.earthquakes.map((x: Earthquake) => ({
|
? data.earthquakes
|
||||||
id: x.id,
|
.map(
|
||||||
|
(x: Earthquake): GeologicalEvent => ({
|
||||||
|
id: x.code,
|
||||||
title: `Earthquake in ${x.code.split("-")[2]}`,
|
title: `Earthquake in ${x.code.split("-")[2]}`,
|
||||||
magnitude: x.magnitude,
|
magnitude: x.magnitude,
|
||||||
longitude: x.longitude,
|
longitude: x.longitude,
|
||||||
latitude: x.latitude,
|
latitude: x.latitude,
|
||||||
|
text1: "",
|
||||||
text2: getRelativeDate(x.date),
|
text2: getRelativeDate(x.date),
|
||||||
}))
|
date: x.date,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.sort((a: GeologicalEvent, b: GeologicalEvent) => new Date(b.date).getTime() - new Date(a.date).getTime()) // Remove Date conversion
|
||||||
: [],
|
: [],
|
||||||
[data]
|
[data]
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
@ -6,18 +7,41 @@ import useSWR from "swr";
|
|||||||
import Sidebar from "@/components/Sidebar";
|
import Sidebar from "@/components/Sidebar";
|
||||||
import Map from "@components/Map";
|
import Map from "@components/Map";
|
||||||
import { fetcher } from "@utils/axiosHelpers";
|
import { fetcher } from "@utils/axiosHelpers";
|
||||||
|
import { Observatory } from "@prismaclient";
|
||||||
|
import { getRelativeDate } from "@utils/formatters";
|
||||||
|
import GeologicalEvent from "@appTypes/Event";
|
||||||
|
|
||||||
export default function Observatories() {
|
export default function Observatories() {
|
||||||
const [selectedEventId, setSelectedEventId] = useState("");
|
const [selectedEventId, setSelectedEventId] = useState("");
|
||||||
const [hoveredEventId, setHoveredEventId] = useState("");
|
const [hoveredEventId, setHoveredEventId] = useState("");
|
||||||
// todo properly integrate loading
|
|
||||||
const { data, error, isLoading } = useSWR("/api/observatories", fetcher);
|
const { data, error, isLoading } = useSWR("/api/observatories", fetcher);
|
||||||
|
|
||||||
|
// todo add in earthquake events
|
||||||
|
const observatoryEvents = useMemo(
|
||||||
|
() =>
|
||||||
|
data && data.observatories
|
||||||
|
? data.observatories
|
||||||
|
.map(
|
||||||
|
(x: Observatory): GeologicalEvent => ({
|
||||||
|
id: x.id.toString(),
|
||||||
|
title: `New Observatory - ${x.name}`,
|
||||||
|
longitude: x.longitude,
|
||||||
|
latitude: x.latitude,
|
||||||
|
text1: "",
|
||||||
|
text2: getRelativeDate(x.dateEstablished),
|
||||||
|
date: x.dateEstablished,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.sort((a: GeologicalEvent, b: GeologicalEvent) => new Date(b.date).getTime() - new Date(a.date).getTime()) // Remove Date conversion
|
||||||
|
: [],
|
||||||
|
[data]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-[calc(100vh-3.5rem)] w-full overflow-hidden">
|
<div className="flex h-[calc(100vh-3.5rem)] w-full overflow-hidden">
|
||||||
<div className="flex-grow h-full">
|
<div className="flex-grow h-full">
|
||||||
<Map
|
<Map
|
||||||
events={data ? data.observatories : []}
|
events={observatoryEvents}
|
||||||
selectedEventId={selectedEventId}
|
selectedEventId={selectedEventId}
|
||||||
setSelectedEventId={setSelectedEventId}
|
setSelectedEventId={setSelectedEventId}
|
||||||
hoveredEventId={hoveredEventId}
|
hoveredEventId={hoveredEventId}
|
||||||
@ -29,7 +53,7 @@ export default function Observatories() {
|
|||||||
logTitle="Observatory Mapping"
|
logTitle="Observatory Mapping"
|
||||||
logSubtitle="Record and search observatories - time/date set-up, location, scientists and recent earthquakes"
|
logSubtitle="Record and search observatories - time/date set-up, location, scientists and recent earthquakes"
|
||||||
recentsTitle="Observatory Events"
|
recentsTitle="Observatory Events"
|
||||||
events={data ? data.observatories : []}
|
events={observatoryEvents}
|
||||||
selectedEventId={selectedEventId}
|
selectedEventId={selectedEventId}
|
||||||
setSelectedEventId={setSelectedEventId}
|
setSelectedEventId={setSelectedEventId}
|
||||||
hoveredEventId={hoveredEventId}
|
hoveredEventId={hoveredEventId}
|
||||||
|
|||||||
@ -1,25 +1,22 @@
|
|||||||
import "mapbox-gl/dist/mapbox-gl.css";
|
import "mapbox-gl/dist/mapbox-gl.css";
|
||||||
|
|
||||||
import mapboxgl, { LngLatBounds } from "mapbox-gl";
|
import mapboxgl, { LngLatBounds } from "mapbox-gl";
|
||||||
import { userAgentFromString } from "next/server";
|
|
||||||
import React, { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from "react";
|
import React, { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from "react";
|
||||||
import ReactDOM from "react-dom";
|
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import { GiObservatory } from "react-icons/gi";
|
import { GiObservatory } from "react-icons/gi";
|
||||||
|
|
||||||
import Event from "@appTypes/Event";
|
import GeologicalEvent from "@appTypes/Event";
|
||||||
import getMagnitudeColor from "@utils/getMagnitudeColour";
|
import getMagnitudeColor from "@utils/getMagnitudeColour";
|
||||||
|
|
||||||
interface MapComponentProps {
|
interface MapComponentProps {
|
||||||
events: Event[];
|
events: GeologicalEvent[];
|
||||||
selectedEventId: Event["id"];
|
selectedEventId: GeologicalEvent["id"];
|
||||||
setSelectedEventId: Dispatch<SetStateAction<string>>;
|
setSelectedEventId: Dispatch<SetStateAction<string>>;
|
||||||
hoveredEventId: Event["id"];
|
hoveredEventId: GeologicalEvent["id"];
|
||||||
setHoveredEventId: Dispatch<SetStateAction<string>>;
|
setHoveredEventId: Dispatch<SetStateAction<string>>;
|
||||||
mapType: String;
|
mapType: String;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map component with location-style pulsing dots, animations, and tooltips
|
|
||||||
function MapComponent({
|
function MapComponent({
|
||||||
events,
|
events,
|
||||||
selectedEventId,
|
selectedEventId,
|
||||||
@ -32,9 +29,9 @@ function MapComponent({
|
|||||||
const markers = useRef<{ [key: string]: mapboxgl.Marker }>({});
|
const markers = useRef<{ [key: string]: mapboxgl.Marker }>({});
|
||||||
const [mapBounds, setMapBounds] = useState<LngLatBounds>();
|
const [mapBounds, setMapBounds] = useState<LngLatBounds>();
|
||||||
|
|
||||||
const fitToBounds = useCallback((bounds: LngLatBounds) => {
|
const fitToBounds = useCallback((bounds: LngLatBounds, padding: number = 150) => {
|
||||||
if (map.current && bounds) {
|
if (map.current && bounds) {
|
||||||
map.current!.fitBounds(bounds, { padding: 150, maxZoom: 10 });
|
map.current!.fitBounds(bounds, { padding, maxZoom: 10, zoom: 1 });
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -49,7 +46,7 @@ function MapComponent({
|
|||||||
Object.values(markers.current).forEach((marker) => marker.getPopup()?.remove());
|
Object.values(markers.current).forEach((marker) => marker.getPopup()?.remove());
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const flyToEvent = useCallback((event: Event) => {
|
const flyToEvent = useCallback((event: GeologicalEvent) => {
|
||||||
if (map.current) {
|
if (map.current) {
|
||||||
map.current.flyTo({
|
map.current.flyTo({
|
||||||
center: [event.longitude, event.latitude],
|
center: [event.longitude, event.latitude],
|
||||||
@ -76,15 +73,13 @@ function MapComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
map.current.on("load", () => {
|
map.current.on("load", () => {
|
||||||
// Fit map to bounds
|
|
||||||
const bounds = new mapboxgl.LngLatBounds();
|
const bounds = new mapboxgl.LngLatBounds();
|
||||||
events.forEach((event) => {
|
events.forEach((event) => {
|
||||||
bounds.extend([event.longitude, event.latitude]);
|
bounds.extend([event.longitude, event.latitude]);
|
||||||
});
|
});
|
||||||
fitToBounds(bounds);
|
fitToBounds(bounds, 0);
|
||||||
setMapBounds(bounds);
|
setMapBounds(bounds);
|
||||||
|
|
||||||
// Add markers with location pulse
|
|
||||||
events.forEach((event) => {
|
events.forEach((event) => {
|
||||||
const quakeElement = document.createElement("div");
|
const quakeElement = document.createElement("div");
|
||||||
const dotElement = document.createElement("div");
|
const dotElement = document.createElement("div");
|
||||||
@ -92,37 +87,31 @@ function MapComponent({
|
|||||||
|
|
||||||
if (event.magnitude) {
|
if (event.magnitude) {
|
||||||
const color = getMagnitudeColor(event.magnitude);
|
const color = getMagnitudeColor(event.magnitude);
|
||||||
|
quakeElement.style.width = "50px";
|
||||||
// Create marker container
|
|
||||||
quakeElement.style.width = "50px"; // Increased size to accommodate pulse
|
|
||||||
quakeElement.style.height = "50px";
|
quakeElement.style.height = "50px";
|
||||||
quakeElement.style.position = "absolute";
|
quakeElement.style.position = "absolute";
|
||||||
quakeElement.style.display = "flex";
|
quakeElement.style.display = "flex";
|
||||||
quakeElement.style.alignItems = "center";
|
quakeElement.style.alignItems = "center";
|
||||||
quakeElement.style.justifyContent = "center";
|
quakeElement.style.justifyContent = "center";
|
||||||
|
|
||||||
// Central dot
|
|
||||||
dotElement.style.width = "10px";
|
dotElement.style.width = "10px";
|
||||||
dotElement.style.height = "10px";
|
dotElement.style.height = "10px";
|
||||||
dotElement.style.backgroundColor = color;
|
dotElement.style.backgroundColor = color;
|
||||||
dotElement.style.borderRadius = "50%";
|
dotElement.style.borderRadius = "50%";
|
||||||
dotElement.style.position = "absolute";
|
dotElement.style.position = "absolute";
|
||||||
dotElement.style.zIndex = "2"; // Ensure dot is above pulse
|
dotElement.style.zIndex = "2";
|
||||||
|
|
||||||
// Pulsing ring
|
|
||||||
pulseElement.className = "location-pulse";
|
pulseElement.className = "location-pulse";
|
||||||
pulseElement.style.width = "20px"; // Initial size
|
pulseElement.style.width = "20px";
|
||||||
pulseElement.style.height = "20px";
|
pulseElement.style.height = "20px";
|
||||||
pulseElement.style.backgroundColor = `${color}80`; // Color with 50% opacity (hex alpha)
|
pulseElement.style.backgroundColor = `${color}80`;
|
||||||
pulseElement.style.borderRadius = "50%";
|
pulseElement.style.borderRadius = "50%";
|
||||||
pulseElement.style.position = "absolute";
|
pulseElement.style.position = "absolute";
|
||||||
pulseElement.style.zIndex = "1";
|
pulseElement.style.zIndex = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Observatory marker
|
|
||||||
//<GiObservatory />
|
|
||||||
const observatoryElement = document.createElement("div");
|
const observatoryElement = document.createElement("div");
|
||||||
const root = createRoot(observatoryElement); // `createRoot` is now the standard API
|
const root = createRoot(observatoryElement);
|
||||||
root.render(<GiObservatory className="text-blue-600 text-2xl drop-shadow-lg" />);
|
root.render(<GiObservatory className="text-blue-600 text-2xl drop-shadow-lg" />);
|
||||||
|
|
||||||
quakeElement.appendChild(pulseElement);
|
quakeElement.appendChild(pulseElement);
|
||||||
@ -143,9 +132,8 @@ function MapComponent({
|
|||||||
marker.setPopup(popup);
|
marker.setPopup(popup);
|
||||||
markers.current[event.id] = marker;
|
markers.current[event.id] = marker;
|
||||||
|
|
||||||
// Add hover events
|
|
||||||
const markerDomElement = marker.getElement();
|
const markerDomElement = marker.getElement();
|
||||||
markerDomElement.style.cursor = "pointer"; // Optional: indicate interactivity
|
markerDomElement.style.cursor = "pointer";
|
||||||
|
|
||||||
markerDomElement.addEventListener("mouseenter", () => setHoveredEventId(event.id));
|
markerDomElement.addEventListener("mouseenter", () => setHoveredEventId(event.id));
|
||||||
markerDomElement.addEventListener("mouseleave", () => setHoveredEventId(""));
|
markerDomElement.addEventListener("mouseleave", () => setHoveredEventId(""));
|
||||||
@ -153,11 +141,19 @@ function MapComponent({
|
|||||||
setSelectedEventId((prevEventId) => (prevEventId === event.id ? "" : event.id))
|
setSelectedEventId((prevEventId) => (prevEventId === event.id ? "" : event.id))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cleanup event listeners on unmount
|
markerDomElement.dataset.listenersAdded = "true";
|
||||||
markerDomElement.dataset.listenersAdded = "true"; // Mark for cleanup
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add map click handler to deselect when clicking outside markers
|
||||||
|
map.current.on("click", (e) => {
|
||||||
|
const target = e.originalEvent.target as HTMLElement;
|
||||||
|
// Check if the click target is not a marker element
|
||||||
|
if (!target.closest(".mapboxgl-marker")) {
|
||||||
|
setSelectedEventId("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
map.current.on("error", (e) => {
|
map.current.on("error", (e) => {
|
||||||
console.error("Mapbox error:", e);
|
console.error("Mapbox error:", e);
|
||||||
});
|
});
|
||||||
@ -170,22 +166,17 @@ function MapComponent({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const event = events.find((x) => x.id === selectedEventId);
|
const event = events.find((x) => x.id === selectedEventId);
|
||||||
if (event) flyToEvent(event);
|
if (event) flyToEvent(event);
|
||||||
else if (!selectedEventId) {
|
else if (!selectedEventId && mapBounds) {
|
||||||
if (mapBounds) fitToBounds(mapBounds);
|
fitToBounds(mapBounds, 0);
|
||||||
}
|
}
|
||||||
}, [events, selectedEventId, mapBounds, fitToBounds, clearAllPopups, flyToEvent]);
|
}, [events, selectedEventId, mapBounds, fitToBounds, flyToEvent]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Clear all popups first
|
|
||||||
clearAllPopups();
|
clearAllPopups();
|
||||||
|
|
||||||
// Handle both events if they exist and are different
|
|
||||||
if (hoveredEventId && selectedEventId && hoveredEventId !== selectedEventId) {
|
if (hoveredEventId && selectedEventId && hoveredEventId !== selectedEventId) {
|
||||||
showPopup(hoveredEventId);
|
showPopup(hoveredEventId);
|
||||||
showPopup(selectedEventId);
|
showPopup(selectedEventId);
|
||||||
}
|
} else if (hoveredEventId || selectedEventId) {
|
||||||
// Handle single event case (either hovered or selected)
|
|
||||||
else if (hoveredEventId || selectedEventId) {
|
|
||||||
showPopup(hoveredEventId || selectedEventId);
|
showPopup(hoveredEventId || selectedEventId);
|
||||||
}
|
}
|
||||||
}, [hoveredEventId, selectedEventId, clearAllPopups, showPopup]);
|
}, [hoveredEventId, selectedEventId, clearAllPopups, showPopup]);
|
||||||
@ -197,7 +188,6 @@ function MapComponent({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CSS for location-style pulsing animation
|
|
||||||
const pulseStyles = `
|
const pulseStyles = `
|
||||||
.location-pulse {
|
.location-pulse {
|
||||||
animation: locationPulse 2s infinite;
|
animation: locationPulse 2s infinite;
|
||||||
@ -1,18 +1,18 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import React, { Dispatch, SetStateAction } from "react";
|
import React, { Dispatch, SetStateAction, useEffect, useRef } from "react";
|
||||||
import { TbHexagon } from "react-icons/tb";
|
import { TbHexagon } from "react-icons/tb";
|
||||||
|
|
||||||
import Event from "@appTypes/Event";
|
import GeologicalEvent from "@appTypes/Event";
|
||||||
import getMagnitudeColor from "@utils/getMagnitudeColour";
|
import getMagnitudeColor from "@utils/getMagnitudeColour";
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
logTitle: string;
|
logTitle: string;
|
||||||
logSubtitle: string;
|
logSubtitle: string;
|
||||||
recentsTitle: string;
|
recentsTitle: string;
|
||||||
events: Event[];
|
events: GeologicalEvent[];
|
||||||
selectedEventId: Event["id"];
|
selectedEventId: GeologicalEvent["id"];
|
||||||
setSelectedEventId: Dispatch<SetStateAction<string>>;
|
setSelectedEventId: Dispatch<SetStateAction<string>>;
|
||||||
hoveredEventId: Event["id"];
|
hoveredEventId: GeologicalEvent["id"];
|
||||||
setHoveredEventId: Dispatch<SetStateAction<string>>;
|
setHoveredEventId: Dispatch<SetStateAction<string>>;
|
||||||
button1Name: string;
|
button1Name: string;
|
||||||
button2Name: string;
|
button2Name: string;
|
||||||
@ -48,6 +48,20 @@ export default function Sidebar({
|
|||||||
button1Name,
|
button1Name,
|
||||||
button2Name,
|
button2Name,
|
||||||
}: SidebarProps) {
|
}: SidebarProps) {
|
||||||
|
const eventsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventId && eventsContainerRef.current) {
|
||||||
|
const selectedEventElement = eventsContainerRef.current.querySelector(`[data-event-id="${selectedEventId}"]`);
|
||||||
|
if (selectedEventElement) {
|
||||||
|
selectedEventElement.scrollIntoView({
|
||||||
|
block: "center",
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedEventId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full w-80 bg-gradient-to-b from-neutral-100 to-neutral-50 shadow-lg">
|
<div className="flex flex-col h-full w-80 bg-gradient-to-b from-neutral-100 to-neutral-50 shadow-lg">
|
||||||
<div className="py-6 flex flex-col h-full">
|
<div className="py-6 flex flex-col h-full">
|
||||||
@ -66,13 +80,14 @@ export default function Sidebar({
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-6 pt-6">
|
<div className="px-6 pt-6">
|
||||||
<h2 className="text-xl font-bold text-neutral-800 mb-2">{recentsTitle}</h2>
|
<h2 className="text-xl font-bold text-neutral-800 mb-4">{recentsTitle}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 px-6 overflow-y-auto pt-2">
|
<div className="flex-1 px-6 overflow-y-auto" ref={eventsContainerRef}>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{events.map((event) => (
|
{events.map((event) => (
|
||||||
<button
|
<button
|
||||||
key={event.title}
|
key={event.id}
|
||||||
|
data-event-id={event.id}
|
||||||
className={`w-full border ${hoveredEventId === event.id ? "bg-neutral-100" : "bg-white"} ${
|
className={`w-full border ${hoveredEventId === event.id ? "bg-neutral-100" : "bg-white"} ${
|
||||||
selectedEventId === event.id ? "border-neutral-800" : "border-neutral-200"
|
selectedEventId === event.id ? "border-neutral-800" : "border-neutral-200"
|
||||||
} rounded-lg p-4 flex items-center gap-4 hover:bg-neutral-100 transition-colors duration-150 shadow-sm text-left`}
|
} rounded-lg p-4 flex items-center gap-4 hover:bg-neutral-100 transition-colors duration-150 shadow-sm text-left`}
|
||||||
@ -83,8 +98,8 @@ export default function Sidebar({
|
|||||||
onMouseLeave={() => setHoveredEventId("")}
|
onMouseLeave={() => setHoveredEventId("")}
|
||||||
>
|
>
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<p className="text-sm font-medium text-neutral-800 truncate">{event.title}</p>
|
<p className="text-sm font-medium text-neutral-800 line-clamp-1">{event.title}</p>
|
||||||
<p className="text-xs text-neutral-500 mt-1 truncate">{event.text2}</p>
|
<p className="text-xs text-neutral-500 mt-1 line-clamp-1">{event.text2}</p>
|
||||||
</div>
|
</div>
|
||||||
{event.magnitude ? <MagnitudeNumber magnitude={event.magnitude} /> : <></>}
|
{event.magnitude ? <MagnitudeNumber magnitude={event.magnitude} /> : <></>}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
interface Event {
|
interface GeologicalEvent {
|
||||||
id: string;
|
id: string;
|
||||||
|
date: Date;
|
||||||
title: string;
|
title: string;
|
||||||
magnitude?: number;
|
magnitude?: number;
|
||||||
longitude: number;
|
longitude: number;
|
||||||
@ -8,4 +9,4 @@ interface Event {
|
|||||||
text2: string;
|
text2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Event;
|
export default GeologicalEvent;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user