123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- 'use strict';
- const { visit, visitSkip, detachNodeFromParent } = require('../lib/xast.js');
- const { collectStylesheet, computeStyle } = require('../lib/style.js');
- const { elemsGroups } = require('./_collections.js');
- exports.type = 'visitor';
- exports.name = 'removeUselessStrokeAndFill';
- exports.active = true;
- exports.description = 'removes useless stroke and fill attributes';
- /**
- * Remove useless stroke and fill attrs.
- *
- * @author Kir Belevich
- *
- * @type {import('../lib/types').Plugin<{
- * stroke?: boolean,
- * fill?: boolean,
- * removeNone?: boolean
- * }>}
- */
- exports.fn = (root, params) => {
- const {
- stroke: removeStroke = true,
- fill: removeFill = true,
- removeNone = false,
- } = params;
- // style and script elements deoptimise this plugin
- let hasStyleOrScript = false;
- visit(root, {
- element: {
- enter: (node) => {
- if (node.name === 'style' || node.name === 'script') {
- hasStyleOrScript = true;
- }
- },
- },
- });
- if (hasStyleOrScript) {
- return null;
- }
- const stylesheet = collectStylesheet(root);
- return {
- element: {
- enter: (node, parentNode) => {
- // id attribute deoptimise the whole subtree
- if (node.attributes.id != null) {
- return visitSkip;
- }
- if (elemsGroups.shape.includes(node.name) == false) {
- return;
- }
- const computedStyle = computeStyle(stylesheet, node);
- const stroke = computedStyle.stroke;
- const strokeOpacity = computedStyle['stroke-opacity'];
- const strokeWidth = computedStyle['stroke-width'];
- const markerEnd = computedStyle['marker-end'];
- const fill = computedStyle.fill;
- const fillOpacity = computedStyle['fill-opacity'];
- const computedParentStyle =
- parentNode.type === 'element'
- ? computeStyle(stylesheet, parentNode)
- : null;
- const parentStroke =
- computedParentStyle == null ? null : computedParentStyle.stroke;
- // remove stroke*
- if (removeStroke) {
- if (
- stroke == null ||
- (stroke.type === 'static' && stroke.value == 'none') ||
- (strokeOpacity != null &&
- strokeOpacity.type === 'static' &&
- strokeOpacity.value === '0') ||
- (strokeWidth != null &&
- strokeWidth.type === 'static' &&
- strokeWidth.value === '0')
- ) {
- // stroke-width may affect the size of marker-end
- // marker is not visible when stroke-width is 0
- if (
- (strokeWidth != null &&
- strokeWidth.type === 'static' &&
- strokeWidth.value === '0') ||
- markerEnd == null
- ) {
- for (const name of Object.keys(node.attributes)) {
- if (name.startsWith('stroke')) {
- delete node.attributes[name];
- }
- }
- // set explicit none to not inherit from parent
- if (
- parentStroke != null &&
- parentStroke.type === 'static' &&
- parentStroke.value !== 'none'
- ) {
- node.attributes.stroke = 'none';
- }
- }
- }
- }
- // remove fill*
- if (removeFill) {
- if (
- (fill != null && fill.type === 'static' && fill.value === 'none') ||
- (fillOpacity != null &&
- fillOpacity.type === 'static' &&
- fillOpacity.value === '0')
- ) {
- for (const name of Object.keys(node.attributes)) {
- if (name.startsWith('fill-')) {
- delete node.attributes[name];
- }
- }
- if (
- fill == null ||
- (fill.type === 'static' && fill.value !== 'none')
- ) {
- node.attributes.fill = 'none';
- }
- }
- }
- if (removeNone) {
- if (
- (stroke == null || node.attributes.stroke === 'none') &&
- ((fill != null &&
- fill.type === 'static' &&
- fill.value === 'none') ||
- node.attributes.fill === 'none')
- ) {
- detachNodeFromParent(node, parentNode);
- }
- }
- },
- },
- };
- };
|