mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-05-28 21:03:51 +00:00
Implement support for Use element inside ClipPath
```jsx
import React from 'react';
import { View } from 'react-native';
import Svg, {
Defs,
ClipPath,
Path,
Rect,
G,
Text,
Polygon,
Use,
} from 'react-native-svg';
const SvgComponent = props => (
<Svg width="100%" height="30%" viewBox="0 0 140 110" {...props}>
<Defs>
<Path
id="prefix__a"
d="M25 10a20 20 0 1 0 0 40 20 20 1 1 0 0-40m20 0a20 20 0 1 0 0 40 20 20 1 1 0 0-40"
/>
<ClipPath id="prefix__b" clipRule="nonzero">
<Use xlinkHref="#prefix__a" clipRule="nonzero" />
</ClipPath>
<ClipPath id="prefix__c" clipRule="evenodd">
<Path
id="prefix__a"
y={50}
d="M25 10a20 20 0 1 0 0 40 20 20 1 1 0 0-40m20 0a20 20 0 1 0 0 40 20 20 1 1 0 0-40"
/>
</ClipPath>
<ClipPath id="prefix__d" clipRule="evenodd">
<Use xlinkHref="#prefix__a" clipRule="evenodd" y={50} />
</ClipPath>
</Defs>
<Path clipPath="url(#prefix__b)" fill="#6495ed" d="M0 5h70v50H0z" />
<Text x={15} y={54} fontSize={5} fill="#fff">
{'non-zero clip-rule'}
</Text>
<Use xlinkHref="#prefix__a" x={70} stroke="#6495ed" />
<Text x={86} y={54} fontSize={5} fill="#fff">
{'non-zero fill-rule'}
</Text>
<G>
<Path clipPath="url(#prefix__d)" fill="#daa520" d="M0 55h70v50H0z" />
<Text x={14} y={105} fontSize={5} fill="#fff">
{'even-odd clip-rule'}
</Text>
</G>
<G>
<Use
fillRule="evenodd"
xlinkHref="#prefix__a"
x={70}
y={50}
stroke="#daa520"
/>
<Text x={85} y={105} fontSize={5} fill="#fff">
{'even-odd fill-rule'}
</Text>
</G>
</Svg>
);
const SvgComponent2 = props => (
<Svg height="90" width="100" viewBox="0 0 100 90">
<Defs>
<Path d="M50,0 21,90 98,35 2,35 79,90z" id="star" fill="white" />
<ClipPath id="emptyStar" clipRule="evenodd">
<Use href="#star" clipRule="evenodd" />
</ClipPath>
<ClipPath id="filledStar" clipRule="nonzero">
<Use href="#star" clipRule="nonzero" />
</ClipPath>
</Defs>
<Rect clipPath="url(#emptyStar)" width="50" height="90" fill="blue" />
<Rect
clipPath="url(#filledStar)"
width="50"
height="90"
x="50"
fill="red"
/>
</Svg>
);
const SvgComponent3 = ({ clipRule = 'nonzero' }) => (
<Svg width="50%" height="500">
<Defs>
<ClipPath id="windowClip" clipRule={clipRule}>
<G>
<Rect x={30} y={50} height={100} width={100} />
<Text x={30} y={70} fontSize={40}>
Hello world
</Text>
<Rect x={30} y={200} height={100} width={100} />
<Rect x={100} y={250} height={100} width={100} />
<Rect x={30} y={370} height={100} width={100} />
<Polygon
transform="translate(70,400)"
points="0,0 0,100 100,120 120,0"
/>
</G>
</ClipPath>
</Defs>
<Rect height="100%" width="100%" fill="#0af" clipPath="url(#windowClip)" />
</Svg>
);
export default class App extends React.Component {
render() {
return (
<View
style={{
flex: 1,
alignContent: 'center',
justifyContent: 'center',
backgroundColor: '#ecf0f1',
}}
>
<SvgComponent />
<SvgComponent2 />
<View
style={{
flex: 1,
flexDirection: 'row',
}}
>
<SvgComponent3 />
<SvgComponent3 clipRule="evenodd" />
</View>
</View>
);
}
}
```
This commit is contained in:
@@ -11,6 +11,7 @@ package com.horcrux.svg;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
|
||||
@@ -66,31 +67,32 @@ class UseView extends RenderableView {
|
||||
void draw(Canvas canvas, Paint paint, float opacity) {
|
||||
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
||||
|
||||
if (template != null) {
|
||||
canvas.translate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
|
||||
if (template instanceof RenderableView) {
|
||||
((RenderableView)template).mergeProperties(this);
|
||||
}
|
||||
|
||||
int count = template.saveAndSetupCanvas(canvas);
|
||||
clip(canvas, paint);
|
||||
|
||||
if (template instanceof SymbolView) {
|
||||
SymbolView symbol = (SymbolView)template;
|
||||
symbol.drawSymbol(canvas, paint, opacity, (float) relativeOnWidth(mW), (float) relativeOnHeight(mH));
|
||||
} else {
|
||||
template.draw(canvas, paint, opacity * mOpacity);
|
||||
}
|
||||
|
||||
this.setClientRect(template.getClientRect());
|
||||
|
||||
template.restoreCanvas(canvas, count);
|
||||
if (template instanceof RenderableView) {
|
||||
((RenderableView)template).resetProperties();
|
||||
}
|
||||
} else {
|
||||
if (template == null) {
|
||||
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
|
||||
"template named: " + mHref + " is not defined.");
|
||||
"template named: " + mHref + " is not defined.");
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.translate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
|
||||
if (template instanceof RenderableView) {
|
||||
((RenderableView)template).mergeProperties(this);
|
||||
}
|
||||
|
||||
int count = template.saveAndSetupCanvas(canvas);
|
||||
clip(canvas, paint);
|
||||
|
||||
if (template instanceof SymbolView) {
|
||||
SymbolView symbol = (SymbolView)template;
|
||||
symbol.drawSymbol(canvas, paint, opacity, (float) relativeOnWidth(mW), (float) relativeOnHeight(mH));
|
||||
} else {
|
||||
template.draw(canvas, paint, opacity * mOpacity);
|
||||
}
|
||||
|
||||
this.setClientRect(template.getClientRect());
|
||||
|
||||
template.restoreCanvas(canvas, count);
|
||||
if (template instanceof RenderableView) {
|
||||
((RenderableView)template).resetProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +107,12 @@ class UseView extends RenderableView {
|
||||
mInvTransform.mapPoints(dst);
|
||||
|
||||
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
||||
if (template == null) {
|
||||
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
|
||||
"template named: " + mHref + " is not defined.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hitChild = template.hitTest(dst);
|
||||
if (hitChild != -1) {
|
||||
return (template.isResponsible() || hitChild != template.getId()) ? hitChild : getId();
|
||||
@@ -115,7 +123,17 @@ class UseView extends RenderableView {
|
||||
|
||||
@Override
|
||||
Path getPath(Canvas canvas, Paint paint) {
|
||||
// todo:
|
||||
return new Path();
|
||||
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
||||
if (template == null) {
|
||||
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
|
||||
"template named: " + mHref + " is not defined.");
|
||||
return null;
|
||||
}
|
||||
Path path = template.getPath(canvas, paint);
|
||||
Path use = new Path();
|
||||
Matrix m = new Matrix();
|
||||
m.setTranslate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
|
||||
path.transform(m, use);
|
||||
return use;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,9 @@
|
||||
} else if (self.href) {
|
||||
// TODO: calling yellow box here
|
||||
RCTLogWarn(@"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.", self.href);
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
CGRect bounds = template.clientRect;
|
||||
self.clientRect = bounds;
|
||||
@@ -120,5 +123,16 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGPathRef)getPath: (CGContextRef)context
|
||||
{
|
||||
CGAffineTransform transform = CGAffineTransformMakeTranslation([self relativeOnWidth:self.x], [self relativeOnHeight:self.y]);
|
||||
RNSVGNode const* template = [self.svgView getDefinedTemplate:self.href];
|
||||
if (!template) {
|
||||
return nil;
|
||||
}
|
||||
CGPathRef path = [template getPath:context];
|
||||
return CGPathCreateCopyByTransformingPath(path, &transform);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user