5.10.1_秒表

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,

            //离屏canvas
            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(){
                //得到从start开始的秒数
                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,//半圆分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.moveTo(circle.x+circle.radius+ring_inner_radius,circle.y);
                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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值