Skip to content

Commit

Permalink
feat(convertPathData): replace with z and remove z when optimal (#1822)
Browse files Browse the repository at this point in the history
  • Loading branch information
KTibow authored Nov 12, 2023
1 parent a9df915 commit 14bdacc
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 17 deletions.
4 changes: 4 additions & 0 deletions docs/03-plugins/convert-path-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ svgo:
lineShorthands:
description: If to convert regular lines to an explicit horizontal or vertical line where possible.
default: true
convertToZ:
description: If to convert lines that go to the start to a <code>z</code> command.
default: true
curveSmoothShorthands:
description: If to convert curves to smooth curves where possible.
default: true
Expand Down Expand Up @@ -55,6 +58,7 @@ This plugin uses multiple techniques to either reduce the number of instructions

* Convert between relative or absolute coordinates, whichever is shortest.
* Convert between commands. For example, a bézier curve that behaves like a straight line might as well use a line instruction.
* Remove redundant commands. For example, a command that moves to the current position can be removed.
* Trim redundant delimiters and leading zeros.
* Round numeric values using conventional rounding rules.

Expand Down
42 changes: 40 additions & 2 deletions plugins/convertPathData.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ let arcTolerance;
* },
* straightCurves: boolean,
* lineShorthands: boolean,
* convertToZ: boolean,
* curveSmoothShorthands: boolean,
* floatPrecision: number | false,
* transformPrecision: number,
Expand Down Expand Up @@ -95,6 +96,7 @@ exports.fn = (root, params) => {
},
straightCurves = true,
lineShorthands = true,
convertToZ = true,
curveSmoothShorthands = true,
floatPrecision = 3,
transformPrecision = 5,
Expand All @@ -116,6 +118,7 @@ exports.fn = (root, params) => {
makeArcs,
straightCurves,
lineShorthands,
convertToZ,
curveSmoothShorthands,
floatPrecision,
transformPrecision,
Expand Down Expand Up @@ -167,6 +170,12 @@ exports.fn = (root, params) => {
(computedStyle['stroke-linecap'].type === 'dynamic' ||
computedStyle['stroke-linecap'].value !== 'butt');
const maybeHasStrokeAndLinecap = maybeHasStroke && maybeHasLinecap;
const isSafeToUseZ = maybeHasStroke
? computedStyle['stroke-linecap']?.type === 'static' &&
computedStyle['stroke-linecap'].value === 'round' &&
computedStyle['stroke-linejoin']?.type === 'static' &&
computedStyle['stroke-linejoin'].value === 'round'
: true;

var data = path2js(node);

Expand All @@ -175,6 +184,7 @@ exports.fn = (root, params) => {
convertToRelative(data);

data = filters(data, newParams, {
isSafeToUseZ,
maybeHasStrokeAndLinecap,
hasMarkerMid,
});
Expand Down Expand Up @@ -371,10 +381,14 @@ const convertToRelative = (pathData) => {
* @type {(
* path: PathDataItem[],
* params: InternalParams,
* aux: { maybeHasStrokeAndLinecap: boolean, hasMarkerMid: boolean }
* aux: { isSafeToUseZ: boolean, maybeHasStrokeAndLinecap: boolean, hasMarkerMid: boolean }
* ) => PathDataItem[]}
*/
function filters(path, params, { maybeHasStrokeAndLinecap, hasMarkerMid }) {
function filters(
path,
params,
{ isSafeToUseZ, maybeHasStrokeAndLinecap, hasMarkerMid }
) {
var stringify = data2Path.bind(null, params),
relSubpoint = [0, 0],
pathBase = [0, 0],
Expand Down Expand Up @@ -664,6 +678,20 @@ function filters(path, params, { maybeHasStrokeAndLinecap, hasMarkerMid }) {
}
}

// convert going home to z
// m 0 0 h 5 v 5 l -5 -5 -> m 0 0 h 5 v 5 z
if (
params.convertToZ &&
(isSafeToUseZ || next?.command === 'Z' || next?.command === 'z') &&
(command === 'l' || command === 'h' || command === 'v')
) {
// @ts-ignore
if (pathBase[0] === item.coords[0] && pathBase[1] === item.coords[1]) {
command = 'z';
data = [];
}
}

// collapse repeated commands
// h 20 h 30 -> h 50
if (
Expand Down Expand Up @@ -806,6 +834,16 @@ function filters(path, params, { maybeHasStrokeAndLinecap, hasMarkerMid }) {
if (prev.command === 'Z' || prev.command === 'z') return false;
prev = item;
}
if (
(command === 'Z' || command === 'z') &&
params.removeUseless &&
isSafeToUseZ &&
// @ts-ignore
item.base[0] === item.coords[0] &&
// @ts-ignore
item.base[1] === item.coords[1]
)
return false;

return true;
});
Expand Down
3 changes: 2 additions & 1 deletion plugins/plugins-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type DefaultPlugins = {
};
straightCurves?: boolean;
lineShorthands?: boolean;
convertToZ?: boolean;
curveSmoothShorthands?: boolean;
floatPrecision?: number | false;
transformPrecision?: number;
Expand Down Expand Up @@ -138,7 +139,7 @@ type DefaultPlugins = {
moveElemsAttrsToGroup: void;
moveGroupAttrsToElems: void;
removeComments: {
preservePatterns: Array<RegExp|string> | false
preservePatterns: Array<RegExp | string> | false;
};
removeDesc: {
removeAny?: boolean;
Expand Down
2 changes: 1 addition & 1 deletion test/coa/testSvg/test.1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/coa/testSvg/test.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions test/plugins/convertPathData.12.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/plugins/convertPathData.13.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions test/plugins/convertPathData.14.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/plugins/convertPathData.18.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/plugins/convertPathData.19.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/plugins/convertPathData.20.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions test/plugins/convertPathData.27.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/svgo/plugins-order.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 14bdacc

Please sign in to comment.