how to apply javascript function only to the element that is hovered - javascript

I selected two elements with same class with document.querySelectorAll and i want to apply function onmousemove but only to the element which has mousemove. Problem is that i dont know how to make it work on both elements but only when that element is hovered (onmousemove over it). I tried this
let menuSingle = document.querySelectorAll('.navigation__single');
let menuSingleText = document.querySelector('.navigation__single-text');
menuSingle.onmousemove = function (e) {
callParallax(e);
};
menuSingle.onmouseleave = function (e) {
TweenMax.to(menuSingleText, 2, {
y: 0,
ease: Power3.easeOut
});
};
It does not work. But when i try to select with querySelector then it only selects the first element and it works like it should. But i need it to work on both elements. Thanks in advance
edit:
my whole code
function menuHoverAnimation() {
let menuSingle = document.querySelector('.navigation__single');
let menuSingleText = document.querySelector('.navigation__single-text');
menuSingle.onmousemove = function (e) {
callParallax(e);
};
menuSingle.onmouseleave = function (e) {
TweenMax.to(menuSingleText, 2, {
y: 0,
ease: Power3.easeOut
});
};
function callParallax(e) {
parallaxIt(e, menuSingleText, 500);
}
function parallaxIt(e, target, movement) {
let $this = menuSingle;
let relY = e.pageY - $this.offsetTop;
TweenMax.to(target, 4, {
y: (relY - $this.offsetHeight / 2) / $this.offsetHeight * movement,
ease: Power3.easeOut
});
}
}
demo with working example only on first child
https://codepen.io/riogrande/pen/MGOrRr

document.querySelectorAll() returns a HTMLElementCollection containing the matches. You can loop through this and set the properties of each element to the desired functions:
let menuSingle = document.querySelectorAll('.navigation__single');
let menuSingleText = document.querySelector('.navigation__single-text');
menuSingle.forEach(elem => elem.onmouseenter = function (e) {
callParallax(e);
});
menuSingle.forEach(elem => elem.onmouseleave = function (e) {
TweenMax.to(menuSingleText, 2, {
y: 0,
ease: Power3.easeOut
});
});
Now, that you edited your post, there are a lot more mistakes of this kind:
function menuHoverAnimation() {
let menuSingle = document.querySelectorAll('.navigation__single');
let menuSingleText = document.querySelectorAll('.navigation__single-text');
menuSingle.forEach(elem => elem.onmousemove = function (e) {
callParallax(e);
});
menuSingle.forEach(elem => elem.onmouseleave = function (e) {
TweenMax.to(menuSingleText, 2, {
y: 0,
ease: Power3.easeOut
});
});
function callParallax(e) {
parallaxIt(e, menuSingleText, 500);
}
function parallaxIt(e, target, movement) {
let $this = menuSingle;
let relY = e.pageY - e.target.offsetTop;
TweenMax.to(e.target, 4, {
y: (relY - e.target.offsetHeight / 2) / e.target.offsetHeight * movement, //assuming they all have the same offsetHeight
ease: Power3.easeOut
});
}
}
menuHoverAnimation();
body {
display: flex;
}
.navigation__single {
width: 50%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: blue;
}
#red {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<div class="navigation__single work-screen__trigger" id="red">
<span class="navigation__single-text">Work</span>
</div>
<div class="navigation__single about-screen__trigger">
<span class="navigation__single-text">About</span>
</div>

You need to add mousemove and mouseleave event listener to each element with class navigation__single. Something like below:
function mousemoveFn(e){
callParallax(e);
}
function mouseleaveFn(e){
TweenMax.to(menuSingleText, 2, {
y: 0,
ease: Power3.easeOut
});
}
let menuSingle = document.querySelectorAll('.navigation__single');
for(var i=0; i<menuSingle.length; i++){
menuSingle[i].addEventListener('mousemove', mousemoveFn);
menuSingle[i].addEventListener('mouseleave', mouseleaveFn);
}

You are almost there. Just need to loop through all the nodes to attach events to them like
let menuSingle = document.querySelectorAll('.navigation__single');
let menuSingleText = document.querySelector('.navigation__single-text');
for(var i=0; i<menuSingle.length; i++){
menuSingle[i].addEventListener("onmousemove", callParallax)
}

