Skip to content

Commit

Permalink
tidying up the additional layer legends.
Browse files Browse the repository at this point in the history
  • Loading branch information
PhillipsOwen committed Jan 28, 2025
1 parent 010eaed commit 7ceaa2e
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 20 deletions.
3 changes: 2 additions & 1 deletion src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useLayers } from '@context';
import { Sidebar } from '@components/sidebar';
import { ControlPanel } from '@components/control-panel';
import { ComparePanel } from '@components/compare-panel';
import { MapLegend } from '@components/legend';
import { MapLegend, AdditionalMapLegend } from '@components/legend';
import { AlertUser } from '@components/alert-user';
import { Config } from '@components/config';
import { Acknowledgements } from "@components/acknowledgements";
Expand Down Expand Up @@ -43,6 +43,7 @@ const Content = () => {
{ (defaultInstanceName != null) && <ControlPanel/> }
<ComparePanel/>
<MapLegend />
<AdditionalMapLegend />
<Acknowledgements />
</Fragment>
);
Expand Down
106 changes: 106 additions & 0 deletions src/components/legend/additional-legend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, { useRef, Fragment } from 'react';
import { Card, Box, Stack, Avatar, Typography } from '@mui/joy';
import { useLayers } from '@context';
import Draggable from "react-draggable";

