5.10.1_秒表
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>秒表</title>
<style>
body{
background: #fff;
}
#canvas{
background: #eee;
}
#controls{
position: absolute;
left: 25px;
top: 25px;
}
</style>
</head>
<body>
<div id="controls">
秒数(0-60):<input id="secondsInput" type="number" value="0" />
<input id="startStopButton" type="button" value="start" />
</div>
<canvas id="canvas" width="1000" height="600"></canvas>
</body>
<script>
StopWatch = function(){};
StopWatch.prototype = {
startTime: 0,
running: false,
elapsed: undefined,
start:function(){
this.startTime = +new Date();
this.elapsed = undefined;
this.running = true;
},
stop:function(){
this.elapsed = (+new Date()) - this.startTime;
this.running = false;
},
getElapsedTime:function(){
if(this.running){
return (+new Date()) - this.startTime;
}else{
return this.elapsed;
}
},
isRunning:function(){
return this.running;
},
reset:function(){
this.elapsed = 0;
}
}
</script>
<script>
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
stopwatch = new StopWatch(),
secondsInput = document.getElementById('secondsInput'),
startStopButton = document.getElementById('startStopButton'),
timerSetting = 0,
offscreenCanvas = document.createElement('canvas'),
offscreenContext = offscreenCanvas.getContext('2d'),
centroid_radius = 10 ,
centroid_stroke_style = 'rgba(0,0,0,0.5)',
centroid_fill_style = 'rgba(80,190,240,0.6)',
ring_inner_radius = 35,
ring_outer_radius = 55,
annotations_fill_style = 'rgba(0,0,230,0.9)',
annotations_text_size = 16,
tick_width = 10,
tick_long_stroke_style = 'rgba(100,140,230,0.9)',
tick_short_stroke_style = 'rgba(100,140,230,0.7)',
tracking_dial_stroking_style = 'rgba(100,140,230,0.5)',
guidewire_stroke_style = 'goldenrod',
guidewire_fill_style = 'rgba(250,250,0,0.6)',
circle ={
x:canvas.width/2,
y:canvas.height/2,
radius:150
};
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
context.shadowColor ='rgba(0,0,0,0.4)';
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowBlur = 4;
context.textAlign = 'center';
context.textBaseline = 'middle';
drawGrid('lightgray',10,10);
drawDial();
offscreenContext.drawImage(canvas,0,0);
drawCentroidGuidewire(circle,-Math.PI/2);
startStopButton.onclick = function(e){
var value = this.value;
timerSetting = parseFloat(secondsInput.value);
if(value == 'start'){
stopwatch.start();
this.value = 'stop';
secondsInput.disabled = true;
requestAnimationFrame(animate);
}else{
stopwatch.stop();
this.value = 'start';
secondsInput.disabled = false;
}
}
function animate(){
if(stopwatch.isRunning()&& stopwatch.getElapsedTime()>timerSetting*1000){
stopwatch.stop();
startStopButton.value = 'start';
secondsInput.disabled = false;
secondsInput.value = 0;
erase();
context.drawImage(offscreenCanvas,0,0);
drawCentroidGuidewire(circle,-Math.PI/2);
}else if(stopwatch.isRunning()){
redraw();
requestAnimationFrame(animate);
}
}
function redraw(){
var ang = (stopwatch.getElapsedTime()/1000)*6*(Math.PI/180)-Math.PI/2;
erase();
context.drawImage(offscreenCanvas,0,0);
drawCentroidGuidewire(circle,ang);
}
function erase(){
context.clearRect(0,0,canvas.width,canvas.height);
}
function drawCentroidGuidewire(loc,ang){
var angle = ang,
radius,endpt;
radius = circle.radius+ring_outer_radius;
if(loc.x>=circle.x){
endpt ={
x:circle.x+radius*Math.cos(angle),
y:circle.y+radius*Math.sin(angle)
}
}else{
endpt = {
x:circle.x-radius*Math.cos(angle),
y:circle.y-radius*Math.sin(angle)
}
}
context.save();
context.strokeStyle = guidewire_stroke_style;
context.fillStyle = guidewire_fill_style;
context.beginPath();
context.moveTo(circle.x,circle.y);
context.lineTo(endpt.x,endpt.y);
context.stroke();
context.beginPath();
context.strokeStyle = tick_long_stroke_style;
context.arc(endpt.x,endpt.y,5,0,Math.PI*2,false);
context.fill();
context.stroke();
context.restore()
}
function drawDial(){
var loc = {
x:circle.x,
y:circle.y
};
drawCentroid();
drawRing();
drawTickInnerCircle();
drawTicks();
drawAnnotations();
}
function drawAnnotations(){
var radius = circle.radius+ring_inner_radius-tick_width*3.5;
context.save();
context.fillStyle = annotations_fill_style;
context.font = annotations_text_size +'px helvetica';
for(var angle =0; angle<2*Math.PI;angle+=Math.PI/6){
context.beginPath();
context.fillText((angle*30/Math.PI).toFixed(0),
circle.x-Math.cos(angle+Math.PI/2)*radius,
circle.y-Math.sin(angle+Math.PI/2)*radius
);
}
context.restore();
}
function drawTicks(){
var radius = circle.radius+ring_inner_radius,
angle_max = Math.PI*2,
angle_delta = Math.PI/30,
tickWidth;
context.save();
for(var angle = 0,cnt=0;angle<angle_max;angle+=angle_delta,cnt++){
drawTick(angle,radius,cnt);
}
context.restore();
}
function drawTick(angle,radius,cnt){
var tickWidth = cnt % 5 ===0? tick_width*2:tick_width/2;
context.beginPath();
context.moveTo(circle.x+Math.cos(angle)*(radius-tickWidth),
circle.y+Math.sin(angle)*(radius-tickWidth)
);
context.lineTo(circle.x+Math.cos(angle)*(radius),
circle.y+Math.sin(angle)*(radius)
);
context.strokeStyle = tick_short_stroke_style;
context.stroke();
}
function drawTickInnerCircle(){
context.save();
context.beginPath();
context.strokeStyle = 'rgba(0,0,0,0.1)';
context.arc(circle.x,circle.y,circle.radius+ring_inner_radius-tick_width,0,Math.PI*2,false);
context.stroke();
context.restore();
}
function drawRing(){
drawRingOuterCircle();
drawRingInnerCircle();
}
function drawRingOuterCircle(){
context.shadowColor = 'rgba(0,0,0,0.7)';
context.shadowOffsetX = 3;
context.shadowOffsetY = 3;
context.shadowBlur = 6;
context.strokeStyle = tracking_dial_stroking_style;
context.beginPath();
context.arc(circle.x,circle.y,circle.radius+ring_outer_radius,0,Math.PI*2,true);
context.stroke();
}
function drawRingInnerCircle(){
context.strokeStyle = 'rgba(0,0,0,0.1)';
context.fillStyle = 'rgba(100,140,230,0.1)';
context.arc(circle.x,circle.y,circle.radius+ring_inner_radius,0,Math.PI*2,false);
context.fill();
context.stroke();
}
function drawCentroid(){
context.beginPath();
context.save();
context.strokeStyle = centroid_stroke_style;
context.fillStyle = centroid_fill_style;
context.arc(circle.x,circle.y,centroid_radius,0,Math.PI*2,false);
context.fill();
context.stroke();
context.restore();
}
function drawGrid(color,stepX,stepY){
context.save();
context.shadowColor = undefined;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur =0;
context.strokeStyle = color;
context.lineWidth =0.5;
context.fillStyle = '#fff';
context.fillRect(0,0,canvas.width,canvas.height);
for(var i=stepX+0.5;i<context.canvas.width;i+=stepX){
context.beginPath();
context.moveTo(i,0);
context.lineTo(i,context.canvas.height);
context.stroke();
}
for(var i=stepY+0.5;i<context.canvas.height;i+=stepY){
context.beginPath();
context.moveTo(0,i);
context.lineTo(context.canvas.width,i);
context.stroke();
}
context.restore();
}
</script>
</html>