d3export_demo icon indicating copy to clipboard operation
d3export_demo copied to clipboard

CSS Defined Styles are lost

Open Hypercubed opened this issue 10 years ago • 2 comments

One trouble with the XML serialization you are doing here is that CSS defined styles are lost. This is a problem I'm working on here: https://github.com/Hypercubed/svgsaver . If you include svgsaver in this project it might be as simple as replacing this line: https://github.com/agordon/d3export_demo/blob/master/index.html#L174 with svgsaver.getHTML(svg).

You might also eliminate the need for a server for downloading SVG and PNG (with some caveats)

Hypercubed avatar Oct 15 '15 02:10 Hypercubed

Yeah that is a lot easier. Wish I had seen svgsaver before trying to mess around with CGI scripts.

For reference (as there aren't specific instructions here) I am making/testing visualisations in D3 and displaying them locally or on gist/ blocks. for the local work i was using the python SimpleHttpServer. for the download.pl script to work though you need to put download.pl in /cgi-bin in the root dir of your app, and then for installation of perl and the relevant cran modules. I had to install:

cpan
cpan[1]>    install autodie
cpan[2]>    install IPC::System::Simple
cpan[3]>    install File::Slurp

I guess there is another way of installing these packages without using the cpan prompt, I have seen it and it looks messy, but tbh I don't really do perl. Anyway then you can do (for python 2.7, its different in python3):

python -m CGIHTTPServer

Then you can download your svg, but yeah as all you are doing is ripping out the svg and pinging it back as a file all the css is missing. I guess you could get the css too and concatenate that to the start of the svg_xml.

The svgsaver is much easier to deal with but will produce quite big svgs if you have a large number of elements as all the elements are individually styled, instead of copying the css across, which I think you can do for svgs. something like:

var svg  = d3.select('svg').node();
var css  = d3.select('style').node();
var svg_xml = (new XMLSerializer).serializeToString(svg.insertBefor(css,svg.firstChild));

Though this will actually modify the DOM which i guess is bad and also you wont get the correct css if you are using an @import or src or if the css is across multiple <style> tags. you could use this to get the css:

var css = getElementChildrenAndStyles('svg')

Anyway it was all very interesting.

Are there plans to get SvgSaver onto a CDN?

Richard-Mathie avatar Oct 29 '15 11:10 Richard-Mathie

Yes, right now svgsaver includes a lot of unnecessary style information in the SVG. This is something I am working on. For example we don't needed to keep redundant inherited styles. If you know beforehand you only rely on a subset of styles you can pass that set to the svgsaver constructor (https://github.com/Hypercubed/svgsaver/blob/master/src/svgsaver.js#L29). I need to document this.

I think one problem with copying the style element as you have shown is it will miss styles like this, since the container elements are not serialized.

#chart-div rect {
  /* the styles */
}

Hypercubed avatar Oct 30 '15 04:10 Hypercubed