SOS

Shane O'Sullivan's technical blog… really ties the room together

Archive for the ‘svg’ Category

dojox.gfx: Rotating in an elliptical line

Posted by Shane O'Sullivan on December 7, 2008

This post describes how to get a shape to rotate a central point following an elliptical path, using the Dojo Ajax Toolkits cross browser graphics engine, dojox.gfx. To see it in action, go to http://www.skynet.ie/~sos/misc/EllipseAnim.html

dojox.gfx is built in much the same way as SVG, with most of the same capabilities.  When it comes to moving shapes around a surface, it provides useful translations that move objects in straight lines, circles and more.

You can also combine different transformation matrices together to create more complex animations.  However, this is difficult in the extreme unless you have an really (and I mean REALLY) good grasp of matrix transformations and Cartesian coordinate manipulation.  Which I don’t.  And it is unlikely that you, the good reader, do either (if you do, I heartily apologise).

Anyhow, I had the requirement to rotate a small circle in an elliptical shape around a central point.  After much hacking, I gave in and asked Eugene, the dojox.gfx author, and one of the guys who DOES understand all this matrix stuff, and he solved it.

The trick is use two transformations simultaneously:

  • The first transformation rotates the shape around a point by 180 degrees.  This is not the central point of the ellipse.  For simplicitys sake, I start the animation with the shape at the leftmost point of the ellipse, level with the ellipse central Y point.  The point around which the shape should rotate has an X position equal to the central point of the shape plus the Y radius of the ellipse, and a Y point equal to the centre Y of the ellipse.
  • The second transformation moves the shape from left to right in a straight line.  This starts from the origin of the shape, and ends just short of the right hand median point of the ellipse.  The distance between the end of the lateral linear transformation and the rightmost point of the ellipse is twice the radius of the circle used for the rotation translation.  The reason for this is that the rotation transformation will, by the end of the linear transformation, have moved the shape twice the radius of the rotation circle in the X direction, so this must be subtracted from the lateral linear transformation.

The code I used for this is shown below.  Feel free to take it and play around.

<html>
<head>
<style type="text/css">
@import "../dojo/resources/dojo.css";
@import "../dijit/tests/css/dijitTests.css";
</style>
<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.2.0/dojo/dojo.xd.js"
djConfig="isDebug: true"></script>

<script type="text/javascript">
dojo.require("dojox.gfx");
dojo.require("dojox.gfx.fx");
dojo.require("dojo.fx");
dojo.require("dojox.gfx.matrix");
dojo.require("dojo.fx.easing");

var circle, surface, cx = 50, cy = 200, rx = 40, ry = 20;
var ellipse;

dojo.addOnLoad(function(){

var domNode = dojo.byId("test");
// Create the surface, this contains all the graphics objects
surface = dojox.gfx.createSurface(domNode, 400, 400);

// Create the circle shape to be moved in a elliptical line
circle = surface.createEllipse({cx: 10, cy: cy, rx: 5, ry:5});
circle.setFill("blue");

// Create an elliptical line, just to show you the path it will take
ellipse = surface.createEllipse({cx: cx, cy: cy, rx: rx, ry: ry});
ellipse.setStroke("black");
});
// Define a function to create an animation.
//'isLTR' means 'Is Left To Right'

function getAnim(isLTR) {

var g = dojox.gfx, m = g.matrix;
var startAngle = isLTR ? 0 : 180;
var endAngle = isLTR ? 180: 360;
var startX = isLTR ? 0 : rx;
var endX = isLTR ? rx: 0;

return g.fx.animateTransform({
shape: circle,
duration: 1000,
transform: [
// The first transform just moves the shape either from
// left to right, or right to left

{name: "translate",
start: [startX, 0], end: [endX, 0]},
// The second transform rotates the shape in a circular
// path

{ name: "rotateAt",
start: [m._degToRad(startAngle), cx - ry, cy],
end: [m._degToRad(endAngle), cx - ry, cy]}
],
onEnd: function(){
// When the animation to make the circle go
// half way around the ellipse finishes,
// start it again in the opposite direction

getAnim(!isLTR).play();
},
easing: dojo.fx.easing.linear
});
}

function animate() {
var anim1 = getAnim(true);
anim1.play();
}

</script>
</head>
<body>
<button onclick="animate()">Animate!</button><br/>
<div id="test" style="border:1px solid black;margin-top:10px;"></div>

</body>
</html>

Posted in Ajax, Dojo, dojox, dojox.gfx, Javascript, open source, svg, Technical | 2 Comments »

Musings on Browser based graphics with dojox.gfx

Posted by Shane O'Sullivan on November 24, 2008

I’m messing around with dojox.gfx at the moment, the Dojo Ajax Toolkit‘s very cool but difficult to use cross browser graphics package. I’m finding out, slowly, its little quirks, annoyances and more.  As I do I will be posting short blog posts so as to both document them for my own sake, and for the enlightenment of you, the good reader.

FYI: The official docs are here – http://docs.dojocampus.org/dojox/gfx

#1 – Adding mouseenter and mouseleave events

When drawing a shape, if it does not have a fill color it is considered to be one dimensional, that is, just a line.  Therefore if you want know when the mouse enters and leaves the shape using code such as:
shape.connect("mouseenter", function() { console.log("entry");});
shape.connect("mouseleave", function() { console.log("exit");});

moving the mouse into the shape (e.g. a rectangle or circle) will fire both event almost simultaneously.  To prevent this, you have to set a fill on the object, using the setFill function, and it will then be treated a two dimensional and the mouse events will work as you would expect with HTML DOM elements.

#2 – Which shape is in front of which is decided by the order they are added to the graphics surface

Graphics work differently to HTML and do not have a z-index property to determine which is displayed in front of which.  However a simple function is available on each shape that will bring it to the front, called strangely enough, moveToFront(), e.g.
var surface = dojox.gfx.createSurface(someDomNode, 100, 100);
var text = surface.createText({x: 10, y: 20, text:"Hello World!!"});
var rect = surface.createRect({x: 1, y: 1, width: 50, height: 50});
rect.setFill("white");
// At this point the text is not visible as the rectangle is in front of it.
text.moveToFront();
// The text is now in front of the rectangle and looks to be surrounded by it

#3 – A mouseenter event on one element causes a mouseleave on the previous element

In the previous example, we had a rectangle surrounding some text.  If we wanted to do something to the rectangle when the mouse entered it, and when it left, such as change the fill color,  the text would mess this up.  This is because when the mouse moves over the text, a mouseleave event would fire for the rectangle, even though the mouse is still inside it.  To fix this, I used a simple delay on executing the code for the mouseleave event, and cancelled it if the mouse entered the text e.g.
var timer;
rect.connect("mouseenter", function(){rect.setFill('blue');});
rect.connect("mouseleave", function() {
timer = setTimeout(function(){rect.setFill('white');}, 50)
});
text.connect("mouseenter", function(){
if (timer) {
clearTimeout(timer);
timer = null;
}
});

Posted in Ajax, Dojo, dojox, dojox.gfx, svg, Technical, vml | 2 Comments »

 
Follow

Get every new post delivered to your Inbox.

Join 533 other followers

%d bloggers like this: