캔버스 기반 에디터의 크기 관리 : 동적 리사이징 vs 고정 크기 [Konva]

강지수·2025년 5월 3일
0

최종 프로젝트 Uuno

목록 보기
3/6

Uuno 에디터 개발 강지수
지난 포스팅에서 작성한 캔버스의 영역과 범위에 관한 기술적 고민에 대한 후속으로, 실제 구현 과정에서 발견한 문제점과 해결책에 대한 글

처음 접근법의 문제점: 동적 Stage 크기

프로젝트 초기에는 사이드바가 열리고 닫힐 때 Stage의 크기를 동적으로 조절하는 방식을 선택했습니다. 이론적으로는 합리적인 접근법처럼 보였으나, 실제 구현 과정에서 여러 문제에 직면했습니다.

'use client';

import EditorCanvas from '@/components/editor/editor-canvas';
import EditorBottomTab from '@/components/editor/editor-ui/bottomTab/editor-bottom-tab';
import EditorSideBar from '@/components/editor/editor-ui/sidebar/editor-sidebar';
import EditorTopbar from '@/components/editor/editor-ui/topbar/editor-topbar';
import { sideBarStore } from '@/store/editor.sidebar.store';
import { useEffect, useRef, useState } from 'react';
const EditPage = () => {
  const containerRef = useRef<HTMLDivElement>(null);
  const sidebarStatus = sideBarStore((state) => state.sidebarStatus);
  const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });

  useEffect(() => {
    const updateSize = () => {
      if (containerRef.current) {
        const { width, height } = containerRef.current.getBoundingClientRect();
        setCanvasSize({ width, height });
      }
    };
    updateSize();

    window.addEventListener('resize', updateSize);

    return () => window.removeEventListener('resize', updateSize);
  }, [sidebarStatus]);

  return (
    <div className='flex h-[calc(100vh-64px)] flex-row overflow-hidden'>
      <EditorSideBar />
      <div
        ref={containerRef}
        className='flex flex-1 flex-col bg-slate-400'
      >
        <EditorTopbar />
        <EditorCanvas canvasSize={canvasSize} />
        <EditorBottomTab />
      </div>
    </div>
  );
};

export default EditPage;

이 접근법의 문제점:

  • 좌표 일관성 문제: Stage 크기가 변경될 때마다 내부 요소들의 절대 좌표값도 다시 계산
  • 요소 위치 오류: 사이드바가 열리고 닫힐 때마다 요소 위치가 비정상적으로 변하는 현상
  • 이벤트 처리 복잡성: 크기 변경에 따른 이벤트 처리 로직이 매우 복잡
  • 성능 저하: 매번 Stage 크기가 변경될 때마다 전체 캔버스를 다시 렌더링

미리캔버스에서 배운 점 : 고정 크기 접근법

문제를 해결하기 위해 미리캔버스와 같은 전문 디자인 툴의
구현 방식을 분석.

대부분의 디자인 툴은 Stage 크기를 고정하고 줌인/줌아웃으로 화면 배율을 조절하는 방식을 채택

개선된 접근법 : 고정크기 stage + zoom in/out

다음과 같이 구조를 개선

  const stageWidth = BASE_STAGE_WIDTH * zoom;
  const stageHeight = BASE_STAGE_HEIGHT * zoom;

  const containerWidth = BASE_CONTAINER_WIDTH * zoom;
  const containerHeight = BASE_CONTAINER_HEIGHT * zoom;

  const currentStageWidth = isHorizontal ? stageWidth : stageHeight;
  const currentStageHeight = isHorizontal ? stageHeight : stageWidth;

  const currentContainerWidth = isHorizontal ? containerWidth : containerHeight;
  const currentContainerHeight = isHorizontal
    ? containerHeight
    : containerWidth;

  return (
    <div
      className={`flex flex-col items-center justify-center bg-white p-[18px]`}
      style={{
        boxShadow: '1px 1px 4px 1px rgba(0, 0, 0, 0.25)',
        width: `${currentContainerWidth}px`,
        height: `${currentContainerHeight}px`,
      }}
    >
      <Stage
        style={{ border: '1px dashed var(--Gray-60, #878A93)' }}
        width={currentStageWidth}
        height={currentStageHeight}
        scale={{ x: zoom, y: zoom }}
        onWheel={handleWheel}
        onMouseDown={(e) => {
          if (e.target === e.target.getStage()) {
            setSelectedElementId(null);
            setEditingElementId(null);
            setSelectedElementType(null);
          }
        }}
        className='bg-white'
      >

새로운 구조의 장점

  • 좌표 일관성: Stage 크기가 고정되어 있으므로 요소들의 좌표가 항상 일관되게 유지
  • 레이아웃 분리: UI 레이아웃(사이드바, 툴바 등)과 캔버스가 완전히 분리되어 각각 독립적으로 관리
  • 줌 기능 활용: 사용자는 줌인/줌아웃으로 작업 영역을 자유롭게 조절
  • 성능 개선: Stage 크기가 변경되지 않아 불필요한 렌더링제거
  • 구현 단순화: 좌표 계산과 이벤트 처리 로직이 단순

기술적 고려사항

1. 확대/축소 구현 방식

  • CSS Transition 사용 : CSS transform : scle()을 사용하는 방법
    • 단점: 고해상도에서 텍스트가 흐려질 수 있음
  • Konva 내장 스케일 사용: Konva의 scaleX, scaleY 속성 활용
    <Stage
            style={{ border: '1px dashed var(--Gray-60, #878A93)' }}
            width={currentStageWidth}
            height={currentStageHeight}
            scale={{ x: zoom, y: zoom }}
            >
    
    • 장점 : 렌더링 품질이 유지됨

2. 확대/축소 중심점 관리

  • 확대/축소 시 중심점을 어디로 설정할지도 중요한 고려사항(ex : 마우스 휠 이벤트)
    • 우리는 마우스 포인터 기반으로 확대하지 않고 화면 가운데를 기준으로 확대

결론 : 캔버스 크기 전략의 중요성

캔버스 기반 에디터를 개발할 때 가장 중요한 결정 중 하나는 캔버스 크기 관리 전략입니다. 처음에는 동적으로 크기를 조절하는 방식이 유연해 보일 수 있지만, 실제로는 고정 크기 접근법이 많은 문제를 해결해주고 사용자 경험도 개선합니다.

미리캔버스나 Figma 같은 전문 디자인 툴이 이러한 접근법을 사용하는 데는 이유가 있습니다. 그들의 경험에서 배우고 적용함으로써, 우리의 에디터도 더 안정적이고 사용하기 쉬운 형태로 발전할 수 있었습니다.


참고자료

profile
프론트엔드 잘하고 싶다

0개의 댓글