html画布图片不显示_如何在HTML5画布上显示图像

html画布图片不显示

by Nash Vail

由Nash Vail

Ok, so here’s a question: “Why do we need an article for this, Nash?”

好的,这是一个问题:“为什么我们需要为此写一篇文章,纳什?”

Well, grab a seat.

好吧,坐下。

No wait! First, have a look at this.

不用了 首先,看看这个。

Exactly. What was that?

究竟。 那是什么?

drawImage is the method used to display or “draw” an image on canvas. You might or might not already know that it’s not as simple as just passing the URI of the image to it. drawImage accepts a maximum of 9 parameters. They go something like this, ready? Hold your breath…

drawImage是用于在canvas上显示或“绘制”图像的方法。 您可能已经知道,也许还不知道它并不像将图像的URI传递给它那样简单。 drawImage最多接受9个参数。 他们会这样,准备好了吗? 屏住呼吸…

(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

Breathe, out.

呼。

I found the documentation for drawImage a little confusing and hardcore. Just the documentation, yes. The concept and how the API works is great for all the needs that it is supposed to serve.

我发现drawImage文档有点混乱和顽固。 只是文档,是的。 API的概念和工作方式非常适合应满足的所有需求。

We’ll go over the parameters mentioned above one by one, in a way that’ll make complete sense to you. If at any point in the article you find yourself going “I just wanted to draw an image on my canvas, dear Nash. Why put my mind through the ringer?”, it’ll be an understandable frustration.

我们将以一种对您完全有意义的方式逐一介绍上述参数。 如果您在文章中的任何时候都发现自己“我只想在画布上绘制图像,亲爱的纳什。 为什么要让我的心惊动呢?”,这是可以理解的挫败感。

The way drawImage works does seem complex to some extent, but this complexity makes drawImage immensely powerful, and useful – as we’ll see through examples at the end. Moreover, the complexity is just on the surface: once you understand the whole picture it’s a downhill bicycle ride on a country road somewhere in Europe.

drawImage工作方式在某种程度上确实看起来很复杂,但是这种复杂性使drawImage极其强大和有用-正如我们将在最后的示例中看到的那样。 而且,复杂性只是表面上的:一旦您了解了整个情况,那就是在欧洲某处的乡间路上骑下坡自行车。

By the end of this article you’ll be able to visualise how drawImage will draw any given image on canvas just by looking at the values of the 9 parameters. Sounds like a superpower you might wanna have? Okay then, let’s dive right in!

到本文结尾,您只需看一下9个参数的值,就可以形象地看到drawImage如何在canvas上绘制任何给定的图像。 听起来像您可能想要的超级大国? 好吧,那就让我们潜水吧!

在画布中加载图像 (Loading an image in canvas)

Let’s start simple with an image and an HTML5 canvas.

让我们从图像和HTML5 canvas开始简单。

Here’s what our directory looks like

这是我们目录的样子

Inside of our index.html file we have created a new canvas element like so.

index.html文件中,我们像这样创建了一个新的canvas元素。

<canvas id="my-canvas" width="400px" height="200px"/>

Our goal is to take the cat.jpg image and put it on the canvas (#my-canvas). And like I already said, it ain’t that easy betty! Otherwise I wouldn’t be writing this article, you feel me? Good.

我们的目标是拍摄cat.jpg图像并将其放在画布上( #my-canvas )。 就像我已经说过的,贝蒂并不是那么容易! 否则我不会写这篇文章,你觉得我吗? 好。

To start with, let’s target the canvas element using JavaScript and get its context.

首先,让我们使用JavaScript定位canvas元素并获取其上下文。

const myCanvas = document.getElementById('my-canvas'); const myContext = myCanvas.getContext('2d');

We need myContext to interact with the canvas element. It’s like, if canvas is a blank sheet of paper, the canvas’s context is the pen. Intuitively, you’ll tell your pen to draw something on a blank sheet of paper, and not just yell at the paper to draw something on itself right?

我们需要myContextcanvas元素进行交互。 就像,如果canvas是一张空白纸,则画布的上下文就是笔。 直观地说,您会告诉您的笔在一张空白的纸上画一些东西,而不仅仅是喊着在纸上自己画些东西,对吗?

There are a number of things you can do with context. You can draw a rectangle, or an ellipse or a line, or an… image. Also, notice that the context myContext is implicitly linked to myCanvas. You can have multiple canvases and call getContext() on each of them to get a new context/pen for each. In our case we are dealing with just one canvas (myCanvas) and just one context (myContext).

您可以使用context执行许多操作。 您可以绘制矩形,椭圆形或直线或图像 。 另外,请注意,上下文myContext隐式链接到myCanvas 。 您可以具有多个canvas并在每个canvas调用getContext()以为每个canvas获取新的上下文/笔。 在我们的案例中,我们只处理一个画布( myCanvas )和一个上下文( myContext )。

Alright, with that out of the way, we can finally start getting our feet wet with drawImage.

好了,有了这种方式,我们终于可以开始使用drawImage弄湿了。

For a refresher, here are the 9 parameters that drawImage accepts.

drawImage一下,这是drawImage接受的9个参数。

(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

We’ll start with the first parameter, image. Let’s first write something that doesn’t work.

我们将从第一个参数image 。 首先让我们写一些行不通的东西。

context.drawImage('./cat.jpg', 0, 0);

See the two zeroes at the end? Good. This is not the part of the article where you’re supposed to understand what they’re there for. Ignore them for now, just keep in the back of your head that Nash wrote 2 zeroes and didn’t explain them. I won’t mind.

看到结尾处的两个零? 好。 这不是您应该了解它们的用途的文章的一部分。 现在忽略它们,只是让您记住,纳什写了2个零并且没有解释它们。 我不介意

Now notice ...('./cat.jpg',.. in the line of code above. Appears to be a perfectly correct URI doesn’t it? And it is…buuuut, if you fire up index.html in a browser you’ll see a long long error message identical to what’s shown below.

现在通知...('./cat.jpg',..在上面的代码行。看来是完全正确的URI不是吗?它是... buuuut,如果你火起来index.html的浏览器中,您会看到一条很长的错误消息,与以下内容相同。

ERROR: The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)

*gulp*

*大嘴*

The error is telling us that it needs an image element and not just a URI to the image. To get around that, this is what we can do.

错误告诉我们它需要一个图像元素 ,而不仅仅是图像的URI。 为了解决这个问题,这是我们可以做的。

const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const img = new Image();        img.src = './cat.jpg';        img.onload = () => {          context.drawImage(img, 0, 0);        };

That is something you didn’t expect did you? Canvas needs a preloaded image in order to draw/display it in itself. No need to show any contempt towards canvas, by the way. It has its reason, it’s just like the rest of us. We’ll eventually see what those reasons are and maybe then you’ll be able to sympathise.

那是您没想到的事吗? 画布需要预加载的图像才能在其自身上绘制/显示。 顺便说一句,无需对帆布表示蔑视。 这是有原因的,就像我们其他人一样。 我们最终将看到这些原因是什么,也许您将能够同情。

To recap:

回顾一下:

drawImage asks for 9 parameters, first of which is image. We looked and understood that canvas requires a preloaded image to draw and not just a URI to the image. Why does it need that? It will become clear as you read.

drawImage需要9个参数,其中第一个是image 。 我们了解到, canvas需要绘制一个预加载的图像,而不仅仅是图像的URI。 为什么需要它? 当您阅读时,它将变得清晰。

Now it’s time for the remaning 8 parameters. Pop your collars! I am gonna learn you some graphics editing first!

现在该剩下8个参数了。 甩开你的衣领! 我要先学习一些图形编辑!

如何裁剪图片 (How to crop a picture)

Every single graphics editing program, even the most basic, comes with the feature of cropping. It’s fairly simple: open an image > select the area you want visible > hit crop. And just like that, the naked beer belly of that obnoxious smelling old man is out. Poof!

每个图形编辑程序,即使是最基本的程序,都具有裁剪功能。 这非常简单:打开图像>选择要显示的区域>裁剪。 就这样,那个令人讨厌的嗅到的老人赤裸的啤酒肚出来了。 of!

Technology! Saving people’s Instagrams since Instagram existed.

技术! 自从Instagram存在以来,拯救人们的Instagram。

Let’s take a step back, and stop riiight, here.

让我们退后一步,在这里停下脚步。

Let’s mark some points on it.

让我们在上面标记一些要点。

“Wait a second! sx, sy, sWidth and sHeight? I have seen them before!”

“等一会儿! sxsysWidthsHeight ? 我以前见过他们!”

Yes, about a minute ago! Which leads us to the fleshiest part of the article.

是的,大约一分钟前! 这使我们进入了文章中最精彩的部分。

在画布上显示图像,步骤1:选择 (Displaying an image on canvas, Step 1: Selection)

The first task drawImage performs (behind the scenes) is it selects a portion of the image based on the four s parameters (sx, sy, sWidth, sHeight). You can say that s in all the s parameters stands for “select”.

drawImage执行的第一个任务(在幕后)是它基于四个s参数( sx, sy, sWidth, sHeight )选择图像的一部分。 您可以说所有s参数中的s代表“选择”。

Here’s how it goes. sx and sy mark the point on the image from where the selection is to begin, or in other words the coordinates of the top left corner of the selection rectangle. sWidth and sHeight then, are the width and height of the selection rectangle respectively. You can scroll right up to the last image to get a clearer picture of what I am trying to explain.

这是怎么回事。 sxsy标记图像上开始选择的点,或者换句话说,选择矩形左上角的坐标。 sWidthsHeight分别是选择矩形的宽度和高度。 您可以向右滚动到最后一张图像,以更清晰地了解我要解释的内容。

“But why the selection Nash? Can’t it just display the entire image?” We’re getting closer to all your answers, patience.

“但是为什么选择纳什呢? 它不能显示整个图像吗?” 我们越来越接近您的所有答案,耐心等待。

Just know that the first step drawImage performs after receiving a proper image is it selects a portion/area of the image based on the s parameters (sx, sy, sWidth, sHeight) you provide.

只要知道drawImage在接收到适当的图像后执行的第一步(sx, sy, sWidth, sHeight)您提供的s参数(sx, sy, sWidth, sHeight)选择图像的一部分/区域。

Remember that you don’t always have to select a small portion of the image, you can select the entire image if you want to. In that case sx and sy will have values 0 and 0 respectively and sWidth, sHeight will be the same as the image’s width and height.

请记住,您不必总是选择图像的一小部分,也可以选择整个图像。 在这种情况下, sxsy值分别为0和0,而sWidthsHeight与图像的宽度和高度相同。

Also, negative values are welcome for sx and sy. The values of sx and sy are relative to the origin of the image on the top left.

此外, sxsy负值也是受欢迎的。 sxsy的值相对于左上方图像的原点。

Once drawImage has selected the area of image you asked it to – and we’ll see soon why selecting an area of the image helps – the next step is to draw the selected portion of the image on the canvas.

一旦drawImage选择了您要求的图像区域–我们将很快看到为什么选择图像区域会有所帮助–下一步是在画布上绘制图像的所选部分。

“Originally” s and d in the official documentation stand for ‘source’ and ‘destination’. But, just between us, let’s call it ‘select’ and ‘draw’. It makes much more sense this way, doesn’t it?

“本来” sd官方文档立场“源”和“目的地”。 但是,就在我们之间,我们称其为“选择”和“绘制”。 这样更有意义,不是吗?

Again. selection is done, the next step is to draw.

再次。 s的选择完成后,下一步是d raw。

在画布上显示图像,步骤2:绘制 (Displaying an image on canvas, Step 2: Drawing)

To draw the selected portion of the image, we again need four parameters.

要绘制图像的选定部分,我们再次需要四个参数。

  1. x Coordinate of where to start drawing on the canvas. ( dx )

    x在画布上开始绘制的位置的坐标。 ( dx )

  2. y Coordinate of where to start drawing on the canvas. ( dy )

    y在画布上开始绘制的位置的坐标。 ( dy )

  3. How wide to draw the image. ( dWidth )

    绘制图像的宽度。 ( dWidth )

  4. How high/tall to draw the image. ( dHeight )

    绘制图像的高度/高度。 ( dHeight )

The values of dx and dy will be relative to the origin of the canvas.

dxdy的值将相对于画布的原点。

There’s a very important but subtle detail to notice here. dWidth and dHeight are in no way tied to sWidth and sHeight. They are independent values. Why do you need to know that? Well, because if you don’t choose values of the width and height of ‘draw’ carefully you will end up with a stretched or squashed image, like this.

这里有一个非常重要但细微的细节需要注意。 dWidthdHeight绝不与sWidthsHeight 。 它们是独立的价值观。 为什么需要知道这一点? 好吧,因为如果您不仔细选择“绘制”的宽度和高度的值,则最终将得到拉伸或挤压的图像,就像这样。

So if that’s something you’re not looking for (which I hope you’re not), make sure to maintain the aspect ratio. Or so to say sWidth divided by sHeight should be equal to dWidth divided by dHeight. That was a small little disclaimer, you’re the ruler of your own world and free to choose whatever values you like.

因此,如果这不是您想要的(我希望您没有),请确保保持宽高比。 或者说sWidth除以sHeight应该等于dWidth除以dHeight 。 那是一个小的免责声明,您是自己世界的统治者,可以自由选择自己喜欢的任何值。

The whole process of displaying/drawing an image on canvas can thus be summarised in just two steps: Selection and Drawing.

因此,在画布上显示/绘制图像的整个过程可以归纳为两个步骤:“选择”和“绘制”。

Awesome! Not so complicated after all is it?

太棒了! 毕竟不是那么复杂吗?

Now at this point, we’re done with all the theory. In rest of the article that follows we’ll bake the batter of knowledge spread around your head with a fun and practical example and you’ll be good to go. But, before we do that, let’s talk about one last important thing concerning drawImage.

现在,我们已经完成了所有理论。 在接下来的其余文章中,我们将通过一个有趣而实用的示例为您散布在您头上的知识提供帮助,您将一路顺风。 但是,在我们这样做之前,让我们先谈一谈关于drawImage最后一件重要事情。

默认值 (The default values)

Remember my lecture on “hey keep the aspect ratio and be careful don’t take chocolates from strangers…”? Well, as it turns out, you can omit certain values and not worry about the aspect ratio at all. As far as taking chocolates from strangers go, again — you’re the ruler of your own world.

还记得我关于“嘿,保持长宽比,注意不要从陌生人那里摘取巧克力……”的演讲吗? 好吧,事实证明,您可以省略某些值,而完全不必担心纵横比。 至于从陌生人那里拿走巧克力,再说一次-您是自己世界的统治者。

Here’s one way to use the method.

这是使用该方法的一种方法。

drawImage(image, dx, dy)

That is all! In this case, you’re telling drawImage only the location on canvas where to start the drawing. The rest, sx, sy, sWidth, sHeight, dWidth and dHeight are taken care of automagically. The method selects the entire image (sx = 0, sy = 0, sWidth = image's width, sHeight = images' height) and starts drawing on canvas at (dx, dy) with dWidth and dHeight same as sWidth(image’s width), sHeight(image’s height) .

就这些! 在这种情况下,您只告诉drawImage在画布上开始绘制的位置。 其余的sxsysWidthsHeightdWidthdHeight会自动处理。 该方法选择整个图像(sx = 0, sy = 0, sWidth = image's width, sHeight = images' height)并在dWidthdHeightsWidth (图像的宽度), sHeight相同的情况下在(dx, dy)画布上开始绘制。 (图像的高度)。

Remember the two zeroes that I didn’t explain? That is where the two zeroes came from.

还记得我没有解释的两个零吗? 那就是两个零的来源。

Yet another way to use the method is,

使用该方法的另一种方法是

drawImage(image, dx, dy, dWidth, dHeight)

In this form sx, sy, sWidth and sHeight are taken care of, and the method automatically selects the entire image and leaves it up to you to choose where and how large of an image to draw.

在这种形式下,将处理sx, sy, sWidth and sHeight ,该方法会自动选择整个图像,然后由您sx, sy, sWidth and sHeight选择要绘制图像的位置和大小。

Pretty cool! isn’t it?

太酷了! 是不是

If I can have your attention for another two minutes I’d like to tell you why selection and drawing are two separate operations. And how it is helpful.

如果我能有你的注意力另外两分钟,我想告诉你为什么s选举和d rawing是两个单独的操作。 以及它如何有所帮助。

Do I have your attention? Great!

请注意 大!

So here.

所以在这里。

Heard of sprites before? You see, sprites are a computer graphics concept where a graphic may be moved on-screen and otherwise manipulated as a single entity.

听说过精灵吗? 您会看到,子画面是计算机图形学的一个概念,其中图形可以在屏幕上移动,也可以作为一个单独的实体进行操作。

…?

……?

I copied this definition from Google to sound suave.

我从Google复制了这个定义,听起来很和ave。

Alright alright. Remember Mario?

好吧好吧。 还记得马里奥吗?

Good.

好。

Let’s do something fun.

让我们做些有趣的事。

用drawImage制作Mario动画 (Animating Mario with drawImage)

You see, when Mario moves forward/backward or in any other direction, it appears as if he is walking. His position changes but also there is an accompanying animation of his legs and hands moving.

您会看到,当Mario向前/向后或在任何其他方向上移动时,看起来好像他在走路。 他的位置发生了变化,但同时伴随着他的腿和手移动的动画。

How do they do that? Do they show different images of Mario in succession, like a flipbook and it appears as if he’s moving?

他们如何做到的? 它们是否连续显示了马里奥的不同图像,例如一本翻页书,看起来好像他在移动?

Well, 50% yes. Imagine how resource intensive storing and loading a huge set of images describing every frame of animation in our program (or game) would be. Instead, there’s a single image and all the positions are laid out in a grid. Like the one shown below.

好吧,百分之五十。 想象一下,资源密集型存储和加载大量图像的过程将如何描述我们程序(或游戏)中的每一帧动画。 取而代之的是,只有一张图像,并且所有位置都布置在一个网格中 。 如下图所示。

To execute an animation, instead of loading a new image every millisecond, a portion of the same image is shown through a viewport just at different positions. Clever isn’t it?

要执行动画,而不是每毫秒加载一次新图像,而是通过视口仅在不同位置显示同一图像的一部分。 是不是很聪明?

So yes, it’s sorta like a flipbook, a clever flipbook actually.

是的,这有点像一本活页簿,实际上是一本聪明的活页簿。

Now if you could just stretch a little and pop your knuckles I would like us to recreate Mario’s walking animation. We’ll use the sprite shown above and everything we have learnt about drawImage so far.

现在,如果您可以稍微伸展一下并弹出指关节,我希望我们重新制作Mario的行走动画。 我们将使用上面显示的sprite以及到目前为止我们对drawImage所学的所有知识。

Ready? Here we go!

准备? 开始了!

Let’s take another look at our sprite and try to figure the grid dimensions that it has been laid out on.

让我们再看一看我们的精灵,并尝试计算出它所放置的网格尺寸。

All that we have done here is imagined a grid over the sprite. Notice that the entire grid is made up of cells of equal dimensions (32 x 39). But it’s still just one image, remember that.

我们在这里所做的一切都只是想象一个精灵上的网格。 请注意,整个网格由相等尺寸(32 x 39) 。 但是它仍然只是一张图像,请记住这一点。

Great! Now let’s get to writing some code. We’ll start in the usual way by first creating a canvas element, grabbing it and its context in JavaScript, and then loading our Mario spritesheet.

大! 现在开始编写一些代码。 我们将以通常的方式开始,首先创建一个canvas元素,在JavaScript中获取它及其上下文,然后加载我们的Mario Spritesheet。

// index.js const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const img = new Image();       img.src = './mario.png';       img.onload = () => {          ctx.drawImage(img, 0, 0);       };
// style.css canvas {   /*Add a border around canvas for legibility*/   border: 1px solid grey; }

The above code will result in the following.

上面的代码将导致以下结果。

Woah-kay! We’ve got the image showing! What’s happening really?

哇! 我们有图像显示! 到底是怎么回事

Here, we’re using the form of drawImagedrawImage(image, sx, sy)–where the whole image is selected and drawn on the canvas as it is.

在这里,我们使用的形式drawImage - drawImage(image, sx, sy) -where整个图像s当选, d rawn在画布上,因为它是。

What we want to do, first of all, is select just one cell of the grid and draw just that single cell. Let’s start out by first making tweaks to our code that selects the first cell in the third row, the one in which Mario is standing facing east. We’ll figure how to animate once we have that done. Sounds good? Lovely!

首先,我们要选择的只是网格中的一个单元格,并仅绘制单个单元格。 首先,对代码进行调整,选择第三行中的第一个单元格,其中Mario朝东站立。 完成后,我们将弄清楚如何制作动画。 听起来不错? 可爱!

Let’s make the necessary changes to our code.

让我们对代码进行必要的更改。

const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d');
// Mario variables const MARIO_WIDTH = 32; const MARIO_HEIGHT = 39;
const mario = new Image(); mario.src = './mario.png'; mario.onload = () => {   ctx.drawImage(     // Image     mario,     // ---- Selection ----     0, // sx     MARIO_HEIGHT * 2, // sy     MARIO_WIDTH, // sWidth     MARIO_HEIGHT, // sHeight     // ---- Drawing ----     0, // dx     0, // dy    MARIO_WIDTH, // dWidth     MARIO_HEIGHT // dHeight   ); };

First off, notice the two variables MARIO_WIDTH and MARIO_HEIGHT. They are the dimensions of the grid cell, that’s all they are. We defined them to make it easier for us to traverse the grid using just multiples of each of those constants. Makes sense?

首先,请注意两个变量MARIO_WIDTHMARIO_HEIGHT 。 它们就是网格单元的尺寸,仅此而已。 我们定义它们是为了使我们可以更轻松地仅使用这些常数中的每个常数的倍数遍历网格。 说得通?

Good.

好。

Next, in the // Selection block we defined the area of the image we want to select, in the // Drawing section we defined the width and height and the position from where to start drawing on the canvas… aaand just like that we managed to draw just one cell of the entire imaginary grid.

接下来,在// Selection块中,我们定义了要选择的图像区域,在// Drawing部分中,定义了宽度和高度以及从哪里开始在画布上绘图的位置... aaand就像我们管理的一样仅绘制整个假想网格中的一个单元。

Pretty simple, just selection and drawing. Now at this point I’d like to digress into an older topic about aspect ratio. “Nash! again? ugghh” I know I know. But it’s cool! Look!

非常简单,只需选择和绘制即可。 现在,我想谈谈一个关于长宽比的老话题。 “纳什! 再次? ”我知道我知道。 但这很酷! 看!

If I change the values of dWidth or dHeight or both of them, look at how the image stretches and squashes.

如果更改dWidthdHeight或两者的值,请查看图像如何拉伸和压缩。

... ctx.drawImage(   // Image    mario,   // ---- Selection ----    0, // sx    MARIO_HEIGHT * 2, // sy    MARIO_WIDTH, // sWidth    MARIO_HEIGHT, // sHeight    // ---- Drawing ----    0, // dx    0, // dy    MARIO_WIDTH * 2, // dWidth    MARIO_HEIGHT * 1.5 // dHeight  ); ...

Hah! See! That’s why I was advising you to maintain the aspect ratio and that the values of selection and drawing have no real interconnection.

哈哈! 看到! 这就是为什么我建议您保持长宽比,并且选择和绘图的值之间没有真正的相互联系的原因。

Okay, back to what we were doing.

好的,回到我们正在做的事情。

So now we have Mario in the canvas, small and little. We need to animate it, or in other words show different frames at the same location in succession and make the illusion of movement happen. Was I too specific? Heck yeah!

所以现在我们在画布上放了Mario,大小不一。 我们需要对其进行动画处理,换句话说就是要在同一位置连续显示不同的帧,并使运动的幻象发生。 我太具体了吗? 哎呀!

We can do that by selecting the grid cells we want to draw in succession. We just need to change the value of sx by the multiples of MARIO_WIDTH.

我们可以通过选择要连续绘制的网格单元来实现。 我们只需要将sx的值更改为MARIO_WIDTH的倍数MARIO_WIDTH

Now doing this will require the use of requestAnimationFrame and I have been explaining that in a streak in this article and this article.

现在,这样做将需要使用的requestAnimationFrame和我一直在解释,在条纹在这个文章, 这个文章。

As a small challenge why don’t you go ahead and try accomplishing this on your own? In any case, you can check out this Codepen where I have Mario running like this. The pen has enough comments to help you understand the tiny bit of high school math that’s being used to make the animation happen.

作为一个小挑战,您为什么不继续尝试自己完成此任务? 无论如何,您都可以在此Codepen中查看我让Mario运行的位置。 笔上有足够的注释,可以帮助您了解用于制作动画的一小部分高中数学。

Cute little thing!

可爱的小东西!

And with that, we’re done with a very comprehensive explanation of drawImage. Hope you enjoyed.

drawImage ,我们对drawImage进行了非常全面的解释。 希望你喜欢。

If you have made it this far, how about you shoot me some feedback or #goodvibes on Twitter?

如果到目前为止,您如何在Twitter上给我一些反馈或#goodvibes?

This article was originally published on www.nashvail.me.

本文最初发布在www.nashvail.me上

Did I tell you about my new website? And did I tell you it has a Newsletter too? I’d love if you subscribed so I can notify you each time I publish something new or put something new for sale in my shop. I’ll continue publishing articles on Medium but there’ll be a two-week gap between when it first goes up on my site and when it shows up here.

我有没有告诉你我的新网站 ? 我也告诉过你它也有新闻通讯吗? 如果您订阅了我会很高兴的,这样每当我出版新东西或在商店出售新东西时我都可以通知你。 我将继续在Medium上发布文章,但是从它第一次出现在我的网站到它出现在这里之间,将有两个星期的间隔。

Thank you so much for reading and thank you so much for your support. Have a good one! :)

非常感谢您的阅读,也非常感谢您的支持。 祝你有个好的一天! :)

翻译自: https://www.freecodecamp.org/news/how-displaying-an-image-on-html5-canvas-works-13e3f6a6c4bd/

html画布图片不显示

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值