d2-ui
Version:
231 lines (185 loc) • 5 kB
JSX
import React from 'react';
import ReactDOM from 'react-dom';
import StylePropable from '../mixins/style-propable';
import ClockNumber from './clock-number';
import ClockPointer from './clock-pointer';
import getMuiTheme from '../styles/getMuiTheme';
function rad2deg(rad) {
return rad * 57.29577951308232;
}
function getTouchEventOffsetValues(e) {
let el = e.target;
let boundingRect = el.getBoundingClientRect();
let offset = {
offsetX: e.clientX - boundingRect.left,
offsetY: e.clientY - boundingRect.top,
};
return offset;
}
const ClockHours = React.createClass({
propTypes: {
format: React.PropTypes.oneOf(['ampm', '24hr']),
initialHours: React.PropTypes.number,
onChange: React.PropTypes.func,
},
contextTypes: {
muiTheme: React.PropTypes.object,
},
//for passing default theme context to children
childContextTypes: {
muiTheme: React.PropTypes.object,
},
mixins: [StylePropable],
getDefaultProps() {
return {
initialHours: new Date().getHours(),
onChange: () => {},
format: 'ampm',
};
},
getInitialState() {
return {
muiTheme: this.context.muiTheme || getMuiTheme(),
};
},
getChildContext() {
return {
muiTheme: this.state.muiTheme,
};
},
componentDidMount() {
let clockElement = ReactDOM.findDOMNode(this.refs.mask);
this.center = {
x: clockElement.offsetWidth / 2,
y: clockElement.offsetHeight / 2,
};
this.basePoint = {
x: this.center.x,
y: 0,
};
},
//to update theme inside state whenever a new theme is passed down
//from the parent / owner using context
componentWillReceiveProps(nextProps, nextContext) {
let newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
this.setState({muiTheme: newMuiTheme});
},
center: {x: 0, y: 0},
basePoint: {x: 0, y: 0},
isMousePressed(e) {
if (typeof e.buttons === 'undefined') {
return e.nativeEvent.which;
}
return e.buttons;
},
handleUp(e) {
e.preventDefault();
this.setClock(e.nativeEvent, true);
},
handleMove(e) {
e.preventDefault();
if (this.isMousePressed(e) !== 1 ) return;
this.setClock(e.nativeEvent, false);
},
handleTouchMove(e) {
e.preventDefault();
this.setClock(e.changedTouches[0], false);
},
handleTouchEnd(e) {
e.preventDefault();
this.setClock(e.changedTouches[0], true);
},
setClock(e, finish) {
if (typeof e.offsetX === 'undefined') {
let offset = getTouchEventOffsetValues(e);
e.offsetX = offset.offsetX;
e.offsetY = offset.offsetY;
}
let hours = this.getHours(e.offsetX, e.offsetY);
this.props.onChange(hours, finish);
},
getHours(offsetX, offsetY) {
let step = 30;
let x = offsetX - this.center.x;
let y = offsetY - this.center.y;
let cx = this.basePoint.x - this.center.x;
let cy = this.basePoint.y - this.center.y;
let atan = Math.atan2(cx, cy) - Math.atan2(x, y);
let deg = rad2deg(atan);
deg = Math.round(deg / step ) * step;
deg %= 360;
let value = Math.floor(deg / step) || 0;
let delta = Math.pow(x, 2) + Math.pow(y, 2);
let distance = Math.sqrt(delta);
value = value || 12;
if (this.props.format === '24hr') {
if (distance < 90) {
value += 12;
value %= 24;
}
} else {
value %= 12;
}
return value;
},
_getSelected() {
let hour = this.props.initialHours;
if (this.props.format === 'ampm') {
hour %= 12;
hour = hour || 12;
}
return hour;
},
_getHourNumbers() {
let style = {
pointerEvents: 'none',
};
let hourSize = this.props.format === 'ampm' ? 12 : 24;
let hours = [];
for (let i = 1; i <= hourSize; i++) {
hours.push(i % 24);
}
return hours.map((hour) => {
const isSelected = this._getSelected() === hour;
return (
<ClockNumber
key={hour}
style={style}
isSelected={isSelected}
type="hour"
value={hour}
/>
);
});
},
render() {
let styles = {
root: {
height: '100%',
width: '100%',
borderRadius: '100%',
position: 'relative',
pointerEvents: 'none',
boxSizing: 'border-box',
},
hitMask: {
height: '100%',
width: '100%',
pointerEvents: 'auto',
},
};
let hours = this._getSelected();
let numbers = this._getHourNumbers();
return (
<div ref="clock" style={this.prepareStyles(styles.root)} >
<ClockPointer hasSelected={true} value={hours} type="hour" />
{numbers}
<div
ref="mask" style={this.prepareStyles(styles.hitMask)} onTouchMove={this.handleTouchMove}
onTouchEnd={this.handleTouchEnd} onMouseUp={this.handleUp} onMouseMove={this.handleMove}
/>
</div>
);
},
});
export default ClockHours;