Skip to content

Instantly share code, notes, and snippets.

@thisancog
Last active August 22, 2017 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thisancog/697d2d956d2291fcc780b37b17e13960 to your computer and use it in GitHub Desktop.
Save thisancog/697d2d956d2291fcc780b37b17e13960 to your computer and use it in GitHub Desktop.
Zeitansage
(function() {
var canvas, ctx, time, synth, audioCtx,
hours, minutes, seconds;
var language = 'de-DE',
pitch = 1,
rate = 0.95,
whenToStart = 10,
voices = [];
var beep = 'Beim nächsten Ton ist es ',
esIst = 'Es ist ',
uhr = ' Uhr ',
und = 'und ',
minuten = ' Minuten.',
minute = ' Minute.';
var tick = function() {
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90;
ctx.strokeStyle = '#FFFFFF';
ctx.lineCap = 'round';
var tock = function() {
ctx.clearRect(- radius, - radius, 2 * radius, 2 * radius);
for (var angle = 0; angle <= 360; angle += 30) {
var start = getCoord(angle, angle % 90 === 0 ? 0.8 * radius : 0.85 * radius),
end = getCoord(angle, 0.9 * radius);
ctx.beginPath();
ctx.moveTo(start.x, start.y);
ctx.lineTo(end.x, end.y);
ctx.stroke();
}
time = new Date();
hours = time.getHours();
minutes = time.getMinutes();
seconds = time.getSeconds();
drawHand((hours % 12) * 30 + minutes / 2, 0.4 * radius, 4);
drawHand(minutes * 6, 0.6 * radius, 4);
drawHand(seconds * 6, 0.8 * radius, 2);
requestAnimFrame(tock);
}
var getCoord = function(angle, radius) {
angle = toRadians(angle);
return {
x: radius * Math.cos(angle),
y: radius * Math.sin(angle)
}
}
var toRadians = function(angle) {
return angle * Math.PI / 180;
}
var drawHand = function(angle, length, width) {
var end = getCoord(angle - 90, length);
ctx.beginPath();
ctx.lineWidth = width;
ctx.moveTo(0, 0);
ctx.lineTo(end.x, end.y);
ctx.stroke();
}
var tellMeTheTime = function() {
if ('speechSynthesis' in window) {
var isTalking = false,
textBase = audioCtx ? beep : esIst;
synth = window.speechSynthesis;
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = function() {
voices = synth.getVoices().filter(function(item) {
return item.lang === language;
});
var talkToMe = function() {
if (!isTalking && (
( audioCtx && seconds % 20 === whenToStart) ||
(!audioCtx && seconds === 0))) {
var nextMinute = (minutes < 59) ? minutes + 1 : 0,
nextHour = (nextMinute === 0) ? hours + 1 : hours,
text = textBase + nextHour + uhr;
if (nextMinute > 0) text += und + nextMinute;
if (nextMinute === 1) text += minute;
if (nextMinute > 1) text += minuten;
var talk = new SpeechSynthesisUtterance(text);
isTalking = true;
talk.pitch = pitch;
talk.rate = rate;
talk.voice = voices[0];
talk.onend = function() {
isTalking = false;
}
synth.speak(talk);
}
if (seconds === 0 && !isTalking && audioCtx) {
var oscillator = audioCtx.createOscillator();
isTalking = true;
oscillator.type = 'sine';
oscillator.frequency.value = 440;
oscillator.connect(audioCtx.destination);
oscillator.start();
setTimeout(function() {
oscillator.stop();
isTalking = false;
}, 1000);
}
requestAnimFrame(talkToMe);
}
if (voices.length > 0)
talkToMe();
else
noSpeech();
};
}
} else {
noSpeech();
}
}
tock();
tellMeTheTime();
}
var noSpeech = function() {
document.querySelector('body').classList.add('speechdisabled');
}
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
var requestAnimFrame = (function(){
return window.requestAnimationFrame || window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame || function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
window.addEventListener('load', function() {
canvas = document.querySelector('.clock');
ctx = canvas.getContext("2d");
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
tick();
});
})();
html, body, div, canvas {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
html, body {
width: 100vw;
height: 100vh;
font-size: 16px;
}
body {
color: #FFFFFF;
background: linear-gradient(135deg, #2DB1E5 0%,#6E7FCC 100%);
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.6;
}
.wrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.clock {
width: 30vmax;
height: 30vmax;
}
.js .jsdisabled,
.speechnotice {
display: none;
}
.no-js .jsdisabled,
.speechdisabled .speechnotice {
display: block;
margin-top: 4vh;
max-width: 350px;
}
<!doctype html>
<html lang="de-DE" class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zeitansage</title>
<link rel="stylesheet" href="styles.css" />
<script>
var html = document.getElementsByClassName('no-js');
for (var i = 0; i < html.length; i++) { html[i].className = 'js'; }
</script>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<div class="wrapper">
<canvas class="clock" width="1200" height="1200"></canvas>
<div class="jsdisabled">
Du hast JavaScript deaktiviert. Schade.
</div>
<div class="speechnotice">
Dein Browser unterstützt die Speech API nicht. Daher gibt's hier nur eine langweilige Uhr.
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment