Javascript: 不能表示正弦图

Javascript: can't represent sinusoidal graph

我想制作一个正弦曲线图移动的盒子。 在我现在所处的位置,我根本无法将框表示为 canvas。一开始我能,但在计算出三角函数部分后,盒子消失了,没有错误...

<!DOCTYPE html>
<html>
 <head>
 </head>
 <body>
    <canvas id="canvas" width="600" height="300" style="background-color:red"></canvas>
    <script type="text/javascript">
        var canvas = document.querySelector("canvas");//isoute me document.getElementsByTagName() 
        var ctx = canvas.getContext("2d");
        var can_width = canvas.width;
        var can_height = canvas.height;
        var x,y;

        function PVector(x_,y_){
            var y = [];
            var x = [0, Math.PI/6, Math.PI/4, Math.PI/3, Math.PI/2, 2/3*Math.PI, 3/4*Math.PI, 
                        5/6*Math.PI, Math.PI, 7/6*Math.PI, 5/4*Math.PI, 4/3*Math.PI, 3/2*Math.PI,
                        5/3*Math.PI, 7/4*Math.PI, 11/6*Math.PI, 2*Math.PI];

            for (var i=0, len=x["length"]; i<len; i++){
                var A;
                A = Math.sin(x[i]);
                y.push(A);

            }console.log(y);console.log(x);
                return{
                    x:x,
                    y:y
                };
        }
        var Point = {
            location : {x:0, y: can_height/2},//initial location
            velocity : new PVector(x,y),
            display : ctx.fillRect(can_width/2,can_height/2 , 25, 25),//initial position of the box
            step : function(){ 
                    this.location.x += this.velocity.x;
                    this.location.y += this.velocity.y;

                },
            display : function(){
                        ctx.fillRect(this.location.x, this.location.y, 25, 25);
                    }   
        };              
        function update(){
            Point["step"]();
            ctx.clearRect(0,0, can_width, can_height);
            Point["display"]();
            window.setTimeout(update, 1000/30);
        }               
        function init(){
            update();
        }
        init();             

    </script>
</body>

问题

在您的 PVector 对象中,您为 xy 返回 Arrays,而您将它们用作 step() 方法中。这将导致整个数组作为字符串添加。

解决方案

您需要遍历该数组的东西。这是一个例子,它可能不是你想要的结果,但它显示了你需要应用的原则:

// first note the return type here:
function PVector(x_,y_){
    var y = [];
    var x = [0, Math.PI/6, Math.PI/4, Math.PI/3, Math.PI/2, 2/3*Math.PI, 
    ...snipped---

    return {
        x:x,  // x and y are arrays
        y:y
    };
}

var Point = {
    location: {
        x: 0,
        y: can_height / 2,
        step: 0                    // some counter to keep track of array position
    }, //initial location
    velocity: new PVector(x, y),
    step: function () {
        
        this.location.step++;     // increase step for arrays

        // using modulo will keep the step as a valid value within the array length:
        // if step = 7 and length = 5, index will become 2 (sort of "wrap around")
        var indexX = this.location.step % this.velocity.x.length;
        var indexY = this.location.step % this.velocity.y.length
        this.location.x += this.velocity.x[indexX];
        this.location.y += this.velocity.y[indexY];

    },
    ...

Updated fiddle

提示:我会像 Robin 在他的回答中一样,建议简化正弦计算。当需要性能并且浏览器跟不上(即,将有数千个对象)时,正弦表很好,但在更简单的场景中,直接计算也可以。

如果您的目标只是让一个盒子在正弦曲线图中移动,可以做得更简单。

This jsfiddle 显示了一个在正弦图中移动的盒子的稍微简单的示例,我只是删除了部分代码并使用 [=22= 计算路径] 并使用时间代替 x 的预先计算值。

function update(){
    time += 0.1;
    ctx.clearRect(0,0, can_width, can_height);
    x = time;
    y = (can_height/2)+(can_height/2)*Math.sin(time);
    console.log(x, y);
    ctx.fillRect(x*16, y, 25, 25);
    window.setTimeout(update, 1000/30);
}  

变量已修改,使其在 canvas 上看起来正常。您可以编辑时间的加法,以及 y 的高度和基线,以满足您的需要。

如果您需要遵循代码中的规范,请查看 Ken 的回答。

既然你想要一个正弦曲线运动,那么使用... sin 函数是有意义的。

正弦移动的公式是:

y = maxValue * sin ( 2 * PI * frequency * time ) ;

其中频率以赫兹 (== 'number of times per second') 为单位,时间以秒为单位。

您很可能会使用 Date.now(),因此您需要转换毫秒时间。由于 PI 的值在不久的将来应该不会改变,因此您可以计算一次幻数

k = 2 * PI / 1000 = 0.006283185307179587

公式变为:

 y = sin( k * frequency * Date.now() );

下面是一个关于如何使用公式的简单示例:

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var can_width = canvas.width;
var can_height = canvas.height;


// magic number
var k = 0.006283185307179587;
// oscillations per second
var frequency = 1/5;
// ...
var amplitude = can_width / 8; 


function animate() {
   ctx.clearRect(0,0,can_width, can_height);
   ctx.fillStyle= '#000';
   var y = amplitude * Math.sin ( k * frequency * Date.now() );
   ctx.fillRect(can_width/2, can_height/2 + y, 20, 20 );
}

setInterval(animate, 30);
<canvas id="canvas" width="400" height="200" style="background-color:red"></canvas>