Lumpy Space Princess - Adventure Time

JAVASCRIPT

Mouse Effect 01 - 마우스 따라다니기 효과에 대해서 알아보자

jongyung 2023. 3. 20. 19:28

“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90

화면에서 보이는 것처럼 마우스에 효과를 줄 수 있습니다.

이번에는 마우스 따라다니기 효과에 대해서 알아보도록 하겠습니다.

body의 main부분과 style부분 그리고 script부분을 나눠서 설명하겠습니다.

body의 main

<main id="main">
    <div class="mouse__wrap">
        <div class="mouse__cursor"></div>
        <div class="mouse__text">
            <p><span class="s1">Life</span> isn't about <span class="s2">finding</span> yourself. Life is about <span class="s3">creating</span> yourself.</p>
            <p><span class="s4">삶</span>은 자신을 <span class="s5">찾아가는 것</span>이 아니라 <span class="s6">만들어 가는 것</span>이다.</p>
        </div>
    </div>
    <div class="mouse__info">
        <ul>
            <li>clientX : <span class="clientX">0</span>px</li>
            <li>clientY : <span class="clientY">0</span>px</li>
            <li>offsetX : <span class="offsetX">0</span>px</li>
            <li>offsetY : <span class="offsetY">0</span>px</li>
            <li>pageX : <span class="pageX">0</span>px</li>
            <li>pageY : <span class="pageY">0</span>px</li>
            <li>screenX : <span class="screenX">0</span>px</li>
            <li>screenY : <span class="screenY">0</span>px</li>
        </ul>
    </div>
</main>
<!-- main -->

body부분은 보이는 것처럼 간단합니다.

이번에는 class를 style과 함수를 적용하기 위해서 지정했습니다.

style

<style>
    .mouse__wrap {
        cursor: none;
    }
    .mouse__cursor {
        position: absolute;
        left: 0;
        top: 0;
        width: 50px;
        height: 50px;
        border-radius: 50%;
        border: 3px solid #fff;
        background-color: rgba(100, 19, 240, 0.1);
        user-select: none;
        pointer-events : none;          
        transition: 
            background-color 0.3s,
            border-color 0.3s,
            transform 0.6s,
            border-radius 0.3s,
            border 0.3s
        ;
    }
    .mouse__cursor.s1 {
        background-color: rgba(255, 255, 255, 0.1);
        border-color: rgb(240, 240, 68);
    }
    .mouse__cursor.s2 {
        background-color: rgba(237, 224, 224, 0.877);
        border-color: rgb(240, 163, 68);
        transform: scale(2) rotateY(720deg);
    }
    .mouse__cursor.s3 {
        background-color: rgba(204, 63, 63, 0.434);
        border-color: rgb(197, 240, 68);
        transform: scale(1.5) rotateX(545deg);
    }
    .mouse__cursor.s4 {
        background-color: rgba(63, 204, 138, 0.434);
        border-color: rgb(206, 68, 240);
        transform: scale(10);
        border-radius: 10px;
    }
    .mouse__cursor.s5 {
        background-color: rgba(204, 204, 63, 0.434);
        border-color: rgb(68, 120, 240);
        transform: scale(5) skew(140deg) rotate(200deg);
    }
    .mouse__cursor.s6 {
        background-color: rgba(63, 72, 204, 0.434);
        border-color: rgb(102, 240, 68);
        transform: scale(0.1);
    }
    .mouse__text {
        width: 100%;
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column; 
    }
    .mouse__text p {
        font-size: 2vw;
        line-height: 2;
    }
    .mouse__text p:last-child {
        font-size: 3vw;
    }
    .mouse__text p span {
        color: gold;            
    }
    .mouse__info {
        position: absolute;
        left: 0;
        bottom: 0;
        padding: 20px;
        font-size: 16px;
        line-height: 1.6;
    }
</style>

마우스 커서의 모양을 새로 만들기 위해서 cursor : none 을 설정한 후에

동그라미에 속은 다른 색으로 만들어 주기 위해서 테두리인 border-color와 속 색인 background-color를 다르게 설정했습니다.

 

user-select : none 은 텍스트 영역이 클릭 및 드래그로 선택되지 않게 하고,

