1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| class ZoomableImage extends HTMLElement {
constructor() {
super()
this.img = document.createElement('img')
this.appendChild(this.img)
this.currentScale = 1
this.pos = { x: 0, y: 0 }
this.start = { x: 0, y: 0 }
this.isDragging = false
}
connectedCallback() {
if (this.hasAttribute('src')) {
this.img.src = this.getAttribute('src')
}
this.classList.add('zoomable-image')
this.bindEvents()
}
bindEvents() {
this.addEventListener('wheel', e => this.onWheel(e))
this.addEventListener('mousedown', e => this.onMouseDown(e))
this.addEventListener('mousemove', e => this.onMouseMove(e))
this.addEventListener('mouseup', () => this.onMouseUp())
this.addEventListener('mouseleave', () => this.onMouseLeave())
}
onWheel(e) {
e.preventDefault()
const MIN_SCALE = 1
const MAX_SCALE = 5
const zoomSpeed = 0.0015
const oldScale = this.currentScale
this.currentScale -= e.deltaY * zoomSpeed
this.currentScale = Math.min(Math.max(this.currentScale, MIN_SCALE), MAX_SCALE)
const rect = this.getBoundingClientRect()
const dx = e.clientX - rect.left - rect.width / 2
const dy = e.clientY - rect.top - rect.height / 2
this.pos.x -= dx * (this.currentScale / oldScale - 1)
this.pos.y -= dy * (this.currentScale / oldScale - 1)
this.updateTransform()
}
onMouseDown(e) {
if (this.currentScale <= 1) return
this.isDragging = true
this.start.x = e.clientX - this.pos.x
this.start.y = e.clientY - this.pos.y
this.style.cursor = 'grabbing'
}
onMouseMove(e) {
if (!this.isDragging) return
this.pos.x = e.clientX - this.start.x
this.pos.y = e.clientY - this.start.y
this.updateTransform()
}
onMouseUp() {
this.isDragging = false
this.style.cursor = 'grab'
}
onMouseLeave() {
this.isDragging = false
this.style.cursor = 'grab'
}
updateTransform() {
if (this.currentScale === 1) {
this.pos.x = 0
this.pos.y = 0
}
this.img.style.transform = `translate(${this.pos.x}px, ${this.pos.y}px) scale(${this.currentScale})`
}
}
customElements.define('zoomable-image', ZoomableImage) |
Partager