/**
* renders the legend for selected additional layers
*
* @constructor
*/
export const AdditionalMapLegend = () => {
// install the selected observation list from the layer context
const { externalLayers, topMostExtLegendIndex, setTopMostExtLegendIndex } = useLayers();

// create a reference to avoid the findDOMNode deprecation issue
const nodeRef = useRef(null);

/**
* handles a click on the legend to make it have focus
*/
const handleClick = (index) => {
// set the new topmost dialog in the stack
setTopMostExtLegendIndex(index);
};

// render the legends
return (
<Fragment>
{
// loop through the external layers and create checkbox selections grouped by the source
externalLayers
// group by the source name
.filter((val, idx, self) => (
idx === self.findIndex((t)=> ( t['source'] === val['source']) ))
)
// output sources
.map((layer) => (
// display legends for all selected external layers
externalLayers
// group by the source name
.filter(item => item.source === layer.source)
// only render visible layers that have a URL to a legend
.filter(item => (item.state.visible && item.params['legendURL']))
// run through all the layers in each group
.map((sublayer, itemIndex) => (
<Draggable
key={ itemIndex }
bounds="parent"
nodeRef={ nodeRef }
handle="#draggable-legend-card"
cancel={ '[class*="MuiDialogContent-root"]' }>

<Card
ref={ nodeRef }
variant="soft"
onClick={ () => handleClick(sublayer['row_num']) }
sx={{
position: 'absolute',
top: 10 + ( 15 * itemIndex ),
right: 75 + ( 25 * itemIndex ),
transition: 'filter 250ms',
padding: '5px',
border: 1,
borderRadius: 'sm',
filter: 'opacity(0.9)', '&:hover': { filter: 'opacity(1.0)' },
width: '60px',
zIndex: (sublayer['row_num'] === topMostExtLegendIndex) ? 1000 : 999 }}>

<Stack
direction="column"
gap={ 1 }
p={ 1 }
alignItems="center">

<Avatar
id="draggable-legend-card"
variant="outlined"
sx={{
filter: 'opacity(0.9)',
'&:hover': { filter: 'opacity(1.0)' },
mt: -.5,
p: 1,
height: 50,
width: 50,
cursor: 'move'
}}>

<Typography sx={{ p: 0, m: 0, fontColor: "black", fontWeight: 'bold', fontSize: "10px" }}>
{ sublayer.source.split(' ').map(word => word.charAt(0)) } { sublayer.row_num }
</Typography>
</Avatar>

<Box
component="img"
alt=""
src={ sublayer.params['legendURL'] }
sx={{ width: '50px', mb: -1, p: 0, height: '160px', zIndex: 999 }} />
</Stack>
</Card>
</Draggable>
))
))
}
</Fragment>
);
};
3 changes: 2 additions & 1 deletion src/components/legend/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './legend';
export * from './legend';
export * from './additional-legend';
1 change: 1 addition & 0 deletions src/components/legend/legend.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const MapLegend = () => {
'&:hover': { filter: 'opacity(1.0)' },
padding: '10px',
zIndex: 999,
border: 1,
borderRadius: 'sm',
visibility: legendVisibilty,

Expand Down
18 changes: 5 additions & 13 deletions src/components/map/external-layers.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,7 @@ export const ExternalLayers = () => {
externalLayers
} = useLayers();

//const sst_url = "https://coastwatch.noaa.gov/erddap/wms/noaacwBLENDEDsstDNDaily/request";
//const sst_layer = "noaacwBLENDEDsstDNDaily:analysed_sst";

//const sst_url = "https://coastwatch.noaa.gov/erddap/wms/noaacwecnAVHRRmultisatsstEastCoastMonthly/request";
//const sst_layer = "noaacwecnAVHRRmultisatsstEastCoastMonthly:sst";

//const sst_url = "https://coastwatch.noaa.gov/erddap/wms/noaacwecnAVHRRmultisatsstEastCoast3Day/request";
//const sst_layer = "noaacwecnAVHRRmultisatsstEastCoast3Day:sst";

// if there are external layers to render
if (externalLayers != null) {
return (
<Fragment>
Expand All @@ -34,10 +26,10 @@ export const ExternalLayers = () => {
.map(
(layer) => (
<WMSTileLayer
key={layer.name}
url={layer.url}
layers={layer.layer}
params={layer.params}
key={ layer.name }
url={ layer.url }
layers={ layer.layer }
params={ layer.params }
/>
)
)
Expand Down
6 changes: 3 additions & 3 deletions src/components/trays/additional-layers/externalLayerItems.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import { KeyboardArrowDown as ExpandIcon } from '@mui/icons-material';
import { useLayers } from "@context/map-context";
import PropTypes from 'prop-types';
import {ActionButton} from "@components/buttons";
import { ActionButton } from "@components/buttons";

// set component prop types
ExternalLayerItems.propTypes = {
Expand Down Expand Up @@ -215,7 +215,7 @@ export default function ExternalLayerItems(data) {
expanded={ getAccordionState(layer['source']) }
onChange={ () => toggleAccordionView(layer['source']) }>

<AccordionSummary>
<AccordionSummary sx={{flexDirection: "row-reverse"}}>
<Typography sx={{ p: 0, fontWeight: 'bold', fontSize: "16px" }}> { layer['source'] }</Typography>
</AccordionSummary>

Expand Down Expand Up @@ -243,7 +243,7 @@ export default function ExternalLayerItems(data) {
<Checkbox
size="sm"
checked={ getCheckedState( layer.name ) }
label={ <Typography sx={{ fontSize: "xs" }}> { layer['name'] } </Typography> }
label={ <Typography sx={{ fontSize: "xs" }}> { layer['row_num'] }: { layer['name'] } </Typography> }
onChange={ () => toggleLayerVisibility(layer['name']) }
/>

Expand Down
2 changes: 2 additions & 0 deletions src/components/trays/remove/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { RemoveAllObservations } from "./remove-observations";
import { RemoveModels } from "./remove-models";
import { ResetStyles } from "./reset-styles";
import { ResetCompare } from "./reset-compare";
import { RemoveAdditionalLayers } from "./remove-addl-layers";

// get an icon for the tray
export const icon = <RemoveIcon />;
Expand All @@ -25,5 +26,6 @@ export const trayContents = () => (
<RemoveModels />
<ResetStyles />
<ResetCompare />
<RemoveAdditionalLayers />
</Stack>
);
21 changes: 21 additions & 0 deletions src/components/trays/remove/remove-addl-layers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { Fragment } from 'react';
import { Button } from '@mui/joy';
import { useLayers } from "@context";

/**
* component that handles the removal of Additional layers.
*
* @returns React.ReactElement
* @constructor
*/
export const RemoveAdditionalLayers = () => {
// get the method to remove the observation items in state
const { removeAdditionalLayers } = useLayers();

// render the button
return (
<Fragment>
<Button color="primary" onClick={() => removeAdditionalLayers()}>Remove selected additional layers</Button>
</Fragment>
);
};
30 changes: 28 additions & 2 deletions src/context/map-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ export const LayersProvider = ({ children }) => {
// state to keep track of the obs dialog that has focus
const [topMostDialogIndex, setTopMostDialogIndex] = useState(0);

// state to keep track of the obs dialog that has focus
const [topMostExtLegendIndex, setTopMostExtLegendIndex] = useState(0);

/**
* this section is for the side-by-side compare mode items
* @type {string}
Expand Down Expand Up @@ -127,6 +130,26 @@ export const LayersProvider = ({ children }) => {
}
};

/**
* hides the selected additional layers
*
*/
const removeAdditionalLayers = () => {
// get a copy of the external layers
const newLayers = [...externalLayers];

// loop through the layers
newLayers.map(layer => {
// if this later is set to visible
if (layer.state.visible) {
layer.state.visible = false;
}
});

// save the altered list
setExternalLayers([...newLayers]);
};

/**
* clears any captured compare selection data and layers
*
Expand Down Expand Up @@ -452,10 +475,13 @@ export const LayersProvider = ({ children }) => {
selectedRightLayer, setSelectedRightLayer,
sideBySideLayers, setSideBySideLayers,
resetCompare, removeSideBySideLayers,

removeAdditionalLayers,

// tracks the dialog that has focus
topMostDialogIndex, setTopMostDialogIndex
topMostDialogIndex, setTopMostDialogIndex,

// tracks the topmost additional layer legend index
topMostExtLegendIndex, setTopMostExtLegendIndex
}}
>
{children}
Expand Down

0 comments on commit 7ceaa2e

Please sign in to comment.