import { useMemo } from 'react'; import { Box, Flex, Spinner, Text } from '@chakra-ui/react'; import { useColorMode } from "@/components/ui/color-mode.jsx"; import Plot from 'react-plotly.js'; import VdapApi from '../../hooks/useVdapApi.js'; import useBuildUrl from "@/hooks/useBuildUrl.js"; // 1. Import your central color dictionary import { rawWidgetColors } from '../../theme.js'; export default function ExplosionEvents({ settings, widgetID }) { // Plotly expects 'linear' for normal axes const plotYAxisType = settings?.yAxisScale === 'log' ? 'log' : 'linear'; // 🎨 Let's check color mode so we can make people happy with light and dark const { colorMode } = useColorMode(); // Assign the active palette based on the current mode const plotColors = colorMode === 'dark' ? rawWidgetColors.dark : rawWidgetColors.light; // Generate url with input dates, default to 7 day range const url = useBuildUrl('/api/v2/explosion_events', settings?.startDate, settings?.endDate); // Clean, single-line data fetching const { data: apiData, isLoading, error } = VdapApi(url); // 1. Build the Traces (Data parsing) const plotTraces = useMemo(() => { if (!apiData || apiData.length === 0) return []; // Array of distinct Plotly shapes const Symbolway = [ 'circle', 'square', 'diamond', 'triangle-up', 'triangle-down', 'star', 'hexagram', 'pentagon', 'hexagon', 'octagon', 'cross', 'x' ]; // Sort data descending by number of events so smaller dots draw on top of larger ones const sortedData = [...apiData].sort((a, b) => b.number_events - a.number_events); // Efficiently group into Plotly traces by volcano const groupedData = sortedData.reduce((acc, curr) => { const name = curr.volcano_name || 'Unknown'; if (!acc[name]) acc[name] = { x: [], y: [] }; // Map the explosion-specific keys acc[name].x.push(new Date(curr.ts_epoch)); acc[name].y.push(curr.number_events); return acc; }, {}); return Object.keys(groupedData).map((volcanoName, index) => ({ name: volcanoName, x: groupedData[volcanoName].x, y: groupedData[volcanoName].y, type: 'scatter', mode: 'markers', marker: { size: 7, line: { width: .5, color: plotColors.text }, symbol: Symbolway[index % Symbolway.length], }, // Replicating the clean D3/Observable tooltip hovertemplate: `${volcanoName}
` + 'Date (UTC): %{x|%b %d %Y %H:%M}
' + 'Number of Explosions: %{y}' })); }, [apiData, plotColors]); // 2. Build the Layout (Styling and Grid) const layout = useMemo(() => { return { autosize: true, paper_bgcolor: 'transparent', plot_bgcolor: 'transparent', font: { color: plotColors.muted }, margin: { t: 40, r: 20, l: 20, b: 20 }, xaxis: { title: { text: 'Date (UTC)', font: { color: plotColors.text, size: 12 } }, type: 'date', tickformat: '%b %d
%Y', gridcolor: plotColors.grid, zerolinecolor: plotColors.grid, automargin: true, }, yaxis: { title: { text: 'Number of Explosions', font: { color: plotColors.text, size: 12 } }, type: plotYAxisType, gridcolor: plotColors.grid, zerolinecolor: plotColors.text, automargin: true, }, hovermode: 'closest', shapes: [ { type: 'line', x0: 0, x1: 1, xref: 'paper', // Spans entire chart width y0: 0, y1: 0, yref: 'y', line: { color: plotColors.text, width: 1 } } ], }; }, [plotYAxisType, plotColors]); if (isLoading) return ( ); if (error) return ( {error} ); if (plotTraces.length === 0) return ( No data available for current filter. ); return ( ); }