groupBy API

JS에서 어떤 데이터를 표현하는 객체의 형태를 변경하는 일은 매우 자주 있고 이에 대한 코드를 작성하는 것은 한번 정도는 도전 정신이 발휘 되기도 하지만 그 다음부터는 짜증스럽기도 합니다. 아래와 같은 데이터가 있다고 가정해 봅시다.

[
  { name: "Jim", age: 48, sex: "F" },
  { name: "Kyle", age: 28, sex: "M" },
  { name: "Sally", age: 28, sex: "F" },
  { name: "Jane", age: 32, sex: "M" },
  { name: "Tom", age: 48, sex: "F" }
]

이 데이터의 필드 중 sex는 성별을 나타내는 것으로 이를 기준으로 데이터를 다음처럼 구성하려고 합니다.

{
  "F": [
    {"name":"Jim","age":48,"sex":"F"},
    {"name":"Sally","age":28,"sex":"F"},
    {"name":"Tom","age":48,"sex":"F"}
  ],
  "M": [
    {"name":"Kyle","age":28,"sex":"M"},
    {"name":"Jane","age":32,"sex":"M"}
  ]
}

데이터의 표현을 F, M으로 구분해 다시 구성한 형태입니다. 이를 위한 목적을 이루기 위해 JS는 하나의 API 제공하고 있는데 다음과 같습니다.

const people = [
  { name: "Jim", age: 48, sex: "F" },
  { name: "Kyle", age: 28, sex: "M" },
  { name: "Sally", age: 28, sex: "F" },
  { name: "Jane", age: 32, sex: "M" },
  { name: "Tom", age: 48, sex: "F" }
]

const groupBySex = Object.groupBy(people, person => {
  return person.sex
})

Object.groupBy가 핵심인데 이 API는 입력 데이터는 변경하지 않고 새로운 데이터를 만들어 반환합니다.

JS를 통해 CSS에 값 전달하기

JS 코드에서 어떤 값을 정해서 CSS에 전달해서 CSS를 통한 스타일을 정의할 때 전달받은 값을 사용하는 내용입니다.

먼저 JS에서 값을 전달하기 위해서는 특정 DOM에 대한 style에 속성(Property)를 설정해 주면 되는데요. 예를 들어서 –x와 –y라는 속성을 설정해 주는 코드는 다음과 같습니다.

const pos = document.documentElement
pos.addEventListener("mousemove", e => {
    pos.style.setProperty("--x", e.clientX + "px")
    pos.style.setProperty("--y", e.clientY + "px")
})

위의 코드는 document에 해당하는 DOM의 스타일에 대한 속성(–x, –y)를 설정하는 코드입니다. 좀더 자세히 설명드리면 마우스 커서의 위치 값으로 설정하고 있습니다. 반드시 document의 스타일 속성으로 설정해야 합니다.

이렇게 JS에서 설정한 값을 CSS에서 사용하는 방식은 다음과 같습니다.

.banner {
  clip-path: circle(15vh at var(--x) var(--y));
}

핵심은 var이라는 명령을 통해 JS를 통해 설정했던 –x와 –y의 값을 바로 사용할 수 있다는 것입니다.

위의 코드를 활용한 예제는 아래와 같습니다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      font-family: 'Gill Sans';
      box-sizing: border-box;
    }

    body {
      background: #111;
      user-select: none;
    }

    .banner {
      position: fixed;
      width: 100%;
      height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      background: #fff;
      z-index: 1;
      /* clip-path: circle(15vh at center center); */
      clip-path: circle(15vh at var(--x) var(--y));
      transition: all .1s linear;
    }

    .banner h2 {
      /* position: relative; */
      color: transparent;
      -webkit-text-stroke: 4px #333;
      font-size: 25vh;
      pointer-events: none;
    }

    .content {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }

    .content h2 {
      color: transparent;
      -webkit-text-stroke: 4px #333;
      font-size: 25vh;
      pointer-events: none;
    }
  </style>
</head>
<body>
  <section class="banner">
    <h2>GIS DEVELOPER</h2>
  </section>
  <section class="content">
    <h2>GIS DEVELOPER</h2>
  </section>

  <script>
    const pos = document.documentElement
    pos.addEventListener("mousemove", e => {
      pos.style.setProperty("--x", e.clientX + "px")
      pos.style.setProperty("--y", e.clientY + "px")
    })
  </script>
</body>
</html>

실행 결과는 다음과 같습니다.