@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.
- package/CHANGELOG.md +18 -0
- package/dist/src/base-image-marker.d.ts +19 -4
- package/dist/src/base-image-marker.js +116 -15
- package/dist/src/base-image-marker.js.map +1 -1
- package/dist/src/ox-image-marker-mode.d.ts +1 -0
- package/dist/src/ox-image-marker-mode.js +12 -2
- package/dist/src/ox-image-marker-mode.js.map +1 -1
- package/dist/src/ox-image-marker-view.js +3 -2
- package/dist/src/ox-image-marker-view.js.map +1 -1
- package/dist/src/ox-image-marker.d.ts +7 -6
- package/dist/src/ox-image-marker.js +165 -71
- package/dist/src/ox-image-marker.js.map +1 -1
- package/dist/stories/ox-image-marker.stories.js +16 -0
- package/dist/stories/ox-image-marker.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/base-image-marker.ts +143 -18
- package/src/ox-image-marker-mode.ts +15 -2
- package/src/ox-image-marker-view.ts +3 -2
- package/src/ox-image-marker.ts +193 -80
- package/stories/ox-image-marker.stories.ts +16 -0
package/src/base-image-marker.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
78
|
-
svg.classList.add('dragging')
|
|
175
|
+
this.panStart = { x, y }
|
|
176
|
+
this.svg.classList.add('dragging')
|
|
79
177
|
|
|
80
|
-
|
|
81
|
-
|
|
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)
|
|
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 =
|
|
88
|
-
const dy =
|
|
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
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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('
|
|
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('
|
|
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.
|
|
12
|
+
@wheel=${this.onSvgWheel}
|
|
13
13
|
@mousedown=${this.onSvgMouseDown}
|
|
14
|
-
@
|
|
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>
|