Skip to content

Commit

Permalink
Implement support for Use element inside ClipPath
Browse files Browse the repository at this point in the history
```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>
    );
  }
}
```
  • Loading branch information
msand committed Apr 1, 2019
1 parent 134cbad commit 76b8b82
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 23 deletions.
64 changes: 41 additions & 23 deletions android/src/main/java/com/horcrux/svg/UseView.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;

Expand Down Expand Up @@ -66,31 +67,32 @@ public void setHeight(Dynamic height) {
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 == null) {
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
"template named: " + mHref + " is not defined.");
return;
}

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);
}
canvas.translate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
if (template instanceof RenderableView) {
((RenderableView)template).mergeProperties(this);
}

this.setClientRect(template.getClientRect());
int count = template.saveAndSetupCanvas(canvas);
clip(canvas, paint);

template.restoreCanvas(canvas, count);
if (template instanceof RenderableView) {
((RenderableView)template).resetProperties();
}
if (template instanceof SymbolView) {
SymbolView symbol = (SymbolView)template;
symbol.drawSymbol(canvas, paint, opacity, (float) relativeOnWidth(mW), (float) relativeOnHeight(mH));
} else {
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
"template named: " + mHref + " is not defined.");
template.draw(canvas, paint, opacity * mOpacity);
}

this.setClientRect(template.getClientRect());

template.restoreCanvas(canvas, count);
if (template instanceof RenderableView) {
((RenderableView)template).resetProperties();
}
}

Expand All @@ -105,6 +107,12 @@ int hitTest(float[] src) {
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();
Expand All @@ -115,7 +123,17 @@ int hitTest(float[] src) {

@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;
}
}
14 changes: 14 additions & 0 deletions ios/Elements/RNSVGUse.m
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ - (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
} 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;
Expand Down Expand Up @@ -120,5 +123,16 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
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

0 comments on commit 76b8b82

Please sign in to comment.