/**
* A circle avatar
*/
function ChatHead({ src, ...props }) {
return (
<img draggable="false"
src={ src }
style={{ transition: 'all 300ms ease-in-out' }}
className="br-100 pa1 ba b--black-10 h3 w3"
alt="chat-head"
{ ...props } />
);
}
/**
* Draggable
* A wrapper component for
* making elements draggable
*/
class Draggable extends React.Component {
constructor() {
super();
this.state = {
x: window.innerWidth / 2,
y: window.innerHeight / 2,
dragging: false,
};
}
onPanStart = e => {
if (e.type === 'dragstart') {
e.dataTransfer.setDragImage(getDragImage(), 0, 0);
}
this.setState({ dragging: true });
};
onPan = e => {
if (e.clientX <= 0 || e.clientY <= 0) return false;
this.setState(getPan(e));
};
onPanEnd = e => {
this.setState({ dragging: false });
};
render() {
const { x, y, dragging } = this.state;
const { children } = this.props;
return (
<div draggable="true"
className="dib move"
style={{
display: 'inline-block',
cursor: 'move',
WebkitTransform: `translate3d(${ x - 32 }px, ${ y - 32 }px, 0)`,
transform: `translate3d(${ x - 32 }px, ${ y - 32 }px, 0)`,
}}
onTouchStart={ this.onPanStart }
onDragStart={ this.onPanStart }
onDrag={ this.onPan }
onTouchMove={ this.onPan }
onTouchEnd={ this.onPanEnd }
onDragEnd={ this.onPanEnd}>
{ children }
</div>
);
}
}
/**
* Root node of the application
*/
function App() {
return (
<Draggable>
<ChatHead
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/149125/profile.jpg"
/>
</Draggable>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
/**
* Utils
*/
function getPan(e) {
if (e.type.includes('drag')) {
return { x: e.clientX, y: e.clientY };
}
const touch = e.targetTouches[0];
return { x: touch.clientX, y: touch.clientY };
}
function getDragImage() {
let img = new Image();
img.src = 'fake.gif';
return img;
}
View Compiled