1

I'm relatively new to Stack Overflow, so I will attempt to be as thorough and concise when asking this question. I'm working on a project, and have just implemented a function to print a png image of a graph (using D3.js). Now I want to add a date (or text) to the downloaded png (only when it has been downloaded). I have been trying various things, with no luck. Any ideas?

window.printPNG = function () {
    // Inputs
    var mySVG = document.getElementById('the-bubble-chart');
    var myXML = (new XMLSerializer()).serializeToString(mySVG);

    // Outputs
    var myCanvas = document.getElementById('canvg-output');
    var myImg = document.getElementById('png-output');
    var myA = document.getElementById('png-link');

    canvg(myCanvas, myXML);

    var dataURL = myCanvas.toDataURL('image/png');
    var dataURLHeaders = "data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=download.png;";

    // Format file name for download
    var d = new Date(),
        dateString = d.getMonth() + 1 + "-" + d.getDate() + "-" + d.getFullYear().toString();

    myImg.src = dataURL;
    myA.href = dataURL.replace('data:', dataURLHeaders);
    myA.download = dateString + "_" + "download.png";
    myA.click()
}
Stephen Ross
  • 376
  • 4
  • 17
  • This question should probably be closed as a duplicate, see here: http://stackoverflow.com/questions/12796513/html5-canvas-to-png-file. I'll leave it open for now in case technologies have changed but I think that question is still the state of things. – Mark Jan 14 '16 at 17:03
  • Thanks for posting that link. I apologize if this post is a duplicate. I tried to search and could not come up with anything. I do believe my question differs in that I am not simply trying to download an image. My function for downloading an image works fine. I am trying to print the date on the image once it has been downloaded. Thank you for the response. – Stephen Ross Jan 14 '16 at 17:15
  • Are you trying to add the date to the image or add the date to the filename? If the latter, that other question pretty much says you can't do it reliably across browsers. If you are trying to add it to the image, your code doesn't really reflect that. – Mark Jan 14 '16 at 17:20
  • One more thing, if you want to add it to the image, that's very do-able and I'd be happy to type up an answer. Just let em know. – Mark Jan 14 '16 at 17:28
  • I am trying to add it to the image itself. And you are correct, it is not reflected in the code because I haven't been able to come up with anything unfortunately. Any help would be greatly appreciated. – Stephen Ross Jan 15 '16 at 04:16

1 Answers1

0

You can add the text directly to the canvas before you convert it to a png:

...
canvg(myCanvas, myXML);

// Format file name for download
var d = new Date(),
dateString = d.getMonth() + 1 + "-" + d.getDate() + "-" + d.getFullYear().toString();

// add date to canvas
var ctx = myCanvas.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText(dateString,10,50);

var dataURL = myCanvas.toDataURL('image/png');
...

Full Code:

<!DOCTYPE html>
<html>

  <head>
    <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
    <script src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script>
  </head>

  <body>
    <svg id="the-bubble-chart" width="500" height="500"></svg>
    <canvas id="canvg-output"></canvas>
    <img id="png-output" /> <br><br>
    <a id="png-link">Click Here</a>
    <script>
  
    var svg = d3.select('#the-bubble-chart');

    svg.append("rect")
      .attr("width", 500)
      .attr("height", 500)
      .style("fill","lightblue");
    
    svg.selectAll('circle')
      .data([0,1,2,3])
      .enter()
      .append('circle')
      .attr('cx', function(d){
        return d * 100 + 50;
      })
      .attr('cy', function(d){
        return d * 100 + 50;
      })
      .attr('r', 30)
      .style('fill','red');
  
    window.printPNG = function() {
      // Inputs
      var mySVG = document.getElementById('the-bubble-chart');
      var myXML = (new XMLSerializer()).serializeToString(mySVG);
      
      console.log(myXML)

      // Outputs
      var myCanvas = document.getElementById('canvg-output');
      var myImg = document.getElementById('png-output');
      var myA = document.getElementById('png-link');

      canvg(myCanvas, myXML);
      
      // Format file name for download
      var d = new Date(),
        dateString = d.getMonth() + 1 + "-" + d.getDate() + "-" + d.getFullYear().toString();

      var ctx = myCanvas.getContext("2d");
      ctx.font = "30px Arial";
      ctx.fillText(dateString,10,50);

      var dataURL = myCanvas.toDataURL('image/png');
      var dataURLHeaders = "data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=download.png;";


      myImg.src = dataURL;
      myA.href = dataURL.replace('data:', dataURLHeaders);
      myA.download = dateString + "_" + "download.png";
      //myA.click()
    }
    
    printPNG();
  </script>
  </body>

</html>
Mark
  • 106,305
  • 20
  • 172
  • 230
  • Thank you. This definitely works for me (had a tweak the code slightly). I tried to upvote this, but my reputation is still too low. If you could possibly upvote my question, that would be awesome (no pressure or anything).But I really appreciate the help! – Stephen Ross Jan 16 '16 at 19:49
  • is there anyway to add the ctx variable to myA.download variable? The ctx varialbe is exactly what I needed, I'm still struggling to get the date to show up on the downloaded graph. – Stephen Ross Jan 16 '16 at 22:07
  • @StephenRoss, I don't understand the question. The code above is a complete sample, does it not include a date in the download? I did comment out the `myA.click()` so that the image wouldn't auto-download and annoy everyone visiting this question. – Mark Jan 16 '16 at 22:55
  • Sorry, I should have stated the question better. I'm having some trouble getting the date to show up once I've downloaded the png image. It seems that I need to pass in the CTX variable somewhere in inline `myImg.src = dataURL; myA.href = dataURL.replace('data:', dataURLHeaders); myA.download = dateString + "_" + "download.png";` – Stephen Ross Jan 18 '16 at 15:22
  • @StephenRoss, unfortunately, I still don't understand. Does my code sample work for you when you push the "Run code snippet" button above? Did you take that code and integrate it into your codebase? If the answer to the first question is yes and the second is no, what did you change? Do you have any errors on your console? "pass in the CTX variable somewhere", I don't get that. The ctx variable is holding the canvas context. It's what you use to draw or write on the canvas. You get the context from the canvas, write on the canvas, convert the canvas to PNG with the text already on it. – Mark Jan 18 '16 at 18:08
  • I'm sorry that I can't explain this very well. I'm new to Javascript development. The code snipper will run, but when I implement the code into my codebase, nothing happens. The only the that changes is that I have removed `var svg`. – Stephen Ross Jan 18 '16 at 19:59
  • @StephenRoss, if you can reproduce your troubles in a jsFiddle or plnkr.co I will take a look. – Mark Jan 18 '16 at 20:00
  • @StephenRoss, couple things wrong with the fiddle. 1.) you didn't load `d3.js`, 2.) You never called the `window.printPNG();` function and 3.) **most importantly**, your order of operations is wrong. Create the SVG, convert to canvas, add date to canvas, make PNG of canvas. You were going create the svg, convert to canvas, make png and then add the date. See fixes here: http://jsfiddle.net/5wgx0z1z/10/ – Mark Jan 18 '16 at 20:35
  • Thanks. That makes a lot more sense now. The `window.printPNG()` is actually being called from a button in index.html. I definitely see the problem with the order of operations though. Once I rearranged the order, everything started working. – Stephen Ross Jan 18 '16 at 21:24