105 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
 | 
						|
const { detachNodeFromParent } = require('../lib/xast.js');
 | 
						|
const { collectStylesheet, computeStyle } = require('../lib/style.js');
 | 
						|
const { path2js, js2path, intersects } = require('./_path.js');
 | 
						|
 | 
						|
exports.type = 'visitor';
 | 
						|
exports.name = 'mergePaths';
 | 
						|
exports.active = true;
 | 
						|
exports.description = 'merges multiple paths in one if possible';
 | 
						|
 | 
						|
/**
 | 
						|
 * Merge multiple Paths into one.
 | 
						|
 *
 | 
						|
 * @author Kir Belevich, Lev Solntsev
 | 
						|
 *
 | 
						|
 * @type {import('../lib/types').Plugin<{
 | 
						|
 *   force?: boolean,
 | 
						|
 *   floatPrecision?: number,
 | 
						|
 *   noSpaceAfterFlags?: boolean
 | 
						|
 * }>}
 | 
						|
 */
 | 
						|
exports.fn = (root, params) => {
 | 
						|
  const {
 | 
						|
    force = false,
 | 
						|
    floatPrecision,
 | 
						|
    noSpaceAfterFlags = false, // a20 60 45 0 1 30 20 → a20 60 45 0130 20
 | 
						|
  } = params;
 | 
						|
  const stylesheet = collectStylesheet(root);
 | 
						|
 | 
						|
  return {
 | 
						|
    element: {
 | 
						|
      enter: (node) => {
 | 
						|
        let prevChild = null;
 | 
						|
 | 
						|
        for (const child of node.children) {
 | 
						|
          // skip if previous element is not path or contains animation elements
 | 
						|
          if (
 | 
						|
            prevChild == null ||
 | 
						|
            prevChild.type !== 'element' ||
 | 
						|
            prevChild.name !== 'path' ||
 | 
						|
            prevChild.children.length !== 0 ||
 | 
						|
            prevChild.attributes.d == null
 | 
						|
          ) {
 | 
						|
            prevChild = child;
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          // skip if element is not path or contains animation elements
 | 
						|
          if (
 | 
						|
            child.type !== 'element' ||
 | 
						|
            child.name !== 'path' ||
 | 
						|
            child.children.length !== 0 ||
 | 
						|
            child.attributes.d == null
 | 
						|
          ) {
 | 
						|
            prevChild = child;
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          // preserve paths with markers
 | 
						|
          const computedStyle = computeStyle(stylesheet, child);
 | 
						|
          if (
 | 
						|
            computedStyle['marker-start'] ||
 | 
						|
            computedStyle['marker-mid'] ||
 | 
						|
            computedStyle['marker-end']
 | 
						|
          ) {
 | 
						|
            prevChild = child;
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          const prevChildAttrs = Object.keys(prevChild.attributes);
 | 
						|
          const childAttrs = Object.keys(child.attributes);
 | 
						|
          let attributesAreEqual = prevChildAttrs.length === childAttrs.length;
 | 
						|
          for (const name of childAttrs) {
 | 
						|
            if (name !== 'd') {
 | 
						|
              if (
 | 
						|
                prevChild.attributes[name] == null ||
 | 
						|
                prevChild.attributes[name] !== child.attributes[name]
 | 
						|
              ) {
 | 
						|
                attributesAreEqual = false;
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
          const prevPathJS = path2js(prevChild);
 | 
						|
          const curPathJS = path2js(child);
 | 
						|
 | 
						|
          if (
 | 
						|
            attributesAreEqual &&
 | 
						|
            (force || !intersects(prevPathJS, curPathJS))
 | 
						|
          ) {
 | 
						|
            js2path(prevChild, prevPathJS.concat(curPathJS), {
 | 
						|
              floatPrecision,
 | 
						|
              noSpaceAfterFlags,
 | 
						|
            });
 | 
						|
            detachNodeFromParent(child, node);
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          prevChild = child;
 | 
						|
        }
 | 
						|
      },
 | 
						|
    },
 | 
						|
  };
 | 
						|
};
 |