complete basic shapes(ios)

This commit is contained in:
Horcrux
2016-04-26 19:10:57 +08:00
parent d7a9e418ae
commit 24dcc83a80
25 changed files with 540 additions and 256 deletions

View File

@@ -213,7 +213,7 @@ const icon = <Svg
</G>
</Svg>;
const samples = [ClipPathAttr, ClipRule, ClipPathElement, TextClipping];
const samples = [ClipPathAttr, ClipRule];//, ClipPathElement, TextClipping
export {
icon,

View File

@@ -2,34 +2,32 @@ import React, {
Component,
PropTypes
} from 'react-native';
import Ellipse from './Ellipse';
let propType = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
class Circle extends Component{
import Shape, {CIRCLE} from './Shape';
import {circleProps, pathProps} from '../lib/props';
import _ from 'lodash';
class Circle extends Shape{
static displayName = 'Circle';
static propTypes = {
cx: propType,
cy: propType,
r: propType
...pathProps,
...circleProps
};
static defaultProps = {
cx: 0,
cy: 0
cy: 0,
r: 0
};
static getPath = props => Ellipse.getPath({
cx: props.cx,
cy: props.cy,
rx: props.r,
ry: props.r
});
static contextTypes = {
...circleProps,
isInGroup: PropTypes.bool
};
render() {
return <Ellipse
{...this.props}
rx={+this.props.r}
ry={+this.props.r}
/>
}
constructor() {
super(...arguments);
this.type = CIRCLE;
};
}
export default Circle;

View File

@@ -2,35 +2,32 @@ import React, {
Component,
PropTypes
} from 'react-native';
import Path from './Path';
let propType = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
class Ellipse extends Component{
import Shape, {ELLIPSE} from './Shape';
import {ellipseProps, pathProps} from '../lib/props';
class Ellipse extends Shape{
static displayName = 'Ellipse';
static propTypes = {
cx: propType,
cy: propType,
rx: propType,
ry: propType
...pathProps,
...ellipseProps
};
static getPath = props => {
let {cx, cy, rx, ry} = props;
return `
M ${cx - rx} ${cy}
a ${rx}, ${ry} 0 1, 0 ${rx * 2}, 0
a ${rx}, ${ry} 0 1, 0 ${-rx * 2}, 0
Z
`;
static defaultProps = {
cx: 0,
cy: 0,
rx: 0,
ry: 0
};
render() {
let {props} = this;
let d = Ellipse.getPath(this.props);
return <Path
{...props}
d={d}
/>;
}
static contextTypes = {
...ellipseProps,
isInGroup: PropTypes.bool
};
constructor() {
super(...arguments);
this.type = ELLIPSE;
};
}
export default Ellipse;

View File

@@ -2,42 +2,34 @@ import React, {
Component,
Children,
cloneElement,
PropTypes,
requireNativeComponent
} from 'react-native';
import createReactNativeComponentClass from 'react-native/Libraries/ReactNative/createReactNativeComponentClass';
import Defs from './Defs';
import _ from 'lodash';
import {GroupAttributes} from '../lib/attributes';
const transformProps = {
scale: null,
scaleX: null,
scaleY: null,
rotate: null,
transform: null,
x: null,
y: null,
originX: null,
originY: null
};
const clipProps = {
clipPath: null,
clipRule: null
};
import {numberProp, shapeProps} from '../lib/props';
import extractProps from '../lib/extract/extractProps';
class G extends Component{
static displayName = 'G';
getChildren = () => {
return Children.map(this.props.children, child => cloneElement(child, {
...this.props,
...transformProps,
...clipProps,
...child.props,
id: null
}));
static childContextTypes = {
svgId: numberProp,
isInGroup: PropTypes.bool,
...shapeProps
};
getChildContext = () => {
return _.reduce(shapeProps, (props, value, key) => {
props[key] = this.props[key];
return props;
}, {
svgId: this.props.svgId,
isInGroup: true
});
};
render() {
@@ -56,7 +48,7 @@ class G extends Component{
return <NativeGroup
{...extractProps(this.props, {transform: true})}
>
{this.getChildren()}
{this.props.children}
</NativeGroup>;
}
}

View File

@@ -2,30 +2,32 @@ import React, {
Component,
PropTypes
} from 'react-native';
import Path from './Path';
import Shape, {LINE} from './Shape';
import {lineProps, pathProps} from '../lib/props';
let propType = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
class Line extends Component{
class Line extends Shape{
static displayName = 'Line';
static propTypes = {
x1: propType,
x2: propType,
y1: propType,
y2: propType,
strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round'])
...pathProps,
...lineProps
};
static getPath = (props) => (
`M${props.x1},${props.y1} L${props.x2},${props.y2}`
);
static defaultProps = {
x1: 0,
x2: 0,
y1: 0,
y2: 0
};
render() {
return <Path
{...this.props}
d={Line.getPath(this.props)}
/>;
}
static contextTypes = {
...lineProps,
isInGroup: PropTypes.bool
};
constructor() {
super(...arguments);
this.type = LINE;
};
}
export default Line;

View File

@@ -5,7 +5,7 @@ import React, {
} from 'react-native';
import stopsOpacity from '../lib/stopsOpacity';
import numberProp from '../lib/numberProp';
import {numberProp} from '../lib/props';
import Gradient from './Gradient';
import {LINEAR_GRADIENT} from '../lib/extract/extractBrush';
import insertColorStopsIntoArray from '../lib/insertProcessor';

View File

@@ -1,8 +1,7 @@
import React, {
Component,
PropTypes,
requireNativeComponent,
cloneElement
requireNativeComponent
} from 'react-native';
import Defs from './Defs';
@@ -11,24 +10,23 @@ import calculateBoundingBox from '../lib/calculateBoundingBox';
import extractProps from '../lib/extract/extractProps';
import SerializablePath from 'react-native/Libraries/ART/ARTSerializablePath';
import {PathAttributes} from '../lib/attributes';
import {pathProps} from '../lib/props';
let propType = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
class Path extends Component{
static displayName = 'Path';
static propTypes = {
visible: PropTypes.bool,
d: PropTypes.string,
x: propType,
y: propType,
strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round']),
strokeCap: PropTypes.oneOf(['butt', 'square', 'round']),
strokeLinejoin: PropTypes.oneOf(['miter', 'bevel', 'round']),
strokeJoin: PropTypes.oneOf(['miter', 'bevel', 'round']),
strokeDasharray: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.number)])
...pathProps
};
static contextTypes = {
...pathProps,
isInGroup: PropTypes.bool
};
static getPath = props => props.d;
_dimensions = null;
@@ -38,16 +36,15 @@ class Path extends Component{
}
};
getBoundingBox = () => {
if (!this._dimensions) {
this._dimensions = calculateBoundingBox(this.props.d);
}
return this._dimensions;
};
render() {
let {props} = this;
if (this.context.isInGroup) {
props = _.defaults(this.context, props, {
isInGroup: null
});
}
if (props.id) {
return <Defs.Item
id={props.id}
@@ -62,7 +59,7 @@ class Path extends Component{
return (
<NativePath
{...extractProps.call(this, props)}
{...extractProps(props)}
d={d}
/>
);

View File

@@ -4,7 +4,7 @@ import React, {
Children
} from 'react-native';
import stopsOpacity from '../lib/stopsOpacity';
import numberProp from '../lib/numberProp';
import {numberProp} from '../lib/props';
import Gradient from './Gradient';
import {RADIAL_GRADIENT} from '../lib/extract/extractBrush';
import insertColorStopsIntoArray from '../lib/insertProcessor';

View File

@@ -2,115 +2,36 @@ import React, {
Component,
PropTypes
} from 'react-native';
import Shape, {RECT} from './Shape';
import {rectProps, pathProps} from '../lib/props';
import Path from './Path';
let propType = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
function processRadius(radius) {
radius = +radius;
return radius || 0;
}
function getR(props) {
let {
width,
height,
rx,
ry
} = props;
rx = processRadius(rx);
ry = processRadius(ry);
if ((rx && !ry) || (ry && !rx)) {
if (rx) {
ry = rx;
} else {
rx = ry;
}
}
if (rx > width / 2) {
rx = width / 2;
}
if (ry > height / 2) {
ry = height / 2;
}
return {
rx,
ry
};
}
class Rect extends Component{
class Rect extends Shape{
static displayName = 'Rect';
static propTypes = {
x: propType,
y: propType,
width: propType,
height: propType,
rx: propType,
ry: propType,
strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round']),
strokeCap: PropTypes.oneOf(['butt', 'square', 'round']),
strokeLinejoin: PropTypes.oneOf(['miter', 'bevel', 'round']),
strokeJoin: PropTypes.oneOf(['miter', 'bevel', 'round'])
...pathProps,
...rectProps
};
static defaultProps = {
x: 0,
y: 0,
width: 0,
height: 0,
rx: 0,
ry: 0
};
static getPath = (props, r) => {
let {
x,
y,
width,
height
} = props;
if (!r) {
r = getR(props);
}
let {rx, ry} = r;
return (rx || ry) ? `
M ${x}, ${y}
h ${width - 2 * rx}
a ${rx},${ry} 0 0 1 ${rx},${ry}
v ${height - 2 * ry}
a ${rx},${ry} 0 0 1 ${-rx},${ry}
h ${2 * rx - width}
a ${rx},${ry} 0 0 1 ${-rx},${-ry}
v ${2 * ry - height}
a ${rx},${ry} 0 0 1 ${rx},${-ry}
Z
` : `
M ${x}, ${y}
h ${width}
v ${height}
h ${-width}
Z
`;
static contextTypes = {
...rectProps,
isInGroup: PropTypes.bool
};
render() {
let r = getR(this.props);
return <Path
{...this.props}
width={null}
height={null}
x={r.rx || null}
y={null}
d={Rect.getPath(this.props, r)}
/>;
}
constructor() {
super(...arguments);
this.type = RECT;
};
}
export default Rect;

View File

@@ -3,32 +3,43 @@ import React, {
PropTypes
} from 'react-native';
import Path from './Path';
import _ from 'lodash';
import extractProps from '../lib/extract/extractProps';
import {ShapeAttributes} from '../lib/attributes';
import SerializableShape from '../lib/SerializableShape';
import createReactNativeComponentClass from 'react-native/Libraries/ReactNative/createReactNativeComponentClass';
import {circleProps, ellipseProps, lineProps, rectProps} from '../lib/props';
/**
* Circle shape type
*/
const CIRCLE = 0;
/**
* ELLIPSE shape type
*/
const ELLIPSE = 1;
/**
* LINE shape type
*/
const LINE = 2;
/**
* RECT shape type
*/
const RECT = 3;
/**
* coord props
*
*/
const COORD_PROPS = {
/**
* algorithm for radius in percentage
* radius = Math.sqrt(Math.pow((width*percent), 2) + Math.pow((height*percent), 2)) / Math.sqrt(2);
*/
const CIRCLE_COORDS = ['cx', 'cy', 'r'];
const ELLIPSE = 1;
const ELLIPSE_COORDS = ['cx', 'cy', 'rx', 'ry'];
const LINE = 2;
const LINE_COORDS = ['x1', 'y1', 'x2', 'y2'];
const RECT = 5;
const RECT_COORDS = ['x', 'y', 'width', 'height'];
[CIRCLE]: Object.keys(circleProps),
[ELLIPSE]: Object.keys(ellipseProps),
[LINE]: Object.keys(lineProps),
[RECT]: Object.keys(rectProps)
};
/**
* virtualNode component for shape elements
@@ -37,14 +48,29 @@ class Shape extends Component{
static displayName = 'Shape';
render() {
let {props} = this;
let props = this.props;
if (this.context.isInGroup) {
props = _.defaults(this.context, props, {
isInGroup: null
});
}
let shape = new SerializableShape(props, COORD_PROPS[this.type]).toJSON();
return <NativePath
{...props}
{...extractProps.call(props)}
shape={new SerializableShape(props).toArray()}
{...extractProps(this.type === 3 ? {
...props,
x: null,
y: null
} : props)}
shape={{
...shape,
type: this.type
}}
/>;
}
};
}
let NativePath = createReactNativeComponentClass({
@@ -53,3 +79,10 @@ let NativePath = createReactNativeComponentClass({
});
export default Shape;
export {
CIRCLE,
ELLIPSE,
LINE,
RECT
};

View File

@@ -6,7 +6,7 @@ import createReactNativeComponentClass from 'react-native/Libraries/ReactNative/
import extractProps from '../lib/extract/extractProps';
import extractText from '../lib/extract/extractText';
import {TextAttributes} from '../lib/attributes';
import numberProp from '../lib/numberProp';
import {numberProp} from '../lib/props';
class Text extends Component{
static displayName = 'Text';

View File

@@ -1,7 +1,6 @@
import React, {
Component,
PropTypes,
cloneElement
PropTypes
} from 'react-native';
import Defs from './Defs';
class Use extends Component{

View File

@@ -25,6 +25,8 @@
10A062FF1CC732020000CEEF /* RNSVGSvgViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10A062FD1CC732020000CEEF /* RNSVGSvgViewManager.m */; };
10A063041CC7320C0000CEEF /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 10A063011CC7320C0000CEEF /* RNSVGPath.m */; };
10A063051CC7320C0000CEEF /* RNSVGSvgView.m in Sources */ = {isa = PBXBuildFile; fileRef = 10A063031CC7320C0000CEEF /* RNSVGSvgView.m */; };
10C068671CCF0F87007C6982 /* RNSVGShape.m in Sources */ = {isa = PBXBuildFile; fileRef = 10C068651CCF0F87007C6982 /* RNSVGShape.m */; };
10C0686A1CCF1061007C6982 /* RNSVGShapeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10C068691CCF1061007C6982 /* RNSVGShapeManager.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -80,6 +82,10 @@
10A063011CC7320C0000CEEF /* RNSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGPath.m; sourceTree = "<group>"; };
10A063021CC7320C0000CEEF /* RNSVGSvgView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGSvgView.h; sourceTree = "<group>"; };
10A063031CC7320C0000CEEF /* RNSVGSvgView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSvgView.m; sourceTree = "<group>"; };
10C068641CCF0F87007C6982 /* RNSVGShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGShape.h; sourceTree = SOURCE_ROOT; };
10C068651CCF0F87007C6982 /* RNSVGShape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGShape.m; sourceTree = SOURCE_ROOT; };
10C068681CCF1061007C6982 /* RNSVGShapeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGShapeManager.h; sourceTree = "<group>"; };
10C068691CCF1061007C6982 /* RNSVGShapeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGShapeManager.m; sourceTree = "<group>"; };
10FEAC6A1CC7D05200F1C23C /* RNSVGCGFCRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGCGFCRule.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -104,10 +110,12 @@
0CF68ADC1AF0549300FF9E5C /* RNSVGContainer.h */,
0CF68ADD1AF0549300FF9E5C /* RNSVGGroup.h */,
0CF68ADE1AF0549300FF9E5C /* RNSVGGroup.m */,
0CF68ADF1AF0549300FF9E5C /* RNSVGNode.h */,
0CF68AE01AF0549300FF9E5C /* RNSVGNode.m */,
10C068641CCF0F87007C6982 /* RNSVGShape.h */,
10C068651CCF0F87007C6982 /* RNSVGShape.m */,
10A063001CC7320C0000CEEF /* RNSVGPath.h */,
10A063011CC7320C0000CEEF /* RNSVGPath.m */,
0CF68ADF1AF0549300FF9E5C /* RNSVGNode.h */,
0CF68AE01AF0549300FF9E5C /* RNSVGNode.m */,
10A063021CC7320C0000CEEF /* RNSVGSvgView.h */,
10A063031CC7320C0000CEEF /* RNSVGSvgView.m */,
0CF68AE11AF0549300FF9E5C /* RNSVGRenderable.h */,
@@ -149,6 +157,8 @@
0CF68AF81AF0549300FF9E5C /* ViewManagers */ = {
isa = PBXGroup;
children = (
10C068681CCF1061007C6982 /* RNSVGShapeManager.h */,
10C068691CCF1061007C6982 /* RNSVGShapeManager.m */,
10A062FA1CC732020000CEEF /* RNSVGPathManager.h */,
10A062FB1CC732020000CEEF /* RNSVGPathManager.m */,
10A062FC1CC732020000CEEF /* RNSVGSvgViewManager.h */,
@@ -220,6 +230,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
10C068671CCF0F87007C6982 /* RNSVGShape.m in Sources */,
0CF68B161AF0549300FF9E5C /* RNSVGTextManager.m in Sources */,
10A063041CC7320C0000CEEF /* RNSVGPath.m in Sources */,
0CF68B111AF0549300FF9E5C /* RNSVGGroupManager.m in Sources */,
@@ -233,6 +244,7 @@
10A063051CC7320C0000CEEF /* RNSVGSvgView.m in Sources */,
0CF68B071AF0549300FF9E5C /* RNSVGRenderable.m in Sources */,
0CF68B101AF0549300FF9E5C /* RCTConvert+RNSVG.m in Sources */,
10C0686A1CCF1061007C6982 /* RNSVGShapeManager.m in Sources */,
10A062FE1CC732020000CEEF /* RNSVGPathManager.m in Sources */,
0CF68B061AF0549300FF9E5C /* RNSVGNode.m in Sources */,
0CF68B0F1AF0549300FF9E5C /* RNSVGSolidColor.m in Sources */,

View File

@@ -18,8 +18,8 @@
@interface RNSVGNode : UIView
@property (nonatomic, assign) CGRect rect;
@property (nonatomic, assign) CGFloat opacity;
@property (nonatomic, assign) CGPathRef clipPath;
@property (nonatomic, assign) RNSVGCGFCRule clipRule;

View File

@@ -80,7 +80,6 @@
_clipPath = CGPathRetain(clipPath);
}
- (void)dealloc
{
CGPathRelease(_clipPath);

17
ios/RNSVGShape.h Normal file
View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import "RNSVGRenderable.h"
#import "RNSVGPath.h"
@interface RNSVGShape : RNSVGPath
@property (nonatomic, strong) NSDictionary* shape;
@end

115
ios/RNSVGShape.m Normal file
View File

@@ -0,0 +1,115 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RNSVGShape.h"
#import "RCTLog.h"
@implementation RNSVGShape
- (void)dealloc
{
}
- (void)renderLayerTo:(CGContextRef)context
{
int type = [[self.shape objectForKey:@"type"] intValue];
CGRect box = CGContextGetClipBoundingBox(context);
CGMutablePathRef path = CGPathCreateMutable();
float height = CGRectGetHeight(box);
float width = CGRectGetWidth(box);
switch (type) {
case 0:
{
// draw circle
CGFloat cx = [self getActualProp:@"cx" relative:width];
CGFloat cy = [self getActualProp:@"cy" relative:height];
CGFloat r = [self getActualProp:@"r" relative:height];
CGPathAddArc(path, nil, cx, cy, r, 0, 2*M_PI, YES);
break;
}
case 1:
{
// draw ellipse
CGFloat cx = [self getActualProp:@"cx" relative:width];
CGFloat cy = [self getActualProp:@"cy" relative:height];
CGFloat rx = [self getActualProp:@"rx" relative:height];
CGFloat ry = [self getActualProp:@"ry" relative:height];
CGPathAddEllipseInRect(path, nil, CGRectMake(cx - rx / 2, cy - ry / 2, rx * 2, ry * 2));
break;
}
case 2:
{
// draw line
CGFloat x1 = [self getActualProp:@"x1" relative:height];
CGFloat y1 = [self getActualProp:@"y1" relative:height];
CGFloat x2 = [self getActualProp:@"x2" relative:height];
CGFloat y2 = [self getActualProp:@"y2" relative:height];
CGPathMoveToPoint(path, nil, x1, y1);
CGPathAddLineToPoint(path, nil, x2, y2);
break;
}
case 3:
{
// draw rect
CGPathMoveToPoint(path, NULL, 0, 0);
CGFloat x = [self getActualProp:@"x" relative:width];
CGFloat y = [self getActualProp:@"y" relative:height];
CGFloat w = [self getActualProp:@"width" relative:width];
CGFloat h = [self getActualProp:@"height" relative:height];
CGFloat rx = [self getActualProp:@"rx" relative:width];
CGFloat ry = [self getActualProp:@"ry" relative:height];
if (rx != 0 || ry != 0) {
if (rx == 0) {
rx = ry;
} else if (ry == 0) {
ry = rx;
}
if (rx > w / 2) {
rx = w / 2;
}
if (ry > h / 2) {
ry = h / 2;
}
CGPathAddRoundedRect(path, nil, CGRectMake(x, y, w, h), rx, ry);
} else {
CGPathAddRect(path, nil, CGRectMake(x, y, w, h));
}
break;
}
default:
RCTLogError(@"Invalid Shape type %d at %@", type, self.shape);
//CGPathRelease(path);
}
self.d = path;
[super renderLayerTo:context];
//NSLog(@"%@", NSStringFromCGRect(box));
//NSLog(@"%@", self.shape);
}
- (CGFloat)getActualProp:(NSString *)name relative:(float)relative
{
NSDictionary *prop = [self.shape objectForKey:name];
CGFloat value = [[prop objectForKey:@"value"] floatValue];
if ([[prop objectForKey:@"percentage"] integerValue] == 1) {
return relative * value;
} else {
return value;
}
}
@end

View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RNSVGRenderableManager.h"
@interface RNSVGShapeManager : RNSVGRenderableManager
@end

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) 2015-present, Horcrux.
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RNSVGShapeManager.h"
#import "RNSVGShape.h"
#import "RCTConvert+RNSVG.h"
@implementation RNSVGShapeManager
RCT_EXPORT_MODULE()
- (RNSVGRenderable *)node
{
return [RNSVGShape new];
}
RCT_EXPORT_VIEW_PROPERTY(shape, NSDictionary)
@end

View File

@@ -1,10 +1,55 @@
export default class {
constructor(props) {
/**
* Format potential percentage props
*
* convert somet props like those
* width="50%"
* height="500"
*
* to
* {
* width: {
* percentage: true,
* value: 0.5
* },
* height: {
* percentage: false,
* value: 500
* }
* }
*
*
*/
import percentToFloat from './percentToFloat';
function percentageTransform(value) {
if (typeof value === 'number') {
return {
percentage: false,
value
};
}
toArray = () => {
let float = percentToFloat(value);
return {
percentage: float !== +value,
value: float
}
}
export default class {
constructor(props, list) {
this.shape = {};
list.forEach(name => {
if (props[name] != null) {
this.shape[name] = percentageTransform(props[name]);
}
});
}
toJSON = () => {
return this.shape;
};
};

View File

@@ -6,7 +6,7 @@ function arrayDiffer(a, b) {
if (a.length !== b.length) {
return true;
}
for (var i = 0; i < a.length; i++) {
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return true;
}
@@ -14,6 +14,22 @@ function arrayDiffer(a, b) {
return false;
}
function shapeDiffer(a, b) {
if (a === b) {
return false;
}
for (let key in a) {
if (a.hasOwnProperty(key)) {
if (key === 'type' && a.type !== b.type) {
return true;
} else if (a[key].percentage !== b[key].percentage || a[key].value !== b[key].value) {
return true;
}
}
}
return false;
}
function fontAndLinesDiffer(a, b) {
if (a === b) {
return false;
@@ -92,7 +108,7 @@ const TextAttributes = {
const ShapeAttributes = {
shape: {
diff: arrayDiffer
diff: shapeDiffer
},
...RenderableAttributes
};

View File

@@ -75,7 +75,7 @@ function extractFont(font) {
};
}
const alignments = {
const anchord = {
right: 1,
center: 2,
left: 0
@@ -83,7 +83,7 @@ const alignments = {
export default function(props) {
return {
alignment: alignments[props.textAnchor] || 0,
alignment: anchord[props.textAnchor] || 0,
frame: extractFontAndLines(
props,
childrenAsString(props.children)

103
lib/props.js Normal file
View File

@@ -0,0 +1,103 @@
import {
PropTypes
} from 'react-native';
const numberProp = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
const fillProps = {
fill: PropTypes.string,
fillOpacity: numberProp,
fillRule: PropTypes.oneOf(['evenodd', 'nonzero'])
};
const clipProps = {
clipRule: PropTypes.oneOf(['evenodd', 'nonzero']),
clipPath: PropTypes.string
};
const strokeProps = {
stroke: PropTypes.string,
strokeWidth: numberProp,
strokeOpacity: numberProp,
strokeDasharray: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.string]),
strokeDashoffset: numberProp,
strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round']),
strokeLinejoin: PropTypes.oneOf(['miter', 'bevel', 'round'])
};
const textProps = {
textAnchor: PropTypes.oneOf(['right', 'center', 'left']),
path: PropTypes.string
};
const transformProps = {
scale: numberProp,
scaleX: numberProp,
scaleY: numberProp,
rotate: numberProp,
x: numberProp,
y: numberProp,
originX: numberProp,
originY: numberProp,
transform: PropTypes.string
};
const pathProps = {
...fillProps,
...strokeProps,
...clipProps,
...transformProps
};
const circleProps = {
cx: numberProp,
cy: numberProp,
r: numberProp
};
const ellipseProps = {
cx: numberProp,
cy: numberProp,
rx: numberProp,
ry: numberProp
};
const lineProps = {
x1: numberProp,
x2: numberProp,
y1: numberProp,
y2: numberProp
};
const rectProps = {
x: numberProp,
y: numberProp,
width: numberProp,
height: numberProp,
rx: numberProp,
ry: numberProp
};
const shapeProps = {
...circleProps,
...ellipseProps,
...lineProps,
...rectProps,
...fillProps,
...strokeProps
};
export {
numberProp,
fillProps,
clipProps,
strokeProps,
transformProps,
textProps,
circleProps,
ellipseProps,
lineProps,
rectProps,
shapeProps,
pathProps
}