Reputation: 1665
I have a javascript cursor, which does quite a few different things (hence a few different blocks of similar looking code), where on hover it will add classes to the cursor divs so it can be manipulated be it a standard hover style, a unique class inherited for a data
attribute or add text to the div, again inherited from a data
value.
This all works ok on the included code. However what I want to do now is if an object has an image specified on it like this: data-img="img/our-work/vbb.jpg"
- this image path can be added to an img
element also within the cursor. Ideally there would not be an empty img
tag when not active and this is only added along with the src
path when required - however my example does have that hardcoded for now as that's where I'm stuck.
The goal is to display the image attached/following the cursor.
You can see this in the example by hovered over the "Image with Data IMG" text.
/**
* Two div's are on the page which are used to create a custom cursor effect.
* `.cursor` follows the pointer whereas the `.cursor-trail` is an outer circle
* that follows the cursor with a delay.
*
* The original script was based on this CodePen example:
* https://codepen.io/ntenebruso/pen/QWLzVjY
*
* But there were performance (lagging and jumping) issues cross-browser, mainly
* in Safari (Mac OS). So it was re-written and this version performed better.
* Previously `calc` was used for sizing and top/left values for positioning.
* Using fixed values instead of `calc` (as we know the size of the cursor) and
* `transform` wasn't as much of a performance hit. If we changed the size of
* the cursor in the CSS we'd need to update the values here accordingly.
*/
var cursor = document.querySelector(".cursor");
var cursorTrail = document.querySelector(".cursor-trail");
var a = document.querySelectorAll("a");
var timeout;
window.addEventListener(
"mousemove",
function(e) {
var x = e.clientX;
var y = e.clientY;
cursor.style.transform = `translate(${x - 2}px, ${y - 2}px)`;
if (!timeout) {
timeout = setTimeout(function() {
timeout = null;
cursorTrail.style.transform = `translate(${x - 16}px, ${y - 16}px)`;
}, 24);
}
},
false
);
/**
* Add/remove classes on click (anywhere).
*/
document.addEventListener("mousedown", function() {
cursor.classList.add("cursor--click");
});
document.addEventListener("mouseup", function() {
cursor.classList.remove("cursor--click");
});
/**
* Add/remove set classes on hover.
*
* 1. This used to start with `a.forEach((item) => {` but changed to `let` so
* that an additional (non-anchor) item could be targeted. `#hello` is for
* the image on the 404 page.
*/
// a.forEach((item) => {
let links = document.querySelectorAll('a'); /* [1] */
links.forEach((item) => { /* [1] */
item.addEventListener("mouseover", () => {
cursorTrail.classList.add("cursor-trail--hover");
});
item.addEventListener("mouseleave", () => {
cursorTrail.classList.remove("cursor-trail--hover");
});
});
/**
* Add custom classes on hover if the cursor needs to be manipulated in a
* unique way. If an element has a `data-interaction=""` value set. This will
* be added as a class to the cursor on hover. For example, this is used to
* style the prev/next arrows on the carousel.
*
* This could be set using a specific class but I've just left it targeting all
* `a` elements for now. Which will add a class of `undefined` if no dataset is
* specified.
*/
a.forEach((item) => {
const interaction = item.dataset.interaction;
item.addEventListener("mouseover", () => {
cursor.classList.add(interaction);
});
item.addEventListener("mouseleave", () => {
cursor.classList.remove(interaction);
});
});
/**
* Text Label
*/
let hasLabel = document.querySelectorAll('.projects__img');
var cursorText = document.querySelector('.cursor__label');
hasLabel.forEach((item) => {
const label = item.dataset.label;
item.addEventListener("mouseover", () => {
cursorText.textContent = label;
});
item.addEventListener("mouseleave", () => {
cursorText.textContent = "";
});
});
/**
* Show Image
*/
let hasImg = document.querySelectorAll('.test-image');
var myImage = document.querySelector('.cursor__img');
hasImg.forEach((item) => {
const label = item.dataset.img;
item.addEventListener("mouseover", () => {
myImage.setAttribute("src", label);
});
item.addEventListener("mouseleave", () => {
myImage.setAttribute("src", "");
});
});
img {
width: 100%;
max-width: 100%;
}
/**
* Core `.cursor` (pointer) styling which is a small dot that follows the real
* browser pointer position.
*
* 1. Add transitions for the `background-color`, `height`, `margin` and `width`
* of the element when the cursor is clicked and the class `.cursor--click`
* is added to it.
* 2. Only add the `background-color` when the `body` is hovered over. Otherwise
* on page load the cursor is stuck in the top/left of the browser until you
* move it, which looks a bit crap. At least this is a bit more graceful.
*/
.cursor {
color: white;
mix-blend-mode: difference;
position: fixed;
z-index: 1000;
}
.cursor span {
background-color: white;
border-radius: 100%;
display: block;
height: 4px;
margin: 0;
pointer-events: none;
transition: background-color 0.12s ease-out, height 0.12s, margin 0.12s, width 0.12s; /* [1] */
position: fixed;
width: 4px;
}
.cursor__label {
color: white;
white-space: nowrap;
top: 16px;
position: absolute;
left: 16px;
}
/**
* A class of `.cursor--click` is added when the user clicks anywhere. When this
* happens we shrink/make the cursor disappear.
*/
.cursor--click span {
height: 0;
margin: 2px 0 0 2px;
width: 0;
}
/**
* Core `.cursor-trail` styling which is a larger cricle that follows `.cursor`
* around the screen but with a smooth delay/lag.
*
* 1. Add a lot transitions for various click/hover states which adjust the size
* and colour of the element. `transform` is the one for the smooth lag when
* moving the cursor.
* 2. Only add the `background-color` when the `body` is hovered over. Otherwise
* on page load the cursor is stuck in the top/left of the browser until you
* move it, which looks a bit crap. At least this is a bit more graceful.
*/
.cursor-trail {
border: 1px solid white;
border-radius: 100%;
box-sizing: border-box;
height: 32px;
margin: 0;
mix-blend-mode: difference;
pointer-events: none;
position: fixed;
transform-origin: center center;
transition: border-color 0.12s ease-out, height 0.12s ease-out, margin 0.12s ease-out, opacity 0.12s ease-out, transform 0.24s cubic-bezier(0, .48, .64, 1), width 0.12s ease-out; /* [1] */
width: 32px;
z-index: 1000;
}
<div class="cursor">
<span></span>
<div class="cursor__label"></div>
<img src="" class="cursor__img">
</div>
<div class="cursor-trail"></div>
<div class="projects__item">
<figure class="projects__img" data-label="#1 Image Label">
<img src="https://images.pexels.com/photos/18399245/pexels-photo-18399245/free-photo-of-brunette-woman-posing-on-a-field.jpeg" alt="ALT TEXT" loading="lazy" class="lazy-image">
</figure>
<p class="test-image" data-img="img/our-work/vbb.jpg">Image with Data IMG</p>
</div>
<div class="projects__item">
<figure class="projects__img" data-label="#2 Image Label">
<img src="https://images.pexels.com/photos/18427938/pexels-photo-18427938/free-photo-of-autumn-mountains.jpeg" alt="ALT TEXT" loading="lazy" class="lazy-image">
</figure>
<p>Image Without</p>
</div>
Upvotes: 0
Views: 76
Reputation: 15867
There are many ways you can add/remove the img tag depending on the existence of a data attribute. You can also keep it simple and keep the img tag hard coded and simply hide it via CSS if the src is empty.
.cursor__img[src='']{
display:none;
}
/**
* Two div's are on the page which are used to create a custom cursor effect.
* `.cursor` follows the pointer whereas the `.cursor-trail` is an outer circle
* that follows the cursor with a delay.
*
* The original script was based on this CodePen example:
* https://codepen.io/ntenebruso/pen/QWLzVjY
*
* But there were performance (lagging and jumping) issues cross-browser, mainly
* in Safari (Mac OS). So it was re-written and this version performed better.
* Previously `calc` was used for sizing and top/left values for positioning.
* Using fixed values instead of `calc` (as we know the size of the cursor) and
* `transform` wasn't as much of a performance hit. If we changed the size of
* the cursor in the CSS we'd need to update the values here accordingly.
*/
var cursor = document.querySelector(".cursor");
var cursorTrail = document.querySelector(".cursor-trail");
var a = document.querySelectorAll("a");
var timeout;
window.addEventListener(
"mousemove",
function(e) {
var x = e.clientX;
var y = e.clientY;
cursor.style.transform = `translate(${x - 2}px, ${y - 2}px)`;
if (!timeout) {
timeout = setTimeout(function() {
timeout = null;
cursorTrail.style.transform = `translate(${x - 16}px, ${y - 16}px)`;
}, 24);
}
},
false
);
/**
* Add/remove classes on click (anywhere).
*/
document.addEventListener("mousedown", function() {
cursor.classList.add("cursor--click");
});
document.addEventListener("mouseup", function() {
cursor.classList.remove("cursor--click");
});
/**
* Add/remove set classes on hover.
*
* 1. This used to start with `a.forEach((item) => {` but changed to `let` so
* that an additional (non-anchor) item could be targeted. `#hello` is for
* the image on the 404 page.
*/
// a.forEach((item) => {
let links = document.querySelectorAll('a'); /* [1] */
links.forEach((item) => { /* [1] */
item.addEventListener("mouseover", () => {
cursorTrail.classList.add("cursor-trail--hover");
});
item.addEventListener("mouseleave", () => {
cursorTrail.classList.remove("cursor-trail--hover");
});
});
/**
* Add custom classes on hover if the cursor needs to be manipulated in a
* unique way. If an element has a `data-interaction=""` value set. This will
* be added as a class to the cursor on hover. For example, this is used to
* style the prev/next arrows on the carousel.
*
* This could be set using a specific class but I've just left it targeting all
* `a` elements for now. Which will add a class of `undefined` if no dataset is
* specified.
*/
a.forEach((item) => {
const interaction = item.dataset.interaction;
item.addEventListener("mouseover", () => {
cursor.classList.add(interaction);
});
item.addEventListener("mouseleave", () => {
cursor.classList.remove(interaction);
});
});
/**
* Text Label
*/
let hasLabel = document.querySelectorAll('.projects__img');
var cursorText = document.querySelector('.cursor__label');
hasLabel.forEach((item) => {
const label = item.dataset.label;
item.addEventListener("mouseover", () => {
cursorText.textContent = label;
});
item.addEventListener("mouseleave", () => {
cursorText.textContent = "";
});
});
/*
* Show Image
*/
let hasImg = document.querySelectorAll('.test-image');
var myImage = document.querySelector('.cursor__img');
hasImg.forEach((item) => {
const label = item.dataset.img;
item.addEventListener("mouseover", () => {
myImage.setAttribute("src", label);
});
item.addEventListener("mouseleave", () => {
myImage.setAttribute("src", "");
});
});
img {
width: 100%;
max-width: 100%;
}
/**
* Core `.cursor` (pointer) styling which is a small dot that follows the real
* browser pointer position.
*
* 1. Add transitions for the `background-color`, `height`, `margin` and `width`
* of the element when the cursor is clicked and the class `.cursor--click`
* is added to it.
* 2. Only add the `background-color` when the `body` is hovered over. Otherwise
* on page load the cursor is stuck in the top/left of the browser until you
* move it, which looks a bit crap. At least this is a bit more graceful.
*/
.cursor {
color: white;
mix-blend-mode: difference;
position: fixed;
z-index: 1000;
}
.cursor span {
background-color: white;
border-radius: 100%;
display: block;
height: 4px;
margin: 0;
pointer-events: none;
transition: background-color 0.12s ease-out, height 0.12s, margin 0.12s, width 0.12s; /* [1] */
position: fixed;
width: 4px;
}
.cursor__label {
color: white;
white-space: nowrap;
top: 16px;
position: absolute;
left: 16px;
}
/**
* A class of `.cursor--click` is added when the user clicks anywhere. When this
* happens we shrink/make the cursor disappear.
*/
.cursor--click span {
height: 0;
margin: 2px 0 0 2px;
width: 0;
}
/**
* Core `.cursor-trail` styling which is a larger cricle that follows `.cursor`
* around the screen but with a smooth delay/lag.
*
* 1. Add a lot transitions for various click/hover states which adjust the size
* and colour of the element. `transform` is the one for the smooth lag when
* moving the cursor.
* 2. Only add the `background-color` when the `body` is hovered over. Otherwise
* on page load the cursor is stuck in the top/left of the browser until you
* move it, which looks a bit crap. At least this is a bit more graceful.
*/
.cursor-trail {
border: 1px solid white;
border-radius: 100%;
box-sizing: border-box;
height: 32px;
margin: 0;
mix-blend-mode: difference;
pointer-events: none;
position: fixed;
transform-origin: center center;
transition: border-color 0.12s ease-out, height 0.12s ease-out, margin 0.12s ease-out, opacity 0.12s ease-out, transform 0.24s cubic-bezier(0, .48, .64, 1), width 0.12s ease-out; /* [1] */
width: 32px;
z-index: 1000;
}
.cursor__img[src='']{
display:none;
}
.cursor__img{
width:25px;
height:25px;
}
<div class="cursor">
<span></span>
<div class="cursor__label"></div>
<img src="" class="cursor__img">
</div>
<div class="cursor-trail"></div>
<div class="projects__item">
<figure class="projects__img" data-label="#1 Image Label">
<img src="https://images.pexels.com/photos/18399245/pexels-photo-18399245/free-photo-of-brunette-woman-posing-on-a-field.jpeg" alt="ALT TEXT" loading="lazy" class="lazy-image">
</figure>
<p class="test-image" data-img="https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Mouse-cursor-hand-pointer.svg/220px-Mouse-cursor-hand-pointer.svg.png">Image with Data IMG</p>
</div>
<div class="projects__item">
<figure class="projects__img" data-label="#2 Image Label">
<img src="https://images.pexels.com/photos/18427938/pexels-photo-18427938/free-photo-of-autumn-mountains.jpeg" alt="ALT TEXT" loading="lazy" class="lazy-image">
</figure>
<p>Image Without</p>
</div>
Upvotes: 0