가구가 다 사각형은 아니다.

원형 테이블, 타원형 러그, L자형 소파도 있음.


사각형

제일 쉽다.

<v-rect
  :config="{
    x: furniture.x,
    y: furniture.y,
    width: furniture.width,
    height: furniture.height,
    fill: furniture.color,
    draggable: true
  }"
/>

원형

<v-circle
  :config="{
    x: furniture.x + furniture.width / 2,
    y: furniture.y + furniture.height / 2,
    radius: Math.min(furniture.width, furniture.height) / 2,
    fill: furniture.color,
    draggable: true
  }"
/>

주의: Circle은 중심점 기준. Rect는 좌상단 기준.

좌표 변환 신경 써야 함.


타원형

<v-ellipse
  :config="{
    x: furniture.x + furniture.width / 2,
    y: furniture.y + furniture.height / 2,
    radiusX: furniture.width / 2,
    radiusY: furniture.height / 2,
    fill: furniture.color,
    draggable: true
  }"
/>

타원도 중심점 기준.


L자형… 문제의 시작

L자형 소파나 책상이 있다.

┌───────┐
│       │
│   ┌───┘
│   │
└───┘

이걸 어떻게 그리지?


Path로 그리기

Konva Path 사용:

function getLShapePath(width: number, height: number, ratio = 0.5) {
  const w = width;
  const h = height;
  const cutW = w * ratio;
  const cutH = h * ratio;
  
  return `M 0 0 
          L ${w} 0 
          L ${w} ${h - cutH} 
          L ${w - cutW} ${h - cutH} 
          L ${w - cutW} ${h} 
          L 0 ${h} 
          Z`;
}
<v-path
  :config="{
    x: furniture.x,
    y: furniture.y,
    data: getLShapePath(furniture.width, furniture.height),
    fill: furniture.color,
    draggable: true
  }"
/>

L자형 방향

L이 어느 쪽으로 꺾이는지도 필요함.

type LShapeDirection = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';

방향별로 Path가 다름:

function getLShapePath(w: number, h: number, ratio: number, direction: LShapeDirection) {
  const cutW = w * ratio;
  const cutH = h * ratio;
  
  switch (direction) {
    case 'bottomRight':
      return `M 0 0 L ${w} 0 L ${w} ${h - cutH} L ${w - cutW} ${h - cutH} L ${w - cutW} ${h} L 0 ${h} Z`;
    case 'bottomLeft':
      return `M 0 0 L ${w} 0 L ${w} ${h} L ${cutW} ${h} L ${cutW} ${h - cutH} L 0 ${h - cutH} Z`;
    case 'topRight':
      return `M 0 0 L ${w - cutW} 0 L ${w - cutW} ${cutH} L ${w} ${cutH} L ${w} ${h} L 0 ${h} Z`;
    case 'topLeft':
      return `M ${cutW} 0 L ${w} 0 L ${w} ${h} L 0 ${h} L 0 ${cutH} L ${cutW} ${cutH} Z`;
  }
}

머리 아프다.


비율 조절

L자의 꺾인 부분 비율도 조절 가능하게:

interface LShapeFurniture extends Furniture {
  shape: 'lshape';
  lshapeDirection: LShapeDirection;
  lshapeRatioX: number;  // 가로 비율 (0.3 ~ 0.7)
  lshapeRatioY: number;  // 세로 비율 (0.3 ~ 0.7)
}

편집 폼에서 슬라이더로 조절.


컴포넌트 분기

shape에 따라 다른 컴포넌트:

<template>
  <v-rect v-if="furniture.shape === 'rect'" ... />
  <v-circle v-else-if="furniture.shape === 'circle'" ... />
  <v-ellipse v-else-if="furniture.shape === 'ellipse'" ... />
  <v-path v-else-if="furniture.shape === 'lshape'" ... />
</template>

다음 글에서 Konva Transformer.

#8 - Konva Transformer