Mouseover and mouseout not firing with animating element - javascript

I need to detect if a user is hovering over an element, which is straightforward. However, these events don't seem to fire when the element is animating. If you check out my fiddle, just have the element animate past your mouse without moving your mouse, and you'll see that the events don't fire. It makes sense why this would happen, but I haven't been able to find a good way to get the behavior I want, which is to detect hovering even if the user doesn't move his/her mouse and the element animates under it.
Any thoughts?
Thanks!
Note: solutions without use of external libraries are optimal, but any help is still appreciated :)
HTML
<div id='moving'></div>
<ul id="message"></ul>
CSS
#moving {
width: 50px;
height: 50px;
background-color: red;
animation: move 7s linear;
}
#keyframes move {
from {transform: translateX(0px)}
to {transform: translateX(500px)}
}
JS
var counter = 0;
document.getElementById("moving").addEventListener("mouseover", function(){
counter++;
var node = document.createElement("LI");
var textnode = document.createTextNode("Entered " + counter);
node.appendChild(textnode);
document.getElementById("message").appendChild(node);
});
document.getElementById("moving").addEventListener("mouseout", function(){
var node = document.createElement("LI");
var textnode = document.createTextNode("Left " + counter);
node.appendChild(textnode);
document.getElementById("message").appendChild(node);
});
Here's a fiddle of it:
https://jsfiddle.net/w5j842Lx/

You can check if the mouse is in or out within an interval. Here is a working fiddle extending from your fiddle.
// This is the helper method I have written
var addMoveListener = function(element, onmouseover, onmouseout) {
var over = false;
var mouseX, mouseY;
var checkOver = function(ev) {
if (ev) {
mouseX = ev.clientX;
mouseY = ev.clientY;
}
if (mouseX == null || mouseY == null) return;
var rect = element.getBoundingClientRect();
var isInside = mouseX >= rect.left && mouseX < rect.right && mouseY >= rect.top && mouseY < rect.bottom;
if (over && !isInside && onmouseout) onmouseout();
if (!over && isInside && onmouseover) onmouseover();
over = isInside;
}
document.addEventListener("mousemove", checkOver);
var interval = setInterval(checkOver.bind(null, null), 100);
}
// Code below is for the sake of demonstration
var counter = 0;
var mouseovercallback = function() {
counter++;
console.log("Entered " + counter);
};
var mouseoutcallback = function() {
console.log("Left " + counter);
};
addMoveListener(document.getElementById("moving"), mouseovercallback, mouseoutcallback);
#moving {
width: 50px;
height: 50px;
background-color: red;
animation: move 7s linear;
}
#keyframes move {
from {
transform: translateX(0px)
}
to {
transform: translateX(500px)
}
}
<div id='moving'></div>
The code checks if the mouse is contained for every 100 miliseconds and also if the mouse is moved. If you want to handle cases where the element is not a rectangle or is rotated, skewed etc., you have to improve the code.

Take a look at this jsfiddle https://jsfiddle.net/3vpaoj59/
It includes a function like this
setInterval(checkMouse, 100);
that basically calls a function 10 times a second to check if the mouse's coordinates are within the animated shape. Your shape is a square and not a circle, so you would have to do some different math. This code is nice because it doesn't use a plugin, but it's probably CPU intensive and might have poor performance in some cases.

Related

Trying to have images only below viewport fade in on scroll

I'm trying to follow this tutorial for my portfolio website.
I've almost got it working but instead of only fading in images as they come into the window, it is fading the images that are already in the window.
$(document).on("scroll", function () {
var pageTop = $(document).scrollTop()
var pageBottom = pageTop + $(window).height()
var tags = $("section")
for (var i = 0; i < tags.length; i++) {
var tag = tags[i]
if ($(tag).position().top < pageBottom) {
$(tag).addClass("visible")
} else {
$(tag).removeClass("visible")
}
}
})
section {
opacity: 0;
transform: translate(0, 20px);
transition: all 1.5s;
}
section.visible {
opacity: 1;
transform: translate(0, 0);
}
This is because everything is hidden until the first scroll event fires. To fix this you can manually trigger a scroll event when the page first loads in order to display the section elements which are already visible in the viewport.
$(document).on("scroll", function () {
// your code here...
}).trigger('scroll');
It's also worth noting that the scroll event handler fires for every pixel that you scroll by. As such performance is important there so it would be worth optimising that handler function.
var $tags = $("section");
var winHeight = $(window).height();
$(document).on("scroll", function() {
var pageTop = $(document).scrollTop();
var pageBottom = pageTop + winHeight;
$tags.each(function() {
this.classList.toggle(this.offsetTop < pageBottom)
});
}).trigger('scroll');
$(window).on('resize', function() {
winHeight = $(this).height();
});

