Simple hover controls - javascript

So I have few squares, and when I hover over one, i want a menu to show up. Then, when I hover out, i want it to disappear. Simple right?
So the problem is when I move my mouse very fast over them, some of them stay... hidden. I can resign from squares going transparent, but my mouseout event is not fired right too.. because my mouse is far away, and my black menu is still on top of a square!
So fading out pink squares is more to show the issue. I am most troubled by black square not disappearing.
$(document).ready(function() {
$('.square').mouseenter(faceon);
$('#hover_controls').mouseleave(faceout);
});
function faceon() {
$(this).stop().clearQueue().fadeTo("slow", 0.15);
$('#hover_controls').stop().clearQueue().css({
top: $(this).offset().top + "px",
left: $(this).offset().left + "px",
display: 'block'
}).fadeTo("fast", 1);
}
function faceout(event) {
var e = event.toElement || event.relatedTarget;
if (e.parentNode == this || e == this) {
return;
}
$('.square').stop().clearQueue().fadeTo("slow", 1);
$('#hover_controls').stop().clearQueue().fadeTo("fast", 0, function() {
$(this).hide();
});
}
.square {
height: 72px;
width: 72px;
background: pink;
margin: 5px;
display: inline-block;
}
#hover_controls {
display: none;
height: 62px;
width: 62px;
opacity: 0;
padding: 5px;
position: fixed;
background: #000;
border-radius: 10px;
z-index: 2;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='hover_controls'>
<a href='#' onclick='alert("aaa");'>a</a>
<a href='#' onclick='alert("bbbb");'>b</a>
</div>
<div class="list">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>
Any ideas?

Replace mouseover and mouseout with mouseenter and mouseleave respectively. I hope this helps.

Change the event handler, fix issue wtih e in the conditional if mouse out fast where e is null.
The complication here is the mouseenter/mouseleave and the animation - note that those events are on different elements, one of which you show/hide when the events trigger. Thus it is likely the mouseleave event does not properly trigger ALL the time due to the element it is hooked to not being visible on a "fast mouse" action behavior.
$(document).ready(function() {
$('.square').on("mouseenter", faceon);
$('#hover_controls').on("mouseleave", faceout);
});
function faceon() {
$(this).stop().clearQueue().fadeTo("slow", 0.15);
$('#hover_controls').stop().clearQueue().css({
top: $(this).offset().top + "px",
left: $(this).offset().left + "px",
display: 'block'
}).fadeTo("fast", 1);
}
function faceout(event) {
var e = event.toElement || event.relatedTarget;
if (e && (e.parentNode == this || e == this)) {
return;
}
$('.square').stop().clearQueue().fadeTo("slow", 1);
$('#hover_controls').stop().clearQueue().fadeTo("fast", 0, function() {
$(this).hide();
});
}
.square {
height: 72px;
width: 72px;
background: pink;
margin: 5px;
display: inline-block;
}
#hover_controls {
display: none;
height: 62px;
width: 62px;
opacity: 0;
padding: 5px;
position: fixed;
background: #000;
border-radius: 10px;
z-index: 2;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='hover_controls'>
<a href='#' onclick='alert("aaa");'>a</a>
<a href='#' onclick='alert("bbbb");'>b</a>
</div>
<div class="list">
<div class="square"></div>
<div class="square"></div>
<div class="square"></div>
</div>

Related

Horizontal scroll areas with buttons and gradients