You can do it with Jquery, just put an ID name
$( "#mydiv" ).hover(
function() {
console.log('Hovering');
}, function() {
console.log('Not Hovering');
}
);
#mydiv {
background-color: red;
height: 100px;
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='mydiv'>
</div>

Related

Javascript animation is skewed when it runs fast

I've just created a simple animation function that moves a box from left to right. The problem is when the animation runs the box becomes a rectangle when it animates so the proportion of the box shape is gone which is not what I want, how can you retain the shape of the box through the animation. When you slow the animation down to 2 seconds the box retains its shape but when you speed up the animation then it becomes skewed. How do you prevent this from happening?
function animate(...args) {
let starttime = new Date().getTime();
let requestID;
if(args.length == 5) {
args = { el: args[0], props: args[1], duration: args[2], step: args[3], callback: args[4] };
} else {
args = { el: args[0], props: args[1], duration: args[2], callback: args[3] };
}
function moveit(args) {
var timestamp = new Date().getTime();
var runtime = timestamp - starttime;
var progress = runtime / args.duration;
progress = Math.min(progress, 1);
for(const prop in args.props) {
let dist = parseInt(args.props[prop].substring(0, args.props[prop].length - 2), 10);
args.el.style[prop] = (dist * progress).toFixed(2) + 'px';
}
if(args.step != undefined) {
args.step(progress);
}
if (runtime < args.duration){ // if duration not met yet
requestID = requestAnimationFrame(moveit.bind(new Date().getTime(), args));
} else {
args.callback();
cancelAnimationFrame(requestID);
}
}
requestAnimationFrame(moveit.bind(new Date().getTime(), args));
}
window.addEventListener('load', function(event) {
//alert('Hello World')
document.getElementById('reset')
.addEventListener('click', function(event) {
document.getElementById('box').setAttribute('style', '')
});
document.getElementById('play')
.addEventListener('click', function(event) {
animate(document.getElementById('box'), { left: '400px' }, 500, function(step) {
}, function() {
});
});
});
.box {
background: red;
width: 50px;
height: 50px;
position: relative;
top: 0;
left: 0;
}
.controls {
position: relative;
top: 20px;
}
<div id="box" class="box"></div>
<div class="controls">
<button id="reset">reset</button>
<button id="play">play</button>
</div>

Javascript animation trigger only when reaching a certain part of webpage

I want a counter animation which is triggered only when webpage reaches that certain part. For example, the js file would be this. I want the count to start only when the page reaches that certain section.
const counters = document.querySelectorAll('.counter');
const speed = 200; // The lower the slower
counters.forEach(counter => {
const updateCount = () => {
const target = +counter.getAttribute('data-target');
const count = +counter.innerText;
// Lower inc to slow and higher to slow
const inc = target / speed;
// console.log(inc);
// console.log(count);
// Check if target is reached
if (count < target) {
// Add inc to count and output in counter
counter.innerText = count + inc;
// Call function every ms
setTimeout(updateCount, 1);
} else {
counter.innerText = target;
}
};
updateCount();
});
Yo can easily do it using Jquery
$(document).ready(function() {
$(window).scroll(function() {
if ($(document).scrollTop() > 50) {
$("div").css("background-color", "#111111");
} else {
$("div").css("background-color", "transparent");
}
});
});
div {
height: 120vh;
transition-duration: 0.5s;
}
<div>
Scroll to Change Background
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
You can use Intersection Observer to do that
const $observeSection = document.querySelector('#second');
const options = {
root: null,
rootMargin: '0px',
threshold: 0.5
};
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio > options.threshold) {
$observeSection.classList.add('yellow');
} else {
$observeSection.classList.remove('yellow');
}
});
}, options);
observer.observe($observeSection);
main {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
main section {
width: 100vw;
height: 100vh;
}
#first {
background: red;
}
#second {
background: blue;
}
#third {
background: green;
}
.yellow {
background: yellow!important;
}
<main>
<section id="first"></section>
<section id="second"></section>
<section id="third"></section>
</main>
In this example, I observe the second section, and when the scroll come to the middle of the section (threshold: 0.5), I add a class to change the color of this section.
Be careful if you need to handle legacies browsers as you can see here :
https://caniuse.com/#feat=intersectionobserver
You don't need jquery to achieve this.
Here is a VanillaJS solution:
window.onscroll = (e) => {
e.stopPropagation();
window.pageYOffset > 50 && console.log("do smh");
}

What may be the cause of the error "ReferenceError: Velocity is not defined"?

help please help, I do not understand the reason. Throws an error ReferenceError: Velocity is not defined. If I use $ (function () {}; then the error disappears, but then simply do not work. Use hammer 2.0.4 and velocity 1.2.3
// Constants
const THRESH = 0.75;
const TIMING = 250;
// When the dom is loaded, set up hammer events.
document.addEventListener('DOMContentLoaded', f => {
var lis = document.querySelectorAll('.swipe');
for (let i = 0; i < lis.length; i++) {
let hammertime = new Hammer(lis[i]);
hammertime.on('panright', e => handlePan(e));
hammertime.on('panend', e => reset(e));
}
});
// pane{right} handler
function handlePan(e, model) {
var {target: el, deltaX: dx} = e;
if (doAction(dx, el)) {
el.classList.add('action');
} else {
el.classList.remove('action');
}
Velocity(el, {
translateX: dx
}, 0);
}
// panend handler
function reset(e) {
var {target: el, deltaX: dx} = e;
// Should we remove the element?
if (doAction(dx, el)) {
Velocity(el, {
translateX: dx * 2
}, TIMING).then(() => {
return Velocity(el, {
height: 0
}, TIMING);
}).then(() => {
el.parentNode.removeChild(el);
});
} else {
Velocity(el, {
translateX: 0
}, TIMING);
}
}
// Determines if an element will be dismissed
function doAction(dx, el) {
return Math.abs(dx) >= THRESH * el.clientWidth;
}
.swipe {
position: relative;
list-style: none;
text-align: center;
background: #9e9e9e;
height: 150px;
line-height: 150px;
width: 40vw;
}
<div class="swipe">Swipe me!</div>
<!--Scripts-->
<script src="http://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.4/hammer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
The velocity library reference should have been BEFORE the
jQuery reference. The way you know this is that when you run the code, with the developers tools open (F12) and you get the error, the error comes up from within the jQuery code - - so that means that jQuery can't find velocity. Then looking at the script references, you can see why...the jQuery library is running before the velocity library has been loaded.
This works:
// Constants
const THRESH = 0.75;
const TIMING = 250;
// When the dom is loaded, set up hammer events.
document.addEventListener('DOMContentLoaded', f => {
var lis = document.querySelectorAll('.swipe');
for (let i = 0; i < lis.length; i++) {
let hammertime = new Hammer(lis[i]);
hammertime.on('panright', e => handlePan(e));
hammertime.on('panend', e => reset(e));
}
});
// pane{right} handler
function handlePan(e, model) {
var {target: el, deltaX: dx} = e;
if (doAction(dx, el)) {
el.classList.add('action');
} else {
el.classList.remove('action');
}
Velocity(el, {
translateX: dx
}, 0);
}
// panend handler
function reset(e) {
var {target: el, deltaX: dx} = e;
// Should we remove the element?
if (doAction(dx, el)) {
Velocity(el, {
translateX: dx * 2
}, TIMING).then(() => {
return Velocity(el, {
height: 0
}, TIMING);
}).then(() => {
el.parentNode.removeChild(el);
});
} else {
Velocity(el, {
translateX: 0
}, TIMING);
}
}
// Determines if an element will be dismissed
function doAction(dx, el) {
return Math.abs(dx) >= THRESH * el.clientWidth;
}
.swipe {
position: relative;
list-style: none;
text-align: center;
background: #9e9e9e;
height: 150px;
line-height: 150px;
width: 40vw;
}
<!--Scripts-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<script src="http://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.4/hammer.min.js"></script>
<div class="swipe">Swipe me!</div>

Listening for addEventListener calls for a custom event

I'm trying to build a custom drag event. Here's my initial pseudocode, note that I left event cleaning up out.
var dragEvent = new CustomEvent("drag");
var anArbitrairyElement = document.querySelector(".box");
anArbitrairyElement.addEventListener("drag", function () {
console.log("event received");
});
(function () {
var dragEventListeners = [];
window.addEventListener("mousedown", function (mousedownEvent) {
dragEventListeners.forEach(function (target) {
if (mousedownEvent.target === target) {
window.addEventListener("mousemove", function (mousemoveEvent) {
target.dispatchEvent(dragEvent);
});
}
// ...
});
});
// does something like this exist?
onDragEventAdded(function (listenerElement) {
dragEventListeners.push(listenerElement);
});
}());
Is there any way I can listen to addEventListener calls without overwriting the addEventListener function itself? The solution needs to end-up in this being possible:
document.querySelector(".someElement").addEventListener("drag", ...);
Otherwise, is there another way how I could achieve the desired behavior of creating a custom drag event?
Do it the following way.
window.addEventListener("mousedown", function (mousedownEvent) {
var mouseMoveHandler =
function(element) {
return function(mouseMoveEvent) {
element.dispatchEvent(dragEvent);
}
}(mousedownEvent.target);
window.addEventListener("mousemove", mouseMoveHandler);
});
});
So in this case on mousedown event you create closure that will trigger drag event on the clicked element. You do not need the array of elements that were clicked. Clicked element is already injected to the handler.
Don't forget to clean listeners on mouseup. Just drop the mousemove listener on window
For anyone who wants to use the drag event, here's an example utilizing it.
var box1 = document.createElement("div");
var box2 = document.createElement("div");
var box3 = document.createElement("div");
document.body.appendChild(box1);
document.body.appendChild(box2);
document.body.appendChild(box3);
box1.className = "box";
box2.className = "box";
box3.className = "box";
box1.innerHTML = "Drag me";
box2.innerHTML = "No drag";
box3.innerHTML = "Drag me";
function dragElement(event) {
event.target.style.top = parseInt(event.target.style.top.split("px")[0] || 0) + event.dy + "px";
event.target.style.left = parseInt(event.target.style.left.split("px")[0] || 0) + event.dx + "px";
}
box1.addEventListener("drag", dragElement);
box3.addEventListener("drag", dragElement);
// custom event logic starting here
var dragEvent = new CustomEvent("drag");
window.addEventListener("mousedown", function (mousedownEvent) {
var mousePosition = {x: mousedownEvent.clientX, y: mousedownEvent.clientY};
(function () {
var target = mousedownEvent.target;
console.log(target);
function moveHandler(event) {
var newMousePosition = {x: event.clientX, y: event.clientY};
dragEvent.dx = newMousePosition.x - mousePosition.x;
dragEvent.dy = newMousePosition.y - mousePosition.y;
dragEvent.clientX = event.clientX;
dragEvent.clientY = event.clientY;
target.dispatchEvent(dragEvent);
mousePosition = newMousePosition;
}
function releaseHandler() {
window.removeEventListener("mousemove", moveHandler);
window.removeEventListener("mouseup", releaseHandler);
}
window.addEventListener("mousemove", moveHandler);
window.addEventListener("mouseup", releaseHandler);
}());
});
.box {
width: 75px;
height: 75px;
background-color: skyblue;
display: inline-block;
margin: 10px;
position: relative;
text-align: center;
font-family: helvetica;
color: white;
vertical-align: middle;
line-height: 75px;
font-weight: bold;
}

