Skip to content

Instantly share code, notes, and snippets.

@ginpei
Last active May 23, 2020 18:13
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save ginpei/33913ee0d082aa36386aa7a2210f2fb3 to your computer and use it in GitHub Desktop.
import React, {
CSSProperties, useCallback, useEffect, useMemo, useState, useRef,
} from 'react';
import Head from 'next/head';
import { Pos } from '../models/Length';
const DraggablePage: React.FC = () => {
const [dragging, setDragging] = useState(false);
const [from, setFrom] = useState<Pos>({ x: 0, y: 0 });
const [pointerType, setPointerType] = useState('');
const [to, setTo] = useState<Pos>({ x: 0, y: 0 });
const ref = useRef<HTMLDivElement>(null);
const rectStyle = useMemo<CSSProperties>(() => {
const left = Math.min(from.x, to.x);
const top = Math.min(from.y, to.y);
const width = Math.abs(from.x - to.x);
const height = Math.abs(from.y - to.y);
const style: CSSProperties = {
backgroundColor: 'tomato',
height: `${height}px`,
left: `${left}px`,
opacity: 0.5,
position: 'fixed',
top: `${top}px`,
width: `${width}px`,
};
return style;
}, [from, to]);
const onPointerDown = useCallback((event: React.PointerEvent) => {
setPointerType(event.pointerType);
setFrom({ x: event.pageX, y: event.pageY });
setTo({ x: event.pageX, y: event.pageY });
setDragging(true);
}, []);
const onPointerMove = useCallback((event: PointerEvent) => {
if (!dragging) {
return;
}
setTo({ x: event.pageX, y: event.pageY });
}, [dragging]);
const onPointerUp = useCallback((event: PointerEvent) => {
setPointerType('');
setDragging(false);
}, [dragging]);
useEffect(() => {
const el = document.documentElement;
el.addEventListener('pointermove', onPointerMove);
el.addEventListener('pointerup', onPointerUp);
el.addEventListener('pointercancel', onPointerUp);
return () => {
el.removeEventListener('pointermove', onPointerMove);
el.removeEventListener('pointerup', onPointerUp);
el.removeEventListener('pointercancel', onPointerUp);
};
}, [onPointerMove, onPointerUp]);
return (
<div
className="PointerPage"
onPointerDown={onPointerDown}
ref={ref}
style={{
cursor: 'crosshair',
height: '100%',
overflow: 'hidden',
touchAction: 'none', // <--- yes, this is it
userSelect: 'none', // <-- and here for mouse
}}
>
<Head>
<title>Draggable</title>
<style>{`
html, body, #__next {
height: 100%;
}
body {
margin: 0;
}
`}</style>
</Head>
<h1>Draggable</h1>
<p>Type: {pointerType}</p>
{dragging && (
<div
style={rectStyle}
/>
)}
</div>
);
};
export default DraggablePage;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment