Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/446.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript HTML5画布中最简单的幻灯片,canvas.context.clearRect不使用setTimeout_Javascript_Html_Canvas_Html5 Canvas - Fatal编程技术网

Javascript HTML5画布中最简单的幻灯片,canvas.context.clearRect不使用setTimeout

Javascript HTML5画布中最简单的幻灯片,canvas.context.clearRect不使用setTimeout,javascript,html,canvas,html5-canvas,Javascript,Html,Canvas,Html5 Canvas,这是一个非常简单的幻灯片的代码,应该在4秒内显示4个图像,每秒一个图像。取而代之的是,我得到了4秒的延迟,然后所有的图像都被画在彼此的上面。我做错了什么 <html> <head> <script langugage="javascript"> // 4 images var image0 = new Image(); image0.src = "img/image0.png"; var image1 = new Image(); image1.src = "

这是一个非常简单的幻灯片的代码,应该在4秒内显示4个图像,每秒一个图像。取而代之的是,我得到了4秒的延迟,然后所有的图像都被画在彼此的上面。我做错了什么

<html>
<head>
<script langugage="javascript">
// 4 images
var image0 = new Image();
image0.src = "img/image0.png";
var image1 = new Image();
image1.src = "img/image1.png";
var image0 = new Image();
image2.src = "img/image2.png";
var image3 = new Image();
image3.src = "img/image3.png";
// array of 4 images
images = new Array(image0, image1, image2, image3);

// this is the main function
function draw(){
    myCanvas = document.getElementById('myCanvas');
    ctx = myCanvas.getContext('2d');
    counter=0; // this is the index of the next image to be shown
    for (var i=0;i<images.length;i++){
        setTimeout(draw_next_image, 1000);
        ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
    }
}
// this is the function called after each timeout to draw next image
function draw_next_image(){
    ctx.drawImage(images[counter], 0, 0);
    counter++;
    if (counter>images.length) {counter=0;}
}

window.onload = draw;
</script>
</head>
<body>
    <canvas id="myCanvas" width="800" height="600"></canvas>
</body>
</html>

//4图像
var image0=新图像();
image0.src=“img/image0.png”;
var image1=新图像();
image1.src=“img/image1.png”;
var image0=新图像();
image2.src=“img/image2.png”;
var image3=新图像();
image3.src=“img/image3.png”;
//4幅图像的数组
图像=新阵列(图像0、图像1、图像2、图像3);
//这是主要功能
函数绘图(){
myCanvas=document.getElementById('myCanvas');
ctx=myCanvas.getContext('2d');
计数器=0;//这是要显示的下一个图像的索引
对于(vari=0;iimages.length){counter=0;}
}
window.onload=draw;
更新:答案是:

在上面的代码中,我错误地假设
getTimeout
函数是同步的,也就是说,我期望在调用时程序执行将停止,等待1000毫秒,然后调用
draw\u next\u image
,然后才执行
ctx.clearRect


事实上,Javascript不是这样工作的。实际上,
getTimeout
是异步的,也就是说,
getTimeout
设置一个超时并几乎立即返回,代码继续执行,因此,
ctx.clearRect
立即被调用,实际上是在
绘制下一幅图像之前被调用。因此,当超时过期并调用
draw\u next\u image
时,代码的执行可能达到任意行代码。在我的例子中,所有4
clearRect
都将几乎同时被调用,远远早于超时到期。然后1000毫秒后,所有4个超时几乎会立即一个接一个地过期,并且所有4个图像也将几乎同时绘制,而没有早就执行过的clearRects

您有一些问题,包括图像变量的命名错误

试试这个:

// 4 images
var image0 = new Image();
image0.src = "http://placekitten.com/200/300";
var image1 = new Image();
image1.src = "http://placekitten.com/205/305";
var image2 = new Image();
image2.src = "http://placekitten.com/300/400";
var image3 = new Image();
image3.src = "http://placekitten.com/800/600";
// array of 4 images
images = new Array(image0, image1, image2, image3);

// global counter and canvas
var counter = 0, ctx, interval;

// this is the main function
function draw(){
    myCanvas = document.getElementById('myCanvas');
    ctx = myCanvas.getContext('2d');
    interval = setInterval(draw_next_image, 1000);
}

// this is the function called after each timeout to draw next image
function draw_next_image(){
    ctx.clearRect(0, 0, myCanvas.width, myCanvas.height);
    ctx.drawImage(images[counter], 0, 0);
    counter++;
    if (counter==images.length) {counter=0;}
}

window.onload = draw;

见:例如。您还可以暂停幻灯片放映,因为我们正在为
setInterval()
函数指定间隔。问题是,在代码中,您将异步函数视为同步函数

要点如下:

image0.src = "img/image0.png";
image1.src = "img/image1.png";
image2.src = "img/image2.png";
image3.src = "img/image3.png";
...
setTimeout(draw_next, delayInMilliseconds);
因为这些调用一旦被调用就会失败,并且您的代码在这些调用的结果(可能)准备就绪之前开始执行下一步

因此,您需要根据事件链接您的呼叫,例如:

//image counter as there is no guarantee that the last images loaded
//is the last one to finish
var loaded = 0, numOfImages = 4;

//first part of chain, invoke async load
var image0 = document.createElement('img'); //this will work in new Chrome
var image1 = document.createElement('img'); //instead of new Image
var image2 = document.createElement('img');
var image3 = document.createElement('img');

//common event handler when images has loaded with counter
//to know that all images has loaded
image0.onload = image1.onload = 
image2.onload = image3.onload = function(e) {
    loaded++;
    if (loaded === numOfImages)
        draw();   // <-- second part of chain, invoke loop
}

//show if any error occurs
image0.onerror = image1.onerror = 
image2.onerror = image3.onerror = function(e) {
    console.log(e);
}

//invoke async loading... you can put these four into your
//window.onload if you want to
image0.src = "img/image0.png";
image1.src = "img/image1.png";
image2.src = "img/image2.png";
image3.src = "img/image3.png";

// this is the main function
function draw() {

    var images = new Array(image0, image1, image2, image3),
        counter = 0,
        delayInMilliseconds = 4000,
        maxNum = images.length - 1,

        myCanvas = document.getElementById('myCanvas'),
        ctx = myCanvas.getContext('2d'),

        me = this; //this we need for setTimeout()

    //third part of chain, have a function to invoke by setTimeout
    this._draw = function() {

        //if the next image will cover the canvas
        //there is no real need to clear the canvas first.
        //I'll leave it here as you ask for this specifically
        ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
        ctx.drawImage(images[counter++], 0, 0);
        if (counter > maxNum) counter = 0;

        setTimeout(me._draw, delayInMilliseconds); //use me instead of this
    }
    this._draw(); //START the loop
}
//图像计数器,因为不能保证最后加载的图像
//是最后一个完成的吗
加载的var=0,numOfImages=4;
//链的第一部分,调用异步加载
var image0=document.createElement('img')//这将在新的Chrome中工作
var image1=document.createElement('img')//而不是新的形象
var image2=document.createElement('img');
var image3=document.createElement('img');
//使用计数器加载图像时的公共事件处理程序
//要知道所有图像都已加载
image0.onload=image1.onload=
image2.onload=image3.onload=function(e){
加载++;
如果(已加载===numOfImages)
draw();/这个怎么样

HTML

<!DOCTYPE HTML>
<html>
    <head>
        <title>Slider</title>
        <meta charset="utf-8">
        <link type="text/css" rel="stylesheet" href="css/main.css">
    </head>
    <body>
        <canvas id="canvas" width="600" height="400"></canvas>
        <script type="text/javascript" src="js/slider.js"></script>
    </body>
</html>

滑块
Javascript

// The 3 images
var im1 = new Image();
im1.src = "img/kitten1.jpg";
var im2 = new Image();
im2.src = "img/kitten2.jpg";
var im3 = new Image();
im3.src = "img/kitten3.jpg";

// Starting position of the 3 images
var x1 = 0;
var x2 = -600;
var x3 = -1200;

var counter = 0;
var img_count = 0;

// Canvas
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
//This draws the first image when the page is loaded
ctx.drawImage(im1, x1, 0);

function sliderMove() {
    if(counter <= 590) {
        x1+=10;
        ctx.drawImage(im1,x1,0);
        x2+=10;
        ctx.drawImage(im2,x2,0);
        x3+=10;         
        ctx.drawImage(im3,x3,0);


        counter+=10;
    }
    else {
        counter = 0;
        img_count++

        if(img_count == 1) {
            x1 = -1200;
        }else if(img_count == 2) {
            x2 = -1200;
        }else if(img_count == 3) {
            x3 = -1200;
        }
        // This stops move_loop once counter gets to 600
        clearInterval(move_loop);
    }
}
function moveImg() {
//This part moves all of the images 20px to the right every 10ms
    move_loop = setInterval(sliderMove, 10);
    if(img_count > 2) {
        img_count = 0;
    }
}
// This executes the moveImg function every 5 seconds
image_loop = setInterval(timer, 5000);
//三幅图像
var im1=新图像();
im1.src=“img/kitten1.jpg”;
var im2=新图像();
im2.src=“img/kitten2.jpg”;
var im3=新图像();
im3.src=“img/kitten3.jpg”;
//3个图像的起始位置
var-x1=0;
变量x2=-600;
var x3=-1200;
var计数器=0;
var img_计数=0;
//帆布
canvas=document.getElementById(“canvas”);
ctx=canvas.getContext(“2d”);
//这将在加载页面时绘制第一个图像
ctx.drawImage(im1,x1,0);
函数sliderMove(){
如有需要(柜台2){
img_计数=0;
}
}
//这将每5秒执行一次moveImg函数
image_loop=setInterval(定时器,5000);

如果代码不是很有条理,很抱歉。这是我第一次用javascript创建任何东西。

Rob W:谢谢你的回答。所以,你用setInterval替换了setTimeout来创建一个持久循环。但是我真的想一次创建一个超时,而不是一个时间间隔。我不明白,为什么不起作用?啊,我想我知道了,我希望setTimeout是同步的,但它是异步的:这意味着,当调用setTimeout并立即执行下一个语句时,它会立即返回(即clearRect)这样,所有4个迭代clearRect几乎立即运行,直到超时过期,我的4个
draw_next_image
函数被执行,所有4个图像都被绘制在彼此的顶部,对吗?对。如果使用setTimeout,则需要4个图像…因此,对于每次迭代,请尝试执行
setTimeout(函数,1000*次迭代)
。这将使它们以类似同步的方式运行。谢谢!嗯,我想知道,javascript中根本没有同步等待功能吗?好的,肯,谢谢你的回答和建议。所以基本上,setTimeout是异步的,会立即返回,然后执行下一行代码。此外,你为什么用
document.crea替换静态图像teElement('img')
?有什么更好的方法吗?正确-
setTimeout
只需在事件队列中对事件进行排队,以便在超时时执行代码,然后继续执行,以便执行下一行代码。
createElement
的原因是,据报告,较新的Chrome出现了“new Image”无法使用的问题。这种方法行得通。请将您的答案添加为实际答案,而不是添加到您的问题中。