0

I have been trying to add/use the getPathData() polyfill to normalize SVG elements into their path data. I have tried using path-data-polyfill, but I get the error ReferenceError: SVGPathElement is not defined when trying to import it. I think this is due to SVGPathElement only being accessible on the DOM, and I am server side rendering it.

My end goal is to convert paper.js Item objects into ItemPaths so that I can use boolean operations. I have been trying to do this by exporting the SVG from the Item, and then creating a new ItemPath from that.

Implementation:

functional component which uses the script:

import React, { useRef, useEffect, useState, useCallback } from "react";
import Paper from "paper";
import useResizeObserver from "use-resize-observer";
import { Point } from "paper/dist/paper-core";

interface Props {}

const Canvas: React.FC<Props> = (props) => {
    const canvasRef = useRef(null);
    const [width, setWidth] = useState(0);
    const [height, setHeight] = useState(0);
    const { ref } = useResizeObserver({
        onResize: ({ width, height }) => {
            setHeight(height ? height : 1);
            setWidth(width ? width : 1);
        },
    });
    const [objects, setObjects] = useState([]);

    useEffect(() => {
        const canvas = canvasRef.current;
        //@ts-ignore
        Paper.setup(canvas);

        const item1 = Paper.project.importSVG(
            `<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" id="svg2" viewBox="0 0 611.43 700" version="1.1">
  <g id="layer1" transform="translate(-54.286 -66.648)">
    <g id="g3761">
      <path id="path2876-1" transform="matrix(1 0 0 -3.5766 0 2808.7)" fill="#bceefe" d="m665.71 570.93c0 108.09-136.87 195.71-305.71 195.71s-305.71-87.624-305.71-195.71v-0.00001h305.71z"/>
      <path id="path3688" fill="#94835c" d="m279.5 651.83c6.4004-35.825 10.316-72.284 19.127-107.49 7.7072-30.8 17.838-61.385 29.887-90.691 6.5917-16.032 16.978-30.382 25.467-45.573 7.2225 3.6112 14.445 7.2225 21.667 10.834-8.1292 16.439-19.178 31.838-24.503 49.275-13.054 42.752-21.596 87.194-31.021 131.11-3.9569 18.438-8.1243 36.83-12.187 55.245-9.4795-0.9028-18.959-1.8056-28.438-2.7084z"/>
      <path id="path3690" fill="#8dcb8d" d="m253.77 455.47c7.2244 0.0398 31.723-0.35416 46.366-5.3695 13.231-4.5317 27.445-8.7088 38.555-17.257 6.1896-4.7629 15.041-19.983 16.645-16.645 3.1692 6.5935-5.2824 31.103-3.1642 46.473 1.6746 12.151 3.0882 27.178 7.2268 36.134 4.1386 8.9565 12.684 20.775 17.605 17.605 11.745-7.5677 25.681-32.586 25.909-53.682 0.17215-15.963-5.6538-42.526 1.1754-47.884 5.8435-4.5846 22.543 17.628 36.366 19.371 15.322 1.9318 41.687 10.609 46.241 3.6506 4.9519-7.567-7.1076-33.466-18.593-47.006-12.837-15.134-30.906-24.629-50.106-27.039-15.531-1.949 5.8544-12.188 8.6503-19.116 4.4994-11.147 4.7975-23.756 6.1972-35.667 0.9119-7.7596 0.97438-15.979-9.9888-13.012-12.962 3.509-26.026 5.7969-37.782 12.923-11.783 7.1425-19.338 19.648-22.016 32.678 0.26315 10.791-13.41-3.1434-19.18-4.8602-10.481-3.118-21.56-3.1179-32.376-4.3493-11.707-1.3328-23.817-2.3389-35.303 1.3217-5.1209 1.632-15.806 0.12475-15.656 3.9141 0.3606 9.1096 12.783 22.091 22.946 30.595 8.4199 7.0456 28.682 12.865 27.1 19.305-2.1024 8.5581-21.627 14.082-30.614 23.6-10.352 10.964-18.729 23.569-23.418 37.945-0.719 2.2045-10.01 6.3322-2.7852 6.3719z"/>
      <path id="path3755" transform="matrix(1.2466 0 0 1.1098 -130.2 -79.458)" fill="#f3ff75" d="m568.57 652.36c0 32.348-23.345 58.571-52.143 58.571s-52.143-26.223-52.143-58.571 23.345-58.571 52.143-58.571 52.143 26.223 52.143 58.571z"/>
      <path id="path3688-7" fill="#95845b" d="m298.44 653.82c-5.3077-28.248-8.5676-57.044-15.862-84.759-6.4027-24.329-14.819-48.463-24.783-71.505-5.4914-12.7-14.08-23.957-21.12-35.935-5.9893 2.8474-11.979 5.6948-17.968 8.5422 6.7418 12.964 15.762 25.075 20.32 38.855 9.1446 27.647 14.818 56.664 21.5 85.173 4.8232 20.578 9.5528 41.177 14.329 61.765 7.8609-0.71184 15.722-1.4237 23.583-2.1355z"/>
      <path id="path3690-4" fill="#8ccc8c" d="m320.64 478.06c-6.1036 1.6328-26.918 6.7223-40.418 5.7203-12.198-0.90537-25.149-1.2931-36.44-6.0668-6.2912-2.6597-17.149-13.578-17.768-10.399-1.2219 6.2802 11.354 25.146 12.964 38.619 1.2728 10.651 3.4031 23.678 1.884 32.172-1.519 8.494-6.1328 20.385-10.998 18.792-11.613-3.8029-28.942-21.885-33.804-39.684-3.6791-13.468-4.63-37.232-11.594-40.254-5.9588-2.5855-15.171 19.905-26.481 24.439-12.536 5.026-32.922 18.204-38.315 13.324-5.8647-5.3062-1.3942-29.888 5.3262-43.887 7.5114-15.646 20.697-27.68 36.408-33.968 12.709-5.0869-7.6512-9.0165-11.55-14.258-6.2743-8.4355-9.3177-19.038-13.138-28.805-2.4892-6.3634-4.3615-13.304 5.5711-13.22 11.744 0.0997 23.303-0.85631 34.827 2.5708 11.55 3.4348 20.711 12.343 25.86 22.775 2.166 9.1883 10.65-5.6279 15.152-8.3577 8.1774-4.958 17.551-7.4104 26.43-10.846 9.6101-3.7191 19.633-7.2508 30.162-6.6962 4.6939 0.24722 13.401-3.3933 14.113-0.15399 1.7114 7.7872-5.9257 21.52-12.642 30.965-5.5643 7.8249-21.419 17.233-18.655 22.332 3.6732 6.7755 21.415 7.127 31.126 13.191 11.186 6.9847 21.063 15.795 28.213 26.92 1.0963 1.706 9.8705 3.1418 3.7669 4.7746z"/>
      <path id="path2876" transform="matrix(1 0 0 -.63504 0 1129.2)" fill="#f3c075" d="m665.71 570.93c0 108.09-136.87 195.71-305.71 195.71s-305.71-87.624-305.71-195.71v-0.00001h305.71z"/>
    </g>
  </g>
</svg>`,
            { applyMatrix: true }
        );

        Paper.project.addLayer(new Paper.Layer(item1));
        const item = Paper.project.importSVG(
            `<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24"><path fill="#6563ff" d="M20.3,12.7c-0.3-0.4-0.3-0.9,0-1.3l1.3-1.4c0.3-0.3,0.3-0.8,0.1-1.2l-2-3.5c-0.2-0.4-0.6-0.6-1.1-0.5l-1.9,0.4c-0.5,0.1-1-0.2-1.1-0.7l-0.6-1.8C14.8,2.3,14.4,2,14,2h-4C9.6,2,9.2,2.3,9.1,2.7L8.4,4.5C8.3,5,7.8,5.3,7.3,5.2L5.4,4.8C5,4.7,4.6,4.9,4.3,5.3l-2,3.5C2.1,9.1,2.2,9.6,2.5,9.9l1.3,1.4c0.3,0.4,0.3,0.9,0,1.3l-1.3,1.4c-0.3,0.3-0.3,0.8-0.1,1.2l2,3.5c0.2,0.4,0.6,0.6,1.1,0.5l1.9-0.4c0.5-0.1,1,0.2,1.1,0.7l0.6,1.8C9.2,21.7,9.6,22,10,22h4c0.4,0,0.8-0.3,0.9-0.7l0.6-1.8c0.2-0.5,0.7-0.8,1.1-0.7l1.9,0.4c0.4,0.1,0.9-0.1,1.1-0.5l2-3.5c0.2-0.4,0.2-0.8-0.1-1.2L20.3,12.7z M12,15c-1.7,0-3-1.3-3-3s1.3-3,3-3s3,1.3,3,3S13.7,15,12,15z"/></svg>`,
            { applyMatrix: true }
        );

        Paper.project.addLayer(new Paper.Layer(item));

        Paper.view.update();
    }, []);

    // keep elements centered on canvas
    useEffect(() => {
        Paper.project.layers.forEach((layer) => {
            layer.position = new Point(width / 2, height / 2);
        });
    }, [width, height]);

    return (
        <div ref={ref} className="h-full w-full">
            <canvas
                ref={canvasRef}
                className="h-full w-full"
                id="canvas"
            ></canvas>
        </div>
    );
};

