※赤い部分をドラッグして動かせます。
See the Pen MovableElement by Yoshiharu (@yoshiharu2580) on CodePen.
パソコン、スマホの両方とも対応しています。
interface ElementPosition {
top: number;
left: number;
}
interface PointerPosition {
x: number | null;
y: number | null;
}
class MovableElement {
// Elementオブジェクト
private element?: HTMLElement;
// 要素の初期位置
private elementInitialPosition?: ElementPosition;
// 要素の動き始めの位置
private elementStartPosition?: ElementPosition;
// ポインタの動き始めの位置
private pointerStartPosition: PointerPosition = {
x: null,
y: null
};
constructor(id: string) {
this.element = document.getElementById(id);
this.elementInitialPosition = this.getCurrentPosition();
this.element.addEventListener("mousedown", (event: MouseEvent) => {
this.elementStartPosition = this.getCurrentPosition();
this.pointerStartPosition.x = event.clientX;
this.pointerStartPosition.y = event.clientY;
});
this.element.addEventListener("touchstart", (event: TouchEvent) => {
this.elementStartPosition = this.getCurrentPosition();
this.pointerStartPosition.x = event.touches[0].clientX;
this.pointerStartPosition.y = event.touches[0].clientY;
});
window.addEventListener("mousemove", (event: MouseEvent) => {
if (
this.pointerStartPosition.x == null ||
this.pointerStartPosition.y == null
)
return;
const pointerMovedDistanceX = event.clientX - this.pointerStartPosition.x;
const pointerMovedDistanceY = event.clientY - this.pointerStartPosition.y;
this.moveDistance(pointerMovedDistanceX, pointerMovedDistanceY);
});
window.addEventListener(
"touchmove",
(event: TouchEvent) => {
if (
this.pointerStartPosition.x == null ||
this.pointerStartPosition.y == null
)
return;
// touchmove中はスクロールをキャンセルする
event.preventDefault();
const pointerMovedDistanceX =
event.touches[0].clientX - this.pointerStartPosition.x;
const pointerMovedDistanceY =
event.touches[0].clientY - this.pointerStartPosition.y;
this.moveDistance(pointerMovedDistanceX, pointerMovedDistanceY);
},
// touchmove中はスクロールをキャンセルする
{ passive: false }
);
window.addEventListener("mouseup", () => {
this.resetPointerStartPosition();
});
window.addEventListener("touchend", () => {
this.resetPointerStartPosition();
});
}
// 要素の位置を取得する
getCurrentPosition(): ElementPosition {
const { top, left } = this.element.getBoundingClientRect();
return { top, left };
}
// 要素を現在位置からの距離だけ移動させる
moveDistance(distanceX: number, distanceY: number) {
// 補正値
const correctionX =
this.elementStartPosition.left - this.elementInitialPosition.left;
const correctionY =
this.elementStartPosition.top - this.elementInitialPosition.top;
// 目標値
const targetX = correctionX + distanceX;
const targetY = correctionY + distanceY;
this.element.style.transform = `translate(${targetX}px, ${targetY}px)`;
}
// 要素の動き始めの位置をリセット
resetPointerStartPosition() {
if (
this.pointerStartPosition.x == null ||
this.pointerStartPosition.y == null
)
return;
this.pointerStartPosition.x = null;
this.pointerStartPosition.y = null;
}
}
new MovableElement('element');
ここから色々応用できそう。