Skip to content

Commit

Permalink
Improve clock adding two levels
Browse files Browse the repository at this point in the history
  • Loading branch information
javivelasco committed Aug 13, 2015
1 parent 9ade334 commit 0f71b32
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 104 deletions.
164 changes: 98 additions & 66 deletions components/clock/index.cjsx
Expand Up @@ -2,97 +2,129 @@ css = require './style'

module.exports = React.createClass

# -- States & Properties
propTypes:
className : React.PropTypes.string

getDefaultProps: ->
className : ''

getInitialState: ->
angle: 0
pressed: false
clockCenter : undefined
clockCenter : undefined
clockInnerMaxRadius : undefined
clockInnerMinRadius : undefined
clockMaxRadius : undefined
clockMinRadius : undefined
handInner : false
pressed : false
handAngle : 0

# -- 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)
clockCenter : @_getClockCenter()
clockMaxRadius : @_getRefRadius('root')
clockMinRadius : @_getRefRadius('clockHolder')
clockInnerMaxRadius : @_getRefRadius('clockHolder')
clockInnerMinRadius : @_getRefRadius('innerClockHolder')

# -- Position Functions
_getClockCenter: ->
bounds = @refs.clock.getDOMNode().getBoundingClientRect()
bounds = @refs.root.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()
_getRefRadius: (ref) ->
bounds = @refs[ref].getDOMNode().getBoundingClientRect()
(bounds.right - bounds.left)/2

_getMaxRadius: ->
bounds = @refs.root.getDOMNode().getBoundingClientRect()
(bounds.right - bounds.left)/2
_isInsideClockArea: (position) ->
@state.clockMinRadius < @_getPositionRadius(position) < @state.clockMaxRadius

_getAngleFromClickEvent: (event) ->
mouse = _getMousePosition(event)
_angle360(@state.center.x, @state.center.y, mouse.x, mouse.y)
_isInsideClockInnerArea: (position) ->
@state.clockInnerMinRadius < @_getPositionRadius(position) < @state.clockInnerMaxRadius

onClockClick: (event) ->
radius = @_getClickRadius(event)
if (@state.minRadius < radius < @state.maxRadius)
@setState angle: @_trimValue(@_getAngleFromClickEvent(event))
_getPositionRadius: (position) ->
x = @state.clockCenter.x - position.x
y = @state.clockCenter.y - position.y
Math.sqrt(x * x + y * y)

_trimValue: (angle) ->
# -- Helper Functions
_positionToAngle: (position) ->
_angle360(@state.clockCenter.x, @state.clockCenter.y, position.x, position.y)

_trimAngleToValue: (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
_getMouseEventMap: ->
mousemove: @onMouseMove
mouseup: @onMouseUp

_moveHandToPosition: (position) ->
trimAngle = @_trimAngleToValue(@_positionToAngle(position))
if @_isInsideClockInnerArea(position)
@setState
handAngle: trimAngle
handInner: true
else if @_isInsideClockArea(position)
@setState
handAngle: trimAngle
handInner: false

_end: (events) ->
_removeEventsFromDocument(events)

render: ->
className = ''
className += ' pressed' if @state.pressed
handStyle =
transform: "rotate(#{@state.angle}deg)"
# -- Event handlers
onClockMouseDown: (event) ->
position = _getMousePosition(event)
@_moveHandToPosition(position)
_addEventsToDocument(@_getMouseEventMap())
@setState pressed: true

<div ref="root" className={css.root + '' + className} onClick={@onClockClick}>
onKnobMouseDown: (event) ->
_addEventsToDocument(@_getMouseEventMap())
@setState pressed: true

onMouseMove: (event) ->
position = _getMousePosition(event)
@_moveHandToPosition(position)

onMouseUp: ->
@_end(@_getMouseEventMap())
@setState pressed: false

render: ->
className = @props.className
className += css.root
className += " hand-inner" if @state.handInner
className += " pressed" if @state.pressed
handStyle = transform: "rotate(#{@state.handAngle}deg)"

<div ref="root" className={className} onMouseDown={@onClockMouseDown}>
{# Main Clock }
<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>
{ <span className={css.hour} key="hour-#{i}">{i}</span> for i in [13..23] }
<span className={css.hour} key="hour-00">00</span>
</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
{# Inner Clock }
<div ref="innerClock" className={css.innerClock}>
{ <span className={css.innerHour} key="hour-#{i}">{i}</span> for i in [1..12] }
</div>

{# Support area holders }
<div ref="clockHolder" className={css.clockHolder}></div>
<div ref="innerClockHolder" className={css.innerClockHolder}></div>

{# Clock hand }
<div ref="hand" style={handStyle} className={css.hand}>
<div className={css.knob} onMouseDown={@onKnobMouseDown}></div>
</div>
</div>

_getMousePosition = (event) ->
x: event.pageX
Expand Down
102 changes: 64 additions & 38 deletions components/clock/style.styl
@@ -1,45 +1,48 @@
rootSize = 266px
innerPadding = 10px
knobSize = 40px
clockSize = rootSize - knobSize - innerPadding
clockSizeInner = clockSize - knobSize - innerPadding
clockRadius = (clockSize/2)
hourSize = 30px
rootSize = 250px
innerPadding = 12px
knobSize = 28px
hourSize = 28px
handWidth = 2px
handDotSize = 8px
clockSize = rootSize - knobSize - innerPadding
clockRadius = clockSize / 2
clockHolderSize = clockSize - knobSize - innerPadding
innerClockSize = clockHolderSize - knobSize - innerPadding
clockInnerRadius = innerClockSize / 2
innerClockHolderSize = innerClockSize - knobSize - innerPadding

centeredCircle(circleSize)
border-radius : 50%
height : circleSize
left : 50%
margin-left : -(circleSize/2)
margin-top : -(circleSize/2)
position : absolute
top : 50%
width : circleSize

:local(.root)
border-radius : 50%
border : 1px solid red
background-color : #ccc
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
centeredCircle 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(.clockHolder)
centeredCircle clockHolderSize

:local(.innerClock)
centeredCircle innerClockSize

:local(.innerClockHolder)
centeredCircle innerClockHolderSize

:local(.hand)
background-color : blue
background-color : magenta
bottom : 50%
display : block
height : clockRadius - (knobSize/2)
Expand All @@ -50,21 +53,24 @@ handWidth = 2px
width : handWidth

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

:local(.root).hand-inner :local(.hand)
height : clockRadius - (knobSize/2) - knobSize - innerPadding

:local(.knob)
cursor : pointer
border-radius : 50%
background-color : blue
background-color : magenta
height : knobSize
left : 50%
margin-left : -(knobSize/2)
Expand All @@ -78,17 +84,37 @@ handWidth = 2px
:local(.hour)
color : #444
border-radius : 50%
background-color : gray
height : hourSize
line-height : hourSize
margin-left : -(hourSize/2)
pointer-events : none
margin-top : -(hourSize/2)
position : absolute
text-align : center
width : hourSize

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

:local(.hours)
:local(.clock)
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
left : ((clockRadius) + (clockRadius) * sin(PI * 2 * (num/12)))
top : ((clockRadius) - (clockRadius) * cos(PI * 2 * (num/12)))

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

0 comments on commit 0f71b32

Please sign in to comment.