Ideally, you want both rich interactive charts in your front-end (“just like Google Finance” is a common request) and the ability to render the same charts on the server for exporting, emailing, or supporting less capable clients (Blackberry, I’m looking at you). The perfect scenario would be to do this using the same library so that they look identical, and so you don’t have to maintain two separate code bases. Unfortunately due to limitations in libraries, platforms and environments - it’s difficult to make this a reality.
Recently, I’ve been developing a HTML5 application in which we used the Highcharts charting library to provide basic line and bar charts. Highcharts is a JavaScript library that will render either SVG or VML dependent on the hosting browser (if you’re interested, take a look at some of their demos). To support exports, the library will create an SVG in the browser and post it up to the web server. In the box (figuratively), they supply a php script which will render this content into an image or a PDF then return it over HTTP. This works great for situations where we have a full web browser, but sadly, we have to resort to another charting library that can produce static images to produce images on the server. It’s challenging to get the charts looking identical, and maintaining two code bases is a pain.
Unless you’ve had something better to do than constantly follow blogs and twitter (oh, just me then…), you’ve probably heard about Nodejs. It’s a server-side JavaScript implementation running on top of Google’s excellent V8 engine (the one under Chrome). Using the jsdom library, we can provide an environment similar to a browser into which we can load client-side scripts. With very little work, I was able to load up the Highcharts library in node, then using identical code which I would write for a browser, render the chart and grab the SVG content. Compare a chart rendering in a browser to the following from my node sample:
var $ = window.jQuery,
Highcharts = window.Highcharts,
document = window.document,
$container = $('<div id="container" />'),
chart;
$container.appendTo(document.body);
chart = new Highcharts.Chart({
chart: {
defaultSeriesType: chartType,
renderTo: $container[0],
renderer: 'SVG',
width: width,
height: height
},
series: [{
animation: false,
data: data
}]
});
svg = $container.children().html();
Once we’ve grabbed this SVG content, we can render it to an image using the command line tool convert. As it’s super easy in Node to create a basic web server (literally just a single function), I created a basic server which accepts requests like /bar?data=1,2,3,4 and will return the chart rendered as an image using Highcharts.
this.server = http.createServer(function(request, response) {
var url = parse(request.url, true),
chartTypeMatch = /^\/(\w+)$/.exec(url.pathname),
chartType = chartTypeMatch ? chartTypeMatch[1] : null,
/* Some code omitted */
createHighchartsWindow(function(window) {
/* chart generation from above */
svg = $container.children().html();
// Start convert reading in an svg and outputting a png
convert = spawn('convert', ['svg:-', 'png:-']);
// We're writing an image, hopefully...
response.writeHeader(200, {'Content-Type': 'image/png'});
// Pump in the svg content
convert.stdin.write(svg);
convert.stdin.end();
// Write the output of convert straight to the response
convert.stdout.on('data', function(data) {
response.write(data);
});
// When we're done rendering, we're done
convert.on('exit', function(code) {
response.end();
});
});
}).listen(2308); // Start HTTP server listening on port 2308
So far I’ve only prototyped these ideas, but it’s working pretty well (see image below). Although I’ve used Highcharts for this example, it should be possible to use any SVG based JavaScript charting package. I feel this technique has the potential to be able to support both rich client side charts and static server generated images using the same libraries, and most importantly, sharing the same code. My prototype is available at up at GitHub. What do you think?

seems awkward to create DOM on the server but maybe I’m just resisting. is it fast?
Thanks David!
What license is your code under? It’s not mentioned here or in your github repo.
Oops, I replied to the wrong comment. ‘scuse me.
JsDom is designed to be as lightweight as possible so it’s super quick. Take a look at the bulk of the code on GitHub. It did feel a little weird at first to pretend that there’s a browser inside node, however once I’d read about how JsDom works and how the scripts are executed, it was pretty straight forward.
The code could also very likely be improved from my prototype. I’m currently creating a ‘window’ object on every request. Assuming the chart can be destroyed cleanly (I think it can). We could only create it once and just remove the chart node when completed. Of course it’s debatable whether responding to an HTTP request is the best way to generate these charts, it could also be done as an offline process.
Hi David,
“the http://nodejs.org/api.html#script-runinnewcontext-100” – is blank page
thanks
I like it. Glad to see you’ve been bitten by the node.js bug. You should come hang out at Nodejitsu HQ sometime. Eli (tmpvar) is part of our team.
Cheers,
Charlie
Thanks Charlie. I’ve love to drop by sometime, I’ve got plenty of jsdom and Node related questions.
hey Dave,
I’m totally new to node, but can you give me a really simple example on how you actually run your code on the server and save the chart to file.
I have node installed and your code. I then type node index.js and i get listening on 2308.
thanks,
tj.
Hi Dave,
I’m trying to get this to work myself. I have this error now after calling like this?
lynx 127.0.0.1:2308/chartType?data=0,1,2,3
/usr/local/lib/node/.npm/jsdom/0.1.16/package/lib/jsdom/browser/index.js:325 process.binding('evals').Script.runInNewContext( ^ TypeError: undefined is not a function at CALL_NON_FUNCTION_AS_CONSTRUCTOR (native) at Object.xhr (http://code.jquery.com/jquery-latest.js:5482:11) at http://code.jquery.com/jquery-latest.js:6012:45 at http://code.jquery.com/jquery-latest.js:6883:2 at /usr/local/lib/node/.npm/jsdom/0.1.16/package/lib/jsdom/browser/index.js:325:41 at IncomingMessage. (/usr/local/lib/node/.npm/jsdom/0.1.16/package/lib/jsdom/browser/index.js:367:13) at IncomingMessage.emit (events:41:20) at HTTPParser.onMessageComplete (http:107:23) at Client.onData [as ondata] (http:848:27) at IOWatcher.callback (net:494:29)That’s strange, maybe insert a console.log call just before line 40 in index.js to see if jQuery is loading correctly.
Looks like this is an issue with jquery 1.4.3
Change line 39 in index.js to include the path to jquery 1.4.2, works for me.
jsdom.jQueryify(window, "http://code.jquery.com/jquery-1.4.2.min.js", function() {
script.src = 'file://' + __dirname + '/highcharts/highcharts.src.js';
script.onload = function() {
if (this.readyState === 'complete') {
fn(window);
}
}
});
Thanks for sharing
Cheers
Roger.
thanks guys, i am progressing, BUT im now getting this error.
listening on 2308 writeHeader() has been renamed to writeHead() Generating chartType chart node.js:63 throw e; ^ Error: EPIPE, Broken pipe at Stream._writeImpl (net:300:14) at Stream._writeOut (net:732:25) at Stream.write (net:665:17) at /home/touchpoint/node/node-v0.2.3/test/hc/index.js:106:17 at Object.onload (/home/touchpoint/node/node-v0.2.3/test/hc/index.js:44:5) at /usr/local/lib/node/.npm/jsdom/0.1.16/package/lib/jsdom/browser/index.js:332:19 at /usr/local/lib/node/.npm/jsdom/0.1.16/package/lib/jsdom/browser/index.js:349:11 at fs:84:13 at node.js:768:9–
I hate not solving things for myself but i am really stuck with how to debug these errors.
-tj
Sorry to take so long getting back to you tj. What URL are you using? chartType was intended as just a placeholder, so your url’s should look like http://localhost:2308/bar?data=1,2,3.
Hi Dave,
I am still getting the same error message, I did have the url wrong (thanks for that).
here is the error:
listening on 2308 writeHeader() has been renamed to writeHead() Generating bar chart node.js:63 throw e; ^ Error: EPIPE, Broken pipe at Stream._writeImpl (net:300:14) at Stream._writeOut (net:732:25) at Stream.write (net:665:17) at /home/touchpoint/node/node-v0.2.3/test/hc/index.js:106:17 at Object.onload (/home/touchpoint/node/node-v0.2.3/test/hc/index.js:44:1) at /usr/local/lib/node/.npm/jsdom/0.1.16/package/lib/jsdom/browser/index.js:332:19 at /usr/local/lib/node/.npm/jsdom/0.1.16/package/lib/jsdom/browser/index.js:349:11 at fs:84:13 at node.js:768:9It looks like there may have been some changes to node since I wrote this, note the writeHeader/writeHead messahe. Change writeHeader to writeHead.
I’ll make sure it’s updated to the latest version of node when I get a chance. Sorry for all this inconvenience.
Thanks Dave, I’ll keep an eye out for your next version.
-t
Hi David,
that was magic. how did you manage to get it working?
got the same error as TJ. Do I need to place batik-rasterizer.jar, related lib and index.php for an export side by side to the index.js?
Hey Artyom,
You don’t need any of the highcharts components to export server side, just the convert command line SVG renderer – http://www.imagemagick.org/script/convert.php. The above is just a proof of concept and not a ready to go solution. I’m considering trying to make it a normal node “highcharts” library which will just take the highcharts options obj and return an image of some description. It’s good to know there’s interest.
David.
Psst. Google Finance uses Flash to do their charts.
That is all
Gee, nothing gets past you does it!?
But seriously. The context for this was generating the same graphs in static images as they see in browser.
Hi Dave,
I have a couple of questions – I’m struggling a bit to get this thing running. Not sure if there have been changes in the latest jsdom but your code that loads the scripts isn’t actually loading highcharts for me. I put console logs in all the included files and jsdom is getting loaded so is jquery but high charts is not unless I do something like
// Load scripts
jsdom.jQueryify(window, “highcharts/jquery.min.js”, function(window, jsdom) {
script.type= ‘text/javascript’;
script.src = ‘file://highcharts/highcharts.src.js’;
script.onload = function() {
fn(window);
}
var head= window.document.getElementsByTagName(‘head’)[0];
head.appendChild(script);
});
Also, when onload gets called the readystate is undefined in my onload function.
Any ideas what might be going on?
Thanks!
Hey Dale,
I think both Node and JsDom have changed quite a bit since this post. As you’re not the first person I’m going to put some effort in to clean this up and maybe find a way to release the server integration as a proper library. I’ll try to have a bash at starting it later this evening or maybe tomorrow. I’ll let you know.
David.
Thanks David! If possible maybe you could post the versions of jsdom, nodeJS, and jquery that you worked with. I noticed you checked in HighCharts. Did you make mods to that?
Hey David,
I was able to get your prototype running using older versions of node and JsDom. The svg that gets generated by High Charts will render fine in Chrome and Image Viewer. (I saved it to a .svg file) However, I’ve not been able to get convert or batik to convert the file. My question to you is did you have to clean up the svg to get it to convert? Did you have to make any changes to the High Charts code?
Thanks
-Dale
Hey Dale,
Thanks for your perseverance. I’ve just tried it myself and managed to get it running roughly against the current version of node and the most recent JsDom in npm. I hit some difficultly with a newer version of jQuery but haven’t had a chance to take a good look at it.
I think I had to make one or two changes to the highcharts code to get it working, nothing significant – just global scope issues I think. I’ll try it against a recently version and see what I find.
I’ve started (20 mins) trying to pull it together into a actual node library which you’ll be able to hand a Highchart’s options object and be handed back a png encoded Buffer. Check it out at https://github.com/davidpadbury/node-highcharts. Feel free to fork
David.
I’ve also just diff’ed my version of Highcharts to see what changes were required. There’s only a single change for one place where an Array type is tested. It appears that the Array type is different in the script context to an array created in node. I’ll try to follow this up in JsDom, but for the mean time I fixed it by simply checking the type name.
Very cool. I can’t wait to give it a try. Today I finally got the system spitting out jpegs. Maybe its because I’m using a real life line graph with lots of options, but I had to write a ton of code to sanitize the svg before batik would convert it. I got this running completely inside of Tomcat without shelling out or spawning any child processes using the Rhino and Batik jars
That’s awesome. Batik’s pretty useful if you’re in Java. Are you using JsDom in Rhino?
No, I went down the JsDom/nodeJS/convert path but I really wanted a pure Java solution and one where I didn’t have to shell out of tomcat. So, I switched over to using Rhino, envjs and Batik. Batik complained a lot about the generated svg and their parser isn’t very helpful in pointing out the errors. I had to write a fair bit of scrubbing code and its mostly by trial and error. I want to thank you again for getting me going in the right direction.
cheers!
-Dale
Hi David,
Glad I found this because I was just about to start something similar.
I’m having a lot of trouble getting the resulting svg to convert properly. At this point, I’ve tried both the convert that came with Ubuntu 10.04 as well as the latest ImageMagick convert compiled from source. Neither work. I also tried batik, but after spending 20 minutes fixing errors there was no end in sight.
What program and version are you using for svg conversions?
Hi David. Glad you had a progress. Unlike you I still get an exception with the latest files from github(trying to run test/index.js) I’m such a noob so I don’t even understand where the error is:
debian:~/node1/test# node ./index.js
node.js:63
throw e;
^
Error: EPIPE, Broken pipe
at Stream._writeImpl (net:300:14)
at Stream._writeOut (net:740:25)
at Stream.write (net:673:17)
at /root/node1/lib/node-highcharts.js:54:17
at Object.onload (/root/node1/lib/node-highcharts.js:30:5)
at Object.javascript (/usr/local/lib/node/.npm/jsdom/0.1.20/package/lib/jsdom/level2/languages/javascript.js:15:13)
at /usr/local/lib/node/.npm/jsdom/0.1.20/package/lib/jsdom/level2/html.js:970:35
at fs:84:13
at node.js:773:9
Is it at line 30 of /root/node1/lib/node-highcharts.js where “callback(window);” is called? or at line 54 on “convert.stdin.write(svg);”?
could you plz help me a bit? may be my server lacks some libs or have different versions of node/jsdom/jquery/whatever?
thx in advance!
@Avery Fay, I was using a recent version of ImageMagick on the Mac.
Avery, I am using the latest batik. I too spent a lot of time chasing down mysterious errors. I finally got the svg code scrubbed enough to work. If you are using High Charts 2.1 you can call chart.getSvg() and it will do a lot of the scrubbing for you. If not try looking at their exporting.src.js module and you will see the scrubbing that High charts had to do to get their examples to export. I had to do even a bit more.
Thanks for the suggestions. I ended up using rsvg-convert from librsvg, which works well without modifications to the SVG output.
The only other issue I’m having is that if I call render, then node.js will no longer exit when there’s nothing left to do, sort of like there’s a lingering event listener that hasn’t been called. Any ideas?
I’ve noticed the hanging too but haven’t found the source. If you find anything let me know.
Hey Dave,
Any word on the new release?
Tried this with some latest and greatest of various libraries and i’m having issues with the conversion (I think). I can view the .svg in my viewer and it looks to be what I’m attempting to create, but when it converts it turns it to an empty, but correctly sized, .png having just a left and top border. Just empty white space. Seen this before?
I can print the svg to the console, copy paste it into a file, and run the conversion tool on it. Doing so results in this error: convert: non-conforming drawing primitive definition `,’ @ error/draw.c/DrawImage/3147.
With so many moving parts its hard to know what might be causing this issue. One library I haven’t updated to the current is Highcharts. That’s pretty much a no go. But all the node stuff is freshly installed from npm and ImageMagik is freshly installed as well.
Any thoughts?
Hey db, could create an issue on the GitHub page for node-highcharts with a highcharts option obj which would reproduce the issue. I’ll take a look into it.
Done!
Worth mentioning that it is behaving this way with the little test example you have in your distro. I had to make a few changes to get it to run, not nothing (I don’t think) that would cause any issues. Just had to be done to make anything happen.
Great – I’ll take a look at it as soon as I can. It’s probably just an issue with cleaning up the outputted SVG from highcharts to be suitable for ImageMagik. I’ll try to clear it up a little to make this project a little more usable.
Because it is a bit more forthcoming with error messages, I was able to get batik to turn the svg outputted by highcharts into what appears to be the right png. Had to do things like change clippath to clipPath and fill empty (“”) x/y/width/height params with zeros.
ImageMagick still complained. Spent some time with it, and it seems to dislike font-family when it looks like this…
font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif
Throughout the .svg I removed the first two entries, leaving just…
verdana, arial, helvetica, sans-serif
…and it generates the image just fine, but the image itself is fairly warped looking.
I’m well outside my comfort zone with this stuff, just sort of taking shots in the dark. Could well be I’m arsing things up a bit somewhere.
Hi David,
that’s exactly what I need but I don’t get it quite right, I think the code is not complete. In the first line you’re using window which is not defined. What must be included to getit running?
Hey Stefan, yeah – it’s a bit of a mess and is difficult (perhaps impossible) to reuse in it’s current state. I’m working on it again for a talk I’ve got coming up so I’m hoping to get it in a suitable state to push to npm.
For a current version of highcharts there must be found a replacement or an implementation for getBBox() calls. Other necessary changes are the same as already done by David.
Hey Stefan. I’ve been working on replacing the dependency on having image magick installed with node-canvas and CanVG. The BBox call is actually a bit problematic – there’s a few places in the highcharts codebase that depend on being able to measure elements, which is clearly quite difficult for us. I’m trying to come up with alternatives. Expect a release soon. Honest.
David -
I’ve tried to get your example running on my Windows XP box with the node binaries from http://node-js.prcn.co.cc. I did encounter a missing jsdom for the require() which I think I resolved by adding them to the /lib folder. Now I’m getting an error about missing module ‘request’ from within the jsdom.js.
Since I’m on a deadline to get this little project (convert Highcharts to PDF) done, I finally decided to write my own jQuery.post coldfusion page to convert the SVG to PNG for inclusion via an img tag. I did discover that the ImageMagick convert couldn’t handle the SVG – something about the font-family: containing font names with embedded spaces. Ended up using Inkscape – incredible package!
I haven’t updated this for a couple of months so it probably needs another update for node 4 and the newer versions of the libraries.
You should probably being using npm for installing jsdom if you’re not already.
David,
I’m sure you’re pretty tired of this thread being dragged back up, but I’m having a peculiar problem with your code: the script.onload event will not fire, regardless of the value of the script.src to load Highcharts. I tried replacing this with a node.js require(), only to find the window/document variables were out of scope in the file.
This code is the exact solution to my problem, so if I can get this working, it would be ideal.
Any advice?
Thanks,
Travis
To follow up, I’ve done a bit more testing. Rewriting your example to use jsdom.env, and trying out Zombie, both return the same error:
‘Invalid character in tag name: <'
This originates from the highcharts.js file. At a loss here.
Hi Travis,
Sorry you’re having difficulties with it. I’m afraid it’s so long since I originally threw it together that just about all the libraries have had significant changes. I’ll give it a quick bash now and let you know how far I get.
Try this – https://github.com/davidpadbury/node-highcharts. Still some work to be done before it’ll be dependable as a decent library but should be a good starting point.
David,
Thank you very much for updating this code! I’m going to run with this and see what I can do to get it fully working. With your example, I’m getting the same “empty PNG with top and left borders” that db mentioned above, and the hanging that Avery Fay mentioned.
I can alter it to push out the SVG just fine (although it’s still hanging).
Thanks so much!
Someone emailed me a while back to let me know that they’d fixed the hanging problem but wasn’t good enough to share how… I assume it’s high charts registering some kind of callback which keeps node waiting. Do feel free to let me know what progress you make, or better yet get me to pull something
Using the librsvg instead of ImageMagick fixed the clipping issue — although for anyone seeing this in the future, I had to install xorg-x11-fonts on my server since I didn’t have an x11 server running–I was just getting boxes for the letters before I did that.
I’m keen on investigating converting the svg to canvas via CanVG and then using node-canvas to render the thing. That way the entire lib would be npm’able.
Could maybe investigate node bindings to librsvg as well if no one has yet…
Well, David, after pouring over the highcharts code, disabling every event listener I could find… I’ve gotten nowhere on that front. I don’t really know node.js well (I’m actually only using it for this specific task =X), so I’ve really exhausted my resources.
I’m taking the easy (albeit naughty) route and doing a process.exit(0) after my successful file generation.
Thanks for your help!
Oh well – I’m sorry that suggestion wasted your time. At least we know.
No waste of time at all! I have a fully functioning (although somewhat hacky) server-side solution to generate my thumbnails! I’m very pleased!
You’re definitely right in that it’s the highcharts.js though… disabling that call prevents the process from hanging–which is why I dug through attempting to find the issue.
Throughout this whole process I just kept thinking there’s got to be a way to get a list of all listeners and timers in node.js, but I couldn’t find anything to that tune.
Did you try node-inspector? I *think* you can get a list of pending callbacks somewhere in the display.
I did not. I’m not exposing any ports for node to use at the moment, and would need to get a lot of approval before opening something up (it’s a production server).
If I get some time this weekend, I may crack open a local copy and give this a whirl.
This probably happens with a new 2.1.4 version of HighChart lib. It works well with v2.0.5 for example.
Try this solution.
Hi Dave,
amazing!and This way I can configure interactively charts in the browser and then generate PDF reports on the server using this JSON configuration. Thank you!
Best Andreas
That’s the idea!
not work with Hightcharts v2.1.6
I’m afraid I may not get a chance to look at it anytime soon. If you’re feeling adventurous the code is all on GitHub (https://github.com/davidpadbury/node-highcharts).
I have spent quite a bit of time looking at getting the newer versions of highcharts and jquery to work with nodejs using your framework. It looks like there are many things that highcharts (as does most client-side javascript) expects the browsers to do that nodejs does not. Even if you hardcode the browser detection isIE,isWebkit,etc., the SVG generated by highcharts in node is very different from the SVG generated using the exporting module button in a browser. In fact, it’s not even valid XML, as the text nodes have style attributes redefined. Bummer.
The highcharts object has a “GetSVG” method, try that.
Also, I’ve actually sadly abandoned this method in my production environment. It was simply too much of a hassle, too slow, and broke too frequently. I’m actually performing an AJAX call when the chart is loaded, and sending the results of GetSVG back to the server, then converting that to PNG via librsvg. I’ve found this to be incredibly reliable with very minimal impact on the client.
The worst part is you can’t systematically generate your thumbnails using only the server. You can run a scheduled task (or cron job equivalent) on your local machine (or any machine with a “head”) to poll your site at any time to perform the rendering and updating AJAX call.
YMMV, good luck and godspeed all.
Hi
I’ve a ‘almost’ working environment, and I think I have the same issue as Alex, regarding svg generated by getSVG, has issues with legends, Y labels, and is putting one on top of the others.
But SVG generated by highcharts (in the classic way, though web browser) does _not_ has this problems..
In my case, I could not use the AJAX call on each onload() event, because my app is working completely in background.
any ideas?
Thanks in advance
Hi Efrain,
The difficultly is that Highcharts wants to measure it’s contents to layout things like the legend (this happens in the getBBox function). As they’re actually getting laid out in jsdom we don’t have any dimensions available.
We got through most of this by just manually positioning everything in Highcharts. You could take a bash at filling in the getBBox function to look at the element and attempt to estimate it’s size – many elements will have height and width properties set. Although I’m afraid it’s nothing I’ve attempted and it’s been a while since I touched all of this.
David.
@Efrain,
I don’t know how to fix the jsdom side of things, but there is one thing you can do to render on the client side without them seeing: create an iFrame and, using absolute positioning, move it to where they can’t see it. The iFrame will contain all the highcharts items as well as the async call to report the SVG back to the server.
I know this method seems naughty, but if you absolutely have to get a production unit up and running like I did, this might be your best bet.
I wouldn’t say it’s naughty. If you have access to a browser then just use the standard exporting functionality in Highcharts. You can then take the SVG and render it anywhere you like (Highcharts comes with a php exaple and I’ve done it ASP.NET and Java using the same technique).
This node stuff is only for when you can’t use a browser.
Thanks guys,
I’ll try your suggestions, I’ve already have the standard exporting options working, so It should be no problem about it.
Regards
Hi, I’m using the (almost) latest highcharts version. My present diff is
1511c1511
nodeName = element.nodeName.toLowerCase(),
Not much, right?
Along with this snippet of code:
Chart.prototype.createHighchartsWindow = function(fn) {
var window = jsdom.jsdom().createWindow();
var script = window.document.createElement(‘script’);
// jsdom doesn’t yet support createElementNS, so just fake it up
window.document.createElementNS = function(ns, tagName) {
var elem = window.document.createElement(tagName);
elem.getBBox = function() {
if (this.textContent) {
return {
width: this.textContent.length * 6.5,
height: 14
}
}
return {
x: elem.offsetLeft,
y: elem.offsetTop,
width: elem.offsetWidth,
height: elem.offsetHeight
};
};
elem.createSVGRect = function() {}
return elem;
};
// Load scripts
jsdom.jQueryify(window, __dirname + ‘/lib/jquery-1.4.4.js’, function() {
script.src = ‘file://’ + __dirname + ‘/lib/highcharts/highcharts.src_110803_charts.js’;
script.type = ‘text/javascript’;
script.onload = function() {
fn(window);
}
var head = window.document.getElementsByTagName(‘head’)[0];
head.appendChild(script);
});
};
Surely, it doesn’t support different font sizes.
The problem with the duplicated style attribute is a jsdom problem. see here:
https://github.com/tmpvar/jsdom/issues/288
Kind of pulling my hair out here. Has to be something simple.
Regardless of the way I grab SVG (existing container html approach, or latest getSVG), when I generate the SVG into an image or PDF, using any tool (convert, xhtml2pdf, whatever) – I get a blank image. The dimensions are there, but it’s totally white.
Anyone ever experienced this?
In response to my own message, it seems the issue is:
.getSVG while running under node does not generate valid XML markup and it’s inconsistent with what is generated when getSVG is fired from the browser.
If the client is made to post the SVG content from the browser to the server, it’s valid.
If nodejs is used to generate the SVG from either grabbing it from the container, or using the getSVG function call, it does not create valid SVG.
This goes back to the earlier comment that jsdom is not handling the style attribute correctly, and it is duplicated and therefore a malformed xml block causing the converters to fail.
I’ve heard that a couple of times recently. As soon as I get a chance I’ll try looking into it.
It seems, jsdom don’t work with the latest highcharts version. Perhaps someone can have a look on jsdom.
Highcharts 2.1.x is not compatible with node-highcharts.
2.0.5 is the last compatible version, distributed with node-highcharts.
Would be great to use the same version of Highcharts on both client and server sides.
Hi,
I tried your example. i created a var svg and loaded it with the svg of a chart.
i did content.stdin.write(svg) but when i do content.stdout.on(‘data’) it always returns false.
Please help me i am stuck.
Hey guys,
I just upgraded to Highcharts 2.1.9. Here’s my diff to make it work:
using jquery 1.6.4.min
jquery >1.7 doesn’t work
Stefan,
I have tried to patch Highcharts 2.1.9 using your diffs below in conjunction with jquery-1.6.4.min.js. Could you provide a zip to a working node.js solution or even just the entire patched 2.1.9 Highcharts library?
Just out of curiosity, does this fix display problems such as jumbled legends as mentioned above?
Have you tried the unified diff in the post below? It also tells you the exact version of highcharts that I use. If you can’t apply the patch using the appropriate tools, you can do it manually, it’s only a small diff. There’s no place where I can put the patched lib.
My patch doesn’t fix anything, but if problems are related to element dimensions, my createElementNS function I posted on February 20 might be helpful. Play with the numeric constants to get a good result.
Thank you very much, stefan4! Your patch did work for me this time and your version of createElementNS (from September 13, 2011 it looks like) did the trick for my legends.
The last important feature that I’m struggling with is null points. It is very important for my server-side charts to NOT show lines connecting when null points are present. I am able to send Highcharts the data [1, 2, null, 4, 5] and see the gap, but when I provide 1000 points with two nulls, the lines get connected. The second case works just fine with 2.2.0 in a browser. This seems very weird to me, any idea?
I’m going to email Highcharts too and see if they can help me. The changelog for 2.2.0 says the numerous bugs and have better performance with thousands of points. Unfortunately, it doesn’t look that they have a place where I can go see exactly what bugs were fixed, so hopefully they will respond to my email.
I’m glad to hear that it works for you. As for the nulls, I haven’t had that case so far, but I know about a plotOption “connectNulls”.
Yeah, the connectNulls option default to false, though. Since you mentioned it, I went ahead and explicetly set it just to make sure the default wasn’t different in 2.1.9 – but that did not help.
Upon further inspection, this definitely seems to be a Highcharts bug when dealing with a large number of points that they have already fixed in 2.2.0. I started messing around with the data by zooming in moving around (technically not zooming – I’m viewing decimated data through ajax) and noticed that null point does but at a random spot in the data until you get to about 40 points or less.
Hopefully they will respond to my email, otherwise its time to sift through 2.2.0 and see what they might have changed.
Thanks again for your help!!
Sorry, the link is gone.
http://pastebin.com/HXtDY6DB
I can’t apply that cleanly to 2.1.9 – can you provide a unified diff (diff -u) instead, please?
http://pastebin.com/NaNpHKcb
There are 16 lines in that diff that are specific to my project (@@ -7082,6 +7087,16 @@). You should probably take them out.
Please tell us if it works for you.
Hi Stefan,
on which version of Highcharts this patch must be applied?
I have the current version of node-highcharts with Highcharts 2.0.5 and the diff from this version and 2.1.9 is very different.
According to the highcharts.src.js file header it is “Highcharts JS v2.1.9 (2011-11-11)”
Pingback: Using NodeJs to render JavaScript charts on the server | x443
I’ve been trying your solution Stefan, but I am getting the following problem. On creating the chart (chart = Highcharts.Chart(options) ), I get the following error:
Error: Invalid character: Invalid character in tag name: <
Any ideas?
This can be solved by setting forExport = true in the chart-options. (options.chart.forExport = true;)
I have had invalid character in tag name several times and had to analyze the SVG to find out.
For me, it was the added copyright character (i use \uA9)
and the solution is to use the export module (it sanitizes the SVG) and add
options.credits.text = options.credits.text.replace(/\xA9/,’(c)’);
in the getSVG function.
A great idea, one would have hoped that HighChart would take this on, as a serverside component would be a great addition to their offerings.
Pingback: The Node.js Revolution, or: How I Learned to Stop Worrying and Love the Node « James on JavaScript
We’ve just released our html5 canvas charting javascript library for node.js.
(It does not need jsdom, the only dependency is the node “canvas” package).
It can be installed from npm (“npm install TeeChart”) and includes a small main.js sample script that returns png images created server-side.
http://search.npmjs.org/#/TeeChart
Hi David
I am completely new to the node.js, I got a requirement to export HighCharts into pdf and come across with this article. I installed Node.js (http://nodejs.org) and downloaded your sample – I am not able to run your sample. I am getting below errorr message
node.js:201
throw e; // process.nextTick error, or ‘error’ event on first tick
^
Error: Cannot find module ‘node-highcharts’
at Function._resolveFilename (module.js:332:11)
at Function._load (module.js:279:25)
at Module.require (module.js:354:17)
at require (module.js:370:17)
at Object. (C:\Program Files\nodejs\example.js:2:18)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
Your help will be much apprecitated
Thanks
Jiju Antony
Jiju — did you ever get this working, it’s exactly what I need to do as well.
I am getting an empty image. using jquery 1.7.1 and highchart 2.2.3. any idiea…I can see the svg content when console.log(svg).
Pingback: jQuery plugins with node.js | Easy jQuery | Free Popular Tips Tricks Plugins API Javascript and Themes
Why am I seeing an empty image even though the svg is generated fine. The svg generated renders fine on the browser but conversion fails by imageMagick convert.
Can anyone please reply to this thread?
If your svg looks fine, you start getting a little off-topic, but I can give you my convert version and my command line parameters (converts from stdin to stdout):
convert -density 150 -quality 100 svg:- png:-
The version number is “Version: ImageMagick 6.2.8″
Good luck.
That did not help me. With ImageMagick 6.2.8 I don’t even get the empty chart. I get undefinded response in onexit handler.
When you save the svg to a file, does the convert work on the command line?
I saved it in a file with .svg extention and used this command “convert chart.svg chart.png” I get error saying [Invalid parameter - "chart.png"]. Is this the right command on Windows?
Apparently not. I don’t use Windows.
Someone?
IMHO, if your server side is a Unix machine, your best bet is to run Xvfb and launch firefox on the server side, then Ajax the SVG data back to the web server, web server stores it and terminates firefox process. It’s the most foolproof because
1. As long as you have a working html file with Highcharts, it will work on the server side. Just using the same script.
2. You don’t need to stick any particular version of Highcharts.
Pingback: Script installation service
I’ve heard positive reviews of http://www.FusionCharts.com as well. have you tried them? how do they compare to HighCharts?
i ported canvg as a module for nodejs: https://npmjs.org/package/canvg
Pingback: Highcharts und PrinceXML | freakcommander
Pingback: Server-Side HighStock charts generation with NodeJS | BlogoSfera
In node-highcharts,js –> window.jQuery,
Highcharts = window.Highcharts, was throwing errors both are undefined, so i was unable to generate svg using render method..
Please provide your input how to proceed on this,
Thanks
Bars of 12 to 14 inches are adequate for most small chores, while an 18- or 20-inch bar is necessary
to remove large trees. Numerous folks would
say that the electric chainsaw is usually greater than those that are powered
by gas alone. The files are fairly reasonably priced, only a few pounds each, so it may be worth purchasing them in
bulk if you undertake lots of timber cutting.