1

我正在尝试练习 HTML5 画布绘图,所以我想出了这个。我应该得到一个黄色的星星,上面有一个绿色的半身像(人的头部和肩膀)的轮廓重叠

但是,如果 drawStar() 线未注释,则不会绘制绿色轮廓。这个工作代码是否不如解释正在发生的事情重要。

http://jsfiddle.net/xiondark2008/LYfHJ/2/

HTML:

<!DOCTYPE html>
<html>
<head>
    <style>
    h6{
        -webkit-margin-before: .5em;
        -webkit-margin-after: 0;
    }
    label{
        margin-left: 1em;
    }
    </style>

</head>
<body>

    <canvas id="myCanvas" width="19" height="19" 
        style="border:1px solid d3d3d3;">
        Your browser does not support the HTML5 canvas tag.</canvas>
</body>
</html>

javascript:

function drawProfile(ctx,x,y,width,height) {
    this.flp = false;
    this.x = function(r){ return Math.floor(width*(this.flp?1-r:r)); }
    this.y = function(r){ return Math.floor(height*r); }

    ctx.save();

    ctx.translate( x, y );
    ctx.fillStyle="#40FF00";

    ctx.beginPath();
    ctx.moveTo( this.x(0), this.y(1) );
    ctx.bezierCurveTo(
        this.x(0),      this.y(125/190),
        this.x(70/190), this.y(170/190),
        this.x(75/190), this.y(120/190)
    );
    ctx.lineTo( this.x(95/190), this.y(130/190) );
    ctx.bezierCurveTo(
        this.x(40/190), this.y(130/190),
        this.x(30/190), this.y(0), 
        this.x(95/190), this.y(0)
    );

    this.flp = true;

    ctx.bezierCurveTo(
        this.x(30/190), this.y(0),
        this.x(40/190), this.y(130/190), 
        this.x(95/190), this.y(130/190)
    );
    ctx.lineTo( this.x(75/190), this.y(120/190) );
    ctx.bezierCurveTo(
        this.x(70/190), this.y(170/190),
        this.x(0), this.y(125/190),
        this.x(0), this.y(1)
    );
    ctx.fill();

    this.flp = false;

    ctx.restore();
}

function drawStar(ctx,x,y,height) {

    var pnts = 5,
        rad = height/(1-Math.cos(0.8*Math.PI));

    this.x = function(p,dst){
        return dst * Math.sin( (p/pnts)*2*Math.PI );
    }
    this.y = function(p,dst){
        return dst * Math.cos( (p/pnts)*2*Math.PI ) * -1;
    }
    this.movePct = function(a,b,pct){
        var f = (function(x){
                var m = (b.y-a.y)/(b.x-a.x);
                return m*x+(a.y-(a.x*m));
            }).bind(),
            r = b.x - a.x,
            point = {};

        point.x = a.x+(r*pct);
        point.y = f(point.x);

        return point;
    }
    this.transPoints = function(s,p,e,pct){
        var sp = this.movePct(s,p,pct),
            ep = this.movePct(e,p,pct);

        return [sp,ep];
    }

    ctx.save();

    ctx.translate( x+rad, y+rad );
    ctx.fillStyle = "#ffff00";

    ctx.beginPath();

    for(var i=0;i<pnts;i++){
        var dst = rad/2,
            s = { x: this.x( i+0.5, dst ),
                  y: this.y( i+0.5, dst ) },
            p = { x: this.x( i+1, rad ),
                  y: this.y( i+1, rad ) },
            e = { x: this.x( i+1.5, dst ),
                  y: this.y( i+1.5, dst ) },
            t = this.transPoints(s,p,e,.75);

        if(i==0){ ctx.moveTo( s.x, s.y ); }

        ctx.lineTo(t[0].x, t[0].y);
        ctx.quadraticCurveTo(p.x, p.y, t[1].x, t[1].y);
        ctx.lineTo(e.x, e.y);
    }
    ctx.fill();

    ctx.restore();

}

function draw(c) {

    var ctx = c.getContext("2d");

    this.x = function(r){ return c.width*r; }
    this.y = function(r){ return c.height*r; }

    ctx.shadowBlur=this.y(1/19);
    ctx.shadowColor="black";

    //drawStar( ctx, this.x(-3/19), this.y(-1/19), this.y(20/19) );
    drawProfile( ctx, this.x(6/19), this.y(1/19), this.x(18/19), this.y(18/19) );


    if(0){
        ctx.clearRect( this.x(1), this.y(0), this.x(1), this.y(1) );
        ctx.clearRect( this.x(0), this.y(1), this.x(1), this.y(1) );
    }

}

draw( document.getElementById("myCanvas") );
4

2 回答 2

2

您正在使用this您的功能。在这里的上下文中,this必然window(有很多关于如何使用的资源,但this你做错了)。

在您使用的每个函数中this,is 都绑定到相同的事物 ( window),因此它们会覆盖彼此的变量。(这是因为您使用这些功能的方式。如果您new编辑它们,那将是另一回事)。

所以

  1. 你的draw()方法集this.x,实际上是window.x
  2. 然后将其drawStar()作为参数传递给
  3. drawStar()函数方法改变this.x(which is )的值window.x并返回draw()
  4. 然后用(which is )draw()调用,但这次它的值是一个函数,而不是你想要的浮点值。drawProfile()this.xwindow.x
  5. drawProfile 期望参数是一个浮点数,但现在它是一个函数

(用于x阅读xy

您可以使用闭包和变量来完成这一切。删除thises,您的程序将运行。大概。

于 2013-09-04T13:50:14.783 回答
0

乔是对的。您正在覆盖 this.x 和 this.y 函数。我不知道你为什么要这样做。我通过在函数 drawProfile 和 drawStar 的末尾将 this.x 和 this.y 函数重置为其旧值来解决问题:

function drawProfile(ctx,x,y,width,height) {
    var oldX = this.x, //storing the old values for this.x ...
        oldY = this.y; // ... and this.y
    this.flp = false;
    this.x = function(r){ return Math.floor(width*(this.flp?1-r:r)); }
    this.y = function(r){ return Math.floor(height*r); }

    ctx.save();

    ctx.translate( x, y );
    ctx.fillStyle="#40FF00";

    ctx.beginPath();
    ctx.moveTo( this.x(0), this.y(1) );
    ctx.bezierCurveTo( this.x(0), this.y(125/190),
                       this.x(70/190), this.y(170/190),
                       this.x(75/190), this.y(120/190)
                      );
    ctx.lineTo( this.x(95/190), this.y(130/190) );
    ctx.bezierCurveTo( this.x(40/190), this.y(130/190),
                       this.x(30/190), this.y(0), 
                       this.x(95/190), this.y(0)
                      );

    this.flp = true;

    ctx.bezierCurveTo( this.x(30/190), this.y(0),
                       this.x(40/190), this.y(130/190), 
                       this.x(95/190), this.y(130/190)
                      );
    ctx.lineTo( this.x(75/190), this.y(120/190) );
    ctx.bezierCurveTo( this.x(70/190), this.y(170/190),
                       this.x(0), this.y(125/190),
                       this.x(0), this.y(1)
                      );
    ctx.fill();

    this.flp = false;

    ctx.restore();

    this.x = oldX; //Restoring old values
    this.y = oldY;
}

function drawStar(ctx,x,y,height)
{
    var pnts = 5,
        rad = height/(1-Math.cos(0.8*Math.PI)),
        oldX = this.x, //storing the old values for this.x ...
        oldY = this.y; // ... and this.y

    this.x = function(p,dst){
        return dst * Math.sin( (p/pnts)*2*Math.PI );
    }
    this.y = function(p,dst){
        return dst * Math.cos( (p/pnts)*2*Math.PI ) * -1;
    }
    this.movePct = function(a,b,pct){
        var f = (function(x){
            var m = (b.y-a.y)/(b.x-a.x);
            return m*x+(a.y-(a.x*m));
        }).bind(),
            r = b.x - a.x,
            point = {};

        point.x = a.x+(r*pct);
        point.y = f(point.x);

        return point;
    }
    this.transPoints = function(s,p,e,pct){
        var sp = this.movePct(s,p,pct),
            ep = this.movePct(e,p,pct);

        return [sp,ep];
    }

    ctx.save();

    ctx.translate( x+rad, y+rad );
    ctx.fillStyle = "#ffff00";

    ctx.beginPath();

    for(var i=0;i<pnts;i++){
        var dst = rad/2,
            s = { x: this.x( i+0.5, dst ),
                 y: this.y( i+0.5, dst ) },
            p = { x: this.x( i+1, rad ),
                 y: this.y( i+1, rad ) },
            e = { x: this.x( i+1.5, dst ),
                 y: this.y( i+1.5, dst ) },
            t = this.transPoints(s,p,e,.75);

        if(i==0){ ctx.moveTo( s.x, s.y ); }

        ctx.lineTo(t[0].x, t[0].y);
        ctx.quadraticCurveTo(p.x, p.y, t[1].x, t[1].y);
        ctx.lineTo(e.x, e.y);
    }
    ctx.fill();

    ctx.restore();

    this.x = oldX; //Resetting the old values
    this.y = oldY;
}

function draw(c)
{

    var ctx = c.getContext("2d");

    this.x = function(r){ return c.width*r; }
    this.y = function(r){ return c.height*r; }

    ctx.shadowBlur=this.y(1/19);
    ctx.shadowColor="black";

    drawStar( ctx, this.x(-3/19), this.y(-1/19), this.y(20/19) );
    drawProfile( ctx, this.x(6/19), this.y(1/19), this.x(18/19), this.y(18/19) );



    if(0){
        ctx.clearRect( this.x(1), this.y(0), this.x(1), this.y(1) );
        ctx.clearRect( this.x(0), this.y(1), this.x(1), this.y(1) );
    }

}

draw( document.getElementById("myCanvas") );

http://jsfiddle.net/hhaXM/

于 2013-09-04T14:02:00.727 回答