Created
July 29, 2020 01:15
-
-
Save CreatiCoding/df479bdc591b99c277b60a5ebf374edd to your computer and use it in GitHub Desktop.
img tag scaler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export default class Scaler { | |
| constructor(el) { | |
| this.zoom_size = 1; | |
| this.zoom_pos = {}; | |
| this.touches_length = 0; | |
| this.image_top = 0; | |
| this.scale = 1; | |
| this.init_distance = null; | |
| //라우터 셋팅 | |
| el.addEventListener('touchstart', this.touchRouter); | |
| el.addEventListener('touchmove', this.trackingCenter); | |
| el.addEventListener('touchmove', this.touchRouter); | |
| el.addEventListener('touchend', this.touchRouter); | |
| // 실제 동작 | |
| el.addEventListener('touchstart-finger', (event) => | |
| this.fingerListenerStart.bind(this, { event, el })() | |
| ); | |
| el.addEventListener('touchend-finger', (event) => | |
| this.fingerListenerEnd.bind(this, { event, el })() | |
| ); | |
| el.addEventListener('touchmove-finger', (event) => | |
| this.fingerListenerMove.bind(this, { event, el })() | |
| ); | |
| } | |
| trackingCenter(event) { | |
| console.log(event.changedTouches); | |
| } | |
| touchRouter(event) { | |
| if (event.type === 'touchmove') { | |
| event.preventDefault(); | |
| } | |
| if (event.type === 'touchmove' || event.type === 'touchstart') { | |
| for (const touch of event.changedTouches) { | |
| const new_event = document.createEvent('Event'); | |
| new_event.initEvent(`${event.type}-finger`, true, true); | |
| for (const k in touch) { | |
| if (k === 'target') continue; | |
| new_event[k] = touch[k]; | |
| } | |
| new_event.touch_point_length = event.changedTouches.length; | |
| new_event.touch_type = event.type; | |
| new_event.touch_identifier = touch.identifier; | |
| event.target.dispatchEvent(new_event); | |
| } | |
| } else if (event.type === 'touchend') { | |
| const touch_list = event.changedTouches; | |
| const new_event = document.createEvent('Event'); | |
| new_event.initEvent(`${event.type}-finger`, true, true); | |
| for (const k in touch_list[0]) { | |
| if (k === 'target') continue; | |
| new_event[k] = touch_list[0][k]; | |
| } | |
| new_event.touches = event.touches; | |
| new_event.touch_point_length = event.changedTouches.length; | |
| new_event.touch_type = event.type; | |
| new_event.touch_identifier = touch_list[0].identifier; | |
| event.target.dispatchEvent(new_event); | |
| } | |
| } | |
| getCenter(pos1, pos2) { | |
| return { | |
| x: (pos2.x + pos1.x) / 2, | |
| y: (pos2.y + pos1.y) / 2, | |
| }; | |
| } | |
| getDistance(pos1, pos2) { | |
| const x = pos1.x - pos2.x; | |
| const y = pos1.y - pos2.y; | |
| return Math.sqrt(x * x + y * y); | |
| } | |
| getRatio(prev_distance, post_distance) { | |
| return post_distance / prev_distance; | |
| } | |
| getOrigin(el, pos1, pos2) { | |
| const center_point = this.getCenter(pos1, pos2); | |
| const offset_top = el.offsetTop; | |
| const offset_left = el.offsetLeft; | |
| const offset_height = el.offsetHeight; | |
| const offset_width = el.offsetWidth; | |
| return { | |
| x: el.offsetWidth * ((center_point.x - offset_left) / offset_width), | |
| y: el.offsetHeight * ((center_point.y - offset_top) / offset_height), | |
| }; | |
| } | |
| scaleImage(el) { | |
| if (!this.init_distance) return; | |
| if (!this.zoom_pos || Object.keys(this.zoom_pos).length < 2) return; | |
| const [pos1, pos2] = Object.values(this.zoom_pos); | |
| const distance = this.getDistance(pos1, pos2); | |
| if (this.init_distance === distance) { | |
| return; | |
| } | |
| let ratio = this.getRatio(this.init_distance, distance); | |
| if (ratio < 1) ratio = 1; | |
| const origin = this.getOrigin(el, pos1, pos2); | |
| const el_style = el.style; | |
| el_style.transform = `scale(${this.scale * ratio})`; | |
| if (!el_style.transformOrigin || el_style.transformOrigin.indexOf('unset') !== -1) { | |
| el_style.transformOrigin = `${origin.x}px ${origin.y}px`; | |
| } | |
| el.ratio = ratio; | |
| } | |
| addZoomPos(event) { | |
| if (this.zoom_pos[`${event.touch_identifier}`]) { | |
| this.zoom_pos[`${event.touch_identifier}`].x = event.pageX; | |
| this.zoom_pos[`${event.touch_identifier}`].y = event.pageY; | |
| } else { | |
| if (Object.keys(this.zoom_pos).length > 2) { | |
| return; | |
| } | |
| this.zoom_pos[`${event.touch_identifier}`] = { | |
| identifier: event.touch_identifier, | |
| x: event.pageX, | |
| y: event.pageY, | |
| }; | |
| } | |
| } | |
| removeZoomPos(event) { | |
| if (event.touches.length === 0) { | |
| for (const identifier in this.zoom_pos) { | |
| delete this.zoom_pos[identifier]; | |
| } | |
| return; | |
| } | |
| if (this.zoom_pos[event.touch_identifier]) { | |
| delete this.zoom_pos[event.touch_identifier]; | |
| } | |
| } | |
| fingerListenerStart({ event, el }) { | |
| this.addZoomPos(event); | |
| if (Object.keys(this.zoom_pos).length === 2) { | |
| el.style.transition = ``; | |
| const [pos1, pos2] = Object.values(this.zoom_pos); | |
| const distance = this.getDistance(pos1, pos2); | |
| this.init_distance = distance; | |
| } else if (Object.keys(this.zoom_pos).length === 1) { | |
| el.style.transition = `transform 100ms ease `; | |
| el.style.transform = `scale(1)`; | |
| setTimeout(() => { | |
| el.style.transformOrigin = ``; | |
| }, 0); | |
| } | |
| } | |
| fingerListenerMove({ event, el }) { | |
| if (this.scale < 1 || Object.keys(this.zoom_pos).length < 2) { | |
| const pos = this.zoom_pos[Object.keys(this.zoom_pos).pop()]; | |
| window.scrollTo( | |
| window.scrollX + (pos.x - event.pageX), | |
| window.scrollY + (pos.y - event.pageY) | |
| ); | |
| } else if (Object.keys(this.zoom_pos).length >= 2) { | |
| this.addZoomPos(event); | |
| this.scaleImage(el); | |
| } else if (Object.keys(this.zoom_pos).length === 1) { | |
| const pos = this.zoom_pos[Object.keys(this.zoom_pos).pop()]; | |
| window.scrollTo( | |
| window.scrollX + (pos.x - event.pageX), | |
| window.scrollY + (pos.y - event.pageY) | |
| ); | |
| } | |
| } | |
| fingerListenerEnd({ event, el }) { | |
| event, el; | |
| this.removeZoomPos(event); | |
| if (Object.keys(this.zoom_pos).length >= 2) { | |
| const [pos1, pos2] = Object.values(this.zoom_pos); | |
| const distance = this.getDistance(pos1, pos2); | |
| this.scale = this.scale * this.getRatio(this.init_distance, distance); | |
| this.init_distance = distance; | |
| } else { | |
| this.scale = 1; | |
| this.init_distance = null; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment