react-toolbox/components/time_picker/ClockHand.js

130 lines
3.0 KiB
JavaScript

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { angle360FromPositions } from '../utils/utils';
import events from '../utils/events';
import prefixer from '../utils/prefixer';
class Hand extends Component {
static propTypes = {
angle: PropTypes.number,
className: PropTypes.string,
length: PropTypes.number,
onMove: PropTypes.func,
onMoved: PropTypes.func,
origin: PropTypes.shape({
x: PropTypes.number,
y: PropTypes.number,
}),
step: PropTypes.number,
theme: PropTypes.shape({
hand: PropTypes.string,
knob: PropTypes.string,
}),
};
static defaultProps = {
className: '',
angle: 0,
length: 0,
origin: {},
};
state = {
knobWidth: 0,
};
componentDidMount() {
setTimeout(() => {
this.setState({ knobWidth: this.knobNode.offsetWidth });
});
}
componentWillUnmount() {
events.removeEventsFromDocument(this.getMouseEventMap());
events.removeEventsFromDocument(this.getTouchEventMap());
}
getMouseEventMap() {
return {
mousemove: this.handleMouseMove,
mouseup: this.handleMouseUp,
};
}
getTouchEventMap() {
return {
touchmove: this.handleTouchMove,
touchend: this.handleTouchEnd,
};
}
getPositionRadius(position) {
const x = this.props.origin.x - position.x;
const y = this.props.origin.y - position.y;
return Math.sqrt((x * x) + (y * y));
}
mouseStart(event) {
events.addEventsToDocument(this.getMouseEventMap());
this.move(events.getMousePosition(event));
}
touchStart(event) {
events.addEventsToDocument(this.getTouchEventMap());
this.move(events.getTouchPosition(event));
events.pauseEvent(event);
}
handleMouseMove = (event) => {
this.move(events.getMousePosition(event));
};
handleTouchMove = (event) => {
this.move(events.getTouchPosition(event));
};
handleMouseUp = () => {
this.end(this.getMouseEventMap());
};
handleTouchEnd = () => {
this.end(this.getTouchEventMap());
};
trimAngleToValue(angle) {
return this.props.step * Math.round(angle / this.props.step);
}
positionToAngle(position) {
return angle360FromPositions(this.props.origin.x, this.props.origin.y, position.x, position.y);
}
end(evts) {
if (this.props.onMoved) this.props.onMoved();
events.removeEventsFromDocument(evts);
}
move(position) {
const degrees = this.trimAngleToValue(this.positionToAngle(position));
const radius = this.getPositionRadius(position);
if (this.props.onMove) this.props.onMove(degrees === 360 ? 0 : degrees, radius);
}
render() {
const { theme } = this.props;
const className = `${theme.hand} ${this.props.className}`;
const handStyle = prefixer({
height: this.props.length - (this.state.knobWidth / 2),
transform: `rotate(${this.props.angle}deg)`,
});
return (
<div className={className} style={handStyle}>
<div ref={(node) => { this.knobNode = node; }} className={theme.knob} />
</div>
);
}
}
export default Hand;