Skip to content

Instantly share code, notes, and snippets.

@DanElliottPalmer
Created July 28, 2013 13:03
Show Gist options
  • Save DanElliottPalmer/6098505 to your computer and use it in GitHub Desktop.
Save DanElliottPalmer/6098505 to your computer and use it in GitHub Desktop.
Trying to whip up an SVG path to canvas renderer. This version is fully tested and there are probably performance issues but it kind of works? JS bin example: http://jsbin.com/awepam/1/edit
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class=""> <!--<![endif]-->
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="robots" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
html,body {
height: 100%;
margin: 0;
overflow: hidden;
width: 100%;
}
</style>
</head>
<body>
<canvas id="domCanvas"></canvas>
<script type="text/javascript">
(function(){
function CanvasPath(path){
this._ = {
"lastCurveX": null,
"lastCurveY": null,
"lastPath": "",
"x": 0,
"y": 0
};
this.points;
this.pathString = "";
if(arguments.length){
this.parse(path);
}
}
CanvasPath.prototype = {};
CanvasPath.prototype.parse = function(path){
var rePath = /[m|l|h|v|c|s|q|t|a|z](?:[\-]?[\d\.]+[,\s]?)*/gi,
rePathValues = /([\-]?[\d\.]+)/g,
pathArray = [],
counter = 0;
this.pathString = path;
this.points = new Array( path.match( rePath ).length );
while( ( pathArray = rePath.exec(path) ) !== null ){
var currentPath = pathArray[0],
pathType = currentPath.substr(0,1),
pathTypeUpper = pathType.toUpperCase(),
pathData = currentPath.substr(1);
var pathValues = pathData.match( rePathValues ) || [];
var isAbsolute = false;
if( pathType === pathTypeUpper ){
isAbsolute = true;
}
pathValues.push( isAbsolute );
this.points[ counter ] = this.PATH[ pathTypeUpper ].apply( this, pathValues );
this._.lastPath = pathTypeUpper;
counter++;
}
};
CanvasPath.prototype.render = function(ctx){
console.log(this.points);
var i = -1,
len = this.points.length-1;
ctx.fillStyle = "#f00";
ctx.beginPath();
while( i++ < len ) {
this.points[i](ctx);
}
// ctx.fill();
ctx.stroke();
};
//Path parse functions
CanvasPath.prototype.PATH = {
"A": function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y, absolute){},
"C": function(x1, y1, x2, y2, x, y, absolute){
x1 = +x1;
y1 = +y1;
x2 = +x2;
y2 = +y2;
x = +x;
y = +y;
if(absolute){
this._.x = x;
this._.y = y;
} else {
//Update the control points
x1 += this._.x;
y1 += this._.y;
x2 += this._.x;
y2 += this._.y;
//Update the x and y
x = (this._.x += x);
y = (this._.y += y);
}
//Keep track of the last bezier point in case we have an S next
this._.lastCurveX = x2;
this._.lastCurveY = y2;
return function(ctx){
// console.log("C - bezier curve to " + x + "," + y);
ctx.bezierCurveTo(x1, y1, x2, y2, x, y);
};
},
"H": function(x, absolute){
if(absolute){
this.x = +x;
} else {
x = (this.x += +x);
}
var y = this._.y;
return function(ctx){
ctx.lineTo(x, y);
};
},
"L": function(x, y, absolute){
x = +x;
y = +y;
if(absolute){
this._.x = x;
this._.y = y;
} else {
x = (this._.x += x);
y = (this._.y += y);
}
return function(ctx){
// console.log("Line to " + x + "," + y);
ctx.lineTo(x, y);
};
},
"M": function(x, y, absolute){
x = +x;
y = +y;
if(absolute){
this._.x = x;
this._.y = y;
} else {
x = (this._.x += x);
y = (this._.y += y);
}
return function(ctx){
// console.log("Moving to " + x + "," + y);
ctx.moveTo(x, y);
};
},
"Q": function(x1, y1, x, y, absolute){
x1 = +x1;
y1 = +y1;
x = +x;
y = +y;
if(absolute){
this._.x = x;
this._.y = y;
} else {
//Update the control point
x1 += this._.x;
y1 += this._.y;
//Update x and y
x = (this._.x += x);
y = (this._.y += y);
}
//Update last curve in case next point is T
this._.lastCurveX = x1;
this._.lastCurveY = y1;
return function(ctx){
ctx.quadraticCurveTo(x1, y1, x, y);
};
},
"S": function(x2, y2, x, y, absolute){
x2 = +x2;
y2 = +y2;
x = +x;
y = +y;
//Check if the last point as a C or S
if( this._.lastPath!=="C" && this._.lastPath!=="S" ){
this._.lastCurveX = x2;
this._.lastCurveY = y2;
}
//Work out x1, y1
//It should be a mirror of the last bezier point
var distX = (this._.lastCurveX - this._.x) * -1,
distY = (this._.lastCurveY - this._.y) * -1;
var x1 = this._.x + distX,
y1 = this._.y + distY;
if(absolute){
this._.x = x;
this._.y = y;
} else {
x2 += this._.x;
y2 += this._.y;
x = (this._.x += x);
y = (this._.y += y);
}
//In case the next point is another S
this._.lastCurveX = x2;
this._.lastCurveY = y2;
return function(ctx){
// console.log("S - bezier curve to " + x + "," + y);
ctx.bezierCurveTo(x1, y1, x2, y2, x, y);
};
},
"T": function(x, y, absolute){
x = +x;
y = +y;
//Check if last point was a Q or T
if( this._.lastPath!=="Q" && this._.lastPath!=="T" ){
this._.lastCurveX = x;
this._.lastCurveY = y;
}
//Reflection - see S
var distX = (this._.lastCurveX - this._.x) * -1,
distY = (this._.lastCurveY - this._.y) * -1;
var x1 = this._.x + distX,
y1 = this._.y + distY;
if(absolute){
this._.x = x;
this._.y = y;
} else {
x1 += this._.x;
y1 += this._.y;
x = (this._.x += x);
y = (this._.y += y);
}
//In case next point is another T
this._.lastCurveX = x1;
this._.lastCurveY = y1;
return function(ctx){
ctx.quadraticCurveTo(x1, y1, x, y);
};
},
"V": function(y, absolute){
if(absolute){
this.y = +y;
} else {
y = (this.y += +y);
}
var x = this._.x;
return function(ctx){
ctx.lineTo(x, y);
};
},
"Z": function(){
return function(ctx){
ctx.closePath();
};
}
};
window.CanvasPath = CanvasPath;
})();
</script>
<script type="text/javascript">
/**
* Testing paths using the Tiger SVG: http://blackicemedia.com/presentations/2013-02-hires/img/awesome_tiger.svg
*/
var domCanvas = document.getElementById("domCanvas"),
ctx = domCanvas.getContext("2d");
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
domCanvas.width = WIDTH;
domCanvas.height = HEIGHT;
var p = new CanvasPath();
p.parse("M95.668,436.985c0.888,10.678,2.632,22.275,5.703,27.783c0,0-6.356,21.895,9.181,45.2c0,0-0.707,12.712,2.119,18.362c0,0,7.063,14.832,15.538,16.244c6.858,1.143,22.26,6.561,39.67,9.04c0,0,30.249,24.859,24.599,47.461c0,0-0.706,28.956-7.063,31.781c0,0,20.481-19.775,3.531,9.888l-7.769,33.192c0,0,45.201-38.138,17.657-5.648l-17.657,45.906c0,0,34.607-32.487,21.894-17.656l-5.65,15.538c0,0,76.276-48.025,21.894,4.237c0,0,14.125-6.356,21.894-1.412c0,0,12.006-2.119,10.594,0.706c0,0-36.726,18.361-43.082,50.851c0,0,14.831-17.657,9.181,1.412l0.706,20.48c0,0,7.063-38.138,6.356,28.25c0,0,33.9-31.78,13.419,4.944v29.662c0,0,26.838-28.956,15.538-6.354c0,0,17.656-15.538,10.594,11.3c0,0-1.413,18.361,6.356-1.412c0,0,28.25-54.029,17.656-7.771c0,0-1.412,33.9,7.063,7.771c0,0,0.706,18.362,16.95,31.075c0,0-2.119-89.695,20.48-26.133l7.063,28.957c0,0,4.943-16.244,4.237-25.426c0,0,26.132-28.957,14.125,14.125c0,0,26.838-40.257,21.188-16.95c0,0-13.419,28.251-10.594,36.727c0,0,29.663-61.444,31.782-64.271c0,0-3.531,74.865,15.537,11.3c0,0,9.888,21.188,4.943,28.957c0,0,14.125-14.125,12.712-19.774c0,0,8.122-14.479,13.066,9.534c0,0,3.178,16.598,6.003,10.946c0,0,7.063,42.377,9.182,2.119c0,0,2.825-24.013-9.888-44.494c0,0,1.412-5.649-3.531-12.713c0,0,24.014,38.139,11.3-12.713c0,0,19.777,14.125,21.896,14.125c0,0-24.015-40.963-8.477-32.487c0,0-9.183-18.362,22.602,2.825c0,0-28.252-28.251,2.825-11.301c0,0,14.125,11.301,0.706-6.356c0,0-25.428-28.25,13.419,3.532c0,0,20.48,28.956,21.895,33.9c0,0-17.655-51.559-25.426-56.501c0,0,14.832-64.271,87.576-36.727c0,0,12.007,30.369,19.774-2.118c0,0,22.602-11.301,42.375,37.432c0,0,7.063-24.013,5.65-28.956c0,0,12.007,2.119,10.594,0c0,0,23.308,7.769,25.427,6.356c0,0,12.006,12.006,12.712,5.648c0,0,16.244,4.944,12.713-1.412c0,0,15.538,27.544,16.244,33.9l4.236-24.719l3.531,4.942c0,0,2.825-13.419,1.413-15.537c-1.413-2.119,35.313,12.006,43.787,48.731l3.531,14.831c0,0,10.594-26.131,7.77-33.193c0,0,9.181,1.412,9.888,9.181c0,0,7.063-40.963-1.412-51.557c0,0,7.769-1.412,9.888,4.944V714.78c0,0,12.713,1.411,12.713-2.825c0,0,7.769-7.063,11.3,1.412c0,0-21.894-62.15,10.594-28.25c0,0,12.714,19.068,6.356-14.125c-6.357-33.194-13.419-36.021-4.943-36.727c0,0,1.412-6.355-2.118-9.181c-3.531-2.825,2.118,0,2.118,0s8.476,7.063-0.707-31.782c0,0,11.302,2.825-9.888-48.73c0,0,4.944-4.237-2.118-19.069c0,0,14.125,7.77,19.069,4.944c0,0-0.707-2.825-6.356-9.889c0,0-38.139-96.759-2.118-57.913c0,0,20.923,23.925,9.623-16.332c0,0-16.088-42.394-14.716-49.979L95.668,436.985z");
// p.parse("M100,100l100,0L200,200l-100,0z");
// p.parse("M100,200 C100,100 250,100 250,200 S400,300 400,200");
// p.parse("M200,300 Q400,50 600,300 T1000,300");
p.render(ctx);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment