问题
(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 :
- 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. - 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