Giter Club home page Giter Club logo

svgdom's Introduction

svgdom

Straightforward DOM implementation to make SVG.js run headless on Node.js

While this dom implementation was designed to run svg.js on node, it now is much more feature complete and can be used by anyone needing an xml, svg or html dom.

Get started with svg.js v3.x

for older versions of svg.js checkout older versions of svgdom

npm install @svgdotjs/svg.js svgdom
import { createSVGWindow } from 'svgdom'
import { SVG, registerWindow } from '@svgdotjs/svg.js'

// returns a window with a document and an svg root node
const window = createSVGWindow()
const document = window.document

// register window and document
registerWindow(window, document)

// create canvas
const canvas = SVG(document.documentElement)

// use svg.js as normal
canvas.rect(100, 100).fill('yellow').move(50,50)

// get your svg as string
console.log(canvas.svg())
// or
console.log(canvas.node.outerHTML)

Create an HTML Dom or XML Dom

// create HTML window with a document and an html root node
import { createHTMLWindow } from 'svgdom'
const window = createHTMLWindow()

// create XML window with a document and a given xml root node
import { createWindow } from 'svgdom'
const window = createWindow(namespaceURI, rootNode)
// e.g. createWindow('http://www.w3.org/1998/Math/MathML', 'math')

Use svgdom as cjs module

svgdom is used best as esm module. However, if you still require cjs, you have to import the module via the async import function:

const main = async () => {
    const { createSVGWindow } = await import('svgdom')
}
main()

Fonts

In order to calculate bounding boxes for text the font needs to be loaded first. svgdom loads Open Sans-Regular by default when no font file for the specified font was found. The following options must be set in order to load your own fonts:

import { config } from 'svgdom'
config.
    // your font directory
    .setFontDir('./fonts')
    // map the font-family to the file
    .setFontFamilyMappings({'Arial': 'arial.ttf'})
    // you can preload your fonts to avoid the loading delay
    // when the font is used the first time
    .preloadFonts()

// Alternatively you can import the functions itself and use them
const {setFontDir, setFontFamilyMappings, preloadFonts} = require('svgdom')
setFontDir('./fonts')
setFontFamilyMappings({'Arial': 'arial.ttf'})
preloadFonts()

Limitations

Almost all functions of svg.js work properly with svgdom. However there are a few known limitations:

  • font properties like bold, italic... are only supported when you explicitely load that font e.g.
    setFontFamilyMappings({'Arial-italic': 'arial_italic.ttf'})
  • querySelector only supports the following pseudo classes:
    • first-child
    • last-child
    • nth-child
    • nth-last-child
    • first-of-type
    • last-of-type
    • nth-of-type
    • nth-last-of-type
    • only-child
    • only-of-type
    • root
    • not
    • matches
    • scope
  • special chars in attribute values: # and . are allowed but things like : or [] will break the selector

Using svgdom in your own projects

Albeit this dom implementation aims to work with svgjs, it is of course possible to use it in your own projects. Keep in mind, that some functions are just not needed in svgjs and therefore not implemented or tested. If you need a certain feature don't hesistate to open an issue or submit a pull request.

Last thing to say: childNodes is an array! (yet)

Donate or Sponsor

svgdom's People

Contributors

apla avatar biojet1 avatar ctcpip avatar danielsogl avatar dbrnz avatar dependabot[bot] avatar duncanmak avatar fuzzyma avatar guseyn avatar henryswanson avatar ind1go avatar jroper avatar jtbrinkmann avatar kimmobrunfeldt avatar michael-brade avatar rssh avatar salarelv avatar th-we avatar tomfalkner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

svgdom's Issues

A method to clean the canvas?

HI, I'm creating a service to generate svg on the server.

I have to delete require.cache[require.resolve('svgdom')] to get a clean canvas every time.

It would be great if there is a function that like canvas.clear() to do so.

Thanks.

bbox() for text: TypeError: Cannot read property 'fontFamilyMappings' of null

Hi!

You have done incredible effort to make SVG.js work in Node, thank you. I'm trying to calculate bounding box for a text element in an existing SVG file. I'm using node 6.9.4, [email protected] and latest master of svgdom. Here's a reproducible example:

const window = require('svgdom');
const svgJs = require('svg.js');

const SVG_STRING = `
<svg width="100px" height="100px" viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <text id="text" font-family="Arial" font-size="16" font-weight="300" letter-spacing="16.363636" fill="#343434">
    <tspan x="10" y="10">Test</tspan>
  </text>
</svg>`;


const SVG = svgJs(window);
const draw = SVG(window.document);
draw.svg(SVG_STRING);

const element = SVG.get('text');
console.log(element.bbox());

Running this causes an error:

/Users/kimmo/myproject/node_modules/svgdom/class/Node.js:416
        fontFamilyMappings: this.ownerDocument.fontFamilyMappings,
                                              ^

TypeError: Cannot read property 'fontFamilyMappings' of null
    at create.getFontDetails (/Users/kimmo/myproject/node_modules/svgdom/class/Node.js:416:47)
    at textIterator (/Users/kimmo/myproject/node_modules/svgdom/utils/bboxUtils.js:154:68)
    at bbox (/Users/kimmo/myproject/node_modules/svgdom/utils/bboxUtils.js:97:19)
    at create.getBBox (/Users/kimmo/myproject/node_modules/svgdom/class/Node.js:287:14)
    at new create (/Users/kimmo/myproject/node_modules/svg.js/dist/svg.js:2292:28)
    at create.bbox (/Users/kimmo/myproject/node_modules/svg.js/dist/svg.js:2319:14)
    at Object.<anonymous> (/Users/kimmo/myproject/test2.js:17:16)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)

