Skip to content

Commit

Permalink
refactor(convertPaths): clean up plugin (svg#1913)
Browse files Browse the repository at this point in the history
  • Loading branch information
SethFalco authored Dec 28, 2023
1 parent f238d6a commit 433dcef
Showing 1 changed file with 36 additions and 89 deletions.
125 changes: 36 additions & 89 deletions plugins/convertPathData.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,15 @@ exports.name = 'convertPathData';
exports.description =
'optimizes path data: writes in shorter form, applies transformations';

/**
* @type {(data: number[]) => number[]}
*/
/** @type {(data: number[]) => number[]} */
let roundData;
/**
* @type {number | false}
*/
/** @type {number | false} */
let precision;
/**
* @type {number}
*/
/** @type {number} */
let error;
/**
* @type {number}
*/
/** @type {number} */
let arcThreshold;
/**
* @type {number}
*/
/** @type {number} */
let arcTolerance;

/**
Expand Down Expand Up @@ -393,16 +383,17 @@ function filters(
params,
{ isSafeToUseZ, maybeHasStrokeAndLinecap, hasMarkerMid },
) {
var stringify = data2Path.bind(null, params),
relSubpoint = [0, 0],
pathBase = [0, 0],
prev = {};
const stringify = data2Path.bind(null, params);
const relSubpoint = [0, 0];
const pathBase = [0, 0];
/** @type {any} */
let prev = {};
/** @type {Point | undefined} */
let qControlPoint;
let prevQControlPoint;

path = path.filter(function (item, index, path) {
const qPoint = qControlPoint;
qControlPoint = undefined;
const qControlPoint = prevQControlPoint;
prevQControlPoint = undefined;

let command = item.command;
let data = item.args;
Expand All @@ -415,9 +406,8 @@ function filters(
if (command === 's') {
sdata = [0, 0].concat(data);

// @ts-ignore
var pdata = prev.args,
n = pdata.length;
const pdata = prev.args;
const n = pdata.length;

// (-x, -y) of the prev tangent point relative to the current point
sdata[0] = pdata[n - 2] - pdata[n - 4];
Expand Down Expand Up @@ -464,24 +454,18 @@ function filters(
nextLonghand;

if (
// @ts-ignore
(prev.command == 'c' &&
// @ts-ignore
isConvex(prev.args) &&
// @ts-ignore
isArcPrev(prev.args, circle)) ||
// @ts-ignore
(prev.command == 'a' && prev.sdata && isArcPrev(prev.sdata, circle))
) {
// @ts-ignore
arcCurves.unshift(prev);
// @ts-ignore
arc.base = prev.base;
// @ts-ignore
arc.args[5] = arc.coords[0] - arc.base[0];
// @ts-ignore
arc.args[6] = arc.coords[1] - arc.base[1];
// @ts-ignore
var prevData = prev.command == 'a' ? prev.sdata : prev.args;
var prevAngle = findArcAngle(prevData, {
center: [
Expand All @@ -498,7 +482,7 @@ function filters(
// check if next curves are fitting the arc
for (
var j = index;
(next = path[++j]) && ~'cs'.indexOf(next.command);
(next = path[++j]) && 'cs'.includes(next.command);

) {
var nextData = next.args;
Expand Down Expand Up @@ -574,7 +558,6 @@ function filters(
relSubpoint[0] += prevArc.args[5] - prev.args[prev.args.length - 2];
// @ts-ignore
relSubpoint[1] += prevArc.args[6] - prev.args[prev.args.length - 1];
// @ts-ignore
prev.command = 'a';
// @ts-ignore
prev.args = prevArc.args;
Expand All @@ -588,11 +571,7 @@ function filters(
item.sdata = sdata.slice(); // preserve curve data for future checks
} else if (arcCurves.length - 1 - hasPrev > 0) {
// filter out consumed next items
path.splice.apply(
path,
// @ts-ignore
[index + 1, arcCurves.length - 1 - hasPrev].concat(output),
);
path.splice(index + 1, arcCurves.length - 1 - hasPrev, ...output);
}
if (!arc) return false;
command = 'a';
Expand Down Expand Up @@ -679,9 +658,7 @@ function filters(
data = data.slice(-2);
} else if (
command === 't' &&
// @ts-ignore
prev.command !== 'q' &&
// @ts-ignore
prev.command !== 't'
) {
command = 'l';
Expand Down Expand Up @@ -716,39 +693,29 @@ function filters(
params.collapseRepeated &&
hasMarkerMid === false &&
(command === 'm' || command === 'h' || command === 'v') &&
// @ts-ignore
prev.command &&
// @ts-ignore
command == prev.command.toLowerCase() &&
((command != 'h' && command != 'v') ||
// @ts-ignore
prev.args[0] >= 0 == data[0] >= 0)
) {
// @ts-ignore
prev.args[0] += data[0];
if (command != 'h' && command != 'v') {
// @ts-ignore
prev.args[1] += data[1];
}
// @ts-ignore
prev.coords = item.coords;
// @ts-ignore
path[index] = prev;
return false;
}

// convert curves into smooth shorthands
// @ts-ignore
if (params.curveSmoothShorthands && prev.command) {
// curveto
if (command === 'c') {
// c + c → c + s
if (
// @ts-ignore
prev.command === 'c' &&
// @ts-ignore
Math.abs(data[0] - -(prev.args[2] - prev.args[4])) < error &&
// @ts-ignore
Math.abs(data[1] - -(prev.args[3] - prev.args[5])) < error
) {
command = 's';
Expand All @@ -757,11 +724,8 @@ function filters(

// s + c → s + s
else if (
// @ts-ignore
prev.command === 's' &&
// @ts-ignore
Math.abs(data[0] - -(prev.args[0] - prev.args[2])) < error &&
// @ts-ignore
Math.abs(data[1] - -(prev.args[1] - prev.args[3])) < error
) {
command = 's';
Expand All @@ -770,9 +734,7 @@ function filters(

// [^cs] + c → [^cs] + s
else if (
// @ts-ignore
prev.command !== 'c' &&
// @ts-ignore
prev.command !== 's' &&
Math.abs(data[0]) < error &&
Math.abs(data[1]) < error
Expand All @@ -786,24 +748,22 @@ function filters(
else if (command === 'q') {
// q + q → q + t
if (
// @ts-ignore
prev.command === 'q' &&
// @ts-ignore
Math.abs(data[0] - (prev.args[2] - prev.args[0])) < error &&
// @ts-ignore
Math.abs(data[1] - (prev.args[3] - prev.args[1])) < error
) {
command = 't';
data = data.slice(2);
}

// t + q → t + t
else if (
// @ts-ignore
prev.command === 't'
) {
// @ts-ignore
const predictedControlPoint = reflectPoint(qPoint, item.base);
else if (prev.command === 't') {
const predictedControlPoint = reflectPoint(
// @ts-ignore
qControlPoint,
// @ts-ignore
item.base,
);
const realControlPoint = [
// @ts-ignore
data[0] + item.base[0],
Expand Down Expand Up @@ -837,14 +797,12 @@ function filters(
return i === 0;
})
) {
// @ts-ignore
path[index] = prev;
return false;
}

// a 25,25 -30 0,1 0,0
if (command === 'a' && data[5] === 0 && data[6] === 0) {
// @ts-ignore
path[index] = prev;
return false;
}
Expand Down Expand Up @@ -874,7 +832,6 @@ function filters(
// z resets coordinates
relSubpoint[0] = pathBase[0];
relSubpoint[1] = pathBase[1];
// @ts-ignore
if (prev.command === 'Z' || prev.command === 'z') return false;
}
if (
Expand All @@ -890,14 +847,14 @@ function filters(

if (command === 'q') {
// @ts-ignore
qControlPoint = [data[0] + item.base[0], data[1] + item.base[1]];
prevQControlPoint = [data[0] + item.base[0], data[1] + item.base[1]];
} else if (command === 't') {
if (qPoint) {
if (qControlPoint) {
// @ts-ignore
qControlPoint = reflectPoint(qPoint, item.base);
prevQControlPoint = reflectPoint(qControlPoint, item.base);
} else {
// @ts-ignore
qControlPoint = item.coords;
prevQControlPoint = item.coords;
}
}
prev = item;
Expand Down Expand Up @@ -971,8 +928,9 @@ function convertToMixed(path, params) {
prev.command.charCodeAt(0) > 96 &&
absoluteDataStr.length == relativeDataStr.length - 1 &&
(data[0] < 0 ||
// @ts-ignore
(/^0\./.test(data[0]) && prev.args[prev.args.length - 1] % 1))
(Math.floor(data[0]) === 0 &&
!Number.isInteger(data[0]) &&
prev.args[prev.args.length - 1] % 1))
))
) {
// @ts-ignore
Expand All @@ -981,7 +939,6 @@ function convertToMixed(path, params) {
}

prev = item;

return true;
});

Expand Down Expand Up @@ -1098,7 +1055,6 @@ function round(data) {
*
* @type {(data: number[]) => boolean}
*/

function isCurveStraightLine(data) {
// Get line equation a·x + b·y + c = 0 coefficients a, b (c = 0) by start and end points.
var i = data.length - 2,
Expand All @@ -1125,7 +1081,6 @@ function isCurveStraightLine(data) {
*/
function calculateSagitta(data) {
if (data[3] === 1) return undefined;

const [rx, ry] = data;
if (Math.abs(rx - ry) > error) return undefined;
const chord = Math.sqrt(data[5] ** 2 + data[6] ** 2);
Expand All @@ -1138,7 +1093,6 @@ function calculateSagitta(data) {
*
* @type {(item: PathDataItem, data: number[]) => PathDataItem}
*/

function makeLonghand(item, data) {
switch (item.command) {
case 's':
Expand All @@ -1160,20 +1114,19 @@ function makeLonghand(item, data) {
*
* @type {(point1: Point, point2: Point) => number}
*/

function getDistance(point1, point2) {
return Math.hypot(point1[0] - point2[0], point1[1] - point2[1]);
return Math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2);
}

/**
* Reflects point across another point
* Reflects point across another point.
*
* @param {Point} input
* @param {Point} controlPoint
* @param {Point} base
* @returns {Point}
*/
function reflectPoint(input, base) {
return [2 * base[0] - input[0], 2 * base[1] - input[1]];
function reflectPoint(controlPoint, base) {
return [2 * base[0] - controlPoint[0], 2 * base[1] - controlPoint[1]];
}

/**
Expand All @@ -1183,7 +1136,6 @@ function reflectPoint(input, base) {
*
* @type {(curve: number[], t: number) => Point}
*/

function getCubicBezierPoint(curve, t) {
var sqrT = t * t,
cubT = sqrT * t,
Expand All @@ -1201,7 +1153,6 @@ function getCubicBezierPoint(curve, t) {
*
* @type {(curve: number[]) => undefined | Circle}
*/

function findCircle(curve) {
var midPoint = getCubicBezierPoint(curve, 1 / 2),
m1 = [midPoint[0] / 2, midPoint[1] / 2],
Expand Down Expand Up @@ -1242,7 +1193,6 @@ function findCircle(curve) {
*
* @type {(curve: number[], circle: Circle) => boolean}
*/

function isArc(curve, circle) {
var tolerance = Math.min(
arcThreshold * error,
Expand All @@ -1264,7 +1214,6 @@ function isArc(curve, circle) {
*
* @type {(curve: number[], circle: Circle) => boolean}
*/

function isArcPrev(curve, circle) {
return isArc(curve, {
center: [circle.center[0] + curve[4], circle.center[1] + curve[5]],
Expand All @@ -1277,7 +1226,6 @@ function isArcPrev(curve, circle) {
* @type {(curve: number[], relCircle: Circle) => number}
*/

function findArcAngle(curve, relCircle) {
var x1 = -relCircle.center[0],
y1 = -relCircle.center[1],
Expand All @@ -1294,7 +1242,6 @@ function findArcAngle(curve, relCircle) {
*
* @type {(params: InternalParams, pathData: PathDataItem[]) => string}
*/

function data2Path(params, pathData) {
return pathData.reduce(function (pathString, item) {
var strData = '';
Expand Down

0 comments on commit 433dcef

Please sign in to comment.