react-native-svg
Version:
SVG library for react-native
310 lines (308 loc) • 6.75 kB
JavaScript
/* eslint-disable @typescript-eslint/no-var-requires */
import { Component } from 'react';
import SvgTouchableMixin from '../lib/SvgTouchableMixin';
import extractBrush from '../lib/extract/extractBrush';
import { findNodeHandle } from 'react-native';
import { BrushProperties } from '../lib/extract/colors';
export function multiplyMatrices(l, r) {
const {
a: al,
b: bl,
c: cl,
d: dl,
e: el,
f: fl
} = l;
const {
a: ar,
b: br,
c: cr,
d: dr,
e: er,
f: fr
} = r;
const a = al * ar + cl * br;
const c = al * cr + cl * dr;
const e = al * er + cl * fr + el;
const b = bl * ar + dl * br;
const d = bl * cr + dl * dr;
const f = bl * er + dl * fr + fl;
return {
a,
c,
e,
b,
d,
f
};
}
export function invert({
a,
b,
c,
d,
e,
f
}) {
const n = a * d - b * c;
return {
a: d / n,
b: -b / n,
c: -c / n,
d: a / n,
e: (c * f - d * e) / n,
f: -(a * f - b * e) / n
};
}
const deg2rad = Math.PI / 180;
export class SVGMatrix {
constructor(matrix) {
if (matrix) {
const {
a,
b,
c,
d,
e,
f
} = matrix;
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
this.f = f;
} else {
this.a = 1;
this.b = 0;
this.c = 0;
this.d = 1;
this.e = 0;
this.f = 0;
}
}
multiply(secondMatrix) {
return new SVGMatrix(multiplyMatrices(this, secondMatrix));
}
inverse() {
return new SVGMatrix(invert(this));
}
translate(x, y) {
return new SVGMatrix(multiplyMatrices(this, {
a: 1,
b: 0,
c: 0,
d: 1,
e: x,
f: y
}));
}
scale(scaleFactor) {
return new SVGMatrix(multiplyMatrices(this, {
a: scaleFactor,
b: 0,
c: 0,
d: scaleFactor,
e: 0,
f: 0
}));
}
scaleNonUniform(scaleFactorX, scaleFactorY) {
return new SVGMatrix(multiplyMatrices(this, {
a: scaleFactorX,
b: 0,
c: 0,
d: scaleFactorY,
e: 0,
f: 0
}));
}
rotate(angle) {
const cos = Math.cos(deg2rad * angle);
const sin = Math.sin(deg2rad * angle);
return new SVGMatrix(multiplyMatrices(this, {
a: cos,
b: sin,
c: -sin,
d: cos,
e: 0,
f: 0
}));
}
rotateFromVector(x, y) {
const angle = Math.atan2(y, x);
const cos = Math.cos(deg2rad * angle);
const sin = Math.sin(deg2rad * angle);
return new SVGMatrix(multiplyMatrices(this, {
a: cos,
b: sin,
c: -sin,
d: cos,
e: 0,
f: 0
}));
}
flipX() {
return new SVGMatrix(multiplyMatrices(this, {
a: -1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0
}));
}
flipY() {
return new SVGMatrix(multiplyMatrices(this, {
a: 1,
b: 0,
c: 0,
d: -1,
e: 0,
f: 0
}));
}
skewX(angle) {
return new SVGMatrix(multiplyMatrices(this, {
a: 1,
b: 0,
c: Math.tan(deg2rad * angle),
d: 1,
e: 0,
f: 0
}));
}
skewY(angle) {
return new SVGMatrix(multiplyMatrices(this, {
a: 1,
b: Math.tan(deg2rad * angle),
c: 0,
d: 1,
e: 0,
f: 0
}));
}
}
export function matrixTransform(matrix, point) {
const {
a,
b,
c,
d,
e,
f
} = matrix;
const {
x,
y
} = point;
return {
x: a * x + c * y + e,
y: b * x + d * y + f
};
}
export class SVGPoint {
constructor(point) {
if (point) {
const {
x,
y
} = point;
this.x = x;
this.y = y;
} else {
this.x = 0;
this.y = 0;
}
}
matrixTransform(matrix) {
return new SVGPoint(matrixTransform(matrix, this));
}
}
export const ownerSVGElement = {
createSVGPoint() {
return new SVGPoint();
},
createSVGMatrix() {
return new SVGMatrix();
}
};
export default class Shape extends Component {
root = null;
constructor(props) {
super(props);
SvgTouchableMixin(this);
}
refMethod = instance => {
this.root = instance;
};
// Hack to make Animated work with Shape components.
getNativeScrollRef() {
return this.root;
}
setNativeProps = props => {
var _this$root;
for (const key in props) {
if (BrushProperties.includes(key)) {
// @ts-ignore TypeScript doesn't know that `key` is a key of `props`
props[key] = extractBrush(props[key]);
}
}
(_this$root = this.root) === null || _this$root === void 0 || _this$root.setNativeProps(props);
};
/*
* The following native methods are experimental and likely broken in some
* ways. If you have a use case for these, please open an issue with a
* representative example / reproduction.
* */
getBBox = options => {
const {
fill = true,
stroke = true,
markers = true,
clipped = true
} = options || {};
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule = require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.getBBox(handle, {
fill,
stroke,
markers,
clipped
});
};
getCTM = () => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule = require('../fabric/NativeSvgRenderableModule').default;
return new SVGMatrix(RNSVGRenderableModule.getCTM(handle));
};
getScreenCTM = () => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule = require('../fabric/NativeSvgRenderableModule').default;
return new SVGMatrix(RNSVGRenderableModule.getScreenCTM(handle));
};
isPointInFill = options => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule = require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.isPointInFill(handle, options);
};
isPointInStroke = options => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule = require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.isPointInStroke(handle, options);
};
getTotalLength = () => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule = require('../fabric/NativeSvgRenderableModule').default;
return RNSVGRenderableModule.getTotalLength(handle);
};
getPointAtLength = length => {
const handle = findNodeHandle(this.root);
const RNSVGRenderableModule = require('../fabric/NativeSvgRenderableModule').default;
return new SVGPoint(RNSVGRenderableModule.getPointAtLength(handle, {
length
}));
};
}
Shape.prototype.ownerSVGElement = ownerSVGElement;
//# sourceMappingURL=Shape.js.map