Skip to content

Commit

Permalink
Merge pull request #193 from Shopify/feature/animated-values
Browse files Browse the repository at this point in the history
Refactor: Animations and values
  • Loading branch information
chrfalch authored Mar 4, 2022
2 parents f15ca2f + 7603d46 commit 22ca990
Show file tree
Hide file tree
Showing 147 changed files with 2,851 additions and 3,284 deletions.
55 changes: 55 additions & 0 deletions docs/docs/animations/animations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
id: animations
title: Animations
sidebar_label: Animations
slug: /animations/animations
---

To ease the process of building animation, the library provides some utilities to help you. There are two types of utility functions - imperative functions and hooks.

If you have a Skia Value that you want to animate declaratively, a hook is the best choice.

In the example below we want the position of the rectangle to animate when we toggle a given value, and we want it to do this with a spring animation.

## Declarative animation

```tsx twoslash
import React, { useState } from "react";
import { Canvas, Rect, useSpring } from "@shopify/react-native-skia";
import { Button, StyleSheet } from "react-native";

export const AnimationExample = () => {
const [toggled, setToggled] = useState(false);
const position = useSpring(toggled ? 100 : 0);
return (
<>
<Canvas style={{ flex: 1 }}>
<Rect x={position} y={100} width={10} height={10} color={"red"} />
</Canvas>
<Button title="Toggle" onPress={() => setToggled((p) => !p)} />
</>
);
};
```

## Imperative animation

Almost the same thing can be accomplished with an imperative function (except that we are not toggling back and forth in this example):

```tsx twoslash
import { Canvas, Rect, runSpring, useValue } from "@shopify/react-native-skia";
import { Button } from "react-native";

export const AnimationExample = () => {
const position = useValue(0);
const changePosition = () => runSpring(position, 100);
return (
<>
<Canvas style={{ flex: 1 }}>
<Rect x={position} y={100} width={10} height={10} color={"red"} />
</Canvas>
<Button title="Toggle" onPress={changePosition} />
</>
);
};
```
38 changes: 38 additions & 0 deletions docs/docs/animations/gestures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
id: touch-events
title: Touch Events
sidebar_label: Touch Events
slug: /animations/touch-events
---

### useTouchHandler

The `useTouchHandler` hook handles touches in the `Canvas`.
It is meant to be used with values to animate elements of the canvas.

```tsx twoslash
import {
Canvas,
Circle,
useTouchHandler,
useValue,
} from "@shopify/react-native-skia";

const MyComponent = () => {
const cx = useValue(100);
const cy = useValue(100);

const touchHandler = useTouchHandler({
onActive: ({ x, y }) => {
cx.current = x;
cy.current = y;
},
});

return (
<Canvas style={{ flex: 1 }} onTouch={touchHandler}>
<Circle cx={cx} cy={cy} r={10} color="red" />
</Canvas>
);
};
```
112 changes: 0 additions & 112 deletions docs/docs/animations/overview.md

This file was deleted.

90 changes: 90 additions & 0 deletions docs/docs/animations/values.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
id: values
title: Values
sidebar_label: Values
slug: /animations/values
---

React Native Skia supports Animations through the concept of Skia Values. A value can be seen as the state in the library where a change in will trigger a repaint request on the `Canvas` component where it is used.

A simple example is shown below shows how a value is used as a property for the x position of the `Rect` element.

```tsx twoslash
import { Canvas, Rect, useValue } from "@shopify/react-native-skia";
import { useCallback } from "react";
import { Button } from "react-native";

const MyComponent = () => {
const position = useValue(0);
const updateValue = useCallback(
() => (position.current = position.current + 10),
[position]
);

return (
<>
<Canvas style={{ flex: 1 }}>
<Rect x={position} y={100} width={10} height={10} color={"red"} />
</Canvas>
<Button title="Move it" onPress={updateValue} />
</>
);
};
```

## Skia Values

The basic `SkiaValue` is a value that stores some kind of Javascript value. It can be used to store numbers, strings, booleans, objects and even arrays:

```tsx twoslash
import { useValue } from "@shopify/react-native-skia";
const progress = useValue({ x: 100, y: 100 });
const actualValue = progress.current; // actualValue is now {x: 100, y: 100}
```

There are a few more value types in the library that will be described below.

## Derived value

This value is a Skia Value that is derived from other Skia Values.
It takes as its input one or more existing values and a function that will calculate the new value based on the input. The function will be evaluated every time the input value changes.

```tsx twoslash
import { useValue, useDerivedValue } from "@shopify/react-native-skia";

const radius = useValue(100);
const theta = useValue(Math.PI);
const length = useDerivedValue((r, t) => r * t, [radius, theta]);
console.log(length.current); // 314.1592653589793
```

## Clock Value

This value is a value that updates on every display frame on the device.
The value will be updated with the number of milliseconds elapsed since it was started.

```tsx twoslash
import {
useClockValue,
Canvas,
Circle,
useDerivedValue,
} from "@shopify/react-native-skia";

const interval = 3000;

const Demo = () => {
const clock = useClockValue();
const opacity = useDerivedValue(
(t) => {
return (t % interval) / interval;
},
[clock]
);
return (
<Canvas style={{ flex: 1 }}>
<Circle r={100} cx={100} cy={100} color="black" opacity={opacity} />
</Canvas>
);
};
```
2 changes: 1 addition & 1 deletion docs/docs/canvas/canvas.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Behind the scenes, it is using its own React renderer.
|:-----|:---------|:-----------------|
| style | `ViewStyle` | View style. |
| ref? | `Ref<SkiaView>` | Reference to the `SkiaView` object |
| onTouch? | `TouchHandler` | Touch handler for the Canvas (see [touch handler](/docs/animations/overview#usetouchhandler)). |
| onTouch? | `TouchHandler` | Touch handler for the Canvas (see [touch handler](/docs/animations/touch-events#usetouchhandler)). |

## Getting a Canvas Snapshot

Expand Down
7 changes: 4 additions & 3 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"lint": "eslint . --ext .ts,.tsx --max-warnings 0"
},
"dependencies": {
"@docusaurus/core": "^2.0.0-beta.16",
"@docusaurus/preset-classic": "^2.0.0-beta.16",
"@docusaurus/core": "^2.0.0-beta.17",
"@docusaurus/preset-classic": "^2.0.0-beta.17",
"@mdx-js/react": "^1.6.21",
"@shopify/react-native-skia": "link:../package/",
"@svgr/webpack": "^5.5.0",
Expand All @@ -31,8 +31,9 @@
"url-loader": "^4.1.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^2.0.0-beta.16",
"@docusaurus/module-type-aliases": "^2.0.0-beta.17",
"@tsconfig/docusaurus": "^1.0.4",
"@types/react-native": "^0.66.15",
"eslint": "^7.32.0",
"eslint-config-react-native-wcandillon": "^3.7.2",
"twoslash-cli": "^1.3.17",
Expand Down
7 changes: 6 additions & 1 deletion docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ const sidebars = {
collapsed: true,
type: "category",
label: "Animations",
items: ["animations/overview", "animations/reanimated"],
items: [
"animations/values",
"animations/animations",
"animations/touch-events",
"animations/reanimated",
],
},
],
};
Expand Down
Loading

0 comments on commit 22ca990

Please sign in to comment.