Thursday, July 15, 2010

Inkscape SVG Not Quite in Raphaël.js

‹prev | My Chain | next›

I am going to take a break from backend coding in my (fab) game to play a bit more with raphaël.js. Specifically, I would like to investigate getting SVG images pulled into my (fab) game by way of raphaël.js.

Unfortunately, that seems to be one of those things that folks roll their own. Since there does not appear to be an official or even generally accepted way to do this, I will spend a bit of time exploring first.

First up, I save my sandbox in /tmp/raphael_svg.html:
<html>
<head>
<title>Raphael / SVG Play</title>
<script src="http://github.com/DmitryBaranovskiy/raphael/blob/master/raphael-min.js?raw=true"></script>
</head>

<body>
<div id="container"></div>
</body>
<script type="application/javascript">
var paper = Raphael("container", 500, 500);
// Play code will go here
</script>
</html>
This will allow me to access the code at file:///tmp/raphael_svg.html.

To play with SVG, I need a tool that generates it. Since I run Ubuntu, that makes my first stop Inkscape. For now, I keep it simple. I make a SVG game player as a circle (with a 3 pixel border), two lines for legs, and two more circles for feet:



I place the legs and the feet in a separate layer so that I can animate between standing and walking:



Now SVG is XML, so I am pretty sure that the generated file is going to be pretty freaking huge. So big that I doubt that I will be able to figure out which element is which. So I use the Inkscape properties dialog to label the elements as circle, ll_standing (left leg), rl_standing, ll_standing, rl_standing, etc.:



As expected, that generates a lot of SVG. Among the wreckage is:
    <path
sodipodi:type="arc"
style="fill:#ff0000;fill-rule:evenodd;stroke:#5c5c5c;stroke-width:14.77256393;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="circle"
sodipodi:cx="142.85715"
sodipodi:cy="295.21933"
sodipodi:rx="48.57143"
sodipodi:ry="48.57143"
d="m 191.42858,295.21933 a 48.57143,48.57143 0 1 1 -97.142863,0 48.57143,48.57143 0 1 1 97.142863,0 z"
transform="matrix(0.20023794,0,0,0.20596072,74.052829,274.15504)">
<title
id="title3746">Player Circle</title>
</path>
The path, the d attribute, can be passed directly directly into a Raphael.path() call. The attributes in the style attribute cannot, however, be passed to Raphael.attr(), which takes a Javascript object. To handle that, I write an svg_object function:
function svg_object(str) {
var attrs = {};
str.split(/;/).
forEach(function(pair) {
var kv = pair.split(/:/);
attrs[kv[0]] = kv[1];
});
return attrs;
}
With that I can use the two SVG attributes to draw my player circle:
var paper = Raphael("container", 500, 500);

var style="fill:#ff0000;fill-rule:evenodd;stroke:#5c5c5c;stroke-width:14.77256393;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none";
var d="m 191.42858,295.21933 a 48.57143,48.57143 0 1 1 -97.142863,0 48.57143,48.57143 0 1 1 97.142863,0 z";

paper.
path(d).
attr(svg_object(style));
And it works!



If I convert d and style variables into attributes on an object, then I write a draw function:
function draw_object(obj) {
paper.
path(obj.d).
attr(svg_object(obj.style));
}
With that, I can draw all parts of my player:
var circle = { ... }
draw_object(circle);

var rf_standing = { ... }
draw_object(rf_standing);

var lf_standing = { ... };
draw_object(lf_standing);

var rl_standing = { ... };
draw_object(rl_standing);

var ll_standing = { ... };
draw_object(ll_standing);
Unfortunately, the drawing ends up looking like this:



Ugh. That will have to suffice as a stopping point for tonight. I have a feeling that the transform attribute on some of the elements has something to do with the improper display:
...
transform="matrix(0.20023794,0,0,0.20596072,74.052829,274.15504)"
...
I will investigate tomorrow.


Day #165

No comments:

Post a Comment