Cursor changer effect - javascript

I am having trouble changing my custom cursor width and height when I hover on the img element.
I tried using both css and javascript for the effect to work but it won't. When I change my function from "onmouseover" to "onclick" it works perfectly fine.
const cursor = document.querySelector('#cursor');
document.addEventListener('mousemove', e => {
cursor.setAttribute("style", "top: " + (e.clientY - 10) + "px; left: " + (e.clientX - 10) + "px;")
})
/*
/////Second way with javascript/////
var cursor = document.getElementById('cursor');
document.addEventListener('mousemove', function(e){
var x = e.clientX;
var y = e.clientY;
cursor.style.left= x + "px";
cursor.style.top= y + "px";
});
*/
function myFunction() {
document.getElementById("cursor").style.width = "100px";
document.getElementById("cursor").style.height = "100px";
}
body {
margin: 0;
height: 100vh;
background: rgb(27, 27, 27);
}
#cursor {
width: 30px;
height: 30px;
border: 2px solid gray;
border-radius: 50%;
position: fixed;
transition-duration: 100ms;
transition-timing-function: ease-out;
}
img {
position: absolute;
top: 50%;
left: 50%;
}
img:hover #cursor {
width: 100px;
height: 100px;
}
<div id="cursor"></div>
<img onmouseover="myFunction()" src="navbar.svg" alt="navbar">

How about this class toggle. Works.
Always preferable to use addEventListener everywhere
const cursor = document.querySelector('#cursor');
document.addEventListener('mousemove', e => {
cursor.setAttribute("style", "top: " + (e.clientY - 10) + "px; left: " + (e.clientX - 10) + "px;")
})
const hoverIt = e => cursor.classList.toggle("hover");
document.getElementById("navbarimg").addEventListener("mouseover",hoverIt);
document.getElementById("navbarimg").addEventListener("mouseover",hoverIt);
#cursor {
width: 30px;
height: 30px;
border: 2px solid gray;
border-radius: 50%;
position: fixed;
transition-duration: 100ms;
transition-timing-function: ease-out;
}
#cursor.hover {
width: 100px;
height: 100px;
}
img {
position: absolute;
top: 50%;
left: 50%;
}
img:hover #cursor {
width: 100px;
height: 100px;
}
<div id="cursor"></div>
<img id="navbarimg" src="navbar.svg" alt="navbar">

So the css solution here will not work as the #cursor is not a child of the img. You could have it a child of the anchor but that is probably the wrong approach anyway as it is not extendable.
You should probably change the logic to use an eventListener for simplicity...
document.getElementById("testImg").addEventListener("mouseover", function( event ) {
alert("over"); // Do your resizing here and ensure the image has the matching id
})

Related

Transition is not working properly in Safari

