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

Pie Widget: Add maxNumber of elements + a sorted by size desc by default #774

Merged
merged 26 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
956deda
add number of selected categories + clear button
vmilan Sep 12, 2023
05c74f2
changelog
vmilan Sep 12, 2023
7dfbd60
cleanup
vmilan Sep 12, 2023
4a39c96
Merge branch 'master' into feature/pie-widget-selected-categories
vmilan Sep 12, 2023
1e1a649
apply a separator between categories
vmilan Sep 13, 2023
9aba9a1
fix tooltip delay
vmilan Sep 13, 2023
6d0ab3c
recover scale effect on hover
vmilan Sep 13, 2023
5ca0d27
Add maxNumber of elements to PieWidget
vmilan Sep 13, 2023
f9fc6ca
changelog
vmilan Sep 13, 2023
511e9d9
sort categories in legend
vmilan Sep 14, 2023
d9563a6
Merge branch 'feature/pie-widget' into feature/pie-widget-max-categories
vmilan Sep 14, 2023
feac850
comment
vmilan Sep 14, 2023
7acf9f3
remove console log
vmilan Sep 14, 2023
7bfb621
Merge branch 'feature/pie-widget' into feature/pie-widget-max-categories
vmilan Sep 14, 2023
4f00507
Merge branch 'feature/pie-widget' into feature/pie-widget-max-categories
vmilan Sep 14, 2023
1a59ffe
first approach to sort categories
vmilan Sep 15, 2023
af44715
cleanup
vmilan Sep 18, 2023
9623081
cleanup
vmilan Sep 18, 2023
dcd7c64
fix selected categories
vmilan Sep 18, 2023
4098013
fix selected categories
vmilan Sep 18, 2023
56007bc
fix reset colorByCategory
vmilan Sep 18, 2023
72d038f
add prop to change order data as is category widget
vmilan Sep 18, 2023
b66b389
Avoid clicking if the category name is Others
vmilan Sep 18, 2023
d6c9ce0
Avoid clicking if the category name is Others
vmilan Sep 18, 2023
52d084c
cleanup
vmilan Sep 18, 2023
81afd66
change function name
vmilan Sep 18, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Not released

- Pie Widget: Add maxNumber of elements + a sorted by size desc by default [#774](https://github.com/CartoDB/carto-react/pull/774)
- Pie Widget: Add number of selected categories + clear button [#771](https://github.com/CartoDB/carto-react/pull/771)

## 2.2
Expand Down
99 changes: 73 additions & 26 deletions packages/react-ui/src/widgets/PieWidgetUI/PieWidgetUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { useMemo, useRef, useEffect, useState, useCallback } from 'react'
import PropTypes from 'prop-types';
import ReactEcharts from '../../custom-components/echarts-for-react';
import { Grid, Link, styled, useTheme } from '@mui/material';
import { disableSerie, setColor } from '../utils/chartUtils';
import { disableSerie, setColor, sortDataDescending } from '../utils/chartUtils';
import { processFormatterRes } from '../utils/formatterUtils';
import PieSkeleton from './PieSkeleton';
import PieSkeleton from './components/PieSkeleton';
import Typography from '../../components/atoms/Typography';

export const OptionsBar = styled(Grid)(({ theme }) => ({
Expand All @@ -26,44 +26,75 @@ function PieWidgetUI({
filterable,
selectedCategories,
onSelectedCategoriesChange,
isLoading
isLoading,
maxItems,
order
}) {
const theme = useTheme();
const [showLabel, setShowLabel] = useState(true);
const [showTooltip, setShowTooltip] = useState(true);
const colorByCategory = useRef({});
const othersCategory = 'Others';

// Reset colorByCategory when colors changes
// Sort data by size if order is ranking, otherwise keep the original order
const orderedData = useMemo(() => {
let orderedCategories = [];

if (order === PieWidgetUI.ORDER_TYPES.RANKING) {
orderedCategories = sortDataDescending(data);
} else {
orderedCategories = [...data];
}

return orderedCategories;
}, [data, order]);

// Limit the number of categories to display, then group the rest into an "Others" category
const groupedData = useMemo(() => {
let categories = [];
let othersValue = 0;

for (const category of orderedData) {
if (categories.length < maxItems) {
categories.push({ ...category });
} else {
othersValue += category.value;
}
}

if (othersValue > 0) {
categories.push({
name: othersCategory,
value: othersValue,
emphasis: { scale: false }
});
}

return categories;
}, [maxItems, orderedData]);

// Add a color to each category
const dataWithColor = useMemo(() => {
return groupedData.map(processDataItem(colorByCategory, colors, theme));
}, [groupedData, colors, theme]);

// Reset colorByCategory when colors and categories change
useEffect(() => {
colorByCategory.current = {};
// Spread colors array to avoid reference problems
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...colors]);

const dataWithColor = useMemo(() => {
return data.map(processDataItem(colorByCategory, colors, theme));
}, [data, colors, theme]);
}, [...colors, dataWithColor]);

// Tooltip
const tooltipOptions = useMemo(
() => ({
show: showTooltip,
showDelay: 100,
transitionDuration: 0.4,
backgroundColor: theme.palette.black[90],
borderColor: 'transparent',
textStyle: { color: theme.palette.common.white },
confine: true,
formatter:
!!tooltipFormatter && ((params) => tooltipFormatter({ ...params, formatter }))
}),
[
showTooltip,
formatter,
theme.palette.common.white,
theme.palette.black,
tooltipFormatter
]
[formatter, theme.palette.common.white, theme.palette.black, tooltipFormatter]
);

// Legend
Expand Down Expand Up @@ -201,7 +232,12 @@ function PieWidgetUI({
(params) => {
if (onSelectedCategoriesChange) {
const newSelectedCategories = [...selectedCategories];
const { name } = data[params.dataIndex];
const { name } = dataWithColor[params.dataIndex];

// Avoid clicking if the category name is "Others"
if (name === othersCategory) {
return;
}

const selectedCategoryIdx = newSelectedCategories.indexOf(name);
if (selectedCategoryIdx === -1) {
Expand All @@ -213,18 +249,16 @@ function PieWidgetUI({
onSelectedCategoriesChange(newSelectedCategories);
}
},
[data, onSelectedCategoriesChange, selectedCategories]
[dataWithColor, onSelectedCategoriesChange, selectedCategories]
);

const onEvents = {
...(filterable && { click: clickEvent }),
mouseover: () => {
setShowLabel(false);
setShowTooltip(true);
},
mouseout: () => {
setShowLabel(true);
setShowTooltip(false);
}
};

Expand Down Expand Up @@ -256,6 +290,15 @@ function PieWidgetUI({
);
}

/**
* Enum for PieWidgetUI order types. 'RANKING' orders the data by value and 'FIXED' keeps the order present in the original data
* @enum {string}
*/
PieWidgetUI.ORDER_TYPES = {
RANKING: 'ranking',
FIXED: 'fixed'
};

PieWidgetUI.defaultProps = {
name: null,
formatter: (v) => v,
Expand All @@ -265,7 +308,9 @@ PieWidgetUI.defaultProps = {
height: '260px',
animation: true,
filterable: true,
selectedCategories: []
selectedCategories: [],
maxItems: 11,
order: PieWidgetUI.ORDER_TYPES.RANKING
};

PieWidgetUI.propTypes = {
Expand All @@ -285,7 +330,9 @@ PieWidgetUI.propTypes = {
filterable: PropTypes.bool,
selectedCategories: PropTypes.array,
onSelectedCategoriesChange: PropTypes.func,
isLoading: PropTypes.bool
isLoading: PropTypes.bool,
maxItems: PropTypes.number,
order: PropTypes.oneOf(Object.values(PieWidgetUI.ORDER_TYPES))
};

export default PieWidgetUI;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Box, Skeleton, styled } from '@mui/material';
import { SKELETON_HEIGHT, SkeletonMask } from '../SkeletonWidgets';
import { SKELETON_HEIGHT, SkeletonMask } from '../../SkeletonWidgets';

const GUTTER = 16;
const LEYEND_SIZE = 64;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { useTheme } from '@mui/material';
import { lighten } from '@mui/material/styles';
import EchartsWrapper from '../../custom-components/echarts-for-react';
import PieSkeleton from '../PieWidgetUI/PieSkeleton';
import PieSkeleton from '../PieWidgetUI/components/PieSkeleton';

/**
* process incoming data to assign labels, colors and selected / unselected styles
Expand Down
11 changes: 11 additions & 0 deletions packages/react-ui/src/widgets/utils/chartUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,14 @@ export function applyChartFilter(serie, clickedSerieIndex, theme) {

return serie;
}

// Sort data from largest to smallest
export function sortDataDescending(data) {
const sortedData = [...data];

sortedData.sort((a, b) => {
return b.value - a.value;
});

return sortedData;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import { Label, ThinContainer } from '../../utils/storyStyles';
const options = {
title: 'Widgets/PieWidgetUI',
component: PieWidgetUI,
argTypes: {
order: {
defaultValue: 'ranking',
control: {
type: 'select',
options: ['ranking', 'fixed']
}
}
},
parameters: {
docs: {
source: {
Expand Down Expand Up @@ -56,8 +65,7 @@ const CustomColorsProps = {
{ name: 'Elephants', value: 100 },
{ name: 'Mamouths', value: 120 },
{ name: 'Torttles', value: 150 },
{ name: 'Snakes', value: 90 },
{ name: 'others', value: 200 }
{ name: 'Snakes', value: 90 }
],
colors: [
'#855C75',
Expand All @@ -70,8 +78,7 @@ const CustomColorsProps = {
'#9C9C5E',
'#A06177',
'#8C785D',
'#467378',
'#7C7C7C'
'#467378'
]
};
CustomColors.args = CustomColorsProps;
Expand All @@ -90,6 +97,27 @@ const SelectedCategoriesProps = {
};
SelectedCategories.args = SelectedCategoriesProps;

export const CollapseMoreThan12Categories = Template.bind({});
const CollapseCategoriesProps = {
data: [
{ name: 'Dogs', value: 100 },
{ name: 'Cats', value: 120 },
{ name: 'Rabbits', value: 150 },
{ name: 'Canaries', value: 90 },
{ name: 'Passerines', value: 200 },
{ name: 'Elephants', value: 100 },
{ name: 'Mamouths', value: 120 },
{ name: 'Torttles', value: 150 },
{ name: 'Spiders', value: 80 },
{ name: 'Frogs', value: 30 },
{ name: 'Pigeons', value: 150 },
{ name: 'Owls', value: 90 },
{ name: 'Snakes', value: 80 },
{ name: 'Birds', value: 220 }
]
};
CollapseMoreThan12Categories.args = CollapseCategoriesProps;

export const Loading = LoadingTemplate.bind({});
const LoadingProps = { data: dataDefault, isLoading: true };
Loading.args = LoadingProps;