在剪裁的画布中移动所有图像

Moving All Images In A Clipped Canvas

本文关键字:图像 移动 布中 剪裁      更新时间:2023-12-14

好的,所以我刚刚研究了Canvas元素,但遇到了一个障碍。

我发现了一个演示,它使用箭头键将三个图像在一个图像的顶部移动。

然而,我剪切了其中一个,下面的图像现在没有移动,即使上面剪切的图像移动了。

HTML:

<canvas id="parallax-canvas">
    Sorry, your browser does not support HTML5 Canvas.
</canvas>

CSS:

.parallax-canvas {
    width: 400px;
    height: 300px;
}

JavaScript:

$(document).ready(function() {
    var w = $("#parallax-canvas").width();
    var h = $("#parallax-canvas").height();
    var sky = new Image();
    sky.src = "assets/img/sky.jpg";
    var skydx = 2;
    var skyx = 0;
    var mountains = new Image();
    mountains.src ="assets/img/mountains.png";
    var mountainsdx = 10;
    var mountainsx = 0;
    var jeep = new Image();
    jeep.src ="assets/img/jeep.png";
    var jeepx = 100; 
    var jeepy = 210; 
    var jeepsx = 0; 
    var jeepsxWidth = 155;
    var cntx =  $("#parallax-canvas")[0].getContext("2d");
    setInterval(draw, 10, cntx);
    $(window).keydown(function(evt) {
        switch (evt.keyCode) {
            case 37: // Left arrow
                if ((skyx + skydx) > skydx)
                  skyx -= skydx;
                else
                  skyx = w;
                if ((mountainsx + mountainsdx) > mountainsdx)
                  mountainsx -= mountainsdx;
                else
                  mountainsx = 398;
                if (jeepsx > 0) 
                    jeepsx -= jeepsxWidth;
                else 
                    jeepsx = (jeepsxWidth*2);
            break;
            case 39: // Right arrow
                if ((skyx + skydx) < (w - skydx))
                  skyx += skydx;
                else
                  skyx = 0;
                if ((mountainsx + mountainsdx) < (w - mountainsdx))
                  mountainsx += mountainsdx;
                else
                  mountainsx = 0;
                if (jeepsx < (jeepsxWidth*2))
                   jeepsx += jeepsxWidth;
                else
                   jeepsx = 0;
                break;
        }
    });
    function draw(_cntx) {
        drawRectangle(_cntx, 0, 0, w, h);
        _cntx.drawImage(sky, skyx, 0, 300, 300, 0, 0, w, 300);
        _cntx.beginPath();
        _cntx.moveTo(0,300);
        _cntx.lineTo(150,150);
        _cntx.lineTo(300, 300);
        _cntx.closePath();
        _cntx.clip();
        _cntx.drawImage(mountains, mountainsx, 0, 300, 300, 0, 0, w, 300);
        _cntx.drawImage(jeep, jeepsx, 0, jeepsxWidth, 60, jeepx, jeepy, 155, 60);
    }
    function drawRectangle(_cntx, x, y, w, h) {
        _cntx.beginPath();
        _cntx.rect(x,y,w,h);
        _cntx.closePath();
        _cntx.fill();
        _cntx.stroke();
    }
});

我添加剪辑的部分是这个部分:

function draw(_cntx) {
    drawRectangle(_cntx, 0, 0, w, h);
    _cntx.drawImage(sky, skyx, 0, 300, 300, 0, 0, w, 300);
    _cntx.beginPath();
    _cntx.moveTo(0,300);
    _cntx.lineTo(150,150);
    _cntx.lineTo(300, 300);
    _cntx.closePath();
    _cntx.clip();
    _cntx.drawImage(mountains, mountainsx, 0, 300, 300, 0, 0, w, 300);
    _cntx.drawImage(jeep, jeepsx, 0, jeepsxWidth, 60, jeepx, jeepy, 155, 60);
}

如果从beginPath方法移除并将其包含到剪辑方法中,将允许三个图像全部移动。

发生了什么:按下左右箭头键时,天空图像不会移动,山脉和吉普车会被剪裁,但会在剪裁区域内移动。

我想发生的事情:天空图像移动,以及剪辑区域的山脉和吉普车。

还有:

我想知道如何使用箭头键移动剪切区域。我的意思是,目前有一个剪切区域,通过向左和向右按压,图像会移动,但剪切(剪切)区域保持静止。我想知道(如果可能的话)如何使用箭头键移动剪切区域。

正在使用的演示:http://www.ibm.com/developerworks/web/library/wa-parallaxprocessing/

不幸的是,无法设置Fiddle,因为图像不在网站上,所以无法提供URL,但.zip在网站上。通过复制和粘贴代码的底部,他们的方法在JavaScript文件中,这就是我得到的。

谢谢你的帮助!

编辑:感谢Ken在缩短代码和提高效率方面的帮助。然而,到目前为止,还没有什么能回答我最初关于如何移动图像以及剪切位置的问题。

您需要为画布设置大小-不要使用CSS来设置画布的大小:

<canvas id="parallax-canvas" width=500 height=300>
    Sorry, your browser does not support HTML5 Canvas.
</canvas>

同样,你需要从画布上读取合适的尺寸:

$(document).ready(function() {
    var canvas = $("#parallax-canvas")[0];
    var w = canvas.width;
    var h = canvas.height;
    ...

每次按下光标键时,都需要重新绘制所有内容。画布不知道里面画了什么——它只是一堆像素,所以我们需要自己提供更新的逻辑。

Update似乎我错过了您从setInterval循环进行重绘的机会,所以这不太适用,但我保留了这个例子,因为它可能是一种更好的方法,因为您只需要在实际发生变化时进行更新。例如,一个总是重新绘制所有内容的循环会很快耗尽电池电量。。

例如:

$(window).keydown(function(evt) {
    switch (evt.keyCode) {
        case 37: // Left arrow
            if ((skyx + skydx) > skydx)
              skyx -= skydx;
            else
              skyx = w;
            if ((mountainsx + mountainsdx) > mountainsdx)
              mountainsx -= mountainsdx;
            else
              mountainsx = 398;
            if (jeepsx > 0) 
                jeepsx -= jeepsxWidth;
            else 
                jeepsx = (jeepsxWidth*2);
        draw(cntx );
        break;
        ...

你需要在其他动作中重复这个动作。

由于加载是异步的,因此加载图像的方式也会遇到问题。您需要通过点击onload处理程序来处理加载:

var sky = new Image();
sky.onload = functionToHandleLoad;
sky.src = "assets/img/sky.jpg";

当你加载许多图像时,你需要对图像进行计数或使用批量加载程序,如我的YAIL加载程序。

对于剪辑,使用保存/恢复很重要,因为当前浏览器无法很好地处理剪辑区域的手动重置:

function draw(_cntx) {
    drawRectangle(_cntx, 0, 0, w, h);
    _cntx.drawImage(sky, skyx, 0, 300, 300, 0, 0, w, 300);
    _cntx.beginPath();
    _cntx.moveTo(0,300);
    _cntx.lineTo(150,150);
    _cntx.lineTo(300, 300);
    _cntx.closePath();
    _cntx.save();     /// save current clip region
    _cntx.clip();
    _cntx.drawImage(mountains, mountainsx, 0, 300, 300, 0, 0, w, 300);
    _cntx.drawImage(jeep, jeepsx, 0, jeepsxWidth, 60, jeepx, jeepy, 155, 60);
    _cntx.restore();  /// reset clip
}

在回答的时候,那里没有小提琴,所以我还没有检查代码的其他部分,但我认为这应该是一个好的开始。

此功能

function drawRectangle(_cntx, x, y, w, h) {
    _cntx.beginPath();
    _cntx.rect(x,y,w,h);
    _cntx.closePath();
    _cntx.fill();
    _cntx.stroke();
}

可以简化为:

function drawRectangle(_cntx, x, y, w, h) {
    _cntx.fillRect(x, y, w, h);
    _cntx.strokeRect(x, y, w, h);
}

不需要关闭rect上的路径,并且不需要使用fillRect/strokeRect的beginPath。