You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
'use strict';
/** * @typedef {import('../lib/types').XastElement} XastElement * @typedef {import('../lib/types').XastParent} XastParent * @typedef {import('../lib/types').XastNode} XastNode */
const JSAPI = require('../lib/svgo/jsAPI.js');
exports.type = 'visitor'; exports.name = 'reusePaths'; exports.active = false; exports.description = 'Finds <path> elements with the same d, fill, and ' + 'stroke, and converts them to <use> elements ' + 'referencing a single <path> def.';
/** * Finds <path> elements with the same d, fill, and stroke, and converts them to * <use> elements referencing a single <path> def. * * @author Jacob Howcroft * * @type {import('../lib/types').Plugin<void>} */ exports.fn = () => { /** * @type {Map<string, Array<XastElement>>} */ const paths = new Map();
return { element: { enter: (node) => { if (node.name === 'path' && node.attributes.d != null) { const d = node.attributes.d; const fill = node.attributes.fill || ''; const stroke = node.attributes.stroke || ''; const key = d + ';s:' + stroke + ';f:' + fill; let list = paths.get(key); if (list == null) { list = []; paths.set(key, list); } list.push(node); } },
exit: (node, parentNode) => { if (node.name === 'svg' && parentNode.type === 'root') { /** * @type {XastElement} */ const rawDefs = { type: 'element', name: 'defs', attributes: {}, children: [], }; /** * @type {XastElement} */ const defsTag = new JSAPI(rawDefs, node); let index = 0; for (const list of paths.values()) { if (list.length > 1) { // add reusable path to defs
/** * @type {XastElement} */ const rawPath = { type: 'element', name: 'path', attributes: { ...list[0].attributes }, children: [], }; delete rawPath.attributes.transform; let id; if (rawPath.attributes.id == null) { id = 'reuse-' + index; index += 1; rawPath.attributes.id = id; } else { id = rawPath.attributes.id; delete list[0].attributes.id; } /** * @type {XastElement} */ const reusablePath = new JSAPI(rawPath, defsTag); defsTag.children.push(reusablePath); // convert paths to <use>
for (const pathNode of list) { pathNode.name = 'use'; pathNode.attributes['xlink:href'] = '#' + id; delete pathNode.attributes.d; delete pathNode.attributes.stroke; delete pathNode.attributes.fill; } } } if (defsTag.children.length !== 0) { if (node.attributes['xmlns:xlink'] == null) { node.attributes['xmlns:xlink'] = 'http://www.w3.org/1999/xlink'; } node.children.unshift(defsTag); } } }, }, }; };
|