-
Notifications
You must be signed in to change notification settings - Fork 55
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: pie animations #451
feat: pie animations #451
Changes from all commits
23b7928
2a10cdb
c745df6
47cbb17
4a58e84
41c084b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"victory-native": minor | ||
--- | ||
|
||
Add animations for pie chart |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,30 +2,40 @@ import React from "react"; | |
import { type Color, Path, type PathProps } from "@shopify/react-native-skia"; | ||
import { useSliceAngularInsetPath } from "./hooks/useSliceAngularInsetPath"; | ||
import { usePieSliceContext } from "./contexts/PieSliceContext"; | ||
import type { PathAnimationConfig } from "../hooks/useAnimatedPath"; | ||
import { AnimatedPath } from "../cartesian/components/AnimatedPath"; | ||
|
||
export type PieSliceAngularInsetData = { | ||
angularStrokeWidth: number; | ||
angularStrokeColor: Color; | ||
}; | ||
|
||
type AdditionalPathProps = Partial<Omit<PathProps, "color" | "path">>; | ||
type AdditionalPathProps = Partial<Omit<PathProps, "color" | "path">> & { | ||
animate?: PathAnimationConfig; | ||
}; | ||
|
||
type PieSliceAngularInsetProps = { | ||
angularInset: PieSliceAngularInsetData; | ||
} & AdditionalPathProps; | ||
|
||
export const PieSliceAngularInset = (props: PieSliceAngularInsetProps) => { | ||
const { angularInset, children, ...rest } = props; | ||
const { angularInset, children, animate, ...rest } = props; | ||
const { slice } = usePieSliceContext(); | ||
const [path, insetPaint] = useSliceAngularInsetPath({ slice, angularInset }); | ||
|
||
// If the path is empty, don't render anything | ||
if (path.toSVGString() === "M0 0L0 0M0 0L0 0") { | ||
return null; | ||
} | ||
|
||
if (angularInset.angularStrokeWidth === 0) { | ||
return null; | ||
} | ||
|
||
const Component = animate ? AnimatedPath : Path; | ||
return ( | ||
<Path path={path} paint={insetPaint} {...rest}> | ||
<Component path={path} paint={insetPaint} animate={animate} {...rest}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thinking out loud. Would be nice in future cleanup if we could just always use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. There's potentially a perf hit of some sort, but it would definitely keep things a bit simpler. |
||
{children} | ||
</Path> | ||
</Component> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# Pie.SliceAngularInset (Component) | ||
|
||
The `Pie.SliceAngularInset` component is a child component of the `Pie.Chart` component and is responsible for rendering the individual slice of a `Pie` or `Donut` chart. By default the `Pie.SliceAngularInset` component will render a simple slice of the pie, but you can customize the rendering of each slice by providing children to the `Pie.Chart` component. | ||
|
||
:::tip | ||
|
||
The [example app](https://github.com/FormidableLabs/victory-native-xl/tree/main/example) inside this repo has a lot of examples of how to use the `Pie.Chart` and its associated components! | ||
|
||
::: | ||
|
||
## Example | ||
|
||
The example below shows how to use `Pie.SliceAngularInset` to render `LinearGradient` slices. | ||
|
||
```tsx | ||
import { View } from "react-native"; | ||
import { Pie, PolarChart } from "victory-native"; | ||
|
||
function MyChart() { | ||
return ( | ||
<View style={{ height: 300 }}> | ||
<PolarChart | ||
data={DATA} // 👈 specify your data | ||
labelKey={"label"} // 👈 specify data key for labels | ||
valueKey={"value"} // 👈 specify data key for values | ||
colorKey={"color"} // 👈 specify data key for color | ||
> | ||
<Pie.Chart> | ||
{({ slice }) => { | ||
// ☝️ render function of each slice object for each pie slice | ||
return ( | ||
<> | ||
<Pie.Slice /> | ||
<Pie.SliceAngularInset | ||
angularInset={{ | ||
angularStrokeWidth: insetWidth, | ||
angularStrokeColor: insetColor, | ||
}} | ||
/> | ||
</> | ||
); | ||
}} | ||
</Pie.Chart> | ||
</PolarChart> | ||
</View> | ||
); | ||
} | ||
|
||
function randomNumber() { | ||
return Math.floor(Math.random() * 26) + 125; | ||
} | ||
function generateRandomColor(): string { | ||
// Generating a random number between 0 and 0xFFFFFF | ||
const randomColor = Math.floor(Math.random() * 0xffffff); | ||
// Converting the number to a hexadecimal string and padding with zeros | ||
return `#${randomColor.toString(16).padStart(6, "0")}`; | ||
} | ||
const DATA = (numberPoints = 5) => | ||
Array.from({ length: numberPoints }, (_, index) => ({ | ||
value: randomNumber(), | ||
color: generateRandomColor(), | ||
label: `Label ${index + 1}`, | ||
})); | ||
``` | ||
|
||
## Props | ||
|
||
### angularStrokeWidth | ||
|
||
The `angularStrokeWidth` prop is used to set the width of the angular inset stroke. | ||
|
||
### angularStrokeColor | ||
|
||
The `angularStrokeColor` prop is used to set the color of the angular inset stroke. | ||
|
||
### `animate` | ||
|
||
The `animate` prop takes [a `PathAnimationConfig` object](../../animated-paths.md#animconfig) and will animate the path when the points changes. | ||
|
||
### `children` | ||
|
||
This component is just a `Path` under the hood, so accepts most props that a `Path` would accept. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a default value of a path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the value of an empty path of the angular inset, yes. I think there's an initial render that happens when all the values haven't been set/received yet higher up so it renders just a point. It's not the best solution, but it fixes the issue.