Added storybook ability to work on widgets before deployment to site.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Box, Flex, Text } from '@chakra-ui/react';
|
||||
import Plot from 'react-plotly.js';
|
||||
|
||||
export default function VaaActivityChart({ data = [] }) {
|
||||
// Transform flat database rows into Plotly's required "Traces"
|
||||
const plotTraces = useMemo(() => {
|
||||
if (!data || data.length === 0) return [];
|
||||
|
||||
const groupedData = data.reduce((acc, curr) => {
|
||||
const name = curr.volc_name || 'Unknown';
|
||||
if (!acc[name]) acc[name] = { x: [], y: [], text: [] };
|
||||
|
||||
acc[name].x.push(new Date(curr.obs_va_epoch));
|
||||
acc[name].y.push(curr.obs_fl);
|
||||
acc[name].text.push(`Volcano: ${name}<br>Flight Level: ${curr.obs_fl}`);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return Object.keys(groupedData).map((volcanoName) => ({
|
||||
name: volcanoName,
|
||||
x: groupedData[volcanoName].x,
|
||||
y: groupedData[volcanoName].y,
|
||||
text: groupedData[volcanoName].text,
|
||||
type: 'scatter',
|
||||
mode: 'markers',
|
||||
hoverinfo: 'text',
|
||||
marker: { size: 8, line: { width: 1, color: 'white' } }
|
||||
}));
|
||||
}, [data]);
|
||||
|
||||
if (plotTraces.length === 0) {
|
||||
return (
|
||||
<Flex height="100%" width="100%" align="center" justify="center" bg="gray.800" borderRadius="md">
|
||||
<Text color="gray.400">No flight level data available.</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box height="100%" width="100%" bg="gray.800" borderRadius="md" overflow="hidden">
|
||||
<Plot
|
||||
data={plotTraces}
|
||||
useResizeHandler={true} // Crucial for reacting to grid drags
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
layout={{
|
||||
autosize: true,
|
||||
paper_bgcolor: 'transparent',
|
||||
plot_bgcolor: 'transparent',
|
||||
font: { color: '#d1d5db' },
|
||||
margin: { t: 40, r: 20, l: 50, b: 40 },
|
||||
title: { text: '7 Day Consolidated Flight Levels', font: { size: 16, color: 'white' }, x: 0.05 },
|
||||
xaxis: { title: 'Date (UTC)', type: 'date', gridcolor: '#4b5563', zerolinecolor: '#4b5563' },
|
||||
yaxis: { title: 'Flight Level', gridcolor: '#4b5563', zerolinecolor: '#ffffff' },
|
||||
legend: { orientation: 'h', y: -0.2, x: 0.5, xanchor: 'center' },
|
||||
hovermode: 'closest'
|
||||
}}
|
||||
config={{ responsive: true, displayModeBar: true, displaylogo: false }}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import VaaActivity7Day from './VaaActivity7Day.jsx';
|
||||
|
||||
export default {
|
||||
title: 'Dashboard Widgets/VAA Activity',
|
||||
component: VaaActivity7Day,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<Box
|
||||
w="100%" maxW="800px" h="400px"
|
||||
border="2px dashed" borderColor="gray.600" p={2}
|
||||
resize="both" overflow="auto"
|
||||
>
|
||||
<Story />
|
||||
</Box>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
const mockData = [
|
||||
{ volc_name: "Fuego", obs_va_epoch: Date.now() - 86400000 * 3, obs_fl: 150 },
|
||||
{ volc_name: "Fuego", obs_va_epoch: Date.now() - 86400000 * 2, obs_fl: 160 },
|
||||
{ volc_name: "Popocatepetl", obs_va_epoch: Date.now() - 86400000 * 3, obs_fl: 220 },
|
||||
{ volc_name: "Popocatepetl", obs_va_epoch: Date.now() - 86400000 * 1, obs_fl: 200 }
|
||||
];
|
||||
|
||||
export const Populated = {
|
||||
args: { data: mockData },
|
||||
};
|
||||
|
||||
export const EmptyState = {
|
||||
args: { data: [] },
|
||||
};
|
||||
Reference in New Issue
Block a user