mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
feat: FeFlood (#2487)
# Summary Continuation of #2362 implementing `FeFlood` filter https://www.w3.org/TR/SVG11/filters.html#feFloodElement ## Test Plan Example app → Filters → `FeFlood` ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | macOS | ✅ _*_ | | Android | ✅ | | Web | ✅ | _* `canvasWidth/canvasHeight` is incorrect on macOS, so there might be some problems_
This commit is contained in:
2
USAGE.md
2
USAGE.md
@@ -1301,6 +1301,7 @@ Filter effects are a way of processing an element’s rendering before it is dis
|
||||
The following filters have been implemented:
|
||||
|
||||
- FeColorMatrix
|
||||
- FeFlood
|
||||
- FeGaussianBlur
|
||||
- FeMerge
|
||||
- FeOffset
|
||||
@@ -1314,7 +1315,6 @@ Not supported yet:
|
||||
- FeDiffuseLighting
|
||||
- FeDisplacementMap
|
||||
- FeDropShadow
|
||||
- FeFlood
|
||||
- FeFuncA
|
||||
- FeFuncB
|
||||
- FeFuncG
|
||||
|
||||
130
android/src/main/java/com/horcrux/svg/FeFloodView.java
Normal file
130
android/src/main/java/com/horcrux/svg/FeFloodView.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import com.facebook.react.bridge.ColorPropConverter;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.JavaOnlyArray;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class FeFloodView extends FilterPrimitiveView {
|
||||
private static final Pattern regex = Pattern.compile("[0-9.-]+");
|
||||
|
||||
public @Nullable ReadableArray floodColor;
|
||||
public float floodOpacity = 1;
|
||||
|
||||
public FeFloodView(ReactContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
public void setFloodColor(@Nullable Dynamic color) {
|
||||
if (color == null || color.isNull()) {
|
||||
floodColor = null;
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
ReadableType strokeType = color.getType();
|
||||
if (strokeType.equals(ReadableType.Map)) {
|
||||
ReadableMap colorMap = color.asMap();
|
||||
setFloodColor(colorMap);
|
||||
return;
|
||||
}
|
||||
|
||||
// This code will probably never be reached with current changes
|
||||
ReadableType type = color.getType();
|
||||
if (type.equals(ReadableType.Number)) {
|
||||
floodColor = JavaOnlyArray.of(0, color.asInt());
|
||||
} else if (type.equals(ReadableType.Array)) {
|
||||
floodColor = color.asArray();
|
||||
} else {
|
||||
JavaOnlyArray arr = new JavaOnlyArray();
|
||||
arr.pushInt(0);
|
||||
Matcher m = regex.matcher(color.asString());
|
||||
int i = 0;
|
||||
while (m.find()) {
|
||||
double parsed = Double.parseDouble(m.group());
|
||||
arr.pushDouble(i++ < 3 ? parsed / 255 : parsed);
|
||||
}
|
||||
floodColor = arr;
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setFloodColor(@Nullable ReadableMap color) {
|
||||
if (color == null) {
|
||||
this.floodColor = null;
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
int type = color.getInt("type");
|
||||
if (type == 0) {
|
||||
ReadableType payloadType = color.getType("payload");
|
||||
if (payloadType.equals(ReadableType.Number)) {
|
||||
this.floodColor = JavaOnlyArray.of(0, color.getInt("payload"));
|
||||
} else if (payloadType.equals(ReadableType.Map)) {
|
||||
this.floodColor = JavaOnlyArray.of(0, color.getMap("payload"));
|
||||
}
|
||||
} else if (type == 1) {
|
||||
this.floodColor = JavaOnlyArray.of(1, color.getString("brushRef"));
|
||||
} else {
|
||||
this.floodColor = JavaOnlyArray.of(type);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setFloodOpacity(float opacity) {
|
||||
this.floodOpacity = opacity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap applyFilter(HashMap<String, Bitmap> resultsMap, Bitmap prevResult) {
|
||||
Bitmap floodBitmap =
|
||||
Bitmap.createBitmap(prevResult.getWidth(), prevResult.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas floodCanvas = new Canvas(floodBitmap);
|
||||
Paint paint = new Paint();
|
||||
paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
this.setupPaint(paint, this.floodOpacity, this.floodColor);
|
||||
floodCanvas.drawPaint(paint);
|
||||
return floodBitmap;
|
||||
}
|
||||
|
||||
private void setupPaint(Paint paint, float opacity, @Nullable ReadableArray colors) {
|
||||
int colorType = colors.getInt(0);
|
||||
switch (colorType) {
|
||||
case 0:
|
||||
if (colors.size() == 2) {
|
||||
int color;
|
||||
if (colors.getType(1) == ReadableType.Map) {
|
||||
color = ColorPropConverter.getColor(colors.getMap(1), getContext());
|
||||
} else {
|
||||
color = colors.getInt(1);
|
||||
}
|
||||
int alpha = color >>> 24;
|
||||
int combined = Math.round((float) alpha * opacity);
|
||||
paint.setColor(combined << 24 | (color & 0x00ffffff));
|
||||
} else {
|
||||
// solid color
|
||||
paint.setARGB(
|
||||
(int) (colors.size() > 4 ? colors.getDouble(4) * opacity * 255 : opacity * 255),
|
||||
(int) (colors.getDouble(1) * 255),
|
||||
(int) (colors.getDouble(2) * 255),
|
||||
(int) (colors.getDouble(3) * 255));
|
||||
}
|
||||
break;
|
||||
// TODO: handle currentColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,8 @@ import com.facebook.react.viewmanagers.RNSVGEllipseManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGEllipseManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeFloodManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeFloodManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeMergeManagerDelegate;
|
||||
@@ -590,6 +592,7 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
RNSVGMask,
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeFlood,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
@@ -641,6 +644,8 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
return new FilterView(reactContext);
|
||||
case RNSVGFeColorMatrix:
|
||||
return new FeColorMatrixView(reactContext);
|
||||
case RNSVGFeFlood:
|
||||
return new FeFloodView(reactContext);
|
||||
case RNSVGFeGaussianBlur:
|
||||
return new FeGaussianBlurView(reactContext);
|
||||
case RNSVGFeMerge:
|
||||
@@ -1605,6 +1610,30 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
|
||||
}
|
||||
}
|
||||
|
||||
static class FeFloodManager extends FilterPrimitiveManager<FeFloodView>
|
||||
implements RNSVGFeFloodManagerInterface<FeFloodView> {
|
||||
FeFloodManager() {
|
||||
super(SVGClass.RNSVGFeFlood);
|
||||
mDelegate = new RNSVGFeFloodManagerDelegate(this);
|
||||
}
|
||||
|
||||
public static final String REACT_CLASS = "RNSVGFeFlood";
|
||||
|
||||
@ReactProp(name = "floodColor")
|
||||
public void setFloodColor(FeFloodView node, @Nullable Dynamic strokeColors) {
|
||||
node.setFloodColor(strokeColors);
|
||||
}
|
||||
|
||||
public void setFloodColor(FeFloodView view, @Nullable ReadableMap value) {
|
||||
view.setFloodColor(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "floodOpacity", defaultFloat = 1f)
|
||||
public void setFloodOpacity(FeFloodView node, float strokeOpacity) {
|
||||
node.setFloodOpacity(strokeOpacity);
|
||||
}
|
||||
}
|
||||
|
||||
static class FeGaussianBlurManager extends FilterPrimitiveManager<FeGaussianBlurView>
|
||||
implements RNSVGFeGaussianBlurManagerInterface<FeGaussianBlurView> {
|
||||
FeGaussianBlurManager() {
|
||||
|
||||
@@ -223,6 +223,15 @@ public class SvgPackage extends TurboReactPackage implements ViewManagerOnDemand
|
||||
return new FeColorMatrixManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
FeFloodManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
new Provider<NativeModule>() {
|
||||
@Override
|
||||
public NativeModule get() {
|
||||
return new FeFloodManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
FeGaussianBlurManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
||||
*
|
||||
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
||||
* once the code is regenerated.
|
||||
*
|
||||
* @generated by codegen project: GeneratePropsJavaDelegate.js
|
||||
*/
|
||||
|
||||
package com.facebook.react.viewmanagers;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.DynamicFromObject;
|
||||
import com.facebook.react.uimanager.BaseViewManagerDelegate;
|
||||
import com.facebook.react.uimanager.BaseViewManagerInterface;
|
||||
|
||||
public class RNSVGFeFloodManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & RNSVGFeFloodManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
|
||||
public RNSVGFeFloodManagerDelegate(U viewManager) {
|
||||
super(viewManager);
|
||||
}
|
||||
@Override
|
||||
public void setProperty(T view, String propName, @Nullable Object value) {
|
||||
switch (propName) {
|
||||
case "x":
|
||||
mViewManager.setX(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "y":
|
||||
mViewManager.setY(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "width":
|
||||
mViewManager.setWidth(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "height":
|
||||
mViewManager.setHeight(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "result":
|
||||
mViewManager.setResult(view, value == null ? null : (String) value);
|
||||
break;
|
||||
case "floodColor":
|
||||
mViewManager.setFloodColor(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "floodOpacity":
|
||||
mViewManager.setFloodOpacity(view, value == null ? 1f : ((Double) value).floatValue());
|
||||
break;
|
||||
default:
|
||||
super.setProperty(view, propName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
||||
*
|
||||
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
||||
* once the code is regenerated.
|
||||
*
|
||||
* @generated by codegen project: GeneratePropsJavaInterface.js
|
||||
*/
|
||||
|
||||
package com.facebook.react.viewmanagers;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
|
||||
public interface RNSVGFeFloodManagerInterface<T extends View> {
|
||||
void setX(T view, Dynamic value);
|
||||
void setY(T view, Dynamic value);
|
||||
void setWidth(T view, Dynamic value);
|
||||
void setHeight(T view, Dynamic value);
|
||||
void setResult(T view, @Nullable String value);
|
||||
void setFloodColor(T view, Dynamic value);
|
||||
void setFloodOpacity(T view, float value);
|
||||
}
|
||||
9
apple/Filters/RNSVGFeFlood.h
Normal file
9
apple/Filters/RNSVGFeFlood.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#import "RNSVGBrush.h"
|
||||
#import "RNSVGFilterPrimitive.h"
|
||||
|
||||
@interface RNSVGFeFlood : RNSVGFilterPrimitive
|
||||
|
||||
@property (nonatomic, strong) RNSVGBrush *floodColor;
|
||||
@property (nonatomic, assign) CGFloat floodOpacity;
|
||||
|
||||
@end
|
||||
91
apple/Filters/RNSVGFeFlood.mm
Normal file
91
apple/Filters/RNSVGFeFlood.mm
Normal file
@@ -0,0 +1,91 @@
|
||||
#import "RNSVGFeFlood.h"
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
#import <React/RCTConversions.h>
|
||||
#import <React/RCTFabricComponentsPlugins.h>
|
||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||
#import <react/renderer/components/view/conversions.h>
|
||||
#import "RNSVGConvert.h"
|
||||
#import "RNSVGFabricConversions.h"
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@implementation RNSVGFeFlood
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
using namespace facebook::react;
|
||||
|
||||
// Needed because of this: https://github.com/facebook/react-native/pull/37274
|
||||
+ (void)load
|
||||
{
|
||||
[super load];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
static const auto defaultProps = std::make_shared<const RNSVGFeFloodProps>();
|
||||
_props = defaultProps;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - RCTComponentViewProtocol
|
||||
|
||||
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||
{
|
||||
return concreteComponentDescriptorProvider<RNSVGFeFloodComponentDescriptor>();
|
||||
}
|
||||
|
||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||
{
|
||||
const auto &newProps = static_cast<const RNSVGFeFloodProps &>(*props);
|
||||
|
||||
id floodColor = RNSVGConvertFollyDynamicToId(newProps.floodColor);
|
||||
if (floodColor != nil) {
|
||||
self.floodColor = [RCTConvert RNSVGBrush:floodColor];
|
||||
}
|
||||
self.floodOpacity = newProps.floodOpacity;
|
||||
|
||||
setCommonFilterProps(newProps, self);
|
||||
_props = std::static_pointer_cast<RNSVGFeFloodProps const>(props);
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
_floodColor = nil;
|
||||
_floodOpacity = 1;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
- (void)setFloodColor:(RNSVGBrush *)floodColor
|
||||
{
|
||||
if (floodColor == _floodColor) {
|
||||
return;
|
||||
}
|
||||
_floodColor = floodColor;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setFloodOpacity:(CGFloat)floodOpacity
|
||||
{
|
||||
if (floodOpacity == _floodOpacity) {
|
||||
return;
|
||||
}
|
||||
_floodOpacity = floodOpacity;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results previousFilterResult:(CIImage *)previous
|
||||
{
|
||||
return [CIImage imageWithColor:[CIColor colorWithCGColor:[self.floodColor getColorWithOpacity:self.floodOpacity]]];
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
Class<RCTComponentViewProtocol> RNSVGFeFloodCls(void)
|
||||
{
|
||||
return RNSVGFeFlood.class;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@end
|
||||
5
apple/ViewManagers/RNSVGFeFloodManager.h
Normal file
5
apple/ViewManagers/RNSVGFeFloodManager.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "RNSVGFilterPrimitiveManager.h"
|
||||
|
||||
@interface RNSVGFeFloodManager : RNSVGFilterPrimitiveManager
|
||||
|
||||
@end
|
||||
16
apple/ViewManagers/RNSVGFeFloodManager.mm
Normal file
16
apple/ViewManagers/RNSVGFeFloodManager.mm
Normal file
@@ -0,0 +1,16 @@
|
||||
#import "RNSVGFeFloodManager.h"
|
||||
#import "RNSVGFeFlood.h"
|
||||
|
||||
@implementation RNSVGFeFloodManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (RNSVGFeFlood *)node
|
||||
{
|
||||
return [RNSVGFeFlood new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(floodColor, RNSVGBrush)
|
||||
RCT_EXPORT_VIEW_PROPERTY(floodOpacity, CGFloat)
|
||||
|
||||
@end
|
||||
141
apps/examples/src/examples/Filters/FeFlood.tsx
Normal file
141
apps/examples/src/examples/Filters/FeFlood.tsx
Normal file
@@ -0,0 +1,141 @@
|
||||
import React, {Component} from 'react';
|
||||
import {
|
||||
Circle,
|
||||
FeFlood,
|
||||
FeMerge,
|
||||
FeMergeNode,
|
||||
Filter,
|
||||
G,
|
||||
Line,
|
||||
Rect,
|
||||
Svg,
|
||||
Use,
|
||||
} from 'react-native-svg';
|
||||
|
||||
class BasicFlood extends Component {
|
||||
static title = 'Basic MDN example with Use';
|
||||
render() {
|
||||
return (
|
||||
<Svg width="200" height="200">
|
||||
<Filter id="floodFilter" filterUnits="userSpaceOnUse">
|
||||
<FeFlood
|
||||
x="50"
|
||||
y="50"
|
||||
width="100"
|
||||
height="100"
|
||||
floodColor="green"
|
||||
floodOpacity="0.5"
|
||||
/>
|
||||
</Filter>
|
||||
<Use href="url(#useless)" filter="url(#floodFilter)" />
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TestCase1 extends Component {
|
||||
static title = 'Custom Test Case 1';
|
||||
render() {
|
||||
return (
|
||||
<Svg width="200" height="200" viewBox="0 0 200 200">
|
||||
<Filter
|
||||
id="floodFilter"
|
||||
// x="50%"
|
||||
filterUnits="userSpaceOnUse"
|
||||
primitiveUnits="userSpaceOnUse">
|
||||
<FeFlood
|
||||
// y="-10%"
|
||||
x="10%"
|
||||
// width="50%"
|
||||
// height="50%"
|
||||
flood-color="red"
|
||||
flood-opacity="0.5"
|
||||
floodColor="yellow"
|
||||
floodOpacity="0.5"
|
||||
/>
|
||||
</Filter>
|
||||
<Rect x="0" y="0" width="100" height="100" fill="blue" />
|
||||
<Circle cx="50" cy="50" r="40" filter="url(#floodFilter)" />
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TestCase2 extends Component {
|
||||
static title = 'Custom Test Case 2';
|
||||
render() {
|
||||
return (
|
||||
<Svg width="200" height="400">
|
||||
<Filter
|
||||
id="flood"
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%"
|
||||
primitiveUnits="objectBoundingBox">
|
||||
<FeFlood
|
||||
x="25%"
|
||||
y="25%"
|
||||
width="50%"
|
||||
height="50%"
|
||||
floodColor="green"
|
||||
floodOpacity="0.75"
|
||||
/>
|
||||
</Filter>
|
||||
<Filter id="merge" primitiveUnits="objectBoundingBox">
|
||||
<FeMerge x="25%" y="25%" width="50%" height="50%">
|
||||
<FeMergeNode in="SourceGraphic" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
|
||||
<G fill="none" stroke="blue" strokeWidth="4">
|
||||
<Rect width="200" height="200" />
|
||||
<Line x2="200" y2="200" />
|
||||
<Line x1="200" y2="200" />
|
||||
</G>
|
||||
<Circle fill="green" filter="url(#flood)" cx="100" cy="100" r="90" />
|
||||
<Rect x="55" y="55" width="90" height="90" />
|
||||
<G transform="translate(0 200)">
|
||||
<G fill="none" stroke="blue" strokeWidth="4">
|
||||
<Rect width="200" height="200" />
|
||||
<Line x2="200" y2="200" />
|
||||
<Line x1="200" y2="200" />
|
||||
</G>
|
||||
<Circle
|
||||
fill="green"
|
||||
fillOpacity="0.5"
|
||||
filter="url(#merge)"
|
||||
cx="100"
|
||||
cy="100"
|
||||
r="90"
|
||||
/>
|
||||
</G>
|
||||
<Rect x="55" y="255" width="90" height="90" fillOpacity=".7" />
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const icon = (
|
||||
<Svg height="30" width="30" viewBox="0 0 140 140">
|
||||
<Filter
|
||||
id="floodFilterIcon"
|
||||
x="50%"
|
||||
filterUnits="userSpaceOnUse"
|
||||
primitiveUnits="userSpaceOnUse">
|
||||
<FeFlood
|
||||
y="-10%"
|
||||
x="10%"
|
||||
width="50%"
|
||||
height="50%"
|
||||
floodColor="yellow"
|
||||
floodOpacity="0.5"
|
||||
/>
|
||||
</Filter>
|
||||
<Rect x="0" y="0" width="100" height="100" fill="blue" />
|
||||
<Circle cx="50" cy="50" r="40" filter="url(#floodFilterIcon)" />
|
||||
</Svg>
|
||||
);
|
||||
|
||||
const samples = [BasicFlood, TestCase1, TestCase2];
|
||||
export {icon, samples};
|
||||
@@ -1,10 +1,12 @@
|
||||
import * as FeColorMatrix from './FeColorMatrix';
|
||||
import * as FeFlood from './FeFlood';
|
||||
import * as FeGaussianBlur from './FeGaussianBlur';
|
||||
import * as FeMerge from './FeMerge';
|
||||
import * as FeOffset from './FeOffset';
|
||||
import * as ReanimatedFeColorMatrix from './ReanimatedFeColorMatrix';
|
||||
export {
|
||||
FeColorMatrix,
|
||||
FeFlood,
|
||||
FeGaussianBlur,
|
||||
FeMerge,
|
||||
FeOffset,
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = {
|
||||
'RNSVGClipPathComponentDescriptor',
|
||||
'RNSVGDefsComponentDescriptor',
|
||||
'RNSVGFeColorMatrixComponentDescriptor',
|
||||
'RNSVGFeFloodComponentDescriptor',
|
||||
'RNSVGFeGaussianBlurComponentDescriptor',
|
||||
'RNSVGFeMergeComponentDescriptor',
|
||||
'RNSVGFeOffsetComponentDescriptor',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ColorValue } from 'react-native';
|
||||
import { ColorValue, NativeMethods } from 'react-native';
|
||||
import RNSVGFeFlood from '../../fabric/FeFloodNativeComponent';
|
||||
import extractFeFlood, { extractFilter } from '../../lib/extract/extractFilter';
|
||||
import { NumberProp } from '../../lib/extract/types';
|
||||
import { warnUnimplementedFilter } from '../../lib/util';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
|
||||
export interface FeFloodProps {
|
||||
@@ -12,12 +13,19 @@ export interface FeFloodProps {
|
||||
export default class FeFlood extends FilterPrimitive<FeFloodProps> {
|
||||
static displayName = 'FeFlood';
|
||||
|
||||
static defaultProps = {
|
||||
static defaultProps: React.ComponentProps<typeof FeFlood> = {
|
||||
...this.defaultPrimitiveProps,
|
||||
floodColor: 'black',
|
||||
floodOpacity: 1,
|
||||
};
|
||||
|
||||
render() {
|
||||
warnUnimplementedFilter();
|
||||
return null;
|
||||
return (
|
||||
<RNSVGFeFlood
|
||||
ref={(ref) => this.refMethod(ref as (FeFlood & NativeMethods) | null)}
|
||||
{...extractFilter(this.props)}
|
||||
{...extractFeFlood(this.props)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
31
src/fabric/FeFloodNativeComponent.ts
Normal file
31
src/fabric/FeFloodNativeComponent.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { ColorValue } from 'react-native';
|
||||
import type {
|
||||
Float,
|
||||
Int32,
|
||||
WithDefault,
|
||||
} from 'react-native/Libraries/Types/CodegenTypes';
|
||||
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
||||
import type { NumberProp } from '../lib/extract/types';
|
||||
import type { UnsafeMixed } from './codegenUtils';
|
||||
import type { ViewProps } from './utils';
|
||||
|
||||
interface FilterPrimitiveCommonProps {
|
||||
x?: UnsafeMixed<NumberProp>;
|
||||
y?: UnsafeMixed<NumberProp>;
|
||||
width?: UnsafeMixed<NumberProp>;
|
||||
height?: UnsafeMixed<NumberProp>;
|
||||
result?: string;
|
||||
}
|
||||
|
||||
type ColorStruct = Readonly<{
|
||||
type?: WithDefault<Int32, -1>;
|
||||
payload?: ColorValue;
|
||||
brushRef?: string;
|
||||
}>;
|
||||
|
||||
export interface NativeProps extends ViewProps, FilterPrimitiveCommonProps {
|
||||
floodColor?: UnsafeMixed<ColorValue | ColorStruct>;
|
||||
floodOpacity?: WithDefault<Float, 1.0>;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<NativeProps>('RNSVGFeFlood');
|
||||
@@ -22,6 +22,7 @@ import RNSVGTSpan from './TSpanNativeComponent';
|
||||
import RNSVGUse from './UseNativeComponent';
|
||||
import RNSVGFilter from './FilterNativeComponent';
|
||||
import RNSVGFeColorMatrix from './FeColorMatrixNativeComponent';
|
||||
import RNSVGFeFlood from './FeFloodNativeComponent';
|
||||
import RNSVGFeGaussianBlur from './FeGaussianBlurNativeComponent';
|
||||
import RNSVGFeMerge from './FeMergeNativeComponent';
|
||||
import RNSVGFeOffset from './FeOffsetNativeComponent';
|
||||
@@ -51,6 +52,7 @@ export {
|
||||
RNSVGUse,
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeFlood,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import React from 'react';
|
||||
import { ColorValue, processColor } from 'react-native';
|
||||
import { FeColorMatrixProps as FeColorMatrixComponentProps } from '../../elements/filters/FeColorMatrix';
|
||||
import { FeFloodProps as FeFloodComponentProps } from '../../elements/filters/FeFlood';
|
||||
import { FeGaussianBlurProps as FeGaussianBlurComponentProps } from '../../elements/filters/FeGaussianBlur';
|
||||
import { FeMergeProps as FeMergeComponentProps } from '../../elements/filters/FeMerge';
|
||||
import { NativeProps as FeColorMatrixNativeProps } from '../../fabric/FeColorMatrixNativeComponent';
|
||||
import { NativeProps as FeFloodNativeProps } from '../../fabric/FeFloodNativeComponent';
|
||||
import { NativeProps as FeGaussianBlurNativeProps } from '../../fabric/FeGaussianBlurNativeComponent';
|
||||
import { NativeProps as FeMergeNativeProps } from '../../fabric/FeMergeNativeComponent';
|
||||
import extractBrush from './extractBrush';
|
||||
import extractOpacity from './extractOpacity';
|
||||
import { NumberProp } from './types';
|
||||
|
||||
const spaceReg = /\s+/;
|
||||
@@ -67,6 +72,28 @@ export const extractFeColorMatrix = (
|
||||
return extracted;
|
||||
};
|
||||
|
||||
const defaultFill = { type: 0, payload: processColor('black') as ColorValue };
|
||||
export default function extractFeFlood(
|
||||
props: FeFloodComponentProps
|
||||
): FeFloodNativeProps {
|
||||
const extracted: FeFloodNativeProps = {};
|
||||
const { floodColor, floodOpacity } = props;
|
||||
|
||||
if (floodColor != null) {
|
||||
extracted.floodColor =
|
||||
!floodColor && typeof floodColor !== 'number'
|
||||
? defaultFill
|
||||
: (extractBrush(floodColor) as unknown as string);
|
||||
} else {
|
||||
// we want the default value of fill to be black to match the spec
|
||||
extracted.floodColor = defaultFill;
|
||||
}
|
||||
if (floodOpacity != null) {
|
||||
extracted.floodOpacity = extractOpacity(floodOpacity);
|
||||
}
|
||||
return extracted;
|
||||
}
|
||||
|
||||
export const extractFeGaussianBlur = (
|
||||
props: FeGaussianBlurComponentProps
|
||||
): FeGaussianBlurNativeProps => {
|
||||
|
||||
Reference in New Issue
Block a user