canvas document.querySelector 이슈 - boostcamp-2020/Project15-A-Client-Based-Formula-Editor GitHub Wiki
그림판, 배경화면 변경과 같은 기능을 구현하기 위해서 canvas를 사용할 필요가 있었는데 이에 대한 고민을 적어보려고 합니다.
- html -> canvas로 변환
- 기존의 html을 선택해서 canvas로 변환하는 부분이 있어야 했고, html2canvas라는 라이브러리를 설치해야 했습니다.
- 설치과정
npm install @type2/html2canvas html2canvas
- 전체 로직
// div 영역 선택
const mathquillSection = document.querySelector(
'.kkOleo'
) as HTMLCanvasElement;
// 이 부분이 핵심입니다. html 영역을 canvas로 바꿔주는 영역입니다. 단 promise를 반환해서 async await을 적용했습니다.
const canvas = await html2canvas(mathquillSection);
// 캔버스의 내용을 문자열로 바꿔주는 부분입니다.
// 이 부분은 이미지 MIME 타입과 인코딩 방법 그리고 인코딩 된 이미지 데이터 문자열이 포함됩니다.
// 저는 애니메이션을 포함하기 위해서 image/gif로 설정해주었습니다.
const imageUrl = canvas.toDataURL('image/gif');
// 클릭 이벤트를 주기 위해서 a태그를 생성하였습니다.
const aTag = document.createElement('a');
// aTag를 body에 추가하였습니다.
document.body.appendChild(aTag);
// 수식 저장.gif 파일을 클릭하면 다운로드 가능하도록 구현합니다.
aTag.download = '수식 저장.gif';
// href을 설정합니다.
aTag.href = imageUrl;
// 클릭 이벤트 설정합니다.
aTag.click();
// aTag를 다시 지워줍니다.
document.body.removeChild(aTag);
이렇게 하면 이미지 저장이 가능합니다.
새로운 접근
- 위의 방식으로 진행하게 되면 문제점이 발생하게 된다.
- document.querySelector로 클래스를 지정할 경우 리액트에 의해서 변환된 클래스 이름으로 인해서 에러가 발생합니다.
- 이러한 에러를 해결하는 방법을 여러가지 생각해보았고, 그 중에서 좀 괜찮다고 판단했던 방법을 제시하려고 합니다.
- useRef와 redux를 이용해서 문제 해결해보기
- useRef는 컴포넌트 내에서 dom 조작을 할 수 있도록 도와줍니다. 따라서 이 녀석을 이용하면 해결할 수 있을거라는 판단하에 진행하게 되었습니다.
- useRef는 컴포넌트 내에서만 접근이 가능하기에 Redux를 이용해서 문제를 해결하려고 노력하였습니다.
- 새로운 소스
- useRef를 이용해서 ref의 값을 초기화합니다.
- dispatch를 이용해서 mathquill 영역을 저장합니다.
- useSelector를 이용해서 상태값을 가져오고 html2canvas를 통해서 다시 저장해줍니다.
const mainSectionRef = useRef<HTMLDivElement>(null);
useEffect(() => {
dispatch(getMathQuillContainer(mainSectionRef));
}, []);
const { mathQuillContainer } = useSelector(
(state: RootState) => state.getMathQuillReducer
);
const onClickImageSaveHandler = async () => {
const mathquillSection = mathQuillContainer.current;
const canvas = await html2canvas(mathquillSection);
const imageUrl = canvas.toDataURL('image/gif');
const aTag = document.createElement('a');
document.body.appendChild(aTag);
aTag.download = '수식 저장.gif';
aTag.href = imageUrl;
aTag.click();
document.body.removeChild(aTag);
};