123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- 'use strict';
- /**
- * @typedef {import('../lib/types').PathDataItem} PathDataItem
- */
- const { visitSkip, detachNodeFromParent } = require('../lib/xast.js');
- const { parsePathData } = require('../lib/path.js');
- const { intersects } = require('./_path.js');
- exports.type = 'visitor';
- exports.name = 'removeOffCanvasPaths';
- exports.active = false;
- exports.description =
- 'removes elements that are drawn outside of the viewbox (disabled by default)';
- /**
- * Remove elements that are drawn outside of the viewbox.
- *
- * @author JoshyPHP
- *
- * @type {import('../lib/types').Plugin<void>}
- */
- exports.fn = () => {
- /**
- * @type {null | {
- * top: number,
- * right: number,
- * bottom: number,
- * left: number,
- * width: number,
- * height: number
- * }}
- */
- let viewBoxData = null;
- return {
- element: {
- enter: (node, parentNode) => {
- if (node.name === 'svg' && parentNode.type === 'root') {
- let viewBox = '';
- // find viewbox
- if (node.attributes.viewBox != null) {
- // remove commas and plus signs, normalize and trim whitespace
- viewBox = node.attributes.viewBox;
- } else if (
- node.attributes.height != null &&
- node.attributes.width != null
- ) {
- viewBox = `0 0 ${node.attributes.width} ${node.attributes.height}`;
- }
- // parse viewbox
- // remove commas and plus signs, normalize and trim whitespace
- viewBox = viewBox
- .replace(/[,+]|px/g, ' ')
- .replace(/\s+/g, ' ')
- .replace(/^\s*|\s*$/g, '');
- // ensure that the dimensions are 4 values separated by space
- const m =
- /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(
- viewBox
- );
- if (m == null) {
- return;
- }
- const left = Number.parseFloat(m[1]);
- const top = Number.parseFloat(m[2]);
- const width = Number.parseFloat(m[3]);
- const height = Number.parseFloat(m[4]);
- // store the viewBox boundaries
- viewBoxData = {
- left,
- top,
- right: left + width,
- bottom: top + height,
- width,
- height,
- };
- }
- // consider that any item with a transform attribute is visible
- if (node.attributes.transform != null) {
- return visitSkip;
- }
- if (
- node.name === 'path' &&
- node.attributes.d != null &&
- viewBoxData != null
- ) {
- const pathData = parsePathData(node.attributes.d);
- // consider that a M command within the viewBox is visible
- let visible = false;
- for (const pathDataItem of pathData) {
- if (pathDataItem.command === 'M') {
- const [x, y] = pathDataItem.args;
- if (
- x >= viewBoxData.left &&
- x <= viewBoxData.right &&
- y >= viewBoxData.top &&
- y <= viewBoxData.bottom
- ) {
- visible = true;
- }
- }
- }
- if (visible) {
- return;
- }
- if (pathData.length === 2) {
- // close the path too short for intersects()
- pathData.push({ command: 'z', args: [] });
- }
- const { left, top, width, height } = viewBoxData;
- /**
- * @type {Array<PathDataItem>}
- */
- const viewBoxPathData = [
- { command: 'M', args: [left, top] },
- { command: 'h', args: [width] },
- { command: 'v', args: [height] },
- { command: 'H', args: [left] },
- { command: 'z', args: [] },
- ];
- if (intersects(viewBoxPathData, pathData) === false) {
- detachNodeFromParent(node, parentNode);
- }
- }
- },
- },
- };
- };
|