2

Here's my (truncated) example SVG image (made with Highcharts, http://www.highcharts.com/ ) - when I render that onto a canvas (with canvg (https://github.com/gabelerner/canvg and code adapted from here: https://stackoverflow.com/a/8997520/2067690) all text in the resulting PNG is duplicated, meaning that it's output double, one piece of text immediately followed by the same text once again. How can I ensure it appears once only?

<svg height="400" width="1170" version="1.1" xmlns="http://www.w3.org/1999/svg">
<text zIndex="8" text-anchor="end" style="font-family:&quot;Lucida Grande&quot;, &quot;Lucida Sans Unicode&quot;, Verdana, Arial, Helvetica, sans-serif;font-size:9px;cursor:pointer;color:#909090;fill:#909090;" y="22" x="220">
  <tspan x="220">Highcharts.com</tspan>
</text>
</svg>
Community
  • 1
  • 1
HumanInDisguise
  • 1,335
  • 4
  • 17
  • 29

4 Answers4

4

This question is a bit old but I also found this pretty annoying to have this double text bug in my graphs. I took a look at the code and modified it to work with tspan. I didn't really dig into it, so I don't understand all the mechanisms taking place in the library, but I noticed that for "tspan", at some point, the object created was :

  • Well, an object, with a type "tspan" and a text attribute.
  • And that object also contained an other object, which is the text value of the tspan (which is then the same as the previous text attribute)

So what I did is to modify the source code of the library. If you search for

// tspan 
svg.Element.tspan = function(node) {

Then you just have to add this inside the function (replacing the old content) :

if ( node.nodeName == "tspan")
    this.text = '' ;
else
    this.text = node.value || node.text || node.textContent || '';

And that solved my problem. I hope that helps someone.

Loufylouf
  • 697
  • 5
  • 13
  • Replacing with the above code gave me this error _Cannot read property 'replace' of undefined_ in the canvg.js in the following code `svg.compressSpaces = function(s) { return s.replace(/[\s\r\t\n]+/gm,' '); }` – Kamil Jun 01 '15 at 19:37
  • I would suggest changing this function into something like this : `svg.compressSpaces = function(s) { if ( typeof s != "undefined") return s.replace(/[\s\r\t\n]+/gm,' '); else return ''; }` . Please note that this is only a dirty fix that I provided, so I do not guarantee that it works great. – Loufylouf Jun 01 '15 at 21:37
1

After much deleting parts of my example SVG image, to find when the error would go away, I found that it's the tspan tags - once I leave them out, canvg will display text only once as intended.

HumanInDisguise
  • 1,335
  • 4
  • 17
  • 29
1

I just added textOutline: 'none' inside your exporting parameter and it works for me.

Codpen with solution https://codepen.io/kirill-kirs/pen/qBjNdwg

 exporting: {
        sourceWidth: 1000,
        sourceHeight: 1000,
        chartOptions: {
            plotOptions: {
                series: {
                    dataLabels: {
                        enabled: true,
                        backgroundColor: 'rgba(0, 0, 0, 0.75)',
                        style: {
                            textOutline: 'none',
                            color: 'white'
                        }
                    }
                }
            }
        }
    }
0
<!-- Client Side Code -->
<script type="text/javascript">
    window.onload = function() {
        //1. Get the Highcharts Graph from the Div containing it
        var chart = $('#IDOfDivContainingHighchartsGraph').highcharts();

        //2. Get SVG from Hicharts Export Service
        var svgString = chart.getSVGForExport();

        //3. Save it client side div to manipulate the fetched string
        $('#exportedSVG').html(svgString);

        //4. LOGIC TO REMOVE THE DUPLICATE TSPAN TAG
        var svgTSPAN_TextElement=$("#exportedSVG text");
        for(i=0;i<svgTSPAN_TextElement.length;i++){
            childTspanElements=$(svgTSPAN_TextElement[i]).children("tspan");
            if(childTspanElements.length==2){
                childTspanElements[1].remove();
            }
        }

        //5. Get the maniupluated object as string
        svgString=$("#exportedSVG svg").get(0).outerHTML;

        //6. POST Maniiulated SVG string
        var url= '/URL/To/Server/Side.php';
        $.ajax({
            type: 'POST',
            data: {svgString:svgString, upload:1},
            url: url,
            async: false,
            success: function(data){
                //Nothing here
            }
        });

    }
</script>

//Server Side Code
<?php
if(isset($_POST["upload"])){
    $SVGData=$_POST["svgString"];
    $locationToSaveFile = "/location/to/Save/SVGFILE.svg";
    file_put_contents($locationToSaveFile, $SVGData);
    exit();
}

//By the end of this code you would have created the svg file of the hicharts on the server side
?>