[웹으로 낙서하기#1]자바스크립트를 사용해서 웹 브라우저에 디지털 시계를 올려놔보자!

2020. 7. 23. 18:30웹돌이 단편선

웹으로 낙서하기 시리즈를 여는 글로써, 자바스크립트를 사용해 디지털 시계를 만들어보겠습니다.

 


필요한 기능

  1. 현재 시간을 HH:mm:ss 포맷으로 보여준다.
  2. 디지털 시계다.
  3. 1초마다 초가 흐른다.

필요한 기능은 이정도만 있으면 될것 같으니 바로 작업을 시작하면 될것같다.


첫 시작

먼저 현재시간을 보여준다.

import React from "react";

function DigitalClock() {
  return <div>{new Date().toString()}</div>;
}

export default DigitalClock;

이제 시계에 보여주고 싶은 HH:mm:ss에 대한 값만 추려서 화면에 뿌려주면 된다.

 

HH, mm, ss를 가져오는 메소드는 각각 아래와 같다.

HH - Date.prototype.getHours

mm - Date.prototype.getMinutes

ss - Date.prototype.getSeconds

메소드들을 사용하여 코드를 수정해보았다. 현재시간 13시 03분 41초였다.

import React from "react";

function DigitalClock() {
  const date = new Date();

  const HH = date.getHours();
  const mm = date.getMinutes();
  const ss = date.getSeconds();

  return <div>{`${HH}:${mm}:${ss}`}</div>;
}

export default DigitalClock;

 

화면에 보여지는 결과는 위와 같다. 시간, 분, 초가 각각 10미만의 정수일때 00 ~ 09의 포맷으로 보이도록 처리가 필요하다.

1 ~ 10의 자릿수까지의 입력에 대하여, 한자릿수만 받으면 앞에 0을 붙이는 함수를 선언했다.

function getZeroPadString(number) {
  return number.toString().replace(/([0-9])?([0-9])$/g, function (_, $1, $2) {
    return `${$1 || 0}${$2}`;
  });
}

함수 검증 완료!

함수를 사용해서 이제 원하는 포맷으로 표현이 된다! 이제 디지털 시계처럼 숫자를 보여주는 작업을 해보겠다.

 

Digit 컴포넌트 만들기

우선 DigitalClock 컴포넌트를 이정도까진 만들고, Digit 컴포넌트를 추가한다.

import React from "react";
import Digit from "../../atoms/Digit";

function getZeroPadString(number) {
  return number.toString().replace(/([0-9])?([0-9])$/g, function (_, $1, $2) {
    return `${$1 || 0}${$2}`;
  });
}

function mapDigit(digit, i) {
  return <Digit key={i} value={digit} />;
}

function DigitalClock() {
  const date = new Date("2020-07-20 13:03:41");

  const HH = getZeroPadString(date.getHours());
  const mm = getZeroPadString(date.getMinutes());
  const ss = getZeroPadString(date.getSeconds());

  return (
    <div>
      {Array.from(HH).map(mapDigit)}:{Array.from(mm).map(mapDigit)}:
      {Array.from(ss).map(mapDigit)}
    </div>
  );
}

export default DigitalClock;

Digit

Digit.js

import React from "react";
import PropTypes from "prop-types";
import c from "./Digit.module.scss";

function Digit({ value }) {
  return <div className={c["wrapper"]}>{value}</div>;
}

Digit.defaultProps = { value: 0 };
Digit.propTypes = { value: PropTypes.number };

export default Digit;

Digit.module.scss

.wrapper {
  display: inline-block;
}

Digit 컴포넌트 내용을 채워서 원하는 디지털 시계의 모양을 만들어보자!

일단 비트맵 느낌의 Digit 컴포넌트를 만들어봤다. 코드는 다음과 같다.

Digit.js

import React from "react";
import PropTypes from "prop-types";
import c from "./Digit.module.scss";

function Digit({ value }) {
  return (
    <div className={c["wrapper"]}>
      {new Array(3)
        .fill("horizontal")
        .concat(new Array(4).fill("vertical"))
        .map((orientation, i) => (
          <div
            className={
              c["dash"] + " " + c[orientation] + " " + c[`dash-${i + 1}`]
            }
          />
        ))}
    </div>
  );
}

Digit.defaultProps = { value: 0 };
Digit.propTypes = { value: PropTypes.number };

export default Digit;

Digit.module.scss

.wrapper {
  margin: 0 0.1em;
  display: inline-block;
  position: relative;
  width: 0.5em;
  height: 1em;
  vertical-align: text-top;

  .dash {
    width: 4px;
    height: 4px;
    background-color: black;
    position: absolute;

    &.horizontal {
      width: 0.5em;
      left: 50%;
      transform: translateX(-50%) translateY(-2px);
    }

    &.vertical {
      height: 0.5em;
      transform: translateX(-50%) translateY(0);
    }

    &.dash-1 {
      top: 0;
    }

    &.dash-2 {
      top: 50%;
    }

    &.dash-3 {
      top: 100%;
    }

    &.dash-4,
    &.dash-5 {
      top: 0%;
    }

    &.dash-6,
    &.dash-7 {
      top: 50%;
    }

    &.dash-4,
    &.dash-6 {
      left: 0;
    }

    &.dash-5,
    &.dash-7 {
      left: 100%;
    }
  }
}

8비트 감성의 시계가 얼추 모양을 드러내는것 같으니, 이제 시간 분별이 가능하도록 생명을 불어넣겠다. 각각의 dash 요소가 on, off 상태를 갖도록 할것이다.

Digit.module.scss

.wrapper {
  margin: 0 0.1em;
  display: inline-block;
  position: relative;
  width: 0.5em;
  height: 1em;
  vertical-align: text-top;

  .dash {
    width: 4px;
    height: 4px;
    background-color: #cccccc;
    position: absolute;
    transition: background-color 0.3s ease;

    &.active {
      background-color: #000000;
    }

    &.horizontal {
      width: 0.5em;
      left: 50%;
      transform: translateX(-50%) translateY(-2px);
    }

    &.vertical {
      height: 0.5em;
      transform: translateX(-50%) translateY(0);
    }

    &.dash-1 {
      top: 0;
    }

    &.dash-2 {
      top: 50%;
    }

    &.dash-3 {
      top: 100%;
    }

    &.dash-4,
    &.dash-5 {
      top: 0%;
    }

    &.dash-6,
    &.dash-7 {
      top: 50%;
    }

    &.dash-4,
    &.dash-6 {
      left: 0;
    }

    &.dash-5,
    &.dash-7 {
      left: 100%;
    }
  }
}

.dash 요소에 대해서 .active라는 클래스의 스타일을 추가하고, Digit.js 파일은 각 value에 대해서 각 선이 가져야할 active 상태에 대한 배열을 정의한다.

import React from "react";
import PropTypes from "prop-types";
import c from "./Digit.module.scss";

const ENTIRE_STATE_MATRIX = [
  [1, 0, 1, 1, 1, 1, 1],
  [0, 0, 0, 0, 1, 0, 1],
  [1, 1, 1, 0, 1, 1, 0],
  [1, 1, 1, 0, 1, 0, 1],
  [0, 1, 0, 1, 1, 0, 1],
  [1, 1, 1, 1, 0, 0, 1],
  [1, 1, 1, 1, 0, 1, 1],
  [1, 0, 0, 1, 1, 0, 1],
  [1, 1, 1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1, 0, 1],
];

function Digit({ value }) {
  const stateMatrix = ENTIRE_STATE_MATRIX[value];

  return (
    <div className={c["wrapper"]}>
      {new Array(3)
        .fill("horizontal")
        .concat(new Array(4).fill("vertical"))
        .map((orientation, i) => (
          <div
            className={
              c["dash"] +
              " " +
              c[orientation] +
              " " +
              c[`dash-${i + 1}`] +
              (stateMatrix[i] ? " " + c["active"] : "")
            }
          />
        ))}
    </div>
  );
}

Digit.defaultProps = { value: 0 };
Digit.propTypes = { value: PropTypes.number };

export default Digit;

 

모든 숫자가 잘 나오는지 App.js에 나열하여 확인해보았다.

import React from "react";
import Digit from "./components/atoms/Digit";

function App() {
  return new Array(10).fill(null).map((_, i) => <Digit value={i} />);
}

export default App;

 

숫자, 디지털, 성공적

만족스럽다.

디지털 시계

만든 Digit 컴포넌트를 사용하여 DigitalClock를 보여주고 남은 부분은 1초마다 현재 시간을 가져와서 화면에 보여주면 될것같다.

 

추가적인 부분은 추가적인 글을 게시해서 풀어가야겠다.