Finding the center of a responsive page with javascript - javascript

I'm currently working on a googly eye that follows your mouse movements. I've been able to center the googly and listen for mouse movements, but I'm having trouble finding the center of the page after I've resized it.
var DrawEye = function(eyecontainer, pupil, eyeposx, eyeposy){
// Initialise core variables
var r = $(pupil).width()/2;
var center = {
x: $(eyecontainer).width()/2 - r,
y: $(eyecontainer).height()/2 - r
};
var distanceThreshold = $(eyecontainer).width()/2.2 - r;
var mouseX = 0, mouseY = 0;
// Listen for mouse movement
$(window).mousemove(function(e){
var d = {
x: e.pageX - r - eyeposx - center.x,
y: e.pageY - r - eyeposy - center.y
};
var distance = Math.sqrt(d.x*d.x + d.y*d.y);
if (distance < distanceThreshold) {
mouseX = e.pageX - eyeposx - r;
mouseY = e.pageY - eyeposy - r;
} else {
mouseX = d.x / distance * distanceThreshold + center.x;
mouseY = d.y / distance * distanceThreshold + center.y;
}
});
// Update pupil location
var pupil = $(pupil);
var xp = 0, yp = 0;
var loop = setInterval(function(){
// change 1 to alter damping/momentum - higher is slower
xp += (mouseX - xp) / 5;
yp += (mouseY - yp) / 5;
pupil.css({left:xp, top:yp});
}, 1);
};
var pariseye1 = new DrawEye("#eyeleft", "#pupilleft", 650, 300);
I'm trying to get it to follow the mouse no matter how big or small the window size is, I'm just having trouble figuring that out.
As of right now, if you resize the page the googly eye still follows the mouse, but it becomes slight ajar and doesn't quite follow the mouse exactly. It seems like where it's actually tracking the mouse stays the same.
I'm fairly new to javascript, so if anyone could help that would be great!
Thanks, James

Related

im making a circle follow the cursor which is working fine but how do i add a smoother effect and avoid the circle going out of the page

I have made a circle that follows the cursor using jquery which works fine but i want to give it a smoother effect, i have tried using timeout but that wont work which is kinda obvious so is there any other way to achieve this ?
Also whenever the cursor is close to the border of the webpage or crosses it the circle also goes outside the webpage creating a scrollbar can this be avoided by any way ?
My code -
var mouseX = 0, mouseY = 0;
var xp = 0, yp = 0;
let mouseMovementStoppedTimer;
const mouseMovementStopped = function() {
$("#circlecc").css({ opacity: 0});
}
$(document).mousemove(function(e){
$("#circlecc").css({opacity: 1})
mouseX = e.clientX - 12;
mouseY = e.clientY - 12;
setTimeout(() => {
$("#circlecc").css({left: mouseX +'px', top: mouseY +'px'});
}, 50)
clearTimeout(mouseMovementStoppedTimer);
mouseMovementStoppedTimer = setTimeout(mouseMovementStopped, 120);
});
My Website
Yes, you can avoid it, by detecting whether it would be outside the edge and making corrections:
let radius = 5; //you can have your own value here
function getX(x) {
if (x - radius < 0) return radius;
if (x + radius >= $(window).width()) return $(window).width() - radius - 1;
return x;
}
function getY(y) {
if (y - radius < 0) return radius;
if (y + radius >= $(window).height()) return $(window).height() - radius - 1;
return y;
}
$(document).mousemove(function(e){
$("#circlecc").css({opacity: 1})
mouseX = e.clientX - 12;
mouseY = e.clientY - 12;
setTimeout(() => {
$("#circlecc").css({left: getX(mouseX) +'px', top: getY(mousey) +'px'});
}, 50)
clearTimeout(mouseMovementStoppedTimer);
mouseMovementStoppedTimer = setTimeout(mouseMovementStopped, 120);
});

Scale image relative to mouse position from its center

Hello my dear fellows,
I've been trying to recreate the effect: image scales up as the mouse get closer to the center of the image found on https://www.davidwilliambaum.com/
I have been very unsuccessfull so far, as I am not sure how to approach the problem.
I started a codepen with some ideas : https://codepen.io/dindon-studio/pen/RwLwRKM
As you can see I first get the center coordinate of the image, and then i try some dirty formula to scales it up with the mouse distance.
But it is very buggy and not convincing at all.
Does anyone got a better approach?
Deep thanks for you help!
var mX, mY, distance, element
element = $('.project')
function calculateDistance(elem, mouseX, mouseY) {
return Math.floor(Math.sqrt(Math.pow(mouseX - (elem.offset().left+(elem.width()/2)), 2) + Math.pow(mouseY - (elem.offset().top+(elem.height()/2)), 2))); }
$(document).mousemove(function(e) {
mX = e.pageX;
mY = e.pageY;
distance = calculateDistance(element, mX, mY);
if (distance< 500 && distance >50){
var scaling = 1 + (1/distance) *100
gsap.to(".project", {duration: 0.01, scale: scaling,ease: "power2.in",});
}
});
I build off from your codepen and made some adjustments: https://codepen.io/Mookiie/pen/qBPBmNe
The higher the scalingFactor the closer the mouse needs to be for a size change.
function calculateCenter(image) {
var rect1 = image.getBoundingClientRect();
var x = rect1.left + rect1.width * 0.5;
var y = rect1.top + rect1.height * 0.5;
return { x: x, y: y }
}
function getDistance(x1, y1, x2, y2){
let y = x2 - x1;
let x = y2 - y1;
return Math.sqrt(x * x + y * y);
}
function distanceFromCenter(image, mouseX, mouseY) {
var imageCenter = calculateCenter(image);
return getDistance(imageCenter.x, imageCenter.y, mouseX, mouseY)
}
function adjustImage(image, mX, mY) {
var distance = distanceFromCenter(image, mX, mY);
const baseScale = 1
const maxScaling = 1.5;
const scalingFactor = 1;
const adjustedScaling = maxScaling - ((distance / 1000) * scalingFactor)
const scaling = adjustedScaling >= baseScale ? adjustedScaling : baseScale
gsap.to(image, {duration: 0.01, scale: scaling, ease: "power2.in",});
}
$(document).mousemove(function(e) {
const mX = e.pageX;
const mY = e.pageY;
const images = $("img")
images.each(function() {
adjustImage(this, mX, mY)
})
});

How to rotate an element on drag with jQuery?

I'm creating a website with a rotating wheel. The user should be able to rotate this wheel with dragging it with mouse. I implemented this in jQuery and it works(rotates). But it behaves as expected just between 90 degrees and 180 degrees. When it rotates more or less than this range, I see some unexpected bounces.
This is my code:
$(document).ready(function(){
var isDragging = false;
$("#box").mousemove(function(e){
if(isDragging){
e.preventDefault();
var rx = $(this).width() / 2;
var ry = $(this).height() / 2;
var px = e.clientX - $(this).offset().left - rx;
var py = e.clientY - $(this).offset().top - ry;
var a = Math.atan2(py,px) * 180 / Math.PI + 90;
if(py <= 0 && px < 0){a = 360 + a;}
$(this).css("-webkit-transform","rotate(" + a + "deg)");
}
});
$("#box").mousedown(function(){
isDragging = true;
});
$("*").mouseup(function(){
isDragging = false;
});
});
What is the problem? How to solve it?
You should check out the answer posted here.
How to make object rotate with drag, how to get a rotate point around the origin use sin or cos?
Here is the working fiddle from their answer
http://jsfiddle.net/mgibsonbr/tBgLh/11/
it involves making your html look similar to this.
<div class="draggable_wp">
<div class="el"></div>
<div class="handle"></div>
</div>
Within your if(isDragging) clause:
var element = document.getElementById("rotatable");
var mouseX = e.pageX || e.clientX + document.documentElement.scrollLeft;
var mouseY = e.pageY || e.clientY + document.documentElement.scrollTop;
var rect = element.getBoundingClientRect();
var s_rad = Math.atan2(
mouseY - rect.top - rect.height / 2,
mouseX - rect.left - rect.width / 2
);
var degree = Math.round(90 + (s_rad * (180 / (Math.PI))) / 15) * 15;
element.style.transform = 'rotate(' + degree + 'deg)';

How to make an object point at mouse

I have a simple sword image (drawn pointing up) that is in an 'open world' game setting, so the player can move around the world to all coordinates. I would like the sword to point at the mouse.
My issue (I think) is that the world coordinates and webpage coordinates do not match up. For example, the player could be at location (6000, 6000), while the mouse coordinates would only be between 0 and 1600 (or whatever the width of the screen is). On top of that, the webpage won't always exist in the same place.
Thoughts so far:
So I need to calculate the position of the mouse relative to the canvas, or vice versa.
Formula I was using. This worked in an older project of mine for XNA:
var xdir = mouse.x - swordcenter.x;
var ydir = mouse.y - swordcenter.y;
var theta = (Math.atan2( ydir, xdir ) - Math.PI/2.0) * (180.0/Math.PI);
I feel like the solution should be simpler than what I'm thinking, but no formula has been working so far. Any ideas?
So the question I suppose is why isn't this working? And my best guess is because of the difference in coordinates. I can't figure out how to factor it in.
Edit: I have figured out how to factor it in. With the following code, the mouse position is put in to game coordinates. So if the mouse hovers over the player, then the mouse pos and player pos are equal. However, the image still spins rapidly with the mouse movement.
document.addEventListener('mousemove', function(e){
mouse.x = e.clientX || e.pageX;
mouse.y = e.clientY || e.pageY;
var view = document.getElementById('viewport');
var rect = view.getBoundingClientRect();
mouse.x -= rect.left;
mouse.y -= rect.top;
var camX = clamp(x - canvas.width/2, -1000, 1000 - canvas.width);
var camY = clamp(y - canvas.height/2, -1000, 1000 - canvas.height);
mouse.x += camX;
mouse.y += camY;
}, false);
Edit 2: Here is how I get the angle:
var getAngle = function() {
var xdir = mouse.x - x;//where x and y are the sword center
var ydir = mouse.y - y;
var theta = Math.atan2( ydir, xdir ) * (180.0/Math.PI);
return theta;
}
Edit 3: Here is how I draw the image:
var draw = function(ctx) {
ctx.fillRect(x-15, y-15, 30, 30);//background player rect
ctx.save();
ctx.translate(x, y);//x and y is the center of the sword/player
ctx.rotate(getAngle());
//this correctly draws the sword on top of the player rect, except for rotation
ctx.drawImage(stanceTexture, -stanceTexture.width/2, -stanceTexture.height/2);
ctx.restore();
};
After all the additional math done to compute the correct "in-game" mouse location, it turns out that my canvas context wanted radians as well. Much confuse. Every other post I found regarding this turns the value back into degrees (WRONG) so I hope this helps someone else out. So here is the complete answer,
document.addEventListener('mousemove', function(e){
mouse.x = e.clientX || e.pageX;
mouse.y = e.clientY || e.pageY;
var view = document.getElementById('viewport');
var rect = view.getBoundingClientRect();
mouse.x -= rect.left;
mouse.y -= rect.top;
var camX = clamp(x - canvas.width/2, world.minX, world.maxX - canvas.width);
var camY = clamp(y - canvas.height/2, world.minY, world.maxX - canvas.height);
mouse.x += camX;
mouse.y += camY;
}, false);
var getAngle = function() {
var xdir = mouse.x - x;//where x and y are the sword center
var ydir = mouse.y - y;
//Note: I only subtract Math.PI/2 to flip the image 180 degrees.
// The value to subtract will depend on the original angle of your image
var theta = Math.atan2( ydir, xdir ) - Math.PI/2.0;
return theta;
}
var draw = function(ctx) {
ctx.fillRect(x-15, y-15, 30, 30);//background player rect
ctx.save();
ctx.translate(x, y);//x and y is the center of the sword/player
ctx.rotate(getAngle());
//this correctly draws the sword on top of the player rect, except for rotation
ctx.drawImage(stanceTexture, -stanceTexture.width/2, -stanceTexture.height/2);
ctx.restore();
};
You don't need trigonometry for that.
Basic vector calculus is enough:
const sword_length = 10;
var sword_x_start = 0;
var sword_y_start = 0;
var mouse_x = ...; // current mouse position
var mouse_y = ...;
var dx = (mouse_x - sword_x_start);
var dy = (mouse_y - sword_y_start);
// sword to mouse distance
var length = Math.sqrt( dx*dx + dy*dy );
// unit vector, see: http://en.wikipedia.org/wiki/Unit_vector
// in sword to mouse direction:
var unit_v_x = dx / length;
var unit_v_y = dy / length;
// and now coordinates of the sword pointing to mouse:
var sword_x_end = sword_x_start + unit_v_x * sword_length ;
var sword_y_end = sword_y_start + unit_v_y * sword_length ;

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