svg-path-d
Version:
SVG path data (path[d] attribute content) manipulation library.
209 lines • 7.54 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeInterpolator = exports.align = void 0;
var math1d_1 = require("./utils/math1d");
var arc_node_1 = require("./arc-node");
var command_assertion_1 = require("./command-assertion");
var path_node_1 = require("./path-node");
var promoter_1 = require("./promoter");
var splitter_1 = require("./splitter");
var builder_1 = require("./builder");
function stretch(pathGroup, size) {
var first = pathGroup[0];
if (!(first && command_assertion_1.isMoveTo(first))) {
throw new Error('First node in a path group should be MoveTo!');
}
var items = [__assign({}, first)];
var a = pathGroup.length - 1;
var b = size - 1;
if (a > 0) {
// Splitting existing nodes.
var r = b % a;
var n = (b - r) / a;
for (var i = 1; i <= a; i++) {
var node = pathGroup[i];
var x = i <= r ? n + 1 : n;
if (x > 1) {
items.push.apply(items, splitter_1.split(node, x));
}
else {
items.push(__assign({}, node));
}
}
}
else {
// Adding empty nodes.
for (var i = 0; i < b; i++) {
items.push({ name: 'L', x: first.x, y: first.y });
}
}
return path_node_1.makePath(items);
}
function alignGroups(groupA, groupB) {
var count = Math.max(groupA.length, groupB.length);
if (groupA.length < count) {
groupA = stretch(groupA, count);
}
else if (groupB.length < count) {
groupB = stretch(groupB, count);
}
var itemsA = [];
var itemsB = [];
for (var i = 0; i < count; i++) {
var a = groupA[i];
var b = groupB[i];
if (a.name === b.name) {
itemsA.push(__assign({}, a));
itemsB.push(__assign({}, b));
}
else if (command_assertion_1.isLineTo(a) && command_assertion_1.isQCurveTo(b)) {
itemsA.push(promoter_1.promoteToQCurve(a));
itemsB.push(__assign({}, b));
}
else if (command_assertion_1.isLineTo(b) && command_assertion_1.isQCurveTo(a)) {
itemsA.push(__assign({}, a));
itemsB.push(promoter_1.promoteToQCurve(b));
}
else {
itemsA.push(promoter_1.canPromoteToCurve(a) ? promoter_1.promoteToCurve(a) : __assign({}, a));
itemsB.push(promoter_1.canPromoteToCurve(b) ? promoter_1.promoteToCurve(b) : __assign({}, b));
}
}
return [path_node_1.makePath(itemsA), path_node_1.makePath(itemsB)];
}
// type SimpleNode = (MoveTo | LineTo | QCurveTo | CurveTo) & { prev: SimpleNode };
function normalize(path) {
var items = [];
// Let's start with a MoveTo node.
if (path.length <= 0 || !command_assertion_1.isMoveTo(path[0])) {
items.push({ name: 'M', x: 0, y: 0 });
}
// Get rid of EllipticalArcs and ClosePaths.
// Promote H/V Lines and Smooth Bezier Curves.
for (var _i = 0, path_1 = path; _i < path_1.length; _i++) {
var node = path_1[_i];
if (command_assertion_1.isEllipticalArc(node)) {
items.push.apply(items, arc_node_1.approximateEllipticalArc(node));
}
else if (command_assertion_1.isClosePath(node)) {
var prev = node.prev;
var x0 = path_node_1.getX(prev);
var y0 = path_node_1.getY(prev);
var x = path_node_1.getX(node);
var y = path_node_1.getY(node);
if (x0 !== x || y0 !== y) {
items.push({ name: 'L', x: x, y: y, prev: prev });
}
}
else if (command_assertion_1.isHLineTo(node) || command_assertion_1.isVLineTo(node)) {
items.push(promoter_1.promoteToLine(node));
}
else if (command_assertion_1.isSmoothCurveTo(node)) {
items.push(promoter_1.promoteToCurve(node));
}
else if (command_assertion_1.isSmoothQCurveTo(node)) {
items.push(promoter_1.promoteToQCurve(node));
}
else {
items.push(__assign({}, node));
}
}
return path_node_1.makePath(items);
}
function addEmptyGroups(groups, count, stopPoints) {
for (var i = 0; i < count; i++) {
var lastGroup = groups[groups.length - 1];
var prev = lastGroup[lastGroup.length - 1];
var x = void 0;
var y = void 0;
if (stopPoints && stopPoints.length > i) {
x = stopPoints[i].x;
y = stopPoints[i].y;
}
else {
x = path_node_1.getX(prev);
y = path_node_1.getY(prev);
}
groups.push([{ name: 'M', x: x, y: y, prev: prev }]);
}
}
function align(src, dst, options) {
var srcGroups = splitter_1.getGroups(normalize(src));
var dstGroups = splitter_1.getGroups(normalize(dst));
var count = srcGroups.length - dstGroups.length;
if (count < 0) {
addEmptyGroups(srcGroups, -count, options === null || options === void 0 ? void 0 : options.groupClosePoints);
}
else if (count > 0) {
addEmptyGroups(dstGroups, count, options === null || options === void 0 ? void 0 : options.groupClosePoints);
}
var size = srcGroups.length;
var itemsA = [];
var itemsB = [];
for (var i = 0; i < size; i++) {
var _a = alignGroups(srcGroups[i], dstGroups[i]), a = _a[0], b = _a[1];
itemsA.push.apply(itemsA, a);
itemsB.push.apply(itemsB, b);
}
return [path_node_1.makePath(itemsA), path_node_1.makePath(itemsB)];
}
exports.align = align;
var ARGS_COUNT = {
Z: 0,
H: 1,
V: 1,
L: 2,
M: 2,
T: 2,
Q: 4,
S: 4,
C: 6,
A: 7,
};
function toPathArray(commands, params, formatter) {
var path = [];
var i = 0;
for (var _i = 0, commands_1 = commands; _i < commands_1.length; _i++) {
var c = commands_1[_i];
var buf = c;
for (var j = i + ARGS_COUNT[c]; i < j; i++) {
buf += ' ' + (formatter ? formatter(params[i]) : params[i].toString());
}
path.push(buf);
}
return path;
}
function makeInterpolator(src, dst, options) {
var commands = [];
var srcParams = [];
var dstParams = [];
var _a = align(src, dst, options), a = _a[0], b = _a[1];
for (var i = 0; i < a.length; i++) {
commands.push(a[i].name);
builder_1.getParams(a[i], srcParams);
builder_1.getParams(b[i], dstParams);
}
return function (t) {
var params = srcParams;
if (t >= 1) {
params = dstParams;
}
else if (t > 0) {
params = srcParams.map(function (value, index) { return math1d_1.lerp(value, dstParams[index], t); });
}
return toPathArray(commands, params, options === null || options === void 0 ? void 0 : options.formatter);
};
}
exports.makeInterpolator = makeInterpolator;
//# sourceMappingURL=interpolator.js.map