Drawing an Svg File on a Html5 Canvas

Drawing an SVG file on a HTML5 canvas

EDIT: Dec 2019

The Path2D() constructor is supported by all major browsers now, "allowing path objects to be declared on 2D canvas surfaces".



EDIT: Nov 2014

You can now use ctx.drawImage to draw HTMLImageElements that have a .svg source in some but not all browsers (75% coverage: Chrome, IE11, and Safari work, Firefox works with some bugs, but nightly has fixed them).

var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
img.src = "http://upload.wikimedia.org/wikipedia/commons/d/d2/Svg_example_square.svg";

Live example here. You should see a green square in the canvas. The second green square on the page is the same <svg> element inserted into the DOM for reference.

You can also use the new Path2D objects to draw SVG (string) paths. In other words, you can write:

var path = new Path2D('M 100,100 h 50 v 50 h 50');
ctx.stroke(path);

Live example of that here.



Original 2010 answer:

There's nothing native that allows you to natively use SVG paths in canvas. You must convert yourself or use a library to do it for you.

I'd suggest looking in to canvg: (check homepage & demos)

canvg takes the URL to an SVG file, or the text of the SVG file, parses it in JavaScript and renders the result on Canvas.

How to draw an inline svg (in DOM) to a canvas?

For inline SVG you'll need to:

  • Convert the SVG string to a Blob
  • Get an URL for the Blob
  • Create an image element and set the URL as src
  • When loaded (onload) you can draw the SVG as an image on canvas
  • Use toDataURL() to get the PNG file from canvas.

For example:

function drawInlineSVG(ctx, rawSVG, callback) {

var svg = new Blob([rawSVG], {type:"image/svg+xml;charset=utf-8"}),
domURL = self.URL || self.webkitURL || self,
url = domURL.createObjectURL(svg),
img = new Image;

img.onload = function () {
ctx.drawImage(this, 0, 0);
domURL.revokeObjectURL(url);
callback(this);
};

img.src = url;
}

// usage:
drawInlineSVG(ctxt, svgText, function() {
console.log(canvas.toDataURL()); // -> PNG data-uri
});

Of course, console.log here is just for example. Store/transfer the string instead here. (I would also recommend adding an onerror handler inside the method).

Also remember to set canvas size using either the width and height attributes, or from JavaScript using properties.

draw svg file on html canvas programmatically

I don't have your svg file, but that being said you have to typically wait till the image is loaded before it will load to canvas. It is like drawing something that isn't there. I think this should work for you.

function drawHandCanvas(){
var canvas = document.getElementById('handCanvas');
var ctx = canvas.getContext('2d');
var img= document.createElement('img');

img.onload = function(){
ctx.drawImage(this,0,0);
}

img.src='images/handCursor.svg';
img.width = 60; img.height = 60;

}
drawHandCanvas();

How to convert SVG files to HTML5's canvas?

There's no 100% solution, but there are script libraries that can convert a subset of svg to canvas, e.g http://code.google.com/p/canvas-svg/. There's also the experimental Path2D API that can draw an svg path data string onto the canvas, not sure how well it's supported across browsers though.

Advise on drawing an SVG path onto a canvas

The relative commands of your path declaration won't work as you expected here.

They will be parsed at the creation of the inner Path2D, which doesn't have an end-point yet and thus they will all be relative to the initial 0,0 point.

Once this inner Path2D is created, the fact that the declaration was using relative methods will be lost, all these points are internally converted to absolute coordinates. So the last point of the final Path2D on which you'll call addPath(path) won't matter.

To do what you want you have a few solutions:

  • You could prepend a Mx,y to your path declaration:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.strokeStyle = '#fff'
ctx.lineWidth = 1
ctx.fillStyle = '#fff'

const radius = 50;
const x = 150;
const y = 70;

const p = new Path2D(`M${x - radius / 2},${y - radius / 2}m${radius},0 a 6.133588769794187,10 0 1, 0 0,${radius * 2} a10,10 0 1, 1 0,${radius * -2}`);

ctx.stroke(p)
ctx.fill(p)
body { background: #333; }
<canvas></canvas>

Drawing a modified SVG to a canvas

I managed to do it. The trick was to:

  1. use XMLHttpRequest() to load the SVG as an XML document
  2. manipulate that XML document
  3. convert the XML document to a string
  4. create an ObjectURL from that string
  5. create an Image with that ObjectURL
  6. copy that Image to the canvas

That's my sourcecode:

Edit: Unfortunately it only works in Firefox and Chrome. It fails in IE9 because XMLSerializer() is not supported (it also doesn't support getElementById on XML documents, but there are workarounds for that) and it fails in Opera because createObjectUrl is not supported.

var xhr = new XMLHttpRequest();
xhr.onload = function() {
// get the XML tree of the SVG
var svgAsXml = xhr.responseXML;
// do some modifications to the XML tree
var element = svgAsXml.getElementById('hat');
element.style.fill = '#ffff00';
// convert the XML tree to a string
var svgAsString = new XMLSerializer().serializeToString(svgAsXml);
// create a new image with the svg string as an ObjectUrl
var svgBlob = new Blob([svgAsString], {type: "image/svg+xml;charset=utf-8"});
var url = window.URL.createObjectURL(svgBlob);
var img = new Image();
img.src = url;
// copy it to the canvas
img.onload = function() {
var theCanvas = document.getElementById('theCanvas');
var context = theCanvas.getContext('2d');
context.drawImage(img, 0, 0);
window.URL.revokeObjectURL(svgBlob);
}
}
xhr.open("GET", "test.svg");
xhr.responseType = "document";
xhr.send();

Drawing SVG into Canvas and manipulating drawn elements using their IDs

Here's how to do this with Fabric:

fabric.loadSVGFromURL('/assets/72.svg', function(objects, options){

var group = fabric.util.groupSVGElements(objects, options);

group
.set({ left: 300, top: 200 })
.scaleToWidth(500)
.setCoords();

canvas.add(group);
}, reviver);

function reviver(element, object) {
object.id = element.getAttribute('id');
}

The code should be pretty self-explanatory. We load SVG; Fabric parses it internally, spitting out set of objects representing each element. We then group those elements and add them onto canvas in one chunk. Reviver is responsible for reading id off of each SVG element and assigning it to a corresponding fabric instance.

Run this snippet in http://fabricjs.com/kitchensink/ and you get:

loaded svg

Let's inspect this grouped object:

canvas.item(0) + ''; "#<fabric.PathGroup (29303): { top: 200, left: 300 }>"

And its children:

canvas.item(0).getObjects(); // Array[2287]

Let's retrieve one by id:

var greenland = canvas.item(0).getObjects().filter(function(obj) {
return obj.id === 'path4206';
})[0];

This is all plain old Javascript, as you can see. Let's change color of that particular object/shape now:

greenland.fill = 'red';

greenland in red

How to draw a SVG on Canvas using Javascript?

Try to use image to draw (so snippet not works - but when you edit it - it works)

let xml = new XMLSerializer().serializeToString(circSvg);   // get svg datalet svg64 = btoa(xml);                         // make it base64let b64Start = 'data:image/svg+xml;base64,';let image64 = b64Start + svg64;                // prepend a "header"
circImg.src = image64; // image sourcecircImg.onload = x=> { can.getContext('2d').drawImage(circImg, 0, 0); // draw}
svg<br><svg id="circSvg" width="100" height="100">   <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />   Sorry, your browser does not support inline SVG.</svg> 
<br>canvas<br> <canvas id="can"></canvas>
<img id="circImg" style="display:none">


Related Topics



Leave a reply



Submit