SVG al lado del servidor PNG-usando node.js



d3.js (1)

Intento seguir este tutorial sobre la conversión de una Vis SVG d3.js a una PNG en el lado del servidor (usando Node.js) http://eng.wealthfront.com/2011/12/converting-dynamic-svg-to-png-with.html

Enlace al código completo: https://gist.github.com/1509145

Sin embargo, sigo recibiendo este error cada vez que intento hacer una solicitud para cargar mi página

    /Users/me/Node/node_modules/jsdom/lib/jsdom.js:171
        features   = JSON.parse(JSON.stringify(window.document.implementation._fea
                                                              ^
    TypeError: Cannot read property 'implementation' of undefined
        at exports.env.exports.jsdom.env.processHTML (/Users/dereklo/Node/node_modules/jsdom/lib/jsdom.js:171:59)
        at Object.exports.env.exports.jsdom.env (/Users/dereklo/Node/node_modules/jsdom/lib/jsdom.js:262:5)
        at Server.<anonymous> (/Users/dereklo/Node/Pie/pie_serv.js:26:9)
        at Server.EventEmitter.emit (events.js:91:17)
        at HTTPParser.parser.onIncoming (http.js:1785:12)
        at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:111:23)
        at Socket.socket.ondata (http.

¿Alguien sabe por qué esto podría ser? He instalado el módulo jsdom muy bien, así que no sé realmente qué está causando estos problemas ... gracias de antemano.

EDITAR

Este es el código que estoy usando para implementar el servidor node.js. Mi último problema está debajo de esta fuente ...

var http = require('http'),
    url = require('url'),
    jsdom = require('jsdom'),
    child_proc = require('child_process'),
    w = 400,
    h = 400,
    __dirname = "Users/dereklo/Node/pie/"

   scripts = ["/Users/dereklo/Node/pie/d3.min.js",
               "/Users/dereklo/Node/pie/d3.layout.min.js",
               "/Users/dereklo/Node/pie/pie.js"],
      //scripts = ["./d3.v2.js",
        //         "./d3.layout.min.js",
          //       "./pie.js"]

    htmlStub = '<!DOCTYPE html><div id="pie" style="width:'+w+'px;height:'+h+'px;"></div>';

http.createServer(function (req, res) {

  res.writeHead(200, {'Content-Type': 'image/png'});
  var convert = child_proc.spawn("convert", ["svg:", "png:-"]),
      values = (url.parse(req.url, true).query['values'] || ".5,.5")
        .split(",")
        .map(function(v){return parseFloat(v)});

  convert.stdout.on('data', function (data) {
    res.write(data);
  });
  convert.on('exit', function(code) {
    res.end();
  });

  jsdom.env({features:{QuerySelector:true}, html:htmlStub, scripts:scripts, done:function(errors, window) {
    var svgsrc = window.insertPie("#pie", w, h, values).innerHTML;

  console.log("svgsrc",svgsrc);

    //jsdom's domToHTML will lowercase element names
    svgsrc = svgsrc.replace(/radialgradient/g,'radialGradient');
    convert.stdin.write(svgsrc);
    convert.stdin.end();
  }});
}).listen(8888, "127.0.0.1");

console.log('Pie SVG server running at http://127.0.0.1:8888/');
console.log('ex. http://127.0.0.1:8888/?values=.4,.3,.2,.1');

Último edicion

    events.js:66
        throw arguments[1]; // Unhandled 'error' event
                       ^
Error: This socket is closed.
    at Socket._write (net.js:519:19)
    at Socket.write (net.js:511:15)
    at http.createServer.jsdom.env.done (/Users/dereklo/Node/Pie/pie_serv.js:38:19)
    at exports.env.exports.jsdom.env.scriptComplete (/Users/dereklo/Node/node_modules/jsdom/lib/jsdom.js:199:39)

https://code.i-harness.com


Esta puede ser una respuesta útil a su pregunta si elimina esa estipulación "using node.js". Si no lo ayuda, tal vez los visitantes posteriores lo encuentren interesante.

He estado trabajando durante algún tiempo para resolver este mismo problema (rasterización d3 del lado del servidor), y he encontrado que PhantomJS es la mejor solución.

server.js:

var page = require('webpage').create(),
    renderElement = require('./renderElement.js'),
    Routes = require('./Routes.js'),
    app = new Routes();

page.viewportSize = {width: 1000, height: 1000};
page.open('./d3shell.html');

app.post('/', function(req, res) {
    page.evaluate(new Function(req.post.d3));
    var pic = renderElement(page, '#Viewport');
    res.send(pic);
});

app.listen(8000);

console.log('Listening on port 8000.');

Routes.js: https://gist.github.com/3061477
renderElement.js: https://gist.github.com/3176500

d3shell.html debería verse algo así como:

<!DOCTYPE HTML>
<html>
<head>
    <title>Shell</title>
</head>
<body>
    <div id="Viewport" style="display: inline-block"></div>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/d3/2.8.1/d3.v2.min.js" type="text/javascript"></script>
</body>
</html>

A continuación, puede iniciar el servidor con phantomjs server.js y POST d3 = [d3 code que representa #Viewport], y el servidor responderá con un png con codificación base64.

(Requiere PhantomJS 1.7 o superior)





d3.js