I have a need to rotate an image in a web application. In an earlier post it was explained to me that on rotation I need to 'translate' the image because the center point changes.
I'm using the HeyGrady 2D transfrom JQuery plugin for rotating and provide it the translation as was suggested, which works fine on FF/Chrome/Safari/IE9. However, on IE8 this does not work well.
Please have a look at the following link.
If you run this on FF/Chrome/Safari/IE9 the image rotates just fine (stays within the black border). However, if you run this on IE8 it will cross the black border boundary when rotating to 90 or 270 degrees.
The plugin project page mentions that "IE also lacks support for transform-origin and translate() [...] The jQuery Transform plug-in handles these calculations automatically". However, it does not seem to do so.
Anyone has any ideas what the problem may be?
Thanks!
I also ran into this same issue in IE 8 using HeyGrady's jQuery transform plugin. Here's a fix by adding this to the execMatrix function, around line 290:
Replace this line:
this.fixPosition(matrix, tx, ty);
With this:
// factor in the object's current rotation so translation remains straight up/down/left/right
// otherwise, object will be translated along the rotated axis, which produces undesirable effects
var rotation = parseInt(this.$elem.css('rotate')) * -1, // the current rotation in degrees, inverted
radians = rotation * (Math.PI / 180), // convert degrees to radians
newX = (tx * (Math.cos(radians))) - (ty * (Math.sin(radians))), // calculate new x
newY = (tx * (Math.sin(radians))) + (ty * (Math.cos(radians))); // calculate new y
this.fixPosition(matrix, newX, newY);
Related
I'm trying to scale and then rotate a triangle and then translate it to a given point in Snap SVG.
I want to rotate the triangle around the top of it not the center, so i can build something like a pie.
So I thought I scale first, then rotate and later translate.
var t = new Snap.Matrix();
t.scale(0.5);
t.rotate(45, bbox.cx, (bbox.cy-(bbox.h/2)));
But the scale and rotation somehow are allways a bit off.
I reused a jsfiddle I found and updated it, so you can see what I try:
http://jsfiddle.net/AGq9X/477/
Somehow the bbox.cx and bbox.cy are not in the center of the triangle.
On my local setup they are.
The strange thing is, just rotation without scaleing works fine,
but scaling and then roation always seems to be a bit off on the y axis, the triangle doesn't stays at the rotation point.
Any ideas how i can fix that?
EDIT:
Ok I found the Solution,thanks to lan, you were right, the center of scaleing is important, and
I thought it was useing the center of the object, but it was the upper left corner. I adjusted it
and now it works greate:
var bbox = obj.getBBox(); //get coords etc. of triangle object
var t = new Snap.Matrix();
var offset = (bbox.cy+(bbox.h)) - centerY; //translate Y to center,
//depends on scaleing factor (0.5 = bbox.h, 0.25 = bbox.h*2)
t.scale(0.5, 0.5, bbox.cx, (bbox.cy+(bbox.h/2))); //scale object
t.translate(0,-offset); //translate to center
t.rotate(45, bbox.cx, (bbox.cy+(bbox.h/2))); //rotate object
obj.transform(t); //apply transformation to object
EDIT2:
I wanted to know how to save transformation, so you don't need to apply them every time you use a new transformation. Ian recommended to use element.transform() like so to get the old transformations:
element.transform( element.transform() + 's2,2' )
This is slightly more complicated than one would expect, but you would be animating a matrix, which does some odd things sometimes.
Personally I would use Snaps alternate animate method Snap.animate() and not using a matrix. Set the scale first and then build your animation string.
Something like..
var triangle2 = p.select("#myShape2").transform('s0.5');
...
Snap.animate(0,90,function( val ) {
triangle2.transform('r'+ val + ',' + bbox.cx+','+(bbox.cy-(bbox.h/2))+'s0.5')
}, 2000)
jsfiddle
I'm experimenting with three.js and the deviceorientation event. I'm rotating a cube with my phone's accelerometer, using the technique used in the THREE.DeviceOrientationState plugin. Basically the coordinates from the deviceorientation event angles are converted to radians and applied to a meshes' rotation coordinates (mesh.rotation.x, etc). Pretty basic.
This technique works fine as long as the phone is not rotated more than 90 degrees, but once it hits 90 degrees the rotation get messed up and the cube basically "flips". Not sure how else to describe it. Also, rotation works perfectly when rotating on only one axis, but as soon as two or more axis are involved and the phone is rotated more than 90 degrees we have problems.
Basically I need to know how to combine more than one rotation angle so that the cube rotates with the phone no matter how much the phone is rotated. The cube should always mimic the rotation of the phone. (I know, it's a bit weird to do that since you can't see the phone screen when it has been rotated so much, but bear with me, I have a plan.)
I thought maybe I was hitting gimbal lock, so tried using quaternions, but I get the same results. To be honest, I'm a little embarrassed to be asking this question. It has been a while since I did any 3D programming, but I feel like I should know how to do this.
Here's some example code. What else do I need to do to combine the rotation angles?
$(window).on('deviceorientation', function(e) {
var x = (!e.originalEvent.beta ? 0 : e.originalEvent.beta) * Math.PI / 180;
var y = (!e.originalEvent.gamma ? 0 : e.originalEvent.gamma) * Math.PI / 180;
var z = (!e.originalEvent.alpha ? 0 : (e.originalEvent.alpha - 180)) * Math.PI / 180;
cube.rotation.x = x;
cube.rotation.y = y;
cube.rotation.z = z;
});
UPDATE: Here is a jsfiddle that illustrates the issue. It has been modified to use the DeviceOrientationControls feature, which is now included in three.js. You'll see that the problem persists. Basically I need the cube to mimic the orientation of the phone exactly, no matter how much I turn the phone.
UPDATE 2: I changed the shape in the above jsfiddle from a cube to a 3d rectangle that is in the shape of a phone. I think it's easier to see what's happening with a rectangle than a cube.
I'm trying to make the so called fine tune thing. Basically this looks like: http://jsfiddle.net/r9KQK/1/
Later I'll have some audio player and this thing will help to select seconds when we use it on a tablet.
The problem is when you try to move the red circle it strangely drops when it passes top and bottom of the green circle, but not at 0 or PI/2, something like at -260..-269 and 181..190 degrees
Just try to move it and you'll see the bug.
What's wrong in my code?
Thanks in advance
update
Last update: http://jsfiddle.net/r9KQK/17/
In this example I get degrees in 0..360 range. But instead I should get delta degrees between the point where I start dragging and where I end it, but I can't work out the maths. I should also take into account the direction of red circle, so that delta will be + or - =\
update
Finally: http://jsfiddle.net/r9KQK/18/
But the code is really awful. Though it's 2:46 AM and I'm kind of sleepy, so...
But anyway I think it could be much more simplified
That's happening because your parameter to Math.atan goes to infinity when DeltaX is zero. I recommend using atan2, which automatically handles this corner case:
function(dx, dy, x, y)
{
var deltaY = this.oy + dy - fineTuning.ring.attr('cy');
var deltaX = this.ox + dx - fineTuning.ring.attr('cx');
var angle = Math.atan2( deltaY, deltaX );
// etcetera, etcetera
Or check the fiddle.
I'm trying to use brownian motion to create a group of random moving particles.
http://jsfiddle.net/J75Em/16/
So far I've got the particles moving randomly but I'm not sure how to set the forward direction to make it look more natural.
I've tried to use the change in x and y axis to calculate rotation using atan, you can see this by uncommenting rotate but this doesn't seem to perform well.
Is this the right approach for this type of movement? thanks;
This is pretty neat!
You are sort of going about it the right way but you should actually use the atan2 function. This removes the need for any 0 checks.
The atan2 function gives you an angle which is anticlockwise from the positive x vector
(1, 0) --->
The bees are 90 degrees off from this starting angle so you must subtract 90 degrees from the direction. (depending on which way round you do the dy and dx calculation, you might need to add)
You could find that the direction changes rapidly, so you could consider limiting the next change to a set of changes that cause an angle change below some threshold. This will make the movement a little smoother.
I would actually go about it by generating an angle between say -pi/8 and pi/8 radians, and a random length. Essentially using polar coordinates. Then add this new random polar offset to the x and y position like
newX = currentX + (randomLength * cos(randomAngle + currentAngle)) and
newY = currentY + (randomLength * sin(randomAngle + currentAngle))
If you work with angles you can also get more natural effects like if you want the bees to stay within a certain area, you can force a bias towards the center of the area as they get closer and closer to the edge.
Update:
So I've taken a closer look. The trouble is that you expect .rotate to set the rotation when it actually adds to the rotation
There are 2 options for fixing this.
Rotate by the difference between the previous and the current angle
Set the rotation using the .transform method
You can see solution 2 in action here http://jsfiddle.net/c5A2A/
For example it may be used in the application of manually adjusting the hands of the clock. I guess it probably involves translating the needle (to make the end point of the needle the centre of rotation) then rotating it, then translating the needle again.
But since the needle listens to the mouse event all the time, the 1st mouse event will be captured. The result is that the needle ends up being translated and not rotated at all. Mouse event is impossible to debug too...
Any idea or code snippets that I can refer to? Using Javascript or CSS to rotate both fine.
In your example, you will want to calculate the angle between the centre of the clock face (black dot), and the current mouse position (red dot), relative to the Y axis (cardinal north if you imagine a compass).
If I remember my trig correctly, you can calculate this by using the following:
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
// alter the angle to be relative to Y axis instead of X
angle += 90;
if(angle < 0) { angle = 360 + angle; }
In the formula, x and y are the coordinates of the two points, one of which you will know (it is the centre of the clock face), and the other you can get from the mouse move event.
Once you have the angle, you can simply translate to the the centre of the circle, rotate the canvas by the calculated amount, and draw the hand.
Update: I created a jsfiddle to illustrate the angle calculation:
http://jsfiddle.net/DAEpy/1/