Mouse coordinate based perspective rotation with centered div [Javascript] - javascript

Second question I've asked, so if I need to add anything else, let me know please!
Been looking everywhere to try and understand concepts, but I feel like I am over thinking it. What I am trying to do is base "transform: rotateX("x"deg)" off of the x location of the users cursor proportionately from the size of the window. Here is a gif that does what I want, but they use matrix3D instead of just transform's rotate.
http://i.imgur.com/tUZSLXA.gif
Here is a js fiddle of what I have so far.
https://jsfiddle.net/z7bet2sw/
JS:
function rotate() {
var x = event.clientX;
var w = window.innerWidth;
var midpoint = w / 2;
// restrictions for rotation
if (x > -20 && x < 20) {
document.getElementsById("logo").style.transform = "perspective(550px)" + "rotateY(" + x + "deg)";
} else {
}
}
document.addEventListener("mousemove", rotate);
Thanks!

You need to pass the event parameter to rotate function from addEventListener, and also you need to calculate a relative position from the x coordinates to get a value between -20 and 20:
function rotate (event)
{
var x = event.clientX;
var w = window.innerWidth;
var midpoint = w / 2;
var pos = x - midpoint;
var val = (pos / midpoint) * 20;
var logo = document.getElementById ("logo");
logo.style.transform = "perspective(550px) rotateY(" + val + "deg)";
}
document.addEventListener("mousemove", function(event)
{
rotate(event)
}, false);
JSFiddle

Two issues:
you are using document.getElementsById which should actually be document.getElementById (no s)
you should subtract midpoint from x
Updated code:
function rotate() {
var x = event.clientX;
var w = window.innerWidth;
var midpoint = w / 2;
x -= midpoint;
if (x > -20 && x < 20) {
document.getElementById("logo").style.transform = "perspective(550px)" + "rotateY(" + x + "deg)";
} else {
}
}
fiddle: https://jsfiddle.net/jacquesc/z7bet2sw/1/

Related

How to have an element follow a dynamic moving element?

Okay, so I got most of this done. Here is the code:
function gi(a) {
return document.getElementById(a)
}
gameworld = document.getElementById('GameWorld');
character = document.getElementById('character');
var oldvX = 30;
var oldvY = 30;
gameworld.addEventListener('click', function(e) {
var offsetX = e.offsetX;
var offsetY = e.offsetY;
var element = e.target;
character.style.left = offsetX + 'px';
character.style.top = offsetY + 'px';
});
setInterval(function() {
monster = gi('monster');
oldvX += 10;
oldvY += 10;
gb = gameworld.getBoundingClientRect();
cb = character.getBoundingClientRect();
oldvX += cb.left / 10;
oldvY += cb.top / 10;
if (oldvX >= (cb.left)) {
return
}
if (oldvY >= (cb.top)) {
return
}
monster.style.left = oldvX + 'px';
monster.style.top = oldvY + 'px';
}, 500);
And here is the jsfiddle:
https://jsfiddle.net/g43nxhcw/12/
As you can see, the monster is making its way towards the player via the players' getBoundingClientRect(). My dilemma is: When I move around the red square, the monster is not following my character. I am not sure how to accomplish this or if this is even possible.
You should calculate a direction vector
vx = cb.left - parseInt(monster.style.left);
vy = cb.top - parseInt(monster.style.top);
vl = Math.sqrt(vx*vx+vy*vy);
vx = vx / vl
vy = vy / vl
it always have the length 1so you can multiply with the step size
vx = vx * 10
vy = vy * 10
and make it chase you like your little friend:
monster.style.left=(parseInt(monster.style.left) + vx) +'px';
monster.style.top=(parseInt(monster.style.top) + vy)+'px';
there is something wrong with your detection of collision also..
but I wont cover that here
https://jsfiddle.net/g43nxhcw/13/

Deg. in rotation

