JavaScript 动态三角函数

<html>
    <head>
        <meta charset="utf8" />
        <title>三角函数图形</title>
        <style type="text/css">
            body {
                background-color:black;
            }
            #canvas {
                position:absolute;
                top:50%;
                left:50%;
                margin:-151px 0 0 -401px;
                border:1px dashed #171717;
            }
        </style>
    </head>
    <body>
        <canvas id="canvas" width="800px" height="300px">您的浏览器不支持canvas</canvas>
        <script type="text/javascript">

            //判断是否支持canvaas
            function isSupportCanvas(canvas) {
                return !!(canvas.getContext && canvas.getContext("2d"));
            }

            //requestAnimationFrame会自动使用最优的帧率进行渲染
            function setupRAF() {
                window.lastTime = 0;

                //兼容各个浏览器,Internet Explorer11、Google Chrome(Microsoft Edge)、Mozilla Firefox、Opera
                var vendors = ["ms", "moz", "webkit", "o"];
                for(var i=0; i<vendors.length; i++) {
                    window.requestAnimationFrame = window[vendors[i] + "RequestAnimationFrame"];
                    window.cancelAnimationFrame = window[vendors[i] + "CancelAnimationFrame"] || window[vendors[i] + "CancelRequestAnimationFrame"];

                    //测试浏览器支持哪一张
                    if(window.requestAnimationFrame) {
                        console.log(vendors[i] + "requestAnimationFrame");
                    }
                    if(window[vendors[i] + "CancelAnimationFrame"]) {
                        console.log(vendors[i] + "CancelAnimationFrame");
                    }
                    if(window[vendors[i] + "CancelRequestAnimationFrame"]) {
                        console.log(vendors[i] + "CancelRequestAnimationFrame");
                    }
                }

                //回退机制
                if(!window.requestAnimationFrame) {
                    window.requestAnimationFrame = function(callback, element) {
                        var currentTime = new Date().getTime();
                        var timeToCall = Math.max(0, 16-(currentTime-window.lastTime));
                        var callTime = currentTime + timeToCall;
                        var id = window.setTimeout(function() {
                            callback(callTime);
                        }, timeToCall);
                        window.lastTime = callTime;
                        return id;
                    };
                }

                //回退机制
                if(!window.cancelAnimationFrame) {
                    window.cancelAnimationFrame = function(id) {
                        clearTimeout(id);
                    }
                }
            }

            var CanvasController = function(canvas) {
                var ctx = canvas.getContext("2d");
                ctx.lineWidth = 1;
                var i = 0;
                var step = 1;
                var unitX = 90
                var unitY = canvas.height * 0.3;

                function update() {
                    i += step;
                    i %= 360;
                }

                //渲染坐标
                function rendeRcoordinate() {
                    var color = "white";
                    ctx.strokeStyle = color;
                    ctx.fillStyle = color;
                    ctx.textBaseline = "top";
                    ctx.font = "normal 8pt Arial"

                    ctx.beginPath();
                    var halfCanvasHeight = 0.5 * canvas.height;
                    var topUnit = halfCanvasHeight - unitY;
                    var bottomUnit = halfCanvasHeight + unitY;
                    ctx.moveTo(0, topUnit);
                    ctx.lineTo(canvas.width, topUnit);
                    ctx.moveTo(0, halfCanvasHeight);
                    ctx.lineTo(canvas.width, halfCanvasHeight);
                    ctx.moveTo(0, bottomUnit);
                    ctx.lineTo(canvas.width, bottomUnit);
                    ctx.stroke();

                    var doubleUnitX = 2 * unitX;
                    var zero = unitX - i;
                    while(zero < 0) {
                        zero += doubleUnitX;
                    }
                    ctx.beginPath();
                    for(var a = zero; a < canvas.width; a += doubleUnitX) {
                        ctx.moveTo(a, 0);
                        ctx.lineTo(a, canvas.height);
                        ctx.fillText("(0,0)", a, halfCanvasHeight);
                    }
                    ctx.stroke();
                }

                //绘制x=sin(a),y=cos(a)的函数
                function renderXSinYCos() {
                    var color = "yellow";
                    ctx.textAlign = "center";
                    ctx.textBaseline = "bottom";
                    ctx.font = "normal 2pt Arial"
                    ctx.strokeStyle = color;
                    ctx.fillStyle = color;

                    ctx.beginPath();
                    var zeroX = 0.5 * canvas.width;
                    var zeroY = 0.5 * canvas.height;
                    for(var x = 0; x < canvas.width; x++) {
                        var a = (x + i) / 180 * Math.PI;
                        var curX = Math.sin(a) * unitX + zeroX;
                        var curY = Math.cos(a) * unitY + zeroY;
                        if(x == 0) {
                            ctx.moveTo(curX, curY);
                        } else {
                            ctx.lineTo(curX, curY);
                        }
                    }
                    ctx.stroke();

                    var text = "x=sin(a)\ny=cos(a)";
                    var textArr = text.split("\n");
                    for(var index = textArr.length - 1, y = zeroY; index >= 0; index--, y -= 20) {
                        ctx.fillText(textArr[index], zeroX, y);
                    }
                }

                //渲染三角函数
                function render(trigonometricFunction, color) {
                    ctx.strokeStyle = color;
                    ctx.textAlign = "left";
                    ctx.textBaseline = "middle";
                    ctx.font = "bold 18pt Calibri";

                    ctx.beginPath();
                    var isLastInRange = false;
                    for(var x = 0; x < canvas.width; x++) {
                        var a = (x + i) / 180 * Math.PI;
                        var y = trigonometricFunction(a);
                        //tan值有可能是无穷大或无穷小(由于这里是用角度换算的,所以一般不会取到无穷的情况)
                        if(isFinite(y)) {
                            y = y * unitY + 0.5 * canvas.height;
                            if(isLastInRange) {
                                if(y < 0 || y > canvas.height) {
                                    isLastInRange = false;
                                } else {
                                    ctx.lineTo(x, y);
                                }
                            } else {
                                if(!(y < 0 || y > canvas.height)) {
                                    isLastInRange = true;
                                    ctx.moveTo(x, y);
                                }
                            }
                            if(x == 0) {
                                ctx.fillStyle = color;
                                var funcName = trigonometricFunction.toString();
                                var reg = /function\s*(\w*)/i;
                                var matches = reg.exec(funcName);
                                ctx.fillText(matches[1], 0, y);
                            } 
                        } else {
                            isLastInRange = false;
                            break;
                        }
                    }
                    ctx.stroke();
                }

                this.init = function() {
                    function loop() {
                        requestAnimationFrame(loop, canvas);
                        ctx.clearRect(0, 0, canvas.width, canvas.height);
                        update();
                        rendeRcoordinate();
                        renderXSinYCos();
                        render(Math.sin, "red");
                        render(Math.cos, "green");
                        render(Math.tan, "blue");
                    }
                    loop();
                }
            }

            function init() {
                var canvas = document.getElementById("canvas");
                if(!isSupportCanvas(canvas)) {
                    return;
                }
                setupRAF();
                var canvasController = new CanvasController(canvas);
                canvasController.init();
            }

            init();
        </script>
    </body>
</html>

这里写图片描述

注意:在绘制曲线时,例如波浪等看似很像正弦(余弦)函数,基本都是使用贝塞尔曲线。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值