2

I would like to create a link to allow the user to download the displayed graph. The way i am currently trying to get it to work is with .toDataUrl is that considered a safe way or is there another way of going about doing this.

HTML:

<canvas id="myChart" baseChart [colors]="colorsOverride" [datasets]="barChartData" [labels]="barChartLabels" [options]="barChartOptions" [legend]="barChartLegend"
    [chartType]="barChartType" (chartHover)="chartHovered($event)" (chartClick)="chartClicked($event)">
</canvas>

<div class="footer">
  <button (click)="exportGraph()">Export Graph</button>
</div>

Components:

  export_graph = <HTMLCanvasElement>document.getElementById("myChart");
  downloadLink: string;

  exportGraph(){
    this.downloadLink = this.export_graph.toDataURL("image/png");
  }

When i try to export this is the error message i get in my console: Cannot read property 'toDataURL' of null

4
  • at the point where the line export_graph = <HTMLCanvasElement>document.getElementById("myChart"); is executed, the dom for your component is not constructed. Thus, it will return null. try putting it in an ngAfterViewInit and dont forget to implement AfterViewInit.. working on a plunker and an answer. Commented May 2, 2017 at 21:29
  • Possible duplicate of Why does jQuery or a DOM method such as getElementById not find the element? Commented May 2, 2017 at 21:45
  • @MikeMcCaughan well - i am using typescript along with angular2 and my question was more towards using ng-charts (charts.js) and none of the suggested solutions are applicable for my code structure. Commented May 2, 2017 at 21:49
  • TypeScript compiles to JavaScript, so anything you do in JavaScript can be used in TypeScript. For Angular, just use ngOnInit. Commented May 2, 2017 at 21:55

1 Answer 1

12

You should use an anchor tag <a> instead of <button>, you can style it to look just like a button. Then you can attach a click event and do it this way:

plunker: http://plnkr.co/edit/xyfWok58R3eQdYk7pAds?p=preview

first, add the download link to your html <a href="#" (click)="downloadCanvas($event)"> DOWNLOAD THIS</a>

then create the downloadCanvas function

downloadCanvas(event) {
    // get the `<a>` element from click event
    var anchor = event.target;
    // get the canvas, I'm getting it by tag name, you can do by id
    // and set the href of the anchor to the canvas dataUrl
    anchor.href = document.getElementsByTagName('canvas')[0].toDataURL();
    // set the anchors 'download' attibute (name of the file to be downloaded)
    anchor.download = "test.png";
}

it is important to do the document.getElement... on click instead of before-hand. This way you know for sure the html view and <canvas> has rendered and is done drawing (you see it on the page).

the way you are doing it in your question, you are looking for <canvas> element before it's even rendered on the page, that why it's undefined.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks this is working as expected now. But one questions when i am doing the export is there a way to control the size of the exported graph? on display it is a small suitable size but when exporting i would like to increase its size.
you'll have to recreate the canvas with the large size you're looking for then download it as per my answer. You can keep the canvas hidden while you do that. I say this because if you just enlarge a small canvas image, it will look pixilated.
true - thanks i will go ahead and give that a try. Also i was further testing this solution out and realized that if i have multiple graphs on the page and regardless which of the graphs i click to download only one graph type is downloaded - Will i need to pass in an id or some distinguisher as to which graph?
You can find the canvas relative to your button location. maybe the button and canvas share the same parent and you can find the specific canvas that way. alternatively, look into writing a plugin for chartjs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.