So I've made a custom cursor for my next website. In Chrome it works as it should but in Safari it's laggy...
I've tried several things like using the webkit stuff but it still doesn't work.
here is the Codepen
html
<div class="cursor"></div>
css
body{
background: #fff;
width: 100%;
height: 100vh;
}
.cursor{
position: fixed;
left: 0px;
top: 0;
width: 25px;
height: 25px;
transition-duration:0.3s;
-webkit-transition-duration:0.3s;
-ms-transition-duration:0.3s;
-moz-transition-duration:0.3s;
transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-webkit-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-moz-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
js
let cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', moveCursor);
function moveCursor(e) {
let x = e.clientX;
let y = e.clientY;
cursor.style.transform = `translate(calc(${x}px - 50%), calc(${y}px - 50%))`
}
I've had nothing but trouble with dynamic transform values in safari. It seems they calculate positions in the window space a little different than other browsers. No source on that one, just my own trials and tribulations.
I would suggest you change your approach, and use top and left values.
I tested this in safari and it's miles more responsive.
let cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', moveCursor);
function moveCursor(e) {
let x = e.clientX;
let y = e.clientY;
cursor.style.top = `${y}px`
cursor.style.left = `${x}px`
}
body {
background: #fff;
width: 100%;
height: 100vh;
}
.cursor {
position: fixed;
left: 0px;
top: 0;
width: 25px;
height: 25px;
transition-duration: 0.3s;
transition-timing-function: cubic-bezier(.33, .81, .66, .95);
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
}
<div class="cursor"></div>
I kept the translate(-50%, -50%) as a permanent value on the cursor, and only updated top and left with javascript.
As a side note, the vendor prefixes are not really necessary for those properties. No need to add them. https://caniuse.com/css-transitions
The translate calc in you js is forcing the cursor to the center.
The transition delay is too long preventing it for following the cursor.
Codepen: https://codepen.io/diomedefan/pen/RwMaYWe
let cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', moveCursor);
function moveCursor(e) {
let x = e.clientX;
let y = e.clientY;
cursor.style.transform = `translate(calc(${x}px), calc(${y}px))`
}
body{
background: #fff;
width: 100%;
height: 100vh;
}
.cursor{
position: fixed;
left: 0px;
top: 0;
width: 25px;
height: 25px;
transition-duration:0.2s;
-webkit-transition-duration:0.2s;
-ms-transition-duration:0.2s;
-moz-transition-duration:0.2s;
transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-webkit-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-moz-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
<div class="cursor"></div>
The answer for my particular case was pretty interesting.
Instead of using css transitions I used a lerp function in javascript:
var mouseX = window.innerWidth / 2,
mouseY = window.innerHeight / 2;
var $ = jQuery
var circle = {
el: $('.cursor'),
x: window.innerWidth / 2,
y: window.innerHeight / 2,
w: 25,
h: 25,
update: function() {
l = this.x - this.w / 2;
t = this.y - this.h / 2;
this.el.css({
'transform': 'translate3d(' + l + 'px, ' + t + 'px, 0)'
});
}
}
$(window).mousemove(function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
})
setInterval(move, 1000 / 60)
function move() {
circle.x = lerp(circle.x, mouseX, 0.1);
circle.y = lerp(circle.y, mouseY, 0.1);
circle.update()
}
function lerp(start, end, amt) {
return (1 - amt) * start + amt * end
}
.cursor {
position: absolute;
width: 25px;
height: 25px;
transition: height 0.3s ease-in-out, width 0.3s ease-in-out;
top: 0;
left: 0;
z-index: 999;
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
body {
background: #fff;
}
<div class="cursor"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
r

Follow mouse on Hover of Div but only on Div

Not sure how to do this but I have the first part setup right via the codepen here
Not sure how to stop it from occurring unless you hover the black div. Basically I'm looking to have the normal mouse functionality until you hover this black div than fire the script/function. I'm also trying to achieve this without using any libraries and just JS.
Code Below
document.addEventListener("mousemove", function() {
myFunction(event);
});
var mouse;
var cursor = document.getElementById("cursor");
function myFunction(e) {
mouseX = e.clientX;
mouseY = e.clientY;
cursor.style.left = (mouseX - 55) + "px";
cursor.style.top = (mouseY - 55) + "px";
}
body {
background: #FFFDFA;
}
#cursor {
height: 100px;
width: 100px;
position: absolute;
backface-visibility: hidden;
z-index: 9999999;
cursor: none;
}
div {
background: black;
width: 200px;
height: 100px;
margin: 30px;
cursor: none;
}
<img src="https://www.figurefoundry.xyz/metal-cursor.svg" id="cursor"></img>
<div>
</div>
You can simply add the event listener to the div element. You also need to disable pointerEvents on the cursor element so that the mouse doesn't register as on top of the cursor rather than the div.
document.getElementById("div").addEventListener("mousemove", function() {
myFunction(event);
});
var mouse;
var cursor = document.getElementById("cursor");
function myFunction(e) {
mouseX = e.clientX;
mouseY = e.clientY;
cursor.style.left = (mouseX - 55) + "px";
cursor.style.top = (mouseY - 55) + "px";
}
body {
background: #FFFDFA;
}
#cursor {
height: 100px;
width: 100px;
position: absolute;
backface-visibility: hidden;
z-index: 9999999;
pointer-events: none; /* pointer-events: none is needed */
cursor: none;
}
div {
background: black;
width: 200px;
height: 100px;
margin: 30px;
cursor: none;
}
<img src="https://www.figurefoundry.xyz/metal-cursor.svg" id="cursor"></img>
<div id="div"></div> <!--add id-->
EDIT: If you want the cursor to disappear on mouseout:
document.getElementById("div").addEventListener("mousemove", function() {
myFunction(event);
});
var mouse;
var cursor = document.getElementById("cursor");
function myFunction(e) {
mouseX = e.clientX;
mouseY = e.clientY;
cursor.style.left = (mouseX - 55) + "px";
cursor.style.top = (mouseY - 55) + "px";
}
body {
background: #FFFDFA;
}
#cursor {
height: 100px;
width: 100px;
position: absolute;
backface-visibility: hidden;
z-index: 9999999;
pointer-events: none; /* pointer-events: none is needed */
cursor: none;
}
div {
background: black;
width: 200px;
height: 100px;
margin: 30px;
cursor: none;
}
<img src="https://www.figurefoundry.xyz/metal-cursor.svg" id="cursor" hidden></img>
<div id="div" onmouseenter="cursor.hidden = false" onmouseleave="cursor.hidden=true"></div> <!--make cursor invisible on leave and visible on enter-->

Parallax Issue in Javascript

