提交 368a67b7 编写于 作者: B Bogdan Chadkin

Convert removeHiddenElems to visitor

上级 17aaf361
'use strict';
const { querySelector, closestByName } = require('../lib/xast.js');
const {
querySelector,
closestByName,
detachNodeFromParent,
} = require('../lib/xast.js');
const { computeStyle } = require('../lib/style.js');
const { parsePathData } = require('../lib/path.js');
exports.type = 'perItem';
exports.type = 'visitor';
exports.active = true;
exports.description =
'removes hidden elements (zero sized, with absent attributes)';
exports.params = {
isHidden: true,
displayNone: true,
opacity0: true,
circleR0: true,
ellipseRX0: true,
ellipseRY0: true,
rectWidth0: true,
rectHeight0: true,
patternWidth0: true,
patternHeight0: true,
imageWidth0: true,
imageHeight0: true,
pathEmptyD: true,
polylineEmptyPoints: true,
polygonEmptyPoints: true,
};
/**
* Remove hidden elements with disabled rendering:
* - display="none"
......@@ -42,238 +26,275 @@ exports.params = {
* - polyline with empty points
* - polygon with empty points
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
* @param {Object} root
* @param {Object} params
*
* @author Kir Belevich
*/
exports.fn = function (item, params) {
if (item.type === 'element') {
// Removes hidden elements
// https://www.w3schools.com/cssref/pr_class_visibility.asp
const computedStyle = computeStyle(item);
if (
params.isHidden &&
computedStyle.visibility &&
computedStyle.visibility.type === 'static' &&
computedStyle.visibility.value === 'hidden' &&
// keep if any descendant enables visibility
querySelector(item, '[visibility=visible]') == null
) {
return false;
}
exports.fn = (root, params) => {
const {
isHidden = true,
displayNone = true,
opacity0 = true,
circleR0 = true,
ellipseRX0 = true,
ellipseRY0 = true,
rectWidth0 = true,
rectHeight0 = true,
patternWidth0 = true,
patternHeight0 = true,
imageWidth0 = true,
imageHeight0 = true,
pathEmptyD = true,
polylineEmptyPoints = true,
polygonEmptyPoints = true,
} = params;
return {
element: {
enter: (node) => {
// Removes hidden elements
// https://www.w3schools.com/cssref/pr_class_visibility.asp
const computedStyle = computeStyle(node);
if (
isHidden &&
computedStyle.visibility &&
computedStyle.visibility.type === 'static' &&
computedStyle.visibility.value === 'hidden' &&
// keep if any descendant enables visibility
querySelector(node, '[visibility=visible]') == null
) {
detachNodeFromParent(node);
return;
}
// display="none"
//
// https://www.w3.org/TR/SVG11/painting.html#DisplayProperty
// "A value of display: none indicates that the given element
// and its children shall not be rendered directly"
if (
params.displayNone &&
computedStyle.display &&
computedStyle.display.type === 'static' &&
computedStyle.display.value === 'none' &&
// markers with display: none still rendered
item.isElem('marker') === false
) {
return false;
}
// display="none"
//
// https://www.w3.org/TR/SVG11/painting.html#DisplayProperty
// "A value of display: none indicates that the given element
// and its children shall not be rendered directly"
if (
displayNone &&
computedStyle.display &&
computedStyle.display.type === 'static' &&
computedStyle.display.value === 'none' &&
// markers with display: none still rendered
node.name !== 'marker'
) {
detachNodeFromParent(node);
return;
}
// opacity="0"
//
// https://www.w3.org/TR/SVG11/masking.html#ObjectAndGroupOpacityProperties
if (
params.opacity0 &&
computedStyle.opacity &&
computedStyle.opacity.type === 'static' &&
computedStyle.opacity.value === '0' &&
// transparent element inside clipPath still affect clipped elements
closestByName(item, 'clipPath') == null
) {
return false;
}
// opacity="0"
//
// https://www.w3.org/TR/SVG11/masking.html#ObjectAndGroupOpacityProperties
if (
opacity0 &&
computedStyle.opacity &&
computedStyle.opacity.type === 'static' &&
computedStyle.opacity.value === '0' &&
// transparent element inside clipPath still affect clipped elements
closestByName(node, 'clipPath') == null
) {
detachNodeFromParent(node);
return;
}
// Circles with zero radius
//
// https://www.w3.org/TR/SVG11/shapes.html#CircleElementRAttribute
// "A value of zero disables rendering of the element"
//
// <circle r="0">
if (
params.circleR0 &&
item.isElem('circle') &&
item.children.length === 0 &&
item.attributes.r === '0'
) {
return false;
}
// Circles with zero radius
//
// https://www.w3.org/TR/SVG11/shapes.html#CircleElementRAttribute
// "A value of zero disables rendering of the element"
//
// <circle r="0">
if (
circleR0 &&
node.name === 'circle' &&
node.children.length === 0 &&
node.attributes.r === '0'
) {
detachNodeFromParent(node);
return;
}
// Ellipse with zero x-axis radius
//
// https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRXAttribute
// "A value of zero disables rendering of the element"
//
// <ellipse rx="0">
if (
params.ellipseRX0 &&
item.isElem('ellipse') &&
item.children.length === 0 &&
item.attributes.rx === '0'
) {
return false;
}
// Ellipse with zero x-axis radius
//
// https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRXAttribute
// "A value of zero disables rendering of the element"
//
// <ellipse rx="0">
if (
ellipseRX0 &&
node.name === 'ellipse' &&
node.children.length === 0 &&
node.attributes.rx === '0'
) {
detachNodeFromParent(node);
return;
}
// Ellipse with zero y-axis radius
//
// https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRYAttribute
// "A value of zero disables rendering of the element"
//
// <ellipse ry="0">
if (
params.ellipseRY0 &&
item.isElem('ellipse') &&
item.children.length === 0 &&
item.attributes.ry === '0'
) {
return false;
}
// Ellipse with zero y-axis radius
//
// https://www.w3.org/TR/SVG11/shapes.html#EllipseElementRYAttribute
// "A value of zero disables rendering of the element"
//
// <ellipse ry="0">
if (
ellipseRY0 &&
node.name === 'ellipse' &&
node.children.length === 0 &&
node.attributes.ry === '0'
) {
detachNodeFromParent(node);
return;
}
// Rectangle with zero width
//
// https://www.w3.org/TR/SVG11/shapes.html#RectElementWidthAttribute
// "A value of zero disables rendering of the element"
//
// <rect width="0">
if (
params.rectWidth0 &&
item.isElem('rect') &&
item.children.length === 0 &&
item.attributes.width === '0'
) {
return false;
}
// Rectangle with zero width
//
// https://www.w3.org/TR/SVG11/shapes.html#RectElementWidthAttribute
// "A value of zero disables rendering of the element"
//
// <rect width="0">
if (
rectWidth0 &&
node.name === 'rect' &&
node.children.length === 0 &&
node.attributes.width === '0'
) {
detachNodeFromParent(node);
return;
}
// Rectangle with zero height
//
// https://www.w3.org/TR/SVG11/shapes.html#RectElementHeightAttribute
// "A value of zero disables rendering of the element"
//
// <rect height="0">
if (
params.rectHeight0 &&
params.rectWidth0 &&
item.isElem('rect') &&
item.children.length === 0 &&
item.attributes.height === '0'
) {
return false;
}
// Rectangle with zero height
//
// https://www.w3.org/TR/SVG11/shapes.html#RectElementHeightAttribute
// "A value of zero disables rendering of the element"
//
// <rect height="0">
if (
rectHeight0 &&
rectWidth0 &&
node.name === 'rect' &&
node.children.length === 0 &&
node.attributes.height === '0'
) {
detachNodeFromParent(node);
return;
}
// Pattern with zero width
//
// https://www.w3.org/TR/SVG11/pservers.html#PatternElementWidthAttribute
// "A value of zero disables rendering of the element (i.e., no paint is applied)"
//
// <pattern width="0">
if (
params.patternWidth0 &&
item.isElem('pattern') &&
item.attributes.width === '0'
) {
return false;
}
// Pattern with zero width
//
// https://www.w3.org/TR/SVG11/pservers.html#PatternElementWidthAttribute
// "A value of zero disables rendering of the element (i.e., no paint is applied)"
//
// <pattern width="0">
if (
patternWidth0 &&
node.name === 'pattern' &&
node.attributes.width === '0'
) {
detachNodeFromParent(node);
return;
}
// Pattern with zero height
//
// https://www.w3.org/TR/SVG11/pservers.html#PatternElementHeightAttribute
// "A value of zero disables rendering of the element (i.e., no paint is applied)"
//
// <pattern height="0">
if (
params.patternHeight0 &&
item.isElem('pattern') &&
item.attributes.height === '0'
) {
return false;
}
// Pattern with zero height
//
// https://www.w3.org/TR/SVG11/pservers.html#PatternElementHeightAttribute
// "A value of zero disables rendering of the element (i.e., no paint is applied)"
//
// <pattern height="0">
if (
patternHeight0 &&
node.name === 'pattern' &&
node.attributes.height === '0'
) {
detachNodeFromParent(node);
return;
}
// Image with zero width
//
// https://www.w3.org/TR/SVG11/struct.html#ImageElementWidthAttribute
// "A value of zero disables rendering of the element"
//
// <image width="0">
if (
params.imageWidth0 &&
item.isElem('image') &&
item.attributes.width === '0'
) {
return false;
}
// Image with zero width
//
// https://www.w3.org/TR/SVG11/struct.html#ImageElementWidthAttribute
// "A value of zero disables rendering of the element"
//
// <image width="0">
if (
imageWidth0 &&
node.name === 'image' &&
node.attributes.width === '0'
) {
detachNodeFromParent(node);
return;
}
// Image with zero height
//
// https://www.w3.org/TR/SVG11/struct.html#ImageElementHeightAttribute
// "A value of zero disables rendering of the element"
//
// <image height="0">
if (
params.imageHeight0 &&
item.isElem('image') &&
item.attributes.height === '0'
) {
return false;
}
// Image with zero height
//
// https://www.w3.org/TR/SVG11/struct.html#ImageElementHeightAttribute
// "A value of zero disables rendering of the element"
//
// <image height="0">
if (
imageHeight0 &&
node.name === 'image' &&
node.attributes.height === '0'
) {
detachNodeFromParent(node);
return;
}
// Path with empty data
//
// https://www.w3.org/TR/SVG11/paths.html#DAttribute
//
// <path d=""/>
if (params.pathEmptyD && item.isElem('path')) {
if (item.attributes.d == null) {
return false;
}
const pathData = parsePathData(item.attributes.d);
if (pathData.length === 0) {
return false;
}
// keep single point paths for markers
if (
pathData.length === 1 &&
computedStyle['marker-start'] == null &&
computedStyle['marker-end'] == null
) {
return false;
}
return true;
}
// Path with empty data
//
// https://www.w3.org/TR/SVG11/paths.html#DAttribute
//
// <path d=""/>
if (pathEmptyD && node.name === 'path') {
if (node.attributes.d == null) {
detachNodeFromParent(node);
return;
}
const pathData = parsePathData(node.attributes.d);
if (pathData.length === 0) {
detachNodeFromParent(node);
return;
}
// keep single point paths for markers
if (
pathData.length === 1 &&
computedStyle['marker-start'] == null &&
computedStyle['marker-end'] == null
) {
detachNodeFromParent(node);
return;
}
return;
}
// Polyline with empty points
//
// https://www.w3.org/TR/SVG11/shapes.html#PolylineElementPointsAttribute
//
// <polyline points="">
if (
params.polylineEmptyPoints &&
item.isElem('polyline') &&
item.attributes.points == null
) {
return false;
}
// Polyline with empty points
//
// https://www.w3.org/TR/SVG11/shapes.html#PolylineElementPointsAttribute
//
// <polyline points="">
if (
polylineEmptyPoints &&
node.name === 'polyline' &&
node.attributes.points == null
) {
detachNodeFromParent(node);
return;
}
// Polygon with empty points
//
// https://www.w3.org/TR/SVG11/shapes.html#PolygonElementPointsAttribute
//
// <polygon points="">
if (
params.polygonEmptyPoints &&
item.isElem('polygon') &&
item.attributes.points == null
) {
return false;
}
}
// Polygon with empty points
//
// https://www.w3.org/TR/SVG11/shapes.html#PolygonElementPointsAttribute
//
// <polygon points="">
if (
polygonEmptyPoints &&
node.name === 'polygon' &&
node.attributes.points == null
) {
detachNodeFromParent(node);
return;
}
},
},
};
};
Remove elements with display=none
===
<svg xmlns="http://www.w3.org/2000/svg">
<style>
.a { display: block; }
......
Remove elements with zero opacity
===
<svg xmlns="http://www.w3.org/2000/svg">
<style>
.a { opacity: 0.5; }
......
Remove circle element with zero radius but preserve when animation element is inside
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<circle r="0"/>
......
Remove ellipse element with zero radius
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<ellipse rx="0"/>
......
Remove rect element with zero size
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<rect width="0"/>
......
Remove pattern element with zero size
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<pattern width="0"/>
......
Remove image element with zero size
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<image width="0"/>
......
Remove empty or single point paths without markers
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<path/>
......
Remove polyline without points
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<polyline/>
......
Remove polygon without points
===
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<polygon/>
......
Preserve transparent rect inside clipPath element
===
<svg width="480" height="360" xmlns="http://www.w3.org/2000/svg">
<clipPath id="opacityclip">
<rect width="100" height="100" opacity="0"/>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册