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

feat: Adding feature to edit discrete legend name #417

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
18 changes: 18 additions & 0 deletions react-app/src/component/ColorSelector/ColorSelectorAccordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { getColorSelectorPosition } from "../Utils/legendCommonFunction";
import CancelIcon from "@mui/icons-material/Cancel";
import { Theme, createStyles, makeStyles } from "@material-ui/core/styles";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { DiscreteColorLegend } from "../Legend/DiscreteLegend";

const useStyles = makeStyles((theme: Theme) =>
createStyles({
Expand Down Expand Up @@ -244,6 +245,23 @@ export const ColorSelectorAccordion = (props: any) => {
/>
</AccordionDetails>
</Accordion>
<Accordion
expanded={expanded === "panel3"}
onChange={handleChange("panel3")}
>
<AccordionSummary>
<ExpandMoreIcon className={"expandMoreIcon"} fontSize="medium" />
<h5>Discrete Code Mapping</h5>
</AccordionSummary>
<AccordionDetails className={"codeMappingDetails"}>
<div>
<DiscreteColorLegend
colorName={props.currentLegendName}
discreteCodeMapping={true}
/>
</div>
</AccordionDetails>
</Accordion>
</Box>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion react-app/src/component/Legend/ColorLegend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export const ColorLegend: React.FC<ColorLegendProps> = ({
ref={divRef}
onClick={toggleColorSelector}
style={{ display: "inline-block", cursor: "pointer" }}
title="Click here to edit"
title="Click to edit"
>
{isCont === true && (
<ContinuousLegend
Expand Down
202 changes: 130 additions & 72 deletions react-app/src/component/Legend/DiscreteLegend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ declare type discreteLegendProps = {
/**
* Discrete data to build legend
*/
discreteData: { objects: Record<string, [number[], number]> };
discreteData?: { objects: Record<string, [number[], number]> };
/**
* Title for the legend
*/
dataObjectName: string;
dataObjectName?: string;
/**
* Name of the color(ex: Rainbow)
*/
Expand All @@ -44,7 +44,7 @@ declare type discreteLegendProps = {
*
* Reference: https://github.com/emerson-eps/color-tables/blob/main/react-app/src/component/color-tables.json
*/
colorTables: colorTablesArray | string;
colorTables?: colorTablesArray | string;
/**
* Font size of legend name (in px)
*/
Expand All @@ -66,6 +66,10 @@ declare type discreteLegendProps = {
* css styles to be applied
*/
cssLegendStyles?: any;
/**
* This props is for discrete code mapping
*/
discreteCodeMapping?: boolean;
};

export const DiscreteColorLegend: React.FC<discreteLegendProps> = ({
Expand All @@ -81,6 +85,7 @@ export const DiscreteColorLegend: React.FC<discreteLegendProps> = ({
numberOfTicks,
legendScaleSize = 200,
cssLegendStyles = { left: "0vw", top: "0vh" },
discreteCodeMapping,
}: discreteLegendProps) => {
const generateUniqueId = Math.ceil(Math.random() * 9999).toString();
const divRef = useRef<HTMLDivElement>(null);
Expand All @@ -97,6 +102,20 @@ export const DiscreteColorLegend: React.FC<discreteLegendProps> = ({
let useSelectorLegend = false;
let itemName: string[] = [];
let itemColor: ItemColor[] = [];

const defaultDiscreteData: any = {
Copy link
Contributor

@hkfb hkfb Jan 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO the default table should be empty. The consumer of this component should be able populate and set a default table depending on the use case. @Midtveit do you agree?

So basically just expose this table as a prop which is default empty. Would be nice with a storybook example that demonstrates this. We could implement this incrementally if you like.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I agree it is up to the consumer of the component to populate the labels

So the basic editing of labels is what we need now.
After edit the component and view using that table should be updated.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. This defaultDiscreteData was actually I had written for testing purpose, which I forgot to remove basically. Will look into this and make necessary changes

OS: [[], 0],
LSF: [[], 1],
USF: [[], 2],
MB: [[], 3],
TB: [[], 4],
TC: [[], 5],
TFS: [[], 6],
TFM: [[], 7],
MSH: [[], 8],
CAL: [[], 9],
};

try {
// fix for dash wrapper
if (typeof colorTables === "string") {
Expand Down Expand Up @@ -167,12 +186,40 @@ export const DiscreteColorLegend: React.FC<discreteLegendProps> = ({

itemName = getColorScaleData.legendColorName;
useSelectorLegend = true;
} else if (discreteCodeMapping) {
const entries = Object.entries(
discreteData ? discreteData : defaultDiscreteData
);

//eslint-disable-next-line
const sorted = entries.sort((a: any, b: any) => a[1][1] - b[1][1]);
sorted.forEach((value) => {
const key = value[0];
const val = value[1];
const code = val[1];
// for colortable colors
if (arrayOfColors.length > 0) {
//compare the first value in colorarray(colortable) and code from discreteData
const matchedColorsArrays = arrayOfColors.find(
(value: [number[], number][]) => {
return value[0] === code;
}
);
if (matchedColorsArrays)
itemColor.push({
color: RGBToHex(matchedColorsArrays),
name: key,
});
itemName.push(key);
}
});
}

const colorLegend = discreteLegendUtil(
itemColor,
useSelectorLegend,
horizontal
horizontal,
discreteCodeMapping
);
let totalRect;

Expand All @@ -193,69 +240,75 @@ export const DiscreteColorLegend: React.FC<discreteLegendProps> = ({
}

const currentDiv = select(divRef.current);
if (!discreteCodeMapping) {
// append the title
currentDiv
.append("div")
.text(dataObjectName)
.style("color", "grey")
.style("white-space", "nowrap")
.style("overflow", "hidden")
.style("width", "150px")
.style("text-overflow", "ellipsis")
.style("margin-bottom", horizontal ? "5px" : "0px")
.style(
"font-size",
legendFontSize && legendFontSize > 0
? `${legendFontSize}px`
: "16px"
)
.style(
"transform",
horizontal ? "none" : "translate(-69px, 80px) rotate(270deg)"
);

// append the title
currentDiv
.append("div")
.text(dataObjectName)
.style("color", "grey")
.style("white-space", "nowrap")
.style("overflow", "hidden")
.style("width", "150px")
.style("text-overflow", "ellipsis")
.style("margin-bottom", horizontal ? "5px" : "0px")
.style(
"font-size",
legendFontSize && legendFontSize > 0
? `${legendFontSize}px`
: "16px"
)
.style(
"transform",
horizontal ? "none" : "translate(-69px, 80px) rotate(270deg)"
);

// Append svg to the div
const svgLegend = currentDiv
.style("margin", horizontal ? "5px 0px 0px 15px" : "0px 5px 0px 5px")
// .style("width", horizontal ? "145px" : "50px")
.style(
"width",
horizontal
? legendScaleSize < 200
? 200
: legendScaleSize
: "50px"
)
.append("svg")
.call(colorLegend);
// Append svg to the div
const svgLegend = currentDiv
.style(
"margin",
horizontal ? "5px 0px 0px 15px" : "0px 5px 0px 5px"
)
// .style("width", horizontal ? "145px" : "50px")
.style(
"width",
horizontal
? legendScaleSize < 200
? 200
: legendScaleSize
: "50px"
)
.append("svg")
.call(colorLegend);

svgLegend
.attr(
"viewBox",
horizontal ? `0 0 ${totalRect} 1.5` : `0 0 2 ${totalRect}`
)
.attr("preserveAspectRatio", "none")
.style("font-size", ".4")
.style("margin-left", horizontal ? "0" : "20px")
// .attr("height", horizontal ? "30px" : "153px")
.attr(
"height",
horizontal
? "30px"
: legendScaleSize < 200
? 190
: legendScaleSize - 10
)
// .attr("width", horizontal ? "150px" : "40px");
.attr(
"width",
horizontal
? legendScaleSize < 200
svgLegend
.attr(
"viewBox",
horizontal ? `0 0 ${totalRect} 1.5` : `0 0 2 ${totalRect}`
)
.attr("preserveAspectRatio", "none")
.style("font-size", ".4")
.style("margin-left", horizontal ? "0" : "20px")
// .attr("height", horizontal ? "30px" : "153px")
.attr(
"height",
horizontal
? "30px"
: legendScaleSize < 200
? 190
: legendScaleSize - 10
: "40px"
);
)
// .attr("width", horizontal ? "150px" : "40px");
.attr(
"width",
horizontal
? legendScaleSize < 200
? 190
: legendScaleSize - 10
: "40px"
);
} else {
currentDiv.append("div").call(colorLegend);
}
} catch (error) {
console.error(error);
}
Expand All @@ -271,19 +324,24 @@ export const DiscreteColorLegend: React.FC<discreteLegendProps> = ({
tickFontSize,
numberOfTicks,
legendScaleSize,
discreteCodeMapping,
]);

return (
<div
style={{
position: "absolute",
minHeight: "70px",
backgroundColor: "#ffffffcc",
borderRadius: "5px",
zIndex: 999,
margin: "10px",
...cssLegendStyles,
}}
style={
!discreteCodeMapping
? {
position: "absolute",
minHeight: "70px",
backgroundColor: "#ffffffcc",
borderRadius: "5px",
zIndex: 999,
margin: "10px",
...cssLegendStyles,
}
: {}
}
>
<div
id={id ? id : `disc-legend - ${generateUniqueId}`}
Expand Down
Loading