How to change cursor on multiple mouseovers - javascript

I am trying to change my cursor into different images depending on the object that it is hovering over inside my banner. Currently I only know to change the cursor style in CSS. But the cursor stays the same throughout. How do I replace the cursor image on mouseover in my javascript? I am only using jQuery and TweenMax as this is for an assignment.

Using CSS cursor property
Without using any pseudo-selectors in CSS, you can have a pretty good result by playing around with the cursor property. For example, you can select one cursor style from a range of available ones. Or even add your own by linking the URL of the icon.
For example, the code below will show a heart when you hover over the grey area:
.heart {
cursor: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/9632/heart.png"), auto;
width: 200px;
height: 200px;
background: grey;
}
<div class="heart"></div>
You can change the origin of the image's position relative to the actual mouse position by setting the x and y position along with the URL in the cursor property:
cursor: url(<URL>) [x y|auto];
Using JavaScript
Of course, you can handle this feature with JavaScript code. Here are several things we will need to achieve this:
creating an HTML element with the image of the cursor you want as background
using the onmouseenter, onmousemove and onmouseleave events
getting the position of the mouse on the page: properties pageX, pageY
setting the position of our cursor element to be at the position of the mouse (the actual mouse pointer will be hidden): with the transform CSS property.
There are several other tricks I have used to get it right: for example setting the boxes' overflow to be hidden so that the cursor elements can't be seen outside the box. Also, listening to the onmouseleave event allows us to hide the cursor element when the mouse is outside the box area.
I have made a little demo here, click Show code snippet > Run code snippet:
const showCursor = function(event) {
let cursor = event.target.querySelector('.cursor');
event.target.onmousemove = function(e) {
cursor.style.display = 'block'
let [x, y] = [e.pageX - e.target.offsetLeft - 20, e.pageY - e.target.offsetTop - 20]
cursor.style.transform = `translate(${x}px, ${y}px)`
}
event.target.onmouseleave = function(e) {
cursor.style.display = 'none'
}
}
.box {
cursor: none;
overflow: hidden;
width: 200px;
height: 200px;
background: pink;
display: inline-block;
margin: 10px;
}
.box:nth-child(1) {
background: aquamarine;
}
.box:nth-child(2) {
background: pink;
}
.box:nth-child(3) {
background: cornflowerblue;
}
.box:nth-child(4) {
background: lightcoral;
}
.cursor {
display: none;
width: 100px;
height: 100px;
}
#heart {
background: no-repeat url("https://png.icons8.com/color/50/000000/hearts.png");
}
#diamond {
background: no-repeat url("https://png.icons8.com/color/50/000000/diamonds.png")
}
#spade {
background: no-repeat url("https://png.icons8.com/metro/50/000000/spades.png")
}
#clubs {
background: no-repeat url("https://png.icons8.com/ios/50/000000/clubs-filled.png")
}
<div onmousemove="showCursor(event)" class="box">
<div id="diamond" class="cursor"></div>
</div>
<div onmouseenter="showCursor(event)" class="box">
<div id="heart" class="cursor"></div>
</div>
<div onmousemove="showCursor(event)" class="box">
<div id="spade" class="cursor"></div>
</div>
<div onmousemove="showCursor(event)" class="box">
<div id="clubs" class="cursor"></div>
</div>
The function showCursor() is called when the user's mouse enters one of the boxes with the attribute onmouseenter="showCursor(event)" (see HTML markup above).
Below I have provided the JavaScript code with comments explaining how it works:
const showCursor = function(event) {
// get the element object of the cursor of this box
let cursor = event.target.querySelector('.cursor');
// function that will be execute whenever the user moves inside the box
event.target.onmousemove = function(e) {
// the user is moving inside the box
// show the cursor element
cursor.style.display = 'block'
// calcultate the translate values of the cursor element
let [x, y] = [e.pageX - e.target.offsetLeft - 20, e.pageY - e.target.offsetTop - 20]
// apply these values to the style of the cursor element
cursor.style.transform = `translate(${x}px, ${y}px)`
}
// function that will be executed when the user leaves the box
event.target.onmouseleave = function(e) {
// the user's mouse left the box area
// hide the cursor element
cursor.style.display = 'none'
}
}
With a <svg> element
A while ago I answered a post on how to add an <svg> element as the cursor of the mouse. It's a little bit more advanced though. It's still a JavaScript solution but it involves using a <svg> element as the cursor instead of it being a simple <div> (as seen in the second point).

Related

How to disable background page scroll when secondary view is open, without changing body css

I'm creating a secondary view that will pop-up on clicking on a link. Content within this secondary view is vertically scrollable and horizontally fixed. The issue is: when scroll reach to the top/bottom of the secondary view, the background page will scroll as well, also if attempt to scroll left/right, the background page will also scroll.
I did some search online but mostly suggest to modify the body css. Due to project constraint, we are not allowed to modify any attribute on body. So I'm trying to find a solution without making css change.
I was trying to achieve using this approach:
secondaryView.addEventListener('wheel', (event) => {
if (//mouse scroll up and secondaryView is at top
|| //mouse scroll down and secondaryView is at bottom
|| //mouse scroll left or right) {
event.preventDefault();
}
});
However, the problem is I don't know how to detect whether mouse scroll is horizontal, not able to rely on event.deltaX since it will be non-zero sometimes when scrolling up or down as well.
This problem has a lot of solutions (see this huge Q&A for options), one of which is listening for scroll event instead of the wheel one (after all, you do not want to be limited to mouse wheel, do you?).
The easiest version (given that for some reason you cannot modify styling) is to keep track of the last known scroll position of the primary view (or the window) and as soon as the secondary view is shown (a boolean flag should suffice), start snapping the primary to it with scrollTo.
The rest depends on your exact requirements - if you need the primary to be scrollable while the secondary is open, things become complex (a solution for mouse-based devices may be to track cursor position to determine what is scrolled).
(() => {
const p = document.getElementById("primary");
const s = document.getElementById("secondary");
const b = document.getElementById("show");
let secondaryShown = false;
b.addEventListener("click", () => {
if (secondaryShown) {
s.classList.remove("shown");
secondaryShown = false;
return;
}
s.classList.add("shown");
secondaryShown = true;
});
let lknownYPos = window.scrollY,
lknownXPos = window.scrollX;
window.addEventListener("scroll", ({
target,
currentTarget
}) => {
if (secondaryShown) {
window.scrollTo(lknownXPos, lknownYPos)
}
lknownWindowPos = window.scrollY;
}, true);
})();
body {
margin: 0;
}
.subcontent {
height: 300vh;
width: 300vw;
}
#primary {
width: 200vw;
height: 200vh;
}
#secondary {
overflow-x: scroll;
width: 50vw;
height: 50vh;
background-color: rgba(0, 0, 0, 0.25);
z-index: 9999;
color: white;
display: none;
font-size: 2rem;
text-align: center;
}
.shown {
display: block !important;
}
<div class="content">
<div id="primary">
<button id="show">Switch secondary</button>
<div id="secondary">
<p>Secondary</p>
<div class="subcontent"></div>
</div>
</div>
</div>

Show element on scroll (both up and down) - hide element when page is static (not scrolling)

I would like to make a svg image of a computer mouse appear at the bottom of the viewport when user scrolls the page (both up and down scrolling). When the page is static (no scroll) I would like the element to be hidden. It is the same effect as the scrollbar on the right in the browser. Is it possible to apply this effect to a html element? Many thanks for your help in advance.
This can be achieved by listening for the "scroll" event, window.addEventListener('scroll', someFunction).
We can show the div by changing its display style from "none" to "block" box.style.display = 'block'.
And setting a timeout that, in five seconds, will call another function to hide the div again setTimeout(hideBox, 5000).
You can find the definition and explanation for all of these functions in the Mozilla docs: https://developer.mozilla.org/en-US/
I've also included a simple but working example:
(function () {
let timeoutHandle = 0;
const box = document.getElementById("box");
// add the scroll event
window.addEventListener("scroll", (e) => {
box.style.display = "block";
clearTimeout(timeoutHandle);
// call function to hide box after 5 seconds
timeoutHandle = setTimeout(hideBox, 5000);
});
// hides box by setting display to 'none'
hideBox = () => {
box.style.display = "none";
};
})();
#box {
position: fixed;
bottom: 2px;
right: 2px;
line-height: 95px;
height: 100px;
width: 100px;
border: 3px solid red;
text-align: center;
display: none;
}
#box p {
display: inline-block;
vertical-align: middle;
}
<div>
<a id="top">
<!-- hidden anchor --></a>
<p> This is just some sample text.</p>
<p> You should pay attention to the tiny box at the bottom right corner. It appears when you scroll.</p>
<p> Now we add a very long image to make scrolling possible.</p>
<img src="https://i.pinimg.com/564x/75/b7/8a/75b78ae86b6f81ed20f41f57e2a3a7f2.jpg">
</div>
<div id="box">
jump top
</div>

Javascript function that uses mouse position to change div style

I'm working with a div in an HTML page that I need to switch the css style of as I move the mouse throughout the page.
Is there any function I can use to constantly track the mouse location? I need to switch the particular div's css style to a different css style as soon as the mouse is at least 30 px from the top of the page. While the mouse cursor is within 30px distance from the top of the page, I want the div to have a particular style. If it is farther than 30 px from the top of the page, I want it to switch styles.
assume i have 2 different styles in my css I can switch back and forth.
Use a mousemove event listener, and switch your styles by editing the href of a link attribute:
document.body.addEventListener("mousemove" event => {
if (event.clientY >= 30) {
document.querySelector("link").setAttribute("href", "style1.css");
} else {
document.querySelector("link").setAttribute("href", "style2.css");
}
});
You can attach "mousemove" event and use 'event.clientY' to get current mouse top postion and write your requirements accordingly.
Here is an example below:
(function(){
document.body.addEventListener("mousemove", function() {
if (event.clientY >= 30) {
document.querySelector(".myDiv").classList.remove('class2');
document.querySelector(".myDiv").classList.add('class1');
} else {
document.querySelector(".myDiv").classList.remove('class1');
document.querySelector(".myDiv").classList.add('class2');
}
});
})();
.myDiv {
height: 200px;
width: 200px;
border:1px solid #f00;
}
.class1 {
border-radius: 50%;
}
.class2 {
border-radius: 10%;
}
<!DOCTYPE html>
<head>
</head>
<body>
<div class="myDiv"></div>
</body>
</html>

