【问题标题】:Nodejs script fails to print after d3.json()?Nodejs 脚本在 d3.json() 之后无法打印?
【发布时间】:2015-02-22 21:11:28
【问题描述】:

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


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

  1. 单个 d3js script.js 确实可以在客户端和服务器端创建基本的 svg 形状。在显示 viz 的 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) 返回 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

【问题讨论】:

  • 您是否遇到任何错误?那个队列跨域请求看起来很狡猾。
  • 跨域查询失败可能是一个线索,我确实在我的电脑上运行它,它在某些在线网站上查询 .json 数据。奇怪的是,blocks.org 上的客户端演示对这个跨域没有任何问题。但我记得 M. Bostock 的 blocks.org 有一些允许跨域的设置:“默认情况下,大多数浏览器不允许跨域请求。要启用跨域请求,请让服务器设置标题 Access- Control-Allow-Origin: * ." (source)
  • 几件事:首先,在d3.json(url, function (error, json) { ,你删除错误,记录它if (error) return console.warn(error);,这可能会提供一些线索。其次,您确定这不是竞争条件吗?您正在进行异步调用,然后等待 7 秒以写出 SVG。你确定它会完成吗?似乎有问题...
  • 另外,我认为这不是 COR 的问题。 ruggr-demast.codio.io 响应包括 Access-Control-Allow-Origin:*
  • 试图复制您的问题,但在jsdom 的内心深处发现了一个错误;显然它在 Windows 上运行不佳...... :(

标签: node.js d3.js jsdom


【解决方案1】:

替换:

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
    );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 2019-04-01
    • 2020-06-29
    • 1970-01-01
    • 2019-09-19
    相关资源
    最近更新 更多