add a funny cursor effect
This commit is contained in:
parent
fc99d01b6d
commit
aa2bf68e2d
|
@ -0,0 +1,212 @@
|
|||
(function() {
|
||||
let possibleColors = [
|
||||
"#D61C59",
|
||||
"#E7D84B",
|
||||
"#1B8798",
|
||||
];
|
||||
let element = document.body;
|
||||
|
||||
let width = window.innerWidth;
|
||||
let height = window.innerHeight;
|
||||
const cursor = { x: width / 2, y: width / 2 };
|
||||
const lastPos = { x: width / 2, y: width / 2 };
|
||||
const particles = [];
|
||||
const canvImages = [];
|
||||
let canvas, context, animationFrame;
|
||||
|
||||
const char = "*";
|
||||
|
||||
const prefersReducedMotion = window.matchMedia(
|
||||
"(prefers-reduced-motion: reduce)"
|
||||
);
|
||||
|
||||
// Re-initialise or destroy the cursor when the prefers-reduced-motion setting changes
|
||||
prefersReducedMotion.onchange = () => {
|
||||
if (prefersReducedMotion.matches) {
|
||||
destroy();
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
};
|
||||
|
||||
function init() {
|
||||
// Don't show the cursor trail if the user has prefers-reduced-motion enabled
|
||||
if (prefersReducedMotion.matches) {
|
||||
console.log(
|
||||
"This browser has prefers reduced motion turned on, so the cursor did not init"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
canvas = document.createElement("canvas");
|
||||
context = canvas.getContext("2d");
|
||||
canvas.style.top = "0px";
|
||||
canvas.style.left = "0px";
|
||||
canvas.style.pointerEvents = "none";
|
||||
|
||||
canvas.style.position = "fixed";
|
||||
element.appendChild(canvas);
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
context.font = "21px serif";
|
||||
context.textBaseline = "middle";
|
||||
context.textAlign = "center";
|
||||
|
||||
possibleColors.forEach((color) => {
|
||||
let measurements = context.measureText(char);
|
||||
let bgCanvas = document.createElement("canvas");
|
||||
let bgContext = bgCanvas.getContext("2d");
|
||||
|
||||
bgCanvas.width = measurements.width;
|
||||
bgCanvas.height =
|
||||
measurements.actualBoundingBoxAscent +
|
||||
measurements.actualBoundingBoxDescent;
|
||||
|
||||
bgContext.fillStyle = color;
|
||||
bgContext.textAlign = "center";
|
||||
bgContext.font = "21px serif";
|
||||
bgContext.textBaseline = "middle";
|
||||
bgContext.fillText(
|
||||
char,
|
||||
bgCanvas.width / 2,
|
||||
measurements.actualBoundingBoxAscent
|
||||
);
|
||||
|
||||
canvImages.push(bgCanvas);
|
||||
});
|
||||
|
||||
bindEvents();
|
||||
loop();
|
||||
}
|
||||
|
||||
// Bind events that are needed
|
||||
function bindEvents() {
|
||||
element.addEventListener("mousemove", onMouseMove);
|
||||
element.addEventListener("touchmove", onTouchMove, { passive: true });
|
||||
element.addEventListener("touchstart", onTouchMove, { passive: true });
|
||||
window.addEventListener("resize", onWindowResize);
|
||||
}
|
||||
|
||||
function onWindowResize(e) {
|
||||
width = window.innerWidth;
|
||||
height = window.innerHeight;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
|
||||
function onTouchMove(e) {
|
||||
if (e.touches.length > 0) {
|
||||
for (let i = 0; i < e.touches.length; i++) {
|
||||
addParticle(
|
||||
e.touches[i].clientX,
|
||||
e.touches[i].clientY,
|
||||
canvImages[Math.floor(Math.random() * canvImages.length)]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseMove(e) {
|
||||
window.requestAnimationFrame(() => {
|
||||
cursor.x = e.clientX;
|
||||
cursor.y = e.clientY;
|
||||
|
||||
const distBetweenPoints = Math.hypot(
|
||||
cursor.x - lastPos.x,
|
||||
cursor.y - lastPos.y
|
||||
);
|
||||
|
||||
if (distBetweenPoints > 1.5) {
|
||||
addParticle(
|
||||
cursor.x,
|
||||
cursor.y,
|
||||
canvImages[Math.floor(Math.random() * possibleColors.length)]
|
||||
);
|
||||
|
||||
lastPos.x = cursor.x;
|
||||
lastPos.y = cursor.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addParticle(x, y, color) {
|
||||
particles.push(new Particle(x, y, color));
|
||||
}
|
||||
|
||||
function updateParticles() {
|
||||
if (particles.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.clearRect(0, 0, width, height);
|
||||
|
||||
// Update
|
||||
for (let i = 0; i < particles.length; i++) {
|
||||
particles[i].update(context);
|
||||
}
|
||||
|
||||
// Remove dead particles
|
||||
for (let i = particles.length - 1; i >= 0; i--) {
|
||||
if (particles[i].lifeSpan < 0) {
|
||||
particles.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (particles.length == 0) {
|
||||
context.clearRect(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
function loop() {
|
||||
updateParticles();
|
||||
animationFrame = requestAnimationFrame(loop);
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
canvas.remove();
|
||||
cancelAnimationFrame(animationFrame);
|
||||
element.removeEventListener("mousemove", onMouseMove);
|
||||
element.removeEventListener("touchmove", onTouchMove);
|
||||
element.removeEventListener("touchstart", onTouchMove);
|
||||
window.addEventListener("resize", onWindowResize);
|
||||
};
|
||||
|
||||
function Particle(x, y, canvasItem) {
|
||||
const lifeSpan = Math.floor(Math.random() * 30 + 60);
|
||||
this.initialLifeSpan = lifeSpan; //
|
||||
this.lifeSpan = lifeSpan; //ms
|
||||
this.velocity = {
|
||||
x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
|
||||
y: Math.random() * 0.7 + 0.9,
|
||||
};
|
||||
this.position = { x: x, y: y };
|
||||
this.canv = canvasItem;
|
||||
|
||||
this.update = function (context) {
|
||||
this.position.x += this.velocity.x;
|
||||
this.position.y += this.velocity.y;
|
||||
this.lifeSpan--;
|
||||
|
||||
this.velocity.y += 0.02;
|
||||
|
||||
const scale = Math.max(this.lifeSpan / this.initialLifeSpan, 0);
|
||||
|
||||
context.drawImage(
|
||||
this.canv,
|
||||
this.position.x - (this.canv.width / 2) * scale,
|
||||
this.position.y - this.canv.height / 2,
|
||||
this.canv.width * scale,
|
||||
this.canv.height * scale
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
return {
|
||||
destroy: destroy
|
||||
}
|
||||
}
|
||||
)();
|
|
@ -0,0 +1,2 @@
|
|||
// https://github.com/tholman/cursor-effects/blob/master/src/fairyDustCursor.js
|
||||
!function(){let t=["#D61C59","#E7D84B","#1B8798"],e=document.body,n=window.innerWidth,i=window.innerHeight;const o={x:n/2,y:n/2},s={x:n/2,y:n/2},h=[],a=[];let c,r,d;const l="*",u=window.matchMedia("(prefers-reduced-motion: reduce)");function f(){if(u.matches)return console.log("This browser has prefers reduced motion turned on, so the cursor did not init"),!1;c=document.createElement("canvas"),r=c.getContext("2d"),c.style.top="0px",c.style.left="0px",c.style.pointerEvents="none",c.style.position="fixed",e.appendChild(c),c.width=n,c.height=i,r.font="21px serif",r.textBaseline="middle",r.textAlign="center",t.forEach(t=>{let e=r.measureText(l),n=document.createElement("canvas"),i=n.getContext("2d");n.width=e.width,n.height=e.actualBoundingBoxAscent+e.actualBoundingBoxDescent,i.fillStyle=t,i.textAlign="center",i.font="21px serif",i.textBaseline="middle",i.fillText(l,n.width/2,e.actualBoundingBoxAscent),a.push(n)}),e.addEventListener("mousemove",p),e.addEventListener("touchmove",v,{passive:!0}),e.addEventListener("touchstart",v,{passive:!0}),window.addEventListener("resize",m),w()}function m(t){n=window.innerWidth,i=window.innerHeight,c.width=n,c.height=i}function v(t){if(t.touches.length>0)for(let e=0;e<t.touches.length;e++)x(t.touches[e].clientX,t.touches[e].clientY,a[Math.floor(Math.random()*a.length)])}function p(e){window.requestAnimationFrame(()=>{o.x=e.clientX,o.y=e.clientY,Math.hypot(o.x-s.x,o.y-s.y)>1.5&&(x(o.x,o.y,a[Math.floor(Math.random()*t.length)]),s.x=o.x,s.y=o.y)})}function x(t,e,n){h.push(new function(t,e,n){const i=Math.floor(30*Math.random()+60);this.initialLifeSpan=i,this.lifeSpan=i,this.velocity={x:(Math.random()<.5?-1:1)*(Math.random()/2),y:.7*Math.random()+.9},this.position={x:t,y:e},this.canv=n,this.update=function(t){this.position.x+=this.velocity.x,this.position.y+=this.velocity.y,this.lifeSpan--,this.velocity.y+=.02;const e=Math.max(this.lifeSpan/this.initialLifeSpan,0);t.drawImage(this.canv,this.position.x-this.canv.width/2*e,this.position.y-this.canv.height/2,this.canv.width*e,this.canv.height*e)}}(t,e,n))}function w(){!function(){if(0!=h.length){r.clearRect(0,0,n,i);for(let t=0;t<h.length;t++)h[t].update(r);for(let t=h.length-1;t>=0;t--)h[t].lifeSpan<0&&h.splice(t,1);0==h.length&&r.clearRect(0,0,n,i)}}(),d=requestAnimationFrame(w)}function g(){c.remove(),cancelAnimationFrame(d),e.removeEventListener("mousemove",p),e.removeEventListener("touchmove",v),e.removeEventListener("touchstart",v),window.addEventListener("resize",m)}u.onchange=(()=>{u.matches?g():f()}),f()}();
|
|
@ -38,5 +38,7 @@
|
|||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src='/script/cursor.min.js' type='application/javascript'></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue