npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@deepnoid/canvas

v0.1.86

Published

이 프로젝트는 본부 내 프로젝트에서 사용되는 공통 CANVAS 라이브러리입니다.

Downloads

419

Readme

deepnoid-canvas

이 프로젝트는 본부 내 프로젝트에서 사용되는 공통 CANVAS 라이브러리입니다.

개요

Canvas 기반 이미지 annotation 라이브러리로, TypeScript Engine + React Host 구조로 설계되었습니다.

  • Engine (TS): Canvas 조작, 상태 관리, 이벤트 처리 등 핵심 로직
  • React: UI 렌더링, DOM ref 관리, Engine 생명주기 관리

주요 기능

  • ✏️ Annotation 지원 (그리기 및 편집)
    • Rectangle (BBox):
      • 모서리/상하좌우 테두리를 통한 직관적 크기 조절
      • 영역 내부 드래그(move 커서)를 통한 도형 전체 이동
    • Polygon:
      • 다각형 점찍기 및 시작점(또는 더블클릭) 클릭으로 도형 완성
      • 선 분할(Edge Point Insertion): 기존 그려진 폴리곤 선(Edge) 위에 마우스를 1초간 올려둘 시, 새로운 꼭짓점(Vertex)을 간편하게 추가 가능 (클릭/이동 오작동 방지)
      • 내부 클릭 후 드래그하여 전체 다각형 이동 지원
    • 스마트 UI 동기화: 캔버스 내의 도형 클릭 시 선택된 객체 타입(RECTANGLE/POLYGON)에 맞춰 외부 도구(React 상태)가 자동으로 전환되도록 이벤트(annotationSelected) 연동
  • 👁️ Viewer 모드 지원 (읽기 전용)
  • 🔍 Pan & Zoom 지원 (Image Canvas / Annotation Canvas 레이어 완전 분리)
  • ↩️ Undo/Redo 기능 (History 상태망 자체 관리)
  • ⌨️ 단축키 지원 (선택 객체 삭제, 되돌리기, 한 객체만 보기 등)
  • 🎨 커스터마이징 가능한 스타일링 (커스텀 렌더링 함수(applyStyle) 주입 가능)

빠른 시작

설치

npm install @deepnoid/canvas

Claude Code 스킬 설치 (선택)

소비자 프로젝트에서 Claude Code가 @deepnoid/canvas API를 정확하게 사용할 수 있도록 스킬을 복사합니다.

# .claude/skills 디렉토리가 없으면 생성
mkdir -p .claude/skills

# 스킬 복사
cp -r node_modules/@deepnoid/canvas/skills/deepnoid-canvas .claude/skills/

복사 후 Claude Code에서 @deepnoid/canvas를 import하면 자동으로 올바른 사용법, Props, applyStyle 작성법 등을 안내합니다.

기본 사용법

import { AnnotationEditor } from 'deepnoid-canvas';

function App() {
  const [annotations, setAnnotations] = useState([]);

  return (
    <AnnotationEditor
      image='https://example.com/image.jpg'
      annotations={annotations}
      setAnnotations={setAnnotations}
      drawing={{
        mode: 'RECTANGLE',
        color: '#FF4136',
        lineSize: 2,
      }}
      options={{
        panZoomEnabled: true,
        zoom: { min: 0.5, max: 4, step: 0.9 },
      }}
      enableHotkeys
    />
  );
}

Props

AnnotationEditor

Editor 모드로 annotation을 생성하고 편집할 수 있습니다.

| Prop | Type | Required | Description | | ---------------- | ------------------------------------- | -------- | -------------------------------- | | image | string | ✅ | 이미지 URL | | drawing | AnnotationCanvasDrawing | ✅ | 그리기 모드 및 스타일 설정 | | annotations | Annotation[] | - | Annotation 목록 | | setAnnotations | (annotations: Annotation[]) => void | - | Annotation 변경 시 호출되는 콜백 | | options | AnnotationCanvasOptions | - | 줌/팬 및 기타 옵션 | | events | AnnotationCanvasEvents | - | 이미지 로드 관련 이벤트 핸들러 | | enableHotkeys | boolean | - | 단축키 활성화 여부 |

AnnotationViewer

Viewer 모드로 annotation을 읽기 전용으로 표시합니다.

| Prop | Type | Required | Description | | --------------- | -------------------------------------------------------------------------- | -------- | ------------------------------ | | image | string | ✅ | 이미지 URL | | drawing | Pick<AnnotationCanvasDrawing, 'lineSize' \| 'applyStyle'> | ✅ | 렌더링 스타일 설정 (mode 제외) | | annotations | Annotation[] | - | 표시할 Annotation 목록 | | options | AnnotationCanvasOptions | - | 줌/팬 및 기타 옵션 | | events | Pick<AnnotationCanvasEvents, 'onImageLoadSuccess' \| 'onImageLoadError'> | - | 이미지 로드 관련 이벤트 핸들러 | | enableHotkeys | boolean | - | 단축키 활성화 여부 |

import { AnnotationViewer } from 'deepnoid-canvas';

function App() {
  const [annotations] = useState([{ type: 'RECTANGLE', x: 100, y: 100, width: 200, height: 150 }]);

  return (
    <AnnotationViewer
      image='https://example.com/image.jpg'
      annotations={annotations}
      drawing={{
        lineSize: 2,
        applyStyle: (params) => {
          // 커스텀 스타일 적용
        },
      }}
      options={{
        panZoomEnabled: true,
      }}
    />
  );
}

Drawing 설정

type AnnotationCanvasDrawing = {
  mode?: 'RECTANGLE' | 'POLYGON' | 'NONE'; // 그리기 모드 (Editor 전용)
  color?: string; // Annotation 색상 (HEX)
  lineSize: number; // 선 두께
  label?: Label; // Annotation에 표시할 라벨
  applyStyle: ApplyAnnotationStyle; // 커스텀 스타일 함수
};

type Label = {
  id: number;
  name: string;
  type: string;
};

type ApplyAnnotationStyle = (params: {
  variant: 'drawRect' | 'drawText';
  context: CanvasRenderingContext2D;
  annotation: Annotation;
  drawLineSize: number;
  zoom: number;
}) => void;

Options 설정

type AnnotationCanvasOptions = {
  panZoomEnabled?: boolean; // 줌/팬 기능 활성화 (기본: false)
  zoom?: {
    min?: number; // 최소 줌 배율 (기본: 0.1)
    max?: number; // 최대 줌 배율 (기본: Infinity)
    step?: number; // 줌 단계 (기본: 0.9)
  };
  ZoomButton?: ComponentType; // 커스텀 줌 버튼 컴포넌트
  resetOnImageChange?: boolean; // 이미지 변경 시 줌 리셋 여부
};

Events 설정

type AnnotationCanvasEvents = {
  onImageLoadSuccess?: () => void; // 이미지 로드 성공 시
  onImageLoadError?: (error: Error) => void; // 이미지 로드 실패 시
};

단축키

| 키 | 기능 | | -------------- | ----------------------------- | | Delete | 선택한 annotation 삭제 | | Ctrl+Z | Undo | | Ctrl+Shift+Z | Redo | | X | 선택한 annotation만 보기 토글 |

아키텍처

Facade 패턴

React Component
      ↓
AnnotationEngine (Facade)
      ↓ ↓ ↓ ↓ ↓
      │ │ │ │ └─ History (Undo/Redo)
      │ │ │ └─── PanZoomController
      │ │ └───── InteractionController
      │ └─────── Renderers
      └───────── Annotation Controllers

디렉토리 구조

src/
├─ engine/              # TypeScript Engine (순수 로직)
│  ├─ annotation/       # Annotation 타입별 로직
│  ├─ interaction/      # 이벤트 처리
│  ├─ pan-zoom/         # 줌/이동 기능
│  ├─ public/           # 외부 공개 API
│  └─ renderer/         # Canvas 렌더링
│
└─ react/               # React 컴포넌트
   ├─ hooks/
   └─ AnnotationCanvas.tsx

설계 원칙

  1. 관심사 분리: Engine(로직, Canvas 렌더링) ↔ React(UI DOM, 상태 연동) 완전 분리
  2. 확장성: Renderer, HitTest, Controller 구조로 분리되어 있어, Polygon과 같은 새로운 Annotation 타입을 손쉽게 플러그인처럼 추가 가능합니다.
  3. 사용자 경험(UX) 중심:
    • 툴 오버 액션과 클릭/드래그 충돌을 방지하는 스마트 HitTest 우선순위
    • 1초 Hover Timer 등 인간 중심적인 편집 인터랙션 제공
  4. 성능 최적화: 레이어별(base image / annotation) 독립된 Canvas를 사용하여 불필요한 이미지 렌더링(Redraw) 비용 원천 차단