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 `z` command.
KTibow marked this conversation as resolved.
Show resolved Hide resolved
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 commands (when applicable). For example, a command that moves to the current position can be removed.
KTibow marked this conversation as resolved.
Show resolved Hide resolved
* Trim redundant delimiters and leading zeros.
* Round numeric values using conventional rounding rules.

Expand Down
44 changes: 42 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,14 @@ exports.fn = (root, params) => {
(computedStyle['stroke-linecap'].type === 'dynamic' ||
computedStyle['stroke-linecap'].value !== 'butt');
const maybeHasStrokeAndLinecap = maybeHasStroke && maybeHasLinecap;
// TODO: when stroke is used, prefer z more
// Z is the same as going home at 90 and 0 degrees, but not at other degrees
KTibow marked this conversation as resolved.
Show resolved Hide resolved
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 +186,7 @@ exports.fn = (root, params) => {
convertToRelative(data);

data = filters(data, newParams, {
isSafeToUseZ,
maybeHasStrokeAndLinecap,
hasMarkerMid,
});
Expand Down Expand Up @@ -371,10 +383,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 +680,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 +836,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