多角形とパス
矩形・線・点といった多角形(Polygon)系の図形と、任意の形状を描けるPathの基本を、トリム(部分描画)デモとあわせて解説します。
制御点で輪郭を作り、塗り・ストローク・トリムを同じPathへ重ねていきます。
前章の円・楕円・Boxに続いて、矩形や線分といった多角形(Polygon)系の図形と、より自由な形状を描ける<Path>を見ていきます。
Rect: 矩形を描く
| Name | Type | Description |
|---|---|---|
| x | number |
x座標 |
| y | number |
y座標 |
| width | number |
幅 |
| height | number |
高さ |
import { Canvas, Rect } from "@shopify/react-native-skia";
const RectDemo = () => {
return (
<Canvas style={{ flex: 1 }}>
<Rect x={0} y={0} width={256} height={256} color="lightblue" />
</Canvas>
);
};
RoundedRect: 角丸矩形を描く
| Name | Type | Description |
|---|---|---|
| x | number |
x座標 |
| y | number |
y座標 |
| width | number |
幅 |
| height | number |
高さ |
| r? | number または Vector |
角丸の半径。省略時は0 |
import { Canvas, RoundedRect } from "@shopify/react-native-skia";
const RoundedRectDemo = () => {
return (
<Canvas style={{ flex: 1 }}>
<RoundedRect x={0} y={0} width={256} height={256} r={25} color="lightblue" />
</Canvas>
);
};
4つの角それぞれに異なる半径を指定したい場合は、rの代わりにrectpropに角ごとの座標を持つオブジェクトを渡します。
const size = 256;
const r = size * 0.2;
const rrct = {
rect: { x: 0, y: 0, width: size, height: size },
topLeft: { x: 0, y: 0 },
topRight: { x: r, y: r },
bottomRight: { x: 0, y: 0 },
bottomLeft: { x: r, y: r },
};
<RoundedRect rect={rrct} color="lightblue" />;
以下のデモでshapeを切り替えると、この章で扱うRect・RoundedRect・DiffRect・Line・Pointsをまとめて確認できます。RoundedRectとDiffRectはradiusで角の丸みを、Pointsはmodeで点のつなぎ方を調整できます。
DiffRect: 2つの矩形の差分を描く
外側の矩形から内側の矩形をくり抜いた形を描きます。ドーナツ状の枠線や、額縁のような表現に使えます。
| Name | Type | Description |
|---|---|---|
| outer | RectOrRRect |
外側の矩形 |
| inner | RectOrRRect |
内側の矩形(くり抜く部分) |
import { Canvas, DiffRect, rect, rrect } from "@shopify/react-native-skia";
const DiffRectDemo = () => {
const outer = rrect(rect(0, 0, 256, 256), 25, 25);
const inner = rrect(rect(50, 50, 156, 156), 50, 50);
return (
<Canvas style={{ flex: 1 }}>
<DiffRect inner={inner} outer={outer} color="lightblue" />
</Canvas>
);
};
上のRoundedRect: 角丸矩形を描く節にあるデモのshapeをdiffRectに切り替えると確認できます。
Line: 線分を描く
| Name | Type | Description |
|---|---|---|
| p1 | Point |
始点 |
| p2 | Point |
終点 |
import { Canvas, Line, vec } from "@shopify/react-native-skia";
const LineDemo = () => {
return (
<Canvas style={{ flex: 1 }}>
<Line p1={vec(0, 0)} p2={vec(256, 256)} color="lightblue" style="stroke" strokeWidth={4} />
</Canvas>
);
};
上のRoundedRect: 角丸矩形を描く節にあるデモのshapeをlineに切り替えると確認できます。
Points: 複数の点を描く
複数の点を描画し、modeで点同士のつなぎ方を指定できます。
| Name | Type | Description |
|---|---|---|
| points | Point[] |
描画する点の配列 |
| mode | PointMode |
points(接続なし)・lines(2点ずつ接続)・polygon(全体を接続)。デフォルトはpoints |
import { Canvas, Points, vec } from "@shopify/react-native-skia";
const points = [
vec(128, 0), vec(168, 80), vec(256, 93), vec(192, 155), vec(207, 244),
vec(128, 202), vec(49, 244), vec(64, 155), vec(0, 93), vec(88, 80), vec(128, 0),
];
const PointsDemo = () => {
return (
<Canvas style={{ flex: 1 }}>
<Points points={points} mode="polygon" color="lightblue" style="stroke" strokeWidth={4} />
</Canvas>
);
};
mode="polygon"で星形の頂点を順につなぐと、そのまま星のアウトラインになります。上のRoundedRect: 角丸矩形を描く節にあるデモのshapeをpointsに切り替えると、modeによる違いも確認できます。
Path: 任意の形状を描く
<Path>はSkiaの中で最も柔軟な図形コンポーネントです。パスの記法はSVG Pathと意味的に同じです。
| Name | Type | Description |
|---|---|---|
| path | SkPath または string |
描画するパス。SVG Path記法の文字列、またはSkia.PathBuilderで作ったオブジェクト |
| start | number |
パスの開始位置をトリムする(0〜1、デフォルト0) |
| end | number |
パスの終了位置をトリムする(0〜1、デフォルト1) |
| stroke | StrokeOptions |
パスをストローク済みの塗りつぶし形状に変換する。width・strokeMiterLimit・precisionを持つ |
SVG記法で書く
import { Canvas, Path } from "@shopify/react-native-skia";
const SVGPathDemo = () => {
return (
<Canvas style={{ flex: 1 }}>
<Path
path="M 128 0 L 168 80 L 256 93 L 192 155 L 207 244 L 128 202 L 49 244 L 64 155 L 0 93 L 88 80 L 128 0 Z"
color="lightblue"
/>
</Canvas>
);
};
PathBuilderで組み立てる
プログラムで動的にパスを組み立てたいときはSkia.PathBuilderを使います。メソッドチェーンで座標を積み上げ、最後に.build()でイミュータブルなSkPathを得ます。
import { Canvas, Path, Skia } from "@shopify/react-native-skia";
const path = Skia.PathBuilder.Make()
.moveTo(128, 0)
.lineTo(168, 80)
.lineTo(256, 93)
.lineTo(192, 155)
.lineTo(207, 244)
.lineTo(128, 202)
.lineTo(49, 244)
.lineTo(64, 155)
.lineTo(0, 93)
.lineTo(88, 80)
.lineTo(128, 0)
.close()
.build();
const PathBuilderDemo = () => {
return (
<Canvas style={{ flex: 1 }}>
<Path path={path} color="lightblue" />
</Canvas>
);
};
先ほどSVG記法で書いた星と同じ形になります。細かい座標をコードで生成したい場合や、後からSkia.Path.Stroke()のような静的操作を適用したい場合はこちらが向いています。
以下のデモはpoints(頂点数)を変えるたびにSkia.PathBuilderでパスを組み立て直しています。SVG文字列では表現しづらい、頂点数が動的に変わる形状を作れるのがPathBuilderの強みです。
start/endでパスを部分的に描く(トリム)
startとendを使うと、パスの一部分だけを描画できます。アニメーションでパスを少しずつ描き足す表現でよく使われます。
<Path
path="M 128 0 L 168 80 L 256 93 L 192 155 L 207 244 L 128 202 L 49 244 L 64 155 L 0 93 L 88 80 L 128 0 Z"
color="lightblue"
style="stroke"
strokeJoin="round"
strokeWidth={5}
// 最初と最後の1/4ずつをトリムする
start={0.25}
end={0.75}
/>
以下のデモでstart・end・strokeWidth・色相(hue)を動かして、トリムされる範囲を確認できます。
fillType: 内側の判定方法
fillTypeは図形の「内側」をどう判定するかを決めるプロパティです。winding(デフォルト)・evenOdd・inverseWinding・inverseEvenOddが指定できます。星形のように自己交差するパスでは、この設定によって塗られる範囲が変わります。
<Path path={starPath} color="lightblue" fillType="evenOdd" />
windingでは交差した内側の五角形部分まで塗りつぶされますが、evenOddでは交差のたびに内外が反転するため、星の角だけが塗られた中抜きの見た目になります。
以下のデモは、隣り合わない頂点を結んで自己交差させたペンタグラム(五芒星)に4種類のfillTypeを切り替えて適用します。windingとevenOddで中央の塗られ方がどう変わるか確認してください。
補足: Path APIのマイグレーション
React Native Skiaは、可変(mutable)なPath APIから、PathBuilderによる不変(immutable)なPath APIへの移行を進めています。既存コードを新しいAPIに書き換える際は、Path API Migration Guideに新旧APIの対応表がまとまっているので参照してください。