I was creating a parallax effect in which the image and the text move in opposite direction to the movement of the mouse. That is happening inside an element called parallax-wrapper. But when I move out of the element I want the image and the text to return back to their original positions. I have tried to detect the mouse position outside the element but for some reason it not firing properly.
The codepen link is - https://codepen.io/rohitgd/pen/gRLNad?editors=1010
HTML
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>
CSS
body {
background-color:#fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color:#0c0c0c;
position: relative;
overflow: hidden;
.layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color:#FFF;
transition: all 200ms ease-out;
}
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
Javascript
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
$(document).mouseleave(function(e) {
var target = $(e.target);
if( !target.is("div.layer")) {
alert('out of the element');
e.stopPropagation();
}
});
What I want is when the mouse is outside the parallax-wrapper the Image and the text return back to their original positions.
You're not resetting the transformations when your mouse leaves. You need to add this where you have the alert...
$(".parallax-wrapper").mouseleave(function(e) {
$("*[data-mouse-parallax]").each(function() {
$(this).css({ transform: "translate3d( 0, 0, 0 )" });
});
});
Note that the mouseleave event is triggered when the mouse leaves .parallax-wrapper, not document as you previously had it.
Here's a modified codepen...
https://codepen.io/anon/pen/ZyBgYJ
I think a selector was wrong. Here's a correct version or see code below.
To show better when you are inside/outside I change the background color, that's better than an alert. When you leave the wrapper (the black background) it flips correctly now.
Where RED is set you can reset the transform to the origin.
// Trying to replicate the effect here - https://tympanus.net/Development/MorphingBackgroundShapes/
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$(".parallax-wrapper").css("background-color", "#00ff00"); // <-- EXIT
// reset transform here
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
// this is the selector I changed from "document" to ".parallax-wrapper"
$(".parallax-wrapper").mouseleave(function(e) {
var target = $(e.target);
if( !target.is("div.layer")) {
$(".parallax-wrapper").css("background-color", "#ff0000"); // <-- ENTER
e.stopPropagation();
}
});
body {
background-color:#fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color:#0c0c0c;
position: relative;
overflow: hidden;
.layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color:#FFF;
transition: all 200ms ease-out;
}
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>
Replace $(document).mouseleave with $(".parallax-wrapper").mouseleave.
$(".parallax-wrapper").mousemove(function(e) {
var x = e.pageX - $(this).offset().left - $(this).width() / 2;
var y = e.pageY - $(this).offset().top - $(this).height() / 2;
$("*[data-mouse-parallax]").each(function() {
var factor = parseFloat($(this).data("mouse-parallax"));
x = -x * factor;
y = -y * factor;
$(this).css({ transform: "translate3d( " + x + "px, " + y + "px, 0 )" });
});
});
$(".parallax-wrapper").mouseleave(function(e) {
alert('out of the element');
});
body {
background-color: #fff;
padding: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.parallax-wrapper {
width: 500px;
height: 300px;
background-color: #0c0c0c;
position: relative;
overflow: hidden;
}
.parallax-wrapper .layer {
width: 80%;
height: 80%;
position: absolute;
left: 30px;
text-align: center;
line-height: 300px;
font-size: 38px;
color: #FFF;
transition: all 200ms ease-out;
}
img {
width: 200px;
height: 200px;
position: relative;
top: 50px;
right: 70px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parallax-wrapper">
<div class="layer" data-mouse-parallax="0.1">
<img src="https://tympanus.net/Development/MorphingBackgroundShapes/img/1.jpg"/>
</div>
<div class="layer" data-mouse-parallax="0.3">REVERT</div>
</div>

How can I prevent this material ripple animation from leaking out into other div?

In the following codepen, the creator has made a material ripple effect. However there is an issue where if I add another div right next to the original the ripple will leak into it.
What should I do to change to code so that the ripple will only be contained in the div that it was activated on?
I have tried editing the JS so that the click function only activates for divs with the class ".rippleDiv" but that did not work either.
Link to codepen http://codepen.io/Ruddy/pen/09052b957d82a17bd6ca70ac6663dd6a
HTML
<div class="rippleDiv">Button</div>
<div>Button 2</div>
CSS
div {
width: 220px;
height: 120px;
background: #222;
color: #fff;
text-align: center;
line-height: 120px;
font-size: 40px;
}
/* Ripple */
.ripple {
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: scale(0);
position: absolute;
opacity: 1;
}
.rippleEffect {
animation: rippleDrop .6s linear;
}
#keyframes rippleDrop {
100% {
transform: scale(2);
opacity: 0;
}
}
JS
$(".rippleDiv").click(function (e) {
// Remove any old one
$(".ripple").remove();
// Setup
var posX = $(this).offset().left,
posY = $(this).offset().top,
buttonWidth = $(this).width(),
buttonHeight = $(this).height();
// Add the element
$(this).prepend("<span class='ripple'></span>");
// Make it round!
if(buttonWidth >= buttonHeight) {
buttonHeight = buttonWidth;
} else {
buttonWidth = buttonHeight;
}
// Get the center of the element
var x = e.pageX - posX - buttonWidth / 2;
var y = e.pageY - posY - buttonHeight / 2;
// Add the ripples CSS and start the animation
$(".ripple").css({
width: buttonWidth,
height: buttonHeight,
top: y + 'px',
left: x + 'px'
}).addClass("rippleEffect");
});
The basic answer is that the 'ripple' element needs to be contained inside a div that has overflow:hidden set.
However to get this right, a number of small changes need to be made so that both the original button content, as well as the ripple itself, are correctly positioned, mainly using divs with the correct positioning attributes set.
So - here are the changes I made to get this to work: http://codepen.io/kitr/pen/xgLQpM
HTML:
<div>Button</div>
<div>Button 2</div>
CSS:
div {
width: 220px;
height: 120px;
background: #222;
color: #fff;
text-align: center;
line-height: 120px;
font-size: 40px;
position:relative;
overflow:hidden;
}
/* Ripple */
.ripple {
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: scale(0);
opacity: 1;
}
.rippleEffect {
animation: rippleDrop .6s linear;
position: absolute;
}
#keyframes rippleDrop {
100% {
transform: scale(2);
opacity: 0;
}
}
Javascript:
$("div").click(function (e) {
// Remove any old one
$(".ripple").remove();
// Setup
var posX = $(this).offset().left,
posY = $(this).offset().top,
buttonWidth = $(this).width(),
buttonHeight = $(this).height();
// Add the element
$(this).append("<div class='ripple'></div>");
// Make it round!
if(buttonWidth >= buttonHeight) {
buttonHeight = buttonWidth;
} else {
buttonWidth = buttonHeight;
}
// Get the center of the element
var x = e.pageX - posX - buttonWidth / 2;
var y = e.pageY - posY - buttonHeight / 2;
// Add the ripples CSS and start the animation
$(".ripple").css({
width: buttonWidth,
height: buttonHeight,
top: y + 'px',
left: x + 'px'
}).addClass("rippleEffect");
});

