[TypeScript] Lightningtalks Timer by HTML5

lightningtalkstimer.png

以前作った HTML5 用のライトニングトーク用のタイマーを、TypeScript で書きなおしてみた。

TypeScript を使うことで、よりすっきりと書ける。また、Visual Studio でのインテリセンスや静的な型チェックが行える為、とても楽だ。

lightningtalktimer.ts

TypeScript コンパイラーによって lightningtalktimer.js に変換される。

// for lightningtalktimer.html
// generated from lightningtalktimer.ts
// Ver.1.01 2014-01-17
// Copyright © 2014 Sho's Software by Fujiwo http://www.shos.info
module LightningTalkTimer {
export class Application {
private static timer = null;
private static get canvas(): HTMLCanvasElement {
return <HTMLCanvasElement>document.querySelector("canvas");
}
private static get context(): CanvasRenderingContext2D {
return <CanvasRenderingContext2D>Application.canvas.getContext("2d");
}
static run() {
Application.sizing();
Application.timer = new Timer(this.context, this.canvas.width, this.canvas.height);
}
static onClick() {
Application.timer.start();
}
private static sizing() {
var canvas    = Application.canvas;
canvas.height = window.innerHeight;
canvas.width  = window.innerWidth ;
}
}
class Utility {
static getQuerystring(key: string, default_: string = null): string {
if (default_ == null)
default_ = "";
key             = key.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regex       = new RegExp("[\\?&]" + key + "=([^&#]*)");
var queryString = regex.exec(window.location.href);
return queryString == null ? default_ : queryString[1];
}
static secondsToString(totalSeconds: number): string {
var minutes     = Math.floor(totalSeconds / 60);
var seconds     = totalSeconds % 60;
var secondsText = (seconds >= 10) ? seconds.toString() : "0" + seconds;
return minutes.toString() + ':' + secondsText;
}
static getCurrentMilliSeconds(): number {
return Date.parse(new Date().toString());
}
}
class Parameter {
maxSeconds       = 60 * 5;
dangerousSeconds = 60 * 1;
fontHeightRate   = 70;
constructor() {
this.setMaxSeconds      ();
this.setDangerousSeconds();
this.setFontHeight      ();
}
private setFontHeight() {
var fontHeightRateText = Utility.getQuerystring("font");
if (fontHeightRateText != "") {
var heightRate = parseInt(fontHeightRateText);
if (heightRate > 0 && heightRate <= 100)
this.fontHeightRate = heightRate;
}
}
private setMaxSeconds() {
var maxSecondsText = Utility.getQuerystring("max");
if (maxSecondsText != "") {
var seconds = parseInt(maxSecondsText);
if (seconds > 0) {
this.maxSeconds = seconds;
if (this.dangerousSeconds > this.maxSeconds)
this.dangerousSeconds = this.maxSeconds;
}
}
}
private setDangerousSeconds() {
var dangerousSecondsText = Utility.getQuerystring("danger");
if (dangerousSecondsText != "") {
var seconds = parseInt(dangerousSecondsText);
if (seconds >= 0 && seconds <= this.maxSeconds)
this.dangerousSeconds = seconds;
}
}
}
class View {
private static normalDarkColor     = "#100";
private static normalLightColor    = "#a99";
private static dangerousDarkColor  = "#e00";
private static dangerousLightColor = "#f99";
private static shadowColor         = "gray";
private context: CanvasRenderingContext2D;
constructor(context: CanvasRenderingContext2D) {
this.context = context;
}
draw(text: string, isNormal: boolean, width: number, height: number, fontHeightRate: number) {
this.context.clearRect(0, 0, width, height);
View.drawText(this.context, text, View.getDarkColor(isNormal), View.getLightColor(isNormal), width, height, fontHeightRate);
}
private static drawText(context: CanvasRenderingContext2D, text: string, colorDark: string, colorLight: string, width: number, height: number, fontHeightRate: number) {
var fontHeight = height * fontHeightRate / 100;
var y          = fontHeight * (16 + 1) / 16;
context.font   = fontHeight + "px 'メイリオ',Meiryo,'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro',Calibri,sans-serif";
View.setGradient(context, fontHeight, colorDark, colorLight);
View.setShadow  (context, fontHeight                       );
context.fillText(text, fontHeight / 12, y);
}
private static getDarkColor(isNormal: boolean): string {
return isNormal ? View.normalDarkColor : View.dangerousDarkColor;
}
private static getLightColor(isNormal: boolean): string {
return isNormal ? View.normalLightColor : View.dangerousLightColor;
}
private static setGradient(context: CanvasRenderingContext2D, fontHeight: number, darkColor: string, lightColor: string) {
var gradient      = context.createLinearGradient(0, 0, 0, fontHeight);
gradient.addColorStop(0.5, darkColor);
gradient.addColorStop(0.6, lightColor);
gradient.addColorStop(0.7, darkColor);
context.fillStyle = gradient;
}
private static setShadow(context: CanvasRenderingContext2D, fontHeight: number) {
context.shadowColor   = View.shadowColor;
context.shadowOffsetX = fontHeight / 36;
context.shadowOffsetY = fontHeight / 36;
context.shadowBlur    = fontHeight / 48;
}
}
class Timer {
private width    : number;
private height   : number;
private parameter: Parameter;
private view     : View;
private timerID =  0;
constructor(context: CanvasRenderingContext2D, width: number, height: number) {
this.width     = width  ;
this.height    = height ;
this.parameter = new Parameter();
this.view      = new View(context);
this.draw(this.parameter.maxSeconds, this.isNormal(this.parameter.maxSeconds));
}
private start() {
this.reset();
var start    = Utility.getCurrentMilliSeconds();
this.timerID = window.setInterval(() => this.update(start), 1000);
}
private update(start: number) {
var now = Utility.getCurrentMilliSeconds();
var remainingSeconds = this.parameter.maxSeconds - (now - start) / 1000;
if (remainingSeconds < 0)
remainingSeconds = 0;
this.draw(remainingSeconds, this.isNormal(remainingSeconds));
if (remainingSeconds == 0)
window.clearInterval(this.timerID);
}
private reset() {
window.clearInterval(this.timerID);
this.draw(this.parameter.maxSeconds, this.isNormal(this.parameter.maxSeconds));
}
private draw(seconds: number, isNormal: boolean) {
this.view.draw(Utility.secondsToString(seconds), isNormal, this.width, this.height, this.parameter.fontHeightRate);
}
private isNormal(remainingSeconds: number): boolean {
return remainingSeconds > this.parameter.dangerousSeconds;
}
}
}
window.onload = () => {
LightningTalkTimer.Application.run();
};

lightningtalktimer.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,minimum-scale=1, maximum-scale=1, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>Sho's Lightning Talks Timer by HTML5</title>
<style>
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, menu, nav, section, menu, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
article, aside, dialog, figure, footer, header, hgroup, nav, section {
display: block;
}
body {
width: 100%;
overflow: hidden;
}
</style>
<script src="lightningtalktimer.js"></script>
</head>
<body>
<canvas width="500" height="500" onclick="LightningTalkTimer.Application.onClick()"></canvas>
</body>
</html>
<!--
Usage:
Click: reset and start counting down.
lightningtalktimer.html               : max = 300 seconds, dangerous =  60 seconds, font height 70%
lightningtalktimer.html?max=100&danger=50  : max = 100 seconds, dangerous =  50 seconds
lightningtalktimer.html?max=100&danger=100 : max = 100 seconds, dangerous = 100 seconds
lightningtalktimer.html?max=100           : max = 100 seconds, dangerous =  60 seconds
lightningtalktimer.html?max=10           : max =10 seconds, dangerous =  10 seconds
lightningtalktimer.html?danger=0       : max = 300 seconds, dangerous =   0 seconds
lightningtalktimer.html?font=50           : font height 50%
- This HTML can work with lightningtalktimer.js online or offline.
Ver.1.01 2014-01-17
Copyright © 2014 Sho's Software by Fujiwo http://www.shos.info
-->

実際に動くもの

使い方

  • クリックするたびカウントダウン (デフォルト 5分)
  • 残り時間が少なくなると赤くなる (デフォルト 1分)
  • クエリー文字列:
    • max で、時間 (秒) の設定 (lightningtalktimer.html?max=100 で 100秒)
    • danger で、赤くなる時間 (秒) の設定 (lightningtalktimer.html?danger=10 で 10秒、lightningtalktimer.html?danger=0 だと最後だけ赤くなる)
    • font で、文字サイズ (%) の設定 (lightningtalktimer.html?font=90 で文字の高さが最大値の90%)
  • Internet Explorer、Firefox、Safari、Google Chrome、Opera の現時点での最新版で動作
  • iPhone、Android フォン等スマートフォンで動作

関連記事