mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-22 15:15:12 +00:00
complete basic shapes(ios)
This commit is contained in:
@@ -213,7 +213,7 @@ const icon = <Svg
|
||||
</G>
|
||||
</Svg>;
|
||||
|
||||
const samples = [ClipPathAttr, ClipRule, ClipPathElement, TextClipping];
|
||||
const samples = [ClipPathAttr, ClipRule];//, ClipPathElement, TextClipping
|
||||
|
||||
export {
|
||||
icon,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
113
elements/Rect.js
113
elements/Rect.js
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, {
|
||||
Component,
|
||||
PropTypes,
|
||||
cloneElement
|
||||
PropTypes
|
||||
} from 'react-native';
|
||||
import Defs from './Defs';
|
||||
class Use extends Component{
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@
|
||||
_clipPath = CGPathRetain(clipPath);
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CGPathRelease(_clipPath);
|
||||
|
||||
17
ios/RNSVGShape.h
Normal file
17
ios/RNSVGShape.h
Normal 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
115
ios/RNSVGShape.m
Normal 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
|
||||
13
ios/ViewManagers/RNSVGShapeManager.h
Normal file
13
ios/ViewManagers/RNSVGShapeManager.h
Normal 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
|
||||
25
ios/ViewManagers/RNSVGShapeManager.m
Normal file
25
ios/ViewManagers/RNSVGShapeManager.m
Normal 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
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
103
lib/props.js
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user