【发布时间】:2015-02-22 21:11:28
【问题描述】:
(编辑:已重写问题以更好地隔离问题。)
我正在编写一个 D3js script.js,它可以在客户端的 Web 浏览器和服务器端的 nodejs 中“按原样”重复使用。我取得了一些不错的进展:
- 单个 d3js
script.js确实可以在客户端和服务器端创建基本的 svg 形状。在显示 viz 的 Web 浏览器上,在服务器端输出所需的 map.svg 文件。 - 我有一个更复杂的 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 width 和height 属性,然后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
【问题讨论】:
-
您是否遇到任何错误?那个队列跨域请求看起来很狡猾。
-
跨域查询失败可能是一个线索,我确实在我的电脑上运行它,它在某些在线网站上查询 .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 上运行不佳...... :(