@deepnoid/canvas 0.1.59 → 0.1.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Canvas 기반 이미지 annotation 라이브러리로, **TypeScript Engine + Rea
|
|
|
12
12
|
## 주요 기능
|
|
13
13
|
|
|
14
14
|
- ✏️ Rectangle annotation 그리기/편집
|
|
15
|
+
- 👁️ Viewer 모드 지원 (읽기 전용)
|
|
15
16
|
- 🔍 Pan & Zoom 지원
|
|
16
17
|
- ↩️ Undo/Redo 기능
|
|
17
18
|
- ⌨️ 단축키 지원
|
|
@@ -82,6 +83,30 @@ Viewer 모드로 annotation을 읽기 전용으로 표시합니다.
|
|
|
82
83
|
| `events` | `Pick<AnnotationCanvasEvents, 'onImageLoadSuccess' \| 'onImageLoadError'>` | - | 이미지 로드 관련 이벤트 핸들러 |
|
|
83
84
|
| `enableHotkeys` | `boolean` | - | 단축키 활성화 여부 |
|
|
84
85
|
|
|
86
|
+
```jsx
|
|
87
|
+
import { AnnotationViewer } from 'deepnoid-canvas';
|
|
88
|
+
|
|
89
|
+
function App() {
|
|
90
|
+
const [annotations] = useState([{ type: 'RECTANGLE', x: 100, y: 100, width: 200, height: 150 }]);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<AnnotationViewer
|
|
94
|
+
image='https://example.com/image.jpg'
|
|
95
|
+
annotations={annotations}
|
|
96
|
+
drawing={{
|
|
97
|
+
lineSize: 2,
|
|
98
|
+
applyStyle: (params) => {
|
|
99
|
+
// 커스텀 스타일 적용
|
|
100
|
+
},
|
|
101
|
+
}}
|
|
102
|
+
options={{
|
|
103
|
+
panZoomEnabled: true,
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
85
110
|
### Drawing 설정
|
|
86
111
|
|
|
87
112
|
```typescript
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
import { ACTIVE_POINT_SIZE } from './rectangleMath';
|
|
2
|
-
import { cloneDeep } from '../../utils/cloneDeep';
|
|
3
2
|
import { MouseAction } from '../../utils/mouseActions';
|
|
4
3
|
import { drawCross } from '../../renderer/drawCross';
|
|
5
4
|
import { getRectangleCorners } from './rectangleHitTest';
|
|
6
5
|
export const rectangleRenderer = {
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
drawAnnotation(context, engine, annotation) {
|
|
7
|
+
const { zoom } = engine.getImageCanvasState();
|
|
8
|
+
const { applyStyle, lineSize } = engine.getDrawing();
|
|
9
|
+
applyStyle({ variant: 'drawRect', context, annotation, drawLineSize: lineSize, zoom });
|
|
10
|
+
applyStyle({ variant: 'drawText', context, annotation, drawLineSize: lineSize, zoom });
|
|
11
|
+
if (annotation.selected && engine.isEditable()) {
|
|
12
|
+
drawActiveRect(context, annotation, zoom, lineSize);
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
drawEditorUI(context, engine) {
|
|
16
|
+
if (engine.getSelectedAnnotation())
|
|
17
|
+
return;
|
|
13
18
|
const renderState = engine.getDrawRenderState();
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (editable && mode && !engine.getSelectedAnnotation()) {
|
|
23
|
-
if (renderState && renderState.mouseAction === MouseAction.LEFT && renderState.startMousePoint) {
|
|
24
|
-
drawNewRectFromPoints(context, renderState.mousePoint, renderState.startMousePoint, zoom, drawLineSize, drawColor);
|
|
25
|
-
}
|
|
26
|
-
const pointerState = engine.getPointerRenderState();
|
|
27
|
-
if (pointerState?.mousePoint) {
|
|
28
|
-
drawCross(context, pointerState.mousePoint, dw, dh, zoom, drawLineSize);
|
|
29
|
-
}
|
|
19
|
+
const pointerState = engine.getPointerRenderState();
|
|
20
|
+
const { zoom, dw, dh } = engine.getImageCanvasState();
|
|
21
|
+
const { lineSize, color } = engine.getDrawing();
|
|
22
|
+
if (renderState?.mouseAction === MouseAction.LEFT && renderState.startMousePoint) {
|
|
23
|
+
drawNewRectFromPoints(context, renderState.mousePoint, renderState.startMousePoint, zoom, lineSize, color);
|
|
24
|
+
}
|
|
25
|
+
if (pointerState?.mousePoint && !engine.getSelectedAnnotation()) {
|
|
26
|
+
drawCross(context, pointerState.mousePoint, dw, dh, zoom, lineSize);
|
|
30
27
|
}
|
|
31
28
|
},
|
|
32
29
|
};
|
|
@@ -164,13 +164,19 @@ export class AnnotationEngine {
|
|
|
164
164
|
this.drawAnnotationsCanvas();
|
|
165
165
|
}
|
|
166
166
|
drawAnnotations(context) {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
const annotations = this.getAnnotations();
|
|
168
|
+
const showSelectedOnly = this.getShowSelectedOnly();
|
|
169
|
+
const clonedAnnotations = cloneDeep(annotations);
|
|
170
|
+
clonedAnnotations.reverse().forEach((annotation) => {
|
|
171
|
+
if (!showSelectedOnly || annotation.selected) {
|
|
172
|
+
const renderer = this.renderers[annotation.type];
|
|
173
|
+
renderer?.drawAnnotation(context, this, annotation);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
if (this.editable && this.drawing.mode) {
|
|
177
|
+
const renderer = this.renderers[this.drawing.mode];
|
|
178
|
+
renderer?.drawEditorUI?.(context, this);
|
|
179
|
+
}
|
|
174
180
|
}
|
|
175
181
|
getSelectedAnnotation() {
|
|
176
182
|
return this.annotations.find((a) => a.selected) ?? null;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { Annotation } from '../annotation/annotationTypes';
|
|
1
2
|
import { AnnotationEngine } from '../public/annotationEngine';
|
|
2
3
|
export interface AnnotationsRenderer {
|
|
3
|
-
|
|
4
|
+
drawAnnotation(context: CanvasRenderingContext2D, engine: AnnotationEngine, annotation: Annotation): void;
|
|
5
|
+
drawEditorUI?(context: CanvasRenderingContext2D, engine: AnnotationEngine): void;
|
|
4
6
|
}
|