Skip to content

Commit

Permalink
Merge pull request #391 from xcube-dev/forman-390-revise_custom_cmaps
Browse files Browse the repository at this point in the history
Revise new color bar features
  • Loading branch information
forman authored Jul 19, 2024
2 parents e875fe7 + b939919 commit 17492f5
Show file tree
Hide file tree
Showing 14 changed files with 220 additions and 131 deletions.
13 changes: 13 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,22 @@
band-math expressions. The variables are defined for a given
dataset and are persisted in the browser's local storage. (#371)

* Revised map color mapping for simplicity and clarity. (#390)
This comprises the following changes:
- Removed the color mapping normalisation modes. Instead, introduced
a "Log" switch in the value-range popup. The normalisation mode
"CAT" (categorical) is no longer required.
- Renamed the user color mapping types "Node", "Bound", "Key" into
"Cont." (continuous), "Stepwise", and "Categ." (categorical).
- The color legend is now showing the variable's UI title instead of the
variable identifier name.
- The value range can now be assigned from the value range
of the color mapping values.

* The datasets in the dataset selector are now sorted by name and may
also be grouped if configured so in xcube server. (#385)


* Made the right sidebar panel's tab bar position sticky. (#373)

* It is now possible to change the color and opacity of user places
Expand Down
2 changes: 1 addition & 1 deletion src/components/ColorBarLegend/ColorBarLabels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
*/

import React, { useMemo } from "react";
import Box from "@mui/material/Box";

import { getLabelsForRange } from "@/util/label";
import Box from "@mui/material/Box";
import { makeStyles } from "@/util/styles";

const styles = makeStyles({
Expand Down
31 changes: 14 additions & 17 deletions src/components/ColorBarLegend/ColorBarLegend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ import { MouseEvent, useRef, useState } from "react";
import Box from "@mui/material/Box";
import Popover from "@mui/material/Popover";

import { makeStyles } from "@/util/styles";
import { ColorBar, ColorBars } from "@/model/colorBar";
import { UserColorBar } from "@/model/userColorBar";
import { ColorBarNorm } from "@/model/variable";
import ColorBarLegendCategorical from "./ColorBarLegendCategorical";
import ColorBarLegendContinuous from "./ColorBarLegendContinuous";
import ColorBarLegendScalable from "./ColorBarLegendScalable";
import ColorBarColorEditor from "./ColorBarColorEditor";
import { makeStyles } from "@/util/styles";

const styles = makeStyles({
container: (theme) => ({
Expand All @@ -55,6 +55,7 @@ const styles = makeStyles({

interface ColorBarLegendProps {
variableName: string | null;
variableTitle: string | null;
variableUnits: string;
variableColorBarName: string;
variableColorBarMinMax: [number, number];
Expand All @@ -79,12 +80,8 @@ interface ColorBarLegendProps {
export default function ColorBarLegend(
props: Omit<ColorBarLegendProps, "onOpenColorBarEditor">,
) {
const {
variableName,
variableUnits,
variableColorBar,
variableColorBarNorm,
} = props;
const { variableName, variableTitle, variableUnits, variableColorBar } =
props;

const colorBarSelectAnchorRef = useRef<HTMLDivElement | null>(null);
const [colorBarSelectAnchorEl, setColorBarSelectAnchorEl] =
Expand All @@ -102,24 +99,24 @@ export default function ColorBarLegend(
return null;
}

const variableTitle = variableColorBar.categories
? variableName
: `${variableName} (${variableUnits || "-"})`;
const variableTitleWithUnits =
variableColorBar.type === "key"
? variableTitle || variableName
: `${variableTitle || variableName} (${variableUnits || "-"})`;

return (
<Box sx={styles.container} ref={colorBarSelectAnchorRef}>
<Box sx={styles.title}>
<span>{variableTitle}</span>
<Box sx={styles.title} component="span">
{variableTitleWithUnits}
</Box>
{variableColorBarNorm === "cat" && variableColorBar.categories ? (
{variableColorBar.type === "key" ? (
<ColorBarLegendCategorical
variableColorBarCategories={variableColorBar.categories}
categories={variableColorBar.colorRecords}
onOpenColorBarEditor={handleOpenColorBarSelect}
{...props}
/>
) : (
<ColorBarLegendContinuous
variableTitle={variableName}
<ColorBarLegendScalable
onOpenColorBarEditor={handleOpenColorBarSelect}
{...props}
/>
Expand Down
9 changes: 6 additions & 3 deletions src/components/ColorBarLegend/ColorBarLegendCategorical.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,20 @@ const styles = makeStyles({
});

export interface ColorBarLegendCategoricalProps {
variableColorBarCategories: HexColorRecord[];
categories?: HexColorRecord[];
onOpenColorBarEditor: () => void;
}

export default function ColorBarLegendCategorical({
variableColorBarCategories,
categories,
onOpenColorBarEditor,
}: ColorBarLegendCategoricalProps) {
if (!categories || categories.length === 0) {
return null;
}
return (
<Box sx={styles.container}>
{variableColorBarCategories.map((category, index) => (
{categories.map((category, index) => (
<Box
key={index}
onClick={onOpenColorBarEditor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@
import { MouseEvent, useState } from "react";
import Popover from "@mui/material/Popover";

import ColorBarCanvas from "./ColorBarCanvas";
import ColorBarRangeEditor from "./ColorBarRangeEditor";
import ColorBarLabels from "./ColorBarLabels";
import { ColorBar } from "@/model/colorBar";
import { ColorBarNorm } from "@/model/variable";
import ColorBarCanvas from "./ColorBarCanvas";
import ColorBarLabels from "./ColorBarLabels";
import ColorBarRangeEditor from "./ColorBarRangeEditor";

export interface ColorBarLegendContinuousProps {
variableTitle: string;
export interface ColorBarLegendScalableProps {
variableColorBar: ColorBar;
variableColorBarName: string;
variableColorBarMinMax: [number, number];
variableColorBarNorm: ColorBarNorm;
variableColorBar: ColorBar;
variableColorBarNorm: ColorBarNorm; // will be "lin" or "log"
variableOpacity: number;
updateVariableColorBar: (
colorBarName: string,
Expand All @@ -47,16 +46,15 @@ export interface ColorBarLegendContinuousProps {
onOpenColorBarEditor: () => void;
}

export default function ColorBarLegendContinuous({
variableTitle,
export default function ColorBarLegendScalable({
variableColorBar,
variableColorBarName,
variableColorBarMinMax,
variableColorBarNorm,
variableColorBar,
variableOpacity,
updateVariableColorBar,
onOpenColorBarEditor,
}: ColorBarLegendContinuousProps) {
}: ColorBarLegendScalableProps) {
const [colorBarRangeEditorAnchorEl, setColorBarRangeEditorAnchorEl] =
useState<HTMLDivElement | null>(null);

Expand Down Expand Up @@ -90,7 +88,7 @@ export default function ColorBarLegendContinuous({
transformOrigin={{ vertical: "top", horizontal: "center" }}
>
<ColorBarRangeEditor
variableTitle={variableTitle}
variableColorBar={variableColorBar}
variableColorBarName={variableColorBarName}
variableColorBarMinMax={variableColorBarMinMax}
variableColorBarNorm={variableColorBarNorm}
Expand Down
93 changes: 83 additions & 10 deletions src/components/ColorBarLegend/ColorBarRangeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,62 @@
* SOFTWARE.
*/

import React, { useEffect, useState } from "react";
import TextField from "@mui/material/TextField";
import React, { ChangeEvent, useEffect, useState } from "react";
import Box from "@mui/material/Box";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
import TextField from "@mui/material/TextField";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import CompressIcon from "@mui/icons-material/Compress";

import i18n from "@/i18n";
import { ColorBarNorm } from "@/model/variable";
import ColorBarRangeSlider from "./ColorBarRangeSlider";
import { makeStyles } from "@/util/styles";
import ColorBarRangeSlider from "./ColorBarRangeSlider";
import { ColorBar } from "@/model/colorBar";
import ToolButton from "@/components/ToolButton";

const HOR_SLIDER_MARGIN = 5;

const styles = makeStyles({
colorBarMinMaxEditor: (theme) => ({
container: (theme) => ({
marginTop: theme.spacing(2),
marginBottom: theme.spacing(2),
display: "flex",
flexDirection: "column",
gap: 1,
}),
header: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
},
title: { paddingLeft: 2, fontWeight: "bold" },
sliderBox: (theme) => ({
marginTop: theme.spacing(1),
marginLeft: theme.spacing(HOR_SLIDER_MARGIN),
marginRight: theme.spacing(HOR_SLIDER_MARGIN),
minWidth: 320,
width: `calc(100% - ${theme.spacing(2 * (HOR_SLIDER_MARGIN + 1))}px)`,
}),
logLabel: { margin: 0, paddingRight: 2, fontWeight: "bold" },
minMaxBox: {
display: "flex",
justifyContent: "center",
},
minTextField: {
maxWidth: "8em",
paddingRight: 2,
marginRight: 2,
},
maxTextField: {
maxWidth: "8em",
paddingLeft: 2,
marginLeft: 2,
},
});

interface ColorBarRangeEditorProps {
variableTitle: string;
variableColorBar: ColorBar;
variableColorBarName: string;
variableColorBarMinMax: [number, number];
variableColorBarNorm: ColorBarNorm;
Expand All @@ -73,7 +91,7 @@ interface ColorBarRangeEditorProps {
}

export default function ColorBarRangeEditor({
variableTitle,
variableColorBar,
variableColorBarName,
variableColorBarMinMax,
variableColorBarNorm,
Expand Down Expand Up @@ -147,9 +165,64 @@ export default function ColorBarRangeEditor({
setEnteredMinMaxError([enteredMinMaxError[0], error]);
};

const handleFromColorRecords = () => {
const colorRecords = variableColorBar.colorRecords!;
const vMin = colorRecords[0].value;
const vMax = colorRecords[colorRecords.length - 1].value;
const newMinMax: [number, number] = [vMin, vMax];
setCurrentMinMax(newMinMax);
setOriginalMinMax(newMinMax);
updateVariableColorBar(
variableColorBarName,
newMinMax,
variableColorBarNorm,
variableOpacity,
);
setEnteredMinMaxError([false, false]);
};

const handleColorBarNorm = (
_event: ChangeEvent<HTMLInputElement>,
value: boolean,
) => {
updateVariableColorBar(
variableColorBarName,
variableColorBarMinMax,
value ? "log" : "lin",
variableOpacity,
);
};

return (
<Box sx={styles.colorBarMinMaxEditor}>
<span style={{ paddingLeft: 14 }}>{variableTitle}</span>
<Box sx={styles.container}>
<Box sx={styles.header}>
<Typography sx={styles.title}>{i18n.get("Value Range")}</Typography>
<span style={{ flexGrow: 1 }} />
{variableColorBar.colorRecords && (
<ToolButton
sx={{ marginRight: 1 }}
icon={<CompressIcon />}
onClick={handleFromColorRecords}
tooltipText={i18n.get("Set min/max from color mapping values")}
/>
)}
<FormControlLabel
sx={styles.logLabel}
control={
<Tooltip title={i18n.get("Logarithmic scaling")}>
<Switch
checked={variableColorBarNorm === "log"}
onChange={handleColorBarNorm}
size="small"
/>
</Tooltip>
}
label={
<Typography variant="body2">{i18n.get("Log-scaled")}</Typography>
}
labelPlacement="start"
/>
</Box>
<Box sx={styles.sliderBox}>
<ColorBarRangeSlider
variableColorBarName={variableColorBarName}
Expand Down
34 changes: 0 additions & 34 deletions src/components/ColorBarLegend/ColorBarStyleEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@
* SOFTWARE.
*/

import { MouseEvent } from "react";
import Box from "@mui/material/Box";
import Slider from "@mui/material/Slider";
import ToggleButton from "@mui/material/ToggleButton";
import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
import Tooltip from "@mui/material/Tooltip";
import InvertColorsIcon from "@mui/icons-material/InvertColors";
import OpacityIcon from "@mui/icons-material/Opacity";
Expand Down Expand Up @@ -111,18 +109,6 @@ export default function ColorBarStyleEditor({
);
};

const handleColorBarNorm = (
_event: MouseEvent<HTMLElement>,
value: ColorBarNorm,
) => {
updateVariableColorBar(
variableColorBarName,
variableColorBarMinMax,
value,
variableOpacity,
);
};

const handleVariableOpacity = (_event: Event, value: number | number[]) => {
updateVariableColorBar(
variableColorBarName,
Expand Down Expand Up @@ -157,26 +143,6 @@ export default function ColorBarStyleEditor({
</ToggleButton>
</Tooltip>
</Box>
<ToggleButtonGroup
exclusive
value={variableColorBarNorm}
onChange={handleColorBarNorm}
size="small"
>
<ToggleButton value="lin" sx={styles.toggleButton}>
<Box fontSize="small">Lin</Box>
</ToggleButton>
<ToggleButton value="log" sx={styles.toggleButton}>
<Box fontSize="small">Log</Box>
</ToggleButton>
<ToggleButton
value="cat"
sx={styles.toggleButton}
disabled={!variableColorBar.categories}
>
<Box fontSize="small">Cat</Box>
</ToggleButton>
</ToggleButtonGroup>
</Box>
<Box component="div" sx={styles.opacityContainer}>
<Box component="span" fontSize="small" sx={styles.opacityLabel}>
Expand Down
Loading

0 comments on commit 17492f5

Please sign in to comment.