Skip to content

Commit

Permalink
Add behavior to select the hour
Browse files Browse the repository at this point in the history
  • Loading branch information
javivelasco committed Aug 12, 2015
1 parent 8f2734d commit 9ade334
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 0 deletions.
117 changes: 117 additions & 0 deletions components/clock/index.cjsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
css = require './style'

module.exports = React.createClass

getInitialState: ->
angle: 0
pressed: false

# -- Lifecycle
componentDidMount: ->
clockBounds = @refs.clock.getDOMNode().getBoundingClientRect()
@setState
center: @_getClockCenter()
minRadius: @_getMinRadius()
maxRadius: @_getMaxRadius()

onKnobMouseDown: ->
@setState pressed: true
_addEventsToDocument(@getMouseEventMap())

getMouseEventMap: ->
mousemove: @onMouseMove
mouseup: @onMouseUp

onMouseMove: (event) ->
radius = @_getClickRadius(event)
if (@state.minRadius < radius < @state.maxRadius)
@setState angle: @_trimValue(@_getAngleFromClickEvent(event))

onMouseUp: ->
@setState pressed: false
@end(@getMouseEventMap())

end: (events) ->
_removeEventsFromDocument(events)

_getClockCenter: ->
bounds = @refs.clock.getDOMNode().getBoundingClientRect()
return {
x: bounds.left + (bounds.right - bounds.left)/2
y: bounds.top + (bounds.bottom - bounds.top) /2
}

_getMinRadius: ->
bounds = @refs.clockInner.getDOMNode().getBoundingClientRect()
(bounds.right - bounds.left)/2

_getMaxRadius: ->
bounds = @refs.root.getDOMNode().getBoundingClientRect()
(bounds.right - bounds.left)/2

_getAngleFromClickEvent: (event) ->
mouse = _getMousePosition(event)
_angle360(@state.center.x, @state.center.y, mouse.x, mouse.y)

onClockClick: (event) ->
radius = @_getClickRadius(event)
if (@state.minRadius < radius < @state.maxRadius)
@setState angle: @_trimValue(@_getAngleFromClickEvent(event))

_trimValue: (angle) ->
step = 360/12
step * Math.round(angle/step)

_getClickRadius: (event) ->
mouse = _getMousePosition(event)
x = @state.center.x - mouse.x
y = @state.center.y - mouse.y
r = Math.sqrt(x * x + y * y)
return r

render: ->
className = ''
className += ' pressed' if @state.pressed
handStyle =
transform: "rotate(#{@state.angle}deg)"

<div ref="root" className={css.root + '' + className} onClick={@onClockClick}>
<div ref="clock" className={css.clock}>
<div ref="hand" style={handStyle} className={css.hand}>
<div className={css.knob} onMouseDown={@onKnobMouseDown}></div>
</div>
<div className={css.hours}>
{ <span className={css.hour} key="hour-#{i}">{i}</span> for i in [1..12] }
</div>
</div>
<div ref="clockInner" className={css.clockInner} onClick={_pauseEvent}></div>
</div>

_pauseEvent = (event) ->
event.stopPropagation()
event.preventDefault()
event.returnValue = false
event.cancelBubble = true
return null

_getMousePosition = (event) ->
x: event.pageX
y: event.pageY

_angle = (cx, cy, ex, ey) ->
dy = ey - cy;
dx = ex - cx;
theta = Math.atan2(dy, dx) + Math.PI/2
theta = theta * 180 / Math.PI
return theta

_angle360 = (cx, cy, ex, ey) ->
theta = _angle(cx, cy, ex, ey)
theta = 360 + theta if (theta < 0)
return theta

_addEventsToDocument = (events) ->
document.addEventListener(key, events[key], false) for key of events

_removeEventsFromDocument = (events) ->
document.removeEventListener(key, events[key], false) for key of events
94 changes: 94 additions & 0 deletions components/clock/style.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
rootSize = 266px
innerPadding = 10px
knobSize = 40px
clockSize = rootSize - knobSize - innerPadding
clockSizeInner = clockSize - knobSize - innerPadding
clockRadius = (clockSize/2)
hourSize = 30px
handWidth = 2px

:local(.root)
border-radius : 50%
border : 1px solid red
height : rootSize
margin-left : 35px
padding : (hourSize/2)
position : relative
width : rootSize

:local(.clock)
border-radius : 50%
height : clockSize
left : 50%
margin-left : -(clockSize/2)
margin-top : -(clockSize/2)
position : absolute
top : 50%
width : clockSize

:local(.clockInner)
border-radius : 50%
border: 1px solid blue
height : clockSizeInner
left : 50%
margin-left : -(clockSizeInner/2)
margin-top : -(clockSizeInner/2)
position : absolute
top : 50%
width : clockSizeInner
z-index : 2

:local(.hand)
background-color : blue
bottom : 50%
display : block
height : clockRadius - (knobSize/2)
left : 50%
margin-left : -(handWidth/2)
position : absolute
transform-origin : 0 100%
width : handWidth

&:before
background-color : blue
border-radius : 50%
bottom : 0
content : ''
height : 8px
left : 50%
margin-bottom : -4px
margin-left : -4px
position : absolute
width : 8px

:local(.knob)
cursor : pointer
border-radius : 50%
background-color : blue
height : knobSize
left : 50%
margin-left : -(knobSize/2)
position : absolute
top : -(knobSize)
width : knobSize

:local(.root).pressed :local(.knob)
background-color : pink

:local(.hour)
color : #444
border-radius : 50%
height : hourSize
line-height : hourSize
margin-left : -(hourSize/2)
pointer-events : none
margin-top : -(hourSize/2)
position : absolute
text-align : center
width : hourSize

:local(.hours)
for num in 1 2 3 4 5 6 7 8 9 10 11 12
:local(.hour):nth-child({num})
left : (clockRadius + clockRadius * sin(PI * 2 * (num/12)))px
top : (clockRadius - clockRadius * cos(PI * 2 * (num/12)))px

0 comments on commit 9ade334

Please sign in to comment.