Created
September 10, 2018 20:07
-
-
Save zaceno/86d4d964ab071d871c2fa60cca0ef7da to your computer and use it in GitHub Desktop.
HAV2 Intro - example 10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<style> | |
.gauge { | |
position: relative; | |
padding: 0; | |
border: 1px #555 solid; | |
background-color: #aaa; | |
width: 200px; | |
height: 40px; | |
border-radius: 4px; | |
overflow: hidden; | |
} | |
.gauge-meter { | |
position: absolute; | |
padding: 0; | |
margin: 0; | |
top: 0; | |
left: 0; | |
bottom: 0; | |
width: 62%; | |
background-color: hotpink; | |
} | |
.gauge-text { | |
position: absolute; | |
margin: 0; | |
padding: 0; | |
line-height: 40px; | |
font-size: 25px; | |
text-align: center; | |
top: 0; | |
left: 0; | |
bottom: 0; | |
width: 100%; | |
color: #fff; | |
text-shadow: #000 0px -1px 1px; | |
z-index: 1000; | |
} | |
</style> | |
<script defer type="module"> | |
import {h, app} from "https://rawgit.com/hyperapp/hyperapp/V2/src/index.js" | |
const DURATION = 15000 //ms = 15s | |
const AnimationFrame = (() => { | |
const effect = (props, dispatch) => { | |
var frameId | |
const onFrame = (timestamp) => { | |
dispatch(props.action, timestamp) | |
nextFrame() | |
} | |
const nextFrame = () => { | |
frameId = requestAnimationFrame(onFrame) | |
} | |
nextFrame() | |
return () => cancelAnimationFrame(frameId) | |
} | |
return props => ({effect, ...props}) | |
})() | |
const Start = (state, event) => { | |
if (state.mode !== 'stopped') return | |
return { | |
mode: 'running', | |
startedTime: event.timeStamp, | |
remainingTime: DURATION, | |
duration: DURATION, | |
} | |
} | |
const Pause = state => { | |
if (state.mode !== 'running') return | |
return { | |
...state, | |
mode: 'paused', | |
} | |
} | |
const Continue = (state, event) => { | |
if (state.mode !== 'paused') return | |
return { | |
...state, | |
mode: 'running', | |
startedTime: event.timeStamp, | |
duration: state.remainingTime, | |
} | |
} | |
const Cancel = state => { | |
return { | |
...state, | |
mode: 'stopped' | |
} | |
} | |
const UpdateTime = (state, timestamp) => { | |
if (state.mode !== 'running') return | |
if (state.remainingTime < 0) return Cancel(state) | |
return { | |
...state, | |
remainingTime: state.duration - (timestamp - state.startedTime) | |
} | |
} | |
const Gauge = (props, children) => h('div', { class: 'gauge'}, [ | |
h('div', { | |
class: 'gauge-meter', | |
style: { | |
width: ( | |
props.active | |
? (100 * props.fraction) + '%' | |
: '100%' | |
), | |
} | |
}), | |
props.active && h('p', { class: 'gauge-text'}, children) | |
]) | |
const TimerControls = ({mode, timer}) => h('p', {}, [ | |
mode === 'stopped' | |
? h('button', {onClick: [StartX, {timer}] }, ['START']) | |
: h('button', {onClick: [CancelX, {timer}] }, ['CANCEL']), | |
mode === 'paused' | |
? h('button', {onClick: [ContinueX, {timer}] }, ['CONT.']) | |
: h('button', { | |
disabled: mode === 'stopped', | |
onClick: [PauseX, {timer}] | |
}, ['PAUSE']), | |
]) | |
const timerAction = (action, state, param, data) => { | |
const returnValue = action(state[param.timer], data) | |
if (returnValue) return { | |
...state, | |
[param.timer]: { ...returnValue }, | |
} | |
} | |
const StartX = (...arg) => timerAction(Start, ...arg) | |
const CancelX = (...arg) => timerAction(Cancel, ...arg) | |
const PauseX = (...arg) => timerAction(Pause, ...arg) | |
const ContinueX = (...arg) => timerAction(Continue, ...arg) | |
const UpdateTimeX = (...arg) => timerAction(UpdateTime, ...arg) | |
app({ | |
init: state => ({ | |
timer1: { | |
mode: 'stopped' | |
}, | |
timer2: { | |
mode: 'stopped' | |
} | |
}), | |
view: state => h('table', {}, [ | |
h('tr', {}, [ | |
h('td', {}, ['A']), | |
h('td', {}, [ | |
h( | |
Gauge, | |
{ | |
active: state.timer1.mode !== 'stopped', | |
fraction: state.timer1.remainingTime / DURATION, | |
}, | |
[ | |
Math.ceil(state.timer1.remainingTime / 1000), | |
' s' | |
] | |
) | |
]), | |
h('td', {}, [ | |
h(TimerControls, {mode: state.timer1.mode, timer: 'timer1'}), | |
]) | |
]), | |
h('tr', {}, [ | |
h('td', {}, ['B']), | |
h('td', {}, [ | |
h( | |
Gauge, | |
{ | |
active: state.timer2.mode !== 'stopped', | |
fraction: state.timer2.remainingTime / DURATION, | |
}, | |
[ | |
Math.ceil(state.timer2.remainingTime / 1000), | |
' s' | |
] | |
) | |
]), | |
h('td', {}, [ | |
h(TimerControls, {mode: state.timer2.mode, timer: 'timer2'}), | |
]) | |
]), | |
]), | |
container: document.body, | |
subscriptions: state => [ | |
state.timer1.mode === 'running' && AnimationFrame({action: [UpdateTimeX, {timer: 'timer1'}] }), | |
state.timer2.mode === 'running' && AnimationFrame({action: [UpdateTimeX, {timer: 'timer2'}] }), | |
] | |
}) | |
</script> | |
</head> | |
<body></body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment