Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group by model runs on the layer tray #132

Merged
merged 7 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/components/trays/layers/delete-layer-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,30 @@ export const DeleteLayerButton = ({ layerId }) => {
DeleteLayerButton.propTypes = {
layerId: PropTypes.string.isRequired
};

export const DeleteModelRunButton = ({ groupId }) => {
const { removeModelRun } = useLayers();

return (
<ActionButton
color="danger"
variant="outlined"
onClick={ () => removeModelRun(groupId) }
sx={{
alignContent: 'right',
m: 1,
'filter': 'opacity(0.3)',
transition: 'filter 250ms',
'&:hover': {
'filter': 'opacity(1.0)',
},
}}
>
<RemoveIcon />
</ActionButton>
);
};

DeleteModelRunButton.propTypes = {
groupId: PropTypes.string.isRequired
};
2 changes: 1 addition & 1 deletion src/components/trays/layers/form.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { ModelSelection } from '../model-selection/model-selection';
import { ModelSelection } from '@model-selection/model-selection';

export const AddLayerForm = () => {
return (
Expand Down
158 changes: 148 additions & 10 deletions src/components/trays/layers/list.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,165 @@
import React from 'react';
import {
AccordionGroup,
Divider,
AccordionGroup, Box,
Divider, Accordion, AccordionSummary, AccordionDetails
} from '@mui/joy';
import { useLayers } from '@context';
import { LayerCard } from './layer-card';
import { DeleteModelRunButton } from "@components/trays/layers/delete-layer-button";

/**
* gets the header data property name index
* This takes into account the two types of runs (tropical, synoptic)
*
* @param layerProps
* @param type
* @returns {string}
*/
const getPropertyName = (layerProps, type) => {
// init the return
let ret_val = undefined;

// capture the name of the element for tropical storms and advisory numbers
if (layerProps['met_class'] === 'tropical') {
switch (type) {
case 'stormOrModelEle':
ret_val = layerProps['storm_name'];
break;
case 'numberName':
ret_val = ' Adv: ';
break;
case 'numberEle':
ret_val = layerProps['advisory_number'];
break;
}
}
// capture the name of the synoptic ADCIRC models and cycle numbers
else {
switch (type) {
case 'stormOrModelEle':
ret_val = layerProps['model'];
break;
case 'numberName':
ret_val = ' Cycle: ';
break;
case 'numberEle':
ret_val = layerProps['cycle'];
break;
}
}

// return to the caller
return ret_val;
};


/**
* gets the summary header text for the layer groups.
* This takes into account the two types of runs (tropical, synoptic)
*
* @param layerProps
* @returns {string}
*/
const getHeaderSummary = (layerProps) => {
// get the full accordian summary text
return layerProps['run_date'] + ': ' +
((getPropertyName(layerProps, 'stormOrModelEle') === undefined) ? 'Data error' : getPropertyName(layerProps, 'stormOrModelEle').toUpperCase()) +
', ' + getPropertyName(layerProps, 'numberName') + getPropertyName(layerProps, 'numberEle') +
', Type: ' + layerProps['event_type'] +
', Grid: ' + layerProps['grid_type'] +
((layerProps['meteorological_model'] === 'None') ? '' : ', ' + layerProps['meteorological_model']);
};

/**
* renders the layer cards for a model run
*
* @param layers
* @param group
* @returns {*[]}
*/
const renderLayerCards = (layers, group) => {
// init the return
const layerCards = [];

// filter/map the layers to create/return the layer card list
layers
// capture the layers for this group
.filter(layer => ( layer['group'] === group) )
// at this point we have the distinct runs
.map((layer, idx) => {
layerCards.push(<LayerCard key={`layer-${ idx }`} layer={ layer } index={ idx }> </LayerCard>);
});

// return to the caller
return layerCards;
};

/**
* collect the list of unique layer groups
*
* @param layers
* @returns {*[]}
*/
const getGroupList = (layers) => {
// init the group list
const groupList = [];

// loop through the layers and get the unique groups
layers
// filter by the group name
.filter((groups, idx, self) =>
( idx === self.findIndex((t)=> ( t['group'] === groups['group']) )))
// .sort((a, b) =>
// a['run_date'] < b['run_date'] ? 1 : -1)
// at this point we have the distinct runs
.map((layer) => {
groupList.push(layer);
});

// return the list of groups
return groupList;
};

/**
* render the layers for the selected run groups
*
* @returns {JSX.Element}
* @constructor
*/
export const LayersList = () => {
// get a handle to the layer state
const { defaultModelLayers } = useLayers();

// get the default layers
const layers = [...defaultModelLayers];

// get the unique groups in the selected run groups
const groupList = getGroupList(layers);

// loop through the layers and put them away
return (
<AccordionGroup variant="soft">
{
layers
.sort((a, b) => a.state.order - b.state.order)
.map((layer, index) => {
// loop through the layer groups and put them away
groupList
// filter by the group name
.filter((groups, idx, self) =>
( idx === self.findIndex((t)=> ( t['group'] === groups['group']) )))
// at this point we have the distinct runs
.map((groups, idx) => {
return (
<LayerCard
key={ `layer-${ layer.id }` }
layer={ layer }
index={ index }
/>
<Accordion key={idx}>
<Box sx={{ display: "flex" }}>
<DeleteModelRunButton groupId={ groups['group'] } />
<Box>
<AccordionSummary sx={{ fontSize: 12 }}>{ getHeaderSummary(groups['properties']) } </AccordionSummary>
</Box>
</Box>

<AccordionDetails>
{ renderLayerCards( layers, groups['group'] ) }
</AccordionDetails>
</Accordion>
);
})
}
Expand Down
4 changes: 0 additions & 4 deletions src/components/trays/model-selection/catalogItems.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export default function CatalogItems(data) {
const [accordianDateIndex, setAccordianDateIndex] = useState(-1);

// variables for the display of checkbox labels
let stormOrModelName = null;
let stormOrModelEle = null;
let numberName = null;
let numberEle = null;
Expand Down Expand Up @@ -137,14 +136,12 @@ export default function CatalogItems(data) {
else {
// save the name of the element for tropical storms and advisory numbers
if (data.isTropical) {
stormOrModelName = '';
stormOrModelEle = 'storm_name';
numberName = ' Adv: ';
numberEle = 'advisory_number';
}
// save the name of the synoptic ADCIRC models and cycle numbers
else if (!data.isTropical) {
stormOrModelName = '';
stormOrModelEle = 'model';
numberName = ' Cycle: ';
numberEle = 'cycle';
Expand Down Expand Up @@ -185,7 +182,6 @@ export default function CatalogItems(data) {
key={ mbrIdx }
checked={ getCheckedState(mbr.group) }
label={
stormOrModelName +
((mbr['properties'][stormOrModelEle] === undefined) ? 'Data error' : mbr['properties'][stormOrModelEle].toUpperCase()) + ', ' +
numberName + mbr['properties'][numberEle] +
', Type: ' + mbr['properties']['event_type'] +
Expand Down
10 changes: 10 additions & 0 deletions src/context/map-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ export const LayersProvider = ({ children }) => {
setDefaultModelLayers(newLayers);
};

const removeModelRun = groupId => {
const index = defaultModelLayers.findIndex(l => l.group === groupId);
if (index === -1) {
return;
}
const newLayers = defaultModelLayers.filter(l => l.group !== groupId);
setDefaultModelLayers(newLayers);
};

const setLayerOpacity = (id, newOpacity) => {
const newLayers = [...defaultModelLayers];
const index = newLayers.findIndex(l => l.id === id);
Expand Down Expand Up @@ -166,6 +175,7 @@ export const LayersProvider = ({ children }) => {
showShareComment, setShowShareComment,
swapLayers,
removeLayer,
removeModelRun,
layerTypes,
baseMap,
setBaseMap,
Expand Down