org-chart icon indicating copy to clipboard operation
org-chart copied to clipboard

Image export incomplete (missing styles)

Open spyro2000 opened this issue 2 years ago • 10 comments

Describe the bug Loving this lib :) But when I export the image, the image seems not complete (not all CSS styles seems to be taken into account)

To Reproduce Steps to reproduce the behavior:

  1. Create chart
  2. Apply some styling like this: h1 {background-color: gray;} (same for DIV borders etc.)
  3. Export as PNG

Expected behavior Exported image should look like in the browser

Screenshots

Browser:

image

Export:

image

Full scss markup

div.node {
    background-color: white;
    border-radius:10px;
    border: 1px solid lightgray;
    padding: 0 $s $s $s;
    max-height: 455px;
    overflow: auto;

    h1 {
      font-size: $md;
      margin: 0 (-$s) $s (-$s);
      align-content: center;
      text-align: center;
      background-color: whitesmoke;
      border-top-left-radius: $s;
      border-top-right-radius: $s;
      padding: $xs;
    }

    table {
      border-collapse: collapse;

      tr {

        &:not(:first-child).category {
          border-top: 1px solid lightgray;
        }

        &.odd {
          background-color: white;
        }

        &.even {
          background-color: whitesmoke;
        }

        &.category {

          td {
            padding-top: $s;
            padding-bottom: $xs;
          }

          td:first-child {
            font-weight: bold;
          }

        }
      }

      ul {
        padding: 0 0 $xs;
        margin: 0 0 0 $md;
      }

    }

  }

Desktop (please complete the following information):

  • OS: Win10x64
  • Browser: Chrome 98.0.4758.102
  • Org-Chart: 2.6.0
  • d3: 7.3

spyro2000 avatar Mar 07 '22 10:03 spyro2000

You have two choices:

Choice 1. Apply those styles as inner CSS - it's tested and working well

Choice 2. Write a js function that will loop over Org Chart dom elements and will apply currently applied styles as inner style. This is theoretical and not sure if it's gonna work. If you do this approach, please also share the code, it may help other people with similar issues

bumbeishvili avatar Mar 07 '22 14:03 bumbeishvili

Hello @bumbeishvili,

thanks for your quick response. I found this library here: https://github.com/lukehorvat/computed-style-to-inline-style They even mention inline SVGs for this. So maybe I am able to solve this. If I got time (and was successful), then I will post the solution here.

spyro2000 avatar Mar 07 '22 18:03 spyro2000

Looking forward to seeing the result

bumbeishvili avatar Mar 07 '22 18:03 bumbeishvili

Hi there, did some tests today.

The library copied each css property over to the SVG in the DOM as it should:

image

(Styles now inlined)

But when calling 'exportImg()', the styles seem still ignored:

image

spyro2000 avatar Apr 25 '22 12:04 spyro2000

So it seems inline styles are the only variant

bumbeishvili avatar Apr 25 '22 16:04 bumbeishvili

Helllo @bumbeishvili,

unfortunately that's not an option for me as there are quite complex (S)CSS selectors in place, regarding table structures in the nodes and so in.

It seems like this library didn't generate inline-styles for the HTML (data) struture inside the nodes but only the SVG nodes itself :(

image

spyro2000 avatar Apr 26 '22 07:04 spyro2000

In that case, maybe try to find some script that will generate inline styles for foreignObject elements? In theory, it should not be hard, it's just a traversing a dom tree and applying calculated styles as inner styles

bumbeishvili avatar Apr 26 '22 07:04 bumbeishvili

Hello @bumbeishvili,

many thinks for your response. The strange thing is, even when I directly add styles by hand in the dom directly to an element via devtools, they get removed by the image export process:

Before:

image

After export attempt via

   this.chart.exportImg({
      full: true, // export the full chart, regardless of screen selection (does not work reliable)
      scale: 5, // font gets smaller for many nodes, so we go BIG here,
    })

image

spyro2000 avatar Apr 26 '22 08:04 spyro2000

@spyro2000 so, the process for exporting as an image is following

• Take SVG element • Convert it to String • Draw it on Canvas • Export image from Canvas element

If your styles are not part of the converted string in step 2, then it will not work. Maybe Dom element reference is different when you are applying the style using chrome and that's why it is not working, I am not exactly sure

bumbeishvili avatar Apr 26 '22 08:04 bumbeishvili

@spyro2000 easiest way it to just inline your styles directly on your svg's elements. And don't use CSS variables. Use js template string variables instead.

Browsers ignore external stylesheets for svgs in canvas because they think they could be a source or arbitrary code that could get run as an attack.

You could write a function that grabs all the style rules from all the stylesheets, crawls your svg's element tree, and checks if any of the rules's selectors match, and append the rules to the element's style attribute, but it becomes incredibly slow with just a handful of chart nodes, and unusable pretty quickly.

Until browsers provide a way to export svgs directly, this isn't going to change.

schindld avatar Jun 09 '22 12:06 schindld