Skip to content

chore(chart legend): convert to typescript #11823

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

Merged
Merged
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ChartDonut } from '@patternfly/react-charts/victory';

interface PetData {
x?: string;
y?: number;
name?: string;
}

export const ChartLegendBasicRightLegend: React.FunctionComponent = () => {
const data: PetData[] = [
{ x: 'Cats', y: 35 },
{ x: 'Dogs', y: 55 },
{ x: 'Birds', y: 10 }
];
const legendData: PetData[] = [{ name: 'Cats: 35' }, { name: 'Dogs: 55' }, { name: 'Birds: 10' }];

return (
<div style={{ height: '230px', width: '350px' }}>
<ChartDonut
ariaDesc="Average number of pets"
ariaTitle="Donut chart example"
constrainToVisibleArea
data={data}
labels={({ datum }) => `${datum.x}: ${datum.y}%`}
legendData={legendData}
legendOrientation="vertical"
legendPosition="right"
name="chart1"
padding={{
bottom: 20,
left: 20,
right: 140, // Adjusted to accommodate legend
top: 20
}}
subTitle="Pets"
title="100"
width={350}
/>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
Chart,
ChartAxis,
ChartBar,
ChartGroup,
ChartThemeColor,
ChartVoronoiContainer
} from '@patternfly/react-charts/victory';

interface PetData {
x?: string;
y?: number;
name?: string;
}

export const ChartLegendBottomAlignedLegend: React.FunctionComponent = () => {
const legendData: PetData[] = [{ name: 'Cats' }, { name: 'Dogs' }, { name: 'Birds' }, { name: 'Mice' }];
const data1: PetData[] = [
{ name: 'Cats', x: '2015', y: 1 },
{ name: 'Cats', x: '2016', y: 2 },
{ name: 'Cats', x: '2017', y: 5 },
{ name: 'Cats', x: '2018', y: 3 }
];
const data2: PetData[] = [
{ name: 'Dogs', x: '2015', y: 2 },
{ name: 'Dogs', x: '2016', y: 1 },
{ name: 'Dogs', x: '2017', y: 7 },
{ name: 'Dogs', x: '2018', y: 4 }
];
const data3: PetData[] = [
{ name: 'Birds', x: '2015', y: 4 },
{ name: 'Birds', x: '2016', y: 4 },
{ name: 'Birds', x: '2017', y: 9 },
{ name: 'Birds', x: '2018', y: 7 }
];
const data4: PetData[] = [
{ name: 'Mice', x: '2015', y: 3 },
{ name: 'Mice', x: '2016', y: 3 },
{ name: 'Mice', x: '2017', y: 8 },
{ name: 'Mice', x: '2018', y: 5 }
];

return (
<div style={{ height: '275px', width: '450px' }}>
<Chart
ariaDesc="Average number of pets"
ariaTitle="Bar chart example"
containerComponent={
<ChartVoronoiContainer labels={({ datum }) => `${datum.name}: ${datum.y}`} constrainToVisibleArea />
}
domainPadding={{ x: [30, 25] }}
legendData={legendData}
legendPosition="bottom"
height={275}
name="chart2"
padding={{
bottom: 75, // Adjusted to accommodate legend
left: 50,
right: 50,
top: 50
}}
themeColor={ChartThemeColor.purple}
width={450}
>
<ChartAxis />
<ChartAxis dependentAxis showGrid />
<ChartGroup offset={11}>
<ChartBar data={data1} />
<ChartBar data={data2} />
<ChartBar data={data3} />
<ChartBar data={data4} />
</ChartGroup>
</Chart>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import {
Chart,
ChartArea,
ChartAxis,
ChartGroup,
ChartLegend,
ChartLegendTooltip,
ChartScatter,
ChartThemeColor,
createContainer,
getInteractiveLegendEvents,
getInteractiveLegendItemStyles
} from '@patternfly/react-charts/victory';
import { getResizeObserver } from '@patternfly/react-core';
import { useRef, useState, useEffect } from 'react';

export const ChartLegendInteractive: React.FunctionComponent = () => {
const containerRef = useRef(null);
const [hiddenSeries, setHiddenSeries] = useState(new Set());
const [width, setWidth] = useState(0);

const series = [
{
datapoints: [
{ x: '2015', y: 3 },
{ x: '2016', y: 4 },
{ x: '2017', y: 8 },
{ x: '2018', y: 6 }
],
legendItem: { name: 'Cats' }
},
{
datapoints: [
{ x: '2015', y: 2 },
{ x: '2016', y: 3 },
{ x: '2017', y: 4 },
{ x: '2018', y: 5 },
{ x: '2019', y: 6 }
],
legendItem: { name: 'Dogs' }
},
{
datapoints: [
{ x: '2015', y: 1 },
{ x: '2016', y: 2 },
{ x: '2017', y: 3 },
{ x: '2018', y: 2 },
{ x: '2019', y: 4 }
],
legendItem: { name: 'Birds' }
}
];

// Returns groups of chart names associated with each data series
const getChartNames = () => series.map((_, index) => [`area-${index}`, `scatter-${index}`]);

// Handles legend click to toggle visibility of data series
const handleLegendClick = (props) => {
setHiddenSeries((prev) => {
const newHidden = new Set(prev);
if (!newHidden.delete(props.index)) {
newHidden.add(props.index);
}
return newHidden;
});
};

// Returns legend data styled per hiddenSeries
const getLegendData = () =>
series.map((s, index) => ({
childName: `area-${index}`,
...s.legendItem,
...getInteractiveLegendItemStyles(hiddenSeries.has(index))
}));

// Returns true if data series is hidden
const isHidden = (index) => hiddenSeries.has(index);

// Checks if any data series is visible
const isDataAvailable = () => hiddenSeries.size !== series.length;

// Set chart width per current window size
useEffect(() => {
const observer = getResizeObserver(containerRef.current, () => {
if (containerRef.current?.clientWidth) {
setWidth(containerRef.current.clientWidth);
}
});
return () => observer();
}, []);

// Note: Container order is important
const CursorVoronoiContainer = createContainer('voronoi', 'cursor');
const container = (
<CursorVoronoiContainer
cursorDimension="x"
labels={({ datum }) => (datum.childName.includes('area-') && datum.y !== null ? `${datum.y}` : null)}
labelComponent={<ChartLegendTooltip legendData={getLegendData()} title={(datum) => datum.x} />}
mouseFollowTooltips
voronoiDimension="x"
voronoiPadding={50}
disable={!isDataAvailable()}
/>
);

return (
<div ref={containerRef}>
<div className="area-chart-legend-bottom-responsive">
<Chart
ariaDesc="Average number of pets"
ariaTitle="Area chart example"
containerComponent={container}
events={getInteractiveLegendEvents({
chartNames: getChartNames(),
isHidden,
legendName: 'chart5-ChartLegend',
onLegendClick: handleLegendClick
})}
height={225}
legendComponent={<ChartLegend name={'chart5-ChartLegend'} data={getLegendData()} />}
legendPosition="bottom-left"
name="chart5"
padding={{ bottom: 75, left: 50, right: 50, top: 50 }}
maxDomain={{ y: 9 }}
themeColor={ChartThemeColor.multiUnordered}
width={width}
>
<ChartAxis tickValues={['2015', '2016', '2017', '2018']} />
<ChartAxis dependentAxis showGrid />
<ChartGroup>
{series.map((s, index) => (
<ChartScatter
key={`scatter-${index}`}
name={`scatter-${index}`}
data={!isHidden(index) ? s.datapoints : [{ y: null }]}
size={({ active }) => (active ? 5 : 3)}
/>
))}
</ChartGroup>
<ChartGroup>
{series.map((s, index) => (
<ChartArea
key={`area-${index}`}
name={`area-${index}`}
data={!isHidden(index) ? s.datapoints : [{ y: null }]}
interpolation="monotoneX"
/>
))}
</ChartGroup>
</Chart>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
Chart,
ChartLegend,
ChartThemeColor,
ChartPie,
getInteractiveLegendEvents,
getInteractiveLegendItemStyles
} from '@patternfly/react-charts/victory';
import { useState } from 'react';

export const ChartLegendInteractivePieChart: React.FunctionComponent = () => {
const [hiddenSeries, setHiddenSeries] = useState<Set<number>>(new Set());

const series = [
{
datapoints: { x: 'Cats', y: 35 },
legendItem: { name: 'Cats: 35' }
},
{
datapoints: { x: 'Dogs', y: 55 },
legendItem: { name: 'Dogs: 55' }
},
{
datapoints: { x: 'Birds', y: 10 },
legendItem: { name: 'Birds: 10' }
}
];

// Returns groups of chart names associated with each data series
const getChartNames = () => {
const result = [];
series.map((_, _index) => {
// Provide names for each series hidden / shown -- use the same name for a pie chart
result.push(['pie']);
});
return result;
};

// Returns legend data styled per hiddenSeries
const getLegendData = () =>
series.map((s, index) => ({
...s.legendItem, // name property
...getInteractiveLegendItemStyles(hiddenSeries.has(index)) // hidden styles
}));

// Hide each data series individually
const handleLegendClick = (props: { index: number }) => {
const newHiddenSeries = new Set(hiddenSeries);
if (newHiddenSeries.delete(props.index)) {
newHiddenSeries.add(props.index);
}
setHiddenSeries(newHiddenSeries);
};

// Returns true if data series is hidden
const isHidden = (index: number) => hiddenSeries.has(index);
// Returns onMouseOver, onMouseOut, and onClick events for the interactive legend
const getEvents = () =>
getInteractiveLegendEvents({
chartNames: getChartNames(),
isHidden,
legendName: 'chart6-ChartLegend',
onLegendClick: handleLegendClick
});

const data = [];
series.map((s, index) => {
data.push(!hiddenSeries.has(index) ? s.datapoints : { y: null });
});

return (
<div style={{ height: '275px', width: '300px' }}>
<Chart
ariaDesc="Average number of pets"
ariaTitle="Pie chart example"
events={getEvents()}
height={275}
legendComponent={<ChartLegend name={'chart6-ChartLegend'} data={getLegendData()} />}
legendPosition="bottom"
name="chart6"
padding={{
bottom: 65,
left: 20,
right: 20,
top: 20
}}
showAxis={false}
themeColor={ChartThemeColor.multiUnordered}
width={300}
>
<ChartPie constrainToVisibleArea data={data} labels={({ datum }) => `${datum.x}: ${datum.y}`} name="pie" />
</Chart>
</div>
);
};
Loading
Loading