123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- '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);
- }
- }
- },
- },
- };
- };
|