0

I am trying to convert my nvd3.js charts into canvas drawings in my web app. There is a good stackoverflow thread about it: How to convert/save d3.js graph to pdf/jpeg

I decided to use Simg library and it is working good except that it generates me black and white images, the colors are lost. The code for the Simg library is small and can be found here: https://raw.githubusercontent.com/krunkosaurus/simg/v1.1.0/src/simg.js

As I understand the main function that is actually doing the convertion is the following one:

toCanvas: function(cb){
  this.toSvgImage(function(img){
    var canvas = document.createElement('canvas');
    var context = canvas.getContext("2d");

    canvas.width = img.width;
    canvas.height = img.height;

    context.drawImage(img, 0, 0);
    cb(canvas);
  });
},

So, what should I modify there to avoid losing colors of my charts? They are drawn using nvd3 and look like that:

enter image description here

The output of Simg library is the following image:

enter image description here

As you can see, the color and axes are lost. Any suggestions would be greatly appreciated.

Update

I tried using canvg() but the output that I got is the following:

enter image description here

I just ran two lines of code:

let svg = d3.select("div#main svg").html();
canvg('canvas', svg);

I like that the axes are not lost but obviously it is unacceptable.

Update

I tried using the code from the duplicate suggested link but it is not working for me. Here is the code that I am using:

let svg = d3.select("div#main svg").node();
console.log(svg);

var sheets = document.styleSheets;
var styleStr = '';
Array.prototype.forEach.call(sheets, function(sheet){
    try{ // we need a try-catch block for external stylesheets that could be there...
        styleStr += Array.prototype.reduce.call(sheet.cssRules, function(a, b){
            return a + b.cssText; // just concatenate all our cssRules' text
            }, "");
        }
    catch(e){console.log(e);}
});
// create our svg nodes that will hold all these rules
var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
var style = document.createElementNS('http://www.w3.org/2000/svg', 'style');
style.innerHTML = styleStr;
defs.appendChild(style);
// now append it in your svg node
svg.insertBefore(defs, svg.firstElementChild);

let xml = xmlserializer.serializeToString(svg);

            // Removing the name space as IE throws an error
//xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');

canvg('canvas', xml);

It throws an error:

Uncaught DOMException: Failed to execute 'matches' on 'Element': '38%' is not a valid selector. at matchesSelector (http://canvg.github.io/canvg/canvg.js:72:16) at svg.Element.g.addStylesFromStyleDefinition (http://canvg.github.io/canvg/canvg.js:838:32) at svg.Element.g.svg.Element.ElementBase (http://canvg.github.io/canvg/canvg.js:864:10) at svg.Element.g.svg.Element.RenderedElementBase (http://canvg.github.io/canvg/canvg.js:902:9) at new svg.Element.g (http://canvg.github.io/canvg/canvg.js:2430:9) at Object.svg.CreateElement (http://canvg.github.io/canvg/canvg.js:2832:9) at svg.Element.svg.addChild (http://canvg.github.io/canvg/canvg.js:830:29) at svg.Element.svg.svg.Element.ElementBase (http://canvg.github.io/canvg/canvg.js:889:40) at svg.Element.svg.svg.Element.RenderedElementBase (http://canvg.github.io/canvg/canvg.js:902:9) at new svg.Element.svg (http://canvg.github.io/canvg/canvg.js:1035:9)

If I avoid using xmlserializer and instead do the following: canvg('canvas', d3.select(svg).html());, then no errors are thrown, except some 404s and nothing is drawn on the page, canvas element just stays empty. The only errors that I see in that case are:

enter image description here

Update

I tried to use Simg.js to download the modified svg with the styles, but it is not working, nothing is just happening, no errors (I eliminated the errors in the previous update):

var simg = new Simg(svg);
simg.download();
Nikita Vlasenko
  • 4,004
  • 7
  • 47
  • 87
  • Your issue is still the same as the dupe: you must include your CSS in the svg markup itself. As for the error you get, this means that one of your CSS files contains invalid rules, where a `38%` value is parsed as a selector. Browsers will ignore it, but canvg code won't. Fix your CSS file and it should work. Anyhow, without a real [mcve] showing the actual svg produced, it's hard to help you further. You might try my old [SVG2Bitmap](https://github.com/Kaiido/SVG2Bitmap) script though I stopped the development of it in an incomplete state. – Kaiido Mar 17 '18 at 05:28
  • I just solved all the issues using your library: https://stackoverflow.com/questions/34094256/convert-inline-svg-to-canvas-using-canvg-script Awesome! – Nikita Vlasenko Mar 17 '18 at 05:42
  • Is there a way of getting the actual converted image in code with your library? Function `SVG2Bitmap(svg, canvas);` just converts svg and draws it into `canvas`, but I need to get the image and append it in different places. Probably I could just access the canvas, but maybe you have some function already for it. – Nikita Vlasenko Mar 17 '18 at 06:03

0 Answers0