삽입 정렬에 대해 알아봅니다.

삽입 정렬

 

삽입 정렬

 

1. 삽입 정렬이란 무엇이고, 어떻게 이뤄지는가?

2. 코드로 살펴보기

 

1. 삽입 정렬이란 무엇이고, 어떻게 이뤄지는가?

 정렬된 요소를 왼쪽으로, 정렬 되지 않은 요소는 오른쪽에 있다고 가정한다. 오른쪽에서 정렬이 되지 않은 요소를 가져와 이미 정렬된 요소들과 비교하여 적절한 위치에 삽입한다.
 이중 반복문을 사용하며, 시간 복잡도는 항상 n^2이다. 따라서 배열의 길이가 늘어날수록 시간이 급격히 증가한다.

2. 코드로 살펴보기

function insertionSort(arr) {
  const len = arr.length;

  for (let i = 1; i < len; i++) {
  // 인덱스 0 요소는 이미 왼쪽에서 정렬되어 있다고 가정한다.
  
    const current = arr[i];
    // 이번 회차에서 정렬하고차 하는 요소

    let j = i - 1;
    // 이미 정렬된 요소의 가장 오른쪽부터 비교를 시작한다.

    while (j >= 0 && arr[j] > current) {
      arr[j + 1] = arr[j];
      j--;
      // 현재 비교하는 수가 정렬 요소의 수보다 작을 때, 정렬된 요소를 오른쪽으로 한칸 땡긴다.
      // 그리고 왼쪽 요소와 비교를 한번 더 진행한다.
    }

    arr[j + 1] = current;
    // 정렬된 요소 중에서 더 작은 수가 없을 경우, 현재 요소를 정렬된 요소의 인덱스로 집어 넣는다.
    
  }

  return arr;
}

'컴퓨터 과학 > 알고리즘' 카테고리의 다른 글

선택 정렬  (0) 2024.04.25
버블 정렬  (0) 2024.04.24

선택 정렬에 대해 알아봅니다.

선택 정렬

 

선택 정렬

 

1. 선택 정렬이란 무엇이고, 어떻게 이뤄지는가?

2. 코드로 살펴보기

 

1. 선택 정렬이란 무엇이고, 어떻게 이뤄지는가?

 가장 큰 수, 혹은 가장 작은 수를 선택해서 정렬을 반복하는 과정이다. 이중 반복문을 사용하며, 각 회차마다 정렬이 되지 않은 모든 요소를 조회하여 가장 큰 수(가장 작은 수)를 찾아 제일 오른쪽(왼쪽)으로 위치를 변경한다.
 이중 반복문을 사용하므로 시간 복잡도는 항상 n^2으로, 배열의 길이가 늘어날수록 시간이 급격히 늘어난다.

2. 코드로 살펴보기

function selectionSort(arr) {
  const len = arr.length;

  for (let i = 0; i < len - 1; i++) {
  // 전체 요소를 조회하면서 가장 작은 수의 인덱스를 찾는다.
  // len - 2 인덱스까지 정렬을 하면, 마지막 인덱스인 len - 1도 자동 정렬이 되기 때문에
  // len - 1 인덱스 까지만 반복문을 실행한다.
  
    let minIndex = i;
    // 반복문을 시작하는 인덱스가 가장 작은 수의 인덱스라고 가정하고 시작한다.

    for (let j = i + 1; j < len; j++) {
    // i 다음 인덱스부터 시작해서 남은 모든 요소를 조회한다.
    
      if (arr[minIndex] > arr[j]) {
        minIndex = j;
        // 만약 현재까지 찾은 가장 작은 수보다 더 작은 수가 나오면, 
        // 해당 수의 인덱스로 변경한다.
        
      }
    }

    if (i !== minIndex) {
      [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
      // 조회하면서 찾은 가장 작은 수의 위치를 가장 왼쪽으로 변경한다.
      
    }
  }

  return arr;
}

'컴퓨터 과학 > 알고리즘' 카테고리의 다른 글

삽입 정렬  (0) 2024.04.25
버블 정렬  (0) 2024.04.24

버블 정렬에 대해 알아봅니다.

버블 정렬

 

버블 정렬

 

1. 버블 정렬이란 무엇이고, 어떻게 이뤄지는가?

2. 코드로 살펴보기

 

1. 버블 정렬이란 무엇이고, 어떻게 이뤄지는가?

 물 속에서 물방울이 수면 위로 올라오는 것처럼 가장 큰 수가 계속 오른쪽으로 자리를 옮겨가면서 진행되는 정렬 알고리즘이다. 이중 반복문으로 진행되며, 각 회차마다 인접한 두 요소 (앞, 뒤)를 비교하고 앞의 요소가 뒤 요소보다 클 시 자리를 교환한다.
 이중 반복문을 사용하여 시간 복잡도는 항상 n^2으로 배열의 크기가 클수록 실행 시간이 크게 늘어난다.

2. 코드로 살펴보기

function bubbleSort(arr) {
  const len = arr.length;

  for (let i = 0; i < len - 1; i++) {
  // 배열의 전체 요소를 조회합니다. 단, 앞, 뒤 요소를 비교하므로 len - 1 미만으로 범위를 지정합니다.
  // 만약 len 미만으로 지정할 시, 맨 마지막 요소는 비교할 대상이 없어 문제가 발생합니다.
  
    for (let j = 0; j < len - 1 - i; j++) {
    // j의 범위는 len -1 -i 미만으로 지정합니다. len -1 -i 이상 인덱스 요소들은 이전 회차에서
    // 이미 정렬이 된 요소 이므로 다시 비교를 진행하지 않습니다.
    
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
        // 만약 앞의 요소가 뒤의 요소보다 클 시, 위치를 변경합니다.
        
      }
    }
  }

  return arr;
}

