epiphany/node_modules/svgo/plugins/cleanupListOfValues.js
2023-12-09 22:48:07 -08:00

147 lines
3.8 KiB
JavaScript

'use strict';
const { removeLeadingZero } = require('../lib/svgo/tools.js');
exports.name = 'cleanupListOfValues';
exports.description = 'rounds list of values to the fixed precision';
const regNumericValues =
/^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/;
const regSeparator = /\s+,?\s*|,\s*/;
const absoluteLengths = {
// relative to px
cm: 96 / 2.54,
mm: 96 / 25.4,
in: 96,
pt: 4 / 3,
pc: 16,
px: 1,
};
/**
* Round list of values to the fixed precision.
*
* @example
* <svg viewBox="0 0 200.28423 200.28423" enable-background="new 0 0 200.28423 200.28423">
* ⬇
* <svg viewBox="0 0 200.284 200.284" enable-background="new 0 0 200.284 200.284">
*
* <polygon points="208.250977 77.1308594 223.069336 ... "/>
* ⬇
* <polygon points="208.251 77.131 223.069 ... "/>
*
* @author kiyopikko
*
* @type {import('./plugins-types').Plugin<'cleanupListOfValues'>}
*/
exports.fn = (_root, params) => {
const {
floatPrecision = 3,
leadingZero = true,
defaultPx = true,
convertToPx = true,
} = params;
/**
* @type {(lists: string) => string}
*/
const roundValues = (lists) => {
const roundedList = [];
for (const elem of lists.split(regSeparator)) {
const match = elem.match(regNumericValues);
const matchNew = elem.match(/new/);
// if attribute value matches regNumericValues
if (match) {
// round it to the fixed precision
let num = Number(Number(match[1]).toFixed(floatPrecision));
/**
* @type {any}
*/
let matchedUnit = match[3] || '';
/**
* @type{'' | keyof typeof absoluteLengths}
*/
let units = matchedUnit;
// convert absolute values to pixels
if (convertToPx && units && units in absoluteLengths) {
const pxNum = Number(
(absoluteLengths[units] * Number(match[1])).toFixed(floatPrecision)
);
if (pxNum.toString().length < match[0].length) {
num = pxNum;
units = 'px';
}
}
// and remove leading zero
let str;
if (leadingZero) {
str = removeLeadingZero(num);
} else {
str = num.toString();
}
// remove default 'px' units
if (defaultPx && units === 'px') {
units = '';
}
roundedList.push(str + units);
}
// if attribute value is "new"(only enable-background).
else if (matchNew) {
roundedList.push('new');
} else if (elem) {
roundedList.push(elem);
}
}
return roundedList.join(' ');
};
return {
element: {
enter: (node) => {
if (node.attributes.points != null) {
node.attributes.points = roundValues(node.attributes.points);
}
if (node.attributes['enable-background'] != null) {
node.attributes['enable-background'] = roundValues(
node.attributes['enable-background']
);
}
if (node.attributes.viewBox != null) {
node.attributes.viewBox = roundValues(node.attributes.viewBox);
}
if (node.attributes['stroke-dasharray'] != null) {
node.attributes['stroke-dasharray'] = roundValues(
node.attributes['stroke-dasharray']
);
}
if (node.attributes.dx != null) {
node.attributes.dx = roundValues(node.attributes.dx);
}
if (node.attributes.dy != null) {
node.attributes.dy = roundValues(node.attributes.dy);
}
if (node.attributes.x != null) {
node.attributes.x = roundValues(node.attributes.x);
}
if (node.attributes.y != null) {
node.attributes.y = roundValues(node.attributes.y);
}
},
},
};
};