I'm creating a custom cursor for a site. I've gotten two divs centered to the cursor when the mouse moves but when I hover on an anchor tag the position of the background cursor is off. I've tried using pageX and pageY to center it in the for loop but it doesn't seem to work. Help?
Here is my HTML:
<div class="cursor"></div>
<div class="cursor-bg"></div>
CSS:
.cursor{
height:10px;
width:10px;
border-radius:50%;
position:absolute;
background: #fff;
z-index: 100;
}
.cursor-bg{
height:30px;
:30px;
border-radius:50%;
position:absolute;
background: $lightCursor-bg;
transition-duration: 400ms;
transition-timing-function: ease-out;
}
.expand{
width: 100px;
height: 100px;
position: absolute;
border:solid 1px #fff;
background: rgba(255,255,255, 0);
}
JS:
(function(){
var cursor = document.querySelector('.cursor');
var cursorBg = document.querySelector('.cursor-bg');
var navLinks = document.querySelectorAll('a');
document.addEventListener('mousemove', e => {
cursor.style.left = (e.pageX - 5) + 'px';
cursor.style.top = (e.pageY - 5) + 'px';
cursorBg.style.left = (e.pageX - 15) + 'px';
cursorBg.style.top = (e.pageY -15) + 'px';
});
for (var i = 0; i < navLinks.length; i++) {
var singleLink = navLinks[i];
singleLink.addEventListener('mouseover', e => {
cursorBg.classList.add("expand");
cursorBg.style.left = (e.pageX - 50) + 'px';
cursorBg.style.left = (e.pageY - 50) + 'px';
})
singleLink.addEventListener('mouseout', e => {
cursorBg.classList.remove("expand");
})
}
})();
You can use the css cursor property for this:
cursor: url(https://example.com/your-image.png), auto
Demo:
div {
width: 200px;
height: 200px;
background: dodgerblue;
padding: 10px;
}
.custom-cursor {
background: red;
cursor: url('https://i.imgur.com/ng6jKDk.png'), auto
}
p {
font-family: sans-serif;
text-align: center;
font-size: 36px;
}
<div class="custom-cursor">
<p>Custom Cursor in this div only!</p>
</div>
<div>
<p>Not in this div!</p>
</div>
If you want the cursor to apply to the entire page, just add the css to the body.
CSS cursor property
Related
I'm trying to build a sort of crosshair which is surrounded by a circle that zooms an image to shoot more precisely. The behavior I want is that crosshair which is also my mouse pointer can move inside of the circle and once it touches the edge of my circle from the inside it moves it to the wanted position. For now, I can only move my circle having crosshair fixed in the middle. Could you please help me to have it moving within my circle?
jQuery(document).ready(function() {
var onBoxX = 0, onBoxY = 0;
var circleWidth = 120;
var circleHeight = 120;
var circleBorderWidth = 1;
var boxWidth = 500;
var boxHeight = 500;
var circleLeft = 0;
var circleTop = 0;
$(box).mousemove(function(event){
// console.log(event);
onBoxX = event.clientX;
onBoxY = event.clientY;
circleLeft = (onBoxX - circleWidth / 2 - circleBorderWidth)/ boxWidth * 100
circleTop = (onBoxY - circleHeight / 2 - circleBorderWidth)/ boxWidth *100
$("#circle").css({left: circleLeft+'%', top: circleTop+'%'});
});
$(circle).mousemove(function(event){
console.log("circle mousemove",event.offsetX, event.offsetY);
});
})
body{
margin:0px;
padding:0px;
font-family: 'Roboto', sans-serif;
}
.box{
width:500px;
height:500px;
background:#000000;
position:relative;
cursor:crosshair;
overflow: hidden;
}
.circle {
position: relative;
background: black;
border: solid 1px #ccc;
width:120px;
height:120px;
border-radius: 50%;
}
.crosshair{
position: absolute;
background-color: white;
width:20px;
height:20px;
left:41.5%;
top:41.5%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="box" class="box">
<div id="circle" class="circle">
<div id="crosshair" class="crosshair"></div>
</div>
</div>
I refactored it a bit and added code to detect when cursor is outside of circle.
jQuery(document).ready(function () {
var cursorX = 0,
cursorY = 0;
var circleRadius = 60;
var circleX = 0;
var circleY = 0;
function updateCursorCoords(x, y) {
cursorX = x;
cursorY = y;
}
function updateCircleCoords() {
// First define if cursor is inside circle
var distX = Math.abs(circleX + circleRadius - cursorX);
var distY = Math.abs(circleY + circleRadius - cursorY);
var dist = Math.sqrt(Math.pow(distY, 2) + Math.pow(distX, 2));
var cursorIsInside = dist < circleRadius;
// And update its position only when cursor is outside of circle
if (!cursorIsInside) {
circleX = cursorX - circleRadius;
circleY = cursorY - circleRadius;
}
}
function drawCircle() {
$("#circle").css({ left: circleX + "px", top: circleY + "px" });
}
$(box).mousemove(function (event) {
updateCursorCoords(event.clientX, event.clientY);
updateCircleCoords();
drawCircle();
});
});
body {
margin:0px;
padding:0px;
font-family: 'Roboto', sans-serif;
}
.box {
width:500px;
height:500px;
background:#000000;
position:relative;
cursor:crosshair;
overflow: hidden;
}
.circle {
position: relative;
background: black;
border: solid 1px #ccc;
width:120px;
height:120px;
border-radius: 50%;
box-sizing: border-box;
}
.crosshair {
position: absolute;
background-color: white;
width:20px;
height:20px;
left:41.5%;
top:41.5%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="box" class="box">
<div id="circle" class="circle">
<div id="crosshair" class="crosshair"></div>
</div>
</div>
I'm trying to make it so that when hovering over a div, the child of that div attaches to the cursor and when you leave the div, the child returns to its original position.
Here's what I have so far:
$('div').each(function() {
var img = $(this).find( "figure" );
var offset = img.offset();
var originLeft = offset.left;
var originTop = offset.top;
$('div').mousemove(function(e) {
img.addClass('active');
img.css({
transform: 'translateX(' + (e.pageX - originLeft/2 ) + 'px) translateY(' + (e.pageY - originTop) + 'px)'
});
}).mouseleave(function() {
img.removeClass('active');
img.css({
transform: 'translateX(0) translateY(0)'
});
});
});
div {
height: 250px;
width: 250px;
background: #eee;
}
div:nth-child(2) {
background: #ccc;
}
figure {
display: block;
height: 50px;
width: 50px;
background: blue;
margin: 0;
transition: transform 500ms ease;
}
.active {
transition: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<figure></figure>
</div>
<div>
<figure></figure>
</div>
The problems are, it doesn't work if there is more than one of them on the page, and also, the mouseleave event seems buggy: sometimes it takes a second or there is some flickering before it returns to the original position.
Using mouseenter to add the mousemove listener and removing it in the mouseleave solves most of the issue. The other part is that if the image is directly under the mouse when it leaves the container, the mouse is still on top of a child .
Adding some additional offset to the image position relative to mouse helps remove the rest of the bugginess
$('div').on('mouseenter', function() {
var img = $(this).find("figure");
var offset = img.offset();
var originLeft = offset.left;
var originTop = offset.top;
// only listen to move on this instance
$(this).mousemove(function(e) {
img.addClass('active').css({
transform: 'translateX(' + (e.pageX - originLeft / 2) + 'px) translateY(' + (e.pageY+10 - originTop) + 'px)'
});
})
}).on('mouseleave', function() {
// remove the mousemove listener
$(this).off('mousemove').find("figure").removeClass('active').css({
transform: 'translateX(0) translateY(0)'
});
});
div {
height: 150px;
width: 150px;
background: #eee;
margin-bottom: 30px
}
div:nth-child(2) {
background: #ccc;
}
figure {
display: block;
height: 50px;
width: 50px;
background: blue;
margin: 0;
transition: transform 500ms ease;
}
.active {
transition: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<figure></figure>
</div>
<div>
<figure></figure>
</div>
Your issue is in this line:
$('div').mousemove(function(e) {
Change it to:
$(this).on('mousemove', function(e) {
That because you need address the current div element on which you are in the each loop:
$('div').each(function() {
The snippet:
$('div').each(function() {
var img = $(this).find( "figure" );
var offset = img.offset();
var originLeft = offset.left;
var originTop = offset.top;
$(this).on('mousemove', function(e) {
img.addClass('active');
img.css({
transform: 'translateX(' + (e.pageX - originLeft/2 ) + 'px) translateY(' + (e.pageY - originTop) + 'px)'
});
}).on('mouseout', function(e) {
img.removeClass('active');
img.css({
transform: 'translateX(0) translateY(0)'
});
});
});
div {
height: 250px;
width: 250px;
background: #eee;
}
div:nth-child(2) {
background: #ccc;
}
figure {
display: block;
height: 50px;
width: 50px;
background: blue;
margin: 0;
transition: transform 500ms ease;
}
.active {
transition: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<figure></figure>
</div>
<div>
<figure></figure>
</div>
I am trying to move and rotate the object in the direction of the mouse click. Unfortunately during the first click object automatically align itself to left. It works perfectly after the first click but it doesn't work during the first click. I couldn't find out why it goes automatically to upper left corner. How can I fix that? Here is the code:
var theThing = document.querySelector("#thing");
var container = document.querySelector("#contentContainer");
var triangle = document.querySelector("#triangle");
container.addEventListener("click", getClickPosition, false);
function getClickPosition(e) {
var xPosition = e.clientX;
var yPosition = e.clientY;
var translate3dValue = "translate3d(" + xPosition + "px," + yPosition + "px,0)";
var box = $("#thing");
var boxCenter = [box.offset().left + box.width() / 2, box.offset().top + box.height() / 2];
var angle = Math.atan2(xPosition - boxCenter[0], -(yPosition - boxCenter[1])) * (180 / Math.PI);
theThing.style.transform += "rotate(" + angle + "deg)";
setTimeout(function() {
theThing.style.transform = translate3dValue;
}, 500);
}
body {
background-color: #FFF;
padding: 0;
margin: 0;
}
#contentContainer {
width: 550px;
height: 350px;
border: 15px #EDEDED;
overflow: hidden;
background-color: #F2F2F2;
cursor: pointer;
}
#thing {
width: 75px;
height: 75px;
background-color: rgb(255, 207, 0);
border-radius: 0%;
transform: translate3d(200px, 100px, 0);
transition: transform.2s ease-in;
}
#triangle {
width: 0;
height: 0;
border-left: 30px solid transparent;
border-right: 45px solid transparent;
border-bottom: 75px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="contentContainer">
<div id="thing">
<div id="triangle">
</div>
</div>
</div>
Because initially the transform is set in the CSS thus you cannot append the rotation to it and you will simply override it. Make it inline using JS and it will work fine. It will behave like the next ones since later you will be adding all the transform inline:
var theThing = document.querySelector("#thing");
var container = document.querySelector("#contentContainer");
var triangle = document.querySelector("#triangle");
container.addEventListener("click", getClickPosition, false);
theThing.style.transform="translate3d(200px, 100px, 0)";
function getClickPosition(e) {
var xPosition = e.clientX;
var yPosition = e.clientY;
var translate3dValue = "translate3d(" + xPosition + "px," + yPosition + "px,0)";
var box = $("#thing");
var boxCenter = [box.offset().left + box.width() / 2, box.offset().top + box.height() / 2];
var angle = Math.atan2(xPosition - boxCenter[0], -(yPosition - boxCenter[1])) * (180 / Math.PI);
theThing.style.transform += "rotate(" + angle + "deg)";
setTimeout(function() {
theThing.style.transform = translate3dValue;
}, 500);
}
body {
background-color: #FFF;
padding: 0;
margin: 0;
}
#contentContainer {
width: 550px;
height: 350px;
border: 15px #EDEDED;
overflow: hidden;
background-color: #F2F2F2;
cursor: pointer;
}
#thing {
width: 75px;
height: 75px;
background-color: rgb(255, 207, 0);
border-radius: 0%;
/*transform: translate3d(200px, 100px, 0);*/
transition: transform.2s ease-in;
}
#triangle {
width: 0;
height: 0;
border-left: 30px solid transparent;
border-right: 45px solid transparent;
border-bottom: 75px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="contentContainer">
<div id="thing">
<div id="triangle">
</div>
</div>
</div>
Here's a link to my codepen: https://codepen.io/Bryandbronstein/pen/NLVQjB
So this is a strange issue and I'm at the end of my rope with this one. I've been learning a bit more about CSS and Javascript, and decided to try out an image comparison slider I found on W3C's website. It works perfectly as a single element, however I want to have a full gallery of these. Yet no matter what I try, they don't seem to want to obey any of the flex rules I set for their parent container. You'll notice in the codepen that one comparison container is hidden behind another. Any ideas?
function initComparisons() {
var x, i;
/*find all elements with an "overlay" class:*/
x = document.getElementsByClassName("img-comp-overlay");
for (i = 0; i < x.length; i++) {
/*once for each "overlay" element:
pass the "overlay" element as a parameter when executing the compareImages function:*/
compareImages(x[i]);
}
function compareImages(img) {
var slider, img, clicked = 0, w, h;
/*get the width and height of the img element*/
w = img.offsetWidth;
h = img.offsetHeight;
/*set the width of the img element to 50%:*/
img.style.width = (w / 2) + "px";
/*create slider:*/
slider = document.createElement("DIV");
slider.setAttribute("class", "img-comp-slider");
/*insert slider*/
img.parentElement.insertBefore(slider, img);
/*position the slider in the middle:*/
slider.style.top = (h / 2) - (slider.offsetHeight / 2) + "px";
slider.style.left = (w / 2) - (slider.offsetWidth / 2) + "px";
/*execute a function when the mouse button is pressed:*/
slider.addEventListener("mousedown", slideReady);
/*and another function when the mouse button is released:*/
window.addEventListener("mouseup", slideFinish);
/*or touched (for touch screens:*/
slider.addEventListener("touchstart", slideReady);
/*and released (for touch screens:*/
window.addEventListener("touchstop", slideFinish);
function slideReady(e) {
/*prevent any other actions that may occur when moving over the image:*/
e.preventDefault();
/*the slider is now clicked and ready to move:*/
clicked = 1;
slider.style.border = "0";
/*execute a function when the slider is moved:*/
window.addEventListener("mousemove", slideMove);
window.addEventListener("touchmove", slideMove);
}
function slideFinish() {
/*the slider is no longer clicked:*/
clicked = 0;
slider.style.border = "3px solid white";
}
function slideMove(e) {
var pos;
/*if the slider is no longer clicked, exit this function:*/
if (clicked == 0) return false;
/*get the cursor's x position:*/
pos = getCursorPos(e)
/*prevent the slider from being positioned outside the image:*/
if (pos < 0) pos = 0;
if (pos > w) pos = w;
/*execute a function that will resize the overlay image according to the cursor:*/
slide(pos);
}
function getCursorPos(e) {
var a, x = 0;
e = e || window.event;
/*get the x positions of the image:*/
a = img.getBoundingClientRect();
/*calculate the cursor's x coordinate, relative to the image:*/
x = e.pageX - a.left;
/*consider any page scrolling:*/
x = x - window.pageXOffset;
return x;
}
function slide(x) {
/*resize the image:*/
img.style.width = x + "px";
/*position the slider:*/
slider.style.left = img.offsetWidth - (slider.offsetWidth / 2) + "px";
}
}
}
html, body {
background-color: #333333;
margin: 0;
padding: 0;
}
* {box-sizing: border-box;}
.gallery_text {
color: white;
font-family: Abel, Helvetica, sans-serif;
font-size: 1.7rem;
text-align: center;
line-height: 1.8em;
}
.row{
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.img-comp-container{
position: relative;
flex: 50%;
}
.img-comp-overlay{
border-right: 2px solid rgba(51,51,51, .5) ;
}
.img-comp-img {
position: absolute;
width: auto;
height: auto;
overflow: hidden;
}
.img-comp-img img {
vertical-align: middle;
}
.img-comp-slider {
position: absolute;
z-index: 9;
cursor: ew-resize;
width: 40px;
height: 40px;
transform: rotate(136deg);
background-color: #333333;
opacity: .8;
border-radius: 10%;
border: 3px solid white;
}
<body onload="initComparisons();">
<div class="row">
<div class="img-comp-container" >
<div class="img-comp-img">
<img src="https://images.pexels.com/photos/162389/lost-places-old-decay-ruin-162389.jpeg?cs=srgb&dl=black-and-white-dark-building-162389.jpg&fm=jpg" width="500" height="450">
</div>
<div class="seperator"></div>
<div class="img-comp-img img-comp-overlay">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSslfAcWKXuMxBpzcJC5ZUyFqMOb2Jtd12x4kBUGG9mTe3KeMJz" width="500" height="450">
</div>
</div>
<div class="img-comp-container">
<div class="img-comp-img">
<img src="https://images.pexels.com/photos/162389/lost-places-old-decay-ruin-162389.jpeg?cs=srgb&dl=black-and-white-dark-building-162389.jpg&fm=jpg" width="500" height="450">
</div>
<div class="seperator"></div>
<div class="img-comp-img img-comp-overlay">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSslfAcWKXuMxBpzcJC5ZUyFqMOb2Jtd12x4kBUGG9mTe3KeMJz" width="500" height="450">
</div>
</div>
<div class="img-comp-container">
<div class="img-comp-img">
<img src="https://images.pexels.com/photos/162389/lost-places-old-decay-ruin-162389.jpeg?cs=srgb&dl=black-and-white-dark-building-162389.jpg&fm=jpg" width="500" height="450">
</div>
<div class="seperator"></div>
<div class="img-comp-img img-comp-overlay">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSslfAcWKXuMxBpzcJC5ZUyFqMOb2Jtd12x4kBUGG9mTe3KeMJz" width="500" height="450">
</div>
</div>
</div>
</body>
The images won't wrap because all children of .img-comp-container were absolutely positioned. This collapsed all the flex elements so that the flex wrap wouldn't work.
Either make one of more of the children of .img-comp-container relative or static, or set a width and height to .img-comp-container.
Here are the changes I made to the CSS:
.img-comp-container{
position: relative;
flex: 50%;
}
.img-comp-img {
position: relative;
width: auto;
height: auto;
overflow: hidden;
}
.img-comp-overlay {
border-right: 2px solid rgba(51, 51, 51, 0.5);
position: absolute;
top: 0;
left: 0;
}
See this codepen fork of your pen for a working solution.
I am trying to implement a crosshair cursor which will be activated through MouseEnter once the cursor enters the canvas. However, after the cursor has been changed to the crosshair, and even if it leaves the canvas, it still remains as the crosshair. I want the crosshair cursor to only be activated inside the canvas, and for the cursor to revert back to the default cursor once it leaves the canvas.
CSS:
#crosshair-h {
width: 100%;
}
#crosshair-v {
height: 100%;
}
.hair {
position: fixed;
top:0; left:0;
margin-top: -3px;
margin-left: -2px;
background: transparent;
border-top: 1px dotted #000;
border-left: 1px dotted #000;
pointer-events: none;
z-index: 2;
}
#mousepos {
position: absolute;
top:0; left:0;
padding: 10px;
margin: 10px;
font: 14px arial;
color: #fff;
background: rgba(0,0,0,0.5);
border-radius: 24px;
z-index: 1;
}
JavaScript:
$(document).ready(function() {
// Setup our variables
var cH = $('#crosshair-h'),
cV = $('#crosshair-v');
$(this).on('mousemove touchmove', function(e) {
var x = e.pageX - 1;
var y = e.pageY - 1;
cH.css('top', e.pageY);
cV.css('left', e.pageX);
$('#mousepos').css({
top: e.pageY + 'px',
left: e.pageX + 'px'
}, 800);
$('#mousepos').text( "X: " + x + "px, Y: " + y + "px");
e.stopPropagation();
});
// Anchor Hover Effects
$("a").hover(function() {
$(".hair").stop().css({borderColor: "#fff"}, 800)},
function() {
$(".hair").stop().css({borderColor: "black"},800)
});
e.stopPropagation();
});
Any help is appreciated, thank you!
If the default crosshair cursor suffices, you can do this with a simple CSS hover rule:
canvas {
border: 1px solid grey;
height: 50px;
width: 100px;
}
canvas:hover {
cursor: crosshair;
}
<canvas></canvas>
If you really have need for the custom one, you can use a mouseleave or mouseout event on the canvas to remove the css class.