@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering
290 lines • 9.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSVGPoint = createSVGPoint;
exports.createSVGMatrix = createSVGMatrix;
exports.createSVGTransform = createSVGTransform;
exports.transformStringToMatrix = transformStringToMatrix;
exports.matrixToTransformString = matrixToTransformString;
exports.parseTransformString = parseTransformString;
exports.decomposeMatrix = decomposeMatrix;
exports.matrixToScale = matrixToScale;
exports.matrixToRotation = matrixToRotation;
exports.matrixToTranslation = matrixToTranslation;
const elem_1 = require("./elem");
const transformRegex = /(\w+)\(([^,)]+),?([^)]+)?\)/gi;
const transformSeparatorRegex = /[ ,]+/;
const transformationListRegex = /^(\w+)\((.*)\)/;
/**
* Returns a SVG point object initialized with the `x` and `y` coordinates.
* @see https://developer.mozilla.org/en/docs/Web/API/SVGPoint
*/
function createSVGPoint(x, y) {
const svgDocument = (0, elem_1.createSvgElement)('svg');
const p = svgDocument.createSVGPoint();
p.x = x;
p.y = y;
return p;
}
/**
* Returns the SVG transformation matrix initialized with the given matrix.
*
* The given matrix is an object of the form:
* {
* a: number
* b: number
* c: number
* d: number
* e: number
* f: number
* }
*
* @see https://developer.mozilla.org/en/docs/Web/API/SVGMatrix
*/
function createSVGMatrix(matrix) {
const svgDocument = (0, elem_1.createSvgElement)('svg');
const mat = svgDocument.createSVGMatrix();
if (matrix != null) {
const source = matrix;
const items = ['a', 'b', 'c', 'd', 'e', 'f'];
for (const key of items) {
if (source[key] === undefined) {
continue;
}
mat[key] = source[key];
}
}
return mat;
}
/**
* Returns a SVG transform object.
* @see https://developer.mozilla.org/en/docs/Web/API/SVGTransform
*/
function createSVGTransform(matrix) {
const svgDocument = (0, elem_1.createSvgElement)('svg');
if (matrix != null) {
if (!(matrix instanceof DOMMatrix)) {
matrix = createSVGMatrix(matrix); // eslint-disable-line
}
return svgDocument.createSVGTransformFromMatrix(matrix);
}
return svgDocument.createSVGTransform();
}
/**
* Returns the SVG transformation matrix built from the `transformString`.
*
* E.g. 'translate(10,10) scale(2,2)' will result in matrix:
* `{ a: 2, b: 0, c: 0, d: 2, e: 10, f: 10}`
*/
function transformStringToMatrix(transform) {
let mat = createSVGMatrix();
const matches = transform != null && transform.match(transformRegex);
if (!matches) {
return mat;
}
for (let i = 0, n = matches.length; i < n; i += 1) {
const transformationString = matches[i];
const transformationMatch = transformationString.match(transformationListRegex);
if (transformationMatch) {
let sx;
let sy;
let tx;
let ty;
let angle;
let ctm = createSVGMatrix();
const args = transformationMatch[2].split(transformSeparatorRegex);
switch (transformationMatch[1].toLowerCase()) {
case 'scale':
sx = parseFloat(args[0]);
sy = args[1] === undefined ? sx : parseFloat(args[1]);
ctm = ctm.scaleNonUniform(sx, sy);
break;
case 'translate':
tx = parseFloat(args[0]);
ty = parseFloat(args[1]);
ctm = ctm.translate(tx, ty);
break;
case 'rotate':
angle = parseFloat(args[0]);
tx = parseFloat(args[1]) || 0;
ty = parseFloat(args[2]) || 0;
if (tx !== 0 || ty !== 0) {
ctm = ctm.translate(tx, ty).rotate(angle).translate(-tx, -ty);
}
else {
ctm = ctm.rotate(angle);
}
break;
case 'skewx':
angle = parseFloat(args[0]);
ctm = ctm.skewX(angle);
break;
case 'skewy':
angle = parseFloat(args[0]);
ctm = ctm.skewY(angle);
break;
case 'matrix':
ctm.a = parseFloat(args[0]);
ctm.b = parseFloat(args[1]);
ctm.c = parseFloat(args[2]);
ctm.d = parseFloat(args[3]);
ctm.e = parseFloat(args[4]);
ctm.f = parseFloat(args[5]);
break;
default:
continue;
}
mat = mat.multiply(ctm);
}
}
return mat;
}
function matrixToTransformString(matrix) {
const m = matrix || {};
const a = m.a != null ? m.a : 1;
const b = m.b != null ? m.b : 0;
const c = m.c != null ? m.c : 0;
const d = m.d != null ? m.d : 1;
const e = m.e != null ? m.e : 0;
const f = m.f != null ? m.f : 0;
return `matrix(${a},${b},${c},${d},${e},${f})`;
}
function parseTransformString(transform) {
let translation;
let rotation;
let scale;
if (transform) {
const separator = transformSeparatorRegex;
// Allow reading transform string with a single matrix
if (transform.trim().indexOf('matrix') >= 0) {
const matrix = transformStringToMatrix(transform);
const decomposedMatrix = decomposeMatrix(matrix);
translation = [decomposedMatrix.translateX, decomposedMatrix.translateY];
rotation = [decomposedMatrix.rotation];
scale = [decomposedMatrix.scaleX, decomposedMatrix.scaleY];
const transformations = [];
if (translation[0] !== 0 || translation[1] !== 0) {
transformations.push(`translate(${translation.join(',')})`);
}
if (scale[0] !== 1 || scale[1] !== 1) {
transformations.push(`scale(${scale.join(',')})`);
}
if (rotation[0] !== 0) {
transformations.push(`rotate(${rotation[0]})`);
}
transform = transformations.join(' '); // eslint-disable-line
}
else {
const translateMatch = transform.match(/translate\((.*?)\)/);
if (translateMatch) {
translation = translateMatch[1].split(separator);
}
const rotateMatch = transform.match(/rotate\((.*?)\)/);
if (rotateMatch) {
rotation = rotateMatch[1].split(separator);
}
const scaleMatch = transform.match(/scale\((.*?)\)/);
if (scaleMatch) {
scale = scaleMatch[1].split(separator);
}
}
}
const sx = scale && scale[0] ? parseFloat(scale[0]) : 1;
return {
raw: transform || '',
translation: {
tx: translation && translation[0]
? parseInt(translation[0], 10)
: 0,
ty: translation && translation[1]
? parseInt(translation[1], 10)
: 0,
},
rotation: {
angle: rotation && rotation[0] ? parseInt(rotation[0], 10) : 0,
cx: rotation && rotation[1]
? parseInt(rotation[1], 10)
: undefined,
cy: rotation && rotation[2]
? parseInt(rotation[2], 10)
: undefined,
},
scale: {
sx,
sy: scale && scale[1] ? parseFloat(scale[1]) : sx,
},
};
}
function deltaTransformPoint(matrix, point) {
const dx = point.x * matrix.a + point.y * matrix.c + 0;
const dy = point.x * matrix.b + point.y * matrix.d + 0;
return { x: dx, y: dy };
}
/**
* Decomposes the SVG transformation matrix into separate transformations.
*
* Returns an object of the form:
* {
* translateX: number
* translateY: number
* scaleX: number
* scaleY: number
* skewX: number
* skewY: number
* rotation: number
* }
*
* @see https://developer.mozilla.org/en/docs/Web/API/SVGMatrix
*/
function decomposeMatrix(matrix) {
// @see https://gist.github.com/2052247
const px = deltaTransformPoint(matrix, { x: 0, y: 1 });
const py = deltaTransformPoint(matrix, { x: 1, y: 0 });
const skewX = (180 / Math.PI) * Math.atan2(px.y, px.x) - 90;
const skewY = (180 / Math.PI) * Math.atan2(py.y, py.x);
return {
skewX,
skewY,
translateX: matrix.e,
translateY: matrix.f,
scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
rotation: skewX,
};
}
function matrixToScale(matrix) {
let a;
let b;
let c;
let d;
if (matrix) {
a = matrix.a == null ? 1 : matrix.a;
d = matrix.d == null ? 1 : matrix.d;
b = matrix.b;
c = matrix.c;
}
else {
a = d = 1;
}
return {
sx: b ? Math.sqrt(a * a + b * b) : a,
sy: c ? Math.sqrt(c * c + d * d) : d,
};
}
function matrixToRotation(matrix) {
let p = { x: 0, y: 1 };
if (matrix) {
p = deltaTransformPoint(matrix, p);
}
const deg = (((180 * Math.atan2(p.y, p.x)) / Math.PI) % 360) - 90;
const angle = (deg % 360) + (deg < 0 ? 360 : 0);
return {
angle,
};
}
function matrixToTranslation(matrix) {
return {
tx: (matrix && matrix.e) || 0,
ty: (matrix && matrix.f) || 0,
};
}
//# sourceMappingURL=matrix.js.map