'컴퓨터 과학 > 알고리즘' 카테고리의 다른 글

삽입 정렬  (0) 2024.04.25
선택 정렬  (0) 2024.04.25

자바스크립트에서 비동기 작업을 가능하게 하는 이벤트 루프에 대해 알아봅니다.

자바스크립트의 이벤트 루프

 

자바스크립트의 이벤트 루프

 

1. 이벤트 루프는 왜 필요한가?

2. 이벤트 루프는 어떻게 작동할까?

3. 예시 코드로 살펴보기

 

1. 이벤트 루프는 왜 필요한가?

 자바스크립트는 싱글스레드 언어이다. 따라서 한번에 하나의 작업만 수행한다. 하지만 이 때의 문제는 만약 시간이 오래 걸리는 작업이 있을 시, 전체 서비스가 멈출 수 있다는 것이다. 예를 들어 서버에서 데이터를 모두 받아올 때까지 서비스의 작동이 멈춘다면 어떻게 될까?
 이러한 상황을 해결하기 위한 것이 이벤트 루프다.

2. 이벤트 루프는 어떻게 작동할까?

 알아야 할 주요 개념은 콜스택, 태스크 큐 2가지다. 콜 스택은 함수가 실행될 때, 콜스택에 추가된다. 콜스택에 담긴 작업은 순차적으로 실행된다.
 만약 당장 실행을 끝마치지 않아도 되는 작업 (비동기 작업)일 시 백그라운드로 옮겨 작업을 진행한다. 비동기 작업이 끝난 후 발생한 작업 (콜백 함수, 데이터 전처리 작업 등이 해당)은 태스크 큐에 추가된다.
 이후 콜스택이 비었을 때 테스크 큐에 있는 작업을 콜스택으로 옮겨 진행한다.

3. 예시 코드로 살펴보기

function fetchData() {
  console.log("fetchData 함수 시작");

  fetch("https://example.com").then((response) => {
    console.log("받아온 데이터를 json으로 변환");
    return response.json();
  });

  console.log("fetchData 함수 끝");
}
 상단의 코드가 실행되는 과정은 다음과 같다.

 1. fetchData 함수가 콜스택에 추가된다.
 2. 'fetchData 함수 시작' 문자열이 출력된다.
 3. 서버에서 데이터를 불러오는 작업을 백그라운드로 옮겨 진행한다.
 3 - 1. 데이터를 모두 불러왔으면, '받아온 데이터를 json으로 변환' 문자열을 출력하는 작업을 태스크 큐에 추가한다.
 4. 'fetchData 함수 끝' 문자열을 출력하고, 콜스택에 fetchData 함수를 제거한다.
 5. 콜스택에 비었으므로, 태스크 큐에서 담긴 '받아온 데이터를 json으로 변환' 작업을 옮겨와 실행한다.

'javascript > 이론' 카테고리의 다른 글

for문과 forEach의 차이점 비교  (0) 2024.06.16

[패스트 캠퍼스] 고성능 대규모 프론트엔드 10개 프로젝트 1-4. 맛집 앱 프로젝트에서 배운 점을 살펴보았다.

[패스트 캠퍼스] 고성능 대규모 프론트엔드 10개 프로젝트 1-4. 맛집 앱 프로젝트

0. 여는글

1. nextAuth의 소셜 로그인

2. 공식문서를 이용해 카카오 지도 API 이용하기

3. Prisma ORM 

강의 바로가기

 

여는글

 카카오 지도 API를 이용해 서울 내 맛집 위치를 표시하고, 좋아요, 댓글 기능을 구현하는 프로젝트이다. 제가 이 프로젝트를 통해 배울 수 있었던 학습 키워드는 nextAuth의 소셜 로그인, Prisma ORM,  카카오 지도 API이다.

 

 

주요 기능은 다음과 같다.

 

  • 유저 관련
    • 소셜 로그인
    • 로그아웃
    • 마이페이지
  • 맛집 관련
    • JSON 형태의 맛집 데이터 지도에 위치 표시
    • 좋아요 추가, 해제
    • 좋아요한 맛집 목록 조회
    • 맛집 추가
    • 맛집 검색
    • 맛집 등록

nextAuth의 소셜 로그인

nextAuth의 providers에 원하는 사이트의 Provider를 추가하면 소셜 로그인을 비교적 간단히 구현 가능하다. 

nextAuth 소셜 로그인 공식문서

  • 공통적인 소셜 로그인 구현 방법
    • 각 사이트의 개발자 지원 사이트에 접속하여 프로젝트에서 사용할 개인 api 키 생성
    • 프로젝트의 .env 파일에 해당 api 키 값 추가
    • nextauth에 원하는 사이트의 provider 추가
    • provider 내에 받아온 api 키 적용

공식문서를 이용해 카카오 지도 API 이용하기

 맛집 지도를 구현할 때에 카카오 지도 API를 이용합니다. 이때에 완성된 코드를 그대로 따라치는 것이 아니라 공식 문서에 어떤 부분을 이용하는 지 같이 살펴본다는 점이 좋았다. 카카오 map을 이용할 때에는 Script를 이용해 불러오기 때문에 대부분 컴포넌트 형식으로 외부 모듈을 불러오는 react/ next 프레임워크의 방식과 다소 차이가 있어 이후에도 참조해야 할듯 하다.

카카오 지도 api 공식문서

 

  • 카카오 지도 API 이용하기
    • Script를 통해 카카오 지도 api를 불러옴.
    • Script의 src 속성에 개인 카카오 지도 api 키 값 적용
    • window.kakao.maps를 이용해 지도 불러오기

Prisma ORM

nextjs는 프론트엔드 뿐만 아니라 백엔드 기능도 담당하므로 데이터 베이스 작업을 담당하는 ORM도 사용하게 된다. 그중 Prisma ORM은 사용법 간편한 편이기 때문에 자주 사용된다. 개인적으로 Prisma를 사용할 때에 Prisma Studio를 사용해 현재 데이터를 보기가 편하다는 이점이 있다.
  • Prisma 구현 과정
    • root 폴더에 prisma 폴더 생성
    • schema.prisma 파일에 사용하고자 하는 테이블 스키마 작성
    • seed.ts에 기본 데이터 추가 과정 작성
Prisma studio, npx prisma studio 명령어를 입력하면 데이터 간편히 조회할 수 있다.

강의 바로가기

고성능 대규모 프론트엔드 10개 프로젝트: 최적화부터 유지보수까지 한 번에 끝내기

 21개 프로젝트로 완성하는 인터랙티브 웹 개발 Part 1 chapter 2 404 에러 페이지에서 배운 점을 살펴봅니다.

 

[패스트 캠퍼스] 21개 프로젝트로 완성하는 인터랙티브 웹 개발 1-2. 404 에러 페이지

 

0. 여는글

1. 구현 화면

2. svg를 이용한 애니메이션 효과

3. transform-box, transform-origin 속성

4. 정리하기

강의 바로가기

 

여는글

 이번 강의는 svg를 통해 애니메이션 효과를 적용하는 내용이다. 그동안은 막연하게 이미지에 세부적으로 애니메이션을 적용하려면 조각조각난 이미지를 합쳐서 표현해야 하나 생각했었는데, 이미지를 svg로 변환한다면 각 부위를 css class를 통해 쉽게 접근할 수 있다는 것을 알게 되었다.

1. 구현화면

2. svg를 이용한 애니메이션 효과

svg 파일일 경우 각 요소들의 태그로 접근해서 css를 적용할 수 있다.

 

 svg 형태의 파일일 경우에는 그려진 요소들이 엘리먼트 태그들이다. 그래서 css 적용을 원하는 태그를 찍어서 해당 태그에만 css 애니메이션을 적용함으로써 역동적인 화면을 만들어 낼 수 있다. 이를 활용하여 기존의 이미지 파일을 svg로 변환한 다음 원하는 조작을 할 수 있다.

3. transform-box, transform-origin 속성

    • transform-box
      • transform 작업이 일어나는 위치 설정
        • 'border-box': 기본값, 테두리를 포함한 영역의 내부 경계선을 기준으로 작업
        • 'stroke-box': 테두리를 포함한 영역의 외부 경계선을 기준으로 작업
        • 'view-box': 현재 뷰포트를 기준으로 작업
        • 'fill-box': 요소의 content를 기준으로 작업

    • transform-origin
      • transform 작업의 중심점 설정
        • 'center', 'top' 등의 키워드 혹은 픽셀값, 백분율 등을 사용하여 어떤 위치를 중심으로 잡을 것인지 선택 가능

  • 이 두가지 속성을 이용해 애니메이션을 좀더 구체적으로 구현할 수 있다. ex) 빙글빙글 도는 애니메이션

4. 정리하기

  • 해당 강의에서 알게된 점은 다음과 같다.
    • svg를 활용하면 세부적인 애니메이션 적용이 가능하다.
    • transform-box, transform-origin을 통해 transform의 세밀한 조정이 가능하다.

강의 바로가기

21개 프로젝트로 완성하는 인터랙티브 웹 개발 With Three.js & Canvas

 

 npm이 아닌 yarn 쓰는 이유에 대해 알아봅니다.

yarn은 왜 쓰는가?

 

0. 여는글

1. npm과 yarn

2. yarn은 뭐가 더 좋은가

3. 정리

추천글

 

여는글

 처음 배웠던 것이 npm이었기에 프로젝트에 모듈을 설치할 때에 언제나 'npm start'를 입력하곤 했다. 하지만 입사한 회사에서는 yarn을 사용하고 있었기에 자동반사로 뛰쳐나오는 'npm install'을 억누르는 중이다. npm 대신 yarn을 쓰게 되면 뭐가 더 좋은 걸까?

npm과 yarn

    • 공통점
      • 자바스크립트의 패키지 매니저

    • npm
      • nodejs의 기본 패키지 관리자
      • 'npm install' 사용시 package-lock.json 파일로 의존성 관리

  • yarn
    • facebook에서 개발한 javascript 패키지 관리자
    • 'yarn insall' 사용 시 yarn.lock 파일로 의존성 관리

yarn은 뭐가 더 좋은가

  • 빠른 패키지 설치 (병렬 설치)
    • 여러 패키지를 설치할 때에 동시에 진행됨.
    • npm은 패키지 설치를 순차적으로 진행하므로 yarn을 사용한다면 설치 시간을 단축시킬 수 있음.

  • 오프라인 패키지 설치
    • yarn은 패키지를 설치할 때에 해당 패키지를 캐시에 저장(.yarn-cache 폴더)
    • 이후 오프라인일 때에도 해당 캐시를 이용해 설치 가능

정리

  • 시간을 단축할 수 있다!
    • yarn을 사용한다면 패키지를 병렬 설치할 수 있다는 점, 기존 패키지들이 캐시에 저장된다는 점을 통해 설치 속도를 줄일 수 있다.

추천글

canvas를 사용해 방향키로 좌우 이동 조작할 수 있는 캐릭터를 만들어보았습니다. 움직이는 캐릭터의 이전 모습을 삭제하기 위해 배경과 캐릭터의 캔버스를 나누어 진행하였습니다.

canvas 캐릭터 방향키로 좌우 이동하기

 

 목차

 

1. 구현 화면

2. 고려사항

3. 구현

4. 구현된 코드로 보기

 

1. 구현 화면

방향키를 통해 좌우 이동하는 캐릭터

