Bin
2025-12-17 d616898802dfe7e5dd648bcf53c6d1f86b6d3642
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
import type { KonvaEventObject } from "konva/lib/Node";
 
// String enums for union types
export enum ShapeType {
  POLYGON = "polygon",
  POLYLINE = "polyline",
}
 
export enum ExportFormat {
  SIMPLE = "simple",
  REGULAR = "regular",
}
 
export enum PathType {
  MAIN = "main",
}
 
export enum PointType {
  REGULAR = "regular",
  BEZIER = "bezier",
  GHOST = "ghost",
}
 
export interface Point {
  x: number;
  y: number;
}
 
export interface BezierPoint extends Point {
  id: string; // UUID for the point
  prevPointId?: string; // Reference to the previous point in the path
  controlPoint1?: Point;
  controlPoint2?: Point;
  isBezier?: boolean;
  disconnected?: boolean;
  isBranching?: boolean;
}
 
// Simple point format for easier usage
export type SimplePoint = [number, number]; // [x, y]
 
// Union type for initialPoints prop
export type PointInput = BezierPoint | SimplePoint;
 
export interface KonvaVectorRef {
  convertPoint: (pointIndex: number) => void;
  selectPointsByIds: (pointIds: string[]) => void;
  clearSelection: () => void;
  getSelectedPointIds: () => string[];
  close: () => boolean;
  exportShape: () => {
    type: ShapeType;
    isClosed: boolean;
    points: Array<{
      x: number;
      y: number;
      bezier: boolean;
      controlPoints: Array<{ x: number; y: number }>;
    }>;
    incomplete: boolean;
  };
  exportSimpleShape: () => {
    type: ShapeType;
    isClosed: boolean;
    points: SimplePoint[];
    incomplete: boolean;
  };
  // Programmatic point creation methods
  startPoint: (x: number, y: number) => boolean;
  updatePoint: (x: number, y: number) => boolean;
  commitPoint: (x: number, y: number) => boolean;
  // Programmatic point transformation methods
  translatePoints: (dx: number, dy: number, pointIds?: string[]) => void;
  rotatePoints: (angle: number, centerX: number, centerY: number, pointIds?: string[]) => void;
  scalePoints: (scaleX: number, scaleY: number, centerX: number, centerY: number, pointIds?: string[]) => void;
  transformPoints: (
    transformation: {
      dx?: number;
      dy?: number;
      rotation?: number;
      scaleX?: number;
      scaleY?: number;
      centerX?: number;
      centerY?: number;
    },
    pointIds?: string[],
  ) => void;
  // Shape analysis methods
  getShapeBoundingBox: () => {
    left: number;
    top: number;
    right: number;
    bottom: number;
  };
  // Hit testing method
  isPointOverShape: (x: number, y: number, hitRadius?: number) => boolean;
  // Delete multiple points by their IDs
  deletePointsByIds: (pointIds: string[]) => void;
}
 
/**
 * Props for the KonvaVector component
 */
export interface KonvaVectorProps {
  /** Initial points in either simple [[x,y],...] or complex {x,y,isBezier,...} format */
  initialPoints?: PointInput[];
  /** Called when points array changes */
  onPointsChange?: (points: BezierPoint[]) => void;
  /** Called when a new point is added */
  onPointAdded?: (point: BezierPoint, index: number) => void;
  /** Called when a point is removed */
  onPointRemoved?: (point: BezierPoint, index: number) => void;
  /** Called when a point is edited */
  onPointEdited?: (point: BezierPoint, index: number) => void;
  /** Called when a point is repositioned */
  onPointRepositioned?: (point: BezierPoint, index: number) => void;
  /** Called when a point is converted between regular/bezier */
  onPointConverted?: (point: BezierPoint, index: number, toBezier: boolean) => void;
  /** Called when the path shape changes */
  onPathShapeChanged?: (points: BezierPoint[]) => void;
  /** Called when path closure state changes */
  onPathClosedChange?: (isClosed: boolean) => void;
  /** Called when transformations complete */
  onTransformationComplete?: (shapeData: {
    type: ShapeType;
    isClosed: boolean;
    points: Array<{
      x: number;
      y: number;
      bezier: boolean;
      controlPoints: Array<{ x: number; y: number }>;
    }>;
    incomplete: boolean;
  }) => void;
  /** Called when a point is selected */
  onPointSelected?: (pointIndex: number | null) => void;
  /** Called when drawing is finished (click on last point or double click on empty space) */
  onFinish?: (e: KonvaEventObject<MouseEvent>) => void;
  /** Called when shift-clicking on a ghost point (for programmatic point insertion when disableInternalPointAddition is true) */
  onGhostPointClick?: (ghostPoint: { x: number; y: number; prevPointId: string; nextPointId: string }) => void;
  /** Canvas width */
  width: number;
  /** Canvas height */
  height: number;
  /** X scale factor */
  scaleX: number;
  /** Y scale factor */
  scaleY: number;
  /** X offset */
  x: number;
  /** Y offset */
  y: number;
  /** Disable ghost line rendering */
  disableGhostLine?: boolean;
  /** Enable image smoothing */
  imageSmoothingEnabled?: boolean;
 
