Reputation: 3
I need help,
I just saw this main page on a great website www.snapplespiked.ca.
I really like so much this kind of cursor-waving effect, when you moving the cursor all over the page. I was trying this web on Atom/VsCode/Codepen and CAN NOT get these effects on the whole page. It appears only in first place on the main page when you just entering on website. In the moment when you scrolling a page down to see the rest of the parts on the page the effect disappears, not working.
I use the same HTML and CSS and all js scripts and there is not the same effect as on the original website.
What I did wrong?
Is anyone know what I did wrong ?
This effect come from this part of the code in HTML:
<div class="c-background js-app-background">
<div class="c-background__texture js-app-backgroundTexture">
<div data-product-id="795" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/mango.png);" data-color="#fc9a44" class=""></div>
<div data-product-id="804" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/lemon_peel.png);" data-color="#ffe24a" class=""></div>
<div data-product-id="808" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/watermelon.png);" data-color="#4ca463" class="is-active"></div>
<div data-product-id="798" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/raspberry.png);" data-color="#ff3443" class=""></div>
<div data-product-id="806" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/strawberry.png);" data-color="#ff3443" class=""></div>
<div data-product-id="802" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/lemon.png);" data-color="#ffe24a" class=""></div>
<div data-product-id="800" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/peach.png);" data-color="#fc9a44" class=""></div>
</div>
<canvas class="c-background__canvas js-app-backgroundCanvas" style="width: 784px; height: 779px;" width="1176" height="1168"></canvas>
</div>
<div class="c-background c-background--foreground js-app-background">
<div class="c-background__texture js-app-backgroundTexture">
<div data-product-id="795" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/mango.png);" data-color="#fc9a44" class="is-active"></div>
<div data-product-id="804" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/lemon_peel.png);" data-color="#fc9a44" class=""></div>
<div data-product-id="808" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/watermelon.png);" data-color="#fc9a44" class=""></div>
<div data-product-id="798" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/raspberry.png);" data-color="#fc9a44" class=""></div>
<div data-product-id="806" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/strawberry.png);" data-color="#fc9a44" class=""></div>
<div data-product-id="802" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/lemon.png);" data-color="#fc9a44" class=""></div>
<div data-product-id="800" style="--url: url(https://www.snapplespiked.ca/wp-content/uploads/2021/02/peach.png);" data-color="#fc9a44" class=""></div>
</div>
</div>
Upvotes: 0
Views: 177
Reputation: 8762
You shouldn't directly copy code snippets from other websites, as you don't have the license to use them legally, and they're only really guarrenteed to be fit for their original purpose --- as you've found, it doesn't really work for your use case, and often it'll also result in a lot of redundant code.
In fact, this effect isn't particularlly hard, so lets try to re-create it ourselves!
The HTML5 canvas element lets us draw pixels onto it in various shapes. It's really useful for creating complex graphical effects like this one. The background of the canvas is transparent by default, and you can clear pixels off of it, so one way we could do this would be to fill the entire canvas white every frame, and then erase away the white where the cursor trails are to reveal the background underneath.
This means that we need to do a few things in our JavaScript:
<canvas>
in placeWe need to start by making the canvas and placing it on the page. Almost everything else will be done with JS.
<div id="page">
<canvas id="mouseTrailEffect"></canvas>
<div class="content"></div>
</div>
The page is the container for both the canvas and the content. The content div contains all of the other content which should appear over the top of the canvas.
We want to do a couple things with the CSS here too:
#page {
position: relative;
}
#page canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#page .content {
position: absolute;
}
This makes sure that it fills its entire parent, but remains sorted behind the rest of the content.
In the JavaScript, we now need to create a reference to the canvas, it's drawing context, and we also need to adjust its size, so that the width and height are set explictly --- even though this has been done with CSS, this will actually just stretch the canvas's pixels to cover the requested area, rather than adding more pixels to it to match the space it covers 1-to-1, which results in it looking quite blurry. We also need to make sure we adjust its size again whenever the user resizes the window, to make it responsive.
function resizeCanvas(cv) {
let rect = cv.getBoundingClientRect();
cv.width = rect.width;
cv.height = rect.height;
}
function setupMouseTrailEffect() {
let cv = document.getElementById("mouseTrailEffect");
let ctx = cv.getContext("2d");
resizeCanvas(cv);
window.addEventListener("resize", ()=>{
resizeCanvas(cv);
});
}
window.addEventListener("load", ()=>{ // When the page load is completed
setupMouseTrailEffect();
});
Whenever the user moves their cursor over our canvas, we get a mousemove
event fired on it that we can listen to. We can then extract the X and Y positions of the mouse from that event (relative to the page's scroll position and the canvas's offset from the top-left corner of the page), and create an object like to represent the blob.
{x: ____, y: ____, size: ____}
We can add those objects into an array, which I'll call blobs
. One thing to note here is that we actually listen for the mousemove
event on the canvas's parent, not the canvas itself. This is so that it gets called even if the user hovers over something else on the page (e.g. some content) which isn't directly the canvas itself.
let blobs = [];
const INITIAL_BLOB_SIZE = 50; // This is radius that blobs will be when they start out! You can change it to make them bigger / smaller.
document.getElementById("page").addEventListener("mousemove", (ev)=>{
blobs.push({
x: ev.pageX - cv.offsetLeft,
y: ev.pageY - cv.offsetTop,
size: INITIAL_BLOB_SIZE
});
});
Now, we need to figure out how to update our canvas every tick. This can be done by first defining the function which should be run each tick, and then at the end of it telling the browser that the next animation frame it gets it should try and run our function again.
const tick = ()=>{
ctx.clearRect(0, 0, cv.width, cv.height);
ctx.fillStyle = "#ffffff"; // white
ctx.fillRect(0, 0, cv.width, cv.height); // fill the entire canvas with white
window.requestAnimationFrame(tick); // run this again ASAP
}
tick(); // Run the first tick to get it started!
Now for the fun part!
Inside our tick
function, after we fill everything white, lets loop through our blobs and erase them from the canvas. Note that the canvas works like e.g. Microsoft Paint does, in that there are no layers --- every pixel can have exactly one colour at one time. Filling it white sets them all to white, and to erase the area occupied by a blob we'll just draw a new shape there, and composite it so that it gets removed and the pixels are set to a fully transparent colour.
We also need to make sure that we adjust the size of the blobs each tick, and that we can remove them from the array once they reach a set minimum size. To do the latter, we'll make sure we loop through the array backwards, so that deleting one doesn't change the indexes that we're looping over.
const BLOB_DECAY_RATE = 2; // How many pixels to remove from the size of a blob each tick
const MIN_BLOB_SIZE = 0; // When a blob reaches this size, we stop tracking it and it disappears.
ctx.globalCompositeOperation = "destination-out"; // Instead of drawing these shapes, erase them instead!
for (let i = blobs.length - 1; i >= 0; i--) { // Loop over the list of blobs backwards
ctx.beginPath(); // Create a path which we'll erase
ctx.arc(blobs[i].x, blobs[i].y, blobs[i].size, 0, Math.PI * 2); // Add a arc to the path with is a circle, centered at the blob's X and Y positions, and with its size as the radius.
ctx.fill();
blobs[i].size -= BLOB_DECAY_RATE; // Adjust the blob's size
if (blobs[i].size <= MIN_BLOB_SIZE) {
blobs.splice(i, 1); // Remove the blob from the array
}
}
ctx.globalCompositeOperation = "source-out"; // Stop erasing when we draw
Here's all that code put together into a working example!
const INITIAL_BLOB_SIZE = 50; // This is radius that blobs will be when they start out! You can change it to make them bigger / smaller.
const BLOB_DECAY_RATE = 4; // How many pixels to remove from the size of a blob each tick
const MIN_BLOB_SIZE = 20; // When a blob reaches this size, we stop tracking it and it disappears.
function resizeCanvas(cv) {
let rect = cv.getBoundingClientRect();
cv.width = rect.width;
cv.height = rect.height;
}
function setupMouseTrailEffect() {
let cv = document.getElementById("mouseTrailEffect");
let ctx = cv.getContext("2d");
resizeCanvas(cv);
window.addEventListener("resize", ()=>{
resizeCanvas(cv);
});
let blobs = [];
document.getElementById("page").addEventListener("mousemove", (ev)=>{
blobs.push({
x: ev.pageX - cv.offsetLeft,
y: ev.pageY - cv.offsetTop,
size: INITIAL_BLOB_SIZE
});
});
const tick = ()=>{
ctx.globalCompositeOperation = "source-out"; // Stop erasing when we draw
ctx.clearRect(0, 0, cv.width, cv.height);
ctx.fillStyle = "#fff"; // white
ctx.fillRect(0, 0, cv.width, cv.height); // fill the entire canvas with white
ctx.globalCompositeOperation = "destination-out"; // Instead of drawing these shapes, erase them instead!
for (let i = blobs.length - 1; i >= 0; i--) { // Loop over the list of blobs backwards
ctx.beginPath(); // Create a path which we'll erase
ctx.arc(blobs[i].x, blobs[i].y, blobs[i].size, 0, Math.PI * 2); // Add a arc to the path with is a circle, centered at the blob's X and Y positions, and with its size as the radius.
ctx.fill();
blobs[i].size -= BLOB_DECAY_RATE; // Adjust the blob's size
if (blobs[i].size <= MIN_BLOB_SIZE) {
blobs.splice(i, 1); // Remove the blob from the array
}
}
window.requestAnimationFrame(tick); // Run this again ASAP!
}
tick(); // Run the first tick to get it started!
}
window.addEventListener("load", ()=>{ // When the page load is completed
setupMouseTrailEffect();
});
#page {
/** Gradient just so we can see the effect **/
background-image: linear-gradient(0deg, #f00 0%, #ff0 100%);
border: solid 1px #000;
height: 250px;
position: relative;
padding: 10px;
}
#page canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#page .content {
position: absolute;
}
<div id="page">
<canvas id="mouseTrailEffect"></canvas>
<div class="content">
<h1>Some content</h1>
Stuff above the canvas.
</div>
</div>
You can tweak the three constants, INITIAL_BLOB_SIZE
, BLOB_DECAY_RATE
and MIN_BLOB_SIZE
to make the effect closer to what you want (and I've moved them all together to the top of the snippet to make that easy :D).
Upvotes: 1