2. 고려사항

  • 하나의 캔버스만 사용할 시 이전 캐릭터의 그림들을 삭제하기 어려움
    • 이전 캐릭터의 그림을 지우기 위해 해당 좌표를 clearRect로 지울 시 배경까지 같이 삭제되어 버림
    • 따라서, 배경, 캐릭터를 레이어로 나누어 구현
    • 배경은 바닥에, 캐릭터는 공중에 뜬 상태로 그려진다고 볼 수 있음

3. 구현

  • 배경 이미지를 넣을 canvas, 캐릭터를 넣을 canvas 2개 생성
  • 배경 canvas와 캐릭터 canvas가 겹쳐져야 하므로 상위 태그에는 relative, canvas에는 absolute 속성 부여

 

<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 배경 이미지를 넣을 canvas, 캐릭터를 넣을 canvas 2개 생성 -->
    <!-- 배경 canvas와 캐릭터 canvas가 겹쳐져야 하므로 상위 태그에는 relative, canvas에는 absolute 속성 부여 -->
    <div style="position: relative;">
      <canvas id="background" style="position: absolute;"></canvas>
      <canvas id="character" style="position: absolute;"></canvas>
    </div>
    <script src="maple.js"></script>
  </body>
</html>

 

  • 배경 canvas 지정
  • 캐릭터 canvas 지정
  • 배경 제작
    • 배경 경로 불러오기
    • 배경 이미지를 불러오면 배경 canvas에 그리기
    • 이미지를 불러오는 과정에서 비율이 깨지지 않게 이미지의 가로, 세로 길이를 그대로 canvas에 지정
  • 캐릭터 제작
    • 캐릭터 경로 불러오기
    • 캐릭터의 x 좌표 지정
    • 캐릭터 불러오면 캐릭터 canvas에 그리기
    • 캐릭터가 이동할 수 있는 반경은 배경 내부 이므로 배경 이미지의 가로, 세로 길이를 그대로 canvas에 지정
  • canvas에서 키입력 이벤트 설정
    • 캐릭터의 좌표가 0이하면 더이상 왼쪽으로 이동 못하게 제한
    • "캐릭터의 x 좌표 값 + 캐릭터의 가로 길이"가 배경의 가로 길이보다 커질 시 더이상 오른쪽으로 이동 못하게 제한

 

// maple.js

// 배경 canvas 지정
const backgroundCanvas = document.getElementById("background");
const backCtx = backgroundCanvas.getContext("2d");

// 캐릭터 canvas 지정
const characterCanvas = document.getElementById("character");
const chaCtx = characterCanvas.getContext("2d");

// 배경 경로 불러오기
const port = new Image();
port.src =
  "https://github.com/ka0824/ka0824.github.io/assets/79782594/e264a9fb-541b-4cd4-845b-947385a19cef";

// 배경 이미지를 불러오면 배경 canvas에 그리기
// 이미지를 불러오는 과정에서 비율이 깨지지 않기 위해 이미지의 가로, 세로 길이를 그대로 canvas에 적용
port.onload = function () {
  backgroundCanvas.width = port.width;
  backgroundCanvas.height = port.height;
  backCtx.drawImage(port, 0, 0);
};

// 캐릭터 경로 불러오기
const mushroom = new Image();
mushroom.src =
  "https://github.com/ka0824/ka0824.github.io/assets/79782594/1cac660c-db2c-46d0-af9a-ecfebe31b62d";

// 캐릭터의 x 좌표 지정
let mushroomX = 0;

// 캐릭터 불러오면 캐릭터 canvas에 그리기
// 캐릭터가 이동할 수 있는 반경은 배경 내부 이므로 배경 이미지의 가로, 세로 길이를 그대로 적용
mushroom.onload = function () {
  characterCanvas.width = port.width;
  characterCanvas.height = port.height;
  chaCtx.drawImage(mushroom, mushroomX, 100, 40, 50);
};

// canvas에서 키입력 이벤트 설정
document.addEventListener("keydown", function (event) {
  switch (event.key) {
    case "ArrowLeft":
      // 캐릭터의 좌표가 0 이하면 더이상 왼쪽으로 이동 못하게 제한
      if (mushroomX <= 0) {
        return;
      }

      // 이동 속도는 -10, 이동할 때 마다 이전 이미지 지워주기
      mushroomX -= 10;
      chaCtx.clearRect(0, 0, characterCanvas.width, characterCanvas.height);
      chaCtx.drawImage(mushroom, mushroomX, 100, 40, 50);
      return;
    case "ArrowRight":
      // 캐릭터의 가로축이 40이므로, '현재 캐릭터의 x 좌표 값 + 40'이 배경의 가로축보다 커지면 오른쪽으로 이동 못하게 제한
      if (mushroomX + 40 >= characterCanvas.width) {
        return;
      }

      mushroomX += 10;
      chaCtx.clearRect(0, 0, characterCanvas.width, characterCanvas.height);
      chaCtx.drawImage(mushroom, mushroomX, 100, 40, 50);
      return;
    default:
      return;
  }
});

