So I have a page where I have replaced my cursor with a div.
The cursor is simply a part of the page that I can animate using CSS.
The main thing I want to achieve is to make this cursor change size when I hover over any button.
I cannot get it to work...
Cursor positioning is handled by a JQuery script but the vanilla one doesn't seem like it wants to work with me...
I can can't fix the error...
// Jquery code that moves the cursor (div element)
$(document).on('mousemove', function(e){
$('#cursor').css({
left: e.pageX - 7,
top: e.pageY - 7
});
});
// Function to be executed when mouse is over a button
document.querySelectorAll('button').addEventListener("mouseover", cursorHovering);
function cursorHovering() {
document.getElementById('object').style = "transform: scale(2);";
}
body {
height: 300px;
width: 300px;
background-color: #ccc;
}
*, body { cursor: none !important; }
#cursor {
position: fixed;
z-index: 20000;
height: 15px;
width: 15px;
background-color: #ffffff;
mix-blend-mode: difference;
border-radius: 50%;
opacity: 0;
transition: 0.3s;
transition-property: transform, opacity;
pointer-events: none;
}
body:hover #cursor {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div id="cursor"></div>
<button class="button1">Hover over me (1)</button>
<button class="button2">Hover over me (2)</button>
<button class="button3">Hover over me (3)</button>
</body>
You mean something like this?
// Jquery code that moves the cursor (div element)
var c = document.getElementById('cursor');
document.addEventListener('mousemove', (e) => {
c.style.left = e.pageX - 7 + 'px';
c.style.top = e.pageY - 7 + 'px';
});
// Function to be executed when mouse is over a button
document
.querySelectorAll('button')
.forEach(b => {
b.addEventListener("mouseover", () => c.style.transform='scale(2)');
b.addEventListener("mouseout", () => c.style.transform='scale(1)');
});
body {
height: 300px;
width: 300px;
background-color: #ccc;
}
*, body { cursor: none !important; }
#cursor {
position: fixed;
z-index: 20000;
height: 15px;
width: 15px;
background-color: #ffffff;
mix-blend-mode: difference;
border-radius: 50%;
opacity: 0;
transition: 0.3s;
transition-property: transform, opacity;
pointer-events: none;
}
body:hover #cursor {
opacity: 1;
}
<body>
<div id="cursor"></div>
<button class="button1">Hover over me (1)</button>
<button class="button2">Hover over me (2)</button>
<button class="button3">Hover over me (3)</button>
</body>
Here's a vanilla JS solution.
document.addEventListener('mousemove', handleMouseMove, false);
// Cache the elements
const cursor = document.getElementById('cursor');
const buttons = document.querySelectorAll('button');
// For each button add the two event listeners
[...buttons].forEach(button => {
button.addEventListener('mouseover', handleMouseOver, false);
button.addEventListener('mouseout', handleMouseOut, false)
});
function handleMouseMove(e) {
// You need to ensure that you add "px" to the
// end of the value. jQuery does this automatically.
cursor.style.left = `${e.pageX - 7}px`;
cursor.style.top = `${e.pageY - 7}px`;
}
function handleMouseOver() {
cursor.style.transform = 'scale(2)';
}
function handleMouseOut() {
cursor.style.transform = 'scale(1)';
}
body {
height: 300px;
width: 300px;
background-color: #ccc;
}
*,
body {
cursor: none !important;
}
#cursor {
position: fixed;
z-index: 20000;
height: 15px;
width: 15px;
background-color: #ffffff;
mix-blend-mode: difference;
border-radius: 50%;
opacity: 0;
transition: 0.3s;
transition-property: transform, opacity;
pointer-events: none;
}
body:hover #cursor {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div id="cursor"></div>
<button class="button1">Hover over me (1)</button>
<button class="button2">Hover over me (2)</button>
<button class="button3">Hover over me (3)</button>
</body>
Related
I wanted to try to do the angular version of a cursor follow movement, but the mouse movement is not smooth, how do I fix this and what's the reason for it?:
https://stackoverflow.com/a/48756322/5152892
My angular attempt:
https://stackblitz.com/edit/angular-vnx9yd?file=src/app/app.component.ts
export class AppComponent {
name = 'Angular';
constructor(
private el: ElementRef
) {}
get tooltip() {
return this.el.nativeElement.querySelector('.sites-circle');
}
enter(source: string) {
this.tooltip.classList.add('show');
}
move(e: { pageX: number; pageY: number }) {
const tooltipStyle = this.tooltip.style;
tooltipStyle.left = e.pageX + 'px';
tooltipStyle.top = e.pageY + 'px';
}
leave() {
this.tooltip.classList.remove('show');
}
}
CSS:
p {
font-family: Lato;
}
.mouse-circle {
position: absolute;
border: solid 1px #ccc;
width: 20px;
height: 20px;
border-radius: 50%;
background: white;
}
.show {
opacity: 1 !important;
}
.sites-circle {
z-index: 500;
position: absolute;
border: solid 1px #ccc;
width: 20px;
height: 20px;
border-radius: 50%;
background: blue;
pointer-events: none;
transition-duration: 200ms;
transition-timing-function: ease-out;
transform: translate(-50%, -50%);
opacity: 0;
}
.wrapper {
height: 100vh;
width: 100%;
}
HTML:
<div
class="wrapper"
(mouseenter)="enter()"
(mousemove)="move($event)"
(mouseleave)="leave()"
>
<p>Start editing to see some magic happen :)</p>
<div class="sites-circle">hello</div>
</div>
sometimes is better use fromEvent rxjs operator to mannage mousemove. This allow use different operators to not emit constantly the event
Use Viewchild to get the elements
<div #mydiv class="show"
class="wrapper"
(mouseenter)="enter()"
(mouseleave)="leave()"
>
<div #tooltip class="sites-circle">hello</div>
</div>
#ViewChild('mydiv',{static:true}) div:ElementRef
#ViewChild('tooltip',{static:true}) tooltipEl:ElementRef
Then
ngOnInit()
{
this.subscription=fromEvent(this.div.nativeElement,'mousemove').pipe(
throttleTime(200,asyncScheduler,{ trailing: true }))
.subscribe((e:any)=>{
const tooltipStyle = this.tooltip.style;
tooltipStyle.left = e.pageX + 'px';
tooltipStyle.top = e.pageY + 'px';
this.cont++;
})
}
ngOnDestroy()
{
this.subscription.unsubscribe()
}
In the e.g. (see stackblitz) I use throttleTime to not emit a new event until 200 miliseconds (you can change to 100 or 150)
I'm using the following code for a progress bar:
<div class="slide-progress-bar">
<div class="progress-bar" id="progress-bar"></div>
<!--progress-bar-->
</div>
<script>
var elem = document.getElementById("progress-bar");
var width = 1;
function progressBar() {
resetProgressBar();
id = setInterval(frame, 300);
function frame() {
if (width >= 100) {
clearInterval(id);
} else {
width++;
elem.style.width = width +"%";
}
}
}
function resetProgressBar() {
width = 1;
elem.style.width = width;
}
progressBar()
</script>
<style>
.slide-progress-bar {
width: 150px;
background-color:rgba(155, 155, 155, 0.36);
transition: width 10s linear;
display: inline-block;
vertical-align: middle;
margin: auto;
width: 100%;
}
.progress-bar {
height: 5px;
background-color: #ff4546;
position: relative;
transition: linear;
}
</style>
It works fine (when the page loads, progress bar starts and completes 300frames) but when I switch the tab or minimizes the window it stops and when I reopen the tab, it resumes. I don't want this top happen. I want the progress bar to continue loading even when not in focus. Is there way to do so ?, cause I saw such progress bars on may other sites.
Set Interval stops when page is minimize. You can use Date object to check how many time pass since progress bar starts loading.
<div class="slide-progress-bar">
<div class="progress-bar" id="progress-bar"></div>
<!--progress-bar-->
</div>
<script>
var animationTimeInMiliseconds = 30000; //30s
var interval = 300;
var elem = document.getElementById("progress-bar");
var beginningDate = new Date().getTime(); // Time in miliseconds
function progressBar() {
resetProgressBar();
id = setInterval(frame, interval);
function frame() {
var milisecondsFromBegin = new Date().getTime() - beginningDate;
var width = Math.floor(milisecondsFromBegin / animationTimeInMiliseconds * 100);
elem.style.width = width + "%";
if (width >= 100) {
clearInterval(id);
}
}
}
function resetProgressBar() {
elem.style.width = 0;
}
progressBar()
</script>
<style>
.slide-progress-bar {
width: 150px;
background-color:rgba(155, 155, 155, 0.36);
transition: width 10s linear;
display: inline-block;
vertical-align: middle;
margin: auto;
width: 100%;
}
.progress-bar {
height: 5px;
background-color: #ff4546;
position: relative;
transition: linear;
}
</style>
You can use css3 transitions instead of js animations to solve the problems you are facing.
You can read more about it here
Adding an example for your reference.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<style>
.slide-progress-bar {
width: 150px;
background-color:rgba(155, 155, 155, 0.36);
transition: width 10s linear;
display: inline-block;
vertical-align: middle;
margin: auto;
width: 100%;
}
.slide-progress-bar .progress-bar {
height: 5px;
background-color: #ff4546;
position: relative;
transition: linear;
animation: progres 4s infinite linear;
}
#keyframes progres{
0%{
width: 0%;
}
25%{
width: 50%;
}
50%{
width: 75%;
}
75%{
width: 85%;
}
100%{
width: 100%;
}
};
</style>
</head>
<body>
<div class="slide-progress-bar">
<div class="progress-bar"></div>
</div>
</body>
</html>
I have a custom cursor on my site that is working perfectly apart from one thing. When clicking through to a new page, when the page loads the cursor resets itself to the top left of the page regardless of where you leave the mouse on the page, then once you moved the mouse the cursor moves back to where the mouse is. I have tried removing "top" & "left" from the CSS but the problem remains. I cant see what is causing this to happen, and I just need the cursor to stay where the mouse is positioned on the page and not reset every time you navigate to a new page.
jQuery(document).ready(function($) {
let cursor = document.querySelector('#custom-cursor');
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i.test(navigator.userAgent)) {
$('#custom-cursor').remove();
}
else { cursor.style.display = 'block';}
document.addEventListener('mousemove', evt => {
let { clientX: x, clientY: y } = evt;
let scale = 1;
if (evt.target.matches('a,span,[onclick],img,video,i')) {
cursor.classList.add('active');
scale = 0.5;
} else {
cursor.classList.remove('active');
}
cursor.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
});
});
* {
cursor: none;
}
#custom-cursor {
display: none;
position: fixed;
width: 20px; height: 20px;
top: -10px;
left: -10px;
border: 2px solid black;
border-radius: 50%;
opacity: 1;
background-color: #fb4d98;
pointer-events: none;
z-index: 99999999;
transition:
transform ease-out 0.15s,
border 0.5s,
opacity 0.5s,
background-color 0.5s;
}
#custom-cursor.active {
opacity: 0.5;
background-color: #000;
border: 2px solid #fb4d98;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="custom-cursor"></div>
Use ordinary CSS cursor as shown in the other answer and replace it with you fancy cursor in the first mouse event:
jQuery(document).ready(function($) {
let cursor = document.querySelector('#custom-cursor');
document.addEventListener('mousemove', evt => {
document.body.classList.add('custom-cursor-moved')
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i.test(navigator.userAgent)) {
$('#custom-cursor').remove();
} else {
cursor.style.display = 'block';
}
let {
clientX: x,
clientY: y
} = evt;
let scale = 1;
if (evt.target.matches('a,span,[onclick],img,video,i')) {
cursor.classList.add('active');
scale = 0.5;
} else {
cursor.classList.remove('active');
}
cursor.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
});
});
body {
height: 100vh;
}
html,
body {
margin: 0;
padding: 0;
}
* {
cursor: url(https://i.stack.imgur.com/7pmmV.png) 0 0, auto;
}
.custom-cursor-moved,
.custom-cursor-moved * {
cursor: none !important;
}
#custom-cursor {
display: none;
position: fixed;
width: 20px;
height: 20px;
top: -10px;
left: -10px;
border: 2px solid black;
border-radius: 50%;
opacity: 1;
background-color: #fb4d98;
pointer-events: none;
z-index: 99999999;
transition: transform ease-out 0.15s, border 0.5s, opacity 0.5s, background-color 0.5s;
}
#custom-cursor.active {
opacity: 0.5;
background-color: #000;
border: 2px solid #fb4d98;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="custom-cursor"></div>
Try me.<br> Try me.
It needs a bit of modifications (better cursor image, fix it hotspot etc.) but it works.
Be very, very careful when doing such thing. Try to not break any accessibility tools and please do not assume that Android/some specific user-agent HAS touchscreen, etc.. Use proper APIs.
Use CSS cursor property instead:
html {
cursor: url(https://cdn.sstatic.net/Sites/stackoverflow/Img/favicon.ico?v=ec617d715196) 0 0, auto;
height: 100%;
}
Try me.
I've found this script for a progress bar. It runs smoothly from 100% to 0% after clicking the button.
But how can I reset the progress bar after it hits the 0? I'm planning to use this script in a slideshow and it should be 100% again after it reaches 0.
Hope you can help me in the right direction.
Thnx,
Leon
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
You can reset the progress bar by removing the complete class.
document.querySelector("button.start").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
document.querySelector("button.reset").addEventListener("click", () => {
let className = document.querySelector(".progress").className;
if (className.indexOf(' complete') > -1) {
className = className.substr(0, className.indexOf(' complete'));
document.querySelector(".progress .bar").style.transitionDuration = "0s";
document.querySelector(".progress").className = className;
}
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button class="start">
Start
</button>
<button class="reset">
Reset
</button>
If you want this to be dynamic without any user interaction, you can use setTimeout, set to the same duration used in your animationDuration, within your click event Handler to reset the transition and remove the complete class.
const start = document.querySelector("#start")
const progressBar = document.querySelector(".progress .bar")
const progress = document.querySelector(".progress")
function resetProgressBar(){
progressBar.style.transitionDuration = "10s"
progress.classList.add("complete")
setTimeout(() => {
progress.classList.remove("complete")// <-- remove the class with width:0
progressBar.style.transitionDuration = "0.1s" //<-- Add a very small transitionDuration or none if you prefer
}, 10000)// <-- Set this timeout duration to the same as your transitionDuration
}
start.addEventListener("click", resetProgressBar);
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button id="start">
Start
</button>
For selector .progress .bar, use a listener for event transitionend, because you are using transition rules in css:
The transitionend event is fired when a CSS transition has completed.
Inside this event listener, set transitionDuration to the default value. And in the next step, remove class complete from .progress, which will return the previous width of the progress bar.
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
document.querySelector(".progress .bar").addEventListener("transitionend", () => {
document.querySelector(".progress.complete .bar").style.transitionDuration = "";
document.querySelector(".progress").classList.remove("complete");
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
Thnx for all your suggestions. I've implemented the last suggestion into my slideshow script.
It is running and it is refreshing after slide change. But somewhere on the ride it stops, I think it's confused when to start the progress bar.
Anyone an idea to make this more solid?
jQuery('.owl-carousel').owlCarousel({
items: 1,
margin: 0,
nav: false,
dots: false,
slideBy: 1,
rewind: false,
autoplay: true,
autoplayTimeout: 5000,
autoplaySpeed: 10000,
loop: true,
animateOut: 'fadeOut',
responsive: false,
mouseDrag: false,
touchDrag: false,
lazyLoadEager: 2
});
jQuery('.owl-carousel').on('changed.owl.carousel', function(event) {
document.querySelector(".progress .bar").style.transitionDuration = "5s";
document.querySelector(".progress").className += " complete";
})
document.querySelector(".progress .bar").addEventListener("transitionend", () => {
document.querySelector(".progress.complete .bar").style.transitionDuration = "5";
document.querySelector(".progress").classList.remove("complete");
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
What I'm trying to do is make it so that if you click on a button (suppose "scroll to left"), it starts scrolling to left and would not stop until I pressed another button (a "stop" button) to stop it.
function co() {
coo=document.getElementById('tar');
var x = coo.style.left;
var y=(x+=10);
coo.style.left=y+'px';
}
div {
position:absolute;
background-color:orange;
border-radius:50%;
width:100px;
height:100px;
transition-duration:2s;
}
body {
width:100%;
height:100%;
}
.plus {
z-index:2;
position:absolute;
background-color:#CCC;
right:15px;
bottom:10px;
}
<body >
<div id="tar"></div>
<button class="plus" onClick="co()">Plus this</button>
</body>
Just use setInterval to repeat your function in a loop and user clearInterval to cancel
Also, you might want to prevent Plus This from being clicked again when the animation is running.
Code Snippet
var cog;
function co() {
// the first run need not have a delay
cot();
cog = setInterval(cot, 500)
}
function nco() {
clearInterval(cog)
}
function cot() {
var coo = document.getElementById('tar');
var x = window.getComputedStyle(coo, null).left;
var y = Number(x.replace('px', '')) + 100;
coo.style.left = y + 'px';
}
div#tar {
left: 10px;
position: absolute;
background-color: orange;
border-radius: 50%;
width: 100px;
height: 100px;
transition-duration: 0.5s;
transition-timing-function: linear;
}
body {
width: 100%;
height: 100%;
}
.plus {
z-index: 2;
position: absolute;
right: 15px;
bottom: 10px;
}
<body>
<div id="tar"></div>
<div class='plus'>
<button onClick="co()">Plus this</button>
<button onClick="nco()">Stop</button>
</div>
</body>