I am building time picker where you can set time on "real" clocks.
Im finding the position of mouse and degrees + rotating div using this script
var g;
var h;
if (e.target.id == "rotationSliderContainer") {
g = e.offsetX;
h = e.offsetY;
} else {
g = e.target.offsetLeft + e.offsetX;
h = e.target.offsetTop + e.offsetY;
}
var atan = Math.atan2(g - radius, h - radius);
deg = -atan / (Math.PI / 180) + 180;
var presne = Math.abs(deg - (Math.round(deg / 30) * 30));
if (presne <= 2) deg = Math.round(deg / 30) * 30;
if(deg == 360)
deg = 0;
two.style.transform = "rotate(" + deg + "deg)";
it works fine but it has little bug , whenever i want to move div , between 12 and 1,2,3 its flipping between 12 and one of those values.
Here is a live demo http://jsfiddle.net/Trolstover/afo7ky03/1/
Is there any shortcut how to prevent this unwanted behavior or did i simply made a mistake somewhere?
This if/else condition is switching between events in the rotationSliderContainer and other DOM elements (such as the rotationSlider and the body). That else condition is your culprit.
if (e.target.id == "rotationSliderContainer") {
g = e.offsetX;
h = e.offsetY;
} else {
g = e.target.offsetLeft + e.offsetX;
h = e.target.offsetTop + e.offsetY;
}
remove those two lines and it should be fine.
if (e.target.id == "rotationSliderContainer") {
g = e.offsetX;
h = e.offsetY;
}
Cool clock ^_^

Konva events mis-positioned after screen resize

In my code I am resizing the Konva canvas and the konvajs-content elements to maintain a full screen appearance.
resizeCanvas()
window.onresize = function() { resizeCanvas(); }
function resizeCanvas() {
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth,
y = w.innerHeight || e.clientHeight || g.clientHeight;
var ratio = x / y;
var should = 1920 / 1080;
var cv = document.getElementsByTagName("canvas")[0];
var cc = document.getElementsByClassName("konvajs-content")[0];
var cx, cy;
var cleft=0;
if(ratio > should) {
cx = (y * 1920/1080);
cy = y;
cleft = (x - cx) / 2;
} else {
cx = x;
cy = (x * 1080/1920);
cv.setAttribute("style", "width:" + x + "px;height:"+ (x*1080/1920) + "px;");
}
cc.setAttribute("style", "width:" + x + "px;height: " + y + "px;");
cv.setAttribute("style", "width:" + cx + "px;heigth: " + cy + "px; position: relative; left: " + cleft + "px");
}
This all works great until I try to capture any event input. As you can see in the JSFiddle, when trying to click on the 'Test' text you will not cause an event to fire.
But if you click ~40px to the left and 20px above the text you will fire the events.
https://jsfiddle.net/3qc3wtr3/2/
Is there a way to keep the resize behavior and to ensure that events are being fired based on the actual location of the elements?
You should use stage.width() and stage.height() to fit a page. You can add scale into stage if you need.

Rotation around a specific point

I'm trying to rotate an element around another element. I've put this code together, and even though the code works fine, I have a little problem with the element's rotation. It's not very accurate. The blue dot leaves the orbit when at the bottom.
I've played with the code but couldn't fix it. You can check the fiddle example.
rotateObj function taken from Felix Eve's answer.
function markCircleCenter(circ, orig) {
if (typeof circ == "string") {
var elm = document.getElementById(circ);
} else { var circle = circ; }
if (typeof orig == "string") {
var mark = document.getElementById(orig);
} else { var elm = orig; }
var width = parseInt(window.getComputedStyle(elm).width, 10);
var height = parseInt(window.getComputedStyle(elm).height, 10);
var top = parseInt(window.getComputedStyle(elm).top, 10);
var left = parseInt(window.getComputedStyle(elm).left, 10);
var markWidth = parseInt(window.getComputedStyle(mark).width, 10);
var markHeight = parseInt(window.getComputedStyle(mark).height, 10);
var circle = {
circle: elm,
x: width/2 + left,
y: height/2 + top,
};
mark.style.position = "absolute";
mark.style.top = circle.y - markWidth/2 + "px";
mark.style.left = circle.x - markHeight/2 + "px";
document.body.insertBefore(mark, elm.nextSibling);
return circle;
}
function placeObjIntoOrbit(obj) {
if (typeof obj == "string") {
var obj = document.getElementById(obj);
} else { var obj = obj; }
var objPos = {
obj: obj,
x: origin.x,
y: parseInt(window.getComputedStyle(origin.circle).top, 10) - parseInt(window.getComputedStyle(obj).width, 10) / 2,
};
obj.style.position = "absolute";
obj.style.top = objPos.y + "px";
obj.style.left = objPos.x + "px";
return objPos;
}
function rotateObj(pointX, pointY, originX, originY, angle) {
var angle = angle * Math.PI / 180.0;
return {
x: Math.cos(angle) * (pointX-originX) - Math.sin(angle) * (pointY-originY) + originX,
y: Math.sin(angle) * (pointX-originX) + Math.cos(angle) * (pointY-originY) + originY,
};
}
var angle = 0;
var origin = markCircleCenter("circle", "origin");
var point = placeObjIntoOrbit("point");
function spin() {
if (angle >= 360) { angle = 0; }
angle += 2;
var newCoor = rotateObj(point.x, point.y, origin.x, origin.y, angle);
point.obj.style.left = newCoor.x + "px";
point.obj.style.top = newCoor.y + "px";
}
setInterval("spin('point')", 1000/30);
You are computing the center of the point but positioning it using its top-left point. You need to take the dimension of the point into account when you position it. Try changing the last two lines in function spin() to:
point.obj.style.left = (newCoor.x - 4) + "px";
point.obj.style.top = (newCoor.y - 4) + "px";
(You should get rid of the "- 4" and substitute half the width and height of the point, but this gets the idea across more tersely.)

