mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-20 05:55:10 +00:00
complete ClipPath refactor
This commit is contained in:
@@ -7,7 +7,9 @@ import Svg, {
|
||||
G,
|
||||
Path,
|
||||
Use,
|
||||
Rect
|
||||
Rect,
|
||||
Circle,
|
||||
ClipPath
|
||||
} from 'react-native-svg';
|
||||
|
||||
class DefsExample extends Component{
|
||||
@@ -19,12 +21,16 @@ class DefsExample extends Component{
|
||||
width="100"
|
||||
>
|
||||
<Defs>
|
||||
<G id="path" x="5" y="2">
|
||||
<G id="path" x="5" y="2" opacity="0.9">
|
||||
<Path id="test" fill='red' d="M38.459,1.66A0.884,0.884,0,0,1,39,2.5a0.7,0.7,0,0,1-.3.575L23.235,16.092,27.58,26.1a1.4,1.4,0,0,1,.148.3,1.3,1.3,0,0,1,0,.377,1.266,1.266,0,0,1-2.078.991L15.526,20.6l-7.58,4.35a1.255,1.255,0,0,1-.485,0,1.267,1.267,0,0,1-1.277-1.258q0-.01,0-0.02a1.429,1.429,0,0,1,0-.446C7.243,20.253,8.6,16.369,8.6,16.29L3.433,13.545A0.743,0.743,0,0,1,2.9,12.822a0.822,0.822,0,0,1,.623-0.773l8.164-2.972,3.018-8.5A0.822,0.822,0,0,1,15.427,0a0.752,0.752,0,0,1,.752.555l2.563,6.936S37.65,1.727,37.792,1.685A1.15,1.15,0,0,1,38.459,1.66Z"/>
|
||||
</G>
|
||||
<ClipPath id="clip">
|
||||
<Circle r="20%" cx="0" cy="0" />
|
||||
</ClipPath>
|
||||
</Defs>
|
||||
<Use href="url(#path)" x="0" fill="blue" />
|
||||
<Use href="url(#path)" x="10" fill="#3a8" />
|
||||
<Use href="url(#path)" x="0" fill="blue" opacity="0.5" />
|
||||
<Use href="url(#path)" x="20" y="5" fill="#8a3" />
|
||||
<Use href="url(#path)" x="30" clipPath="url(#clip)" />
|
||||
</Svg>;
|
||||
}
|
||||
}
|
||||
@@ -34,11 +40,11 @@ const icon = <Svg
|
||||
width="20"
|
||||
>
|
||||
<Defs>
|
||||
<G id="path">
|
||||
<G id="path" scale="0.5">
|
||||
<Path fill='red' d="M38.459,1.66A0.884,0.884,0,0,1,39,2.5a0.7,0.7,0,0,1-.3.575L23.235,16.092,27.58,26.1a1.4,1.4,0,0,1,.148.3,1.3,1.3,0,0,1,0,.377,1.266,1.266,0,0,1-2.078.991L15.526,20.6l-7.58,4.35a1.255,1.255,0,0,1-.485,0,1.267,1.267,0,0,1-1.277-1.258q0-.01,0-0.02a1.429,1.429,0,0,1,0-.446C7.243,20.253,8.6,16.369,8.6,16.29L3.433,13.545A0.743,0.743,0,0,1,2.9,12.822a0.822,0.822,0,0,1,.623-0.773l8.164-2.972,3.018-8.5A0.822,0.822,0,0,1,15.427,0a0.752,0.752,0,0,1,.752.555l2.563,6.936S37.65,1.727,37.792,1.685A1.15,1.15,0,0,1,38.459,1.66Z"/>
|
||||
</G>
|
||||
</Defs>
|
||||
<Use href="url(#path)" x="10" fill="#3a8" />
|
||||
<Use href="url(#path)" fill="#3a8" />
|
||||
</Svg>;
|
||||
|
||||
|
||||
|
||||
@@ -7,15 +7,16 @@ import {circleProps, pathProps, fillProps, strokeProps, numberProp} from '../lib
|
||||
|
||||
class Circle extends Shape {
|
||||
static displayName = 'Circle';
|
||||
|
||||
static propTypes = {
|
||||
...pathProps,
|
||||
...circleProps
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
...fillProps,
|
||||
...strokeProps,
|
||||
...circleProps
|
||||
static defaultProps = {
|
||||
cx: 0,
|
||||
cy: 0,
|
||||
r: 0
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import {set, remove} from '../lib/extract/extractClipping';
|
||||
import createReactNativeComponentClass from 'react/lib/createReactNativeComponentClass';
|
||||
import {ClipPathAttributes} from '../lib/attributes';
|
||||
|
||||
@@ -9,26 +8,9 @@ class ClipPath extends Component{
|
||||
id: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.id = this.props.id + ':' + this.props.svgId;
|
||||
}
|
||||
|
||||
componentWillReceiveProps = nextProps => {
|
||||
let id = nextProps.id + ':' + nextProps.svgId;
|
||||
if (id !== this.id) {
|
||||
remove(this.id);
|
||||
}
|
||||
};
|
||||
|
||||
componentWillUnmount = () => {
|
||||
remove(this.id);
|
||||
};
|
||||
|
||||
render() {
|
||||
set(this.id, this.id);
|
||||
return <RNSVGClipPath
|
||||
name={this.id}
|
||||
name={this.props.id}
|
||||
>{this.props.children}</RNSVGClipPath>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,17 @@ import {EllipseAttributes} from '../lib/attributes';
|
||||
|
||||
class Ellipse extends Shape{
|
||||
static displayName = 'Ellipse';
|
||||
|
||||
static propTypes = {
|
||||
...pathProps,
|
||||
...ellipseProps
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
...fillProps,
|
||||
...strokeProps,
|
||||
...ellipseProps
|
||||
static defaultProps = {
|
||||
cx: 0,
|
||||
cy: 0,
|
||||
rx: 0,
|
||||
ry: 0
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
|
||||
@@ -1,31 +1,14 @@
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import _ from 'lodash';
|
||||
import createReactNativeComponentClass from 'react/lib/createReactNativeComponentClass';
|
||||
import {numberProp, contextProps} from '../lib/props';
|
||||
import {transformProps} from '../lib/props';
|
||||
import {GroupAttributes} from '../lib/attributes';
|
||||
import extractProps from '../lib/extract/extractProps';
|
||||
|
||||
class G extends Component{
|
||||
static displayName = 'G';
|
||||
|
||||
static contextTypes = {
|
||||
...contextProps
|
||||
};
|
||||
|
||||
static childContextTypes = {
|
||||
...contextProps
|
||||
};
|
||||
|
||||
getChildContext = () => {
|
||||
let context = _.reduce(contextProps, (props, value, key) => {
|
||||
if (!_.isNil(this.props[key])) {
|
||||
props[key] = this.props[key];
|
||||
}
|
||||
return props;
|
||||
}, {});
|
||||
|
||||
return _.defaults({}, this.context, context);
|
||||
};
|
||||
static propTypes = transformProps;
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
this.root.setNativeProps(...args);
|
||||
|
||||
@@ -11,14 +11,21 @@ class Image extends Shape {
|
||||
static propTypes = {
|
||||
x: numberProp,
|
||||
y: numberProp,
|
||||
width: numberProp,
|
||||
height: numberProp,
|
||||
width: numberProp.isRequired,
|
||||
height: numberProp.isRequired,
|
||||
href: PropTypes.number.isRequired,
|
||||
...responderProps,
|
||||
...touchableProps
|
||||
//preserveAspectRatio: PropTypes.string
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
this.root.setNativeProps(...args);
|
||||
};
|
||||
|
||||
@@ -7,15 +7,17 @@ import {lineProps, pathProps, fillProps, strokeProps, numberProp} from '../lib/p
|
||||
|
||||
class Line extends Shape {
|
||||
static displayName = 'Line';
|
||||
|
||||
static propTypes = {
|
||||
...pathProps,
|
||||
...lineProps
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
...fillProps,
|
||||
...strokeProps,
|
||||
...lineProps
|
||||
static defaultProps = {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 0,
|
||||
y2: 0
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
|
||||
@@ -10,23 +10,10 @@ class Path extends Shape {
|
||||
static displayName = 'Path';
|
||||
|
||||
static propTypes = {
|
||||
d: PropTypes.string,
|
||||
d: PropTypes.string.isRequired,
|
||||
...pathProps
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
...pathProps
|
||||
};
|
||||
|
||||
|
||||
_dimensions = null;
|
||||
|
||||
componentWillReceiveProps = nextProps => {
|
||||
if (nextProps.d !== this.props.d) {
|
||||
this._dimensions = null;
|
||||
}
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
this.root.setNativeProps(...args);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import Path from './Path';
|
||||
import {pathProps} from '../lib/props';
|
||||
import _ from 'lodash';
|
||||
|
||||
class Polygon extends Component{
|
||||
static displayName = 'Polygon';
|
||||
static propTypes = {
|
||||
...pathProps,
|
||||
points: PropTypes.oneOfType([PropTypes.string, PropTypes.array])
|
||||
points: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
points: ''
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
@@ -14,10 +19,15 @@ class Polygon extends Component{
|
||||
};
|
||||
|
||||
render() {
|
||||
let points = this.props.points;
|
||||
if (_.isArray(points)) {
|
||||
points = points.join(',');
|
||||
}
|
||||
|
||||
return <Path
|
||||
ref={ele => this.root = ele}
|
||||
{...this.props}
|
||||
d={`M${this.props.points.trim().replace(/\s+/g, 'L')}z`}
|
||||
d={`M${points.trim().replace(/\s+/g, 'L')}z`}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import Path from './Path';
|
||||
import {pathProps} from '../lib/props';
|
||||
import _ from 'lodash';
|
||||
|
||||
class Polyline extends Component{
|
||||
static displayName = 'Polyline';
|
||||
static propTypes = {
|
||||
...pathProps,
|
||||
points: PropTypes.oneOfType([PropTypes.string, PropTypes.array])
|
||||
points: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
points: ''
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
@@ -14,10 +19,15 @@ class Polyline extends Component{
|
||||
};
|
||||
|
||||
render() {
|
||||
let points = this.props.points;
|
||||
if (_.isArray(points)) {
|
||||
points = points.join(',');
|
||||
}
|
||||
|
||||
return <Path
|
||||
ref={ele => this.root = ele}
|
||||
{...this.props}
|
||||
d={`M${this.props.points.trim().replace(/\s+/g, 'L')}`}
|
||||
d={`M${points.trim().replace(/\s+/g, 'L')}`}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,19 @@ import Shape from './Shape';
|
||||
|
||||
class Rect extends Shape {
|
||||
static displayName = 'Rect';
|
||||
|
||||
static propTypes = {
|
||||
...pathProps,
|
||||
...rectProps
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
...fillProps,
|
||||
...strokeProps,
|
||||
...rectProps
|
||||
static defaultProps = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
rx: 0,
|
||||
ry: 0
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
@@ -37,8 +41,8 @@ class Rect extends Shape {
|
||||
y={props.y.toString()}
|
||||
width={props.width.toString()}
|
||||
height={props.height.toString()}
|
||||
rx={props.rx ? props.rx.toString() : '0'}
|
||||
ry={props.ry ? props.ry.toString() : '0'}
|
||||
rx={props.rx.toString()}
|
||||
ry={props.ry.toString()}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,15 +30,6 @@ class Svg extends Component{
|
||||
id++;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
getChildren = () => {
|
||||
return Children.map(this.props.children, child => {
|
||||
return cloneElement(child, {
|
||||
svgId: this.id
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
measureInWindow = (...args) => {
|
||||
this.root.measureInWindow(...args);
|
||||
};
|
||||
@@ -67,9 +58,7 @@ class Svg extends Component{
|
||||
preserveAspectRatio={props.preserveAspectRatio}
|
||||
width={props.width}
|
||||
height={props.height}
|
||||
>
|
||||
{this.getChildren()}
|
||||
</ViewBox> : this.getChildren();
|
||||
>{props.children}</ViewBox> : props.children;
|
||||
|
||||
return (
|
||||
<NativeSvgView
|
||||
|
||||
@@ -10,6 +10,7 @@ import Shape from './Shape';
|
||||
|
||||
class Text extends Shape {
|
||||
static displayName = 'Text';
|
||||
|
||||
static propTypes = {
|
||||
dx: numberProp,
|
||||
dy: numberProp,
|
||||
@@ -17,10 +18,9 @@ class Text extends Shape {
|
||||
...pathProps
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
...textProps,
|
||||
...fillProps,
|
||||
...strokeProps
|
||||
static defaultProps = {
|
||||
dx: 0,
|
||||
dy: 0
|
||||
};
|
||||
|
||||
setNativeProps = (...args) => {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import {PropTypes} from 'react';
|
||||
import {pathProps} from '../lib/props';
|
||||
import {UseAttributes} from '../lib/attributes';
|
||||
import {UseAttributes, RenderableOnlyAttributes} from '../lib/attributes';
|
||||
import Shape from './Shape';
|
||||
import React from 'react';
|
||||
import patternReg from '../lib/extract/patternReg';
|
||||
import createReactNativeComponentClass from 'react/lib/createReactNativeComponentClass';
|
||||
import _ from 'lodash';
|
||||
|
||||
class Defs extends Shape {
|
||||
static displayName = 'Use';
|
||||
@@ -32,14 +33,35 @@ class Defs extends Shape {
|
||||
console.warn('Invalid `href` prop for `Use` element, expected a href like `"url(#id)"`, but got: "' + props.href + '"');
|
||||
}
|
||||
|
||||
let mergeList = [];
|
||||
|
||||
let extractedProps = this.extractProps(props, {
|
||||
stroke: true,
|
||||
fill: true,
|
||||
responder: true,
|
||||
transform: true
|
||||
});
|
||||
|
||||
Object.keys(RenderableOnlyAttributes).forEach(name => {
|
||||
|
||||
if (!_.isNil(props[name])) {
|
||||
// clipPath prop may provide `clipPathRef` as native prop
|
||||
if (name === 'clipPath') {
|
||||
if (extractedProps[name]) {
|
||||
mergeList.push(name);
|
||||
} else if (extractedProps.clipPathRef) {
|
||||
mergeList.push('clipPathRef');
|
||||
}
|
||||
} else {
|
||||
mergeList.push(name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return <RNSVGUse
|
||||
ref={ele => this.root = ele}
|
||||
{...this.extractProps(props, {
|
||||
stroke: true,
|
||||
fill: true,
|
||||
responder: true,
|
||||
transform: true
|
||||
})}
|
||||
{...extractedProps}
|
||||
mergeList={mergeList}
|
||||
href={href}
|
||||
>{props.children}</RNSVGUse>;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,4 @@
|
||||
|
||||
@interface RNSVGClipPath : RNSVGGroup
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
|
||||
@implementation RNSVGClipPath
|
||||
|
||||
- (void)saveDefination:(CGContextRef)context
|
||||
{
|
||||
[[self getSvgView] defineClipPath:[self getPath:context] clipPathRef:self.name];
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)saveDefination:(CGContextRef)context
|
||||
{
|
||||
[[self getSvgView] defineClipPath:self clipPathRef:self.name];
|
||||
}
|
||||
|
||||
- (void)removeDefination
|
||||
{
|
||||
if (self.name) {
|
||||
|
||||
@@ -64,10 +64,17 @@
|
||||
[super willRemoveSubview:subview];
|
||||
}
|
||||
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target mergeList:(NSArray<NSString *> *)mergeList
|
||||
{
|
||||
for (RNSVGNode *node in self.subviews) {
|
||||
[node mergeProperties:target];
|
||||
[node mergeProperties:target mergeList:mergeList];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetProperties
|
||||
{
|
||||
for (RNSVGNode *node in self.subviews) {
|
||||
[node resetProperties];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
/**
|
||||
* define <ClipPath></ClipPath> content as clipPath template.
|
||||
*/
|
||||
- (void)defineClipPath:(CGPathRef)clipPath clipPathRef:(NSString *)clipPathRef;
|
||||
- (void)defineClipPath:(__kindof RNSVGNode *)clipPath clipPathRef:(NSString *)clipPathRef;
|
||||
|
||||
- (void)removeClipPath:(NSString *)clipPathRef;
|
||||
|
||||
- (CGPathRef)getDefinedClipPath:(NSString *)clipPathRef;
|
||||
- (RNSVGNode *)getDefinedClipPath:(NSString *)clipPathRef;
|
||||
|
||||
- (void)defineTemplate:(RNSVGNode *)template templateRef:(NSString *)templateRef;
|
||||
- (void)defineTemplate:(__kindof RNSVGNode *)template templateRef:(NSString *)templateRef;
|
||||
|
||||
- (void)removeTemplate:(NSString *)tempalteRef;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
@implementation RNSVGSvgView
|
||||
{
|
||||
NSMutableDictionary<NSString *, NSValue *> *clipPaths;
|
||||
NSMutableDictionary<NSString *, RNSVGNode *> *clipPaths;
|
||||
NSMutableDictionary<NSString *, RNSVGNode *> *templates;
|
||||
}
|
||||
|
||||
@@ -64,12 +64,12 @@
|
||||
return self.responsible ? [super hitTest:point withEvent:event] : nil;
|
||||
}
|
||||
|
||||
- (void)defineClipPath:(CGPathRef)clipPath clipPathRef:(NSString *)clipPathRef
|
||||
- (void)defineClipPath:(__kindof RNSVGNode *)clipPath clipPathRef:(NSString *)clipPathRef
|
||||
{
|
||||
if (!clipPaths) {
|
||||
clipPaths = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
[clipPaths setValue:[NSValue valueWithPointer:clipPath] forKey:clipPathRef];
|
||||
[clipPaths setObject:clipPath forKey:clipPathRef];
|
||||
}
|
||||
|
||||
- (void)removeClipPath:(NSString *)clipPathRef
|
||||
@@ -79,9 +79,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (CGPathRef)getDefinedClipPath:(NSString *)clipPathRef
|
||||
- (RNSVGNode *)getDefinedClipPath:(NSString *)clipPathRef
|
||||
{
|
||||
return clipPaths ? [[clipPaths valueForKey:clipPathRef] pointerValue] : nil;
|
||||
return clipPaths ? [clipPaths objectForKey:clipPathRef] : nil;
|
||||
}
|
||||
|
||||
- (void)defineTemplate:(RNSVGNode *)template templateRef:(NSString *)templateRef
|
||||
|
||||
@@ -15,5 +15,7 @@
|
||||
@interface RNSVGUse : RNSVGRenderable
|
||||
|
||||
@property (nonatomic, strong) NSString *href;
|
||||
@property (nonatomic, copy) NSArray<NSString *> *mergeList;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,12 +10,22 @@
|
||||
|
||||
@implementation RNSVGUse
|
||||
|
||||
- (void)setMergeList:(NSArray<NSString *> *)mergeList
|
||||
{
|
||||
if (mergeList == _mergeList) {
|
||||
return;
|
||||
}
|
||||
_mergeList = mergeList;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
{
|
||||
RNSVGNode* template = [[self getSvgView] getDefinedTemplate:self.href];
|
||||
if (template) {
|
||||
[template mergeProperties:self];
|
||||
[template mergeProperties:self mergeList:self.mergeList];
|
||||
[template renderTo:context];
|
||||
[template resetProperties];
|
||||
} 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);
|
||||
|
||||
@@ -36,16 +36,13 @@
|
||||
*/
|
||||
- (void)renderLayerTo:(CGContextRef)context;
|
||||
|
||||
- (void)renderClip:(CGContextRef)context;
|
||||
|
||||
/**
|
||||
* clip node by clipPath or clipPathRef.
|
||||
*/
|
||||
- (void)clip:(CGContextRef)context;
|
||||
|
||||
/**
|
||||
* get clip path for current node.
|
||||
*/
|
||||
- (CGPathRef)getClipPath;
|
||||
|
||||
/**
|
||||
* getPath will return the path inside node as a ClipPath.
|
||||
*/
|
||||
@@ -70,8 +67,13 @@
|
||||
- (void)removeDefination;
|
||||
|
||||
/**
|
||||
* merge owned properties into target element`s properties
|
||||
* Just for template node to merge target node`s properties into owned properties
|
||||
*/
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target;
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target mergeList:(NSArray<NSString *> *)mergeList;
|
||||
|
||||
/**
|
||||
* Just for template node to reset all owned properties once after rendered.
|
||||
*/
|
||||
- (void)resetProperties;
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#import "RNSVGClipPath.h"
|
||||
|
||||
@implementation RNSVGNode
|
||||
{
|
||||
CGFloat originOpacity;
|
||||
}
|
||||
|
||||
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
|
||||
{
|
||||
@@ -76,13 +79,22 @@
|
||||
if (transparent) {
|
||||
CGContextBeginTransparencyLayer(context, NULL);
|
||||
}
|
||||
[self renderClip:context];
|
||||
[self renderLayerTo:context];
|
||||
if (transparent) {
|
||||
CGContextEndTransparencyLayer(context);
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
|
||||
- (void)renderClip:(CGContextRef)context
|
||||
{
|
||||
if (self.clipPathRef) {
|
||||
self.clipPath = [[[self getSvgView] getDefinedClipPath:self.clipPathRef] getPath:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setClipPath:(CGPathRef)clipPath
|
||||
{
|
||||
if (_clipPath == clipPath) {
|
||||
@@ -99,25 +111,12 @@
|
||||
return CGPathCreateMutable();
|
||||
}
|
||||
|
||||
- (CGPathRef)getClipPath
|
||||
{
|
||||
CGPathRef clipPath = nil;
|
||||
|
||||
if (self.clipPath) {
|
||||
clipPath = self.clipPath;
|
||||
} else if (self.clipPathRef) {
|
||||
clipPath = [[self getSvgView] getDefinedClipPath:self.clipPathRef];
|
||||
}
|
||||
|
||||
return clipPath;
|
||||
}
|
||||
|
||||
- (void)clip:(CGContextRef)context
|
||||
{
|
||||
CGPathRef clipPath = [self getClipPath];
|
||||
CGPathRef clipPath = self.clipPath;
|
||||
|
||||
if (clipPath) {
|
||||
CGContextAddPath(context, [self getClipPath]);
|
||||
CGContextAddPath(context, clipPath);
|
||||
if (self.clipRule == kRNSVGCGFCRuleEvenodd) {
|
||||
CGContextEOClip(context);
|
||||
} else {
|
||||
@@ -182,12 +181,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target mergeList:(NSArray<NSString *> *)mergeList
|
||||
{
|
||||
originOpacity = self.opacity;
|
||||
self.opacity = target.opacity * self.opacity;
|
||||
}
|
||||
|
||||
- (void)resetProperties
|
||||
{
|
||||
self.opacity = originOpacity;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGPathRelease(_clipPath);
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#import "RNSVGRenderable.h"
|
||||
|
||||
@implementation RNSVGRenderable
|
||||
{
|
||||
NSMutableDictionary *originProperties;
|
||||
NSArray *changedList;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
@@ -93,6 +97,7 @@
|
||||
CGContextSaveGState(context);
|
||||
CGContextConcatCTM(context, self.transform);
|
||||
CGContextSetAlpha(context, self.opacity);
|
||||
[self renderClip:context];
|
||||
[self renderLayerTo:context];
|
||||
CGContextRestoreGState(context);
|
||||
}
|
||||
@@ -100,7 +105,7 @@
|
||||
// hitTest delagate
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
CGPathRef clipPath = [self getClipPath];
|
||||
CGPathRef clipPath = self.clipPath;
|
||||
if (self.nodeArea && CGPathContainsPoint(self.nodeArea, nil, point, NO)) {
|
||||
if (!clipPath) {
|
||||
return self;
|
||||
@@ -112,38 +117,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target
|
||||
- (void)mergeProperties:(__kindof RNSVGNode *)target mergeList:(NSArray<NSString *> *)mergeList
|
||||
{
|
||||
RNSVGRenderable* renderableTarget = target;
|
||||
|
||||
if (renderableTarget.fill) {
|
||||
self.fill = renderableTarget.fill;
|
||||
if (mergeList.count == 0) {
|
||||
return;
|
||||
}
|
||||
if (renderableTarget.fillRule) {
|
||||
self.fillRule = renderableTarget.fillRule;
|
||||
|
||||
originProperties = [[NSMutableDictionary alloc] init];
|
||||
|
||||
changedList = mergeList;
|
||||
for (NSString *key in mergeList) {
|
||||
[originProperties setValue:[self valueForKey:key] forKey:key];
|
||||
[self setValue:[target valueForKey:key] forKey:key];
|
||||
}
|
||||
if (renderableTarget.stroke) {
|
||||
self.stroke = renderableTarget.stroke;
|
||||
|
||||
[super mergeProperties:target mergeList:mergeList];
|
||||
}
|
||||
|
||||
- (void)resetProperties
|
||||
{
|
||||
if (changedList) {
|
||||
for (NSString *key in changedList) {
|
||||
[self setValue:[originProperties valueForKey:key] forKey:key];
|
||||
}
|
||||
}
|
||||
if (renderableTarget.strokeWidth) {
|
||||
self.strokeWidth = renderableTarget.strokeWidth;
|
||||
}
|
||||
if (renderableTarget.strokeLinecap) {
|
||||
self.strokeLinecap = renderableTarget.strokeLinecap;
|
||||
}
|
||||
if (renderableTarget.strokeLinejoin) {
|
||||
self.strokeLinejoin = renderableTarget.strokeLinejoin;
|
||||
}
|
||||
if (renderableTarget.strokeMiterlimit) {
|
||||
self.strokeMiterlimit = renderableTarget.strokeMiterlimit;
|
||||
}
|
||||
if (renderableTarget.strokeDasharray.count != 0) {
|
||||
self.strokeDasharray = renderableTarget.strokeDasharray;
|
||||
}
|
||||
if (renderableTarget.strokeDashoffset) {
|
||||
self.strokeDashoffset = renderableTarget.strokeDashoffset;
|
||||
}
|
||||
[super mergeProperties:target];
|
||||
[super resetProperties];
|
||||
changedList = nil;
|
||||
}
|
||||
|
||||
- (void)renderLayerTo:(CGContextRef)context
|
||||
|
||||
@@ -20,5 +20,5 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(href, NSString)
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(mergeList, NSArray<NSString *>)
|
||||
@end
|
||||
|
||||
@@ -42,6 +42,7 @@ function fontAndLinesDiffer(a, b) {
|
||||
}
|
||||
|
||||
const NodeAttributes = {
|
||||
name: true,
|
||||
transform: {
|
||||
diff: arrayDiffer
|
||||
},
|
||||
@@ -50,7 +51,7 @@ const NodeAttributes = {
|
||||
responsible: true
|
||||
};
|
||||
|
||||
const RenderableAttributes = merge(NodeAttributes, {
|
||||
const RenderableOnlyAttributes = {
|
||||
fill: {
|
||||
diff: arrayDiffer
|
||||
},
|
||||
@@ -70,26 +71,31 @@ const RenderableAttributes = merge(NodeAttributes, {
|
||||
},
|
||||
strokeDashoffset: true,
|
||||
strokeMiterlimit: true
|
||||
});
|
||||
};
|
||||
|
||||
const GroupAttributes = merge(NodeAttributes, {
|
||||
const RenderableAttributes = merge({}, NodeAttributes, RenderableOnlyAttributes);
|
||||
|
||||
const GroupAttributes = merge({
|
||||
clipPath: {
|
||||
diff: arrayDiffer
|
||||
},
|
||||
clipRule: true
|
||||
});
|
||||
}, NodeAttributes);
|
||||
|
||||
const UseAttributes = merge(RenderableAttributes, {
|
||||
const UseAttributes = merge({
|
||||
mergeList: {
|
||||
diff: arrayDiffer
|
||||
},
|
||||
href: true
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
const PathAttributes = merge(RenderableAttributes, {
|
||||
const PathAttributes = merge({
|
||||
d: {
|
||||
diff: arrayDiffer
|
||||
}
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
const TextAttributes = merge(RenderableAttributes, {
|
||||
const TextAttributes = merge({
|
||||
alignment: true,
|
||||
frame: {
|
||||
diff: fontAndLinesDiffer
|
||||
@@ -97,48 +103,48 @@ const TextAttributes = merge(RenderableAttributes, {
|
||||
path: {
|
||||
diff: arrayDiffer
|
||||
}
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
const ClipPathAttributes = merge(RenderableAttributes, {
|
||||
const ClipPathAttributes = {
|
||||
name: true
|
||||
});
|
||||
};
|
||||
|
||||
const CircleAttributes = merge(RenderableAttributes, {
|
||||
const CircleAttributes = merge({
|
||||
cx: true,
|
||||
cy: true,
|
||||
r: true
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
const EllipseAttributes = merge(RenderableAttributes, {
|
||||
const EllipseAttributes = merge({
|
||||
cx: true,
|
||||
cy: true,
|
||||
rx: true,
|
||||
ry: true
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
const ImageAttributes = merge(RenderableAttributes, {
|
||||
const ImageAttributes = merge({
|
||||
x: true,
|
||||
y: true,
|
||||
width: true,
|
||||
height: true,
|
||||
src: true
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
const LineAttributes = merge(RenderableAttributes, {
|
||||
const LineAttributes = merge({
|
||||
x1: true,
|
||||
y1: true,
|
||||
x2: true,
|
||||
y2: true
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
const RectAttributes = merge(RenderableAttributes, {
|
||||
const RectAttributes = merge({
|
||||
x: true,
|
||||
y: true,
|
||||
width: true,
|
||||
height: true,
|
||||
rx: true,
|
||||
ry: true
|
||||
});
|
||||
}, RenderableAttributes);
|
||||
|
||||
|
||||
export {
|
||||
@@ -151,5 +157,6 @@ export {
|
||||
ImageAttributes,
|
||||
LineAttributes,
|
||||
RectAttributes,
|
||||
UseAttributes
|
||||
UseAttributes,
|
||||
RenderableOnlyAttributes
|
||||
};
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import SerializablePath from 'react-native/Libraries/ART/ARTSerializablePath';
|
||||
import clipReg from './patternReg';
|
||||
|
||||
let clipPatterns = {};
|
||||
const clipRules = {
|
||||
evenodd: 0,
|
||||
nonzero: 1
|
||||
};
|
||||
|
||||
function set(id, pattern) {
|
||||
clipPatterns[id] = pattern;
|
||||
}
|
||||
|
||||
function remove(id) {
|
||||
delete clipPatterns[id];
|
||||
}
|
||||
|
||||
|
||||
export default function (props) {
|
||||
let {clipPath, clipRule} = props;
|
||||
let clippingProps = {};
|
||||
@@ -26,22 +16,11 @@ export default function (props) {
|
||||
let matched = clipPath.match(clipReg);
|
||||
|
||||
if (matched) {
|
||||
let patternName = `${matched[1]}:${props.svgId}`;
|
||||
let pattern = clipPatterns[patternName];
|
||||
if (pattern) {
|
||||
clippingProps.clipPathRef = pattern;
|
||||
} else {
|
||||
clippingProps = null;
|
||||
// TODO: warn
|
||||
}
|
||||
clippingProps.clipPathRef = matched[1];
|
||||
} else {
|
||||
clippingProps.clipPath = new SerializablePath(clipPath).toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
return clippingProps;
|
||||
}
|
||||
|
||||
export {
|
||||
set,
|
||||
remove
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ function fillFilter(props) {
|
||||
if (fill === 'none') {
|
||||
return null;
|
||||
} else if (fill) {
|
||||
return patterns(fill, fillOpacity, props.svgId);
|
||||
return patterns(fill, fillOpacity);
|
||||
} else if (props.fill === undefined) {
|
||||
return rgba('#000', isNaN(fillOpacity) ? 1 : fillOpacity).rgbaString();
|
||||
} else {
|
||||
|
||||
@@ -39,7 +39,7 @@ function strokeFilter(props) {
|
||||
|
||||
// TODO: propTypes check
|
||||
return {
|
||||
stroke: patterns(stroke, +props.strokeOpacity, props.svgId),
|
||||
stroke: patterns(stroke, +props.strokeOpacity),
|
||||
strokeLinecap: caps[props.strokeLinecap] || 0,
|
||||
strokeLinejoin: joins[props.strokeLinejoin] || 0,
|
||||
strokeDasharray: strokeDasharray || null,
|
||||
|
||||
41
lib/props.js
41
lib/props.js
@@ -86,44 +86,34 @@ const pathProps = {
|
||||
};
|
||||
|
||||
const circleProps = {
|
||||
cx: numberProp,
|
||||
cy: numberProp,
|
||||
r: numberProp
|
||||
cx: numberProp.isRequired,
|
||||
cy: numberProp.isRequired,
|
||||
r: numberProp.isRequired
|
||||
};
|
||||
|
||||
const ellipseProps = {
|
||||
cx: numberProp,
|
||||
cy: numberProp,
|
||||
rx: numberProp,
|
||||
ry: numberProp
|
||||
cx: numberProp.isRequired,
|
||||
cy: numberProp.isRequired,
|
||||
rx: numberProp.isRequired,
|
||||
ry: numberProp.isRequired
|
||||
};
|
||||
|
||||
const lineProps = {
|
||||
x1: numberProp,
|
||||
x2: numberProp,
|
||||
y1: numberProp,
|
||||
y2: numberProp
|
||||
x1: numberProp.isRequired,
|
||||
x2: numberProp.isRequired,
|
||||
y1: numberProp.isRequired,
|
||||
y2: numberProp.isRequired
|
||||
};
|
||||
|
||||
const rectProps = {
|
||||
x: numberProp,
|
||||
y: numberProp,
|
||||
width: numberProp,
|
||||
height: numberProp,
|
||||
x: numberProp.isRequired,
|
||||
y: numberProp.isRequired,
|
||||
width: numberProp.isRequired,
|
||||
height: numberProp.isRequired,
|
||||
rx: numberProp,
|
||||
ry: numberProp
|
||||
};
|
||||
|
||||
const contextProps = {
|
||||
...circleProps,
|
||||
...ellipseProps,
|
||||
...lineProps,
|
||||
...rectProps,
|
||||
...fillProps,
|
||||
...strokeProps,
|
||||
...textProps
|
||||
};
|
||||
|
||||
export {
|
||||
numberProp,
|
||||
fillProps,
|
||||
@@ -135,7 +125,6 @@ export {
|
||||
ellipseProps,
|
||||
lineProps,
|
||||
rectProps,
|
||||
contextProps,
|
||||
pathProps,
|
||||
responderProps,
|
||||
responderPropsKeys,
|
||||
|
||||
Reference in New Issue
Block a user