[React] Canvas를 사용하여, 모달(Modal) 배경화면 색상 설정하기

신세원·2022년 12월 22일
0

React

목록 보기
2/28

최근 개발 공부를하면서, canvas로 이미지 다루는 것을 공부하여 기록하고자 한다.

1. Canvas란?

MDN 내용 중(中)

  • canvas는 처음에는 src 및 alt 속성이 없다는 점만 제외하면 img 요소처럼 보인다.
  • 실제로 canvas 요소에는 width와 height의 두 속성만 있다, 이것들은 모두 선택사항이며 DOM 프로퍼티를 사용하여 설정할 수도 있다.
  • width 및 height 속성을 지정하지 않으면 캔버스의 처음 너비는 300px, 높이는 150px이다.
  • 요소는 CSS에 의해 임의로 크기를 정할 수 있지만 렌더링하는 동안 이미지는 레이아웃 크기에 맞게 크기가 조정된다.
  • CSS 크기 지정이 초기 캔버스의 비율을 고려하지 않으면 왜곡되어 나타납니다.

한마디로 정리하자면, canvas는 웹페이지에서 그래픽을 그릴때 사용하는 컨테이너이다.

2. Canvas Context

canvas 엘리먼트는 고정 크기의 드로잉 영역을 생성하고 하나 이상의 렌더링 컨텍스(rendering contexts)를 노출하여, 출력할 컨텐츠를 생성하고 다루게 되며, 프론트엔드에서 많이 사용하는것은 2D 렌더링 컨텍스트를 다룬다. (WebGL은 OpenGL ES 을 기반으로 하는 3D 컨텍스트를 사용한다.)

캔버스는 처음에 비어있다. 무언가를 표시하기 위해서, 어떤 스크립트가 랜더링 컨텍스트에 접근하여 그리도록 한다. canvas 요소는 getContext() 메서드를 이용해서, 랜더링 컨텍스트와 (렌더링 컨텍스트의) 그리기 함수들을 사용할 수 있다. getContext() 메서드는 렌더링 컨텍스트 타입을 지정하는 하나의 파라미터를 가지는데, 위에서 언급한거처럼 프론트엔드에서 많이 사용되는 것은 "2d"이다.

간단하게 canvas에 대해서 알아보았고, 본론으로 넘어가보도록 한다.

3. 모달 배경색상 설정하기

CSS 작업을 하면서, 모달로 이미지를 띄우는 경우, 배경화면 색상에 대해서 한번쯤은 고민을 하게된다.
"이 이미지에는 어떤 배경이 잘 어울리지?" , "opacity 처리하기에는 너무 밋밋한데 좋은 방법이 없을까?" 등등

위와 같이 사진 리스트들이 있고, 아무 사진을 클릭했을때, 클릭한 사진이 모달 형식으로 보여지게 되는데, 배경화면은 검은색 화면에 opacity만 적용시켰다.
하지만 여기서 이미지와 배경색깔을 비슷하게 맞춰서 UI가 조금더 낫게 만들수 있다.

이미지와 배경색을 어떻게 비슷하게 맞추면 좋을까?

Get average color of image via Javascript 여기서 많은 사람들이 여러가지 해결방안을 알려줬는데, 그걸 토대로 배경 색상을 구해보고자 한다.

3. 이미지 평균 색상을 구하는 코드


// 첫번째 방법
function getAverageColorOfImage(imgElement) {
  // imgElement -> <img src='https://...' alt='...' />
  const canvas = document.createElement('canvas');  // canvas element 생성
  const context = canvas.getContext && canvas.getContext('2d'); // 2d 그래픽을 그릴 수 있는 메서드를 지닌 HTML5 object
  const averageColor = { r: 0, g: 0, b: 0 };

  if (!context) return averageColor;

  const width = (canvas.width = imgElement.naturalWidth || imgElement.offsetWidth || imgElement.width); 
  const height = (canvas.height = imgElement.naturalHeight || imgElement.offsetHeight || imgElement.height);
  context.drawImage(imgElement, 0, 0); // drawImage는 캔버스에서 이미지를 그려준다.

  const imageData = context.getImageData(0, 0, width, height).data; // 지정된 좌표와 폭과 높이를 갖는 사각형으로 표시된 캔버스 영역에 대한 기본 픽셀 데이터를 나타내는 ImageData 객체를 반환한다.
  const length = imageData.length;

  for (let i = 0; i < length; i += 4) {
    averageColor.r += imageData[i];
    averageColor.g += imageData[i + 1];
    averageColor.b += imageData[i + 2];
  }
  const count = length / 4;
  averageColor.r = ~~(averageColor.r / count); 
  averageColor.g = ~~(averageColor.g / count);
  averageColor.b = ~~(averageColor.b / count);

  return averageColor;
}

//두번째 방법
function getAverageColorOfImage(imgElement) {
  if (cache.hasOwnProperty(imgElement.src)) return cache[imgElement.src];
  const context = document.createElement('canvas').getContext('2d');
  context.drawImage(imgElement, 0, 0, 1, 1);
  const i = context.getImageData(0, 0, 1, 1).data;
  const rgba = `rgba(${i[0]},${i[1]},${i[2]},0.8)`;
  // const HEX = '#' + ((1 << 24) + (i[0] << 16) + (i[1] << 8) + i[2]).toString(16).slice(1);
  
  return rgba;
}

필자는 첫번째 방식으로 적용했고, 그 결과는 아래와 같다.

여기서 한가지 유의해야할 점이 있다.

이미지를 클릭했을때, 모달이 떠야하는 상황이기 때문에, img태그에 onClick 이벤트를 달아주어야 하는데, 이때 꼭 img에 Cross Origin 속성 설정을 해줘야 한다.

img에 Cross Origin 속성 설정


function PhotoComponent({ photo: { urls, alt } }) {
  
  const openModal = e => {
    const averageColor = getAverageColorOfImage(e.target);
    {...}
  };

  return (
        <img
          {...}
          crossOrigin="*" // 이 부분 설정
          onClick={openModal}
        />
  );
}


export default PhotoComponent;

위와 같이 설정하지 않고 개발을 하다보면 CORS 에러가 생기는데 이유는 다음과 같다.

Canvas를 사용할 때 CORS 승인 없이 이미지를 사용할 수는 있지만, 
이미지를 변형한 상태에서 데이터를 캔버스에서 꺼내려 한다면 
“canvas tainted” 관련 오류가 발생할 것이다.

누군가가 보았을때는, 사소한 부분이지만, 유저 친화적으로 접근했을때, 꽤 괜찮은 방식의 스타일링이라고 생각한다.

[React] Canvas에서 CORS 에러가 왠 말이야!!
Get average color of image via Javascript
웹 개발 스킬을 한 단계 높여주는 프론트엔드 성능 최적화 가이드 -유동규 지음-

profile
생각하는대로 살지 않으면, 사는대로 생각하게 된다.

0개의 댓글