This is my code so far:
// Show and hide gradients
$(document).ready(function() {
$(".scroll-area").each(function(index) {
if ($(this)[0].scrollWidth <= $(this)[0].clientWidth) {
$(this).closest(".container").find(".left").css("display", "none");
$(this).closest(".container").find(".right").css("display", "none");
} else {
$(this).scroll(function() {
if ($(this)[0].scrollWidth > $(this)[0].clientWidth) {
if ($(this).scrollLeft() > 0) {
$(this).closest(".container").find(".left").css("display", "block");
}
if ($(this).scrollLeft() == 0) {
$(this).closest(".container").find(".left").css("display", "none");
}
var fullWidth = $(this)[0].scrollWidth - $(this)[0].offsetWidth - 1;
if ($(this).scrollLeft() >= fullWidth) {
$(this).closest(".container").find(".right").css("display", "none");
}
if ($(this).scrollLeft() < fullWidth) {
$(this).closest(".container").find(".right").css("display", "block");
}
}
});
}
});
});
// Scroll buttons
let interval;
$('.scroll-btn').on('mousedown', ({
target
}) => {
const type = $(target).attr('id');
interval = setInterval(() => {
var x = $('#a').scrollLeft();
$('#a').scrollLeft(type === 'left-arrow' ? x - 10 : x + 10);
}, 50);
});
$('.scroll-btn').on('mouseup', () => clearInterval(interval));
* {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 16px;
}
.container {
width: 550px;
height: 80px;
background-color: grey;
position: relative;
margin-bottom: 20px;
}
.scroll-area {
white-space: nowrap;
overflow-x: auto;
height: 100%;
}
.left,
.right {
width: 50px;
height: 100%;
position: absolute;
pointer-events: none;
top: 0;
}
.left {
background: linear-gradient(90deg, orange 0%, rgba(0, 0, 0, 0) 100%);
left: 0;
display: none;
}
.right {
background: linear-gradient(-90deg, orange 0%, rgba(0, 0, 0, 0) 100%);
right: 0;
}
.arrow {
display: block;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 15px;
cursor: pointer;
}
.left-arrow {
left: 0;
}
.right-arrow {
right: 0;
}
.left-arrow div,
.right-arrow div {
font-size: 40px;
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<div class="container">
<div id="x" class="left"></div>
<div class="right"></div>
<div class="arrow left-arrow">
<div class="scroll-btn" id="left-arrow">
<</div>
</div>
<div class="arrow right-arrow">
<div class="scroll-btn" id="right-arrow">></div>
</div>
<div id="a" class="scroll-area">
<div class="text">Scroll to right. The gradients and arrows should appear and disappear based on the scroll position. It should work with more than one container. Lorem ipsum.</div>
</div>
</div>
The needs are:
The arrows should appear and disappear in the same way like the gradients.
If there is not enough text to cause a scrollable area, there should be no gradient and now arrow.
There should be more than one container in the end.
Can somebody help me to do that? I would be super thankful!
You can put your arrows inside the left/right gradient divs. That way they will show/hide same way as the gradients.
EDIT
I cleaned up the code a bit since the original answer was kinda messy. (or 'weird' as mstephen19 put it :)).
// Show gradient and left/right arrows only if scrollable
$(".scroll-area").each((i, el) => {
$(el).parent().find(".right")[el.scrollWidth > el.clientWidth ? "show" : "hide"]();
});
// Show/hide gradient and arrows on scroll
$('.scroll-area').scroll((e) => {
const fullWidth = $(e.target)[0].scrollWidth - $(e.target)[0].offsetWidth - 1;
const left = $(e.target).scrollLeft()
$(e.target).parent().find(".left, .left-arrow")[left > 0 ? "show" : "hide"]();
$(e.target).parent().find(".right, .right-arrow")[left < fullWidth ? "show" : "hide"]();
});
// Scroll on left/right arrow mouse down
let intervalId;
$(".left-arrow, .right-arrow").on("mousedown", (e) => {
const scroll = $(e.target).closest(".container").find(".scroll-area");
intervalId = setInterval(() => {
const left = scroll.scrollLeft();
scroll.scrollLeft(e.target.classList.contains("left-arrow") ? left - 10 : left + 10);
}, 50);
}).on("mouseup mouseleave", () => {
clearInterval(intervalId);
});
* {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 16px;
}
.container {
width: 550px;
height: 80px;
background-color: grey;
position: relative;
margin-bottom: 20px;
margin-left: 20px;
}
.scroll-area {
white-space: nowrap;
overflow-x: auto;
height: 100%;
}
.left,
.right {
width: 50px;
height: 100%;
position: absolute;
top: 0;
}
.left {
background: linear-gradient(90deg, orange 0%, rgba(0, 0, 0, 0) 100%);
left: 0;
display: none;
}
.right {
background: linear-gradient(-90deg, orange 0%, rgba(0, 0, 0, 0) 100%);
right: 0;
text-align: right;
}
.left-arrow,
.right-arrow {
margin: 0 10px;
position: absolute;
top: 50%;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
cursor: pointer;
user-select: none;
font-size: 40px
}
.left-arrow {
display: none;
left: -25px;
}
.right-arrow {
right: -25px;
}
<html>
<head>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
<div class="left-arrow"><</div>
<div class="right-arrow">></div>
<div class="scroll-area">
<div class="text">Scroll to right. The gradients and arrows should appear and disappear based on the scroll position. It should work with more than one container. Lorem ipsum.</div>
</div>
</div>
<div class="container">
<div class="left"><span class="left-arrow"><</span></div>
<div class="right"><span class="right-arrow">></span></div>
<div class="scroll-area">
<div class="text">No scroll.</div>
</div>
</div>
</body>
</html>
Some things about your code:
Your original code would not work with multiple containers, because you had a hardcoded #a ID in the interval code. You should really only have IDs on one element ideally, anyways (they're unique identifiers, while classes can be placed on multiple elements). The .scroll-area element should be found based on the target clicked.
You should combine your gradient and arrow elements into one element. By that, I mean making the div in which the arrow lives should be a child of the gradient div. Why manage them both separately?
Use class adding/removing/toggling instead of directly setting the CSS. Remember - when you find yourself writing the same code multiple times, it usually means there is a way to condense it down and make your code more dry and easier to understand + read.
Don't use the literal < and > symbols, as it can confuse some browsers. Use < and > instead.
Rather than toggling display to none and block, it's better to use visibility in this specific case. In my example, we use opacity for a fun fading effect.
Don't forget to listen for both mouseup mouseout events :)
Here is the working solution. I've refactored the code a bit:
let interval;
$('.arrow').on('mousedown', ({ target }) => {
const type = target.classList[1];
const scrollArea = $(target).parent().find('.scroll-area');
interval = setInterval(() => {
const prev = scrollArea.scrollLeft();
scrollArea.scrollLeft(type === 'left-arrow' ? prev - 10 : prev + 10);
}, 50);
});
$('.arrow').on('mouseup mouseout', () => clearInterval(interval));
$('.scroll-area').on('scroll', ({ target }) => {
const left = $(target).parent().find('.left-arrow');
const right = $(target).parent().find('.right-arrow');
const scroll = $(target).scrollLeft();
const fullWidth = $(target)[0].scrollWidth - $(target)[0].offsetWidth;
if (scroll === 0) left.addClass('hide');
else left.removeClass('hide');
if (scroll > fullWidth) right.addClass('hide');
else right.removeClass('hide');
});
.container {
width: 550px;
height: 80px;
background: grey;
position: relative;
}
.right-arrow,
.left-arrow {
height: 100%;
width: 50px;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
cursor: pointer;
transition: all 0.2s linear;
}
.scroll-area {
white-space: nowrap;
overflow-x: scroll;
height: 100%;
}
.right-arrow {
background: linear-gradient(-90deg, orange 0%, rgba(0, 0, 0, 0) 100%);
left: 500px;
}
.left-arrow {
background: linear-gradient(90deg, orange 0%, rgba(0, 0, 0, 0) 100%);
left: 0px;
}
.scroll-btn {
pointer-events: none;
}
.hide {
opacity: 0;
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<div class="container">
<div class="arrow left-arrow">
<div class="scroll-btn" id="left-arrow"><</div>
</div>
<div class="arrow right-arrow">
<div class="scroll-btn" id="right-arrow">></div>
</div>
<div class="scroll-area">
<div class="text">
Scroll to right. The gradients and arrows should appear and disappear based on the scroll position. It should work with more than one
container. Lorem ipsum.
</div>
</div>
</div>
PS: If you don't like the fade effect, remove the transition: all 0.2s linear; part of the CSS, and switch .hide's opacity: 0 to visibility: hidden.

Randomly toggle CSS tag using JS JQUERY

I'm making a random image that changes when the mouse enter in a div with testarea class.
Mouse enter Div, toggle the 'off-cursor' tag of the image randomly.
I have referred to several sites.
but, I am JS and JQUERY beginners. I don't know how to complete it.
I'd be very grateful if you could help me.
const Cursor = document.querySelectorAll('.cursor');
function getRdCursor() {
const index = Math.floor(Math.random() * Cursor.length);
return Cursor[index];
};
$(function () {
$(".testarea").mousemove(function (e) {
$(".cursor").show().css({
"left": e.clientX,
"top": e.clientY
});
}).mouseout(function () {
$(".cursor").hide();
});
});
.testarea {
border: 1px dashed #ccc;
height: 100px;
margin: 100px 100px 100px 100px;
cursor: none;
}
.cursor {
position: absolute;
width: 5%;
height: auto;
left: -100px;
cursor: none;
pointer-events: none;
transform: translate(-50%,-50%);
}
.off-cursor {
visibility: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img src="https://media.giphy.com/media/tJ1jipvvMs4r7xuZnI/giphy.gif" alt="Cursor" class="cursor" />
<img src="https://media.giphy.com/media/XFpIo4jKuUrjQHYHeq/giphy.gif" alt="Cursor" class="cursor off-cursor" />
<img src="https://media.giphy.com/media/uxunn6z4qKrGsND3II/giphy.gif" alt="Cursor" class="cursor off-cursor" />
<img src="https://media.giphy.com/media/XxRl7rbKSFvXEFoNzv/giphy.gif" alt="Cursor" class="cursor off-cursor" />
<div class="testarea"></div>
<div class="testarea"></div>
<div class="testarea"></div>
<div class="testarea"></div>

Avoid mousemove on absolutely positioned children elements

I am trying to understand mousemove Event on absolute elements.
I made a Codepen to demonstrate what i wanted.
I need mousemove to be captured on #main element, But not on any of its children that are positioned absolutely.
HTML:
<div id="main">
<div class="btn">Click Me</div>
</div>
<div id="output">
</div>
JS:
$(document).ready(function(){
$('#main').on('mousemove',function( e ) {
var msg = "mouse move ";
msg += e.pageX + ", " + e.pageY;
$( "#output" ).html(msg);
});
});
Simply check who's the target in your event handler, and if it is one of those you want to block the event, return early.
In current configuration, it is the same as checking if the target is indeed #main, a.k.a jQuery's $event.currentTarget.
$('#main').on('mousemove', function(e) {
// here we only want the events of #main
// so any other target is irrelevant
if (e.target !== e.currentTarget) return;
var msg = "mouse move ";
msg += e.pageX + ", " + e.pageY;
$("#output").html(msg);
});
$('#main').on('mouseout', function() {
$("#output").html('');
});
$('#main>.btn').on('click', e=> $("#output").html('can still click'));
#main {
float: left;
background: yellow;
width: 400px;
height: 400px;
position: relative;
}
#main .btn {
position: absolute;
top: 20px;
left: 20px;
z-index: 2;
border: 0;
background: blue;
color: #FFF;
}
#main .btn .innerbtn {
padding: 10px;
}
#output {
display: inline-block;
background: #efefef;
width: 200px;
position: absolute;
right: 0;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="main">
<div class="btn">
<div class="innerbtn">Click Me</div>
</div>
</div>
<div id="output">
</div>

