Skip to content

Instantly share code, notes, and snippets.

@CreatiCoding
Created July 29, 2020 01:15
Show Gist options
  • Select an option

  • Save CreatiCoding/df479bdc591b99c277b60a5ebf374edd to your computer and use it in GitHub Desktop.

Select an option

Save CreatiCoding/df479bdc591b99c277b60a5ebf374edd to your computer and use it in GitHub Desktop.
img tag scaler
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