@operato/image-marker 8.0.0-alpha.17 → 8.0.0-alpha.22

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.
@@ -36,6 +36,8 @@ export class BaseImageMarker extends LitElement {
36
36
  protected isPanning = false
37
37
  protected panStart = { x: 0, y: 0 }
38
38
  protected initialViewBox = '0 0 800 600'
39
+ private initialPinchDistance: number | null = null
40
+ private initialZoomLevel: number = 1
39
41
 
40
42
  @query('svg') protected svg!: SVGSVGElement
41
43
 
@@ -50,7 +52,7 @@ export class BaseImageMarker extends LitElement {
50
52
  img.src = this.imageUrl
51
53
  }
52
54
 
53
- protected onWheel(event: WheelEvent) {
55
+ protected onSvgWheel(event: WheelEvent) {
54
56
  event.preventDefault()
55
57
 
56
58
  const { offsetX, offsetY, deltaY } = event
@@ -71,21 +73,99 @@ export class BaseImageMarker extends LitElement {
71
73
  }
72
74
 
73
75
  protected onSvgMouseDown(event: MouseEvent) {
74
- const svg = this.svg
76
+ this.startPanning(event)
75
77
 
76
- this.isPanning = true
77
- this.panStart = { x: event.clientX, y: event.clientY }
78
- svg.classList.add('dragging')
78
+ this.svg.addEventListener('mousemove', this.onPanMouseMove)
79
+ this.svg.addEventListener('mouseup', this.onPanMouseUp)
80
+ }
81
+
82
+ protected onSvgTouchStart = (event: TouchEvent) => {
83
+ if (event.touches.length === 1) {
84
+ this.startPanning(event)
85
+ } else if (event.touches.length === 2) {
86
+ this.startPinchZooming(event)
87
+ }
88
+ }
89
+
90
+ protected startPinchZooming(event: TouchEvent) {
91
+ const touch1 = event.touches[0]
92
+ const touch2 = event.touches[1]
93
+
94
+ const dx = touch2.clientX - touch1.clientX
95
+ const dy = touch2.clientY - touch1.clientY
96
+
97
+ this.initialPinchDistance = Math.sqrt(dx * dx + dy * dy)
98
+ this.initialZoomLevel = this.zoomLevel
99
+
100
+ this.svg.addEventListener('touchmove', this.onZoomTouchMove)
101
+ this.svg.addEventListener('touchend', this.onZoomTouchEnd)
102
+ }
79
103
 
80
- svg.addEventListener('mousemove', this.onPanMouseMove)
81
- svg.addEventListener('mouseup', this.onPanMouseUp)
104
+ protected onZoomTouchMove = (event: TouchEvent) => {
105
+ if (event.touches.length === 2 && this.initialPinchDistance) {
106
+ const touch1 = event.touches[0]
107
+ const touch2 = event.touches[1]
108
+ const dx = touch2.clientX - touch1.clientX
109
+ const dy = touch2.clientY - touch1.clientY
110
+ const currentPinchDistance = Math.sqrt(dx * dx + dy * dy)
111
+
112
+ const scaleFactor = currentPinchDistance / this.initialPinchDistance
113
+ this.zoomLevel = this.initialZoomLevel * scaleFactor
114
+
115
+ this.applyZoom()
116
+ }
82
117
  }
83
118
 
84
- protected onPanMouseMove = (event: MouseEvent) => {
85
- if (!this.isPanning) return
119
+ protected onZoomTouchEnd = (event: TouchEvent) => {
120
+ if (event.touches.length < 2) {
121
+ this.initialPinchDistance = null
122
+ }
86
123
 
87
- const dx = event.clientX - this.panStart.x
88
- const dy = event.clientY - this.panStart.y
124
+ this.svg.removeEventListener('touchmove', this.onZoomTouchMove)
125
+ this.svg.removeEventListener('touchend', this.onZoomTouchEnd)
126
+ }
127
+
128
+ protected applyZoom() {
129
+ const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)
130
+ const initialViewBoxNumbers = this.initialViewBox.split(' ').map(Number)
131
+ const newVbWidth = initialViewBoxNumbers[2] / this.zoomLevel
132
+ const newVbHeight = initialViewBoxNumbers[3] / this.zoomLevel
133
+ const newVbX = vbX + (vbWidth - newVbWidth) / 2
134
+ const newVbY = vbY + (vbHeight - newVbHeight) / 2
135
+
136
+ this.viewBox = `${newVbX} ${newVbY} ${newVbWidth} ${newVbHeight}`
137
+ }
138
+
139
+ protected onSvgDoubleClick() {
140
+ this.viewBox = this.initialViewBox
141
+ this.zoomLevel = 1
142
+ }
143
+
144
+ protected startPanning(event: MouseEvent | TouchEvent) {
145
+ const { x, y } = this.getPointFromEvent(event)
146
+
147
+ this.isPanning = true
148
+ this.panStart = { x, y }
149
+ this.svg.classList.add('dragging')
150
+
151
+ if ('touches' in event) {
152
+ this.svg.addEventListener('touchmove', this.onPanMouseMove)
153
+ this.svg.addEventListener('touchend', this.onPanMouseUp)
154
+ } else {
155
+ this.svg.addEventListener('mousemove', this.onPanMouseMove)
156
+ this.svg.addEventListener('mouseup', this.onPanMouseUp)
157
+ }
158
+ }
159
+
160
+ protected onPanMouseMove = (event: MouseEvent | TouchEvent) => {
161
+ if (!this.isPanning) {
162
+ return
163
+ }
164
+
165
+ const { x, y } = this.getPointFromEvent(event)
166
+
167
+ const dx = x - this.panStart.x
168
+ const dy = y - this.panStart.y
89
169
 
90
170
  const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)
91
171
  const scaleX = vbWidth / this.svg.clientWidth
@@ -96,21 +176,22 @@ export class BaseImageMarker extends LitElement {
96
176
  const newVbY = vbY - dy * scale
97
177
 
98
178
  this.viewBox = `${newVbX} ${newVbY} ${vbWidth} ${vbHeight}`
99
- this.panStart = { x: event.clientX, y: event.clientY }
179
+ this.panStart = { x, y }
100
180
  }
101
181
 
102
- protected onPanMouseUp = () => {
182
+ protected onPanMouseUp = (event: MouseEvent | TouchEvent) => {
103
183
  const svg = this.svg
104
184
 
105
185
  this.isPanning = false
106
186
  svg.classList.remove('dragging')
107
- svg.removeEventListener('mousemove', this.onPanMouseMove)
108
- svg.removeEventListener('mouseup', this.onPanMouseUp)
109
- }
110
187
 
111
- protected onDoubleClick() {
112
- this.viewBox = this.initialViewBox
113
- this.zoomLevel = 1
188
+ if ('touches' in event) {
189
+ svg.removeEventListener('touchmove', this.onPanMouseMove)
190
+ svg.removeEventListener('touchend', this.onPanMouseUp)
191
+ } else {
192
+ svg.removeEventListener('mousemove', this.onPanMouseMove)
193
+ svg.removeEventListener('mouseup', this.onPanMouseUp)
194
+ }
114
195
  }
115
196
 
116
197
  protected renderShape(shape: Shape) {
@@ -141,4 +222,18 @@ export class BaseImageMarker extends LitElement {
141
222
  return nothing
142
223
  }
143
224
  }
225
+
226
+ protected getPointFromEvent(event: MouseEvent | TouchEvent) {
227
+ if ('touches' in event) {
228
+ return {
229
+ x: event.touches[0].clientX,
230
+ y: event.touches[0].clientY
231
+ }
232
+ } else {
233
+ return {
234
+ x: event.clientX,
235
+ y: event.clientY
236
+ }
237
+ }
238
+ }
144
239
  }
@@ -127,7 +127,7 @@ export class OxImageMarkerMode extends LitElement {
127
127
 
128
128
  private onClickDelete() {
129
129
  this.dispatchEvent(
130
- new CustomEvent('clicked-delete', {
130
+ new CustomEvent('tap-delete', {
131
131
  bubbles: true,
132
132
  composed: true
133
133
  })
@@ -136,7 +136,7 @@ export class OxImageMarkerMode extends LitElement {
136
136
 
137
137
  private onClickSave() {
138
138
  this.dispatchEvent(
139
- new CustomEvent('clicked-save', {
139
+ new CustomEvent('tap-save', {
140
140
  bubbles: true,
141
141
  composed: true
142
142
  })
@@ -9,9 +9,9 @@ export class OxImageMarkerView extends BaseImageMarker {
9
9
  return html`
10
10
  <div class="container">
11
11
  <svg
12
- @wheel=${this.onWheel}
12
+ @wheel=${this.onSvgWheel}
13
13
  @mousedown=${this.onSvgMouseDown}
14
- @dblclick=${this.onDoubleClick}
14
+ @dblclick=${this.onSvgDoubleClick}
15
15
  viewBox=${this.viewBox}
16
16
  >
17
17
  <image href=${this.imageUrl} @load=${this.onImageLoad}></image>