4. 구현된 코드로 보기

'javascript > canvas' 카테고리의 다른 글

canvas로 간단 애니메이션 구현하기  (0) 2023.10.09
캔버스로 기본 도형(2d) 그리기  (0) 2023.10.08

canvas로 애니메이션을 구현해보겠습니다. 좌표를 어떻게 변경해야 할지 고려해 봅시다.

canvas로 간단 애니메이션 구현하기

 

 목차

 

1. 알아두기

2. 직선 이동 애니메이션

3. 원모양 이동 애니메이션

4. 반복되는 애니메이션

5. 왕복 이동 애니메이션

6. 구현 코드로 보기

추천글

 

1. 알아두기

  • x, y 좌표로 이동시키기
    • canvas의 애니메이션은 애니메이션의 x, y좌표를 변경하면서 진행됨
    • 연속되는 그림이 빠르게 지나가면서 애니메이션으로 보여진다라고 생각할 수 있음

 

  • 애니메이션의 속도는 좌표 변경 값의 크기에 따라 정해짐
    • 좌표 변경 값이 클 수록 속도가 빨라지고, 변경 값이 작을 수록 속도가 느려짐

 

  • 이전 화면이 필요 없다면 clearRect 메서드를 이용해 canvas를 지우기
    • clearRect를 사용하지 않으면 이전 화면도 그대로 남아있음. 상황에 따라 사용 여부 결정할 것.

 

  • requestAnimationFrame 함수를 이용하자
    • 작성한 애니메이션 함수를 requestAnimationFrame을 이용해 애니메이션으로 구현할 수 있음

2. 직선 이동 애니메이션

  • 애니메이션 시작 좌표 정하기
  • 좌표 증가 값 정하기 (애니메이션의 속도)
  • 애니메이션 함수 작성
    • 좌표 증가 시키기
    • 달라진 좌표에 맞춰 그림 그리기
    • 애니메이션 맞춤 설정
// lineAnimation.js

const canvas1 = document.getElementById("my-canvas1");
const ctx1 = canvas1.getContext("2d");

// 애니메이션 시작 좌표 정하기
let startX1 = 10;
let startY1 = 10;

const dx1 = 10;

function lineAnimation() {
  // 캔버스 지우기
  // 캔버스의 width, height 값 입력
  ctx1.clearRect(0, 0, canvas1.width, canvas1.height);

  ctx1.fillStyle = "black";

  // 좌표 증가 시키기
  startX1 += dx1;

  // 달라진 좌표에 맞춰서 그림 그리기
  ctx1.fillRect(startX1, startY1, 100, 100);

  // 애니메이션 맞춤 설정
  requestAnimationFrame(lineAnimation);
}

lineAnimation();

3. 원모양 이동 애니메이션

 

  • 시작 각도 지정
  • 각도 늘어나는 값 지정 (애니메이션 속도)
  • 애니메이션 함수 작성
    • 원의 중심 좌표 업데이트
    • 코사인(cos), 사인(sin)을 이용해  x 좌표, y 좌표를 반지름에 맞춰 비율 조정
      • cos(각도) = b / c
      • sin(각도) = a / c
      • 현재 각도에서 생성된 b와 c의 비율 값을 통해 원 외곽의 x 좌표 구하기
      • 현재 각도에서 생성된 a와 c의 비율 값을 통해 원 외곽의 y 좌표 구하기
      • 생성된 x, y 좌표에 경로의 둘레를 얼마나 크게 할 것 인지 값 설정
원 외곽의 x, y 좌표를 구하는 과정
cos(각도) = b / c, 가로 b를 사용하므로 x좌표에 사용

 

sin(각도) = a / c, 세로 a를 사용하므로 y 좌표에 사용

 

// circleAnimation.js

const canvas2 = document.getElementById("my-canvas2");
const ctx2 = canvas2.getContext("2d");

let startX2 = 50;
let startY2 = 50;

// 각도 지정
let angle = 0;

