[6a3a178] | 1 | 'use strict';
|
---|
| 2 |
|
---|
| 3 | /**
|
---|
| 4 | * @typedef {import('../lib/types').PathDataItem} PathDataItem
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | const { visitSkip, detachNodeFromParent } = require('../lib/xast.js');
|
---|
| 8 | const { parsePathData } = require('../lib/path.js');
|
---|
| 9 | const { intersects } = require('./_path.js');
|
---|
| 10 |
|
---|
| 11 | exports.type = 'visitor';
|
---|
| 12 | exports.name = 'removeOffCanvasPaths';
|
---|
| 13 | exports.active = false;
|
---|
| 14 | exports.description =
|
---|
| 15 | 'removes elements that are drawn outside of the viewbox (disabled by default)';
|
---|
| 16 |
|
---|
| 17 | /**
|
---|
| 18 | * Remove elements that are drawn outside of the viewbox.
|
---|
| 19 | *
|
---|
| 20 | * @author JoshyPHP
|
---|
| 21 | *
|
---|
| 22 | * @type {import('../lib/types').Plugin<void>}
|
---|
| 23 | */
|
---|
| 24 | exports.fn = () => {
|
---|
| 25 | /**
|
---|
| 26 | * @type {null | {
|
---|
| 27 | * top: number,
|
---|
| 28 | * right: number,
|
---|
| 29 | * bottom: number,
|
---|
| 30 | * left: number,
|
---|
| 31 | * width: number,
|
---|
| 32 | * height: number
|
---|
| 33 | * }}
|
---|
| 34 | */
|
---|
| 35 | let viewBoxData = null;
|
---|
| 36 |
|
---|
| 37 | return {
|
---|
| 38 | element: {
|
---|
| 39 | enter: (node, parentNode) => {
|
---|
| 40 | if (node.name === 'svg' && parentNode.type === 'root') {
|
---|
| 41 | let viewBox = '';
|
---|
| 42 | // find viewbox
|
---|
| 43 | if (node.attributes.viewBox != null) {
|
---|
| 44 | // remove commas and plus signs, normalize and trim whitespace
|
---|
| 45 | viewBox = node.attributes.viewBox;
|
---|
| 46 | } else if (
|
---|
| 47 | node.attributes.height != null &&
|
---|
| 48 | node.attributes.width != null
|
---|
| 49 | ) {
|
---|
| 50 | viewBox = `0 0 ${node.attributes.width} ${node.attributes.height}`;
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | // parse viewbox
|
---|
| 54 | // remove commas and plus signs, normalize and trim whitespace
|
---|
| 55 | viewBox = viewBox
|
---|
| 56 | .replace(/[,+]|px/g, ' ')
|
---|
| 57 | .replace(/\s+/g, ' ')
|
---|
| 58 | .replace(/^\s*|\s*$/g, '');
|
---|
| 59 | // ensure that the dimensions are 4 values separated by space
|
---|
| 60 | const m =
|
---|
| 61 | /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(
|
---|
| 62 | viewBox
|
---|
| 63 | );
|
---|
| 64 | if (m == null) {
|
---|
| 65 | return;
|
---|
| 66 | }
|
---|
| 67 | const left = Number.parseFloat(m[1]);
|
---|
| 68 | const top = Number.parseFloat(m[2]);
|
---|
| 69 | const width = Number.parseFloat(m[3]);
|
---|
| 70 | const height = Number.parseFloat(m[4]);
|
---|
| 71 |
|
---|
| 72 | // store the viewBox boundaries
|
---|
| 73 | viewBoxData = {
|
---|
| 74 | left,
|
---|
| 75 | top,
|
---|
| 76 | right: left + width,
|
---|
| 77 | bottom: top + height,
|
---|
| 78 | width,
|
---|
| 79 | height,
|
---|
| 80 | };
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | // consider that any item with a transform attribute is visible
|
---|
| 84 | if (node.attributes.transform != null) {
|
---|
| 85 | return visitSkip;
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | if (
|
---|
| 89 | node.name === 'path' &&
|
---|
| 90 | node.attributes.d != null &&
|
---|
| 91 | viewBoxData != null
|
---|
| 92 | ) {
|
---|
| 93 | const pathData = parsePathData(node.attributes.d);
|
---|
| 94 |
|
---|
| 95 | // consider that a M command within the viewBox is visible
|
---|
| 96 | let visible = false;
|
---|
| 97 | for (const pathDataItem of pathData) {
|
---|
| 98 | if (pathDataItem.command === 'M') {
|
---|
| 99 | const [x, y] = pathDataItem.args;
|
---|
| 100 | if (
|
---|
| 101 | x >= viewBoxData.left &&
|
---|
| 102 | x <= viewBoxData.right &&
|
---|
| 103 | y >= viewBoxData.top &&
|
---|
| 104 | y <= viewBoxData.bottom
|
---|
| 105 | ) {
|
---|
| 106 | visible = true;
|
---|
| 107 | }
|
---|
| 108 | }
|
---|
| 109 | }
|
---|
| 110 | if (visible) {
|
---|
| 111 | return;
|
---|
| 112 | }
|
---|
| 113 |
|
---|
| 114 | if (pathData.length === 2) {
|
---|
| 115 | // close the path too short for intersects()
|
---|
| 116 | pathData.push({ command: 'z', args: [] });
|
---|
| 117 | }
|
---|
| 118 |
|
---|
| 119 | const { left, top, width, height } = viewBoxData;
|
---|
| 120 | /**
|
---|
| 121 | * @type {Array<PathDataItem>}
|
---|
| 122 | */
|
---|
| 123 | const viewBoxPathData = [
|
---|
| 124 | { command: 'M', args: [left, top] },
|
---|
| 125 | { command: 'h', args: [width] },
|
---|
| 126 | { command: 'v', args: [height] },
|
---|
| 127 | { command: 'H', args: [left] },
|
---|
| 128 | { command: 'z', args: [] },
|
---|
| 129 | ];
|
---|
| 130 |
|
---|
| 131 | if (intersects(viewBoxPathData, pathData) === false) {
|
---|
| 132 | detachNodeFromParent(node, parentNode);
|
---|
| 133 | }
|
---|
| 134 | }
|
---|
| 135 | },
|
---|
| 136 | },
|
---|
| 137 | };
|
---|
| 138 | };
|
---|