From ba6f55b8f680da88cab6eb2eaa1d0c510e780e2e Mon Sep 17 00:00:00 2001 From: nils stolpe Date: Wed, 30 Oct 2024 14:06:11 -0400 Subject: [PATCH] fix 'Pie Chart ignores categories prop' (#2934) --- .changeset/proud-bugs-brush.md | 5 ++++ demo/ts/components/victory-pie-demo.tsx | 14 +++++++++- packages/victory-pie/src/helper-methods.ts | 27 ++++++++++++++++++- packages/victory-pie/src/victory-pie.test.tsx | 24 +++++++++++++++++ stories/victory-pie.stories.tsx | 15 +++++++++++ 5 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 .changeset/proud-bugs-brush.md diff --git a/.changeset/proud-bugs-brush.md b/.changeset/proud-bugs-brush.md new file mode 100644 index 000000000..693ecf863 --- /dev/null +++ b/.changeset/proud-bugs-brush.md @@ -0,0 +1,5 @@ +--- +"victory-pie": patch +--- + +Added logic to sort pie chart slices by categories prop diff --git a/demo/ts/components/victory-pie-demo.tsx b/demo/ts/components/victory-pie-demo.tsx index 0a4941fb9..576cae9d3 100644 --- a/demo/ts/components/victory-pie-demo.tsx +++ b/demo/ts/components/victory-pie-demo.tsx @@ -2,7 +2,7 @@ import React from "react"; import { random, range } from "lodash"; import { VictoryPie } from "victory-pie"; import { VictoryTooltip } from "victory-tooltip"; -import { VictoryTheme, LineSegment, Helpers } from "victory-core"; +import { VictoryTheme, Helpers } from "victory-core"; interface VictoryPieDemoState { data: { @@ -153,6 +153,18 @@ export default class VictoryPieDemo extends React.Component< style={{ parent: parentStyle }} labelPosition="startAngle" /> + + + + { if (text === undefined || text === null || Helpers.isFunction(text)) { @@ -59,6 +61,29 @@ const getSlices = (props, data) => { return layoutFunction(data); }; +const getCategoriesFromProps = (props: VictoryPieProps) => + Array.isArray(props.categories) + ? props.categories + : (props?.categories as { x: string[] })?.x ?? []; + +/** + * Sorts data by props.categories or props.categories.x. If all of the data keys aren't + * included in categories, any remaining data will be appended to the data array. + * If extraneous categories are included in the categories prop, the will be ignored and + * have no effect on the rendered component. + */ +const getDataSortedByCategories = (props: VictoryPieProps, data) => { + const sorted: string[] = []; + getCategoriesFromProps(props).forEach((category) => { + const idx = data.findIndex(({ x }) => x === category); + if (idx >= 0) { + const datum = data.splice(idx, 1)[0]; + sorted.push(datum); + } + }); + return [...sorted, ...data]; +}; + const getCalculatedValues = (props) => { const { colorScale, theme } = props; const styleObject = Helpers.getDefaultStyles(props, "pie"); @@ -69,7 +94,7 @@ const getCalculatedValues = (props) => { const padding = Helpers.getPadding(props); const defaultRadius = getRadius(props, padding); const origin = getOrigin(props, padding); - const data = Data.getData(props); + const data = getDataSortedByCategories(props, Data.getData(props)); const slices = getSlices(props, data); return Object.assign({}, props, { style, diff --git a/packages/victory-pie/src/victory-pie.test.tsx b/packages/victory-pie/src/victory-pie.test.tsx index b7a4aaee5..aa8516583 100644 --- a/packages/victory-pie/src/victory-pie.test.tsx +++ b/packages/victory-pie/src/victory-pie.test.tsx @@ -151,6 +151,30 @@ describe("components/victory-pie", () => { expect(xValues).toEqual(xValuesFromGivenData); }); + it("renders data values sorted by categories prop", () => { + const { container } = render( + , + ); + + const xValues = Array.from( + container.querySelectorAll("text[id^=pie-labels] > tspan"), + ).map((slice) => slice.textContent); + + expect(xValues).toEqual(["E", "A", "D", "C", "B"]); + }); + + it("renders data values sorted by categories prop, appending any data keys missing from categories and ignoring any categories values that are not valid data keys", () => { + const { container } = render( + , + ); + + const xValues = Array.from( + container.querySelectorAll("text[id^=pie-labels] > tspan"), + ).map((slice) => slice.textContent); + + expect(xValues).toEqual(["E", "C", "B", "A", "D"]); + }); + it("renders data values sorted by sortKey prop", () => { const data = Helpers.range(9) .map((i) => ({ x: i, y: i })) diff --git a/stories/victory-pie.stories.tsx b/stories/victory-pie.stories.tsx index fc0ac49ea..79328c9aa 100644 --- a/stories/victory-pie.stories.tsx +++ b/stories/victory-pie.stories.tsx @@ -29,6 +29,21 @@ export const DefaultRendering = () => { ); }; +export const Categories = () => { + return ( + <> + + + + ); +}; + export const Data = () => { return ( <>