export default Canvas;

How the component is added to index.tsx:

import "./lib/polyfills/polyfills"; // top of file
...

<NoSSR>
    <Canvas></Canvas>
</NoSSR>

NoSSR:

import dynamic from "next/dynamic";
import React from "react";

const NoSSR: React.FC<any> = (props) => (
    <React.Fragment>{props.children}</React.Fragment>
);

export default dynamic(() => Promise.resolve(NoSSR), {
    ssr: false,
});

removeOverlap.ts, where I want the polyfill to work:

import Paper from "paper";
import { PathItem } from "paper/dist/paper-core";

function removeOverlaps(): void {
    let array: paper.Item[] = [];
    Paper.project.getItems({}).forEach((item) => {
        if (item.hasChildren()) return;

        item.selected = true;
        array.push(item);
    });

    console.log(array);

    array.forEach((e, i) => {
        for (let j = i + 1; j < array.length; j++) {
            if (e.intersects(array[j]) || e.isInside(array[j].bounds)) {
                //@ts-ignore
                let svg: SVGPathElement = e.exportSVG();

                // svg.getPathData({normalise: true})   this does not work

                const pitem = PathItem.create(svg);

                console.log(pitem);
            }
        }
    });
}

export default removeOverlaps;

Note: I have realized that I do not need Next.js for this project, so I switched to a simple react.js project with no server. But, the polyfill still does not work. I am importing it like this answer, where I add import "path-data-polyfill"; after all the other imports.

Note2: I did try to include import "path-data-polyfill"; inside removeOverlap.ts as well

Tudor Popescu
  • 509
  • 1
  • 5
  • 16
  • Does this answer your question: [Why am I getting ReferenceError: self is not defined when I import a client-side library?](https://stackoverflow.com/questions/66096260/why-am-i-getting-referenceerror-self-is-not-defined-when-i-import-a-client-side)? As you mentioned, `SVGPathElement` is a Web API only available in the browser. Try dynamically importing the library on the client-side only. – juliomalves Jan 31 '22 at 23:13
  • @juliomalves the entire component which uses this code is already wrapped in a dynamically imported way with no SSR. The code is used no where else. – Tudor Popescu Jan 31 '22 at 23:49
  • In that case could you please share the relevant code? The component itself, and how you're importing it. – juliomalves Jan 31 '22 at 23:53
  • That will still import the library on the server-side. Move the polyfill import to the `Canvas` component and dynamically import (rather than exporting, as you are now) the whole component instead. – juliomalves Feb 01 '22 at 00:13

0 Answers0