Skip to content

Commit

Permalink
👻 Inner Shadow (#246)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcandillon authored Mar 14, 2022
1 parent d57a340 commit e8532fb
Show file tree
Hide file tree
Showing 21 changed files with 431 additions and 61 deletions.
Binary file added docs/docs/image-filters/assets/inner-shadow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
---
id: drop-shadows
title: Drop Shadows
sidebar_label: Drop Shadows
slug: /image-filters/drop-shadows
id: shadows
title: Shadows
sidebar_label: Shadows
slug: /image-filters/shadows
---

## Drop Shadow

The `DropShadow` image filter is equivalent to its [SVG counterpart](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow()).
It creates a filter that draws a drop shadow under the input content.
There is a `shadowOnly` property that renders the drop shadow excluding the input content.
Expand All @@ -16,11 +18,10 @@ There is a `shadowOnly` property that renders the drop shadow excluding the inpu
| dy | `number` | The Y offset of the shadow. |
| blur | `number` | The blur radius for the shadow |
| color | `Color` | The color of the drop shadow |
| cropRect | `IRect` | Optional rectangle that crops the input and output |
| shadowOnly? | `boolean` | If true, the result does not include the input content |
| children? | `ImageFilter` | Optional image filter to be applied first |

## Example
### Example

The example below creates two drop shadows.
It is equivalent to the following CSS notation
Expand Down Expand Up @@ -60,3 +61,49 @@ const Neumorphism = () => {
### Result

![Drop Shadow](assets/drop-shadow.png)

## Inner Shadow

Inner shadows are drawn within the input content.


| Name | Type | Description |
|:------------|:--------------|:--------------------------------------------------------------|
| dx | `number` | The X offset of the shadow. |
| dy | `number` | The Y offset of the shadow. |
| blur | `number` | The blur radius for the shadow |
| color | `Color` | The color of the drop shadow |
| shadowOnly? | `boolean` | If true, the result does not include the input content |
| children? | `ImageFilter` | Optional image filter to be applied first |

### Example

```tsx twoslash
import {
InnerShadow,
Fill,
Group,
Paint,
RoundedRect,
Canvas
} from "@shopify/react-native-skia";

const Neumorphism = () => {
return (
<Canvas style={{ width: 256, height: 256 }}>
<Fill color="lightblue" />
<Group>
<Paint>
<InnerShadow dx={12} dy={12} blur={25} color="#93b8c4" />
<InnerShadow dx={-12} dy={-12} blur={25} color="#c7f8ff" />
</Paint>
<RoundedRect x={32} y={32} width={192} height={192} rx={32} color="lightblue" />
</Group>
</Canvas>
);
};
```

### Result

![Drop Shadow](assets/inner-shadow.png)
6 changes: 3 additions & 3 deletions docs/docs/shaders/colors.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ import {
Shader,
Fill,
RadialGradient,
BlendShader,
Blend,
vec
} from "@shopify/react-native-skia";

export const BlendDemo = () => {
return (
<Canvas style={{ flex: 1 }}>
<Paint>
<BlendShader mode="difference">
<Blend mode="difference">
<RadialGradient
r={128}
c={vec(128, 128)}
colors={["blue", "yellow"]}
/>
<Turbulence freqX={0.05} freqY={0.05} octaves={4} />
</BlendShader>
</Blend>
</Paint>
<Rect x={0} y={0} width={256} height={256} />
</Canvas>
Expand Down
2 changes: 1 addition & 1 deletion docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const sidebars = {
items: [
"mask-filters",
"color-filters",
"image-filters/drop-shadows",
"image-filters/shadows",
"image-filters",
"path-effects",
"backdrops-filters",
Expand Down
6 changes: 3 additions & 3 deletions example/src/Examples/API/Gradients2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
vec,
Turbulence,
ColorShader,
BlendShader,
Blend,
} from "@shopify/react-native-skia";

const { width } = Dimensions.get("window");
Expand Down Expand Up @@ -70,10 +70,10 @@ export const Gradients = () => {
</Paint>
<Rect rect={r4} />
<Paint>
<BlendShader mode="difference">
<Blend mode="difference">
<ColorShader color="#61DAFB" />
<Turbulence freqX={0.05} freqY={0.05} octaves={4} />
</BlendShader>
</Blend>
</Paint>
<Rect rect={r5} />
<Paint>
Expand Down
132 changes: 132 additions & 0 deletions example/src/Examples/Neumorphism/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {
Canvas,
Circle,
Fill,
Group,
LinearGradient,
Paint,
add,
vec,
DropShadow,
Path,
Text,
Skia,
useLoop,
SweepGradient,
useDerivedValue,
mix,
useFont,
InnerShadow,
RoundedRect,
} from "@shopify/react-native-skia";
import React from "react";
import { Dimensions } from "react-native";

const { width, height } = Dimensions.get("window");
const c = vec(width / 2, height / 2 - 85);
const r = 85;
const r1 = 60;

const meter = Skia.Path.Make();
meter.addCircle(c.x, c.y, r);

export const Neumorphism = () => {
const font = useFont(require("./SF-Mono-Semibold.otf"), 32);
const progress = useLoop({ duration: 15000 });
const end = useDerivedValue(
() => mix(progress.current, 0.2, 0.95),
[progress]
);
const text = useDerivedValue(
() => `${Math.round(end.current * 100)}%`,
[end]
);
if (font === null) {
return null;
}
const pos = font.measureText("30%");
return (
<Canvas style={{ flex: 1 }}>
<Group>
<Paint>
<LinearGradient
start={vec(0, 0)}
end={vec(0, height)}
colors={["#2A2D32", "#131313"]}
/>
</Paint>
<Fill />
</Group>
<Group>
<Paint>
<LinearGradient
start={add(c, vec(-r, 0))}
end={add(c, vec(r, 0))}
colors={["#2B2F33", "#101113"]}
/>
<DropShadow dx={18} dy={18} blur={65} color="#141415" />
<DropShadow dx={-18} dy={-18} blur={65} color="#485057" />
</Paint>
<Circle c={c} r={r} />
</Group>
<Group>
<Paint>
<SweepGradient c={c} colors={["#2FB8FF", "#9EECD9"]} />
</Paint>
<Path
path={meter}
strokeWidth={20}
start={0.1}
end={end}
style="stroke"
strokeCap="round"
/>
</Group>
<Group>
<Paint>
<InnerShadow
dx={2}
dy={1}
blur={2}
color="rgba(255, 255, 255, 0.5)"
/>
<InnerShadow
dx={-26}
dy={-26}
blur={66}
color="rgba(59, 68, 81, 0.5)"
/>
<InnerShadow dx={26} dy={26} blur={81} color="rgba(0, 0, 0, 0.5)" />
</Paint>
<Circle c={c} r={r1} color="#32363B" />
</Group>
<Text
x={c.x - pos.width / 2}
y={c.y + pos.height / 2}
font={font}
text={text}
color="white"
/>
<Group>
<Paint>
<InnerShadow
dx={-3}
dy={-3}
blur={6}
color="rgba(255, 255, 255, 0.25)"
/>
<InnerShadow dx={6} dy={6} blur={6} color="black" />
</Paint>
<RoundedRect
x={32}
y={height / 2 + 32}
width={width - 64}
height={height / 2 - 32}
rx={25}
ry={25}
color="#202122"
/>
</Group>
</Canvas>
);
};
16 changes: 16 additions & 0 deletions example/src/Examples/Neumorphism/Neumorphism.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Group,
Paint,
RoundedRect,
InnerShadow,
} from "@shopify/react-native-skia";
import React from "react";

Expand All @@ -30,6 +31,21 @@ export const Neumorphism = () => {
color="lightblue"
/>
</Group>

<Group>
<Paint>
<InnerShadow dx={12} dy={12} blur={25} color="#93b8c4" />
<InnerShadow dx={-12} dy={-12} blur={25} color="#c7f8ff" />
</Paint>
<RoundedRect
x={PADDING}
y={2 * PADDING + SIZE}
width={SIZE}
height={SIZE}
rx={R}
color="lightblue"
/>
</Group>
</Canvas>
);
};
Binary file not shown.
58 changes: 58 additions & 0 deletions package/cpp/api/JsiSkImageFilterFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@ class JsiSkImageFilterFactory : public JsiSkHostObject {
getContext(), SkImageFilters::Compose(outer, inner)));
}


JSI_HOST_FUNCTION(MakeBlend) {
auto mode = static_cast<SkBlendMode>(arguments[0].asNumber());
sk_sp<SkImageFilter> background = JsiSkImageFilter::fromValue(runtime, arguments[1]);
sk_sp<SkImageFilter> foreground = nullptr;

if(count > 2 && !arguments[2].isNull()) {
foreground = JsiSkImageFilter::fromValue(runtime, arguments[2]);
}

SkImageFilters::CropRect cropRect = {};
if (count > 3 && !arguments[3].isUndefined()) {
cropRect = *JsiSkRect::fromValue(runtime, arguments[3]);
}

return jsi::Object::createFromHostObject(
runtime, std::make_shared<JsiSkImageFilter>(
getContext(), SkImageFilters::Blend(mode, background, foreground, cropRect)));
}

JSI_HOST_FUNCTION(MakeDropShadow) {
auto dx = arguments[0].asNumber();
auto dy = arguments[1].asNumber();
Expand Down Expand Up @@ -136,6 +156,41 @@ class JsiSkImageFilterFactory : public JsiSkHostObject {
color, input, cropRect)));
}

