@operato/image-marker 8.0.0-alpha.23 → 8.0.0-alpha.25
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 +18 -0
- package/dist/src/base-image-marker.d.ts +3 -0
- package/dist/src/base-image-marker.js +24 -11
- package/dist/src/base-image-marker.js.map +1 -1
- package/dist/src/ox-image-marker-mode.d.ts +2 -2
- package/dist/src/ox-image-marker-mode.js +13 -13
- package/dist/src/ox-image-marker-mode.js.map +1 -1
- package/dist/src/ox-image-marker.d.ts +13 -8
- package/dist/src/ox-image-marker.js +148 -116
- package/dist/src/ox-image-marker.js.map +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/base-image-marker.ts +27 -11
- package/src/ox-image-marker-mode.ts +15 -15
- package/src/ox-image-marker.ts +161 -119
- package/src/types.ts +1 -1
|
@@ -38,57 +38,57 @@ export class OxImageMarkerMode extends LitElement {
|
|
|
38
38
|
}
|
|
39
39
|
`
|
|
40
40
|
|
|
41
|
-
@property({ type: String }) currentMode: ImageMarkerMode = '
|
|
41
|
+
@property({ type: String }) currentMode: ImageMarkerMode = 'edit'
|
|
42
42
|
@property({ type: String }) currentShapeType?: ShapeType
|
|
43
43
|
|
|
44
44
|
render() {
|
|
45
45
|
return html`
|
|
46
46
|
<div class="palette">
|
|
47
47
|
<md-icon
|
|
48
|
-
title="
|
|
49
|
-
?selected=${this.currentMode !== '
|
|
50
|
-
@click=${() => this.setMode(this.currentMode !== '
|
|
51
|
-
>${this.currentMode !== '
|
|
48
|
+
title="Edit or View"
|
|
49
|
+
?selected=${this.currentMode !== 'shape'}
|
|
50
|
+
@click=${() => this.setMode(this.currentMode !== 'edit' ? 'edit' : 'view')}
|
|
51
|
+
>${this.currentMode !== 'view' ? 'brush' : 'drag_pan'}</md-icon
|
|
52
52
|
>
|
|
53
53
|
|
|
54
54
|
<md-icon
|
|
55
55
|
title="Text"
|
|
56
|
-
?selected=${this.currentMode === '
|
|
56
|
+
?selected=${this.currentMode === 'shape' && this.currentShapeType === 'text'}
|
|
57
57
|
@click=${() => this.setShape('text')}
|
|
58
58
|
>match_case</md-icon
|
|
59
59
|
>
|
|
60
60
|
|
|
61
61
|
<md-icon
|
|
62
62
|
title="Rectangle"
|
|
63
|
-
?selected=${this.currentMode === '
|
|
63
|
+
?selected=${this.currentMode === 'shape' && this.currentShapeType === 'rectangle'}
|
|
64
64
|
@click=${() => this.setShape('rectangle')}
|
|
65
65
|
>rectangle</md-icon
|
|
66
66
|
>
|
|
67
67
|
|
|
68
68
|
<md-icon
|
|
69
69
|
title="Circle"
|
|
70
|
-
?selected=${this.currentMode === '
|
|
70
|
+
?selected=${this.currentMode === 'shape' && this.currentShapeType === 'circle'}
|
|
71
71
|
@click=${() => this.setShape('circle')}
|
|
72
72
|
>circle</md-icon
|
|
73
73
|
>
|
|
74
74
|
|
|
75
75
|
<md-icon
|
|
76
76
|
title="Triangle"
|
|
77
|
-
?selected=${this.currentMode === '
|
|
77
|
+
?selected=${this.currentMode === 'shape' && this.currentShapeType === 'triangle'}
|
|
78
78
|
@click=${() => this.setShape('triangle')}
|
|
79
79
|
>change_history</md-icon
|
|
80
80
|
>
|
|
81
81
|
|
|
82
82
|
<md-icon
|
|
83
83
|
title="Line"
|
|
84
|
-
?selected=${this.currentMode === '
|
|
84
|
+
?selected=${this.currentMode === 'shape' && this.currentShapeType === 'line'}
|
|
85
85
|
@click=${() => this.setShape('line')}
|
|
86
86
|
>shape_line</md-icon
|
|
87
87
|
>
|
|
88
88
|
|
|
89
89
|
<md-icon
|
|
90
90
|
title="Arrow"
|
|
91
|
-
?selected=${this.currentMode === '
|
|
91
|
+
?selected=${this.currentMode === 'shape' && this.currentShapeType === 'arrow'}
|
|
92
92
|
@click=${() => this.setShape('arrow')}
|
|
93
93
|
>line_end_arrow</md-icon
|
|
94
94
|
>
|
|
@@ -105,7 +105,7 @@ export class OxImageMarkerMode extends LitElement {
|
|
|
105
105
|
`
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
public setMode(mode: ImageMarkerMode) {
|
|
109
109
|
this.currentMode = mode
|
|
110
110
|
|
|
111
111
|
this.dispatchEvent(
|
|
@@ -117,12 +117,12 @@ export class OxImageMarkerMode extends LitElement {
|
|
|
117
117
|
)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
this.currentMode = '
|
|
120
|
+
protected setShape(shapeType: ShapeType) {
|
|
121
|
+
this.currentMode = 'shape'
|
|
122
122
|
this.currentShapeType = shapeType
|
|
123
123
|
this.dispatchEvent(
|
|
124
124
|
new CustomEvent('mode-changed', {
|
|
125
|
-
detail: { mode: '
|
|
125
|
+
detail: { mode: 'shape', shapeType: this.currentShapeType },
|
|
126
126
|
bubbles: true,
|
|
127
127
|
composed: true
|
|
128
128
|
})
|
package/src/ox-image-marker.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import './ox-image-marker-mode'
|
|
2
2
|
|
|
3
3
|
import { html, css, svg, nothing } from 'lit'
|
|
4
|
-
import { state, customElement } from 'lit/decorators.js'
|
|
4
|
+
import { query, state, customElement } from 'lit/decorators.js'
|
|
5
5
|
import { ifDefined } from 'lit/directives/if-defined.js'
|
|
6
6
|
import { keyed } from 'lit/directives/keyed.js'
|
|
7
7
|
|
|
8
8
|
import { ImageMarkerMode, Shape, ShapeType } from './types'
|
|
9
9
|
import { BaseImageMarker } from './base-image-marker'
|
|
10
|
+
import { OxImageMarkerMode } from './ox-image-marker-mode'
|
|
10
11
|
|
|
11
12
|
@customElement('ox-image-marker')
|
|
12
13
|
export class OxImageMarker extends BaseImageMarker {
|
|
@@ -27,11 +28,11 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
svg {
|
|
30
|
-
cursor:
|
|
31
|
+
cursor: default;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
svg
|
|
34
|
-
cursor:
|
|
34
|
+
svg[drawing] {
|
|
35
|
+
cursor: crosshair;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
.resize-handle {
|
|
@@ -41,14 +42,18 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
41
42
|
]
|
|
42
43
|
|
|
43
44
|
@state() private currentShapeType?: ShapeType
|
|
44
|
-
@state() private currentMode: ImageMarkerMode = '
|
|
45
|
+
@state() private currentMode: ImageMarkerMode = 'edit'
|
|
45
46
|
@state() private selectedShape: Shape | null = null
|
|
46
47
|
|
|
48
|
+
@query('ox-image-marker-mode') imageMarkerMode!: OxImageMarkerMode
|
|
49
|
+
|
|
47
50
|
private drawing = false
|
|
48
51
|
private startX = 0
|
|
49
52
|
private startY = 0
|
|
50
53
|
private offsetX = 0
|
|
51
54
|
private offsetY = 0
|
|
55
|
+
private shapeMoveThreshold = 10
|
|
56
|
+
private shapeMoveInitiated = false
|
|
52
57
|
|
|
53
58
|
connectedCallback() {
|
|
54
59
|
super.connectedCallback()
|
|
@@ -72,6 +77,7 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
72
77
|
@wheel=${this.onSvgWheel}
|
|
73
78
|
@dblclick=${this.onSvgDoubleClick}
|
|
74
79
|
viewBox=${this.viewBox}
|
|
80
|
+
?drawing=${this.currentMode == 'shape'}
|
|
75
81
|
>
|
|
76
82
|
<image href=${this.imageUrl} @load=${this.onImageLoad}></image>
|
|
77
83
|
${this.shapes.map(shape => keyed(shape.id, this.renderShape(shape)))}
|
|
@@ -103,15 +109,12 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
103
109
|
protected onSvgMouseDown(event: MouseEvent) {
|
|
104
110
|
event.preventDefault()
|
|
105
111
|
|
|
106
|
-
this.
|
|
107
|
-
this.shapes = this.shapes.map(s => {
|
|
108
|
-
return { ...s, selected: false }
|
|
109
|
-
})
|
|
112
|
+
this.setSelectedShape(null)
|
|
110
113
|
|
|
111
|
-
if (this.currentMode === '
|
|
112
|
-
this.startPanning(event)
|
|
113
|
-
} else if (this.currentMode === 'draw') {
|
|
114
|
+
if (this.currentMode === 'shape') {
|
|
114
115
|
this.startDrawing(event)
|
|
116
|
+
} else {
|
|
117
|
+
this.startPanning(event)
|
|
115
118
|
}
|
|
116
119
|
}
|
|
117
120
|
|
|
@@ -123,15 +126,12 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
if (event.touches.length === 1) {
|
|
126
|
-
this.
|
|
127
|
-
this.shapes = this.shapes.map(s => {
|
|
128
|
-
return { ...s, selected: false }
|
|
129
|
-
})
|
|
129
|
+
this.setSelectedShape(null)
|
|
130
130
|
|
|
131
|
-
if (this.currentMode === '
|
|
132
|
-
this.startPanning(event)
|
|
133
|
-
} else if (this.currentMode === 'draw') {
|
|
131
|
+
if (this.currentMode === 'shape') {
|
|
134
132
|
this.startDrawing(event)
|
|
133
|
+
} else {
|
|
134
|
+
this.startPanning(event)
|
|
135
135
|
}
|
|
136
136
|
} else if (event.touches.length === 2) {
|
|
137
137
|
this.startPinchZooming(event)
|
|
@@ -160,20 +160,24 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
if ('touches' in event) {
|
|
163
|
-
this.svg.addEventListener('touchmove', this.
|
|
164
|
-
this.svg.addEventListener('touchend', this.
|
|
163
|
+
this.svg.addEventListener('touchmove', this.onMouseMoveForDrawing)
|
|
164
|
+
this.svg.addEventListener('touchend', this.onMouseUpForDrawing)
|
|
165
165
|
} else {
|
|
166
|
-
this.svg.addEventListener('mousemove', this.
|
|
167
|
-
this.svg.addEventListener('mouseup', this.
|
|
166
|
+
this.svg.addEventListener('mousemove', this.onMouseMoveForDrawing)
|
|
167
|
+
this.svg.addEventListener('mouseup', this.onMouseUpForDrawing)
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
private setMode(mode: ImageMarkerMode, shapeType: ShapeType) {
|
|
172
|
+
if (mode == 'view') {
|
|
173
|
+
this.setSelectedShape(null)
|
|
174
|
+
}
|
|
175
|
+
|
|
172
176
|
this.currentMode = mode
|
|
173
177
|
this.currentShapeType = shapeType
|
|
174
178
|
}
|
|
175
179
|
|
|
176
|
-
private
|
|
180
|
+
private onMouseMoveForDrawing = (event: MouseEvent | TouchEvent) => {
|
|
177
181
|
if (!this.drawing) {
|
|
178
182
|
return
|
|
179
183
|
}
|
|
@@ -243,8 +247,8 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
243
247
|
return
|
|
244
248
|
}
|
|
245
249
|
|
|
246
|
-
this.selectedShape = newShape
|
|
247
250
|
this.shapes = [...this.shapes, newShape]
|
|
251
|
+
this.setSelectedShape(newShape)
|
|
248
252
|
}
|
|
249
253
|
|
|
250
254
|
if (this.selectedShape) {
|
|
@@ -278,7 +282,7 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
278
282
|
}
|
|
279
283
|
}
|
|
280
284
|
|
|
281
|
-
private
|
|
285
|
+
private onMouseUpForDrawing = (event: MouseEvent | TouchEvent) => {
|
|
282
286
|
event.preventDefault()
|
|
283
287
|
|
|
284
288
|
this.drawing = false
|
|
@@ -286,20 +290,30 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
286
290
|
const svg = this.svg as SVGSVGElement
|
|
287
291
|
|
|
288
292
|
if ('touches' in event) {
|
|
289
|
-
svg.removeEventListener('touchmove', this.
|
|
290
|
-
svg.removeEventListener('touchend', this.
|
|
293
|
+
svg.removeEventListener('touchmove', this.onMouseMoveForDrawing)
|
|
294
|
+
svg.removeEventListener('touchend', this.onMouseUpForDrawing)
|
|
291
295
|
} else {
|
|
292
|
-
svg.removeEventListener('mousemove', this.
|
|
293
|
-
svg.removeEventListener('mouseup', this.
|
|
296
|
+
svg.removeEventListener('mousemove', this.onMouseMoveForDrawing)
|
|
297
|
+
svg.removeEventListener('mouseup', this.onMouseUpForDrawing)
|
|
294
298
|
}
|
|
295
299
|
|
|
296
|
-
|
|
297
|
-
this.selectedShape.selected = true
|
|
298
|
-
}
|
|
300
|
+
this.imageMarkerMode.setMode('edit')
|
|
299
301
|
|
|
300
302
|
this.requestUpdate()
|
|
301
303
|
}
|
|
302
304
|
|
|
305
|
+
private setSelectedShape(shape: Shape | null) {
|
|
306
|
+
this.selectedShape = shape
|
|
307
|
+
|
|
308
|
+
if (!shape) {
|
|
309
|
+
this.shapes = this.shapes.map(s => {
|
|
310
|
+
return { ...s, selected: false }
|
|
311
|
+
})
|
|
312
|
+
} else {
|
|
313
|
+
this.selectedShape!.selected = true
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
303
317
|
private getSvgPoint(event: MouseEvent | TouchEvent) {
|
|
304
318
|
const { x, y } = this.getPointFromEvent(event)
|
|
305
319
|
|
|
@@ -328,8 +342,8 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
328
342
|
y="${shape.y!}"
|
|
329
343
|
fill="${commonAttrs.stroke}"
|
|
330
344
|
style="cursor: ${commonAttrs.cursor}; font-size: 16px;"
|
|
331
|
-
@mousedown="${(e: MouseEvent) => this.
|
|
332
|
-
@touchstart="${(e: TouchEvent) => this.
|
|
345
|
+
@mousedown="${(e: MouseEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
346
|
+
@touchstart="${(e: TouchEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
333
347
|
@dblclick="${(e: MouseEvent) => this.onTextDoubleClick(e, shape)}"
|
|
334
348
|
>${shape.text}</text>
|
|
335
349
|
`
|
|
@@ -345,8 +359,8 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
345
359
|
stroke-width="${commonAttrs['stroke-width']}"
|
|
346
360
|
fill="${commonAttrs.fill}"
|
|
347
361
|
style="cursor: ${commonAttrs.cursor}"
|
|
348
|
-
@mousedown="${(e: MouseEvent) => this.
|
|
349
|
-
@touchstart="${(e: TouchEvent) => this.
|
|
362
|
+
@mousedown="${(e: MouseEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
363
|
+
@touchstart="${(e: TouchEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
350
364
|
></rect>
|
|
351
365
|
${shape.selected ? this.renderResizeHandles(shape) : ''}
|
|
352
366
|
`
|
|
@@ -361,8 +375,8 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
361
375
|
stroke-width="${commonAttrs['stroke-width']}"
|
|
362
376
|
fill="${commonAttrs.fill}"
|
|
363
377
|
style="cursor: ${commonAttrs.cursor}"
|
|
364
|
-
@mousedown="${(e: MouseEvent) => this.
|
|
365
|
-
@touchstart="${(e: TouchEvent) => this.
|
|
378
|
+
@mousedown="${(e: MouseEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
379
|
+
@touchstart="${(e: TouchEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
366
380
|
></circle>
|
|
367
381
|
${shape.selected ? this.renderResizeHandles(shape) : ''}
|
|
368
382
|
`
|
|
@@ -375,8 +389,8 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
375
389
|
stroke-width="${commonAttrs['stroke-width']}"
|
|
376
390
|
fill="${commonAttrs.fill}"
|
|
377
391
|
style="cursor: ${commonAttrs.cursor}"
|
|
378
|
-
@mousedown="${(e: MouseEvent) => this.
|
|
379
|
-
@touchstart="${(e: TouchEvent) => this.
|
|
392
|
+
@mousedown="${(e: MouseEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
393
|
+
@touchstart="${(e: TouchEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
380
394
|
></polygon>
|
|
381
395
|
${shape.selected ? this.renderResizeHandles(shape) : ''}
|
|
382
396
|
`
|
|
@@ -391,8 +405,20 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
391
405
|
stroke="${commonAttrs.stroke}"
|
|
392
406
|
stroke-width="${commonAttrs['stroke-width']}"
|
|
393
407
|
style="cursor: ${commonAttrs.cursor}"
|
|
394
|
-
|
|
395
|
-
|
|
408
|
+
></line>
|
|
409
|
+
<line
|
|
410
|
+
x1="${shape.x1!}"
|
|
411
|
+
y1="${shape.y1!}"
|
|
412
|
+
x2="${shape.x2 ?? shape.x1}"
|
|
413
|
+
y2="${shape.y2 ?? shape.y1}"
|
|
414
|
+
stroke="${commonAttrs.stroke}"
|
|
415
|
+
stroke-width="25"
|
|
416
|
+
stroke-opacity="0"
|
|
417
|
+
pointer-events="stroke"
|
|
418
|
+
@mousedown="${(e: MouseEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
419
|
+
@touchstart="${(e: TouchEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
420
|
+
@mouseenter="${() => (this.svg.style.cursor = 'pointer')}"
|
|
421
|
+
@mouseleave="${() => (this.svg.style.cursor = 'default')}"
|
|
396
422
|
></line>
|
|
397
423
|
${shape.selected ? this.renderResizeHandles(shape) : ''}
|
|
398
424
|
`
|
|
@@ -413,8 +439,20 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
413
439
|
stroke-width="${commonAttrs['stroke-width']}"
|
|
414
440
|
marker-end="url(#arrowhead-${shape.id})"
|
|
415
441
|
style="cursor: ${commonAttrs.cursor}"
|
|
416
|
-
|
|
417
|
-
|
|
442
|
+
></line>
|
|
443
|
+
<line
|
|
444
|
+
x1="${shape.x1!}"
|
|
445
|
+
y1="${shape.y1!}"
|
|
446
|
+
x2="${shape.x2 ?? shape.x1}"
|
|
447
|
+
y2="${shape.y2 ?? shape.y1}"
|
|
448
|
+
stroke="${commonAttrs.stroke}"
|
|
449
|
+
stroke-width="25"
|
|
450
|
+
stroke-opacity="0"
|
|
451
|
+
pointer-events="stroke"
|
|
452
|
+
@mousedown="${(e: MouseEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
453
|
+
@touchstart="${(e: TouchEvent) => this.onMouseDownOnShape(e, shape)}"
|
|
454
|
+
@mouseenter="${() => (this.svg.style.cursor = 'pointer')}"
|
|
455
|
+
@mouseleave="${() => (this.svg.style.cursor = 'default')}"
|
|
418
456
|
></line>
|
|
419
457
|
${shape.selected ? this.renderResizeHandles(shape) : ''}
|
|
420
458
|
`
|
|
@@ -424,7 +462,15 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
424
462
|
}
|
|
425
463
|
}
|
|
426
464
|
|
|
427
|
-
private
|
|
465
|
+
private onMouseDownOnShape(event: MouseEvent | TouchEvent, shape: Shape) {
|
|
466
|
+
if (this.currentMode !== 'edit') {
|
|
467
|
+
return
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if ('touches' in event && event.touches.length > 1) {
|
|
471
|
+
return
|
|
472
|
+
}
|
|
473
|
+
|
|
428
474
|
event.stopPropagation()
|
|
429
475
|
event.preventDefault()
|
|
430
476
|
|
|
@@ -433,99 +479,100 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
433
479
|
selected: s.id === shape.id
|
|
434
480
|
}))
|
|
435
481
|
|
|
436
|
-
this.
|
|
482
|
+
this.shapeMoveInitiated = false
|
|
483
|
+
this.setSelectedShape(this.shapes.find(s => s.id == shape.id)!)
|
|
437
484
|
|
|
438
485
|
const { x, y } = this.getSvgPoint(event)
|
|
439
486
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
case 'rectangle':
|
|
443
|
-
case 'circle':
|
|
444
|
-
this.offsetX = x - (shape.x || shape.cx || 0)
|
|
445
|
-
this.offsetY = y - (shape.y || shape.cy || 0)
|
|
446
|
-
break
|
|
447
|
-
|
|
448
|
-
case 'triangle':
|
|
449
|
-
const points = this.selectedShape.points!.split(' ').map(p => p.split(',').map(Number))
|
|
450
|
-
const [px, py] = points[0] || [0, 0]
|
|
451
|
-
|
|
452
|
-
this.offsetX = x - px
|
|
453
|
-
this.offsetY = y - py
|
|
454
|
-
|
|
455
|
-
break
|
|
456
|
-
|
|
457
|
-
case 'line':
|
|
458
|
-
case 'arrow':
|
|
459
|
-
this.offsetX = x - shape.x1!
|
|
460
|
-
this.offsetY = y - shape.y1!
|
|
461
|
-
break
|
|
462
|
-
}
|
|
487
|
+
this.offsetX = x
|
|
488
|
+
this.offsetY = y
|
|
463
489
|
|
|
464
490
|
const svg = this.svg as SVGSVGElement
|
|
465
491
|
|
|
466
492
|
if ('touches' in event) {
|
|
467
|
-
svg.addEventListener('touchmove', this.
|
|
468
|
-
svg.addEventListener('touchend', this.
|
|
493
|
+
svg.addEventListener('touchmove', this.onMouseMoveOnShape)
|
|
494
|
+
svg.addEventListener('touchend', this.onMouseUpOnShape)
|
|
469
495
|
} else {
|
|
470
|
-
svg.addEventListener('mousemove', this.
|
|
471
|
-
svg.addEventListener('mouseup', this.
|
|
496
|
+
svg.addEventListener('mousemove', this.onMouseMoveOnShape)
|
|
497
|
+
svg.addEventListener('mouseup', this.onMouseUpOnShape)
|
|
472
498
|
}
|
|
473
499
|
}
|
|
474
500
|
|
|
475
|
-
private
|
|
501
|
+
private onMouseMoveOnShape = (event: MouseEvent | TouchEvent) => {
|
|
476
502
|
if (!this.selectedShape) {
|
|
477
503
|
return
|
|
478
504
|
}
|
|
479
505
|
|
|
506
|
+
if ('touches' in event && event.touches.length > 1) {
|
|
507
|
+
return
|
|
508
|
+
}
|
|
509
|
+
|
|
480
510
|
event.preventDefault()
|
|
481
511
|
|
|
482
512
|
const { x, y } = this.getSvgPoint(event)
|
|
483
513
|
|
|
514
|
+
const dx = x - this.offsetX
|
|
515
|
+
const dy = y - this.offsetY
|
|
516
|
+
|
|
517
|
+
if (!this.shapeMoveInitiated) {
|
|
518
|
+
const distance = Math.sqrt(dx * dx + dy * dy)
|
|
519
|
+
|
|
520
|
+
if (distance < this.shapeMoveThreshold) {
|
|
521
|
+
return
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
this.shapeMoveInitiated = true
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
this.offsetX = x
|
|
528
|
+
this.offsetY = y
|
|
529
|
+
|
|
484
530
|
switch (this.selectedShape.type) {
|
|
485
531
|
case 'text':
|
|
486
532
|
case 'rectangle':
|
|
487
|
-
this.selectedShape.x
|
|
488
|
-
this.selectedShape.y
|
|
533
|
+
this.selectedShape.x! += dx
|
|
534
|
+
this.selectedShape.y! += dy
|
|
489
535
|
break
|
|
490
536
|
case 'circle':
|
|
491
|
-
this.selectedShape.cx
|
|
492
|
-
this.selectedShape.cy
|
|
537
|
+
this.selectedShape.cx! += dx
|
|
538
|
+
this.selectedShape.cy! += dy
|
|
493
539
|
break
|
|
494
540
|
case 'triangle':
|
|
495
541
|
const points = this.selectedShape.points!.split(' ').map(p => p.split(',').map(Number))
|
|
496
|
-
const [ox, oy] = points[0]
|
|
497
542
|
|
|
498
|
-
this.selectedShape.points = points
|
|
499
|
-
.map(([px, py]) => [px - ox + x - this.offsetX, py - oy + y - this.offsetY].join(','))
|
|
500
|
-
.join(' ')
|
|
543
|
+
this.selectedShape.points = points.map(([px, py]) => [px + dx, py + dy].join(',')).join(' ')
|
|
501
544
|
break
|
|
502
545
|
case 'line':
|
|
503
546
|
case 'arrow':
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
this.selectedShape.x1 = dxLine
|
|
509
|
-
this.selectedShape.y1 = dyLine
|
|
510
|
-
this.selectedShape.x2 = this.selectedShape.x2! + deltaX
|
|
511
|
-
this.selectedShape.y2 = this.selectedShape.y2! + deltaY
|
|
547
|
+
this.selectedShape.x1! += dx
|
|
548
|
+
this.selectedShape.x2! += dx
|
|
549
|
+
this.selectedShape.y1! += dy
|
|
550
|
+
this.selectedShape.y2! += dy
|
|
512
551
|
break
|
|
513
552
|
}
|
|
514
553
|
|
|
515
554
|
this.requestUpdate()
|
|
516
555
|
}
|
|
517
556
|
|
|
518
|
-
private
|
|
557
|
+
private onMouseUpOnShape = (event: MouseEvent | TouchEvent) => {
|
|
558
|
+
if (!this.selectedShape) {
|
|
559
|
+
return
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if ('touches' in event && event.touches.length > 1) {
|
|
563
|
+
return
|
|
564
|
+
}
|
|
565
|
+
|
|
519
566
|
event.preventDefault()
|
|
520
567
|
|
|
521
568
|
const svg = this.svg as SVGSVGElement
|
|
522
569
|
|
|
523
570
|
if ('touches' in event) {
|
|
524
|
-
svg.removeEventListener('touchmove', this.
|
|
525
|
-
svg.removeEventListener('touchend', this.
|
|
571
|
+
svg.removeEventListener('touchmove', this.onMouseMoveOnShape)
|
|
572
|
+
svg.removeEventListener('touchend', this.onMouseUpOnShape)
|
|
526
573
|
} else {
|
|
527
|
-
svg.removeEventListener('mousemove', this.
|
|
528
|
-
svg.removeEventListener('mouseup', this.
|
|
574
|
+
svg.removeEventListener('mousemove', this.onMouseMoveOnShape)
|
|
575
|
+
svg.removeEventListener('mouseup', this.onMouseUpOnShape)
|
|
529
576
|
}
|
|
530
577
|
}
|
|
531
578
|
|
|
@@ -579,8 +626,8 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
579
626
|
stroke="black"
|
|
580
627
|
class="resize-handle"
|
|
581
628
|
style="cursor: ${handle.cursor};"
|
|
582
|
-
@mousedown="${(e: MouseEvent) => this.
|
|
583
|
-
@touchstart="${(e: TouchEvent) => this.
|
|
629
|
+
@mousedown="${(e: MouseEvent) => this.onResizeHandleMouseDown(e, shape, handle)}"
|
|
630
|
+
@touchstart="${(e: TouchEvent) => this.onResizeHandleMouseDown(e, shape, handle)}"
|
|
584
631
|
></rect>
|
|
585
632
|
</g>
|
|
586
633
|
`
|
|
@@ -588,25 +635,26 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
588
635
|
`
|
|
589
636
|
}
|
|
590
637
|
|
|
591
|
-
private
|
|
638
|
+
private onResizeHandleMouseDown(event: MouseEvent | TouchEvent, shape: Shape, handle: any) {
|
|
592
639
|
event.stopPropagation()
|
|
593
640
|
event.preventDefault()
|
|
594
641
|
|
|
595
|
-
this.
|
|
642
|
+
this.setSelectedShape(shape)
|
|
643
|
+
|
|
596
644
|
this.offsetX = handle.x
|
|
597
645
|
this.offsetY = handle.y
|
|
598
646
|
const svg = this.svg as SVGSVGElement
|
|
599
647
|
|
|
600
648
|
if ('touches' in event) {
|
|
601
|
-
svg.addEventListener('touchmove', this.
|
|
602
|
-
svg.addEventListener('touchend', this.
|
|
649
|
+
svg.addEventListener('touchmove', this.onResizeHandleMouseMove)
|
|
650
|
+
svg.addEventListener('touchend', this.onResizeHandleMouseUp)
|
|
603
651
|
} else {
|
|
604
|
-
svg.addEventListener('mousemove', this.
|
|
605
|
-
svg.addEventListener('mouseup', this.
|
|
652
|
+
svg.addEventListener('mousemove', this.onResizeHandleMouseMove)
|
|
653
|
+
svg.addEventListener('mouseup', this.onResizeHandleMouseUp)
|
|
606
654
|
}
|
|
607
655
|
}
|
|
608
656
|
|
|
609
|
-
private
|
|
657
|
+
private onResizeHandleMouseMove = (event: MouseEvent | TouchEvent) => {
|
|
610
658
|
if (!this.selectedShape) {
|
|
611
659
|
return
|
|
612
660
|
}
|
|
@@ -616,12 +664,6 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
616
664
|
const { x, y } = this.getSvgPoint(event)
|
|
617
665
|
|
|
618
666
|
switch (this.selectedShape.type) {
|
|
619
|
-
// case 'text':
|
|
620
|
-
// this.selectedShape.width = Math.abs(x - this.selectedShape.x!)
|
|
621
|
-
// this.selectedShape.height = Math.abs(y - this.selectedShape.y!)
|
|
622
|
-
// if (x < this.selectedShape.x!) this.selectedShape.x = x
|
|
623
|
-
// if (y < this.selectedShape.y!) this.selectedShape.y = y
|
|
624
|
-
// break
|
|
625
667
|
case 'rectangle':
|
|
626
668
|
const startX = this.selectedShape.x!
|
|
627
669
|
const startY = this.selectedShape.y!
|
|
@@ -691,20 +733,18 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
691
733
|
this.requestUpdate()
|
|
692
734
|
}
|
|
693
735
|
|
|
694
|
-
private
|
|
736
|
+
private onResizeHandleMouseUp = (event: MouseEvent | TouchEvent) => {
|
|
695
737
|
event.preventDefault()
|
|
696
738
|
|
|
697
739
|
const svg = this.svg as SVGSVGElement
|
|
698
740
|
|
|
699
741
|
if ('touches' in event) {
|
|
700
|
-
svg.removeEventListener('touchmove', this.
|
|
701
|
-
svg.removeEventListener('touchend', this.
|
|
742
|
+
svg.removeEventListener('touchmove', this.onResizeHandleMouseMove)
|
|
743
|
+
svg.removeEventListener('touchend', this.onResizeHandleMouseUp)
|
|
702
744
|
} else {
|
|
703
|
-
svg.removeEventListener('mousemove', this.
|
|
704
|
-
svg.removeEventListener('mouseup', this.
|
|
745
|
+
svg.removeEventListener('mousemove', this.onResizeHandleMouseMove)
|
|
746
|
+
svg.removeEventListener('mouseup', this.onResizeHandleMouseUp)
|
|
705
747
|
}
|
|
706
|
-
|
|
707
|
-
this.selectedShape = null
|
|
708
748
|
}
|
|
709
749
|
|
|
710
750
|
private onTextDoubleClick(event: MouseEvent, shape: Shape) {
|
|
@@ -849,7 +889,9 @@ export class OxImageMarker extends BaseImageMarker {
|
|
|
849
889
|
private deleteSelectedShape() {
|
|
850
890
|
if (this.selectedShape) {
|
|
851
891
|
this.shapes = this.shapes.filter(s => s.id !== this.selectedShape!.id)
|
|
852
|
-
|
|
892
|
+
|
|
893
|
+
this.setSelectedShape(null)
|
|
894
|
+
|
|
853
895
|
this.requestUpdate()
|
|
854
896
|
}
|
|
855
897
|
}
|
package/src/types.ts
CHANGED