gpt4 book ai didi

html - 在此示例中,Canvas.Context保存和还原的目的是什么?

转载 作者:行者123 更新时间:2023-12-02 03:07:05 26 4
gpt4 key购买 nike

This page在HTML5 Canvas 中显示了一些动画。如果查看source of the scroller,则有一条语句可以在清除矩形并在动画之后将其还原后保存上下文。如果我用另一个ctx.clearRect(0, 0, can.width, can.height语句代替restore语句,则没有任何效果。我以为还原正在还原已清除的矩形,但似乎正在还原更多信息。下一帧需要额外的信息吗?

我不是在寻找“保存和还原”的HTML5教科书定义,但我想了解为什么在此特定示例中需要它们。

更新

在我不想获得save()和restore()定义的问题中已经特别提到的答案令人沮丧。我已经知道Save()保存上下文的状态,而Restor()e恢复它的状态。我的问题很具体。当所有Save操作都保存为空 Canvas 时,为什么按示例中的方式使用restore()。为什么恢复空的 Canvas 与删除相同?

最佳答案

Canvas 状态不是画在上面的。它是一堆属性,这些属性定义了工具的当前状态,这些工具用于绘制下一个事物的

Canvas 是立即模式位图。
就像MS Paint。一旦存在,就在那里,因此没有必要“保存”当前图像数据,因为这就像保存整个JPEG,每次进行更改,每帧...

...不,您要保存的状态是一种状态,该状态将决定您用来绘制NEXT对象(以及之后的所有对象,直到您手动更改这些值)的坐标方向,尺寸比例,颜色等。

var canvas = document.createElement("canvas"),
easel = canvas.getContext("2d");

easel.fillStyle = "rgb(80, 80, 120)";
easel.strokeStyle = "rgb(120, 120, 200)";

easel.fillRect(x, y, width, height);
easel.strokeRect(x, y, width, height);

easel.save(); // stores ALL current status properties in the stack

easel.rotate(degrees * Math.PI / 180); // radians
easel.scale(scale_X, scale_Y); // any new coordinates/dimensions will now be multiplied by these
easel.translate(new_X, new_Y); // new origin coordinates, based on rotated orientation, multiplied by the scale-factor

easel.fillStyle = "gold";
easel.fillRect(x, y, width, height); // completely new rectangle
// origin is different, and the rotation is different, because you're in a new coordinate space

easel.clearRect(0, 0, width, height); // not even guaranteed to clear the actual canvas, anymore
easel.strokeRect(width/2, height/2, width, height); // still in the new coordinate space, still with the new colour


easel.restore(); // reassign all of the previous status properties
easel.clearRect(0, 0, width, height);

假设您只是堆栈上一个状态的深处更改,那么既然 Canvas 的先前状态已还原,那么最后一行应该已经成功清除了自身(尽管有亚像素的恶作剧)。

正如您所看到的,它与擦除 Canvas 几乎没有任何关系。
实际上,它根本与擦除无关。

它涉及到想要绘制一些东西,进行基本的轮廓绘制和广泛的颜色/样式,然后在顶部手动为较小的细节编写颜色,然后以以前的方式手动编写所有样式,返回到下一个对象的笔触,然后不停地...

取而代之的是,保存将被重用的常规状态,为较小的细节创建一个新状态,然后返回常规状态,而不必每次都对其进行硬编码,或者编写设置函数以在 Canvas 上设置常用值以上(重置比例/旋转/仿射变换/颜色/字体/线宽/基线对齐/等)。

然后,在您的确切示例中,如果您注意的话,您将看到唯一改变的是step的值。

他们为 Canvas 设置了一堆值的状态(颜色/字体/等)。
然后他们保存。好吧,他们保存了什么?
您看起来不够深。他们实际上将保存为默认翻译(即,原始世界空间中的origin = 0,0)
但是您没有看到他们定义它吗?
那是因为它被定义为默认值。

然后,他们增加了第1步像素(实际上,他们首先这样做,但是在第一个循环之后没关系-留在我这里)。
然后,他们将新起点设置为0,0(即:从现在开始,当他们键入0,0时,新起点将指向 Canvas 上一个完全不同的位置)。

该原点等于x是 Canvas 的正中间,而y等于当前步长(即:像素1或像素2等,以及为什么从0开始与从1开始之间的差实际上并没有没关系)。

那他们怎么办?
他们恢复了。

好吧,他们恢复了什么?
...嗯,他们改变了什么?

他们正在将原点恢复为0,0
为什么?

好吧,如果他们不这样做会发生什么?
如果 Canvas 是500px x 200px,并且在我们当前的屏幕空间中是从0,0开始的……那太好了……
然后他们将其转换为width / 2,1
好的,所以现在当他们要求以0,0绘制文本时,他们实际上将以250,1绘制

精彩。但是下次会发生什么?

现在他们按width / 2,2进行翻译
您认为很好,... 0,0的绘制调用将在250、2处进行,因为他们已将其设置为清除数字:canvas.width / 2,2

不。因为根据我们的屏幕,当前0,0实际上是250,1。并且一种翻译是相对于先前的翻译...

...所以现在您要告诉 Canvas 从当前坐标的0,0开始,向左走250,再向下走2。
根据屏幕(就像一个窗口,看着 map ,而不是 map 本身),我们现在向右500px,从开始的地方向下3像素...只有一帧过去了。

因此,在设置新的坐标系之前,他们将 map 的坐标系恢复为与屏幕坐标系相同的原点(旋转度相同,比例尺和倾斜度等)。

正如您可能猜到的那样,现在看一下,您可以看到文本实际上应该从上到下移动。不是从右到左,就像页面上说的那样...

为什么这样
当draw命令在函数中直接为您提供xy时,为什么要麻烦更改绘图上下文的坐标系?

如果您想在 Canvas 上绘制图片,并且知道它的高度和宽度,以及您希望将左上角放在何处,为什么不能这样做:
easel.drawImage(myImg, x, y, myImg.width, myImg.height);

好吧,你可以。
您完全可以做到这一点。没有什么可以阻止你的。

实际上,如果要使其在屏幕上缩放,则可以仅在计时器上更新xy,并将其命名为“day”。

但是,如果您要绘制游戏角色呢?如果角色戴着帽子,戴着手套的手和大靴子,并且所有这些东西都与角色分开绘制怎么办?

因此,首先您要说:“好吧,他在世界上处于x和y的位置,因此,x与他的手相对于他的 body 的位置之和为x + body.x-hand.x ...或者是那个加号。 ..”

...现在,您可以对他的所有零件进行抽奖,这些零件看起来都像是笔记本,装有5年级数学作业。

相反,您可以说:“他在这里。设置我的坐标,以使0,0恰好在我的中间”。现在,您的绘图调用非常简单,例如“我的右手在主体右侧6个像素,我的左手在左侧3个像素”。

绘制完角色后,可以将原点设置回0,0,然后再绘制下一个角色。或者,如果您想尝试该操作,则可以根据从一个字符到另一个字符的差额,从那里转换到下一个字符的原点(这将为您节省每次转换的函数调用)。然后,如果您一直只保存一次状态(原始状态),那么最后,可以通过调用.restore返回0,0。

关于html - 在此示例中,Canvas.Context保存和还原的目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16409105/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com