// 애니메이션 속도, 각도가 늘어나는 값
const speed = 0.1;

function circleAnimation() {
  ctx2.clearRect(0, 0, canvas2.width, canvas2.height);

  ctx2.beginPath();

  ctx2.arc(startX2, startY2, 10, 0, 2 * Math.PI);

  ctx2.fillStyle = "white";
  ctx2.fill();
  ctx2.strokeStyle = "black";
  ctx2.lineWidth = 2;
  ctx2.stroke();

  angle += speed;

  // 원의 중심 좌표 업데이트
  // 코사인, 사인을 이용해 x 좌표, y 좌표를 반지름에 맞춰 비율 조정
  // 뒤에 곱하는 값이 커질수록 경로의 둘레가 커짐
  startX2 = 50 + Math.cos(angle) * 40;
  startY2 = 50 + Math.sin(angle) * 40;

  // 다음 프레임 요청
  requestAnimationFrame(circleAnimation);
}

circleAnimation();

 

4. 반복되는 애니메이션

 

  • 직선 이동 애니메이션 재활용
  • 애니메이션 그림이 화면을 벗어나게 되면 좌표 초기화
// infiniteAnimation.js

const canvas3 = document.getElementById("my-canvas3");
const ctx3 = canvas3.getContext("2d");

let startX3 = 10;
let startY3 = 10;
let dx3 = 10;

function infiniteAnimation() {
  ctx3.clearRect(0, 0, canvas3.width, canvas3.height);

  ctx3.fillStyle = "black";

  // 화면을 벗어나게 되면 좌표 초기화
  if (startX3 === canvas3.width) {
    startX3 = 10;
  } else {
    startX3 += dx3;
  }

  ctx3.fillRect(startX3, startY3, 100, 100);

  requestAnimationFrame(infiniteAnimation);
}

infiniteAnimation();

5. 왕복 이동 애니메이션

  • 직선 이동 애니메이션 재활용
  • 이동 방향 결정하는 변수 추가
  • 특정 지점에 도달할 때마다 이동 방향 변경
  • 이동 방향에 따라 좌표 증감
// leftRightAnimation.js

const canvas4 = document.getElementById("my-canvas4");
const ctx4 = canvas4.getContext("2d");

let startX4 = 10;
let startY4 = 10;

let dx4 = 10;

// 이동 방향 결정하는 변수 추가
let isMoveRight = true;

function leftRightAnimation() {
  ctx4.clearRect(0, 0, canvas4.width, canvas4.height);

  ctx4.fillStyle = "black";

  // 특정 지점에 도달할 때마다 이동 방향 변경
  if (startX4 + 100 === canvas4.width) {
    isMoveRight = false;
  } else if (startX4 === 10) {
    isMoveRight = true;
  }

  // 이동 방향에 따라 좌표 증감
  if (isMoveRight) {
    startX4 += dx4;
  } else {
    startX4 -= dx4;
  }

  ctx4.fillRect(startX4, startY4, 100, 100);

  requestAnimationFrame(leftRightAnimation);
}

leftRightAnimation();

6. 구현 코드로 보기

추천글

2023.10.08 - [javascript/canvas] - 캔버스로 기본 도형(2d) 그리기

 

캔버스로 기본 도형(2d) 그리기

캔버스는 웹 페이지에 그래픽을 그리는 데에 사용되며, 이미지, 그래프, 애니메이션 등 시각적 요소를 생성하고 조작할 수 있습니다. 이 포스팅에서는 캔버스를 이용해 2d 기본 도형을 그리는 방

ddmoonddmoon.tistory.com

 

 

'javascript > canvas' 카테고리의 다른 글

canvas 캐릭터 방향키로 좌우 이동하기  (1) 2023.10.12
캔버스로 기본 도형(2d) 그리기  (0) 2023.10.08

redux toolkit을 이용해 전역 상태 관리 코드를 작성하는 법을 알아봅니다. redux toolkit을 사용하면 기존 redux를 좀더 간편하게 이용할 수 있습니다.

 

redux toolkit으로 전역 상태 관리하기

 

 목차

 

1. redux toolkit이란?

2. toolkit을 사용하면 뭐가 달라지나요?

3. 구현 코드

4. 구현된 코드로 보기

함께 보면 좋은 글

 

1. redux toolkit이란?

  • redux를 더 쉽게 사용하고 관리할 수 있게 도와주는 공식 라이브러리
  • 즉, redux를 좀 더 쉽게 사용하기 위한 라이브러리

