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:
- use XMLHttpRequest() to load the SVG as an XML document
- manipulate that XML document
- convert the XML document to a string
- create an ObjectURL from that string
- create an Image with that ObjectURL
- 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:
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';
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
How to Wrap Text Around a Bottom-Right Div
How to Get This CSS Text-Decoration Override to Work
Does Opacity:0 Have Exactly the Same Effect as Visibility:Hidden
How to Use Colspan and Rowspan in HTML Tables
Inputting a Default Image in Case the Src Attribute of an HTML ≪Img≫ Is Not Valid
How to Escape Hash Character in Url
How to Set Tbody Height With Overflow Scroll
Equal Height Children of Flex Items
Should I Use ≪I≫ Tag For Icons Instead of ≪Span≫
An Invalid Form Control With Name='' Is Not Focusable
How to Use the "Required" Attribute With a "Radio" Input Field
Base64 Encoded Images in Email Signatures
Force to Open "Save As..." Popup Open At Text Link Click For Pdf in Html