写在之前

  • canvas 元素中提供了看似简单的绘图方法,但仔细挖掘,可以以此做出非常复杂而漂亮的图形。随着 API 的逐渐完善,我相信自己能进行更多有意思的尝试。

  • 时钟的 canvas + js 实现主要是应用上下文的简单变换、文本添加及周期性调用方法 setInterval(func, delay)。在绘制表盘及时针过程注意使用save()及restore()方法添加用以保存或返回上一个画布设置属性。

  • 思路:编写两个构造函数,分别代表表盘和时针,最后利用函数加以实现。

  • 具体效果可转接到我的Codepen-->效果演示


代码实现

1, html 部分

<body>
    <canvas id="plate">你看不见我!</canvas>
</body>

2, javascript 部分

<script>
    var plate = document.getElementById("plate");
    var ctp = plate.getContext("2d");
    document.body.style.backgroundColor = "#FFFACD";
    plate.setAttribute('style', 'margin:50px 0 0 300px');
    plate.width = 600;
    plate.height = 600;

    //创建时间对象
    var date = new Date();
    var baseTime; //表示各指针旋转基数
    var counter = 0;
    //构造表盘
    // ct-->上下文, radius-->表盘外延半径, textLen-->文本高度, lineEnd-->刻度线末端y坐标/
    function DrawPlate(ct, radius, textHight, lineLen) {
        this.ct = ct;
        this.radius = radius;
        this.textHight = textHight;
        this.lineLen = lineLen;
    }
    //添加方法,绘制表盘外延
    DrawPlate.prototype.drawPlateCir = function(color) {
        this.ct.beginPath();
        this.ct.save();
        this.ct.translate(300, 300);
        this.ct.arc(0, 0, this.radius, 0, 2*Math.PI, false);
        this.ct.strokeStyle = color;
        this.ct.stroke();
        this.ct.closePath();
        this.ct.restore();
    }
    //添加方法,绘制表盘刻度
    DrawPlate.prototype.drawCalibration = function(color) {
        //大刻度
        for(var i = 1; i <= 12 ; i++) {
            this.ct.beginPath();
            this.ct.save();
            this.ct.translate(300, 300);
            this.ct.rotate(i*Math.PI/6);
            this.ct.moveTo(0, -this.radius);
            this.ct.lineTo(0, this.lineLen - this.radius);
            this.ct.lineWidth = 5;
            this.ct.strokeStyle = color;
            this.ct.stroke();
            this.ct.closePath();
            this.ct.restore();
        }
        //小刻度
        for(var j = 0; j <= 60; j++) {
            this.ct.beginPath();
            this.ct.save();
            this.ct.translate(300, 300);
            this.ct.rotate(j*Math.PI/30);
            this.ct.moveTo(0, -this.radius);
            this.ct.lineTo(0, this.lineLen - this.radius);
            this.ct.lineWidth = 2;
            this.ct.strokeStyle = color;
            this.ct.stroke();
            this.ct.closePath();
            this.ct.restore();
        }
    };
    //添加指示文本
    DrawPlate.prototype.drawPlateText = function() {
        for(var i = 1; i <= 12; i++) {
            this.ct.beginPath();
            this.ct.save();
            this.ct.translate(300, 300);
            this.ct.font = "bold " + this.textHight + "px Times New Roman";
            this.ct.textAlign = "center";
            this.ct.textBaseline = "middle";
            this.ct.fillText(i, -(this.radius - this.lineLen - 0.6*this.textHight)*Math.sin(-i*2*Math.PI/12), -(this.radius - this.lineLen - 0.6*this.textHight)*Math.cos(-i*2*Math.PI/12));
            this.ct.closePath();
            this.ct.restore();
        }
    };
    //构造指针函数
    function DrawNeedles(ct, needleEnd, centerCirR) {
        this.ct = ct;
        this.needleEnd = needleEnd;
        this.centerCirR = centerCirR;
    }
    //绘制中心园
    DrawNeedles.prototype.addCenterCir = function (color) {
        this.ct.beginPath();
        this.ct.save();
        this.ct.translate(300, 300);
        this.ct.arc(0, 0, this.centerCirR, 0, 2*Math.PI, false);
        this.ct.fillStyle = color;
        this.ct.fill();
        this.ct.closePath();
        this.ct.restore();
    };
    //绘制指针方法
    DrawNeedles.prototype.addNeedles = function (needleName, needleLen, lineW, color) {

        var h = date.getHours(), m = date.getMinutes(), s = date.getSeconds();
        this.ct.beginPath();
        this.ct.save();
        this.ct.translate(300, 300);
        switch(needleName){
            case "hr":
                if(h > 12) {
                    h = h -12;
                }
                baseTime = 12;
                this.ct.rotate((h + m/60 + s/3600 + counter/1000/3600)*2*Math.PI/baseTime);
                this.ct.moveTo(0, this.needleEnd);
                this.ct.lineTo(0, this.needleEnd - needleLen);
                break;
            case "min":
                baseTime = 60;
                this.ct.rotate((m + s/60 + counter/1000/60)*2*Math.PI/baseTime);
                this.ct.moveTo(0, this.needleEnd);
                this.ct.lineTo(0, this.needleEnd - needleLen);
                break;
            case "sec":
                baseTime = 60;
                this.ct.rotate((s + counter/1000)*2*Math.PI/baseTime);
                this.ct.moveTo(0, this.needleEnd);
                this.ct.lineTo(0, this.needleEnd - needleLen);
                break;
            default:
                break;
        }
        this.ct.lineWidth = lineW;
        this.ct.lineCap = "round"; //指针末端为圆头
        this.ct.strokeStyle = color;
        this.ct.stroke();
        this.ct.closePath();
        this.ct.restore();
    };
    //实现
    function drawClock() {
        ctp.clearRect(0, 0, plate.width, plate.height);
        var p = new DrawPlate(ctp, 200, 30, 10);
        var n = new DrawNeedles(ctp, 20, 5);
        p.drawPlateCir("green");
        p.drawPlateText();
        p.drawCalibration("green");
        n.addCenterCir("green");
        //时针
        n.addNeedles("hr", 100, 3, "black");
        //分针
        n.addNeedles("min", 145, 2, "black");
        //秒针
        n.addNeedles("sec", 170, 1, "red");
    }
    function index(delay) {
        drawClock();
        setInterval(function() {
            counter = counter + delay;
            drawClock();
        }, delay);
    }
    index(10);
</script>

waouyouy
2 声望1 粉丝

北京冬天的小白菜