pointer-events : none 은 HTML 요소에 정의된 클릭, 상태(hover,active등), 커서 옵션들이 비활성화합니다.

이 두 가지의 속성 값들로 인해 마우스를 글자 위에 올려두면 원형을 유지하며 클릭의 동작은 하지 않도록 했습니다.

 

transition 효과를 넣음으로써 마우스가 어느 곳에 도달하게 되면 변하는데, 이 때에 시간이 설정한 정도로 걸리도록 했습니다.

어느 곳에 해당되는 .mouse__cursor.s1~6는 각자 다른 색의 테두리와 색으로 정했습니다.

여기에 더한 transform 효과들에 대해서 알아보자면,

 

  • transform:scale() - X 또는 Y축으로 확대/ 축소
    scale은 해당 요소를 지정한 크기만큼 확대 또는 축소 시킬 수 있습니다.
  • transform:rotate() - 지정 요소 회전
    rotate는 요소를 지정한 각도만큼 회전시킵니다.
    회전 각도가 플러스 값일 경우 시계 방향, 마이너스 값일 경우 반시계 방향으로 회전합니다.
  • transform:translate() - 지정 요소 X 또는 Y축으로 이동
    translate는 요소를 지정한 위치로 X 또는 Y축만큼 이동 시킵니다.
  • transform:skew() - 지정 요소 X 또는 Y축으로 기울이기
    skew는 요소를 지정한 만큼 X 또는 Y축으로 기울입니다.
  • transform-origin 속성
    위의 transform 속성인 scale(), rotate(), translate(), skew()들을 한번씩 연습해 보았다면, 지정 요소의 중심을 기준으로 동작한다는 것을 알 수 있을 것 입니다.
    하지만 transform-origin 을 사용하면 지정 요소의 기준점을 변경할 수 있습니다.

.mouse__text.mouse__info 로 글자를 정렬시키고, 꾸몄습니다.

script

<script>
    window.addEventListener("mousemove", function(event){
        document.querySelector(".clientX").innerHTML = event.clientX;
        document.querySelector(".clientY").innerHTML = event.clientY;
        document.querySelector(".offsetX").innerHTML = event.offsetX;
        document.querySelector(".offsetY").innerHTML = event.offsetY;
        document.querySelector(".pageX").innerHTML = event.pageX;
        document.querySelector(".pageY").innerHTML = event.pageY;
        document.querySelector(".screenX").innerHTML = event.screenX;
        document.querySelector(".screenY").innerHTML = event.screenY;            
    }); //event는 마우스의 정보

    //선택자
    const cursor = document.querySelector(".mouse__cursor");

    window.addEventListener("mousemove", function(e){
        cursor.style.left = e.clientX -25 + "px";
        cursor.style.top = e.clientY -25 + "px";
    });

    // for(let i=0; i<=7; i++){
    //     documnet.querySelectorAll(".mouse__info ul li span").forEach(function(el,index){
    //         el.innerHTML = index+1 + "00";
    //     });
    // }

    // document.querySelector(".s1").addEventListener("mouseover", function(){
    //     cursor.classList.add("s1");
    // });

    // document.querySelector(".s1").addEventListener("mouseout", function(){
    //     cursor.classList.remove("s1");
    // });

    // document.querySelector(".s2").addEventListener("mouseover", function(){
    //     cursor.classList.add("s2");
    // });

    // document.querySelector(".s2").addEventListener("mouseout", function(){
    //     cursor.classList.remove("s2");
    // });

    // document.querySelector(".s3").addEventListener("mouseover", function(){
    //     cursor.classList.add("s3");
    // });

    // document.querySelector(".s3").addEventListener("mouseout", function(){
    //     cursor.classList.remove("s3");
    // });

    // document.querySelector(".s4").addEventListener("mouseover", function(){
    //     cursor.classList.add("s4");
    // });

    // document.querySelector(".s4").addEventListener("mouseout", function(){
    //     cursor.classList.remove("s4");
    // });

    // document.querySelector(".s5").addEventListener("mouseover", function(){
    //     cursor.classList.add("s5");
    // });

    // document.querySelector(".s5").addEventListener("mouseout", function(){
    //     cursor.classList.remove("s5");
    // });

    // document.querySelector(".s6").addEventListener("mouseover", function(){
    //     cursor.classList.add("s6");
    // });

    // document.querySelector(".s6").addEventListener("mouseout", function(){
    //     cursor.classList.remove("s6");
    // });

    // for(let i=1; i<=6; i++){
    //     document.querySelector(".s"+i).addEventListener("mouseover", function(){
    //         cursor.classList.add("s"+i);
    //     });

    //     document.querySelector(".s"+i).addEventListener("mouseout", function(){
    //         cursor.classList.remove("s"+i);
    //     });
    // }

    document.querySelectorAll(".mouse__text span").forEach(function(el,index){
        el.addEventListener("mouseover", function(){
            cursor.classList.add("s"+(index+1));
        });
        el.addEventListener("mouseout", function(){
            cursor.classList.remove("s"+(index+1));
        });
    });

    //getAttribute(); //속성 값을 가져옴
    document.querySelectorAll(".mouse__text span").forEach(function(span){

        let attr = span.getAttribute("class");

        //attr = s1 s2 s3 s4 s5 s6

        span.addEventListener("mouseover", function(){
            cursor.classList.add(attr);
        });
        span.addEventListener("mouseout", function(){
            cursor.classList.remove(attr);
        });
    });

    //setAttribute(); //값을 가져옴

