Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace with z and remove z when optimal #1822

Merged
merged 11 commits into from
Nov 12, 2023
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.
Loading