How to Disallow `mouseenter` and `mouseleave` event when checkbox checked?

How to disallow mouseenter and mouseleave event when checkbox checked?
window.addEvent('domready',function() {
var z = 2;
var e = document.id('draggable');
var drag = new Drag.Move(e, {
grid: false,
preventDefault: true,
onStart: function() {
e.setStyle('z-index',z++);
}
});
//e.store('Drag', drag);
var w = e.getStyle('width');
var h = e.getStyle('height');
e.set("morph", {duration:700,delay:400}).addEvents({
mouseenter: function(){
this.store("timer", (function() {
this.morph({
width: '700px',
height: '500px',
opacity: [0.5, 1]
});
}).delay(1000, this));
},
mouseleave: function() {
var pin = this.store("timerB", (function() { //probably there is some missateke
this.morph({
width: w,
height: h,
opacity: [1, 0.5]
});
}).delay(1000, this));
$clear(this.retrieve("timer"));
}
});
});
function check(elem) {
var pin = document.id('draggable').retrieve('timerB');
if(elem.checked) {
pin.detach();
}
else {
pin.attach();
}
}
#draggable{
background-color: grey;
width: 300px;
height: 200px;
opacity: 0.5;
}​
​<input type="checkbox" onclick="check(this);">
<div id="draggable">Draggable DIV 1</div>
The code paste in http://jsfiddle.net/89RJp/4/
http://jsfiddle.net/89RJp/6/
you want if (element.get("checked")) return at the top of the mouseenter/mouseleave callbacks.

Categories