</script>

window 객체는 브라우저라는 host 환경에서 동작하는 최상위 객체로, 브라우저 환경에서 동작하는 여러 API들의 가교 역할을 합니다.

document, history, location, setTimout, cookieStore 등 다른 브라우저 api에 접근을 제공합니다.

뿐만 아니라 브라우저 탭에 대한 접근 권한이 있기 때문에 window.open, window.close, window.location 등을 통해 브라우저 탭 레벨의 여러 제어가 가능하다.  
console, alret, confirm 등의 fucntion이 window객체에 정의되어 있습니다.

document 객체는 window에 로드되는 HTML 문서 그 자체를 나타내며, 해당 문서 내부의 HTML Element, Css 등을 제어할 수 있는 여러 메서드를 제공합니다. 보편적으로 window 객체의 프로퍼티로 제공됩니다.
일반적으로 querySelector 등의 메서드로 css selector 기반의 element 쿼리를 많이 하게 됩니다.

 

addEventListener()는 document의 특정요소(Id,class,tag 등등..) event(ex - click하면 함수를 실행하라, 마우스를 올리면 함수를 실행하라 등등.. )를 등록할 때 사용합니다.
하나의 이벤트에서 여러 개의 이벤트 핸들러 함수를 등록하거나, 동일 객체의 동일 이벤트에 서로 다른 모듈이 이벤트 핸들러를 여러개 등록하는 데 문제가 없으려면, 다른 이벤트 핸들러 등록 방법을 사용해야 합니다.

이벤트 대상이 되는 대다수 객체에는 이런 용도로 addEventListener()라는 이벤트 리스너 등록 메서드가 있습니다.

 

mousemove 는 마우스가 움직일 때마다 발생합니다. 마우스 커서의 현재 위치를 계속 기록하는 것에 사용할 수 있습니다.

mouseover 는 마우스를 HTML요소 위에 올리면 발생합니다.

mouseout 는 마우스가 HTML요소 밖으로 벗어날 때 발생합니다.

 

여기에 함수를 적용해서 커서를 다양한 모습으로 변하게 실행시킨 것입니다.

같은 함수를 반복해서 쓰는 것을 피하기 위해서 forEach 메서드로 함수식을 실행시킨 과정을 적은 것입니다.

함수에서 요소, 인덱스,배열의 순으로 값을 찾을 수 있기 때문에, 이를 이용해서 찾고 싶은 값의 자릿수 즉, 인덱스를 문자와 함께 쓴 모습이 ( "s" + (index + 1) ) 이렇게 나온 것입니다.

 

classList 사용은 공백으로 구분된 문자열인 element.className 을 통해 엘리먼트의 클래스 목록에 접근하는 방식을 대체하는 간편한 방법입니다. 이를 이용해서 mouseover 일 때와 mouseout 일 때의 모습을 각 각 다르게 출력하도록 했습니다.