Track mouseover event with moving elements

I am developing an app, and have run into a really simple but frustrating issue. Essentially I have a moving element and I want to track when it moves over the mouse. So currently, if the pointer is in the middle of the screen and not moving while the box passes over it NO event will be triggered. Is there any type of mouse or pointer event I could where it would trigger an event when the box passes over it?
Thanks. The simple code example I wrote is below:
<html>
<head>
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
</head>
<body>
<div id="box" style="height:300px;width:300px;background-color:green;position:absolute;top:600px;"></div>
<script>
var box = document.getElementById('box');
box.addEventListener('onmouseover',function(e){
console.log('im being tagged!')
});
$('#box').animate({top: '1px'},3000);
</script>
</body>
</html>
The events I HAVE tried so far: onmouseover, mouseover, mouseenter, mousemove, pointerenter,pointerover
The pointer events are from a library called pep.
Since you're looking to know when the moving box element is colliding with the mouse, not vice versa, you'll want to set up a looping check for that collision. You'll need to calculate and retain the position of the mouse cursor and use document.elementFromPoint to check if the element over the cursor is the box:
$(document).ready(function() {
var MouseCoords = function(x, y) {
this.x = x;
this.y = y;
};
var mousecoords = new MouseCoords(0,0);
var isTagged = false;
$( document ).on( "mousemove", function( event ) {
mousecoords.x = event.pageX;
mousecoords.y = event.pageY;
});
$('#box').animate({top: '1px'},3000);
function isBoxOverMouse() {
var collidingElement = document.elementFromPoint(mousecoords.x, mousecoords.y);
if (collidingElement != null && collidingElement.id == "box") {
if (!isTagged) {
isTagged = true;
console.log("Tag!");
}
} else {
isTagged = false;
}
}
setInterval(isBoxOverMouse, 500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box" style="height:300px;width:300px;background-color:green;position:absolute;top:600px;"></div>
I have the loop set to fire every 500ms, but that can be changed if that's not your desired frequency. I also set an isTagged variable so the console doesn't report the same collision multiple times, so feel free to remove that if you want the collision reported at every checked interval.
Adapting the code from this great answer to detect element collision
I added a function to run while the animation is in progress. Like this
$('#box').animate({
top: '1px'
}, {
duration: 5000,
// check if box overlaps cursor while animating
progress: function(promise) {
isOverlapping(this);
}
});
See the jQuery API docs for more details
$(function() {
var cursorX, cursorY = 0;
// tracks mouse position and updates its x,y coordinates
$(document).on('mousemove', function(e) {
cursorX = e.pageX;
cursorY = e.pageY;
$("#cursor").text("[X: " + e.pageX + ", Y: " + e.pageY + "]");
isOverlapping("#box");
});
// detects if two elements overlap
var overlaps = (function() {
function getPositions(elem) {
var pos, width, height;
pos = $(elem).position();
width = $(elem).width();
height = $(elem).height();
return [
[pos.left, pos.left + width],
[pos.top, pos.top + height]
];
}
function comparePositions(p1, p2) {
var r1, r2;
r1 = p1[0] < p2[0] ? p1 : p2;
r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function(b) {
// making cursor 2x2 pixels
var pos1 = [
[cursorX, cursorX + 2],
[cursorY, cursorY + 2]
],
pos2 = getPositions(b);
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
};
})();
// updates status if the box overlaps the cursor
var isOverlapping = function(elem){
if (overlaps(elem)) {
$("#boxPos").text("Overlaps");
$("#boxPos").addClass("yes");
$("#boxPos").removeClass("no");
} else {
$("#boxPos").text("No overlap");
$("#boxPos").addClass("no");
$("#boxPos").removeClass("yes");
}
}
$('#box').animate({
top: '1px'
}, {
duration: 5000,
// check if box overlaps cursor while animating
progress: function(promise) {
isOverlapping(this);
}
});
});
#cursor,
#boxPos {
float: right;
display: block;
}
.yes {
background-color: green;
}
.no {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box" style="height:150px;width:150px;background-color:green;position:absolute;top:600px;"></div>
<div id="cursor"></div>
<br/>
<div id="boxPos"></div>
<br/>
Since you are using JQuery, you can use the mousemove event handler attached to the HTML body element. This will give you the mouse position, which you can then use to determine when the mouse is intersecting the box.
<html>
<head>
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
</head>
<body>
<div id="box" style="height:300px;width:300px;background-color:green;position:absolute;top:600px;"></div>
<script>
$(document).ready(function() {
var mousePos = {x:0, y:0}
$('html').mousemove(function(event) {
mousePos.x = event.clientX
mousePos.y = event.clientY
})
$('#box').animate({top: '1px'},{
duration: 3000,
step: function() {
console.log(parseInt($('#box').css('top')) <= mousePos.y)
}
});
})
</script>
</body>
</html>

How to reverse direction of moving div once it reaches side of screen?

I have an absolutely positioned div that uses the jQuery .animate function to move horizontally from the right to left of the screen.
My problem is that once the div reaches the far left side, it continues and eventually disappears from the screen. How do you make it so that once the div reaches the left side, it will reverse and start going to the right? (and then vice versa so that the right side won't continue going right, but goes left again once it reaches the end)
HTML:
<div class="container">
<div class="block"></div>
</div>
CSS:
.block {
float:right;
position:absolute;
right:100px;
width:100px;
height:100px;
background:red;
}
jQuery:
$('.block').click(function() {
$(this).animate(
{"right": "+=100px"},"slow");
});
Here is my JSFiddle: https://jsfiddle.net/ebkc9dzL/
Thank you I really appreciate the help!
may be you should try like this:
$('.block').click(function() {
var leftPosition = $(this).position();
if (leftPosition.left > 100) {
$(this).animate({"right": "+=100px"},"slow");
} else {
$(this).animate({"right": "-=100px"},"slow");
}
});
when the element is close to the border the if..else part of the code will reverse the direction.
Here is a fiddle, try to click on the red box to get an idea on how it works:
https://jsfiddle.net/dimitrioglo/ebkc9dzL/14/
Working fiddle: https://jsfiddle.net/ebkc9dzL/19/
You need to have a variable outside the click function that will tell you the direction of the animation, so that once inside the click function you can calculate the location of the animated object using getBoundingClientRect() (mdn reference).
Then, if object is moving left and its left distance is less than its own width, you need to move it only enough so that it comes to the edge. If it's AT the edge (left is zero), you need to change the direction.
If it's moving right and its right distance is less than its own width, you need to move it only enough (calculated by window.innerWidth - 100, since 100 is width of your object) so that it comes to the edge. If it's AT the right edge, you need to change direction.
Changing direction in object you pass to jQuery's animate function is a simple matter of adding or subtracting from its "right" attribute.
var direction = "+";
$('.block').click(function() {
var obj = {},
distance = 100,
rect = this.getBoundingClientRect();
if(direction=="+"){
if(rect.left>0 && rect.left < 100)
distance = rect.left;
else if(rect.left<=0)
direction = "-";
}
else {
if(rect.right >(window.innerWidth-100) && rect.right+1<window.innerWidth)
distance = (window.innerWidth-rect.right);
else if(rect.right+1 >=window.innerWidth){
direction = "+";
}
}
obj = {"right": direction+"="+distance.toString()+"px"}
$(this).animate(obj,"slow");
});
Here you go: jsFiddle.
The new javascript is as follows:
var goLeft = true;
$('.block').click(function() {
var animateDist = 100;
var distLeft = $(this).position().left;
var distRight = window.innerWidth - distLeft;
if (goLeft) {
if (distLeft < 100) {
animateDist = "+="+distLeft+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = false;
} else {
$(this).animate(
{"right": "+=100px"},"slow"
);
}
} else {
if (distRight < 100) {
animateDist = "-="+distRight+"px";
$(this).animate(
{"right": animateDist},"slow"
);
goLeft = true;
} else {
$(this).animate(
{"right": "-=100px"},"slow"
);
}
}
});
This isn't perfect, you need to adjust your internal window width to match the parent container, but this is enough to get you in the right direction.
Good luck!
Try this code:
var sign = [ "+" , "-" ];
var signPosition = 0;
var maxOffset = $(".block").offset().left;
$('.block').click(function() {
if ($(this).offset().left < 100) {
signPosition = 1;
} else if ($(this).offset().left == maxOffset) {
signPosition = 0;
}
$(this).animate(
{"right": sign[signPosition] + "=100px"},"slow");
});
The variable sign is the array that contains the directions in which the element might move, the variable signPosition contains the position of the direction currently in use, the variable maxOffset contains the starting position.
Hope this will help you.

How to add a text box popup (Jquery tooltip or similar) to a Fabric JS image within a canvas?

I'm working on a Fabric JS project to map a floor with its rooms' locations.
At each room location I added an icon. I want to have a text box pop up (such as jquery tooltip) each time the mouse hover above the icon.
The text box should show room information (phone number \ person \ size \ etc.)
I found this google group post, but no one really described the solution beside sharing this link
Step 1: Set up your watchers
Step 2: Load the dialog
Step 3: Figure out where the bounding rect is on the page and move the dialog.
canvas.observe('mouse:over', function (e) {
console.log("Everyday I'm hovering");
showImageTools(e.target);
});
canvas.observe('mouse:out', function (e) {
$('#imageDialog').remove();
});
function showImageTools (e) {
var url = 'dialog/imageDialog.htm';
$.get(url, function(data) {
// Don't add it twice
if (!$('#imageDialog').length) {
$(body).append(data);
}
moveImageTools();
});
function moveImageTools () {
var w = $('#imageDialog').width();
var h = $('#imageDialog').height();
var e = canvas.getActiveObject();
var coords = getObjPosition(e);
// -1 because we want to be inside the selection body
var top = coords.bottom - h - 1;
var left = coords.right - w - 1;
$('#imageDialog').show();
$('#imageDialog').css({top: top, left: left});
}
function getObjPosition (e) {
// Get dimensions of object
var rect = e.getBoundingRect();
// We have the bounding box for rect... Now to get the canvas position
var offset = canvas.calcOffset();
// Do the math - offset is from $(body)
var bottom = offset._offset.top + rect.top + rect.height;
var right = offset._offset.left + rect.left + rect.width;
var left = offset._offset.left + rect.left;
var top = offset._offset.top + rect.top;
return {left: left, top: top, right: right, bottom: bottom};
}
That should be enough to get you started. Let me know if any of this doesn't make sense.
Add span element below the canvas
<span ref="toolTip" class="toolTip">ToolTip</span>
Add style for span element
NB: Visibility is hidden by default
.toolTip{
position: absolute;
z-index: 1;
background: rgb(119, 128, 0);
height: 30px;
width: 120px;
padding: 8px;
font-size: 13px;
color: #fff;
visibility: hidden;
}
Add mouse over and mouse out events
this.$data.canvas.on('mouse:over', function (e) {
// console.log(e.e.offsetX)
if (e.target && e.target.feature === 'Seat') {
self.$refs.toolTip.innerHTML =
'Seat: ' + e.target.label + ' Row: ' + e.target.rowLabel
self.$refs.toolTip.style.visibility = 'visible'
self.$refs.toolTip.style.top = e.e.offsetY + 'px'
self.$refs.toolTip.style.left = e.e.offsetX + 'px'
}
})
this.$data.canvas.on('mouse:out', function (e) {
self.$refs.toolTip.style.visibility = 'hidden'
})

How can I create a click and drag to change the width of an object with jQuery?

I have an object that I want to change the width of when you click on it and drag right or left. Adding to the width or taking away from it as you move the mouse (or finger).
<style>
#changeMe {width:300px; height: 200px;}
</style>
<div id="changeMe">
Some Content
</div>
<script>
$('#changeMe').mousedown(function(){
//Some Code?????
});
</script>
What you want to do is track the x co-ords of the mouse. If greater than they were before, increase size, if lower, decrease the size.
Not tested but the below should be inspiration.
var oldXPos = 0;
var isDragging = false;
$(document).mousemove(function(event) {
if (isDragging)
{
var difference = event.pageX - oldXPos;
// Do something with this value, will be an int related to how much it's moved
// ie $('#changeMe').css.width += difference;
}
oldXPos = event.pageX;
});
$('#changeMe').mousedown(function() {
isDragging = true;
})
$('#changeMe').mouseup(function() {
isDragging = false;
})
You just need a resizable({}) effect .
$('#changeMe').resizable({});
You can look at this article
Resizable
$(function() {
$('.testSubject').resizable();
});
or
#changeMe {width:300px; height: 200px; border: 1px solid black;}
<body>
<div id="changeMe">
Some Content
</div>
</body>
$('#changeMe').resizable({});
Or
$(function(){
$('img[src*=small]').toggle(
function() {
$(this).attr('src',
$(this).attr('src').replace(/small/,'medium'));
},
function() {
$(this).attr('src',
$(this).attr('src').replace(/medium/,'large'));
},
function() {
$(this).attr('src',
$(this).attr('src').replace(/large/,'small'));
}
);
});
If I understand your question correctly, that you want to be able to dynamically increase/decrease the size of the object as it moves along the x-axis, I recommend that you use $('#changeMe').offset() inside the jQuery UI drag event.
You can create a formula that you want to use based on an initial offset, and the new offset to size your container by $('#changeMe').css({ width: X, height: Y });, and insert whatever your X and Y values are in pixels.
Edited for further elaboration with code:
var initX = 0;
var initW = 0;
$('#changeMe').draggable({
start: function() {
initX = $(this).offset().left;
initW = $(this).width();
},
drag: function() {
var deltaX = initX - $(this).offset().left;
$(this).css({ width: initW + deltaX });
}
});
If you used that as your base, it's a very nice and simple solution for your application.

Categories