CSS Graphics Geometry
Guide
Reference
GitHub
Guide
Reference
GitHub
  • Part 0. Math foundations

    • 좌표계와 CSS pixel
    • 점, 벡터, 거리와 기본 용어
    • 각도, 라디안, atan2
  • Part 1. Transform linear algebra

    • translate, scale, rotate
    • CSS matrix(a,b,c,d,e,f)
    • 변환 순서와 transform-origin
    • local, world, screen 좌표계
    • inverse matrix와 포인터 입력
    • 좌표와 transform 디버깅
  • Part 2. Infinite canvas math and architecture

    • viewport와 camera 모델
    • cursor anchored zoom
    • ruler와 tick 계산
    • 주기 함수와 grid step
    • content, overlay, controls layer
    • scene graph와 nested transform
  • Part 3. Editor tool math

    • Pointer Events와 드래그
    • DOMRect와 getBoundingClientRect
    • hit testing과 bounding box
    • selection rectangle과 marquee
    • selection bounds와 handles
    • resize와 rotation handle
    • snapping과 smart guides
    • group, frame, clipping
  • Part 4. CSS graphics properties as math

    • CSS box로 도형 만들기
    • clip-path, radius, shadow
    • 선형보간과 linear-gradient
    • 거리 함수와 radial/conic-gradient
    • stacking context와 합성
    • layout, paint, composite
  • Part 5. Editor state and persistence

    • 레이어 모델과 z-index
    • 이동, 복제, 삭제, 잠금
    • undo/redo command model
    • JSON export/import
  • Part 6. SVG overlay and vector editing

    • SVG viewBox와 좌표계
    • getScreenCTM과 inverse
    • SVG pointer-events와 stroke hit testing
    • cubic bezier path editing
    • mask, clipPath, marker
  • Part 7. Figma to CSS translation

    • Figma node와 CSS DOM 모델
    • Frame constraints와 Auto Layout
    • Fills, strokes, effects를 CSS로
    • Vector와 text 변환
    • gradient 밖의 CSS 수학
    • Figma gradient를 CSS gradient로 변환하기
    • 수학이 필요한 Figma to CSS 속성들
    • Figma VectorNetwork 정리
  • Appendix A. Canvas renderer transition

    • Canvas로 넘어가는 기준
  • Appendix B. Motion and timing

    • 모션 수학과 timing 함수
    • Keyframe timeline 엔진
    • Motion path 수학
    • Bezier curve 길이 구하기

Pointer Events와 드래그

이번에는 입력입니다. 사용자가 마우스를 누르고, 움직이고, 떼는 그 평범한 동작 말입니다.

편집 도구의 대부분은 이 작은 흐름 위에 올라갑니다.

pointerdown -> pointermove -> pointerup

간단해 보이죠. 그런데 제대로 만들지 않으면 드래그 중 포인터가 요소 밖으로 나갔을 때 이벤트가 끊기고, 도구 상태가 멈추고, 사용자는 “방금 뭐였지?” 하게 됩니다. 그래서 pointer lifecycle을 깔끔하게 잡아야 합니다.

드래그는 작은 상태 기계다

드래그는 그냥 이벤트 세 개가 아니라 상태 전환입니다.

idle -> pressing -> dragging -> committing -> idle
pointer event lifecycle and drag delta diagramidlepressingdraggingcommitdragDelta = currentClient - startClientscreen inputdragDelta = 120pxzoom = 2worldDelta = 60
드래그 도구는 이벤트 세 개가 아니라 상태 기계입니다. screen delta는 zoom을 거쳐 world delta가 됩니다.

pointerdown에서는 시작점을 저장합니다. pointermove에서는 현재점과 시작점의 차이를 계산합니다. pointerup에서는 최종 값을 모델에 반영합니다.

dragDelta = currentClient - startClient
worldDelta = dragDelta / zoom

화면에서 20px 움직였다고 해서 world에서도 항상 20px 움직인 것은 아닙니다. zoom이 2라면 world 기준 이동량은 10입니다. 입력은 screen 좌표로 들어오고, 편집 모델은 world 좌표를 원합니다. 여기서도 좌표 변환이 슬쩍 웃고 있습니다.

pointer capture를 쓰자

드래그 중 포인터가 요소 밖으로 나가도 이벤트를 계속 받고 싶다면 setPointerCapture()를 씁니다.

event.currentTarget.setPointerCapture(event.pointerId);

이걸 해두면 사용자가 빠르게 움직여도 pointermove, pointerup을 안정적으로 받을 수 있습니다. resize handle이나 rotation handle처럼 작은 UI를 잡고 움직일 때 특히 중요합니다.

click과 drag는 구분해야 한다

pointerdown 직후 아주 조금 움직였다고 바로 drag로 처리하면 클릭이 자꾸 드래그로 오해받습니다. 그래서 보통 threshold를 둡니다.

if length(current - start) > 3px:
  dragging = true

터치, 펜, 마우스는 입력 특성이 조금씩 다릅니다. pressure, pointerType, wheel delta 같은 값은 장치마다 다르게 들어올 수 있으니 도구 레벨에서는 정규화해서 쓰는 편이 좋습니다.

취소도 상태다

pointercancel, blur, Escape 처리를 빼먹으면 도구 상태가 stuck 될 수 있습니다. 드래그가 끝났는데 내부 상태는 아직 dragging이라고 믿는 상황입니다. 이런 버그는 재현이 애매해서 더 얄밉습니다.

데모에서 볼 것

데모에서는 드래그 도중 포인터를 영역 밖으로 빼도 이벤트가 유지되는지 확인합니다.

오늘의 핵심은 입력을 이벤트 나열이 아니라 상태 기계로 보는 것입니다. 선택 도구, pan 도구, resize 도구는 모두 같은 lifecycle 위에서 다른 계산만 얹습니다.

Edit this page
최근 수정: 26. 5. 14. PM 5:45
Contributors: easylogic
Next
DOMRect와 getBoundingClientRect