slide right to left div on hover jquery

Good day,
I'm having trouble with jquery. i found a topic here that i want to learn using jquery slide right to left div http://jsfiddle.net/PXLJG/2/.
what i want to achieve is when hover, show hidden content on specific div.
i tried adding .addClass('active'); to the script.
here is the script i made
$(document).ready(function(){
$('.holdingbox').hover(function(){
var rightbox = $('.rightbox');
if (rightbox.hasClass('active')){
rightbox.stop().animate({width: '-0px'}, 1000).removeClass('active');
} else {
rightbox.stop().animate({width: '90px'}, 1000).addClass('active');
}
});
});
The problem now is when i hover on one div, all div shows up.Please see attached image.
Hope you guys can point me to right direction. thank you
You need to target the rightbox element in current element context i.e. this
You can either use context or .find() to target child element.
$('.holdingbox').hover(function() {
var rightbox = $('.rightbox', this); //$(this).find('.rightbox')
});
$(document).ready(function() {
$('.holdingbox').hover(function() {
var rightbox = $('.rightbox', this);
if (rightbox.hasClass('active')) {
rightbox.stop().animate({
width: '-0px'
}, 1000).removeClass('active');
} else {
rightbox.stop().animate({
width: '90px'
}, 1000).addClass('active');
}
});
});
div {
display: inline-block;
}
.holdingbox {
position: relative;
top: 0;
margin-left: 100px;
}
.leftbox {
position: relative;
top: 0;
left: 0;
display: inline-block;
font-size: 24px;
background-color: #ac193d;
color: #FFF;
font-weight: bold;
padding: 1px;
}
.rightbox {
position: relative;
display: inline-block;
overflow: hidden;
width: 0;
height: 30px;
vertical-align: top;
margin-right: 0;
}
.content {
width: 100px;
position: absolute;
background-color: #ac193d;
height: 29px;
left: 0;
top: 0;
right: 0;
color: #FFF;
padding-left: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="holdingbox">
<span class="rightbox"><span class="content">Kenyér</span></span>
<span class="leftbox">></span>
</div>
<div class="holdingbox">
<span class="rightbox">
<span class="content">Kenyér</span>
</span>
<span class="leftbox">></span>
</div>
Change code to this
You'll get children of the hovered element this way. Without using $(this) you target all '.rightbox' elements in document.
$('.holdingbox').hover(function(){
$(this).find('.rightbox').stop().animate({width: '90px'}, 1000)
}, function(){
$(this).find('.rightbox').stop().animate({width: '-0'}, 1000)
});

Custom Drag & Drop not working perfectly

I want to drag a div and drop anywhere in its parent div . For dragging I use css style
draggable="true"
and for drop, I use 'mousemove' event X and Y values and use this values for div top and left .The code I used is
$(".drop").mousedown(function () {
$(this).mousemove(function (e) {
var k = e.clientX ;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top",f);
$(".drop").css("left",k);
});
}).mouseup(function () {
$(this).unbind('mousemove');
}).mouseout(function () {
$(this).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" draggable="true" ></div>
<div>
Now it's drag & drop if I drag with increasing left value. But if I drag with decreasing left value it's not dropping. And how I stop the drag if it reach the end of the main div(GridPart)?
I have fixed your code. All you did is quite good but you should have to use the mousemove event with $(document) element and not with the div. Since when you drag backwards, mouse movement is going out of the div and so its no longer dragging.
Also, as you used custom dragging, you don't need to use draggable="true".
$(".drop").mousedown(function () {
$(document).mousemove(function (e) {
var k = e.clientX;
var f = e.clientY;
$(".drop").text(k+ ", " + f);
$(".drop").css("top", f + 'px');
$(".drop").css("left", k + 'px');
});
});
$(document).mouseup(function () {
$(document).unbind('mousemove');
});
.drop{
position: absolute;
left: 300;
top: 200; /* set these so Chrome doesn't return 'auto' from getComputedStyle */
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
}
.gridPart{
padding: 20px;
background-color: #FFF;
border-radius: 5px;
margin: auto;
margin: 20px;
padding-right: 0px;
padding-bottom: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gridpart">
<div class="drop" ></div>
<div>
Simply use the JQueryUi Draggable:
https://jqueryui.com/draggable/
UPDATE: sample code here:
http://embed.plnkr.co/5W3ACU/
I think what i have discerned from your question you are trying to do, is limit dragging to within the .gridpart div.
The key was moving the drag detection to the container div, and then moving the drag component based on the mousedown position
JSFIDDLE
JS
$(".gridpart").mousedown(function () {
var containerDims = $(this)[0].getBoundingClientRect();
var dropEl = $(this).find('.drop');
// measure the size of the drop element
var dropDims = dropEl[0].getBoundingClientRect()
$(this).mousemove(function (e) {
// position the element centered under the cursor
var k = e.clientX - dropDims.width / 2;
var f = e.clientY - dropDims.height / 2;
if( k >= 0 && k <= containerDims.width - dropDims.width){
dropEl.css("left",k);
}
if(f >= 0 && f <= containerDims.height - dropDims.height){
dropEl.css("top", f);
}
dropEl.text(k + ', ' + f);
});
}).mouseup(function () {
$(this).unbind('mousemove');
});
CSS
.drop{
position: absolute;
left: 0;
top: 20px;
width: 200px;
background: rgba(255,255,255,0.66);
border: 2px solid rgba(0,0,0,0.5);
border-radius: 4px; padding: 8px;
z-index: 3;
/* prevent 'shadow' drag preventing mouseup firing */
-webkit-user-drag: none;
-khtml-user-drag: none;
-moz-user-drag: none;
-o-user-drag: none;
user-drag: none;
}
.gridpart{ /* correct camelcase typo */
background-color: #F00;
border-radius: 5px;
margin: 20px;
padding-right: 0px;
position: relative;
height: 58px;
}
HTML
<div class="gridpart">
<div class="drop" draggable="true">0, 0</div>
<div>

Categories

Resources