How do I get my Javascript to show just one spotlight centred on the mouse?

At the top of my website you can see that I have an animation at the top, I'm having trouble getting it to show just one spotlight that is centred on the mouse along with having the text shadow effect being centred on the mouse also.
I have found that by zooming in on the browser the centring issue is fixed but if possible I would rather not set a fixed zoom level for visitors.
Below I have attached the CSS followed by the JavaScript that I have used:
The CSS:
#text-shadow-box {
position: relative;
width: 100%;
height: 350px;
background: #666;
overflow: hidden;
cursor: none;
border: 1px solid Black;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;
}
#text-shadow-box div.wall {
position: absolute;
top: 175px;
left: 0;
width: 100%;
}
#tsb-text {
margin: 0;
color: #999;
font-family: Helvetica, Arial, sans-serif;
font-size: 80px;
line-height: 1em;
height: 1px;
font-weight: bold;
text-align: center;
}
div.wall div {
position: absolute;
background: #999;
overflow: hidden;
top: 150px;
left: 0;
height: 300px;
width: 100%;
}
#tsb-spot {
position: absolute;
overflow: hidden;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url(/spotlight.png) top center;
}
The JavaScript:
<script type="text/javascript" language="javascript" charset="utf-8">
var text;
var spot;
///window.onload = init;
init();
function init() {
text = document.getElementById('tsb-text');
spot = document.getElementById('tsb-spot');
document.getElementById('text-shadow-box').onmousemove = onMouseMove;
document.getElementById('text-shadow-box').ontouchmove = function (e) {e.preventDefault(); e.stopPropagation(); onMouseMove({clientX: e.touches[0].clientX, clientY: e.touches[0].clientY});};
onMouseMove({clientX: 300, clientY: 200});
}
function onMouseMove(e) {
var xm = e.clientX - 300;
var ym = e.clientY - 175;
var d = Math.sqrt(xm*xm + ym*ym);
text.style.textShadow = -xm + 'px ' + -ym + 'px ' + (d / 5 + 10) + 'px black';
xm = e.clientX - 600;
ym = e.clientY - 450;
spot.style.backgroundPosition = xm + 'px ' + ym + 'px';
}
</script>
With your current implementation, you are using an image for the spotlight, found on this line:
background: url(http://www.zachstronaut.com/lab/text-shadow-box/spotlight.png) top center;
A much better implementation would be to add a <canvas> element instead where your title is currently on your website. You can use CanvasRenderingContext2D.createRadialGradient() to create a spotlight effect: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createRadialGradient.
You can also see some similar implementations of what I am recommending here:
https://jsfiddle.net/4Ezkg/
http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

Categories

Resources