@operato/image-marker 8.0.0-alpha.18 → 8.0.0-alpha.23

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,9 @@ 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
41
+ private lastTouchEnd: number = 0
39
42
 
40
43
  @query('svg') protected svg!: SVGSVGElement
41
44
 
@@ -50,7 +53,7 @@ export class BaseImageMarker extends LitElement {
50
53
  img.src = this.imageUrl
51
54
  }
52
55
 
53
- protected onWheel(event: WheelEvent) {
56
+ protected onSvgWheel(event: WheelEvent) {
54
57
  event.preventDefault()
55
58
 
56
59
  const { offsetX, offsetY, deltaY } = event
@@ -71,21 +74,126 @@ export class BaseImageMarker extends LitElement {
71
74
  }
72
75
 
73
76
  protected onSvgMouseDown(event: MouseEvent) {
74
- const svg = this.svg
77
+ event.preventDefault()
78
+
79
+ this.startPanning(event)
80
+
81
+ this.svg.addEventListener('mousemove', this.onPanMouseMove)
82
+ this.svg.addEventListener('mouseup', this.onPanMouseUp)
83
+ }
84
+
85
+ protected isDoubleTouch(event: TouchEvent) {
86
+ const currentTime = new Date().getTime()
87
+ const tapLength = currentTime - this.lastTouchEnd
88
+
89
+ const result = tapLength < 300 && event.touches.length == 1
90
+ this.lastTouchEnd = currentTime
91
+
92
+ return result
93
+ }
94
+
95
+ protected onSvgTouchStart = (event: TouchEvent) => {
96
+ event.preventDefault()
97
+
98
+ if (this.isDoubleTouch(event)) {
99
+ this.resetZoom()
100
+ }
101
+
102
+ if (event.touches.length === 1) {
103
+ this.startPanning(event)
104
+ } else if (event.touches.length === 2) {
105
+ this.startPinchZooming(event)
106
+ }
107
+ }
108
+
109
+ protected startPinchZooming(event: TouchEvent) {
110
+ const touch1 = event.touches[0]
111
+ const touch2 = event.touches[1]
112
+
113
+ const dx = touch2.clientX - touch1.clientX
114
+ const dy = touch2.clientY - touch1.clientY
115
+
116
+ this.initialPinchDistance = Math.sqrt(dx * dx + dy * dy)
117
+ this.initialZoomLevel = this.zoomLevel
118
+
119
+ this.svg.addEventListener('touchmove', this.onZoomTouchMove)
120
+ this.svg.addEventListener('touchend', this.onZoomTouchEnd)
121
+ }
122
+
123
+ protected onZoomTouchMove = (event: TouchEvent) => {
124
+ event.preventDefault()
125
+
126
+ if (event.touches.length === 2 && this.initialPinchDistance) {
127
+ const touch1 = event.touches[0]
128
+ const touch2 = event.touches[1]
129
+ const dx = touch2.clientX - touch1.clientX
130
+ const dy = touch2.clientY - touch1.clientY
131
+ const currentPinchDistance = Math.sqrt(dx * dx + dy * dy)
132
+
133
+ const scaleFactor = currentPinchDistance / this.initialPinchDistance
134
+ this.zoomLevel = this.initialZoomLevel * scaleFactor
135
+
136
+ this.applyZoom()
137
+ }
138
+ }
139
+
140
+ protected onZoomTouchEnd = (event: TouchEvent) => {
141
+ event.preventDefault()
142
+
143
+ if (event.touches.length < 2) {
144
+ this.initialPinchDistance = null
145
+ }
146
+
147
+ this.svg.removeEventListener('touchmove', this.onZoomTouchMove)
148
+ this.svg.removeEventListener('touchend', this.onZoomTouchEnd)
149
+ }
150
+
151
+ protected applyZoom() {
152
+ const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)
153
+ const initialViewBoxNumbers = this.initialViewBox.split(' ').map(Number)
154
+ const newVbWidth = initialViewBoxNumbers[2] / this.zoomLevel
155
+ const newVbHeight = initialViewBoxNumbers[3] / this.zoomLevel
156
+ const newVbX = vbX + (vbWidth - newVbWidth) / 2
157
+ const newVbY = vbY + (vbHeight - newVbHeight) / 2
158
+
159
+ this.viewBox = `${newVbX} ${newVbY} ${newVbWidth} ${newVbHeight}`
160
+ }
161
+
162
+ protected onSvgDoubleClick() {
163
+ this.resetZoom()
164
+ }
165
+
166
+ protected resetZoom() {
167
+ this.viewBox = this.initialViewBox
168
+ this.zoomLevel = 1
169
+ }
170
+
171
+ protected startPanning(event: MouseEvent | TouchEvent) {
172
+ const { x, y } = this.getPointFromEvent(event)
75
173
 
76
174
  this.isPanning = true
77
- this.panStart = { x: event.clientX, y: event.clientY }
78
- svg.classList.add('dragging')
175
+ this.panStart = { x, y }
176
+ this.svg.classList.add('dragging')
79
177
 
80
- svg.addEventListener('mousemove', this.onPanMouseMove)
81
- svg.addEventListener('mouseup', this.onPanMouseUp)
178
+ if ('touches' in event) {
179
+ this.svg.addEventListener('touchmove', this.onPanMouseMove)
180
+ this.svg.addEventListener('touchend', this.onPanMouseUp)
181
+ } else {
182
+ this.svg.addEventListener('mousemove', this.onPanMouseMove)
183
+ this.svg.addEventListener('mouseup', this.onPanMouseUp)
184
+ }
82
185
  }
83
186
 
84
- protected onPanMouseMove = (event: MouseEvent) => {
85
- if (!this.isPanning) return
187
+ protected onPanMouseMove = (event: MouseEvent | TouchEvent) => {
188
+ if (!this.isPanning) {
189
+ return
190
+ }
191
+ event.preventDefault()
192
+
193
+ const { x, y } = this.getPointFromEvent(event)
86
194
 
87
- const dx = event.clientX - this.panStart.x
88
- const dy = event.clientY - this.panStart.y
195
+ const dx = x - this.panStart.x
196
+ const dy = y - this.panStart.y
89
197
 
90
198
  const [vbX, vbY, vbWidth, vbHeight] = this.viewBox.split(' ').map(Number)
91
199
  const scaleX = vbWidth / this.svg.clientWidth
@@ -96,21 +204,24 @@ export class BaseImageMarker extends LitElement {
96
204
  const newVbY = vbY - dy * scale
97
205
 
98
206
  this.viewBox = `${newVbX} ${newVbY} ${vbWidth} ${vbHeight}`
99
- this.panStart = { x: event.clientX, y: event.clientY }
207
+ this.panStart = { x, y }
100
208
  }
101
209
 
102
- protected onPanMouseUp = () => {
210
+ protected onPanMouseUp = (event: MouseEvent | TouchEvent) => {
211
+ event.preventDefault()
212
+
103
213
  const svg = this.svg
104
214
 
105
215
  this.isPanning = false
106
216
  svg.classList.remove('dragging')
107
- svg.removeEventListener('mousemove', this.onPanMouseMove)
108
- svg.removeEventListener('mouseup', this.onPanMouseUp)
109
- }
110
217
 
111
- protected onDoubleClick() {
112
- this.viewBox = this.initialViewBox
113
- this.zoomLevel = 1
218
+ if ('touches' in event) {
219
+ svg.removeEventListener('touchmove', this.onPanMouseMove)
220
+ svg.removeEventListener('touchend', this.onPanMouseUp)
221
+ } else {
222
+ svg.removeEventListener('mousemove', this.onPanMouseMove)
223
+ svg.removeEventListener('mouseup', this.onPanMouseUp)
224
+ }
114
225
  }
115
226
 
116
227
  protected renderShape(shape: Shape) {
@@ -141,4 +252,18 @@ export class BaseImageMarker extends LitElement {
141
252
  return nothing
142
253
  }
143
254
  }
255
+
256
+ protected getPointFromEvent(event: MouseEvent | TouchEvent) {
257
+ if ('touches' in event) {
258
+ return {
259
+ x: event.touches[0].clientX,
260
+ y: event.touches[0].clientY
261
+ }
262
+ } else {
263
+ return {
264
+ x: event.clientX,
265
+ y: event.clientY
266
+ }
267
+ }
268
+ }
144
269
  }
@@ -94,6 +94,10 @@ export class OxImageMarkerMode extends LitElement {
94
94
  >
95
95
  </div>
96
96
 
97
+ <div class="palette">
98
+ <md-icon title="Fit size" @click=${() => this.onClickFitSize()}>recenter</md-icon>
99
+ </div>
100
+
97
101
  <div class="palette">
98
102
  <md-icon title="Delete" @click=${() => this.onClickDelete()}>delete</md-icon>
99
103
  <md-icon title="Save" @click=${() => this.onClickSave()}>save</md-icon>
@@ -127,7 +131,7 @@ export class OxImageMarkerMode extends LitElement {
127
131
 
128
132
  private onClickDelete() {
129
133
  this.dispatchEvent(
130
- new CustomEvent('clicked-delete', {
134
+ new CustomEvent('tap-delete', {
131
135
  bubbles: true,
132
136
  composed: true
133
137
  })
@@ -136,7 +140,16 @@ export class OxImageMarkerMode extends LitElement {
136
140
 
137
141
  private onClickSave() {
138
142
  this.dispatchEvent(
139
- new CustomEvent('clicked-save', {
143
+ new CustomEvent('tap-save', {
144
+ bubbles: true,
145
+ composed: true
146
+ })
147
+ )
148
+ }
149
+
150
+ private onClickFitSize() {
151
+ this.dispatchEvent(
152
+ new CustomEvent('tap-fit-size', {
140
153
  bubbles: true,
141
154
  composed: true
142
155
  })
@@ -9,9 +9,10 @@ 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
+ @touchstart=${this.onSvgTouchStart}
15
+ @dblclick=${this.onSvgDoubleClick}
15
16
  viewBox=${this.viewBox}
16
17
  >
17
18
  <image href=${this.imageUrl} @load=${this.onImageLoad}></image>