Skip to content

시작하기

@newtil/drawing 은 캡처(스크린샷) 위에 화살표·상자·글자를 얹는 그림판 팝업이다. 함수 하나를 부르면 팝업이 뜨고, 사용자가 완료하면 PNG(독자용)JSON(재편집용) 을 함께 돌려준다.

  • 프레임워크 없음, 순수 DOM. 자기 shadow root 에 떠서 호스트 스타일과 섞이지 않는다.
  • 브라우저 전용이다(document·canvas 를 쓴다). SSR 환경에서는 클라이언트에서만 import 한다.

설치

bash
npm install @newtil/drawing

ESM(import)·CJS(require) 둘 다 제공하고 타입 선언이 들어 있다. CSS 를 따로 불러올 필요 없다 — 스타일은 shadow root 안에 주입된다.

최소 예시

ts
import { openDrawing } from "@newtil/drawing";

const r = await openDrawing({ background: file });   // { data, png } | null(취소)
const r2 = await openDrawing({ initial: r.data });   // 도형 살아 있는 채로 다시 고치기

openDrawingPromise<OpenResult | null> 을 돌려준다. 팝업이 닫힐 때까지 기다린다.

여는 방법 세 가지

ts
// 1. 빈 판(800×450)
await openDrawing();

// 2. 캡처를 배경으로 — File/Blob 또는 같은 출처 이미지 주소
await openDrawing({ background: file });
await openDrawing({ background: "/uploads/shot.png" });

// 3. 이전 결과(JSON)로 다시 열기 — 도형이 그대로 살아 있다
await openDrawing({ initial: savedDrawing });
  • background 는 긴 변이 1600px 을 넘으면 줄여서 data URL 로 굽는다. 판 크기(width·height)는 그 이미지 크기가 된다.
  • initial 이 있으면 background 는 무시된다.
  • 배경 로드에 실패하면(이미지가 아니거나 교차 출처 등) 배경 없이 빈 판으로 열린다.
  • 배경 없이 열었더라도 팝업 안에서 캡처를 붙여넣거나(⌘V / Ctrl+V) "배경 이미지…" 버튼으로 고를 수 있다.

결과 처리

ts
const r = await openDrawing({ background: file });
if (!r) return;                       // 취소

r.png;    // Blob("image/png") — 문서에 넣을 결과물
r.data;   // Drawing — 도형이 살아 있는 JSON. 다음에 initial 로 넘기면 다시 고칠 수 있다
r.saved;  // save 훅이 돌려준 값(주소 등). 훅이 없으면 undefined

PNG 는 보여주는 데 쓰고, data 는 PNG 옆에 곁파일로 저장해 둔다. data 는 배경까지 data URL 로 품고 있어 어디에 두든 자기 완결적이다. 자세한 구조는 데이터 형식 참고.

PNG 를 바로 <img> 에 넣으려면:

ts
import { blobToDataURL } from "@newtil/drawing";
img.src = await blobToDataURL(r.png);          // 또는 URL.createObjectURL(r.png)

저장까지 팝업 안에서

save 훅을 주면 "완료" 를 눌렀을 때 팝업 안에서 호출한다. 서버에 올리고 문서에 넣을 주소를 돌려주면 그 값이 r.saved 에 실린다. 훅이 던지면 팝업은 닫히지 않고 이유를 보인다.

ts
const r = await openDrawing({
  background: file,
  save: async (png, data) => {
    const url = await upload(png, data);   // 실패하면 throw — 팝업이 열린 채 이유를 보인다
    return url;
  },
});

계약과 실패 시 동작은 저장 훅 참고.

취소

다음 경우 null 이 돌아온다.

  • "취소" 버튼
  • 어두운 배경(팝업 바깥) 클릭
  • Esc — 선택된 도형이 있으면 먼저 선택만 풀고, 없으면 취소

한 번이라도 그리거나 고친 뒤라면 "그린 것을 버릴까요?" 확인을 묻는다(window.confirm). 저장 중(save 훅 진행 중)에는 취소되지 않는다.

그 밖의 옵션

ts
await openDrawing({
  background: file,
  notice: "도형 데이터 없이 PNG 만으로 열었습니다.",  // 열 때 6초간 보이는 안내
  lang: "en",                                          // 메시지 언어. 기본은 document.documentElement.lang
  messages: { done: "Insert" },                        // 메시지 일부 덮어쓰기
  mount: container,                                    // 팝업을 붙일 자리. 기본 document.body
});

전체 목록은 APIOpenOptions 참고.