d3.json() 后 Nodejs 脚本无法打印?

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

(编辑: 问题已被重写以更好地隔离问题。)


我正在编写一个 D3js script.js,它可以在客户端的 Web 浏览器和服务器端的 nodejs 中重复使用 "as it"。我取得了一些不错的进步 :

  1. 单个 d3js script.js 确实可以在客户端和服务器端创建基本的 svg 形状。在显示可视化项的 Web 浏览器上,在服务器端输出所需的 map.svg 文件。
  2. 我有一个更复杂的 d3js 地图制作代码:客户端它工作起来很有魅力 (link)

但是! nodejs 调用失败没有错误消息。 xhr d3.json() 似乎正在挂断等待并且没有触发其回调:

mapIt.node.js(服务器端,失败)

传递变量和运行我:

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

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(不完整)

由于 d3.json 回调没有触发,我得到不完整的 map.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 width="800" height="416.6666666666667"></svg>

给定 map.svg 的内容,脚本首先按预期工作,设置 svg widthheight 属性,然后 d3.json() 不起作用,回调永远不会被触发。没有返回错误信息。但是鉴于脚本停止的位置,查询似乎挂起等待。

备注:

完全相同的 d3js 脚本适用于客户端 (link)。

有趣的是,console.warn(window.document.URL) returns file:///data/yug/projects_active/map/script.node.js(纯本地)而 d3.json() xhr 请求在 http://bl.ocks.org/hugolpz/raw/1c34e14d8b7dd457f802/administrative.topo.json.

问题

如何让请求生效?或如何 运行 nodejs 脚本允许查询?

测试

试用脚本 (Github gist):

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

帮助:D3js>API>Requests

替换:

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

来自

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