Issue
Im using Angular 1.5.6 and I want to create a HTML canvas (that's NOT in the DOM) and download as an image. I did it in pure javascript, you can see the fiddle here. The Fiddle code is:
var canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;
var ctx = canvas.getContext('2d');
/**
* Demonstrates how to download a canvas an image with a single
* direct click on a link.
*/
function doCanvas() {
/* draw something */
ctx.fillStyle = '#f90';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#fff';
ctx.font = '20px sans-serif';
ctx.fillText('some text', 10, canvas.height / 2 - 15);
}
/**
* This is the function that will take care of image extracting and
* setting proper filename for the download.
* IMPORTANT: Call it from within a onclick event.
*/
function downloadCanvas(link) {
link.href = canvas.toDataURL();
link.download = 'test.png';
}
/**
* The event handler for the link's onclick event. We give THIS as a
* parameter (=the link element)
*/
document.getElementById('download').addEventListener('click', function() {
downloadCanvas(this);
}, false);
/**
* Draw something to canvas
*/
doCanvas();
However, I'm struggling to get it working in an Angular directive. My directive is:
angular.module('myApp.analyse')
.directive('export', exportGates);
function exportGates($location) {
function createCanvas(gates) {
var canvas = document.createElement("canvas");
canvas.width = 600;
canvas.height = 600;
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f90';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#fff';
ctx.font = '20px sans-serif';
ctx.fillText('some text', 10, canvas.height / 2 - 15);
return canvas;
}
return {
restrict: 'E',
templateUrl: 'analyse/directives/export.tpl.html',
link: function(scope, element, attrs) {
element.bind('click', function () {
var canvas = createCanvas(scope.gates);
element.href = canvas.toDataURL();
element.download = 'export.png';
});
}
}
}
The issue appears to be that in my first example, the callback to addEventListener is passed 'this', which is the link I need to attach the href and download attributes to automatically download on the click. I thought 'element' in my directive link method was what I needed to attach the href and download attributes to, but obviously not. How can I get this working?
Solution
The element actually is an instance of jQLite
element which is like a jQuery element, from which you could try to find
your link inside it and execute the process to download your canvas.
However, I have a better solution that doesn't require an existing link, but rather create your own link and dispatch a click on it without even having to add it to the DOM.
The following snippet implements this solution.
function saveCanvasAs(canvas, fileName) {
// get image data and transform mime type to application/octet-stream
var canvasDataUrl = canvas.toDataURL()
.replace(/^data:image\/[^;]*/, 'data:application/octet-stream');
var link = document.createElement('a'); // create an anchor tag
// set parameters for downloading
link.setAttribute('href', canvasDataUrl);
link.setAttribute('target', '_blank');
link.setAttribute('download', fileName);
// compat mode for dispatching click on your anchor
if (document.createEvent) {
var evtObj = document.createEvent('MouseEvents');
evtObj.initEvent('click', true, true);
link.dispatchEvent(evtObj);
} else if (link.click) {
link.click();
}
}
Finally, you can call it inside your directive like so:
...
var canvas = createCanvas(scope.gates);
saveCanvasAs(canvas, 'export.png');
...
Answered By - lenilsondc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.