JSI_HOST_FUNCTION(MakeErode) {
auto rx = arguments[0].asNumber();
auto ry = arguments[1].asNumber();
sk_sp<SkImageFilter> input;
if (!arguments[2].isNull() && !arguments[2].isUndefined()) {
input = JsiSkImageFilter::fromValue(runtime, arguments[2]);
}
SkImageFilters::CropRect cropRect = {};
if (count > 3 && !arguments[3].isUndefined()) {
cropRect = *JsiSkRect::fromValue(runtime, arguments[3]);
}
return jsi::Object::createFromHostObject(
runtime,
std::make_shared<JsiSkImageFilter>(
getContext(), SkImageFilters::Erode(rx, ry, input, cropRect))
);
}

JSI_HOST_FUNCTION(MakeDilate) {
auto rx = arguments[0].asNumber();
auto ry = arguments[1].asNumber();
sk_sp<SkImageFilter> input;
if (!arguments[2].isNull() && !arguments[2].isUndefined()) {
input = JsiSkImageFilter::fromValue(runtime, arguments[2]);
}
SkImageFilters::CropRect cropRect = {};
if (count > 3 && !arguments[3].isUndefined()) {
cropRect = *JsiSkRect::fromValue(runtime, arguments[3]);
}
return jsi::Object::createFromHostObject(
runtime,
std::make_shared<JsiSkImageFilter>(
getContext(), SkImageFilters::Dilate(rx, ry, input, cropRect)));
}

JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeBlur),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeOffset),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory,
Expand All @@ -144,6 +199,9 @@ class JsiSkImageFilterFactory : public JsiSkHostObject {
MakeShader),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDisplacementMap),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeCompose),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeErode),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDilate),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeBlend),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory, MakeDropShadow),
JSI_EXPORT_FUNC(JsiSkImageFilterFactory,
MakeDropShadowOnly))
Expand Down
Loading

0 comments on commit e8532fb

Please sign in to comment.