mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-21 06:15:15 +00:00
256 lines
6.1 KiB
JavaScript
256 lines
6.1 KiB
JavaScript
import Matrix2D from '../Matrix2D';
|
||
import _ from 'lodash';
|
||
let pooledMatrix = new Matrix2D();
|
||
import peg from 'pegjs';
|
||
|
||
function transformToMatrix(props, transform) {
|
||
pooledMatrix.reset();
|
||
appendTransform(props);
|
||
|
||
if (transform) {
|
||
appendTransform(transform);
|
||
}
|
||
|
||
return pooledMatrix.toArray();
|
||
}
|
||
|
||
const transformParser = peg.generate(`
|
||
{
|
||
const deg2rad = Math.PI / 180;
|
||
|
||
/*
|
||
╔═ ═╗ ╔═ ═╗ ╔═ ═╗
|
||
║ al cl el ║ ║ ar cr er ║ ║ a c e ║
|
||
║ bl dl fl ║ * ║ br dr fr ║ = ║ b d f ║
|
||
║ 0 0 1 ║ ║ 0 0 1 ║ ║ 0 0 1 ║
|
||
╚═ ═╝ ╚═ ═╝ ╚═ ═╝
|
||
*/
|
||
function multiply_matrices(l, r) {
|
||
const [al, cl, el, bl, dl, fl] = l;
|
||
const [ar, cr, er, br, dr, 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];
|
||
}
|
||
}
|
||
|
||
transformList
|
||
= wsp* ts:transforms? wsp* { return ts; }
|
||
|
||
transforms
|
||
= t:transform commaWsp* ts:transforms
|
||
{
|
||
return multiply_matrices(t, ts);
|
||
}
|
||
/ t:transform
|
||
|
||
transform
|
||
= matrix
|
||
/ translate
|
||
/ scale
|
||
/ rotate
|
||
/ skewX
|
||
/ skewY
|
||
|
||
matrix
|
||
= "matrix" wsp* "(" wsp*
|
||
a:number commaWsp
|
||
b:number commaWsp
|
||
c:number commaWsp
|
||
d:number commaWsp
|
||
e:number commaWsp
|
||
f:number wsp* ")"
|
||
{
|
||
return [
|
||
a, c, e,
|
||
b, d, f
|
||
];
|
||
}
|
||
|
||
translate
|
||
= "translate" wsp* "(" wsp* tx:number ty:commaWspNumber? wsp* ")"
|
||
{
|
||
return [
|
||
1, 0, tx,
|
||
0, 1, ty || 0
|
||
];
|
||
}
|
||
|
||
scale
|
||
= "scale" wsp* "(" wsp* sx:number sy:commaWspNumber? wsp* ")"
|
||
{
|
||
return [
|
||
sx, 0, 0,
|
||
0, sy === null ? sx : sy, 0
|
||
];
|
||
}
|
||
|
||
rotate
|
||
= "rotate" wsp* "(" wsp* angle:number c:commaWspTwoNumbers? wsp* ")"
|
||
{
|
||
const cos = Math.cos(deg2rad * angle);
|
||
const sin = Math.sin(deg2rad * angle);
|
||
if (c !== null) {
|
||
const [x, y] = c;
|
||
return [
|
||
cos, -sin, cos * -x + -sin * -y + x,
|
||
sin, cos, sin * -x + cos * -y + y
|
||
];
|
||
}
|
||
return [
|
||
cos, -sin, 0,
|
||
sin, cos, 0
|
||
];
|
||
}
|
||
|
||
skewX
|
||
= "skewX" wsp* "(" wsp* angle:number wsp* ")"
|
||
{
|
||
return [
|
||
1, Math.tan(deg2rad * angle), 0,
|
||
0, 1, 0
|
||
];
|
||
}
|
||
|
||
skewY
|
||
= "skewY" wsp* "(" wsp* angle:number wsp* ")"
|
||
{
|
||
return [
|
||
1, 0, 0,
|
||
Math.tan(deg2rad * angle), 1, 0
|
||
];
|
||
}
|
||
|
||
number
|
||
= f:(sign? floatingPointConstant) { return parseFloat(f.join("")); }
|
||
/ i:(sign? integerConstant) { return parseInt(i.join("")); }
|
||
|
||
commaWspNumber
|
||
= commaWsp n:number { return n; }
|
||
|
||
commaWspTwoNumbers
|
||
= commaWsp n1:number commaWsp n2:number { return [n1, n2]; }
|
||
|
||
commaWsp
|
||
= (wsp+ comma? wsp*) / (comma wsp*)
|
||
|
||
comma
|
||
= ","
|
||
|
||
integerConstant
|
||
= ds:digitSequence { return ds.join(""); }
|
||
|
||
floatingPointConstant
|
||
= f:(fractionalConstant exponent?) { return f.join(""); }
|
||
/ d:(digitSequence exponent) { return d.join(""); }
|
||
|
||
fractionalConstant "fractionalConstant"
|
||
= d1:digitSequence? "." d2:digitSequence { return [d1 ? d1.join("") : null, ".", d2.join("")].join(""); }
|
||
/ d:digitSequence "." { return d.join(""); }
|
||
|
||
exponent
|
||
= e:([eE] sign? digitSequence) { return [e[0], e[1], e[2].join("")].join(""); }
|
||
|
||
sign
|
||
= [+-]
|
||
|
||
digitSequence
|
||
= digit+
|
||
|
||
digit
|
||
= [0-9]
|
||
|
||
wsp
|
||
= [\\u0020\\u0009\\u000D\\u000A]
|
||
`);
|
||
|
||
function appendTransform(transform) {
|
||
if (transform) {
|
||
if (typeof transform === 'string') {
|
||
try {
|
||
const [a, c, e, b, d, f] = transformParser.parse(transform);
|
||
pooledMatrix.append(...[a, b, c, d, e, f]);
|
||
} catch (e) {
|
||
console.error(e);
|
||
}
|
||
} else {
|
||
pooledMatrix
|
||
.appendTransform(
|
||
transform.x + transform.originX,
|
||
transform.y + transform.originY,
|
||
transform.scaleX, transform.scaleY,
|
||
transform.rotation,
|
||
transform.skewX,
|
||
transform.skewY,
|
||
transform.originX,
|
||
transform.originY
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
function universal2axis(universal, axisX, axisY, defaultValue) {
|
||
let coords = [];
|
||
let x;
|
||
let y;
|
||
if (_.isString(universal)) {
|
||
coords = universal.split(/\s*,\s*/);
|
||
if (coords.length === 2) {
|
||
x = +coords[0];
|
||
y = +coords[1];
|
||
} else if (coords.length === 1) {
|
||
x = y = +coords[0];
|
||
}
|
||
} else if (_.isNumber(universal)) {
|
||
x = y = universal;
|
||
}
|
||
|
||
axisX = +axisX;
|
||
if (!isNaN(axisX)) {
|
||
x = axisX;
|
||
}
|
||
|
||
axisY = +axisY;
|
||
if (!isNaN(axisY)) {
|
||
y = axisY;
|
||
}
|
||
|
||
return [x || defaultValue || 0, y || defaultValue || 0];
|
||
}
|
||
|
||
export function props2transform(props) {
|
||
if (props && (typeof props === 'string')) {
|
||
return props;
|
||
}
|
||
let [originX, originY] = universal2axis(props.origin, props.originX, props.originY);
|
||
let [scaleX, scaleY] = universal2axis(props.scale, props.scaleX, props.scaleY, 1);
|
||
let [skewX, skewY] = universal2axis(props.skew, props.skewX, props.skewY);
|
||
let [translateX, translateY] = universal2axis(
|
||
props.translate,
|
||
_.isNil(props.translateX) ? (props.x || 0) : props.translateX,
|
||
_.isNil(props.translateY) ? (props.y || 0) : props.translateY
|
||
);
|
||
|
||
return {
|
||
rotation: +props.rotation || 0,
|
||
scaleX: scaleX,
|
||
scaleY: scaleY,
|
||
originX: originX,
|
||
originY: originY,
|
||
skewX: skewX,
|
||
skewY: skewY,
|
||
x: translateX,
|
||
y: translateY
|
||
};
|
||
}
|
||
|
||
export default function (props) {
|
||
return transformToMatrix(props2transform(props), props.transform ? props2transform(props.transform) : null);
|
||
}
|