Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly generate canvas from complex svg

I'm trying to export a complex SVG block (generated with c3) from my website as an image (be it png, svg, pdf, at this point I'm open to anything that solves it, although vector format would be ideal). I have tried html2canvas, canvg, jsPDF, and all the cool kids from that gang. The problem is: one of my plots gets all screwed up. Line becomes area, areas get inverted, colors are ruined, ... you name it.

I'm pretty far from being js expert. I've just got here and I'm finding my way around, some please bear with me.

I don't know if this is a CSS issue or what. Yep, we do have CSS behind the html.

My temporary solution is to use jQuery.print.js to call a print of my div. This is far from ideal for many reasons:

  • No bbox. It generates a PDF with page size defined by user, not image size;

  • I'm using bootstrap cards with auto resize. Whenever the "print image" is pressed, the print uses the current sizing. I've tried hiding cards to rescale the target one, but the resizing will only take place AFTER the print call, for reasons unknown to me. It this issue is solved, this temporary solution would be better, although still a temp.

So, one question is:

  • how to get the SVG as shown?
  • Alternatively, how to resize the card BEFORE the print is called?
  • Or, how to generate raster (png/jpeg) without the formatting errors obtained from canvg/jsPDF?

The function doing the print call for now is:

function getscreenshot(div) {
  // Hide row pair:
  $('#map-card').addClass('hidden');

  // Temporarily change class attr to spawn all row:
  var divClass = $(div).attr('class');
  $(div).attr('class', 'col');

  // ****PROBLEM****
  // Div size is not upated before calling print()
  // causing the print to have the size as displayed on user screen
  // How to refresh it before print?
  // ********

  // jQuery.print solves it in a non-ideal way, since user has to set save as file and so on
  $(div).print();

  // This solution with jsPDF produces **ugly as hell** image:
  // var pdf = new jsPDF('landscape');
  // pdf.addHTML(document.getElementById(div), function() {
  //     pdf.save(name + 'pdf');
  // });

  // Recover original size after print:
  // Restore row pair and div original state:
  $('#map-card').removeClass('hidden');
  $(div).attr('class', divClass);
}

Here is the row of cards as shown on the webpage: Cards row

The plot on the right is the one I'm focusing my try-outs, and the one that is getting completing unformatted. Check what comes out using html2canvas, jsPDF and the like results in the same misconstruction as seem in the fiddle with SVG pasted, using canvg.js

PS: Yep, I did search a lot. That's how I ended up trying html2canvas, canvg, jsPDF, jqprint, ...

Cheers!

like image 589
Marcelo do Pagode Avatar asked Jun 07 '18 21:06

Marcelo do Pagode


Video Answer


1 Answers

You can solve the problem with Mike Bostock's (or maybe it's NY Times's) SVG Crowbar. Use SVG Crowbar 2. You drag it to the bookmarks bar then click on it when you're on the page where you want to save the SVG. If there is more than one SVG, you will have to choose which one.

I tested SVG Crowbar 1 with c3.js and it didn't save the styles correctly, so make sure you use SVG Crowbar 2. I tested SVG Crowbar 2 with c3.js and it worked for me.

Once you have an SVG, you can use Inkscape to make a PNG out of it. Click: file > export PNG Image. Then choose your desired dimensions for output. Then click Export. This site has a step by step of how to do this

There are also sites online that convert SVG to PNG also, but there are a few so I won't post the links. A google search should find what you need.

If you want to do all of this in a programmatic way, that's another story.

Update: SVG Crowbar (1 and 2) only work in chrome.

like image 169
tgiachetti Avatar answered Oct 05 '22 23:10

tgiachetti