Issues using custom cursor with draggable element

Ok, so I have a draggable element that is contained by it's parent. I'm trying to add a custom cursor while dragging, including when the cursor moves off of the draggable element itself. And then when dragging stops, on mouseup, the cursor should return to default.
<div id="container">
<div class="draggable"></div>
</div>
$(document).ready(function() {
$(window).on("mouseup", function() {
$("*").removeClass("customcursor");
})
$(".draggable").on("mousedown", function() {
$("*").addClass("customcursor");
})
$(".draggable").draggable({
containment: "parent",
});
});
html {
background: lightblue;
}
body {
background-color: teal;
}
#container {
height: 400px;
width: 400px;
background-color: black;
}
.draggable {
height: 200px;
width: 200px;
background-color: red;
}
.customcursor {
cursor: url(http://media.fluke.com/images/8-icon-30x30.gif), default;
}
Here is a working fiddle.
However, this is giving me two issues.
First issue: While dragging, when the cursor moves onto the body element, the custom cursor is no longer in effect. However, when the cursor moves onto the html element, the custom cursor does work. Admittedly, this can be solved by adding a wrapper element, so the cursor is never on the body, but I'm still perplexed about why this is happening.
Second issue: After dragging for the first time, the cursor gets stuck with the custom cursor, even though the .customcursor class has been removed. This second issue can be solved if I add .customcursor class on the start and stop events of the draggable rather than on mousedown and mouseup, but I wanted the custom cursor on mousedown even if the draggable isn't moved.
If anyone has some insight into why these issues are occurring or good ways to fix them, I'd really appreciate the help.
Add !important to the the cursor change:
.customcursor {
cursor: url(http://media.fluke.com/images/8-icon-30x30.gif), default !important;
}
The body was being overrode by a direct element style:
element.style {
cursor: auto;
}
Also, for some reason, the cursor is being left behind as a direct style even after the class is removed. Remove it with JavaScript or jQuery:
$(window).on("mouseup", function() {
$("*").removeClass("customcursor");
//document.body.style.cursor = "";
$("body").css("cursor", "")
console.log("mouseup");
})
Fiddle: https://jsfiddle.net/ntyuuqq2/

javascript window scroll issue

I am working on javascript scroll. I have following html code
JSFIDDLE
<div class="wrapper">
<div class="red div current"></div>
<div class="blue div"></div>
<div class="green div"></div>
<div class="yellow div"></div>
</div>
In above code I have four div tags red, blue, green and yellow. All of them are position in following css.
html, body {
height: 100%;
}
.wrapper {
overflow: hidden;
height: 100%;
}
.div {
position: relative;
height: 100%;
}
.red {
background: red;
}
.blue {
background: blue;
}
.green {
background: green;
}
.yellow {
background: yellow;
}
In above html and css the red div tag is the current one which means user is seeing the red div tag on the screen. Now what I am trying to do is when user scroll over window once, then the next div tag i.e. blue will be animated and moved to the top and will become visible to the user whereas the red div tag will be behind the blue one. This same process goes for both green and yellow.
The problem is that when user scroll once then the div tag should animate however my current javascript code is keep reading the scroll and animating the div tags one after another. What I want is when user scroll once then scroll should be disabled until the blue div tag is animated. Then scroll should be enabled. Again when user scroll second time, the scroll should disable until the green div tag completes its animation. Same goes for yellow.
How can I achieve above?
Here is my javascript
$(window).on("scroll", function () {
var next = $('.current').next();
var height = next.outerHeight();
next.animate({top: '-=' + height}, 500, function () {
$(this).prev().removeClass('current');
$(this).addClass('current');
});
});
Please have a look on update JsFiddle
$(window).on("scroll", function () {
var next = $('.current').next();
var height = $('.current').outerHeight();
$('.current').prevAll().each(function(){
height += $(this).outerHeight();
});
next.animate({top: '-=' + height}, 500, function () {
$(this).prev().css('top','');
$(this).prev().toggleClass('current');
$(this).toggleClass('current');
});
});
The main reason your example wasn't working as expected is because you were relatively positioning the divs, and not moving them to the correct spot.
Working JSFiddle:
http://jsfiddle.net/seanjohnson08/rVVuc/6/
.wrapper {
overflow: hidden;
height: 100%;
position: relative;
}
.div {
position: absolute;
height: 100%;
width: 100%;
top: 100%;
}
.current{
top: 0;
}
If you are looking for a way to limit the amount of scroll events fired, try throttling: http://benalman.com/projects/jquery-throttle-debounce-plugin/. My solution doesn't require this, because no matter how many times it is firing the scroll event, it only ever tells jquery to animate to top:0, there's no chance of it animating past that.

Categories