Display the time left of a given time

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite
1












Context



This software is a countdown/visual timer. It was initially developed to display the time left before the end of an exam.




Question



My JavaScript is working but when I want to validate it by some code quality tool it keeps throwing me this error: SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode.



If any of you can improve this code and help me to improve it(even the design), I would be very grateful.



Here's the code:






'use strict'

const load = () =>
const data =

init(data)

setInterval(() =>
update(data)
render(data)
, 100)

document.querySelector('#start').onclick = event =>
start(data)


document.querySelector('#reset').onclick = event =>
reset(data)


document.querySelector('#license').onclick = showLicense


const init = data =>
data.canvas = document.querySelector('#countdown')
data.ctx = data.canvas.getContext('2d')

data.endTime = Date.now()
data.start = false
data.reset = false

data.canvas.width = data.canvas.height = 500


const update = data =>

const render = data =>
const
canvas,
ctx,
startAngle,
start
= data

ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)

let angle = Math.abs(startAngle)

ctx.save()

if (startAngle > 0)
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.scale(1, -1)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)'
else
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'


while (angle > 2 * Math.PI)
ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI)
ctx.fill()

angle -= 2 * Math.PI


ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle)
ctx.lineTo(canvas.width / 2, canvas.height / 2)
ctx.fill()

ctx.restore()


const start = data =>
const button = document.querySelector('#start')
if (data.start)
button.innerText = 'Start'
else
let hours = document.querySelector('#hours').value
let minutes = document.querySelector('#minutes').value
let seconds = document.querySelector('#seconds').value
if (hours.trim() == '') hours = 0
if (minutes.trim() == '') minutes = 0
if (seconds.trim() == '') seconds = 0

let sign
if (hours != 0)
sign = hours < 0 ? -1 : 1
else if (minutes != 0)
sign = minutes < 0 ? -1 : 1
else
sign = seconds < 0 ? -1 : 1


minutes = sign * Math.abs(minutes)
seconds = sign * Math.abs(seconds)

data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds

button.innerText = 'Pause'

data.start ^= true


const reset = data =>
data.endTime = Date.now()
data.start = false
document.querySelector('#hours').value = ''
document.querySelector('#minutes').value = ''
document.querySelector('#seconds').value = ''
document.querySelector('#start').innerText = 'Start'
data.reset = true


const showLicense = () =>
const mask = document.createElement('div')
mask.style = 'position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0, 0, 0, 0.5);z-index:1;'
mask.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)

document.body.appendChild(mask)

const message = document.createElement('div')
message.style = 'position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:2;background:#fff;padding:10px;border-radius:10px;overflow:auto;max-width:600px;max-height:500px;'
message.innerText = 'License unavailable, please report as a bug.'
message.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)


const ajax = new XMLHttpRequest()
ajax.open('GET', 'LICENSE')
ajax.onreadystatechange = () =>
console.log('AJAX');
message.innerText = ajax.responseText

ajax.send()
document.body.append(message)


const timeToAngle = endTime =>
const difference = endTime - Date.now()
return difference / 3600000 * 2 * Math.PI


const pad = (value, format) => (format + value).slice(-format.length)

load()

* 
box-sizing: border-box;


body
background: #eee;
margin: 0;


main
background: #fff;
max-width: 700px;
margin: auto;
padding: 10px;
display: flex;
flex-flow: column;
align-items: center;


h1
text-align: center;


menu
display: flex;
justify-content: space-between;
width: 500px;
padding: 0;


#hours, #minutes, #seconds
width: 30px;
text-align: center;


footer
max-width: 700px;
margin: auto;
background: #ddd;
padding: 10px;
display: flex;
justify-content: space-between;


footer a
display: inline-block;
background: #ccc;
padding: 10px;
border-radius: 10px;
color: black;
text-decoration: none;
cursor: pointer;


footer a:hover
background: #888;
color: #fff;

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Countdown</title>
<script src="countdown.js" defer></script>
<link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
<main>
<h1 contenteditable>Countdown</h1>
<canvas id="countdown"></canvas>
<menu>
<button id="reset">Reset</button>
<div class="group">
<input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
</div>
<button id="start">Start</button>
</menu>
</main>
<footer>
<a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
<a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
<a id="license">MIT license</a>
</footer>
</body>

</html>









share|improve this question

















  • 1




    You're using a browser version that doesn't support const when in strict mode, most likely a Safari version prior to 10. Simple fix is to just use var or transpile with babel. See this StackOverflow question. I'd say this question is also better placed over at the Stack Overflow site.
    – Sven
    Mar 22 at 17:59










  • I've edited the title and I don't know why it can't pass jslint.com or other validators will keep throwing the same error(I'm pretty lost.) @Svenskunganka
    – DIDIx13
    Mar 22 at 18:33






  • 1




    jslint.com does not support latest JavaScript syntax - it's a pretty outdated site. Try ESLint instead.
    – Rene Saarsoo
    May 5 at 11:39
















up vote
2
down vote

favorite
1












Context



This software is a countdown/visual timer. It was initially developed to display the time left before the end of an exam.




Question



My JavaScript is working but when I want to validate it by some code quality tool it keeps throwing me this error: SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode.



If any of you can improve this code and help me to improve it(even the design), I would be very grateful.



Here's the code:






'use strict'

const load = () =>
const data =

init(data)

setInterval(() =>
update(data)
render(data)
, 100)

document.querySelector('#start').onclick = event =>
start(data)


document.querySelector('#reset').onclick = event =>
reset(data)


document.querySelector('#license').onclick = showLicense


const init = data =>
data.canvas = document.querySelector('#countdown')
data.ctx = data.canvas.getContext('2d')

data.endTime = Date.now()
data.start = false
data.reset = false

data.canvas.width = data.canvas.height = 500


const update = data =>

const render = data =>
const
canvas,
ctx,
startAngle,
start
= data

ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)

let angle = Math.abs(startAngle)

ctx.save()

if (startAngle > 0)
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.scale(1, -1)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)'
else
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'


while (angle > 2 * Math.PI)
ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI)
ctx.fill()

angle -= 2 * Math.PI


ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle)
ctx.lineTo(canvas.width / 2, canvas.height / 2)
ctx.fill()

ctx.restore()


const start = data =>
const button = document.querySelector('#start')
if (data.start)
button.innerText = 'Start'
else
let hours = document.querySelector('#hours').value
let minutes = document.querySelector('#minutes').value
let seconds = document.querySelector('#seconds').value
if (hours.trim() == '') hours = 0
if (minutes.trim() == '') minutes = 0
if (seconds.trim() == '') seconds = 0

let sign
if (hours != 0)
sign = hours < 0 ? -1 : 1
else if (minutes != 0)
sign = minutes < 0 ? -1 : 1
else
sign = seconds < 0 ? -1 : 1


minutes = sign * Math.abs(minutes)
seconds = sign * Math.abs(seconds)

data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds

button.innerText = 'Pause'

data.start ^= true


const reset = data =>
data.endTime = Date.now()
data.start = false
document.querySelector('#hours').value = ''
document.querySelector('#minutes').value = ''
document.querySelector('#seconds').value = ''
document.querySelector('#start').innerText = 'Start'
data.reset = true


const showLicense = () =>
const mask = document.createElement('div')
mask.style = 'position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0, 0, 0, 0.5);z-index:1;'
mask.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)

document.body.appendChild(mask)

const message = document.createElement('div')
message.style = 'position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:2;background:#fff;padding:10px;border-radius:10px;overflow:auto;max-width:600px;max-height:500px;'
message.innerText = 'License unavailable, please report as a bug.'
message.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)


const ajax = new XMLHttpRequest()
ajax.open('GET', 'LICENSE')
ajax.onreadystatechange = () =>
console.log('AJAX');
message.innerText = ajax.responseText

ajax.send()
document.body.append(message)


const timeToAngle = endTime =>
const difference = endTime - Date.now()
return difference / 3600000 * 2 * Math.PI


const pad = (value, format) => (format + value).slice(-format.length)

load()

* 
box-sizing: border-box;


body
background: #eee;
margin: 0;


main
background: #fff;
max-width: 700px;
margin: auto;
padding: 10px;
display: flex;
flex-flow: column;
align-items: center;


h1
text-align: center;


menu
display: flex;
justify-content: space-between;
width: 500px;
padding: 0;


#hours, #minutes, #seconds
width: 30px;
text-align: center;


footer
max-width: 700px;
margin: auto;
background: #ddd;
padding: 10px;
display: flex;
justify-content: space-between;


footer a
display: inline-block;
background: #ccc;
padding: 10px;
border-radius: 10px;
color: black;
text-decoration: none;
cursor: pointer;


footer a:hover
background: #888;
color: #fff;

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Countdown</title>
<script src="countdown.js" defer></script>
<link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
<main>
<h1 contenteditable>Countdown</h1>
<canvas id="countdown"></canvas>
<menu>
<button id="reset">Reset</button>
<div class="group">
<input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
</div>
<button id="start">Start</button>
</menu>
</main>
<footer>
<a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
<a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
<a id="license">MIT license</a>
</footer>
</body>

</html>









share|improve this question

















  • 1




    You're using a browser version that doesn't support const when in strict mode, most likely a Safari version prior to 10. Simple fix is to just use var or transpile with babel. See this StackOverflow question. I'd say this question is also better placed over at the Stack Overflow site.
    – Sven
    Mar 22 at 17:59










  • I've edited the title and I don't know why it can't pass jslint.com or other validators will keep throwing the same error(I'm pretty lost.) @Svenskunganka
    – DIDIx13
    Mar 22 at 18:33






  • 1




    jslint.com does not support latest JavaScript syntax - it's a pretty outdated site. Try ESLint instead.
    – Rene Saarsoo
    May 5 at 11:39












up vote
2
down vote

favorite
1









up vote
2
down vote

favorite
1






1





Context



This software is a countdown/visual timer. It was initially developed to display the time left before the end of an exam.




Question



My JavaScript is working but when I want to validate it by some code quality tool it keeps throwing me this error: SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode.



If any of you can improve this code and help me to improve it(even the design), I would be very grateful.



Here's the code:






'use strict'

const load = () =>
const data =

init(data)

setInterval(() =>
update(data)
render(data)
, 100)

document.querySelector('#start').onclick = event =>
start(data)


document.querySelector('#reset').onclick = event =>
reset(data)


document.querySelector('#license').onclick = showLicense


const init = data =>
data.canvas = document.querySelector('#countdown')
data.ctx = data.canvas.getContext('2d')

data.endTime = Date.now()
data.start = false
data.reset = false

data.canvas.width = data.canvas.height = 500


const update = data =>

const render = data =>
const
canvas,
ctx,
startAngle,
start
= data

ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)

let angle = Math.abs(startAngle)

ctx.save()

if (startAngle > 0)
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.scale(1, -1)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)'
else
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'


while (angle > 2 * Math.PI)
ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI)
ctx.fill()

angle -= 2 * Math.PI


ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle)
ctx.lineTo(canvas.width / 2, canvas.height / 2)
ctx.fill()

ctx.restore()


const start = data =>
const button = document.querySelector('#start')
if (data.start)
button.innerText = 'Start'
else
let hours = document.querySelector('#hours').value
let minutes = document.querySelector('#minutes').value
let seconds = document.querySelector('#seconds').value
if (hours.trim() == '') hours = 0
if (minutes.trim() == '') minutes = 0
if (seconds.trim() == '') seconds = 0

let sign
if (hours != 0)
sign = hours < 0 ? -1 : 1
else if (minutes != 0)
sign = minutes < 0 ? -1 : 1
else
sign = seconds < 0 ? -1 : 1


minutes = sign * Math.abs(minutes)
seconds = sign * Math.abs(seconds)

data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds

button.innerText = 'Pause'

data.start ^= true


const reset = data =>
data.endTime = Date.now()
data.start = false
document.querySelector('#hours').value = ''
document.querySelector('#minutes').value = ''
document.querySelector('#seconds').value = ''
document.querySelector('#start').innerText = 'Start'
data.reset = true


const showLicense = () =>
const mask = document.createElement('div')
mask.style = 'position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0, 0, 0, 0.5);z-index:1;'
mask.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)

document.body.appendChild(mask)

const message = document.createElement('div')
message.style = 'position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:2;background:#fff;padding:10px;border-radius:10px;overflow:auto;max-width:600px;max-height:500px;'
message.innerText = 'License unavailable, please report as a bug.'
message.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)


const ajax = new XMLHttpRequest()
ajax.open('GET', 'LICENSE')
ajax.onreadystatechange = () =>
console.log('AJAX');
message.innerText = ajax.responseText

ajax.send()
document.body.append(message)


const timeToAngle = endTime =>
const difference = endTime - Date.now()
return difference / 3600000 * 2 * Math.PI


const pad = (value, format) => (format + value).slice(-format.length)

load()

* 
box-sizing: border-box;


body
background: #eee;
margin: 0;


main
background: #fff;
max-width: 700px;
margin: auto;
padding: 10px;
display: flex;
flex-flow: column;
align-items: center;


h1
text-align: center;


menu
display: flex;
justify-content: space-between;
width: 500px;
padding: 0;


#hours, #minutes, #seconds
width: 30px;
text-align: center;


footer
max-width: 700px;
margin: auto;
background: #ddd;
padding: 10px;
display: flex;
justify-content: space-between;


footer a
display: inline-block;
background: #ccc;
padding: 10px;
border-radius: 10px;
color: black;
text-decoration: none;
cursor: pointer;


footer a:hover
background: #888;
color: #fff;

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Countdown</title>
<script src="countdown.js" defer></script>
<link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
<main>
<h1 contenteditable>Countdown</h1>
<canvas id="countdown"></canvas>
<menu>
<button id="reset">Reset</button>
<div class="group">
<input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
</div>
<button id="start">Start</button>
</menu>
</main>
<footer>
<a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
<a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
<a id="license">MIT license</a>
</footer>
</body>

</html>









share|improve this question













Context



This software is a countdown/visual timer. It was initially developed to display the time left before the end of an exam.




Question



My JavaScript is working but when I want to validate it by some code quality tool it keeps throwing me this error: SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode.



If any of you can improve this code and help me to improve it(even the design), I would be very grateful.



Here's the code:






'use strict'

const load = () =>
const data =

init(data)

setInterval(() =>
update(data)
render(data)
, 100)

document.querySelector('#start').onclick = event =>
start(data)


document.querySelector('#reset').onclick = event =>
reset(data)


document.querySelector('#license').onclick = showLicense


const init = data =>
data.canvas = document.querySelector('#countdown')
data.ctx = data.canvas.getContext('2d')

data.endTime = Date.now()
data.start = false
data.reset = false

data.canvas.width = data.canvas.height = 500


const update = data =>

const render = data =>
const
canvas,
ctx,
startAngle,
start
= data

ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)

let angle = Math.abs(startAngle)

ctx.save()

if (startAngle > 0)
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.scale(1, -1)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)'
else
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'


while (angle > 2 * Math.PI)
ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI)
ctx.fill()

angle -= 2 * Math.PI


ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle)
ctx.lineTo(canvas.width / 2, canvas.height / 2)
ctx.fill()

ctx.restore()


const start = data =>
const button = document.querySelector('#start')
if (data.start)
button.innerText = 'Start'
else
let hours = document.querySelector('#hours').value
let minutes = document.querySelector('#minutes').value
let seconds = document.querySelector('#seconds').value
if (hours.trim() == '') hours = 0
if (minutes.trim() == '') minutes = 0
if (seconds.trim() == '') seconds = 0

let sign
if (hours != 0)
sign = hours < 0 ? -1 : 1
else if (minutes != 0)
sign = minutes < 0 ? -1 : 1
else
sign = seconds < 0 ? -1 : 1


minutes = sign * Math.abs(minutes)
seconds = sign * Math.abs(seconds)

data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds

button.innerText = 'Pause'

data.start ^= true


const reset = data =>
data.endTime = Date.now()
data.start = false
document.querySelector('#hours').value = ''
document.querySelector('#minutes').value = ''
document.querySelector('#seconds').value = ''
document.querySelector('#start').innerText = 'Start'
data.reset = true


const showLicense = () =>
const mask = document.createElement('div')
mask.style = 'position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0, 0, 0, 0.5);z-index:1;'
mask.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)

document.body.appendChild(mask)

const message = document.createElement('div')
message.style = 'position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:2;background:#fff;padding:10px;border-radius:10px;overflow:auto;max-width:600px;max-height:500px;'
message.innerText = 'License unavailable, please report as a bug.'
message.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)


const ajax = new XMLHttpRequest()
ajax.open('GET', 'LICENSE')
ajax.onreadystatechange = () =>
console.log('AJAX');
message.innerText = ajax.responseText

ajax.send()
document.body.append(message)


const timeToAngle = endTime =>
const difference = endTime - Date.now()
return difference / 3600000 * 2 * Math.PI


const pad = (value, format) => (format + value).slice(-format.length)

load()

* 
box-sizing: border-box;


body
background: #eee;
margin: 0;


main
background: #fff;
max-width: 700px;
margin: auto;
padding: 10px;
display: flex;
flex-flow: column;
align-items: center;


h1
text-align: center;


menu
display: flex;
justify-content: space-between;
width: 500px;
padding: 0;


#hours, #minutes, #seconds
width: 30px;
text-align: center;


footer
max-width: 700px;
margin: auto;
background: #ddd;
padding: 10px;
display: flex;
justify-content: space-between;


footer a
display: inline-block;
background: #ccc;
padding: 10px;
border-radius: 10px;
color: black;
text-decoration: none;
cursor: pointer;


footer a:hover
background: #888;
color: #fff;

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Countdown</title>
<script src="countdown.js" defer></script>
<link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
<main>
<h1 contenteditable>Countdown</h1>
<canvas id="countdown"></canvas>
<menu>
<button id="reset">Reset</button>
<div class="group">
<input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
</div>
<button id="start">Start</button>
</menu>
</main>
<footer>
<a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
<a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
<a id="license">MIT license</a>
</footer>
</body>

</html>








'use strict'

const load = () =>
const data =

init(data)

setInterval(() =>
update(data)
render(data)
, 100)

document.querySelector('#start').onclick = event =>
start(data)


document.querySelector('#reset').onclick = event =>
reset(data)


document.querySelector('#license').onclick = showLicense


const init = data =>
data.canvas = document.querySelector('#countdown')
data.ctx = data.canvas.getContext('2d')

data.endTime = Date.now()
data.start = false
data.reset = false

data.canvas.width = data.canvas.height = 500


const update = data =>

const render = data =>
const
canvas,
ctx,
startAngle,
start
= data

ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)

let angle = Math.abs(startAngle)

ctx.save()

if (startAngle > 0)
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.scale(1, -1)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)'
else
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'


while (angle > 2 * Math.PI)
ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI)
ctx.fill()

angle -= 2 * Math.PI


ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle)
ctx.lineTo(canvas.width / 2, canvas.height / 2)
ctx.fill()

ctx.restore()


const start = data =>
const button = document.querySelector('#start')
if (data.start)
button.innerText = 'Start'
else
let hours = document.querySelector('#hours').value
let minutes = document.querySelector('#minutes').value
let seconds = document.querySelector('#seconds').value
if (hours.trim() == '') hours = 0
if (minutes.trim() == '') minutes = 0
if (seconds.trim() == '') seconds = 0

let sign
if (hours != 0)
sign = hours < 0 ? -1 : 1
else if (minutes != 0)
sign = minutes < 0 ? -1 : 1
else
sign = seconds < 0 ? -1 : 1


minutes = sign * Math.abs(minutes)
seconds = sign * Math.abs(seconds)

data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds

button.innerText = 'Pause'

data.start ^= true


const reset = data =>
data.endTime = Date.now()
data.start = false
document.querySelector('#hours').value = ''
document.querySelector('#minutes').value = ''
document.querySelector('#seconds').value = ''
document.querySelector('#start').innerText = 'Start'
data.reset = true


const showLicense = () =>
const mask = document.createElement('div')
mask.style = 'position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0, 0, 0, 0.5);z-index:1;'
mask.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)

document.body.appendChild(mask)

const message = document.createElement('div')
message.style = 'position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:2;background:#fff;padding:10px;border-radius:10px;overflow:auto;max-width:600px;max-height:500px;'
message.innerText = 'License unavailable, please report as a bug.'
message.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)


const ajax = new XMLHttpRequest()
ajax.open('GET', 'LICENSE')
ajax.onreadystatechange = () =>
console.log('AJAX');
message.innerText = ajax.responseText

ajax.send()
document.body.append(message)


const timeToAngle = endTime =>
const difference = endTime - Date.now()
return difference / 3600000 * 2 * Math.PI


const pad = (value, format) => (format + value).slice(-format.length)

load()

* 
box-sizing: border-box;


body
background: #eee;
margin: 0;


main
background: #fff;
max-width: 700px;
margin: auto;
padding: 10px;
display: flex;
flex-flow: column;
align-items: center;


h1
text-align: center;


menu
display: flex;
justify-content: space-between;
width: 500px;
padding: 0;


#hours, #minutes, #seconds
width: 30px;
text-align: center;


footer
max-width: 700px;
margin: auto;
background: #ddd;
padding: 10px;
display: flex;
justify-content: space-between;


footer a
display: inline-block;
background: #ccc;
padding: 10px;
border-radius: 10px;
color: black;
text-decoration: none;
cursor: pointer;


footer a:hover
background: #888;
color: #fff;

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Countdown</title>
<script src="countdown.js" defer></script>
<link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
<main>
<h1 contenteditable>Countdown</h1>
<canvas id="countdown"></canvas>
<menu>
<button id="reset">Reset</button>
<div class="group">
<input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
</div>
<button id="start">Start</button>
</menu>
</main>
<footer>
<a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
<a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
<a id="license">MIT license</a>
</footer>
</body>

</html>





'use strict'

const load = () =>
const data =

init(data)

setInterval(() =>
update(data)
render(data)
, 100)

document.querySelector('#start').onclick = event =>
start(data)


document.querySelector('#reset').onclick = event =>
reset(data)


document.querySelector('#license').onclick = showLicense


const init = data =>
data.canvas = document.querySelector('#countdown')
data.ctx = data.canvas.getContext('2d')

data.endTime = Date.now()
data.start = false
data.reset = false

data.canvas.width = data.canvas.height = 500


const update = data =>

const render = data =>
const
canvas,
ctx,
startAngle,
start
= data

ctx.fillStyle = '#fff'
ctx.fillRect(0, 0, canvas.width, canvas.height)

let angle = Math.abs(startAngle)

ctx.save()

if (startAngle > 0)
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.scale(1, -1)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)'
else
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.rotate(-Math.PI / 2)
ctx.translate(-canvas.width / 2, -canvas.height / 2)
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'


while (angle > 2 * Math.PI)
ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI)
ctx.fill()

angle -= 2 * Math.PI


ctx.beginPath()
ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle)
ctx.lineTo(canvas.width / 2, canvas.height / 2)
ctx.fill()

ctx.restore()


const start = data =>
const button = document.querySelector('#start')
if (data.start)
button.innerText = 'Start'
else
let hours = document.querySelector('#hours').value
let minutes = document.querySelector('#minutes').value
let seconds = document.querySelector('#seconds').value
if (hours.trim() == '') hours = 0
if (minutes.trim() == '') minutes = 0
if (seconds.trim() == '') seconds = 0

let sign
if (hours != 0)
sign = hours < 0 ? -1 : 1
else if (minutes != 0)
sign = minutes < 0 ? -1 : 1
else
sign = seconds < 0 ? -1 : 1


minutes = sign * Math.abs(minutes)
seconds = sign * Math.abs(seconds)

data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds

button.innerText = 'Pause'

data.start ^= true


const reset = data =>
data.endTime = Date.now()
data.start = false
document.querySelector('#hours').value = ''
document.querySelector('#minutes').value = ''
document.querySelector('#seconds').value = ''
document.querySelector('#start').innerText = 'Start'
data.reset = true


const showLicense = () =>
const mask = document.createElement('div')
mask.style = 'position:fixed;left:0;right:0;top:0;bottom:0;background:rgba(0, 0, 0, 0.5);z-index:1;'
mask.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)

document.body.appendChild(mask)

const message = document.createElement('div')
message.style = 'position:fixed;left:50%;top:50%;transform:translate(-50%, -50%);z-index:2;background:#fff;padding:10px;border-radius:10px;overflow:auto;max-width:600px;max-height:500px;'
message.innerText = 'License unavailable, please report as a bug.'
message.onclick = () =>
document.body.removeChild(mask)
document.body.removeChild(message)


const ajax = new XMLHttpRequest()
ajax.open('GET', 'LICENSE')
ajax.onreadystatechange = () =>
console.log('AJAX');
message.innerText = ajax.responseText

ajax.send()
document.body.append(message)


const timeToAngle = endTime =>
const difference = endTime - Date.now()
return difference / 3600000 * 2 * Math.PI


const pad = (value, format) => (format + value).slice(-format.length)

load()

* 
box-sizing: border-box;


body
background: #eee;
margin: 0;


main
background: #fff;
max-width: 700px;
margin: auto;
padding: 10px;
display: flex;
flex-flow: column;
align-items: center;


h1
text-align: center;


menu
display: flex;
justify-content: space-between;
width: 500px;
padding: 0;


#hours, #minutes, #seconds
width: 30px;
text-align: center;


footer
max-width: 700px;
margin: auto;
background: #ddd;
padding: 10px;
display: flex;
justify-content: space-between;


footer a
display: inline-block;
background: #ccc;
padding: 10px;
border-radius: 10px;
color: black;
text-decoration: none;
cursor: pointer;


footer a:hover
background: #888;
color: #fff;

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>Countdown</title>
<script src="countdown.js" defer></script>
<link rel="stylesheet" href="style.css" type="text/css">
</head>

<body>
<main>
<h1 contenteditable>Countdown</h1>
<canvas id="countdown"></canvas>
<menu>
<button id="reset">Reset</button>
<div class="group">
<input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
</div>
<button id="start">Start</button>
</menu>
</main>
<footer>
<a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
<a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
<a id="license">MIT license</a>
</footer>
</body>

</html>








share|improve this question












share|improve this question




share|improve this question








edited May 7 at 16:12









Sam Onela

5,82961544




5,82961544









asked Mar 22 at 16:23









DIDIx13

1186




1186







  • 1




    You're using a browser version that doesn't support const when in strict mode, most likely a Safari version prior to 10. Simple fix is to just use var or transpile with babel. See this StackOverflow question. I'd say this question is also better placed over at the Stack Overflow site.
    – Sven
    Mar 22 at 17:59










  • I've edited the title and I don't know why it can't pass jslint.com or other validators will keep throwing the same error(I'm pretty lost.) @Svenskunganka
    – DIDIx13
    Mar 22 at 18:33






  • 1




    jslint.com does not support latest JavaScript syntax - it's a pretty outdated site. Try ESLint instead.
    – Rene Saarsoo
    May 5 at 11:39












  • 1




    You're using a browser version that doesn't support const when in strict mode, most likely a Safari version prior to 10. Simple fix is to just use var or transpile with babel. See this StackOverflow question. I'd say this question is also better placed over at the Stack Overflow site.
    – Sven
    Mar 22 at 17:59










  • I've edited the title and I don't know why it can't pass jslint.com or other validators will keep throwing the same error(I'm pretty lost.) @Svenskunganka
    – DIDIx13
    Mar 22 at 18:33






  • 1




    jslint.com does not support latest JavaScript syntax - it's a pretty outdated site. Try ESLint instead.
    – Rene Saarsoo
    May 5 at 11:39







