svg2pdf.js icon indicating copy to clipboard operation
svg2pdf.js copied to clipboard

wrong export from Highcharts svg with outlined text/

Open inc198107 opened this issue 3 years ago • 13 comments

When export from chart with outlined text (nested tSpan used) cintent is duplicated. screenshot

after some debugging svg2pdf library i am founded cause of described bug, it is part of code in textchunk.ts that set x coordinate of tSpan (string 111 - 112 ) image after described changes everything works fine screenshot after string commented

(sorry for my weak english)

Angular 10, Highcharts 9.2.1 , jsPDF 2.4.0, svg2pdf 2.2.0 Chrome 91.0.4472.124 (Official Build) (64-bit)

that used svg:

<svg version="1.1" class="highcharts-root" style="font-family:&quot;Lucida Grande&quot;, &quot;Lucida Sans Unicode&quot;, Arial, Helvetica, sans-serif;font-size:12px;" xmlns="http://www.w3.org/2000/svg" width="1431" height="646" viewBox="0 0 1431 646"> <desc>Created with Highcharts 9.1.2</desc> <defs><clipPath id="highcharts-97af60ab-ef02-e850-0b0f-90b8ffebf2a5"> <rect x="0" y="0" width="1411" height="550" fill="none"></rect> </clipPath></defs><rect fill="#ffffff" class="highcharts-background" x="0" y="0" width="1431" height="646" rx="0" ry="0"></rect><rect fill="none" class="highcharts-plot-background" x="10" y="40" width="1411" height="550"></rect><g class="highcharts-grid highcharts-xaxis-grid" data-z-index="1"></g><g class="highcharts-grid highcharts-yaxis-grid" data-z-index="1"></g><rect fill="none" class="highcharts-plot-border" data-z-index="1" x="10" y="40" width="1411" height="550"></rect><g class="highcharts-axis highcharts-xaxis" data-z-index="2"><path fill="none" class="highcharts-axis-line" data-z-index="7" d="M 10 590 L 1421 590"></path></g><g class="highcharts-axis highcharts-yaxis" data-z-index="2"><path fill="none" class="highcharts-axis-line" data-z-index="7" d="M 10 40 L 10 590"></path></g><g class="highcharts-series-group" data-z-index="3"><g class="highcharts-series highcharts-series-0 highcharts-treemap-series highcharts-color-0 highcharts-tracker" data-z-index="0.1" transform="translate(10,40) scale(1 1)" clip-path="url(#highcharts-97af60ab-ef02-e850-0b0f-90b8ffebf2a5)"><g class="highcharts-level-group-4" data-z-index="996"><rect x="-0.5" y="-0.5" width="906" height="550" fill="#7cb5ec" stroke="#e6e6e6" stroke-width="1" class="highcharts-point"></rect><rect x="905.5" y="-0.5" width="505" height="550" fill="#7cb5ec" stroke="#e6e6e6" stroke-width="1" class="highcharts-point"></rect></g><g class="highcharts-level-group-3" data-z-index="997"><rect x="-0.5" y="-0.5" width="906" height="550" fill="rgba(124,181,236,0.15)" stroke="#e6e6e6" stroke-width="1" class="highcharts-point highcharts-internal-node-interactive"></rect><rect x="905.5" y="-0.5" width="505" height="550" fill="rgba(124,181,236,0.15)" stroke="#e6e6e6" stroke-width="1" class="highcharts-point highcharts-internal-node-interactive"></rect> </g><g class="highcharts-level-group-2" data-z-index="998"><rect x="905.5" y="-0.5" width="505" height="550" fill="rgba(124,181,236,0.15)" stroke="#e6e6e6" stroke-width="1" class="highcharts-point highcharts-internal-node-interactive"></rect><rect x="-0.5" y="-0.5" width="906" height="550" fill="rgba(124,181,236,0.15)" stroke-width="1" class="highcharts-point highcharts-internal-node-interactive" data-z-index="0" stroke="#e6e6e6"></rect></g> <g class="highcharts-level-group-1" data-z-index="999"><rect x="-0.5" y="-0.5" width="906" height="550" fill="rgba(124,181,236,0.15)" stroke-width="3" class="highcharts-point highcharts-internal-node-interactive" data-z-index="0" stroke="rgb(230,230,230)"></rect> <rect x="905.5" y="-0.5" width="505" height="550" fill="rgba(124,181,236,0.15)" stroke="rgb(230,230,230)" stroke-width="3" class="highcharts-point highcharts-internal-node-interactive" data-z-index="0"></rect></g></g> <g class="highcharts-markers highcharts-series-0 highcharts-treemap-series highcharts-color-0" data-z-index="0.1" transform="translate(10,40) scale(1 1)"></g> </g><text x="716" text-anchor="middle" class="highcharts-title" data-z-index="4" style="color:#333333;font-size:18px;fill:#333333;" y="24"></text> <text x="716" text-anchor="middle" class="highcharts-subtitle" data-z-index="4" style="color:#666666;fill:#666666;" y="24"></text> <text x="10" text-anchor="start" class="highcharts-caption" data-z-index="4" style="color:#666666;fill:#666666;" y="643"></text> <g class="highcharts-data-labels highcharts-series-0 highcharts-treemap-series highcharts-color-0 highcharts-tracker" data-z-index="6" transform="translate(10,40) scale(1 1)" opacity="1"> <g class="highcharts-label highcharts-data-label highcharts-data-label-color-undefined" data-z-index="1" transform="translate(0,-9999)"><text x="5" data-z-index="1" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;"> <tspan class="highcharts-text-outline" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2px" stroke-linejoin="round" style="">-<tspan x="5" y="16">​</tspan></tspan>-</text></g> <g class="highcharts-label highcharts-data-label highcharts-data-label-color-undefined" data-z-index="1" transform="translate(1134,263)"><text x="5" data-z-index="1" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;"> <tspan class="highcharts-text-outline" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2px" stroke-linejoin="round">POWER<tspan x="5" y="16">​</tspan></tspan>POWER</text></g><g class="highcharts-label highcharts-data-label highcharts-data-label-color-undefined" data-z-index="1" transform="translate(0,-9999)" opacity="0"><text x="5" data-z-index="1" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;"><tspan class="highcharts-text-outline" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2px" stroke-linejoin="round" style="">OTHER<tspan x="5" y="16">​</tspan></tspan>OTHER</text></g><g class="highcharts-label highcharts-data-label highcharts-data-label-color-undefined" data-z-index="1" transform="translate(436,263)"><text x="5" data-z-index="1" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;"><tspan class="highcharts-text-outline" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2px" stroke-linejoin="round">GAS<tspan x="5" y="16">​</tspan></tspan>GAS</text></g></g><g class="highcharts-legend highcharts-no-tooltip" data-z-index="7" transform="translate(554,602)"><rect fill="none" class="highcharts-legend-box" rx="0" ry="0" x="0" y="0" width="322" height="29" visibility="visible"></rect><g data-z-index="1"><g><g class="highcharts-legend-item highcharts-treemap-series highcharts-color-0 highcharts-series-0" data-z-index="1" transform="translate(8,3)"><text x="21" style="color:#333333;cursor:pointer;font-size:12px;font-weight:bold;fill:#333333;" text-anchor="start" data-z-index="2" y="15">Data Set 1 Ad-hoc/UMM Count (Affected asset)</text><rect x="2" y="4" width="12" height="12" fill="#7cb5ec" rx="6" ry="6" class="highcharts-point" data-z-index="3"></rect></g></g></g></g><g class="highcharts-axis-labels highcharts-xaxis-labels" data-z-index="7"></g><g class="highcharts-axis-labels highcharts-yaxis-labels" data-z-index="7"></g><g class="highcharts-label highcharts-tooltip highcharts-color-0" style="cursor:default;white-space:nowrap;pointer-events:auto;padding:0;" data-z-index="8" transform="translate(993,-9999)" opacity="0" visibility="hidden"><path fill="none" class="highcharts-label-box highcharts-tooltip-box highcharts-shadow" d="M 3 0 L 347 0 C 350 0 350 0 350 3 L 350 72 C 350 75 350 75 347 75 L 181 75 L 175 81 L 169 75 L 3 75 C 0 75 0 75 0 72 L 0 3 C 0 0 0 0 3 0" stroke="#000000" stroke-opacity="0.049999999999999996" stroke-width="5" transform="translate(1, 1)"></path><path fill="none" class="highcharts-label-box highcharts-tooltip-box highcharts-shadow" d="M 3 0 L 347 0 C 350 0 350 0 350 3 L 350 72 C 350 75 350 75 347 75 L 181 75 L 175 81 L 169 75 L 3 75 C 0 75 0 75 0 72 L 0 3 C 0 0 0 0 3 0" stroke="#000000" stroke-opacity="0.09999999999999999" stroke-width="3" transform="translate(1, 1)"></path><path fill="none" class="highcharts-label-box highcharts-tooltip-box highcharts-shadow" d="M 3 0 L 347 0 C 350 0 350 0 350 3 L 350 72 C 350 75 350 75 347 75 L 181 75 L 175 81 L 169 75 L 3 75 C 0 75 0 75 0 72 L 0 3 C 0 0 0 0 3 0" stroke="#000000" stroke-opacity="0.15" stroke-width="1" transform="translate(1, 1)"></path><path fill="rgba(247,247,247,0.85)" class="highcharts-label-box highcharts-tooltip-box" d="M 3 0 L 347 0 C 350 0 350 0 350 3 L 350 72 C 350 75 350 75 347 75 L 181 75 L 175 81 L 169 75 L 3 75 C 0 75 0 75 0 72 L 0 3 C 0 0 0 0 3 0"></path></g><g class="bread" data-z-index="10" transform="translate(11,5)"><path fill="transparent" class="highcharts-label-box" d="M 5 0 L 64 0 C 69 0 69 0 69 5 L 69 23 C 69 28 69 28 64 28 L 5 28 C 0 28 0 28 0 23 L 0 5 C 0 0 0 0 5 0"></path><text x="5" data-z-index="1" y="17">Top Level</text></g></svg>

inc198107 avatar Nov 11 '21 08:11 inc198107

Thanks for reporting this bug. Could you reduce your SVG to only what's necessary to reproduce the bug?

HackbrettXXX avatar Nov 11 '21 09:11 HackbrettXXX

It is little bit hard, because svg generated by Highcharts. But problematic part is here : <text x="5" data-z-index="1" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;"> <tspan class="highcharts-text-outline" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2px" stroke-linejoin="round">POWER<tspan x="5" y="16">​</tspan></tspan>POWER</text></g><g class="highcharts-label highcharts-data-label highcharts-data-label-color-undefined" data-z-index="1" transform="translate(0,-9999)" opacity="0"><text x="5" data-z-index="1" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;"><tspan class="highcharts-text-outline" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2px" stroke-linejoin="round" style="">OTHER<tspan x="5" y="16">​</tspan></tspan>OTHER</text></g><g class="highcharts-label highcharts-data-label highcharts-data-label-color-undefined" data-z-index="1" transform="translate(436,263)"><text x="5" data-z-index="1" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;"><tspan class="highcharts-text-outline" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="2px" stroke-linejoin="round">GAS<tspan x="5" y="16">​</tspan></tspan>GAS</text>

inc198107 avatar Nov 12 '21 08:11 inc198107

I've reduced it a bit further (and fixed it):

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
  <g>
    <text x="5" y="16" style="color:#000000;font-size:11px;font-weight:bold;fill:#000000;">
      <tspan fill="#FFFFFF" stroke="red" stroke-width="2px" stroke-linejoin="round">POWER
        <tspan x="5" y="16">​</tspan>
      </tspan>
      POWER
    </text>
  </g>
</svg>

This renders to image

Could you create a pull request? Although we have to test the suggested fix against other text examples. I'm pretty sure, adding the text width there happens for a reason.

HackbrettXXX avatar Nov 12 '21 09:11 HackbrettXXX

ok

inc198107 avatar Nov 15 '21 12:11 inc198107

Unfortunately, I don't have permission to create a new branch in your repository, so I can't make a pull request.

inc198107 avatar Dec 12 '21 14:12 inc198107

In order to create a pull request you have to fork the repository: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request

HackbrettXXX avatar Dec 13 '21 09:12 HackbrettXXX

Thanks a lot. I will do it in few days

пн, 13 дек. 2021 г. в 11:07, Lukas Holländer @.***>:

In order to create a pull request you have to fork the repository: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/yWorks/svg2pdf.js/issues/192#issuecomment-992251195, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEEJ4DXGJ4FFAFUY3MG457TUQWZTXANCNFSM5HZ3BURA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

inc198107 avatar Dec 14 '21 10:12 inc198107

Hi! Any updates on this issue? Based on this issue reported in Highcharts I was able to reproduce that in your online playground as:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 150">
  <text x="5" data-z-index="1" y="16" style="color: rgb(0, 0, 0); font-size: 11px; font-weight: bold; fill: rgb(0, 0, 0);">
    <tspan class="highcharts-text-outline" fill="red" stroke="red" stroke-width="2px" stroke-linejoin="round" style="">29.9<tspan x="5" y="16">&ZeroWidthSpace;</tspan>
    </tspan>29.9
  </text>
</svg>

image

karolkolodziej avatar Apr 08 '22 11:04 karolkolodziej

There is a PR (#198), but @inc198107 hasn't responded in a while. @karolkolodziej any assistance moving the PR forward would be very welcome.

HackbrettXXX avatar Apr 08 '22 11:04 HackbrettXXX

Sorry I had no time to recheck this previously. But now, as you now, we have war with Russian nazi(I am from Ukraine), houpfully after our victory I will return to this task

пт, 8 апр. 2022 г., 14:47 Lukas Holländer @.***>:

There is a PR (#198 https://github.com/yWorks/svg2pdf.js/pull/198), but @inc198107 https://github.com/inc198107 hasn't responded in a while. @karolkolodziej https://github.com/karolkolodziej any assistance moving the PR forward would be very welcome.

— Reply to this email directly, view it on GitHub https://github.com/yWorks/svg2pdf.js/issues/192#issuecomment-1092777900, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEEJ4DTMEPLNB2BYO5L2OGTVEAMGNANCNFSM5HZ3BURA . You are receiving this because you were mentioned.Message ID: @.***>

inc198107 avatar Apr 08 '22 12:04 inc198107

Thank you for the quick response.

A few comments on the issue and the PR:

  • There are some tests failing with this approach (replacing the calculation with currentTextX = x.
  • This approach(☝️) seems to work in our case but overall it doesn't look like a rounding/float imprecision issue it looks more like an actual error with the calculation.
  • I was able to simplify the code giving such results even more:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 150">
  <text x="8" data-z-index="1" y="16" >
    <tspan class="highcharts-text-outline" fill="red" stroke="red">29.9<tspan x="5" y="16">&ZeroWidthSpace;</tspan>
    </tspan>29.9
  </text>
</svg>
  • It seems that after this PR was introduced.
  • There is an issue with handling the &ZeroWidthSpace. There simply is no case for that in the code.

Perhaps before calculating currentTextX you should check if an element of &ZeroWidthSpace is being introduced. Pseudocode:

if (textNodeContext === '&ZeroWidthSpace') {
   currentTextX = x
} else {
   currentTextX = x + textMeasure.width + textMeasure.length * charSpace
}

Sorry I can't help more but I'm not entirely familiar with that library and also I'm not sure how to test it...

karolkolodziej avatar Apr 08 '22 13:04 karolkolodziej

Thanks for the feedback!

пт, 8 апр. 2022 г., 16:29 Karol Kołodziej @.***>:

Thank you for the quick response.

A few comments on the issue and the PR:

  • There are some tests failing with this approach (replacing the calculation with currentTextX = x.
  • This approach(☝️) seems to work in our case but overall it doesn't look like a rounding/float imprecision issue it looks more like an actual error with the calculation.
  • I was able to simplify the code giving such results even more:
<tspan class="highcharts-text-outline" fill="red" stroke="red">29.9<tspan x="5" y="16">&ZeroWidthSpace;</tspan>

</tspan>29.9

Perhaps before calculating currentTextX you should check if an element of &ZeroWidthSpace is being introduced. Pseudocode:

if (textNodeContext === '&ZeroWidthSpace') {

currentTextX = x

} else {

currentTextX = x + textMeasure.width + textMeasure.length * charSpace

}

Sorry I can't help more but I'm not entirely familiar with that library and also I'm not sure how to test it...

— Reply to this email directly, view it on GitHub https://github.com/yWorks/svg2pdf.js/issues/192#issuecomment-1092861909, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEEJ4DXFPR76MJ7RBNWSBI3VEAYEJANCNFSM5HZ3BURA . You are receiving this because you were mentioned.Message ID: @.***>

inc198107 avatar Apr 09 '22 17:04 inc198107

@karolkolodziej thanks for doing the tests and for the additional insight.

HackbrettXXX avatar Apr 11 '22 08:04 HackbrettXXX