javascript 强制画布更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10597827/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
forcing canvas update
提问by David Burford
Is there any way to force a canvas to update? I'd like to display a loading message but the game locks up loading before it displays. I feel like I need to tell the canvas to "draw now" before load function is called, but maybe there is a another way...
有没有办法强制画布更新?我想显示加载消息,但游戏在显示之前锁定加载。我觉得我需要在调用加载函数之前告诉画布“立即绘制”,但也许还有另一种方法......
EDIT:
编辑:
ok, just to be clear i've written a very small dirty script (best i can do in my tea break :P) to demonstrate what i'm trying to over come. Here:
好的,为了清楚起见,我已经写了一个非常小的脏脚本(我在茶歇时能做的最好的:P)来演示我想要克服的问题。这里:
<html>
<head>
<title>test page</title>
</head>
<body onload="init();">
<canvas id="cnv" width="300" height="300">
canvas not supported.<br/>
</canvas>
</body>
</html>
<script type="text/javascript">
var ctx;
function init()
{
var canvas = document.getElementById('cnv');
ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.fillRect(0,0,300,300);
FakeLoad();
ctx.fillStyle = "rgb(0, 255, 0)";
ctx.fillRect(0,0,300,300);
}
function FakeLoad()
{
var d = new Date();
var start = d.getTime();
while (new Date().getTime() - start < 5000)
{
//emulate 5 secs of loading time
}
}
</script>
now the idea is the script should draw a red square to show its "loading" and a green square when finished. but all you will see if you copy that into a html file is a pause of 5 seconds then the green appears, never red. In my head I wanted to have some command like ctx.Refresh(); after i draw the green square to tell it "update now! don't wait!" but judging from replies this is not the way to handle the problem.
现在的想法是脚本应该在完成后绘制一个红色方块以显示其“加载”和一个绿色方块。但是,如果将其复制到 html 文件中,您将看到的只是 5 秒的暂停,然后出现绿色,而不是红色。在我的脑海里,我想要一些像 ctx.Refresh(); 这样的命令。在我画绿色方块告诉它“现在更新!不要等待!” 但从回复来看,这不是处理问题的方式。
what should I do? :)
我该怎么办?:)
回答by andrewmu
Another thing you could do to allow the canvas to display before you do the longer task is begin FakeLoad after a short timeout:
在执行更长的任务之前,您可以做的另一件事是允许画布显示,在短暂的超时后开始 FakeLoad:
var canvas = document.getElementById('cnv');
ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.fillRect(0,0,300,300);
setTimeout(function() {
FakeLoad();
ctx.fillStyle = "rgb(0, 255, 0)";
ctx.fillRect(0,0,300,300);
}, 20); // 20 ms - should be enough to draw something simple
回答by Andy
If I understand you correctly, there's no way to update a canvas in the same way that you may be able to re-render/paint in WPF or re-flow the HTML DOM.
如果我理解正确,则无法以与在 WPF 中重新渲染/绘制或重新流动 HTML DOM 相同的方式来更新画布。
This is because a canvas uses intermediate mode graphics. Essentially, the only thing that the canvas retains knowledge of is the pixels which make up the canvas. When you call draw rect or draw line, the pixels that make up the rectangle or line are added to the canvas and as far as the canvas is concerned, it forgets all about the draw rect or draw circle call and therefore we cannot refresh the canvas and get the same result.
这是因为画布使用中间模式图形。本质上,画布唯一保留知识的是构成画布的像素。当你调用 draw rect 或 draw line 时,组成矩形或线条的像素被添加到画布上,就画布而言,它会忘记所有关于 draw rect 或 draw circle 的调用,因此我们无法刷新画布并得到相同的结果。
If your looking for something that 'retains' knowledge of the graphics rendered into it, you could try SVG, this uses retained mode graphics. Essentially it has it's own DOM (heirachy of objects (circle, rect etc)), which are re-rendered each time a region is made dirty.
如果您正在寻找“保留”渲染到其中的图形知识的东西,您可以尝试使用 SVG,它使用保留模式图形。本质上,它有自己的 DOM(对象的层次结构(圆形、矩形等)),每次区域变脏时都会重新渲染。
In short, this page is very good at helping you understand the difference between immediate mode graphics and retained mode graphics: http://msdn.microsoft.com/en-us/library/ie/gg193983(v=vs.85).aspx
简而言之,这个页面非常擅长帮助您了解立即模式图形和保留模式图形之间的区别:http: //msdn.microsoft.com/en-us/library/ie/gg193983(v=vs.85)。 aspx
All that said, if I'm misunderstanding your question, please accept my apologies!
说了这么多,如果我误解了你的问题,请接受我的道歉!
Update
更新
From the extra info in the question,
从问题中的额外信息,
The reason why you never see the green square is because the main javascript thread is always busy with your five second loop. It never has any time to update the UI. To allow time for the canvas to update with your loading screen, you'll need to do all your loading asynchronously.
你从来没有看到绿色方块的原因是因为主 javascript 线程总是忙于你的五秒循环。它从来没有时间更新用户界面。为了让画布有时间随着加载屏幕更新,您需要异步执行所有加载。
What sort of loading will you be doing? If it's images etc, you can grab them using $.ajaxand jQuery. This will asynchronously get the images from their location and once the last image has been retrieved, you can then clear and repaint the canvas with your content.
你会做什么样的加载?如果是图像等,您可以使用$.ajax和jQuery获取它们。这将从它们的位置异步获取图像,一旦检索到最后一张图像,您就可以清除并用您的内容重新绘制画布。
I guess something like this:
我猜是这样的:
<script type="text/javascript">
var ctx;
function init()
{
var canvas = document.getElementById('cnv');
ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.fillRect(0,0,300,300);
FakeLoad();
}
function FakeLoad()
{
$.ajax({
url: "www.foo.com/bar.jpg",
success: function(data)
{
// Do something with the data (persist it)
RenderApp();
}
});
}
function RenderApp()
{
// Rendering the rest of the application / game
ctx.fillStyle = "rgb(0, 255, 0)";
ctx.fillRect(0,0,300,300);
}
</script>
Obviously this is kinda psudo-code, but hopefully it'll give you some idea!
显然这是一种伪代码,但希望它能给你一些想法!
let me know if you need any clarification!
如果您需要任何说明,请告诉我!