매우 간단한 스크롤 이벤트를 해보자

addEventListener에 대해 설명하면서 스크롤 이벤트도 ‘있다’고 했는데, 이건 말 그대로 마우스를 스크롤했을 때 일어나는 이벤트이다. 그게 다다.

Reference

https://velog.io/@dunde/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8

https://velog.io/@dunde/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8

https://stackoverflow.com/questions/40475155/does-javascript-have-a-method-that-returns-an-array-of-numbers-based-on-start-s


Basic-마우스 스크롤 위치를 화면에 표시하기

See the Pen scroll events-Basics by koreanraichu (@koreanraichu) on CodePen.

여기서는

let contents = document.querySelector('#content1');

window.addEventListener('scroll', () => { 
  console.log(window.scrollX, window.scrollY);
  let new_pTag = document.createElement('p');
  new_pTag.innerHTML = 'scroll are here: ' + window.scrollY;
  contents.appendChild(new_pTag)
});

를 썼는데 이거는 말 그대로 스크롤을 내렸을 때 X, Y축 위치를 나타낸다. 근데 얘는 스크롤바가 없는 상태에서는 안되더라…

스크롤을 올리고 내릴때마다 색깔 바꾸기

이건 addEventListener가 아니라 windows.onwheel을 사용해서 구현했다. addEventListener(‘wheel’,())와 비슷하다. 일단 블로그를 참고해서 만든 코드부터 보고 가자.

See the Pen Scroll Events-Animation by koreanraichu (@koreanraichu) on CodePen.

HTML이나 CSS는 사실 뭐 특별한 건 없고, 자바스크립트 코드를 보자.

//Reference: https://velog.io/@minkyeong-ko/Javascript-%EC%8A%A4%ED%81%AC%EB%A1%A4%EC%97%90-%EB%94%B0%EB%A5%B8-%EB%B0%B0%EA%B2%BD%EC%83%89-%EB%B3%80%EA%B2%BD

var colors = ['#000000', '#333333', '#666666', '#999999', '#CCCCCC', '#FFFFFF'];
var wrapper = document.querySelector('.box');
var title = document.getElementsByTagName('h1')[0];
var text = document.querySelector('#text');

wrapper.onwheel = changeColor;

var colorIndex = 0;
var scrollValue = 0;

function changeColor(e) {
    scrollValue += e.deltaY * 0.01;
    if (scrollValue > 10) {
        colorIndex += 1;
        if (colorIndex > colors.length - 1) {
            colorIndex = 0;
        }
        text.innerText = colors[colorIndex];
        wrapper.style.backgroundColor = colors[colorIndex];
        if (colorIndex >= 3) {
            title.style.color = '#000000'
            text.style.color = '#000000';
        }
        scrollValue = 0;
    }

    if (scrollValue < -10) {
        colorIndex -= 1;
        if (colorIndex < 0) {
            colorIndex = colors.length - 1;
        }
        text.innerText = colors[colorIndex];
        wrapper.style.backgroundColor = colors[colorIndex];
        if (colorIndex >= 3) {
            title.style.color = '#000000';
            text.style.color = '#000000';
        }
        scrollValue = 0;
    }
}

델타는 말 그대로 Δ이다. 그… 자 그래서 저 세모 어디서 봤어요? 슈뢰딩거 방정식? 그건 ∇(del operator)임… 저거 미분에 나오잖아여… 변화량. 근데 변화량이랑 스크롤이랑 뭔 상관이냐…. 휠 이벤트는 위에 스크롤과 달리 휠을 올렸는가/내렸는가를 확인해 거기에 맞는 이벤트를 준다. 크게 if문이 두 개인데 위쪽은 스크롤을 올렸을 때, 아래쪽은 스크롤을 내렸을 때. scrollValue라는 변수를 통해 delta, 즉 스크롤의 변화를 누적시킨 다음 어느정도 변화가 생겼다 그러면 다음 색으로 넘긴다.

그리고 원래 코드에는 없던 기능이 하나 있는데, 검정->하양으로 가다 보면 글자 색이 하양일 때 안 보이는 배경색이 당연히 존재한다. 이건 뭐 착한 사람도 안 보이는 배경이여… 그래서 colorIndex 배열에서 #999999부터는 글자색도 흰색으로 바꿨다.

See the Pen Scroll Events-Animation(Gradation) by koreanraichu (@koreanraichu) on CodePen.

얘는 위의 코드를 살짝 응용했다.

function makeArr(startValue, stopValue, cardinality) {
    var arr = [];
    var step = (stopValue - startValue) / (cardinality - 1);
    for (var i = 0; i < cardinality; i++) {
        arr.push(startValue + (step * i));
    }
    return arr;
}

var colors = [];
var red = makeArr(65, 53, 8);
var green = makeArr(184, 73, 8);
var blue = makeArr(131, 94, 8);

for (let i = 0; i < red.length; i++) {
    var red_grad = (Math.floor(red[i]).toString(16).padStart(2, '0'))
    var green_grad = (Math.floor(green[i]).toString(16).padStart(2, '0'))
    var blue_grad = (Math.floor(blue[i]).toString(16).padStart(2, '0'))
    var color_code = '#' + red_grad + green_grad + blue_grad
    colors.push(color_code)
}

배열 관련해서 추가 및 수정된 부분이 이거. 기본 코드는 배열 안에 풀로 색깔 코드가 들어갔는데, 여기서는 좀 자연스러운 변화를 줘야 하는데 인제 그걸 시작과 끝을 이용해서 알아서 만드는? 뭐 그런거다. 예를 들어서 빨강이 255이고 0까지 5개로 만들어달라고 하면 알아서 딱딱 나누는 대충 넘파이의 linspace같은 기능…인데 이제 그게 자바스크립트에 없어요… 그럼 어쩌겠음. 함수 때려박아야지…

그래서 RGB에 대해 일정한 간격을 가지는 배열을 만든 다음 그걸 합해서 색깔 코드를 만든 게 저거다.

참고로 배경 고정값이 Vue.js 로고 컬러다. 그거 이쁘잖음.

See the Pen Scroll Events-Animation(Gradation 2) by koreanraichu (@koreanraichu) on CodePen.

또 응용편이 나왔는데 이거는 처음 색과 끝 색을 지정해서 매우 자연스러운 색 변화를 유도할 수 있다. 좋아 자연스러웠어 그래서 함수가 또 복잡해졌다. 왜냐하면 입력한 색에서 RGB를 또 가져와야 하거든… 

const button = document.getElementById('confirm');
button.addEventListener('click', () => {
    makeColor()
})

function makeColor() {
    var startcolor = document.getElementById('startcolor').value;
    var endcolor = document.getElementById('endcolor').value;

    var start_red = startcolor.substr(0, 2);
    start_red = parseInt(start_red, 16);
    var end_red = endcolor.substr(0, 2);
    end_red = parseInt(end_red, 16);

    var start_green = startcolor.substr(2, 2);
    start_green = parseInt(start_green, 16);
    var end_green = endcolor.substr(2, 2);
    end_green = parseInt(end_green, 16);

    var start_blue = startcolor.substr(4, 2);
    start_blue = parseInt(start_blue, 16);
    var end_blue = endcolor.substr(4, 2);
    end_blue = parseInt(end_blue, 16);

    var red = makeArr(start_red, end_red, 10);
    var green = makeArr(start_green, end_green, 10);
    var blue = makeArr(start_blue, end_blue, 10);

    for (let i = 0; i < red.length; i++) {
        var red_grad = (Math.floor(red[i]).toString(16).padStart(2, '0'))
        var green_grad = (Math.floor(green[i]).toString(16).padStart(2, '0'))
        var blue_grad = (Math.floor(blue[i]).toString(16).padStart(2, '0'))
        var color_code = '#' + red_grad + green_grad + blue_grad
        colors.push(color_code)
    }

    text.innerText = colors[colorIndex];
    wrapper.style.backgroundColor = colors[colorIndex];

    return colors
}

