From 6a32cad264390d11d7eaed054d2d3d371681837c Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Fri, 3 May 2024 10:36:29 +0200 Subject: [PATCH 1/9] experimenting with map splitter --- src/actions/controlActions.tsx | 13 +++++ src/components/MapSplitter.tsx | 91 +++++++++++++++++++++++++++++++ src/components/VariableSelect.tsx | 20 ++++++- src/components/Viewer.tsx | 3 + src/components/ol/Map.tsx | 3 + src/connected/MapSplitter.tsx | 39 +++++++++++++ src/connected/VariableSelect.tsx | 8 ++- src/connected/Viewer.tsx | 2 + src/reducers/controlReducer.ts | 4 ++ src/states/controlState.ts | 2 + 10 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 src/components/MapSplitter.tsx create mode 100644 src/connected/MapSplitter.tsx diff --git a/src/actions/controlActions.tsx b/src/actions/controlActions.tsx index 2c37b47b..3d629792 100644 --- a/src/actions/controlActions.tsx +++ b/src/actions/controlActions.tsx @@ -357,6 +357,18 @@ export function selectVariable( //////////////////////////////////////////////////////////////////////////////// +export const TOGGLE_VARIABLE_COMPARE_MODE = "TOGGLE_VARIABLE_COMPARE_MODE"; + +export interface ToggleVariableCompareMode { + type: typeof TOGGLE_VARIABLE_COMPARE_MODE; +} + +export function toggleVariableCompareMode(): ToggleVariableCompareMode { + return { type: TOGGLE_VARIABLE_COMPARE_MODE }; +} + +//////////////////////////////////////////////////////////////////////////////// + export const SELECT_TIME = "SELECT_TIME"; export interface SelectTime { @@ -751,4 +763,5 @@ export type ControlAction = | ShowInfoCard | SetVisibleInfoCardElements | UpdateInfoCardElementCodeMode + | ToggleVariableCompareMode | FlyTo; diff --git a/src/components/MapSplitter.tsx b/src/components/MapSplitter.tsx new file mode 100644 index 00000000..78e61b3c --- /dev/null +++ b/src/components/MapSplitter.tsx @@ -0,0 +1,91 @@ +import React, { useState, useRef } from "react"; +import makeStyles from "@mui/styles/makeStyles"; +import { isNumber } from "@/util/types"; + +const useStyles = makeStyles({ + splitter: { + position: "absolute", + top: 0, + left: "50%", + width: "6px", + height: "100%", + background: "white", + zIndex: 999, + opacity: "50%", + border: "1px solid yellow", + cursor: "col-resize", + }, +}); + +type Point = [number, number]; + +function useMouseDrag(onMouseDrag: (delta: Point) => void) { + const lastPosition = useRef(null); + + const handleMouseMove = useRef((event: MouseEvent) => { + if (event.buttons === 1 && lastPosition.current !== null) { + event.preventDefault(); + const { screenX, screenY } = event; + const [lastScreenX, lastScreenY] = lastPosition.current; + const delta: Point = [screenX - lastScreenX, screenY - lastScreenY]; + lastPosition.current = [screenX, screenY]; + onMouseDrag(delta); + } + }); + + // Return value + const startDrag = useRef((event: React.MouseEvent) => { + if (event.buttons === 1) { + event.preventDefault(); + document.body.addEventListener("mousemove", handleMouseMove.current); + document.body.addEventListener("mouseup", endDrag.current); + document.body.addEventListener("onmouseleave", endDrag.current); + lastPosition.current = [event.screenX, event.screenY]; + } + }); + + const endDrag = useRef((event: Event) => { + if (lastPosition.current !== null) { + event.preventDefault(); + lastPosition.current = null; + document.body.removeEventListener("mousemove", handleMouseMove.current); + document.body.removeEventListener("mouseup", endDrag.current); + document.body.removeEventListener("onmouseleave", endDrag.current); + } + }); + + return startDrag.current; +} + +interface MapSplitterProps { + hidden?: boolean; + position?: number; +} + +export default function MapSplitter({ hidden, position }: MapSplitterProps) { + // TODO: move up as prop + const [_position, setPosition] = useState(position); + + const classes = useStyles(); + const divRef = useRef(null); + const handleDrag = useRef(([deltaX, _]: Point) => { + if (divRef.current !== null) { + setPosition(divRef.current.offsetLeft + deltaX); + } + }); + const startDrag = useMouseDrag(handleDrag.current); + + if (hidden) { + return null; + } + + return ( +
+ ); +} diff --git a/src/components/VariableSelect.tsx b/src/components/VariableSelect.tsx index ddd83fc9..ebcdc513 100644 --- a/src/components/VariableSelect.tsx +++ b/src/components/VariableSelect.tsx @@ -33,6 +33,7 @@ import Select, { SelectChangeEvent } from "@mui/material/Select"; import createStyles from "@mui/styles/createStyles"; import withStyles from "@mui/styles/withStyles"; import Tooltip from "@mui/material/Tooltip"; +import CompareIcon from "@mui/icons-material/Compare"; import TimelineIcon from "@mui/icons-material/Timeline"; import i18n from "@/i18n"; @@ -59,6 +60,8 @@ interface VariableSelectProps extends WithStyles, WithLocale { variables: Variable[]; selectVariable: (variableName: string | null) => void; addTimeSeries: () => void; + variableCompareMode: boolean; + toggleVariableCompareMode: () => void; } const _VariableSelect: React.FC = ({ @@ -68,6 +71,8 @@ const _VariableSelect: React.FC = ({ variables, selectVariable, addTimeSeries, + variableCompareMode, + toggleVariableCompareMode, }) => { const handleVariableChange = (event: SelectChangeEvent) => { selectVariable(event.target.value || null); @@ -112,19 +117,30 @@ const _VariableSelect: React.FC = ({ className={classes.button} disabled={!canAddTimeSeries} onClick={handleAddTimeSeriesButtonClick} - size="large" > {} ); + const compareButton = ( + + + {} + + + ); return ( ); }; diff --git a/src/components/Viewer.tsx b/src/components/Viewer.tsx index 16fea7c1..5ebbeaab 100644 --- a/src/components/Viewer.tsx +++ b/src/components/Viewer.tsx @@ -108,6 +108,7 @@ interface ViewerProps extends WithStyles { datasetBoundaryLayer?: MapElement; placeGroupLayers?: MapElement; colorBarLegend?: MapElement; + mapSplitter?: MapElement; userDrawnPlaceGroupName: string; addDrawnUserPlace?: ( placeGroupTitle: string, @@ -143,6 +144,7 @@ const _Viewer: React.FC = ({ datasetBoundaryLayer, placeGroupLayers, colorBarLegend, + mapSplitter, userDrawnPlaceGroupName, addDrawnUserPlace, importUserPlacesFromText, @@ -374,6 +376,7 @@ const _Viewer: React.FC = ({ onDrawEnd={handleDrawEnd} /> {colorBarControl} + {mapSplitter} diff --git a/src/components/ol/Map.tsx b/src/components/ol/Map.tsx index c596dc4a..92b70372 100644 --- a/src/components/ol/Map.tsx +++ b/src/components/ol/Map.tsx @@ -61,6 +61,9 @@ interface MapProps extends OlMapOptions { interface MapState {} const DEFAULT_CONTAINER_STYLE: React.CSSProperties = { + position: "relative", + top: 0, + left: 0, width: "100%", height: "100%", }; diff --git a/src/connected/MapSplitter.tsx b/src/connected/MapSplitter.tsx new file mode 100644 index 00000000..cc6363f8 --- /dev/null +++ b/src/connected/MapSplitter.tsx @@ -0,0 +1,39 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019-2024 by the xcube development team and contributors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { connect } from "react-redux"; + +import { AppState } from "@/states/appState"; +import _MapSplitter from "@/components/MapSplitter"; + +const mapStateToProps = (state: AppState) => { + return { + hidden: !state.controlState.variableCompareMode, + }; +}; + +const mapDispatchToProps = {}; + +const MapSplitter = connect(mapStateToProps, mapDispatchToProps)(_MapSplitter); +export default MapSplitter; diff --git a/src/connected/VariableSelect.tsx b/src/connected/VariableSelect.tsx index 5a96fd48..731a2fc0 100644 --- a/src/connected/VariableSelect.tsx +++ b/src/connected/VariableSelect.tsx @@ -27,7 +27,10 @@ import { connect } from "react-redux"; import _VariableSelect from "@/components/VariableSelect"; import { AppState } from "@/states/appState"; import { addTimeSeries } from "@/actions/dataActions"; -import { selectVariable } from "@/actions/controlActions"; +import { + selectVariable, + toggleVariableCompareMode, +} from "@/actions/controlActions"; import { canAddTimeSeriesSelector, selectedDatasetVariablesSelector, @@ -36,16 +39,17 @@ import { const mapStateToProps = (state: AppState) => { return { locale: state.controlState.locale, - selectedVariableName: state.controlState.selectedVariableName, canAddTimeSeries: canAddTimeSeriesSelector(state), variables: selectedDatasetVariablesSelector(state), + variableCompareMode: state.controlState.variableCompareMode, }; }; const mapDispatchToProps = { selectVariable, addTimeSeries, + toggleVariableCompareMode, }; const VariableSelect = connect( diff --git a/src/connected/Viewer.tsx b/src/connected/Viewer.tsx index f356b5c5..6d2261b2 100644 --- a/src/connected/Viewer.tsx +++ b/src/connected/Viewer.tsx @@ -47,6 +47,7 @@ import _Viewer from "@/components/Viewer"; import { userPlaceGroupsSelector } from "@/selectors/dataSelectors"; import { selectPlace } from "@/actions/controlActions"; import ColorBarLegend from "./ColorBarLegend"; +import MapSplitter from "@/connected/MapSplitter"; interface OwnProps { onMapRef?: (map: OlMap | null) => void; @@ -60,6 +61,7 @@ const mapStateToProps = (state: AppState, ownProps: OwnProps) => { datasetBoundaryLayer: selectedDatasetBoundaryLayerSelector(state), placeGroupLayers: selectedDatasetPlaceGroupLayersSelector(state), colorBarLegend: , + mapSplitter: , userDrawnPlaceGroupName: state.controlState.userDrawnPlaceGroupName, userPlaceGroups: userPlaceGroupsSelector(state), userPlaceGroupsVisibility: userPlaceGroupsVisibilitySelector(state), diff --git a/src/reducers/controlReducer.ts b/src/reducers/controlReducer.ts index aa4f5404..943643ea 100644 --- a/src/reducers/controlReducer.ts +++ b/src/reducers/controlReducer.ts @@ -47,6 +47,7 @@ import { SET_VOLUME_RENDER_MODE, SHOW_INFO_CARD, SHOW_VOLUME_CARD, + TOGGLE_VARIABLE_COMPARE_MODE, UPDATE_INFO_CARD_ELEMENT_VIEW_MODE, UPDATE_SETTINGS, UPDATE_TIME_ANIMATION, @@ -497,6 +498,9 @@ export function controlReducer( dialogOpen: { ...state.dialogOpen, [dialogId]: false }, }; } + case TOGGLE_VARIABLE_COMPARE_MODE: { + return { ...state, variableCompareMode: !state.variableCompareMode }; + } case CONFIGURE_SERVERS: { if (state.selectedServerId !== action.selectedServerId) { return { ...state, selectedServerId: action.selectedServerId }; diff --git a/src/states/controlState.ts b/src/states/controlState.ts index e149b704..78a7f5f9 100644 --- a/src/states/controlState.ts +++ b/src/states/controlState.ts @@ -143,6 +143,7 @@ export interface ControlState { exportPlacesAsCollection: boolean; exportZipArchive: boolean; exportFileName: string; + variableCompareMode: boolean; } export function newControlState(): ControlState { @@ -211,6 +212,7 @@ export function newControlState(): ControlState { exportPlacesAsCollection: true, exportZipArchive: true, exportFileName: "export", + variableCompareMode: false, }; return loadUserSettings(state); } From 1b4f6584ccfe2392bda0261c329068955ef07055 Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Fri, 3 May 2024 20:08:14 +0200 Subject: [PATCH 2/9] swipe mode selectable in visibility layer --- src/actions/controlActions.tsx | 16 ++++++++ src/components/ControlBarActions.tsx | 8 +++- src/components/LayerSelect.tsx | 32 +++++++++++----- src/components/LayerSelectItem.tsx | 39 ++++++-------------- src/components/SelectableMenuItem.tsx | 53 +++++++++++++++++++++++++++ src/connected/ControlBarActions.tsx | 5 ++- src/reducers/controlReducer.ts | 5 +++ src/states/controlState.ts | 4 ++ 8 files changed, 124 insertions(+), 38 deletions(-) create mode 100644 src/components/SelectableMenuItem.tsx diff --git a/src/actions/controlActions.tsx b/src/actions/controlActions.tsx index 3d629792..b282e119 100644 --- a/src/actions/controlActions.tsx +++ b/src/actions/controlActions.tsx @@ -342,6 +342,21 @@ export function setLayerVisibility( //////////////////////////////////////////////////////////////////////////////// +export const SET_VARIABLE_LAYER_SWIPE_MODE = "SET_VARIABLE_LAYER_SWIPE_MODE"; + +export interface SetVariableLayerSwipeMode { + type: typeof SET_VARIABLE_LAYER_SWIPE_MODE; + variableLayerSwipeMode: boolean; +} + +export function setVariableLayerSwipeMode( + variableLayerSwipeMode: boolean, +): SetVariableLayerSwipeMode { + return { type: SET_VARIABLE_LAYER_SWIPE_MODE, variableLayerSwipeMode }; +} + +//////////////////////////////////////////////////////////////////////////////// + export const SELECT_VARIABLE = "SELECT_VARIABLE"; export interface SelectVariable { @@ -764,4 +779,5 @@ export type ControlAction = | SetVisibleInfoCardElements | UpdateInfoCardElementCodeMode | ToggleVariableCompareMode + | SetVariableLayerSwipeMode | FlyTo; diff --git a/src/components/ControlBarActions.tsx b/src/components/ControlBarActions.tsx index 9c095795..90b0d6aa 100644 --- a/src/components/ControlBarActions.tsx +++ b/src/components/ControlBarActions.tsx @@ -70,6 +70,8 @@ interface ControlBarActionsProps extends WithStyles, WithLocale { layerId: keyof LayerVisibilities, visible: boolean, ) => void; + variableLayerSwipeMode: boolean; + setVariableLayerSwipeMode: (selected: boolean) => void; } const _ControlBarActions: React.FC = ({ @@ -86,6 +88,8 @@ const _ControlBarActions: React.FC = ({ compact, layerVisibilities, setLayerVisibility, + variableLayerSwipeMode, + setVariableLayerSwipeMode, }) => { if (!visible) { return null; @@ -95,9 +99,11 @@ const _ControlBarActions: React.FC = ({ const layerSelect = ( ); diff --git a/src/components/LayerSelect.tsx b/src/components/LayerSelect.tsx index c8a9a457..f31ae0ac 100644 --- a/src/components/LayerSelect.tsx +++ b/src/components/LayerSelect.tsx @@ -38,6 +38,7 @@ import i18n from "@/i18n"; import { WithLocale } from "@/util/lang"; import { LayerVisibilities } from "@/states/controlState"; import LayerSelectItem from "./LayerSelectItem"; +import SelectableMenuItem from "@/components/SelectableMenuItem"; // noinspection JSUnusedLocalSymbols const styles = (_theme: Theme) => createStyles({}); @@ -49,10 +50,17 @@ interface LayerSelectProps extends WithStyles, WithLocale { layerId: keyof LayerVisibilities, visible: boolean, ) => void; + variableLayerSwipeMode: boolean; + setVariableLayerSwipeMode: (selected: boolean) => void; } const _LayerSelect: React.FC = (props) => { - const { openDialog, ...otherProps } = props; + const { + openDialog, + variableLayerSwipeMode, + setVariableLayerSwipeMode, + ...layerSelectProps + } = props; const [menuAnchor, setMenuAnchor] = React.useState(null); const handleUserOverlays = () => { @@ -74,17 +82,23 @@ const _LayerSelect: React.FC = (props) => { setMenuAnchor(null)} > - - - - - - - + + + + + + + + + + setVariableLayerSwipeMode(!variableLayerSwipeMode)} + /> {i18n.get("User Base Maps") + "..."} diff --git a/src/components/LayerSelectItem.tsx b/src/components/LayerSelectItem.tsx index ade93ed4..92982eba 100644 --- a/src/components/LayerSelectItem.tsx +++ b/src/components/LayerSelectItem.tsx @@ -22,18 +22,14 @@ * SOFTWARE. */ -import * as React from "react"; -import Check from "@mui/icons-material/Check"; -import MenuItem from "@mui/material/MenuItem"; -import ListItemText from "@mui/material/ListItemText"; -import ListItemIcon from "@mui/material/ListItemIcon"; - import i18n from "@/i18n"; import { LayerVisibilities } from "@/states/controlState"; +import SelectableMenuItem from "@/components/SelectableMenuItem"; const layerLabels: Record = { baseMap: "Base Map", datasetRgb: "Dataset RGB", + datasetVariable2: "Dataset Variable 2", datasetVariable: "Dataset Variable", datasetBoundary: "Dataset Boundary", datasetPlaces: "Dataset Places", @@ -50,28 +46,17 @@ interface LayerSelectItemProps { ) => void; } -const LayerSelectItem: React.FC = ({ +export default function LayerSelectItem({ layerId, layerVisibilities, setLayerVisibility, -}) => { - const visible = layerVisibilities[layerId]; - const label = i18n.get(layerLabels[layerId]); - - const handleClick = () => setLayerVisibility(layerId, !visible); - - return visible ? ( - - - - - {label} - - ) : ( - - {label} - +}: LayerSelectItemProps) { + const visible = !!layerVisibilities[layerId]; + return ( + setLayerVisibility(layerId, !visible)} + /> ); -}; - -export default LayerSelectItem; +} diff --git a/src/components/SelectableMenuItem.tsx b/src/components/SelectableMenuItem.tsx new file mode 100644 index 00000000..6af2239f --- /dev/null +++ b/src/components/SelectableMenuItem.tsx @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019-2024 by the xcube development team and contributors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import Check from "@mui/icons-material/Check"; +import MenuItem from "@mui/material/MenuItem"; +import ListItemText from "@mui/material/ListItemText"; +import ListItemIcon from "@mui/material/ListItemIcon"; + +interface SelectableMenuItemProps { + label: string; + selected: boolean; + onClick: () => void; +} + +export default function SelectableMenuItem({ + label, + selected, + onClick, +}: SelectableMenuItemProps) { + return selected ? ( + + + + + {label} + + ) : ( + + {label} + + ); +} diff --git a/src/connected/ControlBarActions.tsx b/src/connected/ControlBarActions.tsx index 46c19577..7260948f 100644 --- a/src/connected/ControlBarActions.tsx +++ b/src/connected/ControlBarActions.tsx @@ -28,9 +28,10 @@ import { AppState } from "@/states/appState"; import _ControlBarActions from "@/components/ControlBarActions"; import { openDialog, - setLayerVisibility, showInfoCard, showVolumeCard, + setLayerVisibility, + setVariableLayerSwipeMode, } from "@/actions/controlActions"; import { Config } from "@/config"; import { updateResources } from "@/actions/dataActions"; @@ -48,6 +49,7 @@ const mapStateToProps = (state: AppState) => { compact: Config.instance.branding.compact, allowRefresh: Config.instance.branding.allowRefresh, layerVisibilities: layerVisibilitiesSelector(state), + variableLayerSwipeMode: state.controlState.variableLayerSwipeMode, }; }; @@ -57,6 +59,7 @@ const mapDispatchToProps = { openDialog, updateResources, setLayerVisibility, + setVariableLayerSwipeMode, }; const ControlBarActions = connect( diff --git a/src/reducers/controlReducer.ts b/src/reducers/controlReducer.ts index 943643ea..9d98dee1 100644 --- a/src/reducers/controlReducer.ts +++ b/src/reducers/controlReducer.ts @@ -43,6 +43,7 @@ import { SET_LAYER_VISIBILITY, SET_MAP_INTERACTION, SET_RGB_LAYER_VISIBILITY, + SET_VARIABLE_LAYER_SWIPE_MODE, SET_VISIBLE_INFO_CARD_ELEMENTS, SET_VOLUME_RENDER_MODE, SHOW_INFO_CARD, @@ -217,6 +218,10 @@ export function controlReducer( }, }; } + case SET_VARIABLE_LAYER_SWIPE_MODE: { + const { variableLayerSwipeMode } = action; + return { ...state, variableLayerSwipeMode }; + } case SELECT_TIME: { let { selectedTime } = action; if (selectedTime !== null && appState) { diff --git a/src/states/controlState.ts b/src/states/controlState.ts index 78a7f5f9..5cc7ab86 100644 --- a/src/states/controlState.ts +++ b/src/states/controlState.ts @@ -76,6 +76,7 @@ export interface LayerVisibilities { baseMap?: boolean; datasetRgb?: boolean; datasetVariable?: boolean; + datasetVariable2?: boolean; datasetBoundary?: boolean; datasetPlaces?: boolean; userPlaces?: boolean; @@ -130,6 +131,7 @@ export interface ControlState { mapProjection: string; imageSmoothingEnabled: boolean; layerVisibilities: LayerVisibilities; + variableLayerSwipeMode: boolean; selectedBaseMapId: string | null; selectedOverlayId: string | null; userBaseMaps: LayerDefinition[]; @@ -183,11 +185,13 @@ export function newControlState(): ControlState { baseMap: true, datasetRgb: false, datasetVariable: true, + datasetVariable2: true, datasetBoundary: false, datasetPlaces: true, userPlaces: true, overlay: true, }, + variableLayerSwipeMode: false, datasetLocateMode: "pan", placeLocateMode: "panAndZoom", volumeCardOpen: false, From 83276c3b61b7c80e8bbdccb7c75db7727b414926 Mon Sep 17 00:00:00 2001 From: Norman Fomferra Date: Fri, 3 May 2024 20:53:52 +0200 Subject: [PATCH 3/9] can now set the 2nd variable --- src/actions/controlActions.tsx | 34 ++++++++++++++++--------- src/components/ControlBarActions.tsx | 12 ++++----- src/components/LayerSelect.tsx | 14 +++++------ src/components/VariableSelect.tsx | 37 +++++++++++++++++----------- src/connected/ControlBarActions.tsx | 6 ++--- src/connected/VariableSelect.tsx | 11 ++++----- src/reducers/controlReducer.ts | 25 +++++++++++++------ src/states/controlState.ts | 10 +++++--- 8 files changed, 91 insertions(+), 58 deletions(-) diff --git a/src/actions/controlActions.tsx b/src/actions/controlActions.tsx index b282e119..879f6f2b 100644 --- a/src/actions/controlActions.tsx +++ b/src/actions/controlActions.tsx @@ -342,17 +342,20 @@ export function setLayerVisibility( //////////////////////////////////////////////////////////////////////////////// -export const SET_VARIABLE_LAYER_SWIPE_MODE = "SET_VARIABLE_LAYER_SWIPE_MODE"; +export const SET_VARIABLE_COMPARE_MODE = "SET_VARIABLE_LAYER_SWIPE_MODE"; export interface SetVariableLayerSwipeMode { - type: typeof SET_VARIABLE_LAYER_SWIPE_MODE; - variableLayerSwipeMode: boolean; + type: typeof SET_VARIABLE_COMPARE_MODE; + variableCompareMode: boolean; } -export function setVariableLayerSwipeMode( +export function setVariableCompareMode( variableLayerSwipeMode: boolean, ): SetVariableLayerSwipeMode { - return { type: SET_VARIABLE_LAYER_SWIPE_MODE, variableLayerSwipeMode }; + return { + type: SET_VARIABLE_COMPARE_MODE, + variableCompareMode: variableLayerSwipeMode, + }; } //////////////////////////////////////////////////////////////////////////////// @@ -372,14 +375,23 @@ export function selectVariable( //////////////////////////////////////////////////////////////////////////////// -export const TOGGLE_VARIABLE_COMPARE_MODE = "TOGGLE_VARIABLE_COMPARE_MODE"; +export const SELECT_VARIABLE_2 = "SELECT_VARIABLE_2"; -export interface ToggleVariableCompareMode { - type: typeof TOGGLE_VARIABLE_COMPARE_MODE; +export interface SelectVariable2 { + type: typeof SELECT_VARIABLE_2; + selectedDataset2Id: string | null; + selectedVariable2Name: string | null; } -export function toggleVariableCompareMode(): ToggleVariableCompareMode { - return { type: TOGGLE_VARIABLE_COMPARE_MODE }; +export function selectVariable2( + selectedDataset2Id: string | null, + selectedVariable2Name: string | null, +): SelectVariable2 { + return { + type: SELECT_VARIABLE_2, + selectedDataset2Id, + selectedVariable2Name, + }; } //////////////////////////////////////////////////////////////////////////////// @@ -778,6 +790,6 @@ export type ControlAction = | ShowInfoCard | SetVisibleInfoCardElements | UpdateInfoCardElementCodeMode - | ToggleVariableCompareMode + | SelectVariable2 | SetVariableLayerSwipeMode | FlyTo; diff --git a/src/components/ControlBarActions.tsx b/src/components/ControlBarActions.tsx index 90b0d6aa..69c37387 100644 --- a/src/components/ControlBarActions.tsx +++ b/src/components/ControlBarActions.tsx @@ -70,8 +70,8 @@ interface ControlBarActionsProps extends WithStyles, WithLocale { layerId: keyof LayerVisibilities, visible: boolean, ) => void; - variableLayerSwipeMode: boolean; - setVariableLayerSwipeMode: (selected: boolean) => void; + variableCompareMode: boolean; + setVariableCompareMode: (selected: boolean) => void; } const _ControlBarActions: React.FC = ({ @@ -88,8 +88,8 @@ const _ControlBarActions: React.FC = ({ compact, layerVisibilities, setLayerVisibility, - variableLayerSwipeMode, - setVariableLayerSwipeMode, + variableCompareMode, + setVariableCompareMode, }) => { if (!visible) { return null; @@ -102,8 +102,8 @@ const _ControlBarActions: React.FC = ({ openDialog={openDialog} layerVisibilities={layerVisibilities} setLayerVisibility={setLayerVisibility} - variableLayerSwipeMode={variableLayerSwipeMode} - setVariableLayerSwipeMode={setVariableLayerSwipeMode} + variableCompareMode={variableCompareMode} + setVariableCompareMode={setVariableCompareMode} /> ); diff --git a/src/components/LayerSelect.tsx b/src/components/LayerSelect.tsx index f31ae0ac..0ac1015e 100644 --- a/src/components/LayerSelect.tsx +++ b/src/components/LayerSelect.tsx @@ -50,15 +50,15 @@ interface LayerSelectProps extends WithStyles, WithLocale { layerId: keyof LayerVisibilities, visible: boolean, ) => void; - variableLayerSwipeMode: boolean; - setVariableLayerSwipeMode: (selected: boolean) => void; + variableCompareMode: boolean; + setVariableCompareMode: (selected: boolean) => void; } const _LayerSelect: React.FC = (props) => { const { openDialog, - variableLayerSwipeMode, - setVariableLayerSwipeMode, + variableCompareMode, + setVariableCompareMode, ...layerSelectProps } = props; const [menuAnchor, setMenuAnchor] = React.useState(null); @@ -95,9 +95,9 @@ const _LayerSelect: React.FC = (props) => { setVariableLayerSwipeMode(!variableLayerSwipeMode)} + label={i18n.get("Compare Mode (Swipe)")} + selected={variableCompareMode} + onClick={() => setVariableCompareMode(!variableCompareMode)} /> diff --git a/src/components/VariableSelect.tsx b/src/components/VariableSelect.tsx index ebcdc513..309a0d0e 100644 --- a/src/components/VariableSelect.tsx +++ b/src/components/VariableSelect.tsx @@ -55,24 +55,31 @@ const styles = (theme: Theme) => }); interface VariableSelectProps extends WithStyles, WithLocale { + selectedDatasetId: string | null; + selectedDataset2Id: string | null; selectedVariableName: string | null; + selectedVariable2Name: string | null; canAddTimeSeries: boolean; variables: Variable[]; selectVariable: (variableName: string | null) => void; + selectVariable2: ( + dataset2Id: string | null, + variable2Name: string | null, + ) => void; addTimeSeries: () => void; - variableCompareMode: boolean; - toggleVariableCompareMode: () => void; } const _VariableSelect: React.FC = ({ classes, canAddTimeSeries, + selectedDatasetId, selectedVariableName, + selectedDataset2Id, + selectedVariable2Name, variables, selectVariable, + selectVariable2, addTimeSeries, - variableCompareMode, - toggleVariableCompareMode, }) => { const handleVariableChange = (event: SelectChangeEvent) => { selectVariable(event.target.value || null); @@ -82,8 +89,9 @@ const _VariableSelect: React.FC = ({ addTimeSeries(); }; - selectedVariableName = selectedVariableName || ""; - variables = variables || []; + const isSelectedVariable2 = + selectedDatasetId === selectedDataset2Id && + selectedVariableName === selectedVariable2Name; const variableSelectLabel = ( @@ -95,13 +103,13 @@ const _VariableSelect: React.FC = ({