mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-21 06:15:15 +00:00
Add Symbol element refactor viewbox
Add Symbol element refactor viewbox
This commit is contained in:
@@ -10,6 +10,7 @@ import * as Text from './examples/Text';
|
|||||||
import * as G from './examples/G';
|
import * as G from './examples/G';
|
||||||
import * as Stroking from './examples/Stroking';
|
import * as Stroking from './examples/Stroking';
|
||||||
import * as Use from './examples/Use';
|
import * as Use from './examples/Use';
|
||||||
|
import * as Symbol from './examples/Symbol';
|
||||||
import * as Gradients from './examples/Gradients';
|
import * as Gradients from './examples/Gradients';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -25,5 +26,6 @@ export {
|
|||||||
Stroking,
|
Stroking,
|
||||||
G,
|
G,
|
||||||
Use,
|
Use,
|
||||||
|
Symbol,
|
||||||
Gradients
|
Gradients
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ class SvgViewbox extends Component{
|
|||||||
height="100"
|
height="100"
|
||||||
width="100"
|
width="100"
|
||||||
viewbox="40 20 100 40"
|
viewbox="40 20 100 40"
|
||||||
|
preserveAspectRatio="none"
|
||||||
>
|
>
|
||||||
<Rect x="0" y="0" width="100" height="100" fill="black" />
|
<Rect x="0" y="0" width="100" height="100" fill="black" />
|
||||||
<Circle cx="50" cy="50" r="30" fill="yellow" />
|
<Circle cx="50" cy="50" r="30" fill="yellow" />
|
||||||
|
|||||||
79
Example/examples/Symbol.js
Normal file
79
Example/examples/Symbol.js
Normal 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
|
||||||
|
}
|
||||||
@@ -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 {
|
class ArtSvgExample extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -5,74 +5,14 @@ import React, {
|
|||||||
Children,
|
Children,
|
||||||
cloneElement
|
cloneElement
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
import extractViewbox from '../lib/extractViewbox';
|
||||||
|
import ViewBox from './ViewBox';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
let {
|
let {
|
||||||
Surface,
|
Surface,
|
||||||
Group
|
Group
|
||||||
} = ART;
|
} = 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;
|
let id = 0;
|
||||||
|
|
||||||
class Svg extends Component{
|
class Svg extends Component{
|
||||||
@@ -101,36 +41,33 @@ class Svg extends Component{
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let opacity = +this.props.opacity;
|
let {props} = this;
|
||||||
let viewbox = extractViewbox(this.props);
|
let opacity = +props.opacity;
|
||||||
if (viewbox) {
|
if (props.viewbox) {
|
||||||
let {scaleX, scaleY} = viewbox;
|
|
||||||
|
|
||||||
return <Surface
|
return <Surface
|
||||||
{...this.props}
|
{...props}
|
||||||
style={[
|
style={[
|
||||||
this.props.style,
|
props.style,
|
||||||
!isNaN(opacity) && {
|
!isNaN(opacity) && {
|
||||||
opacity: opacity
|
opacity: opacity
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{(!scaleX || !scaleY) ? null :
|
<ViewBox
|
||||||
<Group
|
viewbox={props.viewbox}
|
||||||
x={viewbox.x}
|
preserveAspectRatio={props.preserveAspectRatio}
|
||||||
y={viewbox.y}
|
width={props.width}
|
||||||
scaleX={scaleX}
|
height={props.height}
|
||||||
scaleY={scaleY}
|
|
||||||
>
|
>
|
||||||
{this.getChildren()}
|
{this.getChildren()}
|
||||||
</Group>}
|
</ViewBox>
|
||||||
</Surface>;
|
</Surface>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Surface
|
return <Surface
|
||||||
{...this.props}
|
{...props}
|
||||||
style={[
|
style={[
|
||||||
this.props.style,
|
props.style,
|
||||||
!isNaN(opacity) && {
|
!isNaN(opacity) && {
|
||||||
opacity: opacity
|
opacity: opacity
|
||||||
}
|
}
|
||||||
|
|||||||
34
elements/Symbol.js
Normal file
34
elements/Symbol.js
Normal 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
47
elements/ViewBox.js
Normal 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;
|
||||||
2
index.js
2
index.js
@@ -13,6 +13,7 @@ import Path from './elements/Path';
|
|||||||
import G from './elements/G';
|
import G from './elements/G';
|
||||||
import Text from './elements/Text';
|
import Text from './elements/Text';
|
||||||
import Use from './elements/Use';
|
import Use from './elements/Use';
|
||||||
|
import Symbol from './elements/Symbol';
|
||||||
import Defs from './elements/Defs';
|
import Defs from './elements/Defs';
|
||||||
import LinearGradient from './elements/LinearGradient';
|
import LinearGradient from './elements/LinearGradient';
|
||||||
import RadialGradient from './elements/RadialGradient';
|
import RadialGradient from './elements/RadialGradient';
|
||||||
@@ -35,6 +36,7 @@ export {
|
|||||||
Line,
|
Line,
|
||||||
Rect,
|
Rect,
|
||||||
Use,
|
Use,
|
||||||
|
Symbol,
|
||||||
Defs,
|
Defs,
|
||||||
LinearGradient,
|
LinearGradient,
|
||||||
RadialGradient,
|
RadialGradient,
|
||||||
|
|||||||
71
lib/extractViewbox.js
Normal file
71
lib/extractViewbox.js
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user