@operato/image-marker 8.0.0-alpha.33 → 8.0.0-alpha.37
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/CHANGELOG.md +10 -0
- package/dist/src/base-image-marker.d.ts +19 -26
- package/dist/src/base-image-marker.js +93 -141
- package/dist/src/base-image-marker.js.map +1 -1
- package/dist/src/default-image-provider.d.ts +4 -0
- package/dist/src/default-image-provider.js +6 -0
- package/dist/src/default-image-provider.js.map +1 -0
- package/dist/src/ox-image-marker-view.js +4 -4
- package/dist/src/ox-image-marker-view.js.map +1 -1
- package/dist/src/ox-image-marker.d.ts +11 -11
- package/dist/src/ox-image-marker.js +173 -226
- package/dist/src/ox-image-marker.js.map +1 -1
- package/dist/src/types.d.ts +10 -0
- package/dist/src/types.js.map +1 -1
- package/dist/stories/test-image-provider.d.ts +7 -0
- package/dist/stories/test-image-provider.js +41 -0
- package/dist/stories/test-image-provider.js.map +1 -0
- package/dist/stories/test-image-provider.stories.d.ts +33 -0
- package/dist/stories/test-image-provider.stories.js +119 -0
- package/dist/stories/test-image-provider.stories.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -14
- package/src/base-image-marker.ts +105 -160
- package/src/default-image-provider.ts +7 -0
- package/src/ox-image-marker-view.ts +4 -4
- package/src/ox-image-marker.ts +187 -235
- package/src/types.ts +12 -0
- package/stories/test-image-provider.stories.ts +135 -0
- package/stories/test-image-provider.ts +49 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [8.0.0-alpha.37](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.36...v8.0.0-alpha.37) (2024-10-20)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :bug: Bug Fix
|
|
10
|
+
|
|
11
|
+
* pointer-event & pointer-event for ox-image-marker ([c503d0a](https://github.com/hatiolab/operato/commit/c503d0a235ddadd97fdcd84ae98a303a7ffe7a6f))
|
|
12
|
+
* update dev-dependencies version ([d6fe342](https://github.com/hatiolab/operato/commit/d6fe342de738c6bad3528550a862b5a1d2573161))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
6
16
|
## [8.0.0-alpha.33](https://github.com/hatiolab/operato/compare/v8.0.0-alpha.32...v8.0.0-alpha.33) (2024-10-14)
|
|
7
17
|
|
|
8
18
|
**Note:** Version bump only for package @operato/image-marker
|
|
@@ -1,41 +1,34 @@
|
|
|
1
|
-
import { LitElement, nothing } from 'lit';
|
|
2
|
-
import {
|
|
1
|
+
import { LitElement, nothing, PropertyValues } from 'lit';
|
|
2
|
+
import { GestureEventDoubleTap, GestureEventDrag, GestureEventPinch } from '@operato/utils/gesture-helper.js';
|
|
3
|
+
import { ImageProvider, Shape } from './types';
|
|
3
4
|
export declare class BaseImageMarker extends LitElement {
|
|
4
5
|
static styles: import("lit").CSSResult[];
|
|
5
6
|
imageUrl: string;
|
|
6
7
|
shapes: Shape[];
|
|
8
|
+
protected currentImage?: string;
|
|
7
9
|
protected viewBox: string;
|
|
8
10
|
protected zoomLevel: number;
|
|
11
|
+
private imageProvider?;
|
|
12
|
+
protected debouncedUpdateImage: import("lodash").DebouncedFunc<() => Promise<void>>;
|
|
9
13
|
protected zoomFactor: number;
|
|
10
14
|
protected zoomThreshold: number;
|
|
11
|
-
protected
|
|
12
|
-
protected panStart: {
|
|
13
|
-
x: number;
|
|
14
|
-
y: number;
|
|
15
|
-
};
|
|
16
|
-
protected panInitiated: boolean;
|
|
17
|
-
protected panThreshold: number;
|
|
18
|
-
protected initialViewBox: string;
|
|
19
|
-
private initialPinchDistance;
|
|
20
|
-
private initialZoomLevel;
|
|
21
|
-
private lastTouchEnd;
|
|
15
|
+
protected initialViewBox: string | null;
|
|
22
16
|
protected svg: SVGSVGElement;
|
|
17
|
+
private gestureHelper;
|
|
18
|
+
connectedCallback(): void;
|
|
19
|
+
disconnectedCallback(): void;
|
|
20
|
+
protected updated(changes: PropertyValues): void;
|
|
21
|
+
setImageProvider(provider: ImageProvider): void;
|
|
23
22
|
protected onImageLoad(event: Event): void;
|
|
23
|
+
protected updateImage(): Promise<void>;
|
|
24
24
|
protected onSvgWheel(event: WheelEvent): void;
|
|
25
|
-
protected
|
|
26
|
-
protected
|
|
27
|
-
protected
|
|
28
|
-
|
|
29
|
-
protected
|
|
30
|
-
protected onZoomTouchEnd: (event: TouchEvent) => void;
|
|
31
|
-
protected applyZoom(): void;
|
|
32
|
-
protected onSvgDoubleClick(): void;
|
|
33
|
-
protected resetZoom(): void;
|
|
34
|
-
protected startPanning(event: MouseEvent | TouchEvent): void;
|
|
35
|
-
protected onPanMouseMove: (event: MouseEvent | TouchEvent) => void;
|
|
36
|
-
protected onPanMouseUp: (event: MouseEvent | TouchEvent) => void;
|
|
25
|
+
protected onSvgPinch(e: GestureEventPinch): void;
|
|
26
|
+
protected onSvgDoubleTap(e: GestureEventDoubleTap): void;
|
|
27
|
+
protected onSvgDrag(e: GestureEventDrag): void;
|
|
28
|
+
zoom(scale: number, offsetX: number, offsetY: number): void;
|
|
29
|
+
protected reset(): void;
|
|
37
30
|
protected renderShape(shape: Shape): import("lit-html").TemplateResult<2> | typeof nothing;
|
|
38
|
-
protected getPointFromEvent(event: MouseEvent |
|
|
31
|
+
protected getPointFromEvent(event: MouseEvent | PointerEvent | GestureEventDrag): {
|
|
39
32
|
x: number;
|
|
40
33
|
y: number;
|
|
41
34
|
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { LitElement, css, svg, nothing } from 'lit';
|
|
3
3
|
import { property, state, query } from 'lit/decorators.js';
|
|
4
|
+
import { debounce } from 'lodash-es';
|
|
5
|
+
import { GestureHelper } from '@operato/utils/gesture-helper.js';
|
|
6
|
+
import { DefaultImageProvider } from './default-image-provider';
|
|
4
7
|
export class BaseImageMarker extends LitElement {
|
|
5
8
|
constructor() {
|
|
6
9
|
super(...arguments);
|
|
@@ -8,87 +11,12 @@ export class BaseImageMarker extends LitElement {
|
|
|
8
11
|
this.shapes = [];
|
|
9
12
|
this.viewBox = '0 0 800 600';
|
|
10
13
|
this.zoomLevel = 1;
|
|
14
|
+
this.imageProvider = new DefaultImageProvider();
|
|
15
|
+
this.debouncedUpdateImage = debounce(this.updateImage.bind(this), 300);
|
|
11
16
|
this.zoomFactor = 0.1;
|
|
12
17
|
this.zoomThreshold = 0.05;
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this.panInitiated = false;
|
|
16
|
-
this.panThreshold = 20;
|
|
17
|
-
this.initialViewBox = '0 0 800 600';
|
|
18
|
-
this.initialPinchDistance = null;
|
|
19
|
-
this.initialZoomLevel = 1;
|
|
20
|
-
this.lastTouchEnd = 0;
|
|
21
|
-
this.onSvgTouchStart = (event) => {
|
|
22
|
-
event.preventDefault();
|
|
23
|
-
if (this.isDoubleTouch(event)) {
|
|
24
|
-
this.resetZoom();
|
|
25
|
-
}
|
|
26
|
-
if (event.touches.length === 1) {
|
|
27
|
-
this.startPanning(event);
|
|
28
|
-
}
|
|
29
|
-
else if (event.touches.length === 2) {
|
|
30
|
-
this.startPinchZooming(event);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
this.onZoomTouchMove = (event) => {
|
|
34
|
-
event.preventDefault();
|
|
35
|
-
if (event.touches.length === 2 && this.initialPinchDistance) {
|
|
36
|
-
const touch1 = event.touches[0];
|
|
37
|
-
const touch2 = event.touches[1];
|
|
38
|
-
const dx = touch2.clientX - touch1.clientX;
|
|
39
|
-
const dy = touch2.clientY - touch1.clientY;
|
|
40
|
-
const currentPinchDistance = Math.sqrt(dx * dx + dy * dy);
|
|
41
|
-
const scaleFactor = currentPinchDistance / this.initialPinchDistance;
|
|
42
|
-
// 줌 threshold 확인 후 줌 적용
|
|
43
|
-
if (Math.abs(scaleFactor - 1) > this.zoomThreshold) {
|
|
44
|
-
this.zoomLevel = this.initialZoomLevel * scaleFactor;
|
|
45
|
-
this.applyZoom();
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
this.onZoomTouchEnd = (event) => {
|
|
50
|
-
event.preventDefault();
|
|
51
|
-
if (event.touches.length < 2) {
|
|
52
|
-
this.initialPinchDistance = null;
|
|
53
|
-
}
|
|
54
|
-
this.svg.removeEventListener('touchmove', this.onZoomTouchMove);
|
|
55
|
-
this.svg.removeEventListener('touchend', this.onZoomTouchEnd);
|
|
56
|
-
};
|
|
57
|
-
this.onPanMouseMove = (event) => {
|
|
58
|
-
if (!this.isPanning) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
event.preventDefault();
|
|
62
|
-
const { x, y } = this.getPointFromEvent(event);
|
|
63
|
-
const dx = x - this.panStart.x;
|
|
64
|
-
const dy = y - this.panStart.y;
|
|
65
|
-
if (!this.panInitiated && Math.sqrt(dx * dx + dy * dy) < this.panThreshold) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
this.panInitiated = true;
|
|
69
|
-
const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number);
|
|
70
|
-
const scaleX = vbWidth / this.svg.clientWidth;
|
|
71
|
-
const scaleY = vbHeight / this.svg.clientHeight;
|
|
72
|
-
const scale = Math.max(scaleX, scaleY);
|
|
73
|
-
const newVbX = vbX - dx * scale;
|
|
74
|
-
const newVbY = vbY - dy * scale;
|
|
75
|
-
this.viewBox = `${newVbX} ${newVbY} ${vbWidth} ${vbHeight}`;
|
|
76
|
-
this.panStart = { x, y };
|
|
77
|
-
};
|
|
78
|
-
this.onPanMouseUp = (event) => {
|
|
79
|
-
event.preventDefault();
|
|
80
|
-
const svg = this.svg;
|
|
81
|
-
this.isPanning = false;
|
|
82
|
-
svg.classList.remove('dragging');
|
|
83
|
-
if ('touches' in event) {
|
|
84
|
-
svg.removeEventListener('touchmove', this.onPanMouseMove);
|
|
85
|
-
svg.removeEventListener('touchend', this.onPanMouseUp);
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
svg.removeEventListener('mousemove', this.onPanMouseMove);
|
|
89
|
-
svg.removeEventListener('mouseup', this.onPanMouseUp);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
18
|
+
this.initialViewBox = null;
|
|
19
|
+
this.gestureHelper = null;
|
|
92
20
|
}
|
|
93
21
|
static { this.styles = [
|
|
94
22
|
css `
|
|
@@ -108,24 +36,89 @@ export class BaseImageMarker extends LitElement {
|
|
|
108
36
|
cursor: pointer;
|
|
109
37
|
width: 100%;
|
|
110
38
|
height: 100%;
|
|
39
|
+
touch-action: none;
|
|
111
40
|
}
|
|
112
41
|
`
|
|
113
42
|
]; }
|
|
43
|
+
connectedCallback() {
|
|
44
|
+
super.connectedCallback();
|
|
45
|
+
requestAnimationFrame(() => {
|
|
46
|
+
this.gestureHelper = new GestureHelper(this.svg);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
disconnectedCallback() {
|
|
50
|
+
super.disconnectedCallback();
|
|
51
|
+
this.gestureHelper?.dispose();
|
|
52
|
+
this.gestureHelper = null;
|
|
53
|
+
}
|
|
54
|
+
updated(changes) {
|
|
55
|
+
if (changes.has('imageUrl') || changes.has('imageProvider')) {
|
|
56
|
+
this.initialViewBox = null;
|
|
57
|
+
this.updateImage();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
setImageProvider(provider) {
|
|
61
|
+
this.imageProvider = provider;
|
|
62
|
+
}
|
|
114
63
|
onImageLoad(event) {
|
|
115
64
|
const img = new Image();
|
|
116
65
|
img.onload = () => {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
66
|
+
const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number);
|
|
67
|
+
if (!this.initialViewBox) {
|
|
68
|
+
const width = img.naturalWidth;
|
|
69
|
+
const height = img.naturalHeight;
|
|
70
|
+
this.initialViewBox = `0 0 ${width} ${height}`;
|
|
71
|
+
this.viewBox = this.initialViewBox;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.viewBox = `${vbX} ${vbY} ${vbWidth} ${vbHeight}`;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
img.src = this.currentImage;
|
|
78
|
+
}
|
|
79
|
+
async updateImage() {
|
|
80
|
+
if (!this.imageProvider) {
|
|
81
|
+
throw new Error('ImageProvider is not set');
|
|
82
|
+
}
|
|
83
|
+
const options = {
|
|
84
|
+
id: this.imageUrl, // 이미지 ID는 imageUrl 속성을 사용
|
|
85
|
+
scale: this.zoomLevel, // scale은 zoomLevel 속성을 사용
|
|
86
|
+
offsetX: 0, // offsetX는 0으로 설정
|
|
87
|
+
offsetY: 0, // offsetY는 0으로 설정
|
|
88
|
+
currentImage: this.currentImage // 기존 이미지 객체 전달
|
|
121
89
|
};
|
|
122
|
-
|
|
90
|
+
this.currentImage = await this.imageProvider.getImage(options);
|
|
123
91
|
}
|
|
124
92
|
onSvgWheel(event) {
|
|
125
93
|
event.preventDefault();
|
|
126
94
|
const { offsetX, offsetY, deltaY } = event;
|
|
127
95
|
const scale = deltaY > 0 ? 1 - this.zoomFactor : 1 + this.zoomFactor;
|
|
128
|
-
|
|
96
|
+
this.zoom(scale, offsetX, offsetY);
|
|
97
|
+
}
|
|
98
|
+
onSvgPinch(e) {
|
|
99
|
+
e.stopPropagation();
|
|
100
|
+
const { scale, centerX, centerY } = e.detail;
|
|
101
|
+
console.log('pinch', e.detail);
|
|
102
|
+
this.zoom(scale, centerX, centerY);
|
|
103
|
+
}
|
|
104
|
+
onSvgDoubleTap(e) {
|
|
105
|
+
e.stopPropagation();
|
|
106
|
+
this.reset();
|
|
107
|
+
}
|
|
108
|
+
onSvgDrag(e) {
|
|
109
|
+
const { deltaX, deltaY } = e.detail;
|
|
110
|
+
console.log('drag', e.detail);
|
|
111
|
+
const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number);
|
|
112
|
+
const scaleX = vbWidth / this.svg.clientWidth;
|
|
113
|
+
const scaleY = vbHeight / this.svg.clientHeight;
|
|
114
|
+
const scale = Math.max(scaleX, scaleY);
|
|
115
|
+
const newVbX = vbX - deltaX * scale;
|
|
116
|
+
const newVbY = vbY - deltaY * scale;
|
|
117
|
+
this.viewBox = `${newVbX} ${newVbY} ${vbWidth} ${vbHeight}`;
|
|
118
|
+
this.debouncedUpdateImage();
|
|
119
|
+
}
|
|
120
|
+
zoom(scale, offsetX, offsetY) {
|
|
121
|
+
if (Math.abs(scale) > this.zoomThreshold) {
|
|
129
122
|
this.zoomLevel *= scale;
|
|
130
123
|
const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number);
|
|
131
124
|
const mouseX = vbX + (offsetX / this.svg.clientWidth) * vbWidth;
|
|
@@ -135,61 +128,13 @@ export class BaseImageMarker extends LitElement {
|
|
|
135
128
|
const newVbX = mouseX - (offsetX / this.svg.clientWidth) * newVbWidth;
|
|
136
129
|
const newVbY = mouseY - (offsetY / this.svg.clientHeight) * newVbHeight;
|
|
137
130
|
this.viewBox = `${newVbX} ${newVbY} ${newVbWidth} ${newVbHeight}`;
|
|
131
|
+
this.debouncedUpdateImage();
|
|
138
132
|
}
|
|
139
133
|
}
|
|
140
|
-
|
|
141
|
-
event.preventDefault();
|
|
142
|
-
this.startPanning(event);
|
|
143
|
-
this.svg.addEventListener('mousemove', this.onPanMouseMove);
|
|
144
|
-
this.svg.addEventListener('mouseup', this.onPanMouseUp);
|
|
145
|
-
}
|
|
146
|
-
isDoubleTouch(event) {
|
|
147
|
-
const currentTime = new Date().getTime();
|
|
148
|
-
const tapLength = currentTime - this.lastTouchEnd;
|
|
149
|
-
const result = tapLength < 300 && event.touches.length == 1;
|
|
150
|
-
this.lastTouchEnd = currentTime;
|
|
151
|
-
return result;
|
|
152
|
-
}
|
|
153
|
-
startPinchZooming(event) {
|
|
154
|
-
const touch1 = event.touches[0];
|
|
155
|
-
const touch2 = event.touches[1];
|
|
156
|
-
const dx = touch2.clientX - touch1.clientX;
|
|
157
|
-
const dy = touch2.clientY - touch1.clientY;
|
|
158
|
-
this.initialPinchDistance = Math.sqrt(dx * dx + dy * dy);
|
|
159
|
-
this.initialZoomLevel = this.zoomLevel;
|
|
160
|
-
this.svg.addEventListener('touchmove', this.onZoomTouchMove);
|
|
161
|
-
this.svg.addEventListener('touchend', this.onZoomTouchEnd);
|
|
162
|
-
}
|
|
163
|
-
applyZoom() {
|
|
164
|
-
const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number);
|
|
165
|
-
const initialViewBoxNumbers = this.initialViewBox.split(' ').map(Number);
|
|
166
|
-
const newVbWidth = initialViewBoxNumbers[2] / this.zoomLevel;
|
|
167
|
-
const newVbHeight = initialViewBoxNumbers[3] / this.zoomLevel;
|
|
168
|
-
const newVbX = vbX + (vbWidth - newVbWidth) / 2;
|
|
169
|
-
const newVbY = vbY + (vbHeight - newVbHeight) / 2;
|
|
170
|
-
this.viewBox = `${newVbX} ${newVbY} ${newVbWidth} ${newVbHeight}`;
|
|
171
|
-
}
|
|
172
|
-
onSvgDoubleClick() {
|
|
173
|
-
this.resetZoom();
|
|
174
|
-
}
|
|
175
|
-
resetZoom() {
|
|
134
|
+
reset() {
|
|
176
135
|
this.viewBox = this.initialViewBox;
|
|
177
136
|
this.zoomLevel = 1;
|
|
178
|
-
|
|
179
|
-
startPanning(event) {
|
|
180
|
-
const { x, y } = this.getPointFromEvent(event);
|
|
181
|
-
this.isPanning = true;
|
|
182
|
-
this.panStart = { x, y };
|
|
183
|
-
this.panInitiated = false; // 팬 동작이 아직 시작되지 않았음을 나타냄
|
|
184
|
-
this.svg.classList.add('dragging');
|
|
185
|
-
if ('touches' in event) {
|
|
186
|
-
this.svg.addEventListener('touchmove', this.onPanMouseMove);
|
|
187
|
-
this.svg.addEventListener('touchend', this.onPanMouseUp);
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
this.svg.addEventListener('mousemove', this.onPanMouseMove);
|
|
191
|
-
this.svg.addEventListener('mouseup', this.onPanMouseUp);
|
|
192
|
-
}
|
|
137
|
+
this.debouncedUpdateImage();
|
|
193
138
|
}
|
|
194
139
|
renderShape(shape) {
|
|
195
140
|
const commonAttrs = {
|
|
@@ -219,16 +164,17 @@ export class BaseImageMarker extends LitElement {
|
|
|
219
164
|
}
|
|
220
165
|
}
|
|
221
166
|
getPointFromEvent(event) {
|
|
222
|
-
if ('
|
|
167
|
+
if ('clientX' in event) {
|
|
223
168
|
return {
|
|
224
|
-
x: event.
|
|
225
|
-
y: event.
|
|
169
|
+
x: event.clientX,
|
|
170
|
+
y: event.clientY
|
|
226
171
|
};
|
|
227
172
|
}
|
|
228
173
|
else {
|
|
174
|
+
const { clientX, clientY } = event.detail;
|
|
229
175
|
return {
|
|
230
|
-
x:
|
|
231
|
-
y:
|
|
176
|
+
x: clientX,
|
|
177
|
+
y: clientY
|
|
232
178
|
};
|
|
233
179
|
}
|
|
234
180
|
}
|
|
@@ -239,12 +185,18 @@ __decorate([
|
|
|
239
185
|
__decorate([
|
|
240
186
|
property({ type: Array })
|
|
241
187
|
], BaseImageMarker.prototype, "shapes", void 0);
|
|
188
|
+
__decorate([
|
|
189
|
+
state()
|
|
190
|
+
], BaseImageMarker.prototype, "currentImage", void 0);
|
|
242
191
|
__decorate([
|
|
243
192
|
state()
|
|
244
193
|
], BaseImageMarker.prototype, "viewBox", void 0);
|
|
245
194
|
__decorate([
|
|
246
195
|
state()
|
|
247
196
|
], BaseImageMarker.prototype, "zoomLevel", void 0);
|
|
197
|
+
__decorate([
|
|
198
|
+
state()
|
|
199
|
+
], BaseImageMarker.prototype, "imageProvider", void 0);
|
|
248
200
|
__decorate([
|
|
249
201
|
query('svg')
|
|
250
202
|
], BaseImageMarker.prototype, "svg", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-image-marker.js","sourceRoot":"","sources":["../../src/base-image-marker.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, svg, nothing } from 'lit'\nimport { property, state, query } from 'lit/decorators.js'\n\nimport { Shape } from './types'\n\nexport class BaseImageMarker extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n }\n\n .container {\n flex: 1;\n position: relative;\n }\n\n svg {\n position: absolute;\n top: 0;\n left: 0;\n cursor: pointer;\n width: 100%;\n height: 100%;\n }\n `\n ]\n\n @property({ type: String }) imageUrl: string = ''\n @property({ type: Array }) shapes: Shape[] = []\n\n @state() protected viewBox = '0 0 800 600'\n @state() protected zoomLevel = 1\n\n protected zoomFactor = 0.1\n protected zoomThreshold = 0.05\n protected isPanning = false\n protected panStart = { x: 0, y: 0 }\n protected panInitiated = false\n protected panThreshold = 20\n\n protected initialViewBox = '0 0 800 600'\n private initialPinchDistance: number | null = null\n private initialZoomLevel: number = 1\n private lastTouchEnd: number = 0\n\n @query('svg') protected svg!: SVGSVGElement\n\n protected onImageLoad(event: Event) {\n const img = new Image()\n img.onload = () => {\n const width = img.naturalWidth\n const height = img.naturalHeight\n this.viewBox = `0 0 ${width} ${height}`\n this.initialViewBox = `0 0 ${width} ${height}`\n }\n img.src = this.imageUrl\n }\n\n protected onSvgWheel(event: WheelEvent) {\n event.preventDefault()\n\n const { offsetX, offsetY, deltaY } = event\n const scale = deltaY > 0 ? 1 - this.zoomFactor : 1 + this.zoomFactor\n if (Math.abs(scale - 1) > this.zoomThreshold) {\n this.zoomLevel *= scale\n\n const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)\n const mouseX = vbX + (offsetX / this.svg.clientWidth) * vbWidth\n const mouseY = vbY + (offsetY / this.svg.clientHeight) * vbHeight\n\n const newVbWidth = vbWidth / scale\n const newVbHeight = vbHeight / scale\n\n const newVbX = mouseX - (offsetX / this.svg.clientWidth) * newVbWidth\n const newVbY = mouseY - (offsetY / this.svg.clientHeight) * newVbHeight\n\n this.viewBox = `${newVbX} ${newVbY} ${newVbWidth} ${newVbHeight}`\n }\n }\n\n protected onSvgMouseDown(event: MouseEvent) {\n event.preventDefault()\n\n this.startPanning(event)\n\n this.svg.addEventListener('mousemove', this.onPanMouseMove)\n this.svg.addEventListener('mouseup', this.onPanMouseUp)\n }\n\n protected isDoubleTouch(event: TouchEvent) {\n const currentTime = new Date().getTime()\n const tapLength = currentTime - this.lastTouchEnd\n\n const result = tapLength < 300 && event.touches.length == 1\n this.lastTouchEnd = currentTime\n\n return result\n }\n\n protected onSvgTouchStart = (event: TouchEvent) => {\n event.preventDefault()\n\n if (this.isDoubleTouch(event)) {\n this.resetZoom()\n }\n\n if (event.touches.length === 1) {\n this.startPanning(event)\n } else if (event.touches.length === 2) {\n this.startPinchZooming(event)\n }\n }\n\n protected startPinchZooming(event: TouchEvent) {\n const touch1 = event.touches[0]\n const touch2 = event.touches[1]\n\n const dx = touch2.clientX - touch1.clientX\n const dy = touch2.clientY - touch1.clientY\n\n this.initialPinchDistance = Math.sqrt(dx * dx + dy * dy)\n this.initialZoomLevel = this.zoomLevel\n\n this.svg.addEventListener('touchmove', this.onZoomTouchMove)\n this.svg.addEventListener('touchend', this.onZoomTouchEnd)\n }\n\n protected onZoomTouchMove = (event: TouchEvent) => {\n event.preventDefault()\n\n if (event.touches.length === 2 && this.initialPinchDistance) {\n const touch1 = event.touches[0]\n const touch2 = event.touches[1]\n const dx = touch2.clientX - touch1.clientX\n const dy = touch2.clientY - touch1.clientY\n const currentPinchDistance = Math.sqrt(dx * dx + dy * dy)\n\n const scaleFactor = currentPinchDistance / this.initialPinchDistance\n\n // 줌 threshold 확인 후 줌 적용\n if (Math.abs(scaleFactor - 1) > this.zoomThreshold) {\n this.zoomLevel = this.initialZoomLevel * scaleFactor\n this.applyZoom()\n }\n }\n }\n\n protected onZoomTouchEnd = (event: TouchEvent) => {\n event.preventDefault()\n\n if (event.touches.length < 2) {\n this.initialPinchDistance = null\n }\n\n this.svg.removeEventListener('touchmove', this.onZoomTouchMove)\n this.svg.removeEventListener('touchend', this.onZoomTouchEnd)\n }\n\n protected applyZoom() {\n const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)\n const initialViewBoxNumbers = this.initialViewBox.split(' ').map(Number)\n const newVbWidth = initialViewBoxNumbers[2] / this.zoomLevel\n const newVbHeight = initialViewBoxNumbers[3] / this.zoomLevel\n const newVbX = vbX + (vbWidth - newVbWidth) / 2\n const newVbY = vbY + (vbHeight - newVbHeight) / 2\n\n this.viewBox = `${newVbX} ${newVbY} ${newVbWidth} ${newVbHeight}`\n }\n\n protected onSvgDoubleClick() {\n this.resetZoom()\n }\n\n protected resetZoom() {\n this.viewBox = this.initialViewBox\n this.zoomLevel = 1\n }\n\n protected startPanning(event: MouseEvent | TouchEvent) {\n const { x, y } = this.getPointFromEvent(event)\n\n this.isPanning = true\n this.panStart = { x, y }\n this.panInitiated = false // 팬 동작이 아직 시작되지 않았음을 나타냄\n this.svg.classList.add('dragging')\n\n if ('touches' in event) {\n this.svg.addEventListener('touchmove', this.onPanMouseMove)\n this.svg.addEventListener('touchend', this.onPanMouseUp)\n } else {\n this.svg.addEventListener('mousemove', this.onPanMouseMove)\n this.svg.addEventListener('mouseup', this.onPanMouseUp)\n }\n }\n\n protected onPanMouseMove = (event: MouseEvent | TouchEvent) => {\n if (!this.isPanning) {\n return\n }\n event.preventDefault()\n\n const { x, y } = this.getPointFromEvent(event)\n\n const dx = x - this.panStart.x\n const dy = y - this.panStart.y\n\n if (!this.panInitiated && Math.sqrt(dx * dx + dy * dy) < this.panThreshold) {\n return\n }\n\n this.panInitiated = true\n\n const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)\n const scaleX = vbWidth / this.svg.clientWidth\n const scaleY = vbHeight / this.svg.clientHeight\n const scale = Math.max(scaleX, scaleY)\n\n const newVbX = vbX - dx * scale\n const newVbY = vbY - dy * scale\n\n this.viewBox = `${newVbX} ${newVbY} ${vbWidth} ${vbHeight}`\n this.panStart = { x, y }\n }\n\n protected onPanMouseUp = (event: MouseEvent | TouchEvent) => {\n event.preventDefault()\n\n const svg = this.svg\n\n this.isPanning = false\n svg.classList.remove('dragging')\n\n if ('touches' in event) {\n svg.removeEventListener('touchmove', this.onPanMouseMove)\n svg.removeEventListener('touchend', this.onPanMouseUp)\n } else {\n svg.removeEventListener('mousemove', this.onPanMouseMove)\n svg.removeEventListener('mouseup', this.onPanMouseUp)\n }\n }\n\n protected renderShape(shape: Shape) {\n const commonAttrs = {\n stroke: 'red',\n 'stroke-width': 1,\n fill: 'transparent'\n }\n\n switch (shape.type) {\n case 'text':\n return svg`<text x=\"${shape.x}\" y=\"${shape.y}\" text-anchor=\"middle\" alignment-baseline=\"middle\" fill=\"black\">${shape.text}</text>`\n case 'rectangle':\n return svg`<rect x=\"${shape.x}\" y=\"${shape.y}\" width=\"${shape.width}\" height=\"${shape.height}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\" fill=\"${commonAttrs.fill}\"></rect>`\n case 'circle':\n return svg`<circle cx=\"${shape.cx}\" cy=\"${shape.cy}\" r=\"${shape.r}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\" fill=\"${commonAttrs.fill}\"></circle>`\n case 'line':\n return svg`<line x1=\"${shape.x1}\" y1=\"${shape.y1}\" x2=\"${shape.x2}\" y2=\"${shape.y2}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\"></line>`\n case 'arrow':\n return svg`\n <defs>\n <marker id=\"arrowhead-${shape.id}\" markerWidth=\"10\" markerHeight=\"7\" refX=\"10\" refY=\"3.5\" orient=\"auto\">\n <polygon points=\"0 0, 10 3.5, 0 7\" fill=\"${commonAttrs.stroke}\"></polygon>\n </marker>\n </defs>\n <line x1=\"${shape.x1}\" y1=\"${shape.y1}\" x2=\"${shape.x2}\" y2=\"${shape.y2}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\" marker-end=\"url(#arrowhead-${shape.id})\"></line>`\n default:\n return nothing\n }\n }\n\n protected getPointFromEvent(event: MouseEvent | TouchEvent) {\n if ('touches' in event) {\n return {\n x: event.touches[0].clientX,\n y: event.touches[0].clientY\n }\n } else {\n return {\n x: event.clientX,\n y: event.clientY\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"base-image-marker.js","sourceRoot":"","sources":["../../src/base-image-marker.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAQ,GAAG,EAAE,OAAO,EAAkB,MAAM,KAAK,CAAA;AACzE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EAIL,aAAa,EACd,MAAM,kCAAkC,CAAA;AAEzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AAE/D,MAAM,OAAO,eAAgB,SAAQ,UAAU;IAA/C;;QAwB8B,aAAQ,GAAW,EAAE,CAAA;QACtB,WAAM,GAAY,EAAE,CAAA;QAG5B,YAAO,GAAG,aAAa,CAAA;QACvB,cAAS,GAAG,CAAC,CAAA;QACf,kBAAa,GAAmB,IAAI,oBAAoB,EAAE,CAAA;QAEjE,yBAAoB,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAA;QACjE,eAAU,GAAG,GAAG,CAAA;QAChB,kBAAa,GAAG,IAAI,CAAA;QAEpB,mBAAc,GAAkB,IAAI,CAAA;QAItC,kBAAa,GAAyB,IAAI,CAAA;IAgLpD,CAAC;aAvNQ,WAAM,GAAG;QACd,GAAG,CAAA;;;;;;;;;;;;;;;;;;;KAmBF;KACF,AArBY,CAqBZ;IAoBD,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,qBAAqB,CAAC,GAAG,EAAE;YACzB,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,oBAAoB;QAClB,KAAK,CAAC,oBAAoB,EAAE,CAAA;QAE5B,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,CAAA;QAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAA;IAC3B,CAAC;IAES,OAAO,CAAC,OAAuB;QACvC,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YAC5D,IAAI,CAAC,cAAc,GAAG,IAAI,CAAA;YAC1B,IAAI,CAAC,WAAW,EAAE,CAAA;QACpB,CAAC;IACH,CAAC;IAEM,gBAAgB,CAAC,QAAuB;QAC7C,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAA;IAC/B,CAAC;IAES,WAAW,CAAC,KAAY;QAChC,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAA;QAEvB,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE;YAChB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAEzE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAA;gBAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,CAAA;gBAEhC,IAAI,CAAC,cAAc,GAAG,OAAO,KAAK,IAAI,MAAM,EAAE,CAAA;gBAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,cAAc,CAAA;YACpC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAA;YACvD,CAAC;QACH,CAAC,CAAA;QAED,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,YAAa,CAAA;IAC9B,CAAC;IAES,KAAK,CAAC,WAAW;QACzB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;QAC7C,CAAC;QAED,MAAM,OAAO,GAAG;YACd,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,0BAA0B;YAC7C,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,0BAA0B;YACjD,OAAO,EAAE,CAAC,EAAE,kBAAkB;YAC9B,OAAO,EAAE,CAAC,EAAE,kBAAkB;YAC9B,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,eAAe;SAChD,CAAA;QAED,IAAI,CAAC,YAAY,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAChE,CAAC;IAES,UAAU,CAAC,KAAiB;QACpC,KAAK,CAAC,cAAc,EAAE,CAAA;QAEtB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;QAC1C,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAA;QAEpE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACpC,CAAC;IAES,UAAU,CAAC,CAAoB;QACvC,CAAC,CAAC,eAAe,EAAE,CAAA;QAEnB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,CAAA;QAE5C,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;QAE9B,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACpC,CAAC;IAES,cAAc,CAAC,CAAwB;QAC/C,CAAC,CAAC,eAAe,EAAE,CAAA;QAEnB,IAAI,CAAC,KAAK,EAAE,CAAA;IACd,CAAC;IAES,SAAS,CAAC,CAAmB;QACrC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAA;QACnC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;QAE7B,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAEzE,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAA;QAC7C,MAAM,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAA;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAEtC,MAAM,MAAM,GAAG,GAAG,GAAG,MAAM,GAAG,KAAK,CAAA;QACnC,MAAM,MAAM,GAAG,GAAG,GAAG,MAAM,GAAG,KAAK,CAAA;QAEnC,IAAI,CAAC,OAAO,GAAG,GAAG,MAAM,IAAI,MAAM,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAA;QAE3D,IAAI,CAAC,oBAAoB,EAAE,CAAA;IAC7B,CAAC;IAED,IAAI,CAAC,KAAa,EAAE,OAAe,EAAE,OAAe;QAClD,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACzC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAA;YAEvB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACzE,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,OAAO,CAAA;YAC/D,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,QAAQ,CAAA;YAEjE,MAAM,UAAU,GAAG,OAAO,GAAG,KAAK,CAAA;YAClC,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,CAAA;YAEpC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,UAAU,CAAA;YACrE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,WAAW,CAAA;YAEvE,IAAI,CAAC,OAAO,GAAG,GAAG,MAAM,IAAI,MAAM,IAAI,UAAU,IAAI,WAAW,EAAE,CAAA;YAEjE,IAAI,CAAC,oBAAoB,EAAE,CAAA;QAC7B,CAAC;IACH,CAAC;IAES,KAAK;QACb,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,cAAe,CAAA;QACnC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAA;QAElB,IAAI,CAAC,oBAAoB,EAAE,CAAA;IAC7B,CAAC;IAES,WAAW,CAAC,KAAY;QAChC,MAAM,WAAW,GAAG;YAClB,MAAM,EAAE,KAAK;YACb,cAAc,EAAE,CAAC;YACjB,IAAI,EAAE,aAAa;SACpB,CAAA;QAED,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,OAAO,GAAG,CAAA,YAAY,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,mEAAmE,KAAK,CAAC,IAAI,SAAS,CAAA;YACpI,KAAK,WAAW;gBACd,OAAO,GAAG,CAAA,YAAY,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,YAAY,KAAK,CAAC,KAAK,aAAa,KAAK,CAAC,MAAM,aAAa,WAAW,CAAC,MAAM,mBAAmB,WAAW,CAAC,cAAc,CAAC,WAAW,WAAW,CAAC,IAAI,WAAW,CAAA;YACjN,KAAK,QAAQ;gBACX,OAAO,GAAG,CAAA,eAAe,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,QAAQ,KAAK,CAAC,CAAC,aAAa,WAAW,CAAC,MAAM,mBAAmB,WAAW,CAAC,cAAc,CAAC,WAAW,WAAW,CAAC,IAAI,aAAa,CAAA;YACxL,KAAK,MAAM;gBACT,OAAO,GAAG,CAAA,aAAa,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,aAAa,WAAW,CAAC,MAAM,mBAAmB,WAAW,CAAC,cAAc,CAAC,WAAW,CAAA;YAC5K,KAAK,OAAO;gBACV,OAAO,GAAG,CAAA;;oCAEkB,KAAK,CAAC,EAAE;yDACa,WAAW,CAAC,MAAM;;;sBAGrD,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,SAAS,KAAK,CAAC,EAAE,aAAa,WAAW,CAAC,MAAM,mBAAmB,WAAW,CAAC,cAAc,CAAC,gCAAgC,KAAK,CAAC,EAAE,YAAY,CAAA;YAC5M;gBACE,OAAO,OAAO,CAAA;QAClB,CAAC;IACH,CAAC;IAES,iBAAiB,CAAC,KAAmD;QAC7E,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;YACvB,OAAO;gBACL,CAAC,EAAE,KAAK,CAAC,OAAO;gBAChB,CAAC,EAAE,KAAK,CAAC,OAAO;aACjB,CAAA;QACH,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,CAAA;YACzC,OAAO;gBACL,CAAC,EAAE,OAAO;gBACV,CAAC,EAAE,OAAO;aACX,CAAA;QACH,CAAC;IACH,CAAC;;AA/L2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;iDAAsB;AACtB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;+CAAqB;AAE5B;IAAlB,KAAK,EAAE;qDAAgC;AACrB;IAAlB,KAAK,EAAE;gDAAkC;AACvB;IAAlB,KAAK,EAAE;kDAAwB;AACf;IAAhB,KAAK,EAAE;sDAAmE;AAQnD;IAAvB,KAAK,CAAC,KAAK,CAAC;4CAA8B","sourcesContent":["import { LitElement, css, html, svg, nothing, PropertyValues } from 'lit'\nimport { property, state, query } from 'lit/decorators.js'\nimport { debounce } from 'lodash-es'\n\nimport {\n GestureEventDoubleTap,\n GestureEventDrag,\n GestureEventPinch,\n GestureHelper\n} from '@operato/utils/gesture-helper.js'\nimport { ImageProvider, Shape } from './types'\nimport { DefaultImageProvider } from './default-image-provider'\n\nexport class BaseImageMarker extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n }\n\n .container {\n flex: 1;\n position: relative;\n }\n\n svg {\n position: absolute;\n top: 0;\n left: 0;\n cursor: pointer;\n width: 100%;\n height: 100%;\n touch-action: none;\n }\n `\n ]\n\n @property({ type: String }) imageUrl: string = ''\n @property({ type: Array }) shapes: Shape[] = []\n\n @state() protected currentImage?: string\n @state() protected viewBox = '0 0 800 600'\n @state() protected zoomLevel = 1\n @state() private imageProvider?: ImageProvider = new DefaultImageProvider()\n\n protected debouncedUpdateImage = debounce(this.updateImage.bind(this), 300)\n protected zoomFactor = 0.1\n protected zoomThreshold = 0.05\n\n protected initialViewBox: string | null = null\n\n @query('svg') protected svg!: SVGSVGElement\n\n private gestureHelper: GestureHelper | null = null\n\n connectedCallback(): void {\n super.connectedCallback()\n requestAnimationFrame(() => {\n this.gestureHelper = new GestureHelper(this.svg)\n })\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback()\n\n this.gestureHelper?.dispose()\n this.gestureHelper = null\n }\n\n protected updated(changes: PropertyValues): void {\n if (changes.has('imageUrl') || changes.has('imageProvider')) {\n this.initialViewBox = null\n this.updateImage()\n }\n }\n\n public setImageProvider(provider: ImageProvider) {\n this.imageProvider = provider\n }\n\n protected onImageLoad(event: Event) {\n const img = new Image()\n\n img.onload = () => {\n const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)\n\n if (!this.initialViewBox) {\n const width = img.naturalWidth\n const height = img.naturalHeight\n\n this.initialViewBox = `0 0 ${width} ${height}`\n this.viewBox = this.initialViewBox\n } else {\n this.viewBox = `${vbX} ${vbY} ${vbWidth} ${vbHeight}`\n }\n }\n\n img.src = this.currentImage!\n }\n\n protected async updateImage() {\n if (!this.imageProvider) {\n throw new Error('ImageProvider is not set')\n }\n\n const options = {\n id: this.imageUrl, // 이미지 ID는 imageUrl 속성을 사용\n scale: this.zoomLevel, // scale은 zoomLevel 속성을 사용\n offsetX: 0, // offsetX는 0으로 설정\n offsetY: 0, // offsetY는 0으로 설정\n currentImage: this.currentImage // 기존 이미지 객체 전달\n }\n\n this.currentImage = await this.imageProvider.getImage(options)\n }\n\n protected onSvgWheel(event: WheelEvent) {\n event.preventDefault()\n\n const { offsetX, offsetY, deltaY } = event\n const scale = deltaY > 0 ? 1 - this.zoomFactor : 1 + this.zoomFactor\n\n this.zoom(scale, offsetX, offsetY)\n }\n\n protected onSvgPinch(e: GestureEventPinch) {\n e.stopPropagation()\n\n const { scale, centerX, centerY } = e.detail\n\n console.log('pinch', e.detail)\n\n this.zoom(scale, centerX, centerY)\n }\n\n protected onSvgDoubleTap(e: GestureEventDoubleTap) {\n e.stopPropagation()\n\n this.reset()\n }\n\n protected onSvgDrag(e: GestureEventDrag) {\n const { deltaX, deltaY } = e.detail\n console.log('drag', e.detail)\n\n const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)\n\n const scaleX = vbWidth / this.svg.clientWidth\n const scaleY = vbHeight / this.svg.clientHeight\n const scale = Math.max(scaleX, scaleY)\n\n const newVbX = vbX - deltaX * scale\n const newVbY = vbY - deltaY * scale\n\n this.viewBox = `${newVbX} ${newVbY} ${vbWidth} ${vbHeight}`\n\n this.debouncedUpdateImage()\n }\n\n zoom(scale: number, offsetX: number, offsetY: number) {\n if (Math.abs(scale) > this.zoomThreshold) {\n this.zoomLevel *= scale\n\n const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)\n const mouseX = vbX + (offsetX / this.svg.clientWidth) * vbWidth\n const mouseY = vbY + (offsetY / this.svg.clientHeight) * vbHeight\n\n const newVbWidth = vbWidth / scale\n const newVbHeight = vbHeight / scale\n\n const newVbX = mouseX - (offsetX / this.svg.clientWidth) * newVbWidth\n const newVbY = mouseY - (offsetY / this.svg.clientHeight) * newVbHeight\n\n this.viewBox = `${newVbX} ${newVbY} ${newVbWidth} ${newVbHeight}`\n\n this.debouncedUpdateImage()\n }\n }\n\n protected reset() {\n this.viewBox = this.initialViewBox!\n this.zoomLevel = 1\n\n this.debouncedUpdateImage()\n }\n\n protected renderShape(shape: Shape) {\n const commonAttrs = {\n stroke: 'red',\n 'stroke-width': 1,\n fill: 'transparent'\n }\n\n switch (shape.type) {\n case 'text':\n return svg`<text x=\"${shape.x}\" y=\"${shape.y}\" text-anchor=\"middle\" alignment-baseline=\"middle\" fill=\"black\">${shape.text}</text>`\n case 'rectangle':\n return svg`<rect x=\"${shape.x}\" y=\"${shape.y}\" width=\"${shape.width}\" height=\"${shape.height}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\" fill=\"${commonAttrs.fill}\"></rect>`\n case 'circle':\n return svg`<circle cx=\"${shape.cx}\" cy=\"${shape.cy}\" r=\"${shape.r}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\" fill=\"${commonAttrs.fill}\"></circle>`\n case 'line':\n return svg`<line x1=\"${shape.x1}\" y1=\"${shape.y1}\" x2=\"${shape.x2}\" y2=\"${shape.y2}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\"></line>`\n case 'arrow':\n return svg`\n <defs>\n <marker id=\"arrowhead-${shape.id}\" markerWidth=\"10\" markerHeight=\"7\" refX=\"10\" refY=\"3.5\" orient=\"auto\">\n <polygon points=\"0 0, 10 3.5, 0 7\" fill=\"${commonAttrs.stroke}\"></polygon>\n </marker>\n </defs>\n <line x1=\"${shape.x1}\" y1=\"${shape.y1}\" x2=\"${shape.x2}\" y2=\"${shape.y2}\" stroke=\"${commonAttrs.stroke}\" stroke-width=\"${commonAttrs['stroke-width']}\" marker-end=\"url(#arrowhead-${shape.id})\"></line>`\n default:\n return nothing\n }\n }\n\n protected getPointFromEvent(event: MouseEvent | PointerEvent | GestureEventDrag) {\n if ('clientX' in event) {\n return {\n x: event.clientX,\n y: event.clientY\n }\n } else {\n const { clientX, clientY } = event.detail\n return {\n x: clientX,\n y: clientY\n }\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"default-image-provider.js","sourceRoot":"","sources":["../../src/default-image-provider.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,oBAAoB;IAC/B,KAAK,CAAC,QAAQ,CAAC,OAAqB;QAClC,OAAO,OAAO,CAAC,EAAE,CAAA;IACnB,CAAC;CACF","sourcesContent":["import { ImageOptions, ImageProvider } from './types'\n\nexport class DefaultImageProvider implements ImageProvider {\n async getImage(options: ImageOptions): Promise<string> {\n return options.id\n }\n}\n"]}
|
|
@@ -8,12 +8,12 @@ let OxImageMarkerView = class OxImageMarkerView extends BaseImageMarker {
|
|
|
8
8
|
<div class="container">
|
|
9
9
|
<svg
|
|
10
10
|
@wheel=${this.onSvgWheel}
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
@
|
|
11
|
+
@doubletap=${this.onSvgDoubleTap}
|
|
12
|
+
@pinch=${this.onSvgPinch}
|
|
13
|
+
@drag=${this.onSvgDrag}
|
|
14
14
|
viewBox=${this.viewBox}
|
|
15
15
|
>
|
|
16
|
-
<image href=${this.
|
|
16
|
+
<image href=${this.currentImage} @load=${this.onImageLoad}></image>
|
|
17
17
|
${this.shapes.map(shape => this.renderShape(shape))}
|
|
18
18
|
</svg>
|
|
19
19
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ox-image-marker-view.js","sourceRoot":"","sources":["../../src/ox-image-marker-view.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAGjD,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,eAAe;IACpD,MAAM;QACJ,OAAO,IAAI,CAAA;;;mBAGI,IAAI,CAAC,UAAU;uBACX,IAAI,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"ox-image-marker-view.js","sourceRoot":"","sources":["../../src/ox-image-marker-view.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAGjD,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,eAAe;IACpD,MAAM;QACJ,OAAO,IAAI,CAAA;;;mBAGI,IAAI,CAAC,UAAU;uBACX,IAAI,CAAC,cAAc;mBACvB,IAAI,CAAC,UAAU;kBAChB,IAAI,CAAC,SAAS;oBACZ,IAAI,CAAC,OAAO;;wBAER,IAAI,CAAC,YAAY,UAAU,IAAI,CAAC,WAAW;YACvD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;;;KAGxD,CAAA;IACH,CAAC;CACF,CAAA;AAjBY,iBAAiB;IAD7B,aAAa,CAAC,sBAAsB,CAAC;GACzB,iBAAiB,CAiB7B","sourcesContent":["import { html } from 'lit'\nimport { customElement } from 'lit/decorators.js'\n\nimport { BaseImageMarker } from './base-image-marker.js'\n\n@customElement('ox-image-marker-view')\nexport class OxImageMarkerView extends BaseImageMarker {\n render() {\n return html`\n <div class=\"container\">\n <svg\n @wheel=${this.onSvgWheel}\n @doubletap=${this.onSvgDoubleTap}\n @pinch=${this.onSvgPinch}\n @drag=${this.onSvgDrag}\n viewBox=${this.viewBox}\n >\n <image href=${this.currentImage} @load=${this.onImageLoad}></image>\n ${this.shapes.map(shape => this.renderShape(shape))}\n </svg>\n </div>\n `\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import './ox-image-marker-mode';
|
|
2
2
|
import { nothing } from 'lit';
|
|
3
|
+
import { GestureEventDrag, GestureEventPinch } from '@operato/utils/gesture-helper.js';
|
|
3
4
|
import { Shape } from './types';
|
|
4
5
|
import { BaseImageMarker } from './base-image-marker';
|
|
5
6
|
import { OxImageMarkerMode } from './ox-image-marker-mode';
|
|
@@ -19,22 +20,21 @@ export declare class OxImageMarker extends BaseImageMarker {
|
|
|
19
20
|
connectedCallback(): void;
|
|
20
21
|
disconnectedCallback(): void;
|
|
21
22
|
render(): import("lit-html").TemplateResult<1>;
|
|
22
|
-
protected onSvgMouseDown(event: MouseEvent): void;
|
|
23
|
-
protected onSvgTouchStart: (event: TouchEvent) => void;
|
|
24
|
-
private startDrawing;
|
|
25
23
|
private setMode;
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
protected onSvgPinch(e: GestureEventPinch): void;
|
|
25
|
+
protected onSvgDrag(e: GestureEventDrag): void;
|
|
26
|
+
protected onSvgClick(e: MouseEvent): void;
|
|
27
|
+
private drawShape;
|
|
28
28
|
private setSelectedShape;
|
|
29
29
|
private getSvgPoint;
|
|
30
30
|
protected renderShape(shape: Shape): import("lit-html").TemplateResult<2> | typeof nothing;
|
|
31
|
-
private
|
|
32
|
-
private
|
|
33
|
-
private
|
|
31
|
+
private onPointerDownOnShape;
|
|
32
|
+
private onPointerMoveOnShape;
|
|
33
|
+
private onPointerUpOnShape;
|
|
34
34
|
private renderResizeHandles;
|
|
35
|
-
private
|
|
36
|
-
private
|
|
37
|
-
private
|
|
35
|
+
private onResizeHandlePointerDown;
|
|
36
|
+
private onResizeHandlePointerMove;
|
|
37
|
+
private onResizeHandlePointerUp;
|
|
38
38
|
private onTextDoubleClick;
|
|
39
39
|
private showTextInput;
|
|
40
40
|
private adjustInputWidth;
|