Add Symbol element refactor viewbox

Add Symbol element refactor viewbox
This commit is contained in:
Horcrux
2016-01-25 18:07:06 +08:00
parent 2556c2537e
commit 50b941c4bc
9 changed files with 256 additions and 83 deletions

View File

@@ -10,6 +10,7 @@ import * as Text from './examples/Text';
import * as G from './examples/G';
import * as Stroking from './examples/Stroking';
import * as Use from './examples/Use';
import * as Symbol from './examples/Symbol';
import * as Gradients from './examples/Gradients';
export {
@@ -25,5 +26,6 @@ export {
Stroking,
G,
Use,
Symbol,
Gradients
};

View File

@@ -72,6 +72,7 @@ class SvgViewbox extends Component{
height="100"
width="100"
viewbox="40 20 100 40"
preserveAspectRatio="none"
>
<Rect x="0" y="0" width="100" height="100" fill="black" />
<Circle cx="50" cy="50" r="30" fill="yellow" />

View File

@@ -0,0 +1,79 @@
import React, {
Component
} from 'react-native';
import Svg, {
Symbol,
Circle,
Use
} from 'react-native-art-svg';
class SymbolExample extends Component{
static title = 'Symbol example';
render() {
return <Svg
height="150"
width="110"
>
<Symbol id="symbol" viewbox="0 0 150 110">
<Circle cx="50" cy="50" r="40" strokeWidth="8" stroke="red" fill="red"/>
<Circle cx="90" cy="60" r="40" strokeWidth="8" stroke="green" fill="white"/>
</Symbol>
<Use
href="#symbol"
x="0"
y="0"
width="100"
height="50"
/>
<Use
href="#symbol"
x="0"
y="50"
width="75"
height="38"
/>
<Use
href="#symbol"
x="0"
y="100"
width="50"
height="25"
/>
</Svg>;
}
}
const icon = <Svg
height="20"
width="20"
>
<Symbol id="symbol" viewbox="0 0 150 110">
<Circle cx="50" cy="50" r="40" strokeWidth="8" stroke="red" fill="red"/>
<Circle cx="90" cy="60" r="40" strokeWidth="8" stroke="green" fill="white"/>
</Symbol>
<Use
href="#symbol"
x="0"
y="0"
width="20"
height="10"
/>
<Use
href="#symbol"
x="0"
y="12"
width="20"
height="8"
/>
</Svg>;
const samples = [SymbolExample];
export {
icon,
samples
}

View File

@@ -104,7 +104,7 @@ const styles = StyleSheet.create({
}
});
const names = ['Svg', 'Stroking', 'Path', 'Line', 'Rect', 'Polygon', 'Polyline', 'Circle', 'Ellipse', 'G', 'Text', 'Use', 'Gradients'];
const names = ['Svg', 'Stroking', 'Path', 'Line', 'Rect', 'Polygon', 'Polyline', 'Circle', 'Ellipse', 'G', 'Text', 'Use', 'Symbol', 'Gradients'];
class ArtSvgExample extends Component {
constructor() {

View File

@@ -5,74 +5,14 @@ import React, {
Children,
cloneElement
} from 'react-native';
import extractViewbox from '../lib/extractViewbox';
import ViewBox from './ViewBox';
import _ from 'lodash';
let {
Surface,
Group
} = ART;
function extractViewbox({viewbox, width, height, preserveAspectRatio}) {
if (!viewbox || !width || !height) {
return false;
}
if (typeof viewbox === 'string') {
let parts = viewbox.trim().split(/\s+/);
let vw = +parts[2];
let vh = +parts[3];
// width or height can`t be negative
if (vw < 0 || vh < 0 || parts.length !== 4) {
return false;
}
// width or height equals zero disable render
if (!vw || !vh) {
return {
x: 0,
y: 0,
scaleX: 0,
scaleY: 0
}
}
let vx = +parts[0] || 0;
let vy = +parts[1] || 0;
let preserve = preserveAspectRatio !== 'none';
let scaleX = 1;
let scaleY = 1;
let x = 0;
let y = 0;
let sx = width / vw;
let sy = height / vh;
if (preserve) {
scaleX = sx;
scaleY = sy;
x = -vx * sx;
y = -vy * sy;
} else {
scaleX = scaleY = Math.min(sx, sy);
x = width / 2 - Math.min(vw, vh) * scaleX / 2 - vx * scaleX;
y = 0 - vy * scaleX;
if (sx < sy) {
[x, y] = [y, x];
}
}
return {
x,
y,
scaleX,
scaleY
};
}
return false;
}
let id = 0;
class Svg extends Component{
@@ -101,36 +41,33 @@ class Svg extends Component{
};
render() {
let opacity = +this.props.opacity;
let viewbox = extractViewbox(this.props);
if (viewbox) {
let {scaleX, scaleY} = viewbox;
let {props} = this;
let opacity = +props.opacity;
if (props.viewbox) {
return <Surface
{...this.props}
{...props}
style={[
this.props.style,
props.style,
!isNaN(opacity) && {
opacity: opacity
}
]}
>
{(!scaleX || !scaleY) ? null :
<Group
x={viewbox.x}
y={viewbox.y}
scaleX={scaleX}
scaleY={scaleY}
<ViewBox
viewbox={props.viewbox}
preserveAspectRatio={props.preserveAspectRatio}
width={props.width}
height={props.height}
>
{this.getChildren()}
</Group>}
</ViewBox>
</Surface>;
}
return <Surface
{...this.props}
{...props}
style={[
this.props.style,
props.style,
!isNaN(opacity) && {
opacity: opacity
}

34
elements/Symbol.js Normal file
View File

@@ -0,0 +1,34 @@
import React, {
Component,
PropTypes,
ART
} from 'react-native';
import ViewBox from './ViewBox';
import Defs from './Defs';
import extractViewbox from '../lib/extractViewbox';
class Symbol extends Component{
static displayName = 'Symbol';
static propType = {
id: PropTypes.string.isRequired
};
render() {
let {props} = this;
return <Defs.Item
id={props.id}
svgId={props.svgId}
>
<ViewBox
viewbox={props.viewbox}
preserveAspectRatio={props.preserveAspectRatio}
width={props.width}
height={props.height}
shouldTransform={true}
>
{props.children}
</ViewBox>
</Defs.Item>
}
}
export default Symbol;

47
elements/ViewBox.js Normal file
View File

@@ -0,0 +1,47 @@
import React, {
Component,
PropTypes,
ART
} from 'react-native';
let {
Shape,
} = ART;
import G from './G';
import extractViewbox from '../lib/extractViewbox';
class ViewBox extends Component{
static displayName = 'ViewBox';
static propType = {
transform: PropTypes.bool
};
static defaultProps = {
transform: false
};
render() {
let viewbox = extractViewbox(this.props);
let scaleX = 1;
let scaleY = 1;
let x = 0;
let y = 0;
if (viewbox) {
scaleX = viewbox.scaleX;
scaleY = viewbox.scaleY;
x = viewbox.x;
y = viewbox.y;
}
return <G
x={x}
y={y}
scaleX={scaleX}
scaleY={scaleY}
id={this.props.id}
svgId={this.props.svgId}
>
{(!scaleX || !scaleY) ? null : this.props.children}
</G>
}
}
export default ViewBox;

View File

@@ -13,6 +13,7 @@ import Path from './elements/Path';
import G from './elements/G';
import Text from './elements/Text';
import Use from './elements/Use';
import Symbol from './elements/Symbol';
import Defs from './elements/Defs';
import LinearGradient from './elements/LinearGradient';
import RadialGradient from './elements/RadialGradient';
@@ -35,6 +36,7 @@ export {
Line,
Rect,
Use,
Symbol,
Defs,
LinearGradient,
RadialGradient,

71
lib/extractViewbox.js Normal file
View File

@@ -0,0 +1,71 @@
export default function({viewbox, width, height, preserveAspectRatio, x: dx, y: dy, dScale, dScaleX, dScaleY, shouldTransform}) {
if (!viewbox || !width || !height) {
return false;
}
if (typeof viewbox === 'string') {
let parts = viewbox.trim().split(/\s+/);
let vw = +parts[2];
let vh = +parts[3];
// width or height can`t be negative
if (vw < 0 || vh < 0 || parts.length !== 4) {
return false;
}
// width or height equals zero disable render
if (!vw || !vh) {
return {
x: 0,
y: 0,
scaleX: 0,
scaleY: 0
}
}
let vx = +parts[0] || 0;
let vy = +parts[1] || 0;
let preserve = preserveAspectRatio !== 'none';
let scaleX = 1;
let scaleY = 1;
let x = 0;
let y = 0;
let sx = width / vw;
let sy = height / vh;
if (preserve) {
scaleX = scaleY = Math.min(sx, sy);
x = width / 2 - Math.min(vw, vh) * scaleX / 2 - vx * scaleX;
y = 0 - vy * scaleX;
if (sx < sy) {
[x, y] = [y, x];
}
} else {
scaleX = sx;
scaleY = sy;
x = -vx * sx;
y = -vy * sy;
}
if (shouldTransform) {
x += (+dx || 0);
y += (+dy || 0);
if (dScale) {
scaleX *= (+dScale || 1);
scaleY *= (+dScale || 1);
} else {
scaleX *= (+dScaleX || 1);
scaleY *= (+dScaleY || 1);
}
}
return {
x,
y,
scaleX,
scaleY
};
}
return false;
}