Using translate and rotate in CSS - javascript

I'm trying to make a div rotate and move along the Y axis. I got it to work individually but not in the same time. This is the code i use to rotate the div:
function rotate_horizon_bg(deg){
var rotate = "rotate(" + (deg) + "deg);";
var tr = new Array(
"transform:" + rotate,
"-moz-transform:" + rotate,
"-webkit-transform:" + rotate,
"-ms-transform:" + rotate,
"-o-transform:" + rotate
);
var horizon_bg = document.getElementById("horizon_bg");
horizon_bg.setAttribute("style", tr.join(";"));
}
This works perfectly to rotate the div. If I make a new function to transelateY. Only transelateY will work.
Any ideas on how I can get this to work
simultaneous?

Just combine the effects. Here's a literal example:
transform: rotate(-45deg) translate(-120px,-30px)
function rotate_horizon_bg(rotateDeg, x, y){
var horizon_bg = document.getElementById("horizon_bg");
horizon_bg.style.transform = "rotate(" + rotateDeg + "deg) translate(" + x + "px, " + y + "px)";
}
rotate_horizon_bg(-30, 3, 3);
<div id="horizon_bg">Translate Me!</div>

Related

javascript find same position in rotated element

I have a "base" reference rect (red)
Inside a rotated div (#map), I need a clone rect (yellow), it has to be same size and position of "base" rect, independent of its parent (#map) rotation.
This is where I am so far, any help would be welcoming.
http://codepen.io/christianpugliese/pen/oXKOda
var controls = { degrees: 0, rectX:125, rectY:55 };
var wBounds = document.getElementById("wrapper").getBoundingClientRect(),
mapBounds = document.getElementById("map").getBoundingClientRect(),
rectBounds = document.getElementById("rect").getBoundingClientRect();
var _x = ((mapBounds.width - wBounds.width) / 2) + $('#rect').position().left,
_y = ((mapBounds.height - wBounds.height) / 2) + $('#rect').position().top;
$('#rect').css({top: controls.rectY+'px', left:controls.rectX+'px'});
$('#mapRect').width(rectBounds.width);
$('#mapRect').height(rectBounds.height);
$('#mapRect').css({top: _y+'px',
left:_x+'px',
'transform': 'rotate('+ Math.round(-controls.degrees) +'deg)'});
$('#map').css('transform', 'rotate('+ Math.round(controls.degrees) +'deg)');
Since you're rotating the #mapRect an equal amount in the opposite direction you're getting rotation/orientation right but not the origin. The transform-origin would be the center of the #mapBounds, but relative to the #rect;
Fork of your pen: http://codepen.io/MisterCurtis/pen/vNBYZJ?editors=101
Since there is some rounding/subpixel positioning happening the yellow rect doesn't align pixel perfect.
function updateUI(){
var _x = ((mapBounds.width - wBounds.width) / 2) + $('#rect').position().left,
_y = ((mapBounds.height - wBounds.height) / 2) + $('#rect').position().top,
_ox = mapBounds.width/2 - _x, // origin x
_oy = mapBounds.height/2 - _y; // origin y
...
$('#mapRect').css({
'transform-origin': _ox + 'px ' + _oy + 'px', // now it rotates by the bounds
top: _y + 'px',
left: _x + 'px',
'transform': 'rotate(' + Math.round(-controls.degrees) + 'deg)'
});
}
Edit: Updated the pen. You'll have to ditch using Rectangle and instead use Polygon. This way you can use a plugin like https://github.com/ahmadnassri/google-maps-polygon-rotate to perform the rotation along the map center.

Get the pixel from coordinates

I have 2 coordinates x and y of a point. I want to calculate the angle between three points, say A,B,C.
Now for the B point I do not have a pixel which contains the 2 coordinates instead I have the pixel, how can I get a single pixel which I can use in my formula.
function find_angle(A,B,C) {
var AB = Math.sqrt(Math.pow(B.x-A.x,2)+ Math.pow(B.y-A.y,2));
var BC = Math.sqrt(Math.pow(B.x-C.x,2)+ Math.pow(B.y-C.y,2));
var AC = Math.sqrt(Math.pow(C.x-A.x,2)+ Math.pow(C.y-A.y,2));
var abc = (BC*BC)+ (AB*AB)-(AC*AC);
var x = abc/(2*BC*AB);
var Angle = FastInt((Math.acos(x) * 180/3.14159));
document.getElementById("Angle").value = Angle;
}
How to proceed with this.
A is changing every time I move the point and I have the updated coordinates as well but I am not able to get the whole pixel I can use in the formula to calculate the new angle.
If I understand what you are asking - you want to create a calculator for the angle formed between
3 dots (A, B middle, C).
Your function should work for the final calculation but you need to recall the function every time
a point has moved.
I created a nice fiddle to demonstrate how you can achieve it with : jQuery, jQuery-ui, html.
I used the draggable() plugin of the UI library to allow the user to manually drag the dots around
And I'm recalculating the angle while dragging.
Take a look: COOL DEMO JSFIDDLE
The CODE ( you will find all HTML & CSS in the demo):
$(function(){
//Def Position values:
var defA = { top:20, left:220 };
var defB = { top:75, left:20 };
var defC = { top:200, left:220 };
//Holds the degree symbol:
var degree_symbol = $('<div>').html('゜').text();
//Point draggable attachment.
$(".point").draggable({
containment: "parent",
drag: function() {
set_result(); //Recalculate
},
stop: function() {
set_result(); //Recalculate
}
});
//Default position:
reset_pos();
//Reset button click event:
$("#reset").click(function(){ reset_pos(); });
//Calculate position of points and updates:
function set_result() {
var A = get_middle("A");
var B = get_middle("B");
var C = get_middle("C");
angle = find_angle(A,B,C);
$("#angle").val(angle + degree_symbol);
connect_line("AB");
connect_line("CB");
}
//Angle calculate:
function find_angle(A,B,C) {
var AB = Math.sqrt(Math.pow(B.x-A.x,2)+ Math.pow(B.y-A.y,2));
var BC = Math.sqrt(Math.pow(B.x-C.x,2)+ Math.pow(B.y-C.y,2));
var AC = Math.sqrt(Math.pow(C.x-A.x,2)+ Math.pow(C.y-A.y,2));
radians = Math.acos((BC*BC+AB*AB-AC*AC)/(2*BC*AB)); //Radians
degree = radians * (180/Math.PI); //Degrees
return degree.toFixed(3);
}
//Default position:
function reset_pos() {
$("#A").css(defA);
$("#B").css(defB);
$("#C").css(defC);
set_result();
}
//Add lines and draw them:
function connect_line(points) {
var off1 = null;
var offB = get_middle("B");
var thickness = 4;
switch (points) {
case "AB": off1 = get_middle("A"); break;
case "CB": off1 = get_middle("C"); break;
}
var length = Math.sqrt(
((offB.x-off1.x) * (offB.x-off1.x)) +
((offB.y-off1.y) * (offB.y-off1.y))
);
var cx = ((off1.x + offB.x)/2) - (length/2);
var cy = ((off1.y + offB.y)/2) - (thickness/2);
var angle = Math.atan2((offB.y-off1.y),(offB.x-off1.x))*(180/Math.PI);
var htmlLine = "<div id='" + points + "' class='line' " +
"style='padding:0px; margin:0px; height:" + thickness + "px; " +
"line-height:1px; position:absolute; left:" + cx + "px; " +
"top:" + cy + "px; width:" + length + "px; " +
"-moz-transform:rotate(" + angle + "deg); " +
"-webkit-transform:rotate(" + angle + "deg); " +
"-o-transform:rotate(" + angle + "deg); " +
"-ms-transform:rotate(" + angle + "deg); " +
"transform:rotate(" + angle + "deg);' />";
$('#testBoard').find("#" + points).remove();
$('#testBoard').append(htmlLine);
}
//Get Position (center of the point):
function get_middle(el) {
var _x = Number($("#" + el).css("left").replace(/[^-\d\.]/g, ''));
var _y = Number($("#" + el).css("top").replace(/[^-\d\.]/g, ''));
var _w = $("#" + el).width();
var _h = $("#" + el).height();
return {
y: _y + (_h/2),
x: _x + (_w/2),
width: _w,
height: _h
};
}
});
This Code requires jQuery & jQuery-UI. Don't forget to include them if you test it locally.
Have fun!

Javascript to transform on both X and Y axis (CSS 3D)

I am using tween to rotate on both X and Y axis. But I cant seem to find the correct javascript to edit the css.
Target is a div, and with the following code, it only rotates the axis while ignoring the Y axis.
It uses Tween JS
function update() {
target.style.left = position.x + 'px';
target.style.top = position.y + 'px';
target.style.webkitTransform = 'rotateY(' + Math.floor(position.rotation) + 'deg)';
target.style.MozTransform = 'rotateY(' + Math.floor(position.rotation) + 'deg)';
target.style.webkitTransform = 'rotateX(' + Math.floor(position.rotation) + 'deg)';
target.style.MozTransform = 'rotateY(' + Math.floor(position.rotation) + 'deg)';
}
How do I tell javascript to rotate on both and not just one axis?
You separate arguments with spaces. For example:
target.style.webkitTransform = 'rotateX(' + Math.floor(rotationX) + 'deg) rotateY(' + Math.floor(rotationY) + 'deg)';
(If you change the same property twice, you'll only overwrite previous value.)

Strange behaviour of GestureEvent.rotation on iOS webkit

I am using javascript Gesture events to detect multitouch pan/scale/rotation applied to an element in a HTML document.
Visit this URL with an iPad:
http://www.merkwelt.com/people/stan/rotate_test/
You can touch the element with two finger and rotate it, but sometimes the rotation property goes go astray and my element flips around many full rotations.
Here is part of my code, I am really only taking the value directly from the event object:
...bind("gesturechange",function(e){
e.preventDefault();
curX = e.originalEvent.pageX - startX;
curY = e.originalEvent.pageY - startY;
node.style.webkitTransform = "rotate(" + (e.originalEvent.rotation) + "deg)" +
" scale(" + e.originalEvent.scale + ") translate3D(" + curX + "px, " + curY + "px, 0px)";
}...
What happens is that the value gets either 360 degrees added or subtracted, so I could monitor the value and react to sudden large changes, but this feels like a last resort.
Am I missing something obvious?
I found a solution.
In order to avoid sudden changes in the rotation that don't reflect real finger moves you need to test for that. I do that testing if the rotation changed more then 300 degrees in either direction, if it does then you need to add or subtract 360 depending on the direction. Not really intuitive, but it works.
Fixed page is here:
http://www.merkwelt.com/people/stan/rotate_test/index2.html
Here is the code
<script type="text/javascript">
var node;
var node_rotation=0;
var node_last_rotation=0;
$('.frame').bind("gesturestart",function(e){
e.preventDefault();
node=e.currentTarget;
startX=e.originalEvent.pageX;
startY=e.originalEvent.pageY;
node_rotation=e.originalEvent.rotation;
node_last_rotation=node_rotation;
}).bind("gesturechange",function(e){
e.preventDefault();
//whats the difference to the last given rotation?
var diff=(e.originalEvent.rotation-node_last_rotation)%360;
//test for the outliers and correct if needed
if( diff<-300)
{
diff+=360;
}
else if(diff>300)
{
diff-=360;
}
node_rotation+=diff;
node_last_rotation=e.originalEvent.rotation;
node.style.webkitTransform = "rotate(" + (node_rotation) + "deg)" +
" scale(" + (e.originalEvent.scale) +
") translate3D(" + (e.originalEvent.pageX - startX) + "px, " + (e.originalEvent.pageY - startY) + "px, 0px)";
}).bind("gestureend",function(e){
e.preventDefault();
});
</script>

jQuery Element Free Rotation. Correcting Transform Origin and Translate in IE

I'm developing a jQuery plugin to make a block-level element rotatable with mouse. Now it works as expected in non-IE browsers, but have a strange behavior while rotating in Internet Explorer.
Demo is hosted at testerski.antaranian.me here, rotation plugin script is
$.fn.roll = function(angle){
var $this = this,
ie = !jQuery.support.leadingWhitespace;
if (ie) {
var cosAngle = parseFloat(parseFloat(Math.cos(angle.rad())).toFixed(8)),
sinAngle = parseFloat(parseFloat(Math.sin(angle.rad())).toFixed(8)),
tx = 0, ty = 0,
matrixFilter = '(M11=' + cosAngle + ', '
+ 'M12=' + -sinAngle + ', '
+ 'M21=' + sinAngle + ', '
+ 'M22=' + cosAngle + ','
+ 'sizingMethod=\'auto expand\')',
filter = 'progid:DXImageTransform.Microsoft.Matrix' + matrixFilter,
css = {
'-ms-filter': filter,
'filter': filter
};
debug.log(filter);
var matrix = $M([
[cosAngle, -sinAngle, tx],
[sinAngle, cosAngle, ty],
[0, 0, 1]
]);
debug.log(matrix);
$this.transformOrigin(matrix);
$this.fixIeBoundaryBug(matrix);
} else {
var css = {
'-webkit-transform': 'rotate(' + angle + 'deg)',
'-moz-transform': 'rotate(' + angle + 'deg)',
'-o-transform': 'rotate(' + angle + 'deg)'
};
}
$this.css(css);
return this;
};
I googled and found these two pages related to this subject
Grady's guide and Zoltan's guide
As I get there are some accounting needed related to Linear Algebra, but it's hard for me so if anyone have more simple tutorial, or knows the direct solution, please let me know.
Any help would be appreciated,
Antaranian.
IE's Transform Filter, unfortunately, doesn't have a concept of "transform-origin". the 'auto expand' sizingMethod will make the transformed object take the minimum amount of space possible, and you need to change it's positioning.
In cssSandpaper, I put another <div> tag around the transformed object and adjusted it's margin-left and margin-top. If you go to the cssSandpaper website and look through the code, you will see the exact formula (search for "setMatrixFilter" in cssSandpaper.js). You can hard code it into your library, or you can use cssSandpaper itself to do it (using the cssSandpaper.setTransform() method). Even though it may add a few KB to your code, I suggest this just in case I make improvements to the way I handle transforms in the future.
In any case, good luck!
Z.
Actually I've coded it according to my needs, here is the code, if anyone else is interested.
$.fn.ieRotate = function(alfa){
var self = this,
cosAlfa = Math.cos(alfa),
sinAlfa = Math.sin(alfa),
matrix = '(M11=' + cosAlfa + ', '
+ 'M12=' + -sinAlfa + ', '
+ 'M21=' + sinAlfa + ', '
+ 'M22=' + cosAlfa + ','
+ 'sizingMethod=\'auto expand\')',
// constructing the final filter string
filter = 'progid:DXImageTransform.Microsoft.Matrix' + matrix;
self.each(function(el){
var $this = $(el),
size = $this.data('size'),
pos = $this.data('pos');
$this.css({
'-ms-filter': filter,
'filter': filter,
// for IE9
'transform': 'rotate(' + angle + 'deg)'
});
// calculate the difference between element's expeced and the actual centers
var dLeft = ($this.width() - size.width) / 2,
dTop = ($this.height() - size.height) / 2;
$this.css({
top: pos.top -dTop,
left: pos.left - dLeft
});
});
return self;
};
Usage:
// caching the image object to a variable
$image = $('img#my-image');
// saving images non-rotated position and size data
$image.data('pos', {
top: $image.position().top,
left: $image.position().left
}).data('size', {
height: $image.height(),
width: $image.width()
});
// rotate image 1.2 radians
$image.ieRotate(1.2);
Thanks to #Zoltan Hawryluk, his code helped me during the development.
The position fix for IE can also be calculated analytically - see here

Categories