Scalable Vector Graphics (SVG) is a family of specifications of an XML-based file format for describing two-dimensional vector graphics. It’s been around for a while, and is a central component of common web technologies such as Flash.
The HTML5 Canvas is a relatively new component of the HTML specification, which allows you to use javascript to draw images inside a div. You can learn more about the canvas tag and the necessary javascript here.
But imagine you have an image defined as SVG, but you want to use it as part of your HTML canvas. Can you convert one to the other? Here’s a starting point.
First, I’ve set up a basic page with a HTML5 canvas:
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<style type="text/css">
body { background-color:#ccc; text-align:center; }
#canvas { background-color:red; padding: 60px 100px 40px 100px; }
</style>
<script type="application/javascript">
function draw() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "#000000";
ctx.lineWidth = 2;
<?php require "process.php"; ?>
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="299" height="268"></canvas><br />
</body>
</html>
Let’s assume that we have a fairly normal SVG file, which contains various path nodes. I’m just considering M (moveTo), L (lineTo) and C(curveTo) commands for the time being, but in theory this method could be expanded to include other path commands, and even the entire SVG format.
All we need to do now is extract the relevant information, and reconstruct the various commands as <canvas> javascript calls. The file “process.php” does this for us (below).
Note that I’m converting the SVG object on the fly here, which could be useful. If you want a static version which will save on server load, it’s simple to render the javascript and save it. Then just include that file inside the draw() function.
<?php
$svg = simplexml_load_file("3-legs-of-man.svg");
foreach ($svg as $path) {
foreach ($path->attributes() as $key => $val) {
if ($key == "fill")
echo "n" . 'ctx.fillStyle = "' . $val . '";' . "n";
elseif ($key == "d") {
$bang = array_filter(preg_split ("/(M|C|L|Z)/", $val, -1, PREG_SPLIT_DELIM_CAPTURE), "shall_i_remove");
$j = 1;
foreach ($bang as $b) {
if ($b == "M")
$bang[$j+1] = "ctx.moveTo(" . str_replace(" ", ", ", trim($bang[$j+1])) . ");";
elseif ($b == "C")
$bang[$j+1] = "ctx.bezierCurveTo(" . str_replace(" ", ", ", trim($bang[$j+1])) . ");";
elseif ($b == "L")
$bang[$j+1] = "ctx.lineTo(" . str_replace(" ", ", ", trim($bang[$j+1])) . ");";
$j++;
}
$results = array_filter($bang, "shall_i_clean");
echo "ctx.beginPath();n";
foreach ($results as $r) {
echo $r . "n";
}
echo "ctx.stroke();nctx.fill();n";
}
}
}
function shall_i_remove($arr) {
return ($arr == "" || $arr == " " || $arr == "Z") ? false : true;
}
function shall_i_clean($arr) {
return ($arr == "C" || $arr == "L" || $arr == "M") ? false : true;
}
Adam, brilliant. Found the link to your work from stack overflow. Thanks very much for your contribution.