From 563d032ccf29519b473c349210c1ce414950c5de Mon Sep 17 00:00:00 2001 From: Ryan Srofe Date: Thu, 9 Jan 2025 11:44:43 -0500 Subject: [PATCH 1/4] remove calculation based x0 and y0 values The issue is in the getDatasets method where the voronoi points are calculated. Currently, it calculates the voronoi point position as the midpoint between x and x0 for X coordinates, and y and y0 for Y coordinates. The fix should be to use just the primary coordinates for voronoi calculations, ignoring the baseline coordinates. --- packages/victory-voronoi-container/src/voronoi-helpers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/victory-voronoi-container/src/voronoi-helpers.ts b/packages/victory-voronoi-container/src/voronoi-helpers.ts index 170b39ecc..2854bf76c 100644 --- a/packages/victory-voronoi-container/src/voronoi-helpers.ts +++ b/packages/victory-voronoi-container/src/voronoi-helpers.ts @@ -37,9 +37,9 @@ class VoronoiHelpersClass { const continuous = child && child.type && child.type.continuous; const style = child ? child.props && child.props.style : props.style; return data.map((datum, index) => { - const { x, y, y0, x0 } = Helpers.getPoint(datum); - const voronoiX = (Number(x) + Number(x0)) / 2; - const voronoiY = (Number(y) + Number(y0)) / 2; + const { x, y } = Helpers.getPoint(datum); + const voronoiX = Number(x); + const voronoiY = Number(y); return Object.assign( { From bd42780f91315c1cdf48ce3cf1480c849c06b19c Mon Sep 17 00:00:00 2001 From: Ryan Srofe Date: Thu, 9 Jan 2025 11:46:45 -0500 Subject: [PATCH 2/4] Adding Voronoi stories from docs and bug example Added a Voronoi section to Storybook to test the users bug example (voronoi-y0). I also added all the existing Voronoi examples to Storybook from the docs. --- .../victory-charts/victory-voronoi/config.ts | 27 ++++++++ .../victory-charts/victory-voronoi/data.ts | 35 ++++++++++ .../voronoi-animation.stories.tsx | 64 +++++++++++++++++++ .../victory-voronoi/voronoi-basic.stories.tsx | 30 +++++++++ .../voronoi-circles.stories.tsx | 38 +++++++++++ .../voronoi-events.stories.tsx | 56 ++++++++++++++++ .../voronoi-labels.stories.tsx | 39 +++++++++++ .../voronoi-standalone-rendering.stories.tsx | 42 ++++++++++++ .../voronoi-styles.stories.tsx | 38 +++++++++++ .../voronoi-tooltips-grouped.stories.tsx | 55 ++++++++++++++++ .../voronoi-tooltips.stories.tsx | 39 +++++++++++ .../victory-voronoi/voronoi-y0.stories.tsx | 64 +++++++++++++++++++ 12 files changed, 527 insertions(+) create mode 100644 stories/victory-charts/victory-voronoi/config.ts create mode 100644 stories/victory-charts/victory-voronoi/data.ts create mode 100644 stories/victory-charts/victory-voronoi/voronoi-animation.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-basic.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-circles.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-labels.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-standalone-rendering.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-styles.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-tooltips-grouped.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-tooltips.stories.tsx create mode 100644 stories/victory-charts/victory-voronoi/voronoi-y0.stories.tsx diff --git a/stories/victory-charts/victory-voronoi/config.ts b/stories/victory-charts/victory-voronoi/config.ts new file mode 100644 index 000000000..c00bf10c9 --- /dev/null +++ b/stories/victory-charts/victory-voronoi/config.ts @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { VictoryVoronoi, VictoryVoronoiProps } from "@/victory"; + +import { + VictoryCommonProps, + VictoryDatableProps, + VictoryMultiLabelableProps, +} from "../../utils/arg-types"; +import { componentContainer } from "../../utils/decorators"; + +type StoryProps = VictoryVoronoiProps & { + themeKey: string; +}; + +export const ComponentMeta: Meta> = { + component: VictoryVoronoi, + decorators: [componentContainer], + + argTypes: { + ...VictoryCommonProps, + ...VictoryDatableProps, + ...VictoryMultiLabelableProps, + }, +}; + +export type Story = StoryObj; diff --git a/stories/victory-charts/victory-voronoi/data.ts b/stories/victory-charts/victory-voronoi/data.ts new file mode 100644 index 000000000..ca944c3bd --- /dev/null +++ b/stories/victory-charts/victory-voronoi/data.ts @@ -0,0 +1,35 @@ +export const sampleData = [ + { x: 1, y: 2 }, + { x: 2, y: 3 }, + { x: 3, y: 5 }, + { x: 4, y: 4 }, + { x: 5, y: 7 }, +]; + +export const sampleDataWithLabels = [ + { x: 1, y: 2, label: "Dogs" }, + { x: 2, y: 3, label: "Cats" }, + { x: 3, y: 5, label: "Snakes" }, + { x: 4, y: 4, label: "Rabbits" }, + { x: 5, y: 7, label: "Birds" }, +]; + +export const sampleDataGroupOne = [ + { x: 1, y: -3 }, + { x: 2, y: 5 }, + { x: 3, y: 3 }, + { x: 4, y: 0 }, + { x: 5, y: -2 }, + { x: 6, y: -2 }, + { x: 7, y: 5 }, +]; + +export const sampleDataGroupTwo = [ + { x: 1, y: 3 }, + { x: 2, y: 1 }, + { x: 3, y: 2 }, + { x: 4, y: -2 }, + { x: 5, y: -1 }, + { x: 6, y: 2 }, + { x: 7, y: 3 }, +]; diff --git a/stories/victory-charts/victory-voronoi/voronoi-animation.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-animation.stories.tsx new file mode 100644 index 000000000..83c40bf05 --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-animation.stories.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; +import range from "lodash/range"; +import random from "lodash/random"; + +import { + VictoryChart, + VictoryVoronoi, + VictoryScatter, + VictoryTheme, +} from "@/victory"; + +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +function getData() { + return range(20).map((i: number) => { + return { + x: random(600), + y: random(600), + i, + }; + }); +} + +export const Animation: Story = { + args: { + themeKey: "clean", + }, + render: function AnimationComponent(props) { + const [data, setData] = React.useState(getData()); + + React.useEffect(() => { + const setStateInterval = window.setInterval(() => { + setData(getData()); + }, 4000); + + return () => { + window.clearInterval(setStateInterval); + }; + }, []); + + return ( + + + + + ); + }, +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-basic.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-basic.stories.tsx new file mode 100644 index 000000000..7263fba6a --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-basic.stories.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { VictoryChart, VictoryVoronoi, VictoryTheme } from "@/victory"; + +import { sampleData } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const Basic: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + + + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-circles.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-circles.stories.tsx new file mode 100644 index 000000000..46141a779 --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-circles.stories.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { + VictoryChart, + VictoryLine, + VictoryVoronoi, + VictoryScatter, + VictoryTheme, +} from "@/victory"; + +import { sampleData } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const Circles: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + + + + + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx new file mode 100644 index 000000000..eb50fb541 --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { VictoryChart, VictoryVoronoi, VictoryTheme } from "@/victory"; + +import { sampleData } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const Events: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + + { + return [ + { + target: "data", + mutation: (props) => { + const fill = props.style && props.style.fill; + return fill === "white" + ? null + : { + style: { + fill: "white", + }, + }; + }, + }, + ]; + }, + }, + }, + ]} + data={sampleData} + /> + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-labels.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-labels.stories.tsx new file mode 100644 index 000000000..776ea9b8f --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-labels.stories.tsx @@ -0,0 +1,39 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { VictoryChart, VictoryVoronoi, VictoryTheme } from "@/victory"; + +import { sampleData, sampleDataWithLabels } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const Labels: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + + + + + `y: ${datum.y}`} + /> + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-standalone-rendering.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-standalone-rendering.stories.tsx new file mode 100644 index 000000000..f04845ce9 --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-standalone-rendering.stories.tsx @@ -0,0 +1,42 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { VictoryVoronoi, VictoryTheme } from "@/victory"; + +import { sampleData } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const StandaloneRendering: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + + + + + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-styles.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-styles.stories.tsx new file mode 100644 index 000000000..e911b52cd --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-styles.stories.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { VictoryChart, VictoryVoronoi, VictoryTheme } from "@/victory"; + +import { sampleData } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const Styles: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-tooltips-grouped.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-tooltips-grouped.stories.tsx new file mode 100644 index 000000000..88c0b5e83 --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-tooltips-grouped.stories.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { + VictoryVoronoi, + VictoryTheme, + VictoryChart, + VictoryGroup, + VictoryLine, + VictoryScatter, + VictoryTooltip, + VictoryVoronoiContainer, +} from "@/victory"; + +import { sampleDataGroupOne, sampleDataGroupTwo } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const TooltipsGrouped: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + } + theme={VictoryTheme[props.themeKey]} + > + `y: ${datum.y}`} + labelComponent={} + data={sampleDataGroupOne} + > + + (active ? 8 : 3)} /> + + `y: ${datum.y}`} + labelComponent={} + data={sampleDataGroupTwo} + > + + (active ? 8 : 3)} /> + + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-tooltips.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-tooltips.stories.tsx new file mode 100644 index 000000000..f0457e5cf --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-tooltips.stories.tsx @@ -0,0 +1,39 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { + VictoryChart, + VictoryVoronoi, + VictoryTooltip, + VictoryTheme, +} from "@/victory"; + +import { sampleDataWithLabels } from "./data"; +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const Tooltips: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + + datum.y} + labelComponent={} + /> + + + ), +}; + +export default meta; diff --git a/stories/victory-charts/victory-voronoi/voronoi-y0.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-y0.stories.tsx new file mode 100644 index 000000000..8c5029715 --- /dev/null +++ b/stories/victory-charts/victory-voronoi/voronoi-y0.stories.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; + +import { + VictoryChart, + VictoryArea, + VictoryVoronoi, + VictoryVoronoiContainer, + VictoryTooltip, + VictoryTheme, +} from "@/victory"; + +import { Story, ComponentMeta } from "./config"; + +const meta: Meta = { + ...ComponentMeta, + title: "Victory Charts/VictoryVoronoi", +}; + +export const y0: Story = { + args: { + themeKey: "clean", + }, + render: (props) => ( + <> + } + theme={VictoryTheme[props.themeKey]} + > + datum.y} + labelComponent={} + data={[ + { x: 1, y: 4 }, + { x: 2, y: 5 }, + { x: 3, y: 7 }, + ]} + y0={() => 2} + /> + datum.y} + labelComponent={} + data={[ + { x: 1, y: 2 }, + { x: 2, y: 3 }, + { x: 3, y: 5 }, + ]} + y0={() => 2} + /> + + + ), +}; + +export default meta; From 2e652220c56e23adc85f0755a6f203eb36f533cf Mon Sep 17 00:00:00 2001 From: Ryan Srofe Date: Thu, 9 Jan 2025 12:13:10 -0500 Subject: [PATCH 3/4] rename `props` to `eventProps` --- .../victory-charts/victory-voronoi/voronoi-events.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx b/stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx index eb50fb541..3638e3ab3 100644 --- a/stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx +++ b/stories/victory-charts/victory-voronoi/voronoi-events.stories.tsx @@ -30,8 +30,8 @@ export const Events: Story = { return [ { target: "data", - mutation: (props) => { - const fill = props.style && props.style.fill; + mutation: (eventProps) => { + const fill = eventProps.style && eventProps.style.fill; return fill === "white" ? null : { From 9a50fc543409a99c5953156237beb83c4ade4d59 Mon Sep 17 00:00:00 2001 From: Ryan Srofe Date: Thu, 9 Jan 2025 12:22:37 -0500 Subject: [PATCH 4/4] changeset --- .changeset/rude-kids-sniff.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rude-kids-sniff.md diff --git a/.changeset/rude-kids-sniff.md b/.changeset/rude-kids-sniff.md new file mode 100644 index 000000000..f6ca75d9e --- /dev/null +++ b/.changeset/rude-kids-sniff.md @@ -0,0 +1,5 @@ +--- +"victory-voronoi-container": minor +--- + +Use only x and y coordinates for voronoi calculations, ignoring the baseline x0 and y0 coordinates. Fixes #2298.