I'm not sure if this is problem of SVG.js or svgdom, but ownerDocument is not set for the text element. Here you can find where .parentNode is set for the element, maybe we should have ownerDocument there as well:

node.parentNode = this

DocumentFragment: if detached, assigning textContent crashes

This here doesn't work anymore:

var f = document.createDocumentFragment();
f.textContent = "";

I don't know if the spec allows it but it works in the browser.
The reason in svgdom is that this.ownerDocument is null, but it is used for the createTextNode() call. It is actually true for any detached Node since this code is in dom/Node.js, line 399.

Probably my configuration, but...

When using svgdom with TypeScript (ts-jest), it fails in module resolution, because main points to a .cjs file. If I change it to reference main-module.js everything works.

As the likely use case is running inside Node anyway, is the .cjs file needed?

Vanilla node fails to import

$ node
Welcome to Node.js v13.2.0.
Type ".help" for more information.
> require('svgdom')
Thrown:
Error: No valid exports main found for '.../node_modules/svgdom'
    at resolveExportsTarget (internal/modules/cjs/loader.js:611:9)
    at applyExports (internal/modules/cjs/loader.js:492:14)
    at resolveExports (internal/modules/cjs/loader.js:541:12)
    at Function.Module._findPath (internal/modules/cjs/loader.js:643:22)
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:941:27)
    at Function.Module._load (internal/modules/cjs/loader.js:847:27)
    at Module.require (internal/modules/cjs/loader.js:1016:19)
    at require (internal/modules/cjs/helpers.js:69:18) {
  code: 'MODULE_NOT_FOUND'
}

ReferenceError: ij is not defined

When dx is set for tspan element, calling SVG.js method rbox() causes an error.

ReferenceError: ij is not defined
    at textIterator (/home/kimmo/svgdom/utils/bboxUtils.js:143:35)
    at bbox (/home/kimmo/svgdom/utils/bboxUtils.js:97:19)
    at create.getBoundingClientRect (/home/kimmo/svgdom/class/Node.js:290:14)
    at new create (/home/kimmo/myproject/node_modules/svg.js/dist/svg.js:2341:39)
    at create.rbox (/home/kimmo/myproject/node_modules/svg.js/dist/svg.js:2364:14)
    at _getBBoxForSvgElement (/home/kimmo/myproject/dist/core/get-bbox.js:297:29)

This happens because of the for loop breaking expression j < ij:

for(jl = data.length; j < ij; j++){
.

I suspect it's just a typo and should actually read j < jl.

href vs xlink:href issue in bboxUtils.js

I got an (node:3708) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'slice' of null error for this SVG fragment:
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>

I tracked it down to this code in line 57:
let ref = node.getAttribute('href')

Quickly changing it to let ref = node.getAttribute('href') || node.getAttribute('xlink:href') made it work for my case. I'm not familiar enough to suggest this as a general fix, but perhaps somebody more familiar with the meaning behind "href" and "xlink:href" could take a look at this?

Error during invocation: Error: ENOENT: no such file or directory, open '//data.trie'

Trying to use inside of a js lambda function via netlify-lambda like so:

import { createSVGWindow } from 'svgdom'
import { SVG, registerWindow } from '@svgdotjs/svg.js'

export async function handler(event, context) {
  return {
    statusCode: 200,
    headers: {
      'content-type': "image/svg",
    },
    body: returnSVG(),
  }
}

function returnSVG() {
  const window = createSVGWindow()
  const document = window.document
  registerWindow(window, document)
  draw.svg('<g><rect width="100" height="50" fill="#f06"></rect></g>')
  return draw.svg()
}

(using standin draw.svg('<g><rect width="100" height="50" fill="#f06"></rect></g>') for testing but would eventually import from an svg file)

I get this error when i hit the endpoint:

Error during invocation:  Error: ENOENT: no such file or directory, open '//data.trie'
    at Object.openSync (node:fs:505:3)
    at Object.readFileSync (node:fs:401:35)
    at Module.<anonymous> (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:221:379836)
    at Module.<anonymous> (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:221:379880)
    at r (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:1:158)
    at Object.<anonymous> (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:221:484)
    at Object.<anonymous> (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:221:252494)
    at r (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:1:158)
    at Object.fontkit (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:209:55)
    at r (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:1:81402)
    at Module../src/utils/textUtils.js (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:205:149)
    at r (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:1:81402)
    at Module../src/utils/bboxUtils.js (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:165:225)
    at r (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:1:81402)
    at Module../src/dom/svg/SVGGraphicsElement.js (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:117:194)
    at r (/Users/billy/GitHub/folia-app/kudzu-api/build/svg.js:1:81402) {
  errno: -2,
  syscall: 'open',
  code: 'ENOENT',
  path: '//data.trie'
}

The error isn't very helpful i know but it goes away when i comment out import { createSVGWindow } from 'svgdom'. I've tried importing the file directly from the node_modules in various ways but get different errors:

// import {createSVGWindow} from 'svgdom/main_module.js'
// var foo = require('../node_modules/svgdom/main-require.cjs')
// console.log({foo})

Nothing seems to work : \

Error: Cannot find module './src/utils\dirname.cjs'

Using [email protected]. When I try to require() the module in node code or interactive session, I get an error. Using node 8.17.0.

> require('svgdom')
Error: Cannot find module './src/utils\dirname.cjs'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._load (module.js:475:25)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object../dirname.cjs (/home/kimmo/project/node_modules/svgdom/main-require.cjs:96:18)
    at __webpack_require__ (/home/kimmo/project/node_modules/svgdom/main-require.cjs:20:30)
    at Module../src/utils/defaults.js (/home/kimmo/project/node_modules/svgdom/main-require.cjs:3655:70)
    at __webpack_require__ (/home/kimmo/project/node_modules/svgdom/main-require.cjs:20:30)
    at Module../main-module.js (/home/kimmo/project/node_modules/svgdom/main-require.cjs:109:80)
    at __webpack_require__ (/home/kimmo/project/node_modules/svgdom/main-require.cjs:20:30)

Could not load font file (text bbox)

Hi @Fuzzyma and team,

Been trying this since yesterday, but no luck. I've loaded 5 fonts on my server, and added their mappings and dir path as per the docs, but I get the following error:

Could not load font file for Pacifico.Error: ENOENT: no such file or directory, open '/absolute/path/to/fonts/OpenSans-Regular.ttf'

Relevant snippets of code:

const window = require('svgdom');
const SVG = require('svg.js')(window);
const document = window.document;
const path = require('path');

const fontMap = {
  'Pacifico': 'Pacifico-Regular.ttf',
  'Droid Sans': 'DroidSans-Bold.ttf',
  'Rubik': 'Rubik-Black.ttf',
  'Eczar': 'Eczar-Bold.ttf',
  'Russo One': 'RussoOne-Regular.ttf'
};
var pathToFonts = path.join(__dirname, "/fonts");
window.setFontDir(pathToFonts)
.setFontFamilyMappings(fontMap);

I've also printed the contents of the window object in case it helps anyone:

     _preloaded: {},
     fontDir: '/absolute/path/to/fonts',
     fontFamilyMappings: 
      { Pacifico: 'Pacifico-Regular.ttf',
        'Droid Sans': 'DroidSans-Bold.ttf',
        Rubik: 'Rubik-Black.ttf',
        Eczar: 'Eczar-Bold.ttf',
        'Russo One': 'RussoOne-Regular.ttf' } },

Am I doing something wrong?

Thanks a lot for your help, again.

Cheers,
Alex

0.1.x breaks style.setProperty

Hi,

I just tried to upgrade to the shiny new svgdom 0.1.4. But it breaks Element.style.setProperty():

this.style[propertyName] = value + priority ? ` !${priority}` : ''

This line, for some reason, invokes the Proxy getter again, which then returns a string, which then errors with e.g.

TypeError: Cannot create property '--size' on string ''

Using SVG.invent with SVG.js v3

I wonder if there is a way to use svg.js ability to define custom shapes with svgdom. I am using [email protected] and @svgdotjs/[email protected]. The following code works fine in the browser (from the docs):

...
SVG.Rounded = SVG.invent({
    // Define the type of element that should be created
    create: 'rect',

    // Specify from which existing class this shape inherits
    inherit: SVG.Shape,

    // Add custom methods to invented shape
    extend: {
        // Create method to proportionally scale the rounded corners
        size: function (width, height) {
            return this.attr({
                width: width
                , height: height
                , rx: height / 5
                , ry: height / 5
            })
        }
    },

    // Add method to parent elements
    construct: {
        // Create a rounded element
        rounded: function (width, height) {
            return this.put(new SVG.Rounded).size(width, height)
        }
    }
});

It fails under nodejs, however, at the line SVG.Rounded = SVG.invent({ with the following stack trace:

/home/mike/node_modules/@svgdotjs/svg.js/dist/svg.node.js:2407
    this.type = node.nodeName;
                     ^
TypeError: Cannot read property 'nodeName' of undefined
    at new Dom (/home/mike/node_modules/@svgdotjs/svg.js/dist/svg.node.js:2407:22)
    at new Element (/home/mike/node_modules/@svgdotjs/svg.js/dist/svg.node.js:2688:5)
    at new Shape (/home/mike/node_modules/@svgdotjs/svg.js/dist/svg.node.js:3106:1)
    at Function.invent (/home/mike/node_modules/@svgdotjs/svg.js/dist/svg.node.js:308:29)
    at Object.<anonymous> (/home/mike/dev/projects/svg-test/test.js:16:19)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)

SVG.extend appears to works fine with nodejs with the following code:

'use strict';

const window = require('svgdom');
const document = window.document;

const obj = require('@svgdotjs/svg.js');
obj.registerWindow(window, document);

const SVG = (arg) => {
    return obj.SVG(arg);
};

Object.assign(SVG, obj);
const canvas = SVG(document.documentElement);

// this works
SVG.extend(SVG.Element, {
...
}

// this fails
SVG.Rounded = SVG.invent({
...
}

Arc.length(): Maximum call stack size exceeded

Run in Node.js v12.15.0:

const { SVG, registerWindow } = require('@svgdotjs/svg.js');
const window = require('svgdom');
const document = window.document;
registerWindow(window , window.document);

const svg = SVG(document.documentElement);

let path = svg.path('M 11.938 22.013 A 0.125 0.125 0 1 1 11.791 21.913');

let len = path.length();

Last line produces the following error:

/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/class/Point.js:5
  constructor (x, y) {
              ^

RangeError: Maximum call stack size exceeded
    at new Point (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/class/Point.js:5:15)
    at Point.clone (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/class/Point.js:24:12)
    at new Arc (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:171:18)
    at Arc.splitAt (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:275:7)
    at Arc.length (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:258:20)
    at Arc.length (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:266:19)
    at Arc.length (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:266:19)
    at Arc.length (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:266:19)
    at Arc.length (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:266:19)
    at Arc.length (/Users/mlg/code/ldb-streamline-data/node_modules/svgdom/utils/pathUtils.js:266:19)

As far as I can see it's a valid arc command, though.

EDIT:
"@svgdotjs/svg.js": "^3.0.16",
"svgdom": "0.0.21"

EDIT 2:
running the same calculation in the browser is sucessful and returns a length of 0.5878579616546631

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script type="module">
    import { SVG } from './node_modules/@svgdotjs/svg.js/dist/svg.esm.js';
    
    let svg = SVG();
    
    let path = svg.path('M 11.938 22.013 A 0.125 0.125 0 1 1 11.791 21.913');

    let len = path.length();
    
    console.log(len);
  </script>
</body>
</html>

Issue parsing transform matrix with leading space (easy fix!)

I just encountered an issue where I didn't get correct bounding boxes (they had null and NaN values).

I tracked it down to this piece of SVG: transform="matrix( 1, 0, 0, 1, 0,0) "
Changing it to this makes it work: transform="matrix(1, 0, 0, 1, 0, 0) "

It got messed up by the leading space, since the regexes aren't very clean. But there is a simple fix:

In the file node.js in the matrixify function, line 272 change the following:
from: kv[1].split(regex.delimiter)
to: kv[1].trim().split(regex.delimiter)

A more "correct" solution likely would be to check if we should delimit by commas or spaces, and regex accordingly.

core-js 2 is no longer supported

When installing svgdom, NPM complains that core-js version 2.6 is no longer supported, and core-js version 3 or higher should be used.
That being said -- do you need core-js at all? (Also -- 98 packages? really? It would probably be cheaper to emit SVG using just string concatenation...)

SVGElement is not defined

Just stumbled upon this project, and it looks like a good solution for serving svg's.

However, when attempting to use the basic example, I immediately run into the below issue. I haven't used SVG.js before, so I'm not really sure where to even begin debugging this.

ReferenceError: SVGElement is not defined
    at /www/server/node_modules/svg.js/dist/svg.js:278:68
    at Object.filter (/www/server/node_modules/svg.js/dist/svg.js:261:11)
    at Object.filterSVGElements (/www/server/node_modules/svg.js/dist/svg.js:278:17)
    at create.children (/www/server/node_modules/svg.js/dist/svg.js:3088:38)
    at create.each (/www/server/node_modules/svg.js/dist/svg.js:3129:27)
    at create.writeDataToDom (/www/server/node_modules/svg.js/dist/svg.js:1259:12)
    at create.svg (/www/server/node_modules/svg.js/dist/svg.js:1242:14)
    at /www/server/routes/svg.js:16:20
    at Layer.handle [as handle_request] (/www/server/node_modules/express/lib/router/layer.js:95:5)
    at next (/www/server/node_modules/express/lib/router/route.js:131:13)
    at Route.dispatch (/www/server/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/www/server/node_modules/express/lib/router/layer.js:95:5)
    at /www/server/node_modules/express/lib/router/index.js:277:22
    at param (/www/server/node_modules/express/lib/router/index.js:349:14)
    at param (/www/server/node_modules/express/lib/router/index.js:365:14)
    at Function.process_params (/www/server/node_modules/express/lib/router/index.js:410:3)

The relevant route;

const express = require('express');
const router = express.Router();

const window   = require('svgdom')
const SVG      = require('svg.js')(window)
const document = window.document

router.get( "*", function( req, res, next ){
    // create svg.js instance
    const draw = SVG(document.documentElement)

    // use svg.js as normal
    draw.rect(100,100).fill('yellow').move(50,50)

    // get your svg as string
    // res.setHeader( "Content-Type", "image/svg+xml");
    res.send(draw.svg());
});

module.exports = router;

draw.node.outerHtml is likewise undefined...

namespace not supported

setAttributeNS just maps to setAttribute at the moment. Imo it should be the other way round and teh ns should be added to the markup, too

Call stack exceeded when getting the length of a circular path

The following results in RangeError: Maximum call stack size exceeded:

const window = require('svgdom')
const document = window.document
const {SVG, registerWindow} = require('@svgdotjs/svg.js')

registerWindow(window , window.document)

const canvas = SVG(document.documentElement)

// A circular path
const path = canvas.path('M0.5 50a49.5 49.5 0 1 0 99 0 49.5 49.5 0 1 0-99 0');

// Gets RangeError: Maximum call stack size exceeded
const len = path.length();

Erroring on following SVG

Loading this SVG errors:

<svg xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 95 95" enable-background="new 0 0 95 95" space="preserve">
    <g>
        <defs>
            <rect id="b" x="5.851" y="0.001" width="84.374" height="94.682" />
        </defs>
        <clipPath id="a">
            <use href="#b" overflow="visible" />
        </clipPath>
        <path clip-path="url(#a)" d="M46.841,83.972c0,0-0.343,6.545-9.223,6.545c-12.297,0-24.254-21.42-24.254-33.617   c0-12.198,7.516-24.099,17.763-24.099c10.248,0,15.713,10.71,15.713,10.71V83.972z M86.463,39.644   c-13.664-24.991-39.282-7.438-39.282-7.438s-10.929-4.462-17.078-4.462c-6.148,0-24.251,5.951-24.251,30.048   c0,24.099,22.545,36.892,32.107,36.892c9.562,0,9.565-5.652,9.565-5.652s-0.343,5.652,12.639,5.652   C73.143,94.683,100.126,64.633,86.463,39.644" />
        <path clip-path="url(#a)" fill="#000000" d="M32.921,59.465c0,0.924-2.352,1.674-5.252,1.674s-5.251-0.75-5.251-1.674   s2.352-1.674,5.251-1.674S32.921,58.541,32.921,59.465" />
        <path clip-path="url(#a)" d="M48.292,24.545c0,0-0.769-20.975,21.263-24.544C72.375,21.421,48.292,24.545,48.292,24.545" />
        <path clip-path="url(#a)" fill="#000000" d="M46.756,30.793c0,0-13.579-21.644-23.058-23.652   c-2.306,2.677-2.817,4.463-2.817,4.463S34.714,15.843,46.756,30.793" />
        <path clip-path="url(#a)" fill="#000000" d="M35.079,47.166c-0.407,0.852-2.909,0.757-5.586-0.213   c-2.679-0.97-4.518-2.448-4.111-3.302c0.408-0.853,2.909-0.759,5.586,0.212C33.646,44.833,35.487,46.312,35.079,47.166" />
        <path clip-path="url(#a)" fill="#000000" d="M37.618,71.495c0.418,0.849-1.403,2.346-4.067,3.342   c-2.666,0.996-5.166,1.116-5.584,0.268c-0.418-0.849,1.403-2.347,4.067-3.343C34.7,70.767,37.199,70.646,37.618,71.495" />
    </g>
</svg>

How to "clean up" the element

Hi,
What is the suggested way to empty the document.documentElement to start over with a clean SVG element?
Right now my solution is to document.createElement('svg'), then create the SVG with it, and then do document.removeChild(element). Or is there a better solution? By just using re-using document.documentElement the old SVG image will stay there.
Thanks

TypeError: Cannot read property 'nodeType' of undefined

Hello,

I'm getting an error when calling the svg function to load an svg file (using svg.js 3.0):

const window = require('svgdom');
const document = window.document;
const {SVG, registerWindow} = require('@svgdotjs/svg.js');
registerWindow(window , document);
let data = fs.readFileSync(filePath, 'utf8');
let element = document.createElement('svg');
const canvas = SVG(element);
canvas.svg(data);

In svgdom/class/Node.js:
image

Called by svg.node.js:

image

Getting bbox of element "g" is not possible

Hello,

First, thanks for such a useful tool!

I use this library to analyze SVGs which are -in other app- displayed and modified in the browser (with SVG.js v3, too).
For instance i would like to get the position of several elements (mostly g).
I set the default font through config, and then :

fs.readFile("./test.svg", "utf8", (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  const window = createHTMLWindow();
  const document = window.document;
  registerWindow(window, document);
  var svgDoc = SVG(document.documentElement);
  svgDoc.svg(data);
  var title = svgDoc.findOne("#my_g_element");
  console.log(title.x(), title.y());
});

It gives me an error with all tested elements:

Error: Getting bbox of element "g" is not possible. TypeError: node.matrixify is not a function
    at getBox.call.el (/[...]/node_modules/@svgdotjs/svg.js/dist/svg.node.js:3124:13)

It should say that using .x() and .y() on these elements works well in the browser.

Is this an expected behavior?

Closing tag error

Importing svg with path causes an error:

Error: Closing tag was found which was not opened before at col ...

Code:

const window = require('svgdom');
const SVG = require('svg.js')(window);
const document = window.document;
const canvas = SVG(document.documentElement).size('100%', '100%');

const svgStr1 = `<g><rect width="100" height="50" fill="#f06"></rect></g>`;

const svgStr2 = `
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg version="1.0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 91.46" enable-background="new 0 0 100 91.46" xml:space="preserve"><path d="M49.999,91.46c3.944-3.943,26.458-26.47,40.533-40.543c12.61-12.611,12.341-30.992,0.876-42.395
	C79.943-2.884,61.404-2.834,49.999,8.632C38.595-2.834,20.056-2.884,8.591,8.522C-2.874,19.925-3.142,38.306,9.467,50.917
	C23.541,64.99,46.058,87.517,49.999,91.46z"></path></svg>`;

const svg1 = canvas.svg(svgStr1); // works well
console.log(svg1.svg()); 

console.log('\n------------------\n');

const svg2 = canvas.svg(svgStr2); // error 
console.log(svg2.svg());

But works well in browser, code here

SVG.js 3.0.+ Support

Hey there,

I'm just wondering how to use the new svg.js 3.0.5 with svgdom. The constructor of svg.js has changed.

Thanks

Do you have a typescript definition?

I have been testing this project and so far it seems like it will work for my needs. I like the simplicity of svg.js and svgdom compared to the d3-based options. For the best fit, it would have a typescript definition file. Is one available? This isn't a deal breaker since I can fall back to a generic definition or try to build one that fits what I need. -- thank you!

Gl-Matrix reference requires window

gl-matrix.js:38 references window and throws an undefined error when trying to use this with Node:

const temp = require('svgdom');

Is this due to a gl-matrix update, and if so what version should I be using?

Cannot import module on Node v12.13.0

Hey folks, just trying get this up and running, but falling at the first hurdle!

  1. installed the package with npm install @svgdotjs/svg.js svgdom
  2. import the package using import { createSVGWindow } from "svgdom";
  3. run with node --experimental-modules index.mjs using Node v12.13.0
  4. get the following error in the terminal:
internal/modules/esm/default_resolve.js:82
  let url = moduleWrapResolve(specifier, parentURL);
            ^

Error: Cannot resolve package exports target 'undefined' matched for '.' in C:\*****\server\node_modules\svgdom\package.json, imported from C:\*****\server\routes\composite\utils.mjs
    at Loader.resolve [as _resolve] (internal/modules/esm/default_resolve.js:82:13)
    at Loader.resolve (internal/modules/esm/loader.js:73:33)
    at Loader.getModuleJob (internal/modules/esm/loader.js:147:40)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:41:40)
    at link (internal/modules/esm/module_job.js:40:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Apologies if this is something glaringly obvious that I'm doing wrong at my end.

are stylesheets supported

<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
  <style>    circle {      fill: gold;      stroke: maroon;      stroke-width: 2px;    }  </style>
  <circle id="maru" cx="5" cy="5" r="4" />
</svg>
const maru = document.querySelector('#maru');
const style = window.getComputedStyle(maru);
console.log(style.getPropertyValue('fill')); // <- null

Error while trying to load fonts

Hello,

First of all, thanks for this great addition to svg.js

Have been fiddling with svgdom for a couple days and I keep getting an error while I'm trying to preload my fonts. I'm sure the path is correct.

Here is my code:

const window = require('svgdom')
const path = require('path');
	
var pathToFonts = path.join(__dirname, "/fonts");

console.log(pathToFonts);

window.setFontDir(pathToFonts)
.setFontFamilyMappings(
	{'Bebas': 'BEBAS.TTF'}
);

And here's the error:

path.js:28
throw new TypeError('Path must be a string. Received ' + inspect(path));
TypeError: Path must be a string. Received undefined

When I remove the line

.setFontFamilyMappings(
	{'Bebas': 'BEBAS.TTF'}
);

the error goes away, but of course, the fonts aren't loaded either...

What might be wrong here?

Mysterious inner svg with polyline.

Hi!
I have same code for browser and for nodejs, and generated svg string differs badly.
When I do it at node, SVG contains excessive inner svg element with polyline, which supposed to be invisible.
But graphicsmagic doesn't agree to work with such things.
My code for Node:

const window   = require('svgdom');
  const SVG      = require('svg.js')(window);
  const document = window.document;

let draw = SVG(document.documentElement);
//Do nothing! Or draw something - doesn't matter
console.log(draw.svg());

Output SVG:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs">
<defs id="SvgjsDefs1001"></defs>
<svg id="SvgjsSvg1002" width="2" height="0" style="overflow: hidden; top: -100%; left: -100%; position: absolute; opacity: 0">
<polyline id="SvgjsPolyline1003" points="0,0"></polyline>
<path id="SvgjsPath1004" d="M0 0 "></path></svg></svg>

gm says when seeing this:

Error: gm compare: Non-conforming drawing primitive definition (polyline).

0.1.x: xmlns attribute eaten?

Sorry, one and a half more issues :-D

I have lots of unit tests and when switching to svgdom 0.1.8 I see that the following elements

<math xmlns="http://www.w3.org/1998/Math/MathML">
<svg xmlns="http://www.w3.org/2000/svg" width=...>

turn to

<math>
<svg width=...>

So the xmlns attribute disappears.

Also, the half-issue ;-), only when KaTeX is used, all the style attributes get spaces and the final style rule gets an ;. All my other test cases don't change. I don't care much but maybe it's something you are interested in 😁

How can I use this to do testing in React?

The tests in my project use JSDOM, which makes testing the rendering of svg elements impossible. Can I use SVGDOM to help with testing React components with svg in them? How can I do this? In this code, the Map component uses react-simple-maps to render an svg map.

  it('should render an empty map', () => {
    const { container } = renderWithStores(
      Map,
      {
        dataCenterLocationsItems: [],
      },
      {},
    );
    const map = container.querySelector('.rsm-svg') as SVGElement;
    const circles = container.querySelectorAll('circle');
    expect(circles.length).toBe(0);
    expect(map).toBeDefined();
  });

renderWithStores which use react-testing-library.

import React from 'react';
import { Provider } from 'mobx-react';
import { render } from 'react-testing-library';
import { HashRouter } from 'react-router-dom';

export function renderWithStores(Component, props, stores) {
  return render(
    <HashRouter>
      <Provider {...stores}>
        <Component {...props} />
      </Provider>
    </HashRouter>,
  );
}

Still getting error for Node SSR

Hi, and thanks for this fix but even with the right svg.js version 2.5.1 as mentioned in the README i still get this error:

capture d ecran 2018-12-29 a 17 39 22

Here is the integration:

const window   = require('svgdom');
const SVG      = require('svg.js')(window);
global['SVG'] = SVG; // Polyfill missing SVG props for svgjs lib

svg.js: 2.5.2
svgdom: 0.0.15

I'm using AngularUniversal

Am i missing something?

I also used domino to create a window object and it has the method but not the window created from svg.js.

Run the bbox function on a group in nodejs, it sometimes returns a zero value.

Bug report

Fiddle

https://jsfiddle.net/SooChangLee/9wck4v3z/

Explanation

The problem does not appear in the browser, but in nodeJS, the result of the bbox function in the first group is zero.(The fiddle works fine.)

Run the bbox function on a group in nodejs, it sometimes returns a zero value.
I use svg.js 2.7.1, svgdom 0.1.27 on nodeJS.

run the bbox () function on a child group of an svg file, most groups return the correct result, but one group returns zero.

{
w: 0,
h: 0,
x2: 0,
y2: 0,
cx: 0,
cy: 0,
x: 0,
y: 0,
width: 0,
height: 0
}

Getting text bboxes

Hi,

First of all, I cannot thank you guys enough for both this library and SVG.js - they are truly outstanding.

However, I have small issue with svgdom. You mention in your documentation that text bboxes are not yet implemented, and unfortunately this feature is crucial for our project.

I can imagine you're busy people, and we can't rely on you developing the feature, so I'm hoping you can at least offer me a few pointers on how to get around it...

Like you mention in your docs, I've tried parsing the font file, and from there I've computed a "theoretical" or "scaled" value based on yMin, yMax and the units per em. However, I can never arrive at the same figure as Chrome (and the difference is significant +10% pixels)...

Are there any pointers you could offer on how to get around this issue? Do you have any idea of how the different browsers compute this, or could you point me to any relevant snippets of code, documentation, or potential ways of solving this?

Again, thanks a lot for your time.

Cheers,
Alex

Update: I'm adding a shout-out to @Fuzzyma who I see is a svg.js contributor and very knowledgeable in headless SVGs... I also found that you asked a similar question on SO recently (http://stackoverflow.com/questions/43140096/reproduce-bounding-box-of-text-in-browsers) so maybe you can report your findings or at the very least benefit from this discussion. Thanks!!

High level use case

Could you please explain the high level use case on the top of the readme.

I am (and maybe others which are not familiar with the details yet) very curious why you want to do this.

<style> support?

Hey there! I'm using svgdom to extract SVG path data to be used as input to a pen plotter. I'd like to use stroke color information to separate layers so that, for example, I can lay down all the red paths with one pen, then switch pens, and lay down all the blue paths with a different pen.

Currently I'm able to extract stroke color data correctly if it's specified either as a stroke="#f00" attribute or a style="stroke: #f00" attribute, but svgdom doesn't seem to parse css that's present in a <style> tag.

Is this something you'd consider supporting?

Load an SVG file and use it with svg.js

This looks like where I need to be, but I'm having trouble figuring this one out.

I have an SVG file on my server that I want to be able to edit the text in and then return a temporary PNG for instance to create a PDF

Once I get to the editing an SVG I should be able to finish the rest.

I was able to grab the DOM elements out of the SVG with fs.readFile, but how do I turn this into an SVG I can make edits to with svg.js?

{svg.js GROUP}.svg() throw "Error: Doctype can only be appended to document"

Can't success running svg.js method svg().
The code that worked before the update was broken.

I update svgdom.

-    "svgdom": "0.0.21",
+    "svgdom": "0.1.4",

(use svg.js version is "svg.js": "^2.7.1",)

call: group_edge_icon.svg(rendering_handle.resource.edge_icon_svg);
(rendering_handle.resource.edge_icon_svg is raw svg string from read svg file.)

throw this error.
Error: Doctype can only be appended to document

====

console.log(rendering_handle.resource.edge_icon_svg)

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
	 y="0px" width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
<line fill="#FFFFFF" stroke="#000000" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="30" y1="2" x2="2" y2="30"/>
<line fill="#FFFFFF" stroke="#000000" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="30" y1="12" x2="12" y2="30"/>
<line fill="#FFFFFF" stroke="#000000" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" x1="30" y1="22" x2="22" y2="30"/>
</svg>

throw call graph

/home/nuka/daisy_sequence/daisy_sequence/node_modules/svgdom/main-require.cjs:1879
      throw new Error('Doctype can only be appended to document')
      ^

Error: Doctype can only be appended to document
    at SAXParser.HTMLParser.parser.ondoctype (/home/nuka/daisy_sequence/daisy_sequence/node_modules/svgdom/main-require.cjs:1879:13)
    at emit (/home/nuka/daisy_sequence/daisy_sequence/node_modules/sax/lib/sax.js:624:35)
    at emitNode (/home/nuka/daisy_sequence/daisy_sequence/node_modules/sax/lib/sax.js:629:5)
    at SAXParser.write (/home/nuka/daisy_sequence/daisy_sequence/node_modules/sax/lib/sax.js:1132:13)
    at HTMLParser (/home/nuka/daisy_sequence/daisy_sequence/node_modules/svgdom/main-require.cjs:1929:10)
    at HTMLElement.set (/home/nuka/daisy_sequence/daisy_sequence/node_modules/svgdom/main-require.cjs:933:77)
    at initializer.svg (/home/nuka/daisy_sequence/daisy_sequence/node_modules/svg.js/dist/svg.js:1247:24)
    at Function.draw_fragment (/home/nuka/daisy_sequence/daisy_sequence/js/renderer.js:718:21)
    at Function.rendering_ (/home/nuka/daisy_sequence/daisy_sequence/js/renderer.js:262:14)
    at Function.get_dummy_draw_from_diagram_ (/home/nuka/daisy_sequence/daisy_sequence/js/daisy-io.js:104:12)

rbox for text element doesn't take letter-spacing into account

Hi again!

I'm trying to get a tight bounding box of a text, but I'm seeing a bit different results between Chrome and svgdom.

This first result is from Chrome, using svg.querySelector('#small-header').getBBox().
screenshot 2017-06-18 13 30 41

This second result is with [email protected], [email protected] + svgdom (latest master) combo, using .rbox() method for the tspan element (not the text element as with Chrome). I used tspan because rbox for the text element gave even larger bounding box which I suppose vertically starts at y:3727 and ends at y:3727+417 (y attribute of the tspan).

screenshot 2017-06-18 13 33 33

My SVG is this:

<svg height="4700px" version="1.1" viewBox="0 0 3500 4700" width="3500px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <!-- ... -->
    <g id="labels" transform="translate(1773.000000, 3727.000000)">
        <g id="center" text-anchor="middle">
            <text fill="#000000" font-family="JosefinSans, Josefin Sans" font-size="90" font-weight="normal" id="small-header" letter-spacing="18.363636">
                <tspan x="0" y="417">TEST STRING</tspan>
            </text>
        </g>
    </g>
    <!-- ... -->
</svg>

JosefinSans font loads correctly, using the font mappings. I'm pretty sure this happens because of the letter-spacing attribute. Bounding box was correct when there's no letter-spacing.

I would be interested to fix this behavior in svgdom, but do you have some pointers how to implement it? I quickly checked fontkit but didn't see any mentions of letter spacing.

Example does not run

When I install the current versions of svg.js and svgdom like so:

 ~/temp > mkdir svg.js-test
 ~/temp > cd svg.js-test/
 ~/temp/svg.js-test > npm init
 [usual stuff here]
 ~/temp/svg.js-test > npm i svg.js svgdom
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN [email protected] No description
npm WARN [email protected] No repository field.

+ [email protected]
+ [email protected]
added 79 packages from 170 contributors and audited 318 packages in 10.501s
found 0 vulnerabilities

 ~/temp/svg.js-test > node -v
v9.5.0

and then try the example, the first line fails like so:

~/temp/svg.js-test/ > node
> const window = require('svgdom')
ReferenceError: window is not defined
    at Object.<anonymous> (/Users/jasonthorpe/temp/svg.js-test/node_modules/core-js/library/modules/_global.js:2:14)
    at Module._compile (module.js:660:30)
    at Object.Module._extensions..js (module.js:671:10)
    at Module.load (module.js:573:32)
    at tryModuleLoad (module.js:513:12)
    at Function.Module._load (module.js:505:3)
    at Module.require (module.js:604:17)
    at require (internal/module.js:11:18)

That error is fixed by using var instead of const, but then the second line throws an error:

 ~/temp/svg.js-test > node
> var window = require('svgdom')
undefined
> const SVG      = require('svg.js')(window)
TypeError: element.appendChild is not a function
    at new create (/Users/jasonthorpe/temp/svg.js-test/node_modules/svg.js/dist/svg.js:3618:17)
    at SVG.SVG (/Users/jasonthorpe/temp/svg.js-test/node_modules/svg.js/dist/svg.js:27:15)
> SVG
ReferenceError: SVG is not defined

Now if the first two const tokens are converted to var, the second line still throws an error, but the rest of the readme still works with the exception that draw.node.outerHtml is undefined, whereas the readme would suggest that this should be the same as draw.svg()

for what it's worth, I put the package-loc.json file generated by the npm i svgdom svg.js call in this gist.

TypeError: Cannot read property 'startsWith' of null

I'm using svgdom to run svg.js on NodeJS v8.7.0. I'm using svg.select("[id^=my]") and getting the following error:

message: "Cannot read property 'startsWith' of null"
stack: "TypeError: Cannot read property 'startsWith' of null
at create.^= (c:\git\data-import-scripts\node_modules\svgdom\class\CssQuery.js:171:60)
at create.matches (c:\git\data-import-scripts\node_modules\svgdom\class\CssQuery.js:262:27)
at create.matchHelper (c:\git\data-import-scripts\node_modules\svgdom\class\CssQuery.js:99:37)
at create.matches (c:\git\data-import-scripts\node_modules\svgdom\class\CssQuery.js:92:17)
at create.matches (c:\git\data-import-scripts\node_modules\svgdom\class\Node.js:369:34)
at create.querySelectorAll (c:\git\data-import-scripts\node_modules\svgdom\class\Node.js:374:31)
at create.querySelectorAll (c:\git\data-import-scripts\node_modules\svgdom\class\Node.js:375:45)
at create.querySelectorAll (c:\git\data-import-scripts\node_modules\svgdom\class\Node.js:375:45)
at Function.SVG.select (c:\git\data-import-scripts\node_modules\svg.js\dist\svg.js:5322:40)
at create.select (c:\git\data-import-scripts\node_modules\svg.js\dist\svg.js:5331:16)"

I believe the reason I'm getting this error is because not every element in my SVG document has an id. I stepped through the execution and found that the attributeMatcher for "^=" is being called with i=false, a="my" and b=null.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.