블로그 심심해 2탄을 준비해봤다. 이전 포스팅에서 스크롤할때 내가 현재 읽고 있는 글의 상태를 바형태로 넣어보았다. 🙂 그래도 뭔가 좀 심심하다… 이번에는 마우스커서를 바꿔보기로 해보자.
아래는 먼저 참고한 사이트의 튜토리얼이다. 음 상당히 복잡하고 어렵다… 그래서 최대한 요약해서 필요한것만 적용해보기로 했다.
심심해 1탄 프로그레스바 포스트보기
마크업 적용
전역에 들어가야 하니 헤더나 푸터에 넣고 싶은곳에 넣자.
<div class="cursor cursor--small"></div>
<canvas class="cursor cursor--canvas" resize></canvas>
스타일 적용
@media only screen and (min-width:769px) {
body,
a {
cursor: none;
}
.cursor {
position: fixed;
left: 0;
top: 0;
pointer-events: none;
}
.cursor--small {
width: 20px;
height: 20px;
left: -10px;
top: -10px;
border-radius: 50%;
z-index: 99;
background: #b7dde18c;
}
.cursor--canvas {
width: 100vw;
height: 100vh;
z-index: 100;
}
}
@media only screen and (max-width:768px) {
body {
cursor: none;
}
.cursor--small,
.cursor--canvas {
display: none;
}
}
자바 스크립트 적용
const cursorModule = () => {
const innerCursor = document.querySelector(".cursor--small");
const canvas = document.querySelector(".cursor--canvas");
let clientX = -100;
let clientY = -100;
const initCursor = () => {
document.addEventListener("mousemove", e => {
clientX = e.clientX;
clientY = e.clientY;
});
const render = () => {
TweenMax.set(innerCursor, {
x: clientX,
y: clientY
});
requestAnimationFrame(render);
};
requestAnimationFrame(render);
};
initCursor();
let lastX = 0;
let lastY = 0;
let isStuck = false;
let showCursor = false;
let group;
let stuckX;
let stuckY;
let fillOuterCursor;
const initCanvas = () => {
const shapeBounds = {
width: 75,
height: 75,
};
paper.setup(canvas);
const strokeColor = 'rgba(60, 74, 83, 0.5)';
const strokeWidth = 1;
const segments = 8;
const radius = 15;
const noiseScale = 150;
const noiseRange = 6;
let isNoisy = false;
const polygon = new paper.Path.RegularPolygon(
new paper.Point(0,0),
segments,
radius,
);
polygon.strokeColor = strokeColor;
polygon.strokeWidth = strokeWidth;
polygon.smooth();
group = new paper.Group([polygon]);
group.applyMatrix = false;
const noiseObjects = polygon.segments.map(() => new SimplexNoise());
let bigCoordinates = [];
const lerp = (a, b, n) => {
return (1 - n) * a + n * b;
};
const map = (value, in_min, in_max, out_min, out_max) => {
return (
((value - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
);
};
paper.view.onFrame = event => {
if (!isStuck) {
// move circle around normally
lastX = lerp(lastX, clientX, 0.2);
lastY = lerp(lastY, clientY, 0.2);
group.position = new paper.Point(lastX, lastY);
} else if (isStuck) {
// fixed position on a nav item
lastX = lerp(lastX, stuckX, 0.08);
lastY = lerp(lastY, stuckY, 0.08);
group.position = new paper.Point(lastX, lastY);
}
if (isStuck && polygon.bounds.width < shapeBounds.width) {
// scale up the shape
polygon.scale(1.15);
} else if (!isStuck && polygon.bounds.width > 30) {
// remove noise
if (isNoisy) {
polygon.segments.forEach((segment, i) => {
segment.point.set(bigCoordinates[i][0], bigCoordinates[i][1]);
});
isNoisy = false;
bigCoordinates = [];
}
// scale down the shape
const scaleDown = 0.92;
polygon.scale(scaleDown);
}
// while stuck and big, apply simplex noise
if (isStuck && polygon.bounds.width >= shapeBounds.width) {
isNoisy = true;
// first get coordinates of large circle
if (bigCoordinates.length === 0) {
polygon.segments.forEach((segment, i) => {
bigCoordinates[i] = [segment.point.x, segment.point.y];
});
}
// loop over all points of the polygon
polygon.segments.forEach((segment, i) => {
// get new noise value
// we divide event.count by noiseScale to get a very smooth value
const noiseX = noiseObjects[i].noise2D(event.count / noiseScale, 0);
const noiseY = noiseObjects[i].noise2D(event.count / noiseScale, 1);
// map the noise value to our defined range
const distortionX = map(noiseX, -1, 1, -noiseRange, noiseRange);
const distortionY = map(noiseY, -1, 1, -noiseRange, noiseRange);
// apply distortion to coordinates
const newX = bigCoordinates[i][0] + distortionX;
const newY = bigCoordinates[i][1] + distortionY;
// set new (noisy) coordindate of point
segment.point.set(newX, newY);
});
}
polygon.smooth();
}
}
initCanvas();
const initCursorHovers = () => {
const handleCanvasCursorMouseEnter = e => {
const navItem = e.currentTarget;
const navItemBox = navItem.getBoundingClientRect();
stuckX = Math.round(navItemBox.left + navItemBox.width / 2);
stuckY = Math.round(navItemBox.top + navItemBox.height / 2);
isStuck = true;
TweenMax.to(innerCursor, 1, {background:'rgba(60, 74, 83, 0.5)', scale:0.25, ease: Expo.easeOut});
};
const handleCanvasCursorMouseLeave = () => {
isStuck = false;
TweenMax.to(innerCursor, 1, {background:'#b7dde1', scale:1, ease: Expo.easeOut});
};
const handleBasicCursorMouseEnter = e => {
TweenMax.to(innerCursor, 1, {background:'rgba(60, 74, 83, 0.5)', scale:2, ease: Expo.easeOut});
};
const handleBasicCursorMouseLeave = () => {
TweenMax.to(innerCursor, 1, {background:'#b7dde1', scale:1, ease: Expo.easeOut});
};
const $links = document.querySelectorAll('.link');
$links.forEach(link => {
link.addEventListener("mouseenter", handleCanvasCursorMouseEnter);
link.addEventListener("mouseleave", handleCanvasCursorMouseLeave);
});
const $otherLinks = document.querySelectorAll('.another-link');
$otherLinks.forEach(link => {
link.addEventListener("mouseenter", handleBasicCursorMouseEnter);
link.addEventListener("mouseleave", handleBasicCursorMouseLeave);
});
}
initCursorHovers();
}
window.onload = () => {
cursorModule();
}
워드프레스 함수에서 JS 불러오기
add_action( 'wp_enqueue_scripts', 'Scripts_mouse_effect' );
function Scripts_mouse_effect() {
wp_enqueue_script('mouse-e-script', get_stylesheet_directory_uri() . '/js/mouse-e.js', array(), '1.0.0', true );
}
라이브러리 가져오기
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.2/paper-full.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/simplex-noise/2.4.0/simplex-noise.min.js"></script>
링크호버 효과 확인
[PC에서만 확인가능]링크 호버효과 추가 클래스 link -> link A
링크 호버효과 추가 클래스 another-link -> another-link B
다른 스타일 데모 보기
Last updated on: 2022-01-29, am 12:38