1




1




You're using a browser version that doesn't support const when in strict mode, most likely a Safari version prior to 10. Simple fix is to just use var or transpile with babel. See this StackOverflow question. I'd say this question is also better placed over at the Stack Overflow site.
– Sven
Mar 22 at 17:59




You're using a browser version that doesn't support const when in strict mode, most likely a Safari version prior to 10. Simple fix is to just use var or transpile with babel. See this StackOverflow question. I'd say this question is also better placed over at the Stack Overflow site.
– Sven
Mar 22 at 17:59












I've edited the title and I don't know why it can't pass jslint.com or other validators will keep throwing the same error(I'm pretty lost.) @Svenskunganka
– DIDIx13
Mar 22 at 18:33




I've edited the title and I don't know why it can't pass jslint.com or other validators will keep throwing the same error(I'm pretty lost.) @Svenskunganka
– DIDIx13
Mar 22 at 18:33




1




1




jslint.com does not support latest JavaScript syntax - it's a pretty outdated site. Try ESLint instead.
– Rene Saarsoo
May 5 at 11:39




jslint.com does not support latest JavaScript syntax - it's a pretty outdated site. Try ESLint instead.
– Rene Saarsoo
May 5 at 11:39










2 Answers
2






active

oldest

votes

















up vote
2
down vote













You're passing your app state as the parameter data to almost all the functions.



This suggests you're better off combining these functions into a class, where you could assign these values to this which would be automatically accessible from all methods in class.



Alternatively, if this all is a tiny app, you could just use global variables, which too would be accessible from all functions.






share|improve this answer




























    up vote
    1
    down vote













    Review points



    • Fetching DOM elements is not cheap, so cache those in a variable (perhaps in data) instead of accessing them each time.

    • When fetching DOM elements by id attribute, use document.getElementById() instead of document.querySelector('#') refer to answers to this SO question and the relevant jsPerf test



    • An event delegate can reduce the number of click handlers needed - the example snippet below uses Function.bind() to create partially applied functions for a simple event delegate - if you didn't use an event delegate, the click handlers like:




      document.querySelector('#start').onclick = event => 
      start(data)




      Could be simplified like this:



      document.querySelector('#start').onclick = start.bind(null, data)


    • Unless you fully understand the ways Automatic semicolon insertion can be broken by certain statements, add semi-colons to terminate the lines.

    • The AJAX statechange handler (i.e. registered via onreadystatechange) doesn't check the readyState and status properties of the request, and thus the innerText property of message will likely be updated before desired (e.g. during request open, transmission, loading, etc.)

    Rewrite



    Below is what one could do with the advice above.






    'use strict'

    const load = () =>
    const data = ;

    init(data);

    setInterval(() =>
    update(data);
    render(data);
    , 100);
    const mapping =
    "start": start.bind(null, data),
    "reset": reset.bind(null, data),
    "license": showLicense
    ;
    const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
    document.body.addEventListener('click', clickHandler);


    const init = data =>
    data.canvas = document.getElementById('countdown');
    data.ctx = data.canvas.getContext('2d');

    data.endTime = Date.now();
    data.start = false;
    data.reset = false;

    data.canvas.width = data.canvas.height = 500;

    const inputs = ['hours', 'minutes', 'seconds'];
    inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
    data.startButton = document.getElementById('start');


    const update = data =>

    const render = data =>
    const
    canvas,
    ctx,
    startAngle,
    start
    = data;

    ctx.fillStyle = '#fff';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    let angle = Math.abs(startAngle);

    ctx.save();

    if (startAngle > 0)
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate(-Math.PI / 2);
    ctx.scale(1, -1);
    ctx.translate(-canvas.width / 2, -canvas.height / 2);
    ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
    else
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate(-Math.PI / 2);
    ctx.translate(-canvas.width / 2, -canvas.height / 2);
    ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';


    while (angle > 2 * Math.PI)
    ctx.beginPath();
    ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
    ctx.fill();

    angle -= 2 * Math.PI;


    ctx.beginPath();
    ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
    ctx.lineTo(canvas.width / 2, canvas.height / 2);
    ctx.fill();

    ctx.restore();


    const start = data =>
    if (data.start)
    data.startButton.innerText = 'Start';
    else
    let hours = data.hoursInput.value;
    let minutes = data.minutesInput.value;
    let seconds = data.secondsInput.value;
    if (hours.trim() == '') hours = 0;
    if (minutes.trim() == '') minutes = 0;
    if (seconds.trim() == '') seconds = 0;

    let sign;
    if (hours != 0)
    sign = hours < 0 ? -1 : 1;
    else if (minutes != 0)
    sign = minutes < 0 ? -1 : 1;
    else
    sign = seconds < 0 ? -1 : 1;


    minutes = sign * Math.abs(minutes);
    seconds = sign * Math.abs(seconds);

    data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

    data.startButton.innerText = 'Pause';

    data.start ^= true;


    const reset = data =>
    data.endTime = Date.now();
    data.start = false;
    data.hoursInput.value = '';
    data.minutesInput.value = '';
    data.secondsInput.value = '';
    data.startButton.innerText = 'Start';
    data.reset = true;


    const showLicense = () =>
    const mask = document.createElement('div');
    mask.id = 'mask';
    mask.onclick = () =>
    document.body.removeChild(mask);
    document.body.removeChild(message);

    document.body.appendChild(mask);

    const message = document.createElement('div');
    message.id = 'messageContainer';
    message.innerText = 'License unavailable, please report as a bug.';
    message.onclick = () =>
    document.body.removeChild(mask);
    document.body.removeChild(message);


    const ajax = new XMLHttpRequest();
    ajax.open('GET', '/');
    ajax.onreadystatechange = () =>
    //check state, this doesn't make sense here in this snippet
    if (ajax.readyState === 4 && ajax.status === 200)
    //message.innerText = ajax.responseText

    ;
    ajax.send();
    document.body.append(message);


    const timeToAngle = endTime =>
    const difference = endTime - Date.now();
    return difference / 3600000 * 2 * Math.PI;


    const pad = (value, format) => (format + value).slice(-format.length);

    load();

    * 
    box-sizing: border-box;


    body
    background: #eee;
    margin: 0;


    main
    background: #fff;
    max-width: 700px;
    margin: auto;
    padding: 10px;
    display: flex;
    flex-flow: column;
    align-items: center;


    h1
    text-align: center;


    menu
    display: flex;
    justify-content: space-between;
    width: 500px;
    padding: 0;


    #hours,
    #minutes,
    #seconds
    width: 30px;
    text-align: center;


    footer
    max-width: 700px;
    margin: auto;
    background: #ddd;
    padding: 10px;
    display: flex;
    justify-content: space-between;


    footer a
    display: inline-block;
    background: #ccc;
    padding: 10px;
    border-radius: 10px;
    color: black;
    text-decoration: none;
    cursor: pointer;


    footer a:hover
    background: #888;
    color: #fff;


    #mask
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 1;


    #messageContainer
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 2;
    background: #fff;
    padding: 10px;
    border-radius: 10px;
    overflow: auto;
    max-width: 600px;
    max-height: 500px;

    <main>
    <h1 contenteditable>Countdown</h1>
    <canvas id="countdown"></canvas>
    <menu>
    <button id="reset">Reset</button>
    <div class="group">
    <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
    </div>
    <button id="start">Start</button>
    </menu>
    </main>
    <footer>
    <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
    <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
    <a id="license">MIT license</a>
    </footer>








    share|improve this answer























      Your Answer




      StackExchange.ifUsing("editor", function ()
      return StackExchange.using("mathjaxEditing", function ()
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      );
      );
      , "mathjax-editing");

      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "196"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );








       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190220%2fdisplay-the-time-left-of-a-given-time%23new-answer', 'question_page');

      );

      Post as a guest






























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      2
      down vote













      You're passing your app state as the parameter data to almost all the functions.



      This suggests you're better off combining these functions into a class, where you could assign these values to this which would be automatically accessible from all methods in class.



      Alternatively, if this all is a tiny app, you could just use global variables, which too would be accessible from all functions.






      share|improve this answer

























        up vote
        2
        down vote













        You're passing your app state as the parameter data to almost all the functions.



        This suggests you're better off combining these functions into a class, where you could assign these values to this which would be automatically accessible from all methods in class.



        Alternatively, if this all is a tiny app, you could just use global variables, which too would be accessible from all functions.






        share|improve this answer























          up vote
          2
          down vote










          up vote
          2
          down vote









          You're passing your app state as the parameter data to almost all the functions.



          This suggests you're better off combining these functions into a class, where you could assign these values to this which would be automatically accessible from all methods in class.



          Alternatively, if this all is a tiny app, you could just use global variables, which too would be accessible from all functions.






          share|improve this answer













          You're passing your app state as the parameter data to almost all the functions.



          This suggests you're better off combining these functions into a class, where you could assign these values to this which would be automatically accessible from all methods in class.



          Alternatively, if this all is a tiny app, you could just use global variables, which too would be accessible from all functions.







          share|improve this answer













          share|improve this answer



          share|improve this answer











          answered May 5 at 11:49









          Rene Saarsoo

          2,016714




          2,016714






















              up vote
              1
              down vote













              Review points



              • Fetching DOM elements is not cheap, so cache those in a variable (perhaps in data) instead of accessing them each time.

              • When fetching DOM elements by id attribute, use document.getElementById() instead of document.querySelector('#') refer to answers to this SO question and the relevant jsPerf test



              • An event delegate can reduce the number of click handlers needed - the example snippet below uses Function.bind() to create partially applied functions for a simple event delegate - if you didn't use an event delegate, the click handlers like:




                document.querySelector('#start').onclick = event => 
                start(data)




                Could be simplified like this:



                document.querySelector('#start').onclick = start.bind(null, data)


              • Unless you fully understand the ways Automatic semicolon insertion can be broken by certain statements, add semi-colons to terminate the lines.

              • The AJAX statechange handler (i.e. registered via onreadystatechange) doesn't check the readyState and status properties of the request, and thus the innerText property of message will likely be updated before desired (e.g. during request open, transmission, loading, etc.)

              Rewrite



              Below is what one could do with the advice above.






              'use strict'

              const load = () =>
              const data = ;

              init(data);

              setInterval(() =>
              update(data);
              render(data);
              , 100);
              const mapping =
              "start": start.bind(null, data),
              "reset": reset.bind(null, data),
              "license": showLicense
              ;
              const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
              document.body.addEventListener('click', clickHandler);


              const init = data =>
              data.canvas = document.getElementById('countdown');
              data.ctx = data.canvas.getContext('2d');

              data.endTime = Date.now();
              data.start = false;
              data.reset = false;

              data.canvas.width = data.canvas.height = 500;

              const inputs = ['hours', 'minutes', 'seconds'];
              inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
              data.startButton = document.getElementById('start');


              const update = data =>

              const render = data =>
              const
              canvas,
              ctx,
              startAngle,
              start
              = data;

              ctx.fillStyle = '#fff';
              ctx.fillRect(0, 0, canvas.width, canvas.height);

              let angle = Math.abs(startAngle);

              ctx.save();

              if (startAngle > 0)
              ctx.translate(canvas.width / 2, canvas.height / 2);
              ctx.rotate(-Math.PI / 2);
              ctx.scale(1, -1);
              ctx.translate(-canvas.width / 2, -canvas.height / 2);
              ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
              else
              ctx.translate(canvas.width / 2, canvas.height / 2);
              ctx.rotate(-Math.PI / 2);
              ctx.translate(-canvas.width / 2, -canvas.height / 2);
              ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';


              while (angle > 2 * Math.PI)
              ctx.beginPath();
              ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
              ctx.fill();

              angle -= 2 * Math.PI;


              ctx.beginPath();
              ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
              ctx.lineTo(canvas.width / 2, canvas.height / 2);
              ctx.fill();

              ctx.restore();


              const start = data =>
              if (data.start)
              data.startButton.innerText = 'Start';
              else
              let hours = data.hoursInput.value;
              let minutes = data.minutesInput.value;
              let seconds = data.secondsInput.value;
              if (hours.trim() == '') hours = 0;
              if (minutes.trim() == '') minutes = 0;
              if (seconds.trim() == '') seconds = 0;

              let sign;
              if (hours != 0)
              sign = hours < 0 ? -1 : 1;
              else if (minutes != 0)
              sign = minutes < 0 ? -1 : 1;
              else
              sign = seconds < 0 ? -1 : 1;


              minutes = sign * Math.abs(minutes);
              seconds = sign * Math.abs(seconds);

              data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

              data.startButton.innerText = 'Pause';

              data.start ^= true;


              const reset = data =>
              data.endTime = Date.now();
              data.start = false;
              data.hoursInput.value = '';
              data.minutesInput.value = '';
              data.secondsInput.value = '';
              data.startButton.innerText = 'Start';
              data.reset = true;


              const showLicense = () =>
              const mask = document.createElement('div');
              mask.id = 'mask';
              mask.onclick = () =>
              document.body.removeChild(mask);
              document.body.removeChild(message);

              document.body.appendChild(mask);

              const message = document.createElement('div');
              message.id = 'messageContainer';
              message.innerText = 'License unavailable, please report as a bug.';
              message.onclick = () =>
              document.body.removeChild(mask);
              document.body.removeChild(message);


              const ajax = new XMLHttpRequest();
              ajax.open('GET', '/');
              ajax.onreadystatechange = () =>
              //check state, this doesn't make sense here in this snippet
              if (ajax.readyState === 4 && ajax.status === 200)
              //message.innerText = ajax.responseText

              ;
              ajax.send();
              document.body.append(message);


              const timeToAngle = endTime =>
              const difference = endTime - Date.now();
              return difference / 3600000 * 2 * Math.PI;


              const pad = (value, format) => (format + value).slice(-format.length);

              load();

              * 
              box-sizing: border-box;


              body
              background: #eee;
              margin: 0;


              main
              background: #fff;
              max-width: 700px;
              margin: auto;
              padding: 10px;
              display: flex;
              flex-flow: column;
              align-items: center;


              h1
              text-align: center;


              menu
              display: flex;
              justify-content: space-between;
              width: 500px;
              padding: 0;


              #hours,
              #minutes,
              #seconds
              width: 30px;
              text-align: center;


              footer
              max-width: 700px;
              margin: auto;
              background: #ddd;
              padding: 10px;
              display: flex;
              justify-content: space-between;


              footer a
              display: inline-block;
              background: #ccc;
              padding: 10px;
              border-radius: 10px;
              color: black;
              text-decoration: none;
              cursor: pointer;


              footer a:hover
              background: #888;
              color: #fff;


              #mask
              position: fixed;
              left: 0;
              right: 0;
              top: 0;
              bottom: 0;
              background: rgba(0, 0, 0, 0.5);
              z-index: 1;


              #messageContainer
              position: fixed;
              left: 50%;
              top: 50%;
              transform: translate(-50%, -50%);
              z-index: 2;
              background: #fff;
              padding: 10px;
              border-radius: 10px;
              overflow: auto;
              max-width: 600px;
              max-height: 500px;

              <main>
              <h1 contenteditable>Countdown</h1>
              <canvas id="countdown"></canvas>
              <menu>
              <button id="reset">Reset</button>
              <div class="group">
              <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
              </div>
              <button id="start">Start</button>
              </menu>
              </main>
              <footer>
              <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
              <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
              <a id="license">MIT license</a>
              </footer>








              share|improve this answer



























                up vote
                1
                down vote













                Review points



                • Fetching DOM elements is not cheap, so cache those in a variable (perhaps in data) instead of accessing them each time.

                • When fetching DOM elements by id attribute, use document.getElementById() instead of document.querySelector('#') refer to answers to this SO question and the relevant jsPerf test



                • An event delegate can reduce the number of click handlers needed - the example snippet below uses Function.bind() to create partially applied functions for a simple event delegate - if you didn't use an event delegate, the click handlers like:




                  document.querySelector('#start').onclick = event => 
                  start(data)




                  Could be simplified like this:



                  document.querySelector('#start').onclick = start.bind(null, data)


                • Unless you fully understand the ways Automatic semicolon insertion can be broken by certain statements, add semi-colons to terminate the lines.

                • The AJAX statechange handler (i.e. registered via onreadystatechange) doesn't check the readyState and status properties of the request, and thus the innerText property of message will likely be updated before desired (e.g. during request open, transmission, loading, etc.)

                Rewrite



                Below is what one could do with the advice above.






                'use strict'

                const load = () =>
                const data = ;

                init(data);

                setInterval(() =>
                update(data);
                render(data);
                , 100);
                const mapping =
                "start": start.bind(null, data),
                "reset": reset.bind(null, data),
                "license": showLicense
                ;
                const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
                document.body.addEventListener('click', clickHandler);


                const init = data =>
                data.canvas = document.getElementById('countdown');
                data.ctx = data.canvas.getContext('2d');

                data.endTime = Date.now();
                data.start = false;
                data.reset = false;

                data.canvas.width = data.canvas.height = 500;

                const inputs = ['hours', 'minutes', 'seconds'];
                inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
                data.startButton = document.getElementById('start');


                const update = data =>

                const render = data =>
                const
                canvas,
                ctx,
                startAngle,
                start
                = data;

                ctx.fillStyle = '#fff';
                ctx.fillRect(0, 0, canvas.width, canvas.height);

                let angle = Math.abs(startAngle);

                ctx.save();

                if (startAngle > 0)
                ctx.translate(canvas.width / 2, canvas.height / 2);
                ctx.rotate(-Math.PI / 2);
                ctx.scale(1, -1);
                ctx.translate(-canvas.width / 2, -canvas.height / 2);
                ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
                else
                ctx.translate(canvas.width / 2, canvas.height / 2);
                ctx.rotate(-Math.PI / 2);
                ctx.translate(-canvas.width / 2, -canvas.height / 2);
                ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';


                while (angle > 2 * Math.PI)
                ctx.beginPath();
                ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
                ctx.fill();

                angle -= 2 * Math.PI;


                ctx.beginPath();
                ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
                ctx.lineTo(canvas.width / 2, canvas.height / 2);
                ctx.fill();

                ctx.restore();


                const start = data =>
                if (data.start)
                data.startButton.innerText = 'Start';
                else
                let hours = data.hoursInput.value;
                let minutes = data.minutesInput.value;
                let seconds = data.secondsInput.value;
                if (hours.trim() == '') hours = 0;
                if (minutes.trim() == '') minutes = 0;
                if (seconds.trim() == '') seconds = 0;

                let sign;
                if (hours != 0)
                sign = hours < 0 ? -1 : 1;
                else if (minutes != 0)
                sign = minutes < 0 ? -1 : 1;
                else
                sign = seconds < 0 ? -1 : 1;


                minutes = sign * Math.abs(minutes);
                seconds = sign * Math.abs(seconds);

                data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

                data.startButton.innerText = 'Pause';

                data.start ^= true;


                const reset = data =>
                data.endTime = Date.now();
                data.start = false;
                data.hoursInput.value = '';
                data.minutesInput.value = '';
                data.secondsInput.value = '';
                data.startButton.innerText = 'Start';
                data.reset = true;


                const showLicense = () =>
                const mask = document.createElement('div');
                mask.id = 'mask';
                mask.onclick = () =>
                document.body.removeChild(mask);
                document.body.removeChild(message);

                document.body.appendChild(mask);

                const message = document.createElement('div');
                message.id = 'messageContainer';
                message.innerText = 'License unavailable, please report as a bug.';
                message.onclick = () =>
                document.body.removeChild(mask);
                document.body.removeChild(message);


                const ajax = new XMLHttpRequest();
                ajax.open('GET', '/');
                ajax.onreadystatechange = () =>
                //check state, this doesn't make sense here in this snippet
                if (ajax.readyState === 4 && ajax.status === 200)
                //message.innerText = ajax.responseText

                ;
                ajax.send();
                document.body.append(message);


                const timeToAngle = endTime =>
                const difference = endTime - Date.now();
                return difference / 3600000 * 2 * Math.PI;


                const pad = (value, format) => (format + value).slice(-format.length);

                load();

                * 
                box-sizing: border-box;


                body
                background: #eee;
                margin: 0;


                main
                background: #fff;
                max-width: 700px;
                margin: auto;
                padding: 10px;
                display: flex;
                flex-flow: column;
                align-items: center;


                h1
                text-align: center;


                menu
                display: flex;
                justify-content: space-between;
                width: 500px;
                padding: 0;


                #hours,
                #minutes,
                #seconds
                width: 30px;
                text-align: center;


                footer
                max-width: 700px;
                margin: auto;
                background: #ddd;
                padding: 10px;
                display: flex;
                justify-content: space-between;


                footer a
                display: inline-block;
                background: #ccc;
                padding: 10px;
                border-radius: 10px;
                color: black;
                text-decoration: none;
                cursor: pointer;


                footer a:hover
                background: #888;
                color: #fff;


                #mask
                position: fixed;
                left: 0;
                right: 0;
                top: 0;
                bottom: 0;
                background: rgba(0, 0, 0, 0.5);
                z-index: 1;


                #messageContainer
                position: fixed;
                left: 50%;
                top: 50%;
                transform: translate(-50%, -50%);
                z-index: 2;
                background: #fff;
                padding: 10px;
                border-radius: 10px;
                overflow: auto;
                max-width: 600px;
                max-height: 500px;

                <main>
                <h1 contenteditable>Countdown</h1>
                <canvas id="countdown"></canvas>
                <menu>
                <button id="reset">Reset</button>
                <div class="group">
                <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
                </div>
                <button id="start">Start</button>
                </menu>
                </main>
                <footer>
                <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
                <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
                <a id="license">MIT license</a>
                </footer>








                share|improve this answer

























                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  Review points



                  • Fetching DOM elements is not cheap, so cache those in a variable (perhaps in data) instead of accessing them each time.

                  • When fetching DOM elements by id attribute, use document.getElementById() instead of document.querySelector('#') refer to answers to this SO question and the relevant jsPerf test



                  • An event delegate can reduce the number of click handlers needed - the example snippet below uses Function.bind() to create partially applied functions for a simple event delegate - if you didn't use an event delegate, the click handlers like:




                    document.querySelector('#start').onclick = event => 
                    start(data)




                    Could be simplified like this:



                    document.querySelector('#start').onclick = start.bind(null, data)


                  • Unless you fully understand the ways Automatic semicolon insertion can be broken by certain statements, add semi-colons to terminate the lines.

                  • The AJAX statechange handler (i.e. registered via onreadystatechange) doesn't check the readyState and status properties of the request, and thus the innerText property of message will likely be updated before desired (e.g. during request open, transmission, loading, etc.)

                  Rewrite



                  Below is what one could do with the advice above.






                  'use strict'

                  const load = () =>
                  const data = ;

                  init(data);

                  setInterval(() =>
                  update(data);
                  render(data);
                  , 100);
                  const mapping =
                  "start": start.bind(null, data),
                  "reset": reset.bind(null, data),
                  "license": showLicense
                  ;
                  const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
                  document.body.addEventListener('click', clickHandler);


                  const init = data =>
                  data.canvas = document.getElementById('countdown');
                  data.ctx = data.canvas.getContext('2d');

                  data.endTime = Date.now();
                  data.start = false;
                  data.reset = false;

                  data.canvas.width = data.canvas.height = 500;

                  const inputs = ['hours', 'minutes', 'seconds'];
                  inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
                  data.startButton = document.getElementById('start');


                  const update = data =>

                  const render = data =>
                  const
                  canvas,
                  ctx,
                  startAngle,
                  start
                  = data;

                  ctx.fillStyle = '#fff';
                  ctx.fillRect(0, 0, canvas.width, canvas.height);

                  let angle = Math.abs(startAngle);

                  ctx.save();

                  if (startAngle > 0)
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.scale(1, -1);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
                  else
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';


                  while (angle > 2 * Math.PI)
                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
                  ctx.fill();

                  angle -= 2 * Math.PI;


                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
                  ctx.lineTo(canvas.width / 2, canvas.height / 2);
                  ctx.fill();

                  ctx.restore();


                  const start = data =>
                  if (data.start)
                  data.startButton.innerText = 'Start';
                  else
                  let hours = data.hoursInput.value;
                  let minutes = data.minutesInput.value;
                  let seconds = data.secondsInput.value;
                  if (hours.trim() == '') hours = 0;
                  if (minutes.trim() == '') minutes = 0;
                  if (seconds.trim() == '') seconds = 0;

                  let sign;
                  if (hours != 0)
                  sign = hours < 0 ? -1 : 1;
                  else if (minutes != 0)
                  sign = minutes < 0 ? -1 : 1;
                  else
                  sign = seconds < 0 ? -1 : 1;


                  minutes = sign * Math.abs(minutes);
                  seconds = sign * Math.abs(seconds);

                  data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

                  data.startButton.innerText = 'Pause';

                  data.start ^= true;


                  const reset = data =>
                  data.endTime = Date.now();
                  data.start = false;
                  data.hoursInput.value = '';
                  data.minutesInput.value = '';
                  data.secondsInput.value = '';
                  data.startButton.innerText = 'Start';
                  data.reset = true;


                  const showLicense = () =>
                  const mask = document.createElement('div');
                  mask.id = 'mask';
                  mask.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);

                  document.body.appendChild(mask);

                  const message = document.createElement('div');
                  message.id = 'messageContainer';
                  message.innerText = 'License unavailable, please report as a bug.';
                  message.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);


                  const ajax = new XMLHttpRequest();
                  ajax.open('GET', '/');
                  ajax.onreadystatechange = () =>
                  //check state, this doesn't make sense here in this snippet
                  if (ajax.readyState === 4 && ajax.status === 200)
                  //message.innerText = ajax.responseText

                  ;
                  ajax.send();
                  document.body.append(message);


                  const timeToAngle = endTime =>
                  const difference = endTime - Date.now();
                  return difference / 3600000 * 2 * Math.PI;


                  const pad = (value, format) => (format + value).slice(-format.length);

                  load();

                  * 
                  box-sizing: border-box;


                  body
                  background: #eee;
                  margin: 0;


                  main
                  background: #fff;
                  max-width: 700px;
                  margin: auto;
                  padding: 10px;
                  display: flex;
                  flex-flow: column;
                  align-items: center;


                  h1
                  text-align: center;


                  menu
                  display: flex;
                  justify-content: space-between;
                  width: 500px;
                  padding: 0;


                  #hours,
                  #minutes,
                  #seconds
                  width: 30px;
                  text-align: center;


                  footer
                  max-width: 700px;
                  margin: auto;
                  background: #ddd;
                  padding: 10px;
                  display: flex;
                  justify-content: space-between;


                  footer a
                  display: inline-block;
                  background: #ccc;
                  padding: 10px;
                  border-radius: 10px;
                  color: black;
                  text-decoration: none;
                  cursor: pointer;


                  footer a:hover
                  background: #888;
                  color: #fff;


                  #mask
                  position: fixed;
                  left: 0;
                  right: 0;
                  top: 0;
                  bottom: 0;
                  background: rgba(0, 0, 0, 0.5);
                  z-index: 1;


                  #messageContainer
                  position: fixed;
                  left: 50%;
                  top: 50%;
                  transform: translate(-50%, -50%);
                  z-index: 2;
                  background: #fff;
                  padding: 10px;
                  border-radius: 10px;
                  overflow: auto;
                  max-width: 600px;
                  max-height: 500px;

                  <main>
                  <h1 contenteditable>Countdown</h1>
                  <canvas id="countdown"></canvas>
                  <menu>
                  <button id="reset">Reset</button>
                  <div class="group">
                  <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
                  </div>
                  <button id="start">Start</button>
                  </menu>
                  </main>
                  <footer>
                  <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
                  <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
                  <a id="license">MIT license</a>
                  </footer>








                  share|improve this answer















                  Review points



                  • Fetching DOM elements is not cheap, so cache those in a variable (perhaps in data) instead of accessing them each time.

                  • When fetching DOM elements by id attribute, use document.getElementById() instead of document.querySelector('#') refer to answers to this SO question and the relevant jsPerf test



                  • An event delegate can reduce the number of click handlers needed - the example snippet below uses Function.bind() to create partially applied functions for a simple event delegate - if you didn't use an event delegate, the click handlers like:




                    document.querySelector('#start').onclick = event => 
                    start(data)




                    Could be simplified like this:



                    document.querySelector('#start').onclick = start.bind(null, data)


                  • Unless you fully understand the ways Automatic semicolon insertion can be broken by certain statements, add semi-colons to terminate the lines.

                  • The AJAX statechange handler (i.e. registered via onreadystatechange) doesn't check the readyState and status properties of the request, and thus the innerText property of message will likely be updated before desired (e.g. during request open, transmission, loading, etc.)

                  Rewrite



                  Below is what one could do with the advice above.






                  'use strict'

                  const load = () =>
                  const data = ;

                  init(data);

                  setInterval(() =>
                  update(data);
                  render(data);
                  , 100);
                  const mapping =
                  "start": start.bind(null, data),
                  "reset": reset.bind(null, data),
                  "license": showLicense
                  ;
                  const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
                  document.body.addEventListener('click', clickHandler);


                  const init = data =>
                  data.canvas = document.getElementById('countdown');
                  data.ctx = data.canvas.getContext('2d');

                  data.endTime = Date.now();
                  data.start = false;
                  data.reset = false;

                  data.canvas.width = data.canvas.height = 500;

                  const inputs = ['hours', 'minutes', 'seconds'];
                  inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
                  data.startButton = document.getElementById('start');


                  const update = data =>

                  const render = data =>
                  const
                  canvas,
                  ctx,
                  startAngle,
                  start
                  = data;

                  ctx.fillStyle = '#fff';
                  ctx.fillRect(0, 0, canvas.width, canvas.height);

                  let angle = Math.abs(startAngle);

                  ctx.save();

                  if (startAngle > 0)
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.scale(1, -1);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
                  else
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';


                  while (angle > 2 * Math.PI)
                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
                  ctx.fill();

                  angle -= 2 * Math.PI;


                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
                  ctx.lineTo(canvas.width / 2, canvas.height / 2);
                  ctx.fill();

                  ctx.restore();


                  const start = data =>
                  if (data.start)
                  data.startButton.innerText = 'Start';
                  else
                  let hours = data.hoursInput.value;
                  let minutes = data.minutesInput.value;
                  let seconds = data.secondsInput.value;
                  if (hours.trim() == '') hours = 0;
                  if (minutes.trim() == '') minutes = 0;
                  if (seconds.trim() == '') seconds = 0;

                  let sign;
                  if (hours != 0)
                  sign = hours < 0 ? -1 : 1;
                  else if (minutes != 0)
                  sign = minutes < 0 ? -1 : 1;
                  else
                  sign = seconds < 0 ? -1 : 1;


                  minutes = sign * Math.abs(minutes);
                  seconds = sign * Math.abs(seconds);

                  data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

                  data.startButton.innerText = 'Pause';

                  data.start ^= true;


                  const reset = data =>
                  data.endTime = Date.now();
                  data.start = false;
                  data.hoursInput.value = '';
                  data.minutesInput.value = '';
                  data.secondsInput.value = '';
                  data.startButton.innerText = 'Start';
                  data.reset = true;


                  const showLicense = () =>
                  const mask = document.createElement('div');
                  mask.id = 'mask';
                  mask.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);

                  document.body.appendChild(mask);

                  const message = document.createElement('div');
                  message.id = 'messageContainer';
                  message.innerText = 'License unavailable, please report as a bug.';
                  message.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);


                  const ajax = new XMLHttpRequest();
                  ajax.open('GET', '/');
                  ajax.onreadystatechange = () =>
                  //check state, this doesn't make sense here in this snippet
                  if (ajax.readyState === 4 && ajax.status === 200)
                  //message.innerText = ajax.responseText

                  ;
                  ajax.send();
                  document.body.append(message);


                  const timeToAngle = endTime =>
                  const difference = endTime - Date.now();
                  return difference / 3600000 * 2 * Math.PI;


                  const pad = (value, format) => (format + value).slice(-format.length);

                  load();

                  * 
                  box-sizing: border-box;


                  body
                  background: #eee;
                  margin: 0;


                  main
                  background: #fff;
                  max-width: 700px;
                  margin: auto;
                  padding: 10px;
                  display: flex;
                  flex-flow: column;
                  align-items: center;


                  h1
                  text-align: center;


                  menu
                  display: flex;
                  justify-content: space-between;
                  width: 500px;
                  padding: 0;


                  #hours,
                  #minutes,
                  #seconds
                  width: 30px;
                  text-align: center;


                  footer
                  max-width: 700px;
                  margin: auto;
                  background: #ddd;
                  padding: 10px;
                  display: flex;
                  justify-content: space-between;


                  footer a
                  display: inline-block;
                  background: #ccc;
                  padding: 10px;
                  border-radius: 10px;
                  color: black;
                  text-decoration: none;
                  cursor: pointer;


                  footer a:hover
                  background: #888;
                  color: #fff;


                  #mask
                  position: fixed;
                  left: 0;
                  right: 0;
                  top: 0;
                  bottom: 0;
                  background: rgba(0, 0, 0, 0.5);
                  z-index: 1;


                  #messageContainer
                  position: fixed;
                  left: 50%;
                  top: 50%;
                  transform: translate(-50%, -50%);
                  z-index: 2;
                  background: #fff;
                  padding: 10px;
                  border-radius: 10px;
                  overflow: auto;
                  max-width: 600px;
                  max-height: 500px;

                  <main>
                  <h1 contenteditable>Countdown</h1>
                  <canvas id="countdown"></canvas>
                  <menu>
                  <button id="reset">Reset</button>
                  <div class="group">
                  <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
                  </div>
                  <button id="start">Start</button>
                  </menu>
                  </main>
                  <footer>
                  <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
                  <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
                  <a id="license">MIT license</a>
                  </footer>








                  'use strict'

                  const load = () =>
                  const data = ;

                  init(data);

                  setInterval(() =>
                  update(data);
                  render(data);
                  , 100);
                  const mapping =
                  "start": start.bind(null, data),
                  "reset": reset.bind(null, data),
                  "license": showLicense
                  ;
                  const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
                  document.body.addEventListener('click', clickHandler);


                  const init = data =>
                  data.canvas = document.getElementById('countdown');
                  data.ctx = data.canvas.getContext('2d');

                  data.endTime = Date.now();
                  data.start = false;
                  data.reset = false;

                  data.canvas.width = data.canvas.height = 500;

                  const inputs = ['hours', 'minutes', 'seconds'];
                  inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
                  data.startButton = document.getElementById('start');


                  const update = data =>

                  const render = data =>
                  const
                  canvas,
                  ctx,
                  startAngle,
                  start
                  = data;

                  ctx.fillStyle = '#fff';
                  ctx.fillRect(0, 0, canvas.width, canvas.height);

                  let angle = Math.abs(startAngle);

                  ctx.save();

                  if (startAngle > 0)
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.scale(1, -1);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
                  else
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';


                  while (angle > 2 * Math.PI)
                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
                  ctx.fill();

                  angle -= 2 * Math.PI;


                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
                  ctx.lineTo(canvas.width / 2, canvas.height / 2);
                  ctx.fill();

                  ctx.restore();


                  const start = data =>
                  if (data.start)
                  data.startButton.innerText = 'Start';
                  else
                  let hours = data.hoursInput.value;
                  let minutes = data.minutesInput.value;
                  let seconds = data.secondsInput.value;
                  if (hours.trim() == '') hours = 0;
                  if (minutes.trim() == '') minutes = 0;
                  if (seconds.trim() == '') seconds = 0;

                  let sign;
                  if (hours != 0)
                  sign = hours < 0 ? -1 : 1;
                  else if (minutes != 0)
                  sign = minutes < 0 ? -1 : 1;
                  else
                  sign = seconds < 0 ? -1 : 1;


                  minutes = sign * Math.abs(minutes);
                  seconds = sign * Math.abs(seconds);

                  data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

                  data.startButton.innerText = 'Pause';

                  data.start ^= true;


                  const reset = data =>
                  data.endTime = Date.now();
                  data.start = false;
                  data.hoursInput.value = '';
                  data.minutesInput.value = '';
                  data.secondsInput.value = '';
                  data.startButton.innerText = 'Start';
                  data.reset = true;


                  const showLicense = () =>
                  const mask = document.createElement('div');
                  mask.id = 'mask';
                  mask.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);

                  document.body.appendChild(mask);

                  const message = document.createElement('div');
                  message.id = 'messageContainer';
                  message.innerText = 'License unavailable, please report as a bug.';
                  message.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);


                  const ajax = new XMLHttpRequest();
                  ajax.open('GET', '/');
                  ajax.onreadystatechange = () =>
                  //check state, this doesn't make sense here in this snippet
                  if (ajax.readyState === 4 && ajax.status === 200)
                  //message.innerText = ajax.responseText

                  ;
                  ajax.send();
                  document.body.append(message);


                  const timeToAngle = endTime =>
                  const difference = endTime - Date.now();
                  return difference / 3600000 * 2 * Math.PI;


                  const pad = (value, format) => (format + value).slice(-format.length);

                  load();

                  * 
                  box-sizing: border-box;


                  body
                  background: #eee;
                  margin: 0;


                  main
                  background: #fff;
                  max-width: 700px;
                  margin: auto;
                  padding: 10px;
                  display: flex;
                  flex-flow: column;
                  align-items: center;


                  h1
                  text-align: center;


                  menu
                  display: flex;
                  justify-content: space-between;
                  width: 500px;
                  padding: 0;


                  #hours,
                  #minutes,
                  #seconds
                  width: 30px;
                  text-align: center;


                  footer
                  max-width: 700px;
                  margin: auto;
                  background: #ddd;
                  padding: 10px;
                  display: flex;
                  justify-content: space-between;


                  footer a
                  display: inline-block;
                  background: #ccc;
                  padding: 10px;
                  border-radius: 10px;
                  color: black;
                  text-decoration: none;
                  cursor: pointer;


                  footer a:hover
                  background: #888;
                  color: #fff;


                  #mask
                  position: fixed;
                  left: 0;
                  right: 0;
                  top: 0;
                  bottom: 0;
                  background: rgba(0, 0, 0, 0.5);
                  z-index: 1;


                  #messageContainer
                  position: fixed;
                  left: 50%;
                  top: 50%;
                  transform: translate(-50%, -50%);
                  z-index: 2;
                  background: #fff;
                  padding: 10px;
                  border-radius: 10px;
                  overflow: auto;
                  max-width: 600px;
                  max-height: 500px;

                  <main>
                  <h1 contenteditable>Countdown</h1>
                  <canvas id="countdown"></canvas>
                  <menu>
                  <button id="reset">Reset</button>
                  <div class="group">
                  <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
                  </div>
                  <button id="start">Start</button>
                  </menu>
                  </main>
                  <footer>
                  <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
                  <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
                  <a id="license">MIT license</a>
                  </footer>





                  'use strict'

                  const load = () =>
                  const data = ;

                  init(data);

                  setInterval(() =>
                  update(data);
                  render(data);
                  , 100);
                  const mapping =
                  "start": start.bind(null, data),
                  "reset": reset.bind(null, data),
                  "license": showLicense
                  ;
                  const clickHandler = event => event.target.id in mapping && mapping[event.target.id]();
                  document.body.addEventListener('click', clickHandler);


                  const init = data =>
                  data.canvas = document.getElementById('countdown');
                  data.ctx = data.canvas.getContext('2d');

                  data.endTime = Date.now();
                  data.start = false;
                  data.reset = false;

                  data.canvas.width = data.canvas.height = 500;

                  const inputs = ['hours', 'minutes', 'seconds'];
                  inputs.forEach(inputName => data[inputName + 'Input'] = document.getElementById(inputName));
                  data.startButton = document.getElementById('start');


                  const update = data =>

                  const render = data =>
                  const
                  canvas,
                  ctx,
                  startAngle,
                  start
                  = data;

                  ctx.fillStyle = '#fff';
                  ctx.fillRect(0, 0, canvas.width, canvas.height);

                  let angle = Math.abs(startAngle);

                  ctx.save();

                  if (startAngle > 0)
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.scale(1, -1);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
                  else
                  ctx.translate(canvas.width / 2, canvas.height / 2);
                  ctx.rotate(-Math.PI / 2);
                  ctx.translate(-canvas.width / 2, -canvas.height / 2);
                  ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';


                  while (angle > 2 * Math.PI)
                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, 2 * Math.PI);
                  ctx.fill();

                  angle -= 2 * Math.PI;


                  ctx.beginPath();
                  ctx.arc(canvas.width / 2, canvas.width / 2, canvas.width / 2, 0, angle);
                  ctx.lineTo(canvas.width / 2, canvas.height / 2);
                  ctx.fill();

                  ctx.restore();


                  const start = data =>
                  if (data.start)
                  data.startButton.innerText = 'Start';
                  else
                  let hours = data.hoursInput.value;
                  let minutes = data.minutesInput.value;
                  let seconds = data.secondsInput.value;
                  if (hours.trim() == '') hours = 0;
                  if (minutes.trim() == '') minutes = 0;
                  if (seconds.trim() == '') seconds = 0;

                  let sign;
                  if (hours != 0)
                  sign = hours < 0 ? -1 : 1;
                  else if (minutes != 0)
                  sign = minutes < 0 ? -1 : 1;
                  else
                  sign = seconds < 0 ? -1 : 1;


                  minutes = sign * Math.abs(minutes);
                  seconds = sign * Math.abs(seconds);

                  data.endTime = Date.now() + 3600000 * hours + 60000 * minutes + 1000 * seconds;

                  data.startButton.innerText = 'Pause';

                  data.start ^= true;


                  const reset = data =>
                  data.endTime = Date.now();
                  data.start = false;
                  data.hoursInput.value = '';
                  data.minutesInput.value = '';
                  data.secondsInput.value = '';
                  data.startButton.innerText = 'Start';
                  data.reset = true;


                  const showLicense = () =>
                  const mask = document.createElement('div');
                  mask.id = 'mask';
                  mask.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);

                  document.body.appendChild(mask);

                  const message = document.createElement('div');
                  message.id = 'messageContainer';
                  message.innerText = 'License unavailable, please report as a bug.';
                  message.onclick = () =>
                  document.body.removeChild(mask);
                  document.body.removeChild(message);


                  const ajax = new XMLHttpRequest();
                  ajax.open('GET', '/');
                  ajax.onreadystatechange = () =>
                  //check state, this doesn't make sense here in this snippet
                  if (ajax.readyState === 4 && ajax.status === 200)
                  //message.innerText = ajax.responseText

                  ;
                  ajax.send();
                  document.body.append(message);


                  const timeToAngle = endTime =>
                  const difference = endTime - Date.now();
                  return difference / 3600000 * 2 * Math.PI;


                  const pad = (value, format) => (format + value).slice(-format.length);

                  load();

                  * 
                  box-sizing: border-box;


                  body
                  background: #eee;
                  margin: 0;


                  main
                  background: #fff;
                  max-width: 700px;
                  margin: auto;
                  padding: 10px;
                  display: flex;
                  flex-flow: column;
                  align-items: center;


                  h1
                  text-align: center;


                  menu
                  display: flex;
                  justify-content: space-between;
                  width: 500px;
                  padding: 0;


                  #hours,
                  #minutes,
                  #seconds
                  width: 30px;
                  text-align: center;


                  footer
                  max-width: 700px;
                  margin: auto;
                  background: #ddd;
                  padding: 10px;
                  display: flex;
                  justify-content: space-between;


                  footer a
                  display: inline-block;
                  background: #ccc;
                  padding: 10px;
                  border-radius: 10px;
                  color: black;
                  text-decoration: none;
                  cursor: pointer;


                  footer a:hover
                  background: #888;
                  color: #fff;


                  #mask
                  position: fixed;
                  left: 0;
                  right: 0;
                  top: 0;
                  bottom: 0;
                  background: rgba(0, 0, 0, 0.5);
                  z-index: 1;


                  #messageContainer
                  position: fixed;
                  left: 50%;
                  top: 50%;
                  transform: translate(-50%, -50%);
                  z-index: 2;
                  background: #fff;
                  padding: 10px;
                  border-radius: 10px;
                  overflow: auto;
                  max-width: 600px;
                  max-height: 500px;

                  <main>
                  <h1 contenteditable>Countdown</h1>
                  <canvas id="countdown"></canvas>
                  <menu>
                  <button id="reset">Reset</button>
                  <div class="group">
                  <input id="hours" placeholder="HH" autofocus>:<input id="minutes" placeholder="MM">:<input id="seconds" placeholder="SS">
                  </div>
                  <button id="start">Start</button>
                  </menu>
                  </main>
                  <footer>
                  <a href="https://github.com/SteeveDroz/countdown">Find the project on GitHub</a>
                  <a href="https://github.com/SteeveDroz/countdown/issues">Report bugs</a>
                  <a id="license">MIT license</a>
                  </footer>






                  share|improve this answer















                  share|improve this answer



                  share|improve this answer








                  edited May 7 at 17:10


























                  answered May 7 at 16:13









                  Sam Onela

                  5,82961544




                  5,82961544






















                       

                      draft saved


                      draft discarded


























                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190220%2fdisplay-the-time-left-of-a-given-time%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Popular posts from this blog

                      Greedy Best First Search implementation in Rust

                      Function to Return a JSON Like Objects Using VBA Collections and Arrays

                      C++11 CLH Lock Implementation