Svg.js: Is there a way to make svg.js work with jsdom

Created on 21 Mar 2016  路  27Comments  路  Source: svgdotjs/svg.js

Hi,
I'm trying to make svg.js work with jsdom in node.js but it looks like jsdom work with svg 1.1.
Is there a way to make the library work with Node.js using jsdom or something else?

Most helpful comment

@Tpower36 we just released the new project svgdom which enables svg.js to run on node. Its nothing big but give it a try and report back :)

All 27 comments

There are a few issues regarding node.js and svg.js. Maybe you try the approaches written there. E. G. You can pass a custom window object while requiring svg.js:

var SVG = require('svg.js')(customWindow) 

see #352

the require works fine, the problem comes when I try to use the library, the console prints 'false' for SVG.supported and the draw variable is undefined which makes it unusable.

var jsdom = require('jsdom');
var fs = require('fs');
jsdom.env(
      "test.html",
      function (err, window) {
          var svg = require('svg.js')(window)
          console.log(SVG.supported)
          var draw = SVG('drawing').size('100%', '100%')
      }
);

Is there a way to fix this?

Does the window object has a document property? The supported check just tests if it is possible to create namespaced elements (document.createElementNS). If jsdom cant do that it wouldnt work

See https://github.com/wout/svg.js/issues/352#issuecomment-150836968 for a good explanation (especially the links).

I'm sorry if I missed something but I did like in the #352 (comment) and I still have the same issue, SVG.supported returns false. Here is my code:

var jsdom = require('jsdom').jsdom
var document = jsdom('<div id="drawing"></div>')
var window = document.defaultView

var svgjs = require('svg.js')(window)
console.log(SVG.supported)
var svg = SVG('test').size(300, 300)

In your code it should be var svg = SVG('drawing').size(300, 300) but this doenst fix the support problem though...

Indeed, I changed it but it still doesn't work.

Actually I found out that !!document.createElementNS returns true but the following line returns false:
!! document.createElementNS(SVG.ns,'svg').createSVGRect

Just try to comment out this line and see if svg.js works anyway. We dont rly use this function. Its more or less a support check for svg in general

I tried that, I now have SVGElement is not defined on line 260...
return [].filter.call(p, function(el){ return el instanceof SVGElement })

ahh, okay... try to replace this one with window.SVGElement - all implicit globals have to be prefixed with window to make it work (at least that is what I guess)

I tried it, it doesn't work, jsdom does not support SVGElement.

EDIT: But I did make svg.js work with jsdom by using the 1.1.0 release, editing the factory by adding the possibility to pass a window and by commenting out the createSVGRect in the support test.

Thanks for your help!

@Tpower36 Have you considered using PhantomJS? It's a server side version of WebKit so it should do the trick.

@wout Yes I tried with PhantomJS it works fine, I also tried by using the phantom module in node.js and it works too. I wanted to make the svg.js library run in native Node.js to make tests and to find out which solution is the fastest

From what I read, jsdom is a pretty basic implementation and does not support SVG.

It is basic indeed but it works with SVG 1.0 and I could make the 1.1.0 release of svg.js run in Node.js.
I just compared the two solutions and the one with PhantomJS is pretty slow because it needs to start the headless browser before generating the svg which takes almost 1 second

Hi all,

not a solution right now, but a proposal. This code is cheating :metal: but works

/**
 * Polyfill (dummy ;) createElementNS
 */

function createElementNS (ns, name) {
  function element (name) {
    this.name = name
  }

  function setAttribute (name, value) {
    this[name] = value
  }

  element.prototype.setAttribute = setAttribute

  function createSVGRect () {}

  element.prototype.createSVGRect = createSVGRect

  return new element(name)
}

var jsdom = require('jsdom').jsdom
var doc = jsdom('<!doctype html><html><body>hello jsdom</body></html>');

// Create global window and document
window = doc.defaultView
document = window.document

// Inject polyfill
document.createElementNS = createElementNS

var SVG = require('svg.js')
console.log(SVG)

I mean, _createElementNS_ could be polyfilled server side. It is a long task to polyfill everything svg.js can do, but it would make svg.js conquer the server side.
Does it make sense?

I just remembered PhantomJS. Its a headless browser based on webkit..
Maybe we can use this one to render svg on serverside?

// edit: sorry - didn't see all the other answers :D
@Tpower36 you can run PhantomJS as server so it doesn't has to start every time. It's very fast then. I will update my answer as soon as I find the link where I read that

@Fuzzyma PhantomJS can be run as a server but it is still experimental and not intended to run in a production environment.
http://phantomjs.org/api/webserver/

  const document = jsdom.jsdom();
  const element = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  console.log(element.outerHTML);

From here: https://github.com/tmpvar/jsdom/issues/1371

Looks like createElementNS is / was supported

Like I wrote in this comment, I know that createElementNS is supported and this line works.
What is not supported in jsdom is the SVGElement and the createSVGRect. Thats why I could make svg.js work with an older version (the 1.1.0)

@fibo Hi! I tried your solution but it does not work because when I try to create a new drawing I get this error: "node.getAttribute is not a function" on the line 1055 of the svg.js file.

Here is my code:

function createElementNS (ns, name) {
  function element (name) {
    this.name = name
  }

  function setAttribute (name, value) {
    this[name] = value
  }

  element.prototype.setAttribute = setAttribute

  function createSVGRect () {}

  element.prototype.createSVGRect = createSVGRect

  return new element(name)
}

var jsdom = require('jsdom').jsdom
var doc = jsdom('<!doctype html><html><body><div id="drawing"></div></body></html>');


window = doc.defaultView
document = window.document


document.createElementNS = createElementNS

var SVG = require('svg.js')
//The following line does not work:
var draw = SVG('drawing').size(300, 300) 

@Tpower36 you already said it yourself that createElementNS is supported in jsdom anyway so we dont have to polyfill that one. The error is a consequence of the uncomplete solution of fibo.

The only way to make it work is to remove all instanceof SVGElement stuff from the lib OR implement SVG Elements in jsdom.

Closing this for now. Please let us know if you have any more questions.

@Tpower36 we just released the new project svgdom which enables svg.js to run on node. Its nothing big but give it a try and report back :)

check out also svgx which is renders SVG server side

Was this page helpful?
0 / 5 - 0 ratings