2. toolkit을 사용하면 뭐가 달라지나요?

  • 코드 간소화
    • 기존 redux는 boilertemplate(기본 코드)가 너무 길다는 단점이 있었음
    • toolkit을 통해 코드를 간략화 할 수 있음

 

  • 불변성 관리
    • 기존 redux에서는 상태 관리 로직에서 불변성 관리가 되지 않아, 기존 값을 따로 복사해야 했음
    • ex) { ...state, name: 홍길동 }
    • toolkit을 사용할 시 불변성 유지가 되기 때문에, 변경하고 싶은 값만 변경하면 됨
    • ex) state.name = "홍길동"

 

  • 개발자 도구 적용 간편
    • toolkit은 redux-devtools를 따로 설치하지 않고, 설정만 해도 적용

3. 구현 코드

  • slice 생성
    • slice는 reducer와 action을 동시에 관리함
    • 초기 상태 값 설정
    • slice 내부에 action 생성 (state의 변경 시키고 싶은 값만 수정)
    • slice를 통해 생성된 action 내보내기

 

// store/slice/infoSlice.js

import { createSlice } from "@reduxjs/toolkit";

// 초기 상태 값 설정
const initialState = { name: "홍길동", age: 20 };

// slice를 통해 action 생성
const infoSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    // 액션 생성
    // state의 변경 시키고 싶은 값만 수정
    changeName: (state, action) => {
      state.name = action.payload;
    },

    changeAge: (state, action) => {
      state.age = action.payload;
    },
  },
});

// reducer에 생성한 action export
export const { changeName, changeAge } = infoSlice.actions;
export default infoSlice.reducer;

 

  • store 생성
    • configure 함수 사용
    • reducer 등록
    • 개발자 도구 사용 설정

 

// store/store.js

import { configureStore } from "@reduxjs/toolkit";
import infoReducer from "./slice/infoSlice";

// configureStore 함수 사용
// devTools 따로 설치하지 않고 설정만 해도 사용 가능
const store = configureStore({
  // 생성한 reducer 등록
  reducer: {
    info: infoReducer,
  },
  // 개발자 도구 사용 설정 ON
  devTools: true,
});

export default store;

 

  • 가장 상위 컴포넌트에 store 등록

 

// main.jsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store/store";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    {/* 작성한 store 적용 */}
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

 

  • redux 사용하기
    • state 불러오기
    • dispatch 사용하기
    • dispatch를 통해 action을 store로 전달

 

// App.jsx

import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { changeAge, changeName } from "./store/slice/infoSlice";

function App() {
  // store의 state 불러오기
  const info = useSelector((state) => state.info);
  // dispatch 사용하기
  const dispatch = useDispatch();

  const [name, setName] = useState("홍길동");
  const [age, setAge] = useState(20);

  const handleInputName = (e) => {
    setName(e.target.value);
  };

  const handleInputAge = (e) => {
    setAge(e.target.value);
  };

  // dispatch를 통해 action을 store로 전달
  const submitName = () => {
    dispatch(changeName(name));
  };

  const submitAge = () => {
    dispatch(changeAge(age));
  };

  return (
    <div className="App" style={{ display: "flex", flexDirection: "column" }}>
      <div>{`현재 이름은 ${info.name} 입니다.`}</div>
      <div>{`현재 나이는 ${info.age}세 입니다.`}</div>
      <div>
        <label>
          이름
          <input onChange={handleInputName}></input>
          <button onClick={submitName}>이름 변경</button>
        </label>
      </div>
      <div>
        <label>
          나이
          <input type="number" onChange={handleInputAge}></input>
          <button onClick={submitAge}>나이 변경</button>
        </label>
      </div>
    </div>
  );
}

export default App;

 

4. 구현된 코드로 보기

함께 보면 좋은 글

2023.10.09 - [react/상태관리] - redux 기본 라이브러리로 전역상태 관리하기 (without toolkit, 레거시)

 

redux 기본 라이브러리로 전역상태 관리하기 (without toolkit, 레거시)

redux toolkit 없이 전역 상태 관리 하는 방법을 알아봅니다. 현재는 toolkit 사용을 권장하고 있어, 오늘날에 사용되는 코드는 아닙니다. redux 기본 라이브러리로 전역상태 관리하기 (without toolkit, 레

ddmoonddmoon.tistory.com

 

+ Recent posts