Conflicting JavaScript for gyroscope move and touchmove on iOS, how do I pause one part when the second is in use?

I'm punching above my weight a bit with some JavaScript code on an iOS web app.
What I'm doing is moving a layer above another layer using:
Gyro and accelerometer data and
Touch input.
This means I've got two bits of javascript both trying to move the same thing. This doesn't work so well, as you can see from the current version when viewed on an iOS device (hint: the transparency is turned on with the button on the right, and no, it can't be moved with a mouse right now and wont move unless you are using an iOS device with a Gyro).
So I've done the hard bits but I'm stuck on what I expect is a gotcha based on my newb(ish) level of proficiency with JavaScript.
How can I stop the gyro-move code when the touch-move code is active? Also I guess I'll need to update the x+y values so the transparency does not jump position once the touch-move ends.
I've tried adding an if, else statement to the top of the code but this seems to break the whole lot.
BTW thanks to everyone on StackOverflow, previous Q and As have been tons of help in getting me this far.
Help will be most appreciated.
Stefan
Here's my code so far, it's living in the body element...
var x = 0, y = 0,
vx = 0, vy = 0,
ax = 0, ay = 0;
var transp = document.getElementById("transp");
if (window.DeviceMotionEvent != undefined) {
window.ondevicemotion = function(e) {
ax = event.accelerationIncludingGravity.x * 5;
ay = event.accelerationIncludingGravity.y * 5 + 19;
document.getElementById("accelerationX").innerHTML = e.accelerationIncludingGravity.x;
document.getElementById("accelerationY").innerHTML = e.accelerationIncludingGravity.y;
document.getElementById("accelerationZ").innerHTML = e.accelerationIncludingGravity.z;
if ( e.rotationRate ) {
document.getElementById("rotationAlpha").innerHTML = e.rotationRate.alpha;
document.getElementById("rotationBeta").innerHTML = e.rotationRate.beta;
document.getElementById("rotationGamma").innerHTML = e.rotationRate.gamma;
}
}
setInterval( function() {
var landscapeOrientation = window.innerWidth/window.innerHeight > 1;
if ( landscapeOrientation) {
vx = vx + ay;
vy = vy + ax;
} else {
vy = vy - ay;
vx = vx + ax;
}
vx = vx * 0.98;
vy = vy * 0.98;
y = parseInt(y + vy / 70);
x = parseInt(x + vx / 70);
boundingBoxCheck();
transp.style.top = y + "px";
transp.style.left = x + "px";
}, 25);
}
function boundingBoxCheck(){
if (x<-310) { x = -310; vx = -vx; }
if (y<-300) { y = -300; vy = -vy; }
if (x>document.documentElement.clientWidth) { x = document.documentElement.clientWidth; vx = -vx; }
if (y>document.documentElement.clientHeight+400) { y = document.documentElement.clientHeight+400; vy = -vy; }
}
$.fn.moveable = function() {
var offset = null;
var start = function(e) {
var orig = e.originalEvent;
var pos = $(this).position();
offset = {
x: orig.changedTouches[0].pageX - pos.left,
y: orig.changedTouches[0].pageY - pos.top
};
};
var moveMe = function(e) {
e.preventDefault();
var orig = e.originalEvent;
$(this).css({
top: orig.changedTouches[0].pageY - offset.y,
left: orig.changedTouches[0].pageX - offset.x
});
};
this.bind("touchstart", start);
this.bind("touchmove", moveMe);
};
$(".moveable").moveable();
My first thought would be is to have an isTouching variable that gets set to true on touchstart and set back to false on touchEnd. Then using a conditional the gyro code will only run if the isTouching variable is false. Hope that helps.

Categories

Resources