diff --git a/Example/examples/Clipping.js b/Example/examples/Clipping.js
index 23f41579..47eebae2 100644
--- a/Example/examples/Clipping.js
+++ b/Example/examples/Clipping.js
@@ -213,7 +213,7 @@ const icon = ;
-const samples = [ClipPathAttr, ClipRule];//, ClipPathElement, TextClipping
+const samples = [ClipPathAttr, ClipRule, ClipPathElement, TextClipping];
export {
icon,
diff --git a/README.md b/README.md
index b057d450..8bf8dfde 100644
--- a/README.md
+++ b/README.md
@@ -564,7 +564,7 @@ npm install
6. more Text features support
7. Pattern element
8. Image element
-
+9. calculate bounding box only if necessary.
#### Thanks:
diff --git a/elements/ClipPath.js b/elements/ClipPath.js
index cb9644e7..240afd6f 100644
--- a/elements/ClipPath.js
+++ b/elements/ClipPath.js
@@ -28,26 +28,13 @@ class ClipPath extends Component{
remove(this.id);
};
- _combinePaths = children => {
- // TODO: combine g elements and their children
- // TODO: combine text elements
- Children.forEach(children, child => {
- let {props, type: {getPath}} = child;
-
- if (getPath) {
- this._path += getPath(props);
- }
-
- this._combinePaths(props.children);
- });
- };
-
- _path = '';
-
render() {
- this._combinePaths(this.props.children);
- set(this.id, this._path);
- return ;
+ set(this.id, this.id);
+
+ return {this.props.children};
}
}
diff --git a/elements/Defs.js b/elements/Defs.js
index e8699205..15e45afb 100644
--- a/elements/Defs.js
+++ b/elements/Defs.js
@@ -80,11 +80,16 @@ class Defs extends Component{
static Item = DefsItem;
static Use = DefsUse;
+ shouldRender = false;
getChildren = () => {
return Children.map(this.props.children, child => {
let {type} = child;
if (type === LinearGradient || type === RadialGradient || type === ClipPath) {
+ if (type === ClipPath) {
+ this.shouldRender = true;
+ }
+
return cloneElement(child, {
svgId: this.props.svgId
});
@@ -99,8 +104,9 @@ class Defs extends Component{
};
render() {
- return
- {this.getChildren()}
+ let children = this.getChildren();
+ return
+ {children}
;
}
}
diff --git a/elements/G.js b/elements/G.js
index b08eeb91..7cdcd7ff 100644
--- a/elements/G.js
+++ b/elements/G.js
@@ -47,6 +47,7 @@ class G extends Component{
} else {
return
{this.props.children}
;
diff --git a/elements/Shape.js b/elements/Shape.js
index 741bcbf9..15b77e4f 100644
--- a/elements/Shape.js
+++ b/elements/Shape.js
@@ -58,7 +58,7 @@ class Shape extends Component{
let shape = new SerializableShape(props, COORD_PROPS[this.type]).toJSON();
- return
{props.children}
diff --git a/elements/ViewBox.js b/elements/ViewBox.js
index 9ebc55d2..8fb69a75 100644
--- a/elements/ViewBox.js
+++ b/elements/ViewBox.js
@@ -7,12 +7,7 @@ import G from './G';
import extractViewbox from '../lib/extract/extractViewbox';
class ViewBox extends Component{
static displayName = 'ViewBox';
- static propType = {
- shouldTransform: PropTypes.bool
- };
- static defaultProps = {
- shouldTransform: false
- };
+
render() {
let viewbox = extractViewbox(this.props);
let scaleX = 1;
diff --git a/ios/RNSVGGroup.h b/ios/RNSVGGroup.h
index f55512e7..3a0828e2 100644
--- a/ios/RNSVGGroup.h
+++ b/ios/RNSVGGroup.h
@@ -13,8 +13,7 @@
#import "RNSVGCGFCRule.h"
@interface RNSVGGroup : RNSVGNode
+@property (nonatomic, strong) NSString *asClipPath; // Current group is a element and asClipPath is its id.
-@property (nonatomic, assign) CGPathRef clipPath;
-@property (nonatomic, assign) RNSVGCGFCRule clipRule;
@end
diff --git a/ios/RNSVGGroup.m b/ios/RNSVGGroup.m
index 41190747..1c7701aa 100644
--- a/ios/RNSVGGroup.m
+++ b/ios/RNSVGGroup.m
@@ -12,10 +12,24 @@
- (void)renderLayerTo:(CGContextRef)context
{
- [self clip:context];
- for (RNSVGNode *node in self.subviews) {
- [node renderTo:context];
+ if (self.asClipPath == NULL) {
+ [self clip:context];
+ for (RNSVGNode *node in self.subviews) {
+ [node renderTo:context];
+ }
+ } else {
+ [self defineClipPath:[self getPath:context] clipPathId:self.asClipPath];
}
}
+- (CGPathRef)getPath:(CGContextRef)context
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+ for (RNSVGNode *node in self.subviews) {
+ CGPathAddPath(path, nil, [node getPath:context]);
+ }
+
+ return path;
+}
+
@end
diff --git a/ios/RNSVGNode.h b/ios/RNSVGNode.h
index 40c64830..db6e0572 100644
--- a/ios/RNSVGNode.h
+++ b/ios/RNSVGNode.h
@@ -20,8 +20,9 @@
@property (nonatomic, assign) CGRect rect;
@property (nonatomic, assign) CGFloat opacity;
-@property (nonatomic, assign) CGPathRef clipPath;
@property (nonatomic, assign) RNSVGCGFCRule clipRule;
+@property (nonatomic, assign) CGPathRef clipPath; // convert clipPath="M0,0 L0,10 L10,10z" into path
+@property (nonatomic, strong) NSString *clipPathId; // use clipPath="url(#clip)" as ClipPath
- (void)invalidate;
- (void)renderTo:(CGContextRef)context;
@@ -33,6 +34,19 @@
*/
- (void)renderLayerTo:(CGContextRef)context;
+/**
+ * clip node by clipPath or clipPathId.
+ */
- (void)clip:(CGContextRef)context;
+/**
+ * define content as clipPath template.
+ */
+- (void)defineClipPath:(CGPathRef)clipPath clipPathId:(NSString *)clipPathId;
+
+/**
+ * getPath will return the path inside node as a ClipPath.
+ */
+- (CGPathRef)getPath: (CGContextRef) context;
+
@end
diff --git a/ios/RNSVGNode.m b/ios/RNSVGNode.m
index 533c601c..9a88d042 100644
--- a/ios/RNSVGNode.m
+++ b/ios/RNSVGNode.m
@@ -10,6 +10,8 @@
#import "RNSVGContainer.h"
+static NSMutableDictionary *ClipPaths;
+
@implementation RNSVGNode
- (void)insertSubview:(UIView *)subview atIndex:(NSInteger)index
@@ -71,6 +73,17 @@
}
- (void)setClipPath:(CGPathRef)clipPath
+{
+ if (_clipPath == clipPath) {
+ return;
+ }
+ [self invalidate];
+ CGPathRelease(_clipPath);
+ _clipPath = CGPathRetain(clipPath);
+}
+
+
+-(void)defineClipPath:(CGPathRef)clipPath clipPathId:(NSString *)clipPathId
{
if (clipPath == _clipPath) {
return;
@@ -78,6 +91,11 @@
[self invalidate];
CGPathRelease(_clipPath);
_clipPath = CGPathRetain(clipPath);
+ if (ClipPaths == NULL) {
+ ClipPaths = [[NSMutableDictionary alloc] init];
+ }
+
+ [ClipPaths setValue:[NSValue valueWithPointer:_clipPath] forKey:clipPathId];
}
- (void)dealloc
@@ -91,15 +109,29 @@
// abstract
}
+- (CGPathRef)getPath: (CGContextRef) context
+{
+ // abstract
+ return CGPathCreateMutable();
+}
+
- (void)clip:(CGContextRef)context
{
+ CGPathRef clipPath = nil;
+
if (self.clipPath) {
- CGContextAddPath(context, self.clipPath);
- if (self.clipRule == kRNSVGCGFCRuleEvenodd) {
- CGContextEOClip(context);
- } else {
- CGContextClip(context);
- }
+ clipPath = self.clipPath;
+ } else if (self.clipPathId) {
+ clipPath = [[ClipPaths valueForKey:self.clipPathId] pointerValue];
+ } else {
+ return;
+ }
+
+ CGContextAddPath(context, clipPath);
+ if (self.clipRule == kRNSVGCGFCRuleEvenodd) {
+ CGContextEOClip(context);
+ } else {
+ CGContextClip(context);
}
}
diff --git a/ios/RNSVGPath.m b/ios/RNSVGPath.m
index e928f639..dd88a55c 100644
--- a/ios/RNSVGPath.m
+++ b/ios/RNSVGPath.m
@@ -39,9 +39,7 @@
fillColor = [self.fill applyFillColor:context];
if (!fillColor) {
- if (self.clipPath) {
- [self clip:context];
- }
+ [self clip:context];
CGContextSaveGState(context);
CGContextAddPath(context, self.d);
@@ -97,4 +95,9 @@
CGContextDrawPath(context, mode);
}
+- (CGPathRef)getPath:(CGContextRef)context
+{
+ return self.d;
+}
+
@end
diff --git a/ios/RNSVGShape.m b/ios/RNSVGShape.m
index 6137d2e6..25f673e4 100644
--- a/ios/RNSVGShape.m
+++ b/ios/RNSVGShape.m
@@ -11,13 +11,15 @@
@implementation RNSVGShape
-- (void)dealloc
-{
-
-}
-
- (void)renderLayerTo:(CGContextRef)context
{
+ self.d = [self getPath: context];
+ [super renderLayerTo:context];
+}
+
+- (CGPathRef)getPath:(CGContextRef)context
+{
+
int type = [[self.shape objectForKey:@"type"] intValue];
CGRect box = CGContextGetClipBoundingBox(context);
CGMutablePathRef path = CGPathCreateMutable();
@@ -39,7 +41,7 @@
CGFloat value = [[prop objectForKey:@"value"] floatValue];
if ([[prop objectForKey:@"percentage"] integerValue] == 1) {
r = sqrt(pow((width * value), 2) + pow((height * value), 2)) / sqrt(2);
-
+
} else {
r = value;
}
@@ -104,13 +106,9 @@
RCTLogError(@"Invalid Shape type %d at %@", type, self.shape);
//CGPathRelease(path);
-
}
- self.d = path;
- [super renderLayerTo:context];
- //NSLog(@"%@", NSStringFromCGRect(box));
- //NSLog(@"%@", self.shape);
+ return path;
}
- (CGFloat)getActualProp:(NSString *)name relative:(float)relative
diff --git a/ios/ViewManagers/RNSVGGroupManager.m b/ios/ViewManagers/RNSVGGroupManager.m
index fa2daa31..a2744c8a 100644
--- a/ios/ViewManagers/RNSVGGroupManager.m
+++ b/ios/ViewManagers/RNSVGGroupManager.m
@@ -22,5 +22,6 @@ RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath)
RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule)
+RCT_EXPORT_VIEW_PROPERTY(asClipPath, NSString)
@end
diff --git a/ios/ViewManagers/RNSVGNodeManager.m b/ios/ViewManagers/RNSVGNodeManager.m
index 0333bf6f..08ec88a8 100644
--- a/ios/ViewManagers/RNSVGNodeManager.m
+++ b/ios/ViewManagers/RNSVGNodeManager.m
@@ -31,5 +31,6 @@ RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(transform, CGAffineTransform)
+RCT_EXPORT_VIEW_PROPERTY(clipPathId, NSString)
@end
diff --git a/lib/attributes.js b/lib/attributes.js
index cc4623e2..dfcde8a2 100644
--- a/lib/attributes.js
+++ b/lib/attributes.js
@@ -63,10 +63,12 @@ const NodeAttributes = {
clipPath: {
diff: arrayDiffer
},
+ clipPathId: true,
clipRule: true
};
const GroupAttributes = {
+ asClipPath: true,
...NodeAttributes
};
diff --git a/lib/extract/extractClipping.js b/lib/extract/extractClipping.js
index db0dc3f8..45245a41 100644
--- a/lib/extract/extractClipping.js
+++ b/lib/extract/extractClipping.js
@@ -29,9 +29,9 @@ export default function (props) {
let patternName = `${matched[1]}:${props.svgId}`;
let pattern = clipPatterns[patternName];
if (pattern) {
- clippingProps.clipPath = new SerializablePath(pattern).toJSON();
+ clippingProps.clipPathId = pattern;
} else {
- clippingProps = {};
+ clippingProps = null;
// TODO: warn
}
} else {