Skip to content

Commit

Permalink
docs: fix typos in skia guide and cropzoom docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Glazzes committed Aug 23, 2024
1 parent 4192d4d commit b5d4e6b
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 47 deletions.
4 changes: 3 additions & 1 deletion docs/docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,18 @@ export default defineConfig({
},
{
text: 'Utilities',
collapsed: true,
items: [
{ text: 'useImageResolution', link: '/utilities/useimageresolution' },
{ text: 'getAspectRatioSize', link: '/utilities/getAspectRatioSize' },
],
},
{
text: 'Guides',
collapsed: true,
items: [
{
text: 'Use CropZoom with Expo Image Manipulator',
text: 'CropZoom and Expo Image Manipulator',
link: '/guides/cropzoomexpo',
},
{
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/components/cropzoom.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ we can find the following:
This component comes with a handy algorithm to perform cropping operations for you, however you will need the
help a of deidicated library for this task.

- see [Use Crop Zoom with Expo Image Manipulator](../guides/cropzoomexpo) guide.
- see [CropZoom and Expo Image Manipulator](../guides/cropzoomexpo) guide.

The next video footage is taken from the [Example app](https://github.com/Glazzes/react-native-zoom-toolkit/tree/main/example).

Expand Down Expand Up @@ -267,7 +267,7 @@ ref.current?.crop(200);
Map all the transformations applied to your component into an object describing the context necessary to perform
a crop operation, such object must be used along with a library capable of cropping images and/or videos, for instance
Expo Image Manipulator, see [Use Crop Zoom with Expo Image Manipulator](../guides/cropzoomexpo).
Expo Image Manipulator, see [CropZoom and Expo Image Manipulator](../guides/cropzoomexpo).
- type definition: `(fixedWidth?: number) => CropContextResult`
- parameter information
Expand Down
62 changes: 41 additions & 21 deletions docs/docs/guides/cropzoomexpo.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
---
title: How to use CropZoom and Expo Image Manipulator
outline: deep
---

# Use CropZoom with Expo Image Manipulator
[Expo Image Manipulator](#https://docs.expo.dev/versions/latest/sdk/imagemanipulator/) is by far my favorite library for this particular use case because of its unoppinionated nature and feature set which includes horizontal flipping, vertical flipping, rotation and resizing image capabilities, in others words a feature set that aligns very well with one the provided by [CroopZoom](/components/cropzoom#crop).
# CropZoom and Expo Image Manipulator

Expo Image Manipulator is by far my favorite library for this particular use case because of its
unoppinionated nature and feature set which includes horizontal flipping, vertical flipping, rotation and
resizing image capabilities, in others words a feature set that aligns very well with one the provided
by [CroopZoom](/components/cropzoom#crop) component.

## What you'll be building
You'll build a simple example in which you'll overlay the resulting crop image on top of CropZoom component's crop area so you can see results are accurate, in order to see both the crop and gesture detection areas you will make use of the [debug](/components/cropzoom#debug) property.

You'll build a simple example in which you'll overlay the resulting crop image on top of CropZoom component's
crop area so you can see results are accurate, in order to see both the crop and gesture detection areas
you will make use of the [debug](/components/cropzoom#debug) property.

The next video footage shows what the end result looks like.

Expand All @@ -15,7 +23,9 @@ The next video footage shows what the end result looks like.
</div>

## Setup
Make sure you've followed the [Installation](/installation) guide first then you will need to install Expo image manipulator library.

Make sure you've followed the [Installation](/installation) guide first then you will need to install
Expo image manipulator library.

::: code-group

Expand All @@ -24,7 +34,7 @@ npm install expo-image-manipulator
```

```sh [yarn]
yarn install expo-image-manipulator
yarn add expo-image-manipulator
```

```sh [expo]
Expand All @@ -33,7 +43,7 @@ expo install expo-image-manipulator

:::

Copy and paste the following boilerplate code into your app, pay attention to `crop method` in the `Controls.tsx` file.
Copy and paste the following boilerplate code into your app and pay attention to crop method in Controls.tsx file.

::: code-group

Expand Down Expand Up @@ -147,19 +157,27 @@ export default Controls;
:::

## Crop Method
In `Controls.tsx` you saw crop method is empty, lets address that by using [manipulateAsync](https://docs.expo.dev/versions/latest/sdk/imagemanipulator/#imagemanipulatormanipulateasyncuri-actions-saveoptions) method from Expo Image Manipulator, this method allows you to apply the following actions to an image of your choice: `flip horizontally`, `flip vertically`, `rotate`, `resize` and `crop`.

Although [manipulateAsync](https://docs.expo.dev/versions/latest/sdk/imagemanipulator/#imagemanipulatormanipulateasyncuri-actions-saveoptions) method lets you apply actions in any order you want, you must follow an specific order to ensure both performance and the desired functionality:
- Resize
- Flip Horizontal
- Flip Vertical
- Rotate
- Crop
In Controls.tsx file you could see crop method is empty, lets address that by using [manipulateAsync](https://docs.expo.dev/versions/latest/sdk/imagemanipulator/#imagemanipulatormanipulateasyncuri-actions-saveoptions)
method from Expo Image Manipulator, this method allows you to apply the following actions to an image of your
choice: flip horizontally and/or vertically, rotate, resize and crop.

Although [manipulateAsync](https://docs.expo.dev/versions/latest/sdk/imagemanipulator/#imagemanipulatormanipulateasyncuri-actions-saveoptions)
method lets you apply actions in any order you want, you must follow an specific order to ensure both performance
and the desired functionality:

For this use case all actions are optional except the crop action, therefore you'll need to make some checks to maintain the previous mentioned order, so let's get to it.
- resize
- flip horizontal
- flip vertical
- rotate
- crop

- Call [crop method](/components/cropzoom#crop) from `cropRef` property as it will give you all the information needed to perform a crop operation.
- Perform the checks in the specified order.
For this use case all actions are optional except the crop action, therefore you'll need to make some checks
to maintain the previous mentioned order, so let's get to it.

- call [crop method](/components/cropzoom#crop) from cropRef property as it will give you the context required
to perform a crop operation.
- perform the checks in the specified order.

```typescript
const crop = async () => {
Expand All @@ -186,7 +204,7 @@ const crop = async () => {
}

actions.push({ crop: result.crop });
}
};
```

With all action checks in place all that remains is to crop the image and set the result with `setCrop` property, add the following to the end of `crop method`.
Expand All @@ -202,9 +220,11 @@ setTimeout(() => {
```

## What's next?

This example is pretty basic, you can check out both [Example app](https://github.com/Glazzes/react-native-zoomable/tree/main/example)'s CroopZoom examples, however you can keep working in this example, how about:

- Make it prettier.
- Use different images.
- Test with different `cropSize` values, nobody said `width` and `height` properties must be equals.
- Use `fixedWidth` argument with CropZoom's [crop method](/components/cropzoom#crop) to enforce resulting crops to be of any size you want.
- make it look pretty.
- use different aspect ratio size images.
- test with different `cropSize` property values, nobody said width and height dimensions must be equals.
- use `fixedWidth` argument with CropZoom's [crop method](/components/cropzoom#crop) to enforce resulting
crops to be of any size you want.
53 changes: 30 additions & 23 deletions docs/docs/guides/skia.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,33 @@ outline: deep

# How to use with Skia Components

As the saying goes "no pain, no gains", setting up any of this library components with Skia requires a little
more effort than wrapping a component into a another, you may have think of one of these two solutions
already:
As the saying goes "no pain, no gain", setting up any of this library components with Skia requires a little
more effort than wrapping a component into another, at this point you may have think of one of these two
solutions already:

- I'm gonna use x component within a `Canvas` element.
- I'm gonna wrap my `Canvas` within X component.
- I'm gonna use x zoom component within my Skia canvas.
- I'm gonna wrap my Skia canvas within x zoom component.

Sadly none of them works, the first one will crash your app and the second one may look like it's working but
it will produce a pixelated result because your canvas is getting scaled directly by one of the zoom components.

## Working around this issue

In order to get this working as expected we want to mirror the transformation state from one component to the
other, so the Skia Canvas never gets scaled directly but the items within it do.
In order to get this working as expected we want to mirror the transformation state from the zoom component
to the Skia component, this way the Skia canvas never gets scaled but the items within it do.

Luckily for you, the components exposed by this library have a property called `onGestureActive` which reports
the changes in the transformation state.

To make it short, we can to use these components with transparent views and update the Skia components accordingly
to the values provided by `onGestureActive` callback.
To make it short, we can to use these zoom components by nesting a transparent view and update the Skia components
accordingly to the values provided by `onGestureActive` callback.

## The Heart of the Matter

ResumableZoom is the heart of this library, therefore it makes the most sense to showcase the Skia usage with it,
however the techniques you will use are also applicable to the other components as well.

As of today release (2.1.4) we need to write some boilerplate in the form of a simplified hook, in the
As of today release (2.1.4) we need to write some boilerplate code in the form of a simplified hook, in the
next major release a complete version of this hook will come bundled with the library.

```ts
Expand All @@ -43,12 +43,12 @@ import {
import type { Transforms3d } from '@shopify/react-native-skia';
import type { ResumableZoomState } from 'react-native-zoom-toolkit';

type ResumableTransformationValues = {
type TransformationHelpers = {
transform: Readonly<SharedValue<Transforms3d>>;
onUpdate: (state: ResumableZoomState) => void;
};

export const useResumableValues = (): ResumableTransformationValues => {
export const useTransformationState = (): TransformationHelpers => {
const translateX = useSharedValue<number>(0);
const translateY = useSharedValue<number>(0);
const scale = useSharedValue<number>(1);
Expand Down Expand Up @@ -77,7 +77,7 @@ export const useResumableValues = (): ResumableTransformationValues => {
We will focus on replicating the example seen in ResumableZoom documentation, let's set up our basic structure
with Skia first.

```tsx{38}
```tsx{38-39}
import React from 'react';
import { View, useWindowDimensions } from 'react-native';
import { Canvas, Image, useImage } from '@shopify/react-native-skia';
Expand Down Expand Up @@ -115,7 +115,8 @@ const App = () => {
y={y}
width={imageSize.width}
height={imageSize.height}
origin={vec(centerX, centerY)} // Center of transformation must match the center of the image
// Center of transformation must match the center of the image
origin={vec(centerX, centerY)}
/>
</Canvas>
</View>
Expand All @@ -125,28 +126,29 @@ const App = () => {
export default App;
```

With our basic structure in place, let's discuss the two missing steps to make this example work:
With our basic structure in place, let's address the two missing steps to make this example work:

- Overlay ResumableZoom on top of the Skia Canvas in such a way it's parallel with our Skia Image.
- Overlay ResumableZoom on top of the Skia Canvas in such a way our transparent view and our Skia image are parallel
to each other.
- Use the hook we just created a moment ago, assign `onUpdate` callback to ResumableZoom's onGestureActive
property and `transform` property to Skia Image's transform property.

Let's see how the end result looks like:

```tsx{13,39,44-48}
```tsx{13,40,44-52}
import React from 'react';
import { View, useWindowDimensions } from 'react-native';
import { Canvas, Image, useImage } from '@shopify/react-native-skia';
import { getAspectRatioSize } from 'react-native-zoom-toolkit';
import { useResumableValues } from 'path to the hook we created above';
import { useTransformationState } from 'path to the hook we created above';
const uri =
'https://assets-global.website-files.com/63634f4a7b868a399577cf37/64665685a870fadf4bb171c2_labrador%20americano.jpg';
const App = () => {
const image = useImage(uri);
const { width, height } = useWindowDimensions();
const { onUpdate, transform } = useResumableValues();
const { onUpdate, transform } = useTransformationState();
if (image === null) {
return null;
Expand Down Expand Up @@ -178,7 +180,11 @@ const App = () => {
</Canvas>
<View style={{ width, height, position: 'absolute' }}>
<ResumableZoom maxScale={resolution} extendGestures={true} onGestureActive={onUpdate}>
<ResumableZoom
maxScale={resolution}
extendGestures={true}
onGestureActive={onUpdate}
>
<View style={{ width: imageSize.width, height: imageSize.height }} />
</ResumableZoom>
</View>
Expand All @@ -191,10 +197,11 @@ export default App;

Let's see what we can take from this example

- The overlying zoom component must be the same size as the canvas.
- The overlying zoom component must be the same size as the canvas, this also applies to the transparent view
size and the Skia component to zoom.
- You can assign a color to the transparent view and lower the opacity if you are having trouble centering the
zoom component with your Skia component.
- Skia Images pixelate at a faster rate than RN image component, therefore setting ResumableZoom's maxscale
to the image resolution is a recommended practice.
- Skia Images get pixelated at a faster rate than RN image component does, therefore setting ResumableZoom's
maxscale to the image resolution is a recommended practice.

And that's pretty much it, thanks for reading!

0 comments on commit b5d4e6b

Please sign in to comment.