  /** Transform object with zoom and offset */
  transform?: { zoom: number; offsetX: number; offsetY: number };
  /** Fit scale factor */
  fitScale?: number;
 
  /** Allow path to be closed */
  allowClose?: boolean;
  /** External state for path closure (used when allowClose is true) */
  closed?: boolean;
  /** Allow bezier curve creation */
  allowBezier?: boolean;
  /** Minimum number of points required */
  minPoints?: number;
  /** Maximum number of points allowed */
  maxPoints?: number;
  /** Enable skeleton mode for point connections */
  skeletonEnabled?: boolean;
  /** Export format: "simple" or "regular" */
  format?: ExportFormat;
  /** Stroke color for the vector path */
  stroke?: string;
  /** Fill color for closed polygons */
  fill?: string;
  /** Stroke width for the vector path */
  strokeWidth?: number;
  /** Opacity for the vector path */
  opacity?: number;
  /** Enable pixel snapping for precise alignment */
  pixelSnapping?: boolean;
  /** Point styling configuration */
  pointRadius?: {
    /** Radius when component is enabled (default: 6) */
    enabled?: number;
    /** Radius when component is disabled (default: 4) */
    disabled?: number;
  };
  /** Point fill color (default: "#ffffff") */
  pointFill?: string;
  /** Point stroke color when not selected (default: "#3b82f6") */
  pointStroke?: string;
  /** Point stroke color when selected (default: "#fbbf24") */
  pointStrokeSelected?: string;
  /** Point stroke width (default: 2) */
  pointStrokeWidth?: number;
  /** Mouse down event handler */
  onMouseDown?: (e: KonvaEventObject<MouseEvent>) => void;
  /** Mouse move event handler */
  onMouseMove?: (e: KonvaEventObject<MouseEvent>) => void;
  /** Mouse up event handler */
  onMouseUp?: (e?: KonvaEventObject<MouseEvent>) => void;
  /** Click event handler */
  onClick?: (e: KonvaEventObject<MouseEvent>) => void;
  /** Double click event handler */
  onDblClick?: (e: KonvaEventObject<MouseEvent>) => void;
  /** Called when transformation starts (point dragging, multi-point transformation, etc.) */
  onTransformStart?: () => void;
  /** Called when transformation ends (point dragging, multi-point transformation, etc.) */
  /** Can be called with an optional event parameter for backward compatibility */
  onTransformEnd?: (e?: KonvaEventObject<MouseEvent>) => void;
  /** Mouse enter event handler */
  onMouseEnter?: (e: KonvaEventObject<MouseEvent>) => void;
  /** Mouse leave event handler */
  onMouseLeave?: (e: KonvaEventObject<MouseEvent>) => void;
  /** Enable all interactions when true (default: true) */
  selected?: boolean;
  /** Completely disable all interactions when true - user cannot change or move the shape at all */
  disabled?: boolean;
  /** Enable transform mode where all points are treated as selected */
  transformMode?: boolean;
  /** Whether multiple regions are currently selected (disables internal transformer) */
  isMultiRegionSelected?: boolean;
  /** Disable internal point addition - when true, prevents KonvaVector from adding points internally and disables the invisible shape */
  disableInternalPointAddition?: boolean;
  /** Name attribute for the component */
  name?: string;
  /** Ref to access component methods */
  ref?: React.RefObject<KonvaVectorRef>;
}
 
// Ghost point with point references
export interface GhostPoint {
  x: number;
  y: number;
  prevPointId: string; // ID of the point before this segment
  nextPointId: string; // ID of the point after this segment
}