버튼은 뭐… 다들 아실테니 패스하고, 색깔 부분을 살펴보자. 시작색과 끝색의 RGB로 자연스러운 그라데이션을 만들기 위해서는 RGB별로 10진수가 필요하고, 그걸로 등간격인 10개의 요소를 만들게 된다. 그리고 적용하는 건 똑같다. 근데 이제 여기까지는 글자색이 안바꼈었는데…

function makeColor() {
    var startcolor = document.getElementById('startcolor').value;
    var endcolor = document.getElementById('endcolor').value;

    var start_red = startcolor.substr(0, 2);
    start_red = parseInt(start_red, 16);
    var invert_start_red = 255 - start_red;
    var end_red = endcolor.substr(0, 2);
    end_red = parseInt(end_red, 16);
    var invert_end_red = 255 - end_red;

    var start_green = startcolor.substr(2, 2);
    start_green = parseInt(start_green, 16);
    var invert_start_green = 255 - start_green;
    var end_green = endcolor.substr(2, 2);
    end_green = parseInt(end_green, 16);
    var invert_end_green = 255 - end_green;

    var start_blue = startcolor.substr(4, 2);
    start_blue = parseInt(start_blue, 16);
    var invert_start_blue = 255 - start_blue;
    var end_blue = endcolor.substr(4, 2);
    end_blue = parseInt(end_blue, 16);
    var invert_end_blue = 255 - end_blue;

    var red = makeArr(start_red, end_red, 10);
    var invert_red = makeArr(invert_start_red, invert_end_red, 10);
    var green = makeArr(start_green, end_green, 10);
    var invert_green = makeArr(invert_start_green, invert_end_green, 10);
    var blue = makeArr(start_blue, end_blue, 10);
    var invert_blue = makeArr(invert_start_blue, invert_end_blue, 10);

    for (let i = 0; i < red.length; i++) {
        var red_grad = (Math.floor(red[i]).toString(16).padStart(2, '0'));
        var invert_red_grad = (Math.floor(invert_red[i]).toString(16).padStart(2, '0'));
        var green_grad = (Math.floor(green[i]).toString(16).padStart(2, '0'));
        var invert_green_grad = (Math.floor(invert_green[i]).toString(16).padStart(2, '0'));
        var blue_grad = (Math.floor(blue[i]).toString(16).padStart(2, '0'));
        var invert_blue_grad = (Math.floor(invert_blue[i]).toString(16).padStart(2, '0'));
        var color_code = '#' + red_grad + green_grad + blue_grad;
        var invert_color_code = '#' + invert_red_grad + invert_green_grad + invert_blue_grad;
        colors.push(color_code)
        invert_colors.push(invert_color_code)
    }

    text.innerText = colors[colorIndex];
    text.style.color = invert_colors[colorIndex];
    title.style.color = invert_colors[colorIndex];
    button.style.color = colors[colorIndex];
    button.style.backgroundColor = invert_colors[colorIndex];
    wrapper.style.backgroundColor = colors[colorIndex];
    for (let i = 0; i < label.length; i++) {
        label[i].style.color = invert_colors[colorIndex]
    }
    for (let i = 0; i < input.length; i++) {
        input[i].style.border = '2px solid' + invert_colors[colorIndex];
    }

    return colors, invert_colors
}

놀랍게도 글자색도 바뀌게 할 수 있었다. 이것은 매우 놀랍게도 진짜다. 입력값을 RGB로 나눠서 배열로 만들 때 invert_colors라는 배열을 추가로 만들게 되는데, 여기에 들어가는 요소는 시작색의 RGB, 끝색의 RGB의 255의 보수로 만든 배열이 들어간다. 이게 뭐야 우리가 2의 보수 1의 보수가 유명해서 글치 이진법에서만 보수 쓰라는 법은 없음. 아무튼 그래서.. 

이렇게 됐는데… 하다보면 글자 색이 궁금할 수도 있죠?

text.innerText = 'background-color: ' + colors[colorIndex] + '/' + 'font-color: ' + invert_colors[colorIndex];

이걸 추가해주자.

참 쉽죠?