Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Translating SVG elements for an Isometric view

I'm working on some JavaScript code to render standard 2D SVG/Canvas elements (drawn with Raphael-JS) in an isometric 3Dish view.

Say we have two rectangles drawn next to each other. I then have them redrawn at the correct angles (basically a 30 degree twist) for an isometric view.

alt text

(In the image above I've shown the origin for two corresponding elements.)

My problem is I don't know how to properly translate all the individual elements so they "tile" correctly instead of just overlapping.

While actually using tiles would make things easier as I could just base any given tile's placement on the one before it, tiles won't work in this case. Everything is dynamic and will be more complex than simple x/y planes.

Here is an image of some isometric tiles if there's any confusions as to how I want these objects to be placed.

like image 478
Chris Cummings Avatar asked Jan 23 '11 07:01

Chris Cummings


2 Answers

You shouldn't apply the transformation to the individual elements, but to the source elements as a collection. In Raphael, you could use something like

var s = paper.set();
s.push(square1, square2);

and now do the transformations without too much math, which is supposed to work like this:

// s.clone(); // if you want to keep originals
s.rotate(45, 0, 0).scale(1, .7).translate(100, 0);

(However, scaling of rotated items seems to be broken in RaphaelJS.)

Plain SVG example:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
    viewBox="-200,-500 1000,1000">
    <title>Isometric</title>
       <g id="source"> <!-- group -->
           <circle cx="-50" cy="-50" r="50"/>
           <rect width="100" height="100"/>
           <rect width="100" height="100" x="101"/>
           <rect width="100" height="100" x="50" y="-200"/>
       </g>
       <!-- make copy of group and apply transformations -->
       <use xlink:href="#source" transform="translate(500) scale(1, .7) rotate(-45)"/>
</svg>
like image 165
user123444555621 Avatar answered Oct 13 '22 00:10

user123444555621


Using Raphel.js 2.0 you can do this using the .transform() method and providing a transform string that rotates 45 degrees and scales vertically 70% (or whatever pitch you want). It's important to pay attention to the position you are rotating and scaling around as well - in this case I'm using 0,0. You will also notice I'm translating 100 over to the right to compensate for the rotation.

Transform strings are also great for this use case because you can simply prepend the projection transformation to the transformation of other objects in the scene and they will all end up in the right place.

For example (see http://jsfiddle.net/k22yG/):

var paper = Raphael(10, 10, 320, 240),
    set = paper.set();

// Build a set to make it easier to transform them all at once
set.push(
    // Grid of rectangles
    paper.rect(0, 0, 50, 50),
    paper.rect(60, 0, 50, 50),
    paper.rect(0, 60, 50, 50),
    paper.rect(60, 60, 50, 50)
);

// Rotate, then scale, then move (describe in "reverse" order)
set.transform('t100,0s1,0.7,0,0r45,0,0');​
like image 24
Trevor Parscal Avatar answered Oct 12 '22 22:10

Trevor Parscal