Nodejs script fails to print after d3.json()?

≡放荡痞女 提交于 2019-12-25 04:08:08

问题


(Edit: the question have been rewritten to better isolate the issue.)


I'am writing a single D3js script.js which could be reused "as it" in both web browser for client side and nodejs for server side uses. I made some good progress :

  1. a single d3js script.js indeed create basic svg shapes on both client and server sides. On web browser displaying the viz, on server side outputing the wanted map.svg file.
  2. I have a more complex d3js map making code: client side it works like a charm (link)

but! the nodejs call fails without error message. The xhr d3.json() seems to be hanging up waiting and not firing up its callback:

mapIt.node.js (server side, fails)

Pass variables and run me:

$ WIDTH=800 ITEM="world-1e3" node script.node.js

Content of script.node.js:

var jsdom = require('jsdom');         // npm install jsdom
var fs    = require('fs');            // natively in nodejs.

jsdom.env(
  "<html><body></body></html>",       // CREATE DOM HOOK
  [ './d3.v3.min.js',             // load assets into window environment (!)
  './topojson.v1.min.js', 
  './queue.v1.min.js', 
  './script.js' ],

  function (err, window) {
    /* ***************************************************************** */
    /* Check availability of loaded assets in window scope. ************ */
    console.log(typeof window.mapIt);       // expect: 'function',  because exist in script.js !
    console.log(typeof window.doesntExist); // expect: 'undefined', because doesn't exist anywhere.
    // if all as expected, should work !

    /* ***************************************************************** */
    /* COLLECT ENV.VARIABLES ******************************************* */
    var width = process.env.WIDTH,
        target= process.env.ITEM;

    /* ***************************************************************** */
    /* D3js FUNCTION *************************************************** */
    var url = "http://rugger-demast.codio.io/output/"+target+"/administrative.topo.json";
    console.log(url);
    console.warn(window.document.URL);

    var mapIt = function(width, target){
        console.log("mapIt(): start");

        var svg = d3.select('body').append('svg')
            .attr('width', width)
            .attr('height', width/960*500);
        var projection = d3.geo.mercator()
            .scale(100)
            .translate([width / 2, height/2]);
        var path = d3.geo.path()
            .projection(projection);

        var url = "http://rugger-demast.codio.io/output/"+target+"/administrative.topo.json";

        /* FROM HERE SOMETHING FAILS ********************** */
        d3.json(url, function (error, json) { // from here: NOT fired on server side :(
        if (error) return console.warn(error);
            d3.select("svg").append("g").attr("log","d3.json"); 
            svg.append('path')
                .datum(topojson.feature(json, json.objects.admin_0))
                    .attr('d', path)
                    .attr('class', 'L0');
        });    
    };
    window.mapIt(width,target);
    /* ***************************************************************** */
    /* SVG PRINT ******************************************************* */
    // better svg header:
    var svgheader = '<?xml version="1.0" encoding="utf-8"?>\n'
    +'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
    // printing + timer, to be sure all is ready when printing file:
    setTimeout(
      fs.writeFileSync('map.svg', svgheader + window.d3.select("body").html()) ,
      30000
    );
 }
);

map.svg (incomplete)

Since d3.json callback is not fired, I get the incomplete map.svg such:

<?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 width="800" height="416.6666666666667"></svg>

Given map.svg's content, the script first work as expected, setting the svg width and height attributes, then the d3.json() doesn't work, the call back is never fired up. There is no error message back. But given where the script stop, it seems the query is hanging up waiting.

Notes:

The same exact d3js script works client side (link).

Interestingly, console.warn(window.document.URL) returns file:///data/yug/projects_active/map/script.node.js (purely local) while the d3.json() xhr request is on http://bl.ocks.org/hugolpz/raw/1c34e14d8b7dd457f802/administrative.topo.json.

Question

How to get the request working ? or How to run nodejs script with so the query is allowed ?

Testing

To try out the script (Github gist):

git clone https://gist.github.com/9bdc50271afc49d33e35.git ./map
cd ./map; npm install
WIDTH=800 ITEM="world-1e3" node script.node.js

Help: D3js>API>Requests


回答1:


Replace :

setTimeout(
      fs.writeFileSync('map.svg', svgheader + window.d3.select("body").html()) ,
      10000
    );

by

setTimeout(
      function(){ fs.writeFileSync('map.svg', svgheader + window.d3.select("body").html()) } ,
      10000
    );


来源:https://stackoverflow.com/questions/28663300/nodejs-script-fails-to-print-after-d3-json

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!