Skip to content

Commit

Permalink
Fix rectangle processing (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
william-candillon authored Jan 5, 2022
1 parent fbf4223 commit 7a7536e
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 32 deletions.
33 changes: 31 additions & 2 deletions docs/docs/shapes/polygons.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ Draws a rectangle.
| y | `number` | Y coordinate. |
| width | `number` | Width of the rectangle. |
| height | `number` | Height of the rectangle. |
| rx? | `number` | Horizontal corner radius. Defaults to `ry` if specified or 0. |
| ry? | `number` | Vertical corner radius. Defaults to `rx` if specified or 0. |

```tsx twoslash
import {Canvas, Rect} from "@shopify/react-native-skia";
Expand All @@ -25,6 +23,37 @@ const RectDemo = () => {
return (
<Canvas style={{ flex: 1}}>
<Rect
x={0}
y={0}
width={256}
height={256}
color="lightblue"
/>
</Canvas>
);
};
```

## RRect

Draws a rounded rectangle.

| Name | Type | Description |
|:-------|:---------|:--------------------------------------------------------------|
| x | `number` | X coordinate. |
| y | `number` | Y coordinate. |
| width | `number` | Width of the rectangle. |
| height | `number` | Height of the rectangle. |
| rx? | `number` | Horizontal corner radius. Defaults to `ry` if specified or 0. |
| ry? | `number` | Vertical corner radius. Defaults to `rx` if specified or 0. |

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

const RectDemo = () => {
return (
<Canvas style={{ flex: 1}}>
<RRect
x={0}
y={0}
width={256}
Expand Down
3 changes: 2 additions & 1 deletion example/src/Examples/API/Shapes2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
rrect,
Paint,
DashPathEffect,
RRect,
} from "@shopify/react-native-skia";

import { Title } from "./components/Title";
Expand Down Expand Up @@ -65,7 +66,7 @@ export const Shapes = () => {
<Canvas style={styles.container}>
<Group color="#61DAFB">
<Rect rect={{ x: PADDING, y: PADDING, width: 100, height: 100 }} />
<Rect
<RRect
x={SIZE + 2 * PADDING}
y={PADDING}
width={SIZE}
Expand Down
5 changes: 3 additions & 2 deletions package/src/renderer/components/shaders/Shader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import type { IRuntimeEffect } from "../../../skia";
import type { Vector, AnimatedProps, TransformProps } from "../../processors";
import { useDeclaration } from "../../nodes/Declaration";
import { localMatrix } from "../../processors";
import { hasProperty } from "../../typeddash";

// We need to use any here because hasOwnProperty doesn't work on JSI instances
const isVector = (obj: unknown): obj is Vector =>
hasProperty(obj, "x") && hasProperty(obj, "y");
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(obj as any).x !== undefined && (obj as any).y !== undefined;

type Uniform = number | number[] | Vector;

Expand Down
26 changes: 15 additions & 11 deletions package/src/renderer/components/shapes/Rect.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import React from "react";

import type { CustomPaintProps } from "../../processors";
import type { RectOrRRectDef } from "../../processors/Shapes";
import { isRRect } from "../../processors/Shapes";
import type { IRect } from "../../../skia/Rect";
import { processRectOrRRect } from "../../processors";
import type { RectDef, RRectDef } from "../../processors/Shapes";
import { processRect, processRRect } from "../../processors/Shapes";
import type { AnimatedProps } from "../../processors/Animations/Animations";
import { useDrawing } from "../../nodes/Drawing";

export type RectProps = RectOrRRectDef & CustomPaintProps;
export type RectProps = RectDef & CustomPaintProps;

export const Rect = (props: AnimatedProps<RectProps>) => {
const onDraw = useDrawing(props, ({ canvas, paint }, rectProps) => {
const rect = processRectOrRRect(rectProps);
if (isRRect(rect)) {
canvas.drawRRect(rect, paint);
} else {
canvas.drawRect(rect as IRect, paint);
}
const rect = processRect(rectProps);
canvas.drawRect(rect, paint);
});
return <skDrawing onDraw={onDraw} {...props} />;
};

export type RRectProps = RRectDef & CustomPaintProps;

export const RRect = (props: AnimatedProps<RRectProps>) => {
const onDraw = useDrawing(props, ({ canvas, paint }, rectProps) => {
const rrect = processRRect(rectProps);
canvas.drawRRect(rrect, paint);
});
return <skDrawing onDraw={onDraw} {...props} />;
};
26 changes: 13 additions & 13 deletions package/src/renderer/processors/Shapes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Here we use any because hasOwnProperty doesn't work on JSI instances not does the (key in obj) syntax
// And using Object.keys for such use-case is incredibly slow
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { ReactNode } from "react";

import type { IRect, IRRect } from "../../skia";
import { hasProperty } from "../typeddash";

import type { Vector as Point } from "./math/Vector";
import { vec } from "./math/Vector";
Expand All @@ -26,7 +28,7 @@ interface ScalarCircleDef {
export type CircleDef = PointCircleDef | ScalarCircleDef;

const isCircleScalarDef = (def: CircleDef): def is ScalarCircleDef =>
hasProperty(def, "cx");
(def as any).cx;
export const processCircle = (def: CircleDef) => {
if (isCircleScalarDef(def)) {
return { c: vec(def.cx, def.cy), r: def.r };
Expand Down Expand Up @@ -64,12 +66,12 @@ export const center = (r: IRect | IRRect) =>
? vec(r.rect.x + r.rect.width / 2, r.rect.y + r.rect.height / 2)
: vec(r.x + r.width / 2, r.y + r.height / 2);

export const isRectCtor = (def: RectOrRRectDef): def is RectCtor =>
!hasProperty(def, "rect");
export const isRect = (def: RectOrRRectDef): def is IRect =>
hasProperty(def, "rect");
export const isRRect = (def: RectOrRRectDef): def is IRRect =>
!isRectCtor(def) && hasProperty(def, "rx");
export const isRRectCtor = (def: RRectDef): def is RRectCtor =>
(def as any).rect !== undefined;
export const isRectCtor = (def: RectDef): def is RectCtor =>
(def as any).rect !== undefined;
export const isRRect = (def: IRect | IRRect): def is IRRect =>
(def as any).rect !== undefined;

export interface RectCtor {
x: number;
Expand All @@ -84,7 +86,7 @@ export interface RRectCtor extends RectCtor {
}

export type RectDef = RectCtor | { rect: IRect };
export type RectOrRRectDef = RRectCtor | { rect: IRect | IRRect };
export type RRectDef = RRectCtor | { rect: IRRect };

export const processRect = (def: RectDef) => {
if (isRectCtor(def)) {
Expand All @@ -94,10 +96,8 @@ export const processRect = (def: RectDef) => {
}
};

export const processRectOrRRect = (def: RectOrRRectDef) => {
if (isRectCtor(def) && !hasProperty(def, "rx") && !hasProperty(def, "ry")) {
return rect(def.x, def.y, def.width, def.height);
} else if (isRectCtor(def)) {
export const processRRect = (def: RRectDef) => {
if (isRRectCtor(def)) {
const { rx, ry } = def;
return rrect(
rect(def.x, def.y, def.width, def.height),
Expand Down
3 changes: 0 additions & 3 deletions package/src/renderer/typeddash.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
export const mapKeys = <T>(obj: T) => Object.keys(obj) as (keyof T)[];

export const hasProperty = (obj: unknown, key: string) =>
!!(typeof obj === "object" && obj !== null && key in obj);

export const exhaustiveCheck = (a: never): never => {
throw new Error(`Unexhaustive handling for ${a}`);
};

0 comments on commit 7a7536e

Please sign in to comment.