canvas api_HTML Canvas API教程

canvas api

Tip: also check my tutorials how to print a canvas to a data URL, how to write text into to an HTML canvas, how to load an image in an HTML canvas and how to create and save an image with Node.js and Canvas

提示:还请查看我的教程, 如何将画布打印到数据URL如何将文本写入HTML画布如何在HTML画布中加载图像以及如何使用Node.js和Canvas创建和保存图像

The HTML canvas is an HTML tag, <canvas>, which is an element where we can draw to using the Canvas API.

HTML canvas是HTML标记<canvas> ,这是我们可以使用Canvas API绘制的元素。

创建一个画布 (Create a canvas)

Creating a canvas is as simple as dropping a <canvas></canvas> in a blank HTML file:

创建画布就像将<canvas></canvas>放到空白HTML文件中一样简单:

You don’t see anything in the page because the canvas is an invisible element. Let’s add some border:

您不会在页面中看到任何内容,因为画布是不可见的元素。 让我们添加一些边框:

Chrome automatically adds an 8px margin to the body element. This is why our border looks like a frame, and you can remove that margin by setting

Chrome会自动向body元素添加8px的边距。 这就是为什么我们的边框看起来像框架,而您可以通过设置

body {
  margin: 0;
}

We’ll leave the default for now.

我们暂时保留默认设置。

Our canvas is now reachable from JavaScript using the DOM Selectors API, so we can use document.querySelector():

现在,可以使用DOM Selectors API通过JavaScript来访问我们的画布,因此我们可以使用document.querySelector()

const canvas = document.querySelector('canvas')

更改画布的背景颜色 (Change the background color of a canvas)

You do that in CSS:

您可以在CSS中执行此操作:

canvas {
  background-color: lightblue;
}

调整画布大小 (Resize a canvas)

You can set the width and height in CSS:

您可以在CSS中设置宽度和高度:

canvas {
  border: 1px solid black;
  width: 100%;
  height: 100%;
}

and in this way the canvas will expand to fill all the outer element size.

这样,画布将扩展为填充所有外部元素的大小。

If you put the canvas as a first level element in the HTML, the above code will expand the canvas to fit the entire body.

如果将画布作为HTML中的第一级元素放置,则上面的代码将扩展画布以适合整个身体。

The body is not filling the entire window size. To fill the entire page instead we need to use JavaScript:

主体未填充整个窗口大小。 要填充整个页面,我们需要使用JavaScript:

canvas.width = window.innerWidth
canvas.height = window.innerHeight

If you now remove the body margin and set the background of the canvas using CSS, we can fill our entire page with the canvas and we can start drawing on it:

如果现在删除主体边距并使用CSS设置画布的背景,我们可以用画布填充整个页面,然后开始在其上绘制:

If the window resizes we need to recalculate the canvas width as well, using a debounce to avoid calling too many times our canvas resizing (the resize event can be called hundreds of times as you move the window with the mouse, for example):

如果窗口调整大小,我们还需要重新计算画布的宽度,请使用反跳来避免调用过多的画布调整大小(例如,当您用鼠标移动窗口时, resize事件可以被调用数百次):

const debounce = (func) => {
  let timer
  return (event) => {
    if (timer) { clearTimeout(timer) }
    timer = setTimeout(func, 100, event)
  }
}

window.addEventListener('resize', debounce(() => {
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
}))

从画布获取上下文 (Get a context from the canvas)

We want to draw to the canvas.

我们想画在画布上。

To do this, we need to get a context:

为此,我们需要获取上下文:

const c = canvas.getContext('2d')

Some assign the context to a variable named c, some ctx - it’s a common way to shortcut “context”

一些将上下文分配给名为c的变量,一些ctx这是快捷方式“ context”的常用方法

The getContext() method returns a drawing context on the canvas, according to the type that you pass as parameter.

根据您作为参数传递的类型, getContext()方法返回画布上的绘图上下文。

Valid values are

有效值为

  • 2d, the one we’ll use

    2d ,我们将使用的那个

  • webgl to use WebGL version 1

    webgl使用WebGL版本1

  • webgl2 to use WebGL version 2

    webgl2使用WebGL版本2

  • bitmaprenderer to use with ImageBitmap

    bitmaprenderer与使用ImageBitmap

Based on the context type, you can pass a second parameter to getContext() to specify additional options.

根据上下文类型,可以将第二个参数传递给getContext()以指定其他选项。

In the case of the 2d context, we basically have one parameter we can use in all browsers, and it’s alpha, a boolean that defaults to true. If set to false, the browser knows the canvas does not have a transparent background and can speed up rendering.

2d上下文的情况下,我们基本上有一个可以在所有浏览器中使用的参数,它是alpha ,默认为true的布尔值。 如果设置为false,则浏览器知道画布没有透明背景,可以加快渲染速度。

在画布上绘制元素 (Draw elements to a canvas)

With the context we can now draw elements.

有了上下文,我们现在可以绘制元素。

We have several methods to do so. We can draw:

我们有几种方法可以做到这一点。 我们可以得出:

  • text

    文本
  • lines

    线
  • rectangles

    矩形
  • paths

    路径
  • images

    图片

and for each of those elements we can alter the fill, the stroke, the gradient, the pattern, the shadow, rotate them, scale and perform a lot of operations.

对于这些元素,我们可以更改填充,笔触,渐变,图案,阴影,旋转它们,缩放并执行很多操作。

Let’s start with the simplest thing: a rectangle.

让我们从最简单的事情开始:一个矩形。

The fillRect(x, y, width, height) method serves this purpose:

fillRect(x, y, width, height)方法用于此目的:

c.fillRect(100, 100, 100, 100)

This is going to draw a black rectangle of 100 x 100 pixels, starting from position x 100 and y 100:

这将从位置x 100和y 100开始绘制一个100 x 100像素的黑色矩形:

You can color the rectangle by using the fillStyle() method, passing any valid CSS color string:

您可以使用fillStyle()方法为矩形着色,并传递任何有效CSS颜色字符串:

c.fillStyle = 'white'
c.fillRect(100, 100, 100, 100)

You can get creative now and draw many things in this way:

您现在可以发挥创意,并以这种方式绘制许多东西:

for (let i = 0; i < 60; i++) {
  for (let j = 0; j < 60; j++) {
    c.fillStyle = `rgb(${i * 5}, ${j * 5}, ${(i+j) * 50})`
    c.fillRect(j * 20, i * 20, 10, 10)
  }
}

or

要么

for (let i = 0; i < 60; i++) {
  for (let j = 0; j < 60; j++) {
    c.fillStyle = `rgb(${i * 5}, ${j * 5}, ${(i+j) * 50})`
    c.fillRect(j * 20, i * 20, 20, 20)
  }
}

绘图元素 (Drawing elements)

As mentioned you can draw many things:

如前所述,您可以画出很多东西:

  • text

    文本
  • lines

    线
  • rectangles

    矩形
  • paths

    路径
  • images

    图片

Let’s just see a few of them, rectangles and text, to get the gist of how things work. You can find the API for all the rest that you need here.

让我们看看其中的一些矩形和文本,以了解事物的工作原理。 您可以在此处找到所有所需的API。

改变颜色 (Changing the colors)

Use the fillStyle and strokeStyle properties to change the fill and stroke colors of any figure. They accept any valid CSS color, including strings and RGB calculations:

使用fillStylestrokeStyle属性可以更改任何图形的填充和描边颜色。 它们接受任何有效CSS颜色,包括字符串和RGB计算:

c.strokeStyle = `rgb(255, 255, 255)`
c.fillStyle = `white`

长方形 (Rectangles)

You have 3 methods:

您有3种方法:

  • clearRect(x, y, width, height)

    clearRect(x,y,宽度,高度)
  • fillRect(x, y, width, height)

    fillRect(x,y,width,height)
  • strokeRect(x, y, width, height)

    strokeRect(x,y,宽度,高度)

We saw fillRect() in the previous section. strokeRect() is similar in how it’s called, but instead of filling a rect, it just draws the stroke using the current stroke style (which can be changed using the strokeStyle context property):

我们在上一节中看到了fillRect()strokeRect()的调用方式类似,但是它不是填充矩形,而是使用当前的笔触样式(可以使用strokeStyle上下文属性更改)来绘制笔划:

const c = canvas.getContext('2d')
for (let i = 0; i < 61; i++) {
  for (let j = 0; j < 61; j++) {
    c.strokeStyle = `rgb(${i * 5}, ${j * 5}, ${(i+j) * 50})`
    c.strokeRect(j * 20, i * 20, 20, 20)
  }
}

clearRect() sets an area as transparent:

clearRect()将区域设置为透明:

文本 (Text)

Drawing text is similar to rectangles. You have 2 methods

绘图文本类似于矩形。 你有两种方法

  • fillText(text, x, y)

    fillText(text,x,y)
  • strokeText(text, x, y)

    strokeText(text,x,y)

which let you write text on the canvas.

让您在画布上写文字。

x and y refer to the bottom-left corner.

xy指的是左下角。

You change the font family and size using the font property of the canvas:

您可以使用画布的font属性更改字体系列和大小:

c.font = '148px Courier New'

There are other properties you can change, related to text (* = default):

您还可以更改与文本相关的其他属性(* =默认值):

  • textAlign (start*, end, left, right, center)

    textAlign (开始*,结束,左,右,中心)

  • textBaseline (top, hanging, middle, alphabetic*, ideographic, bottom)

    textBaseline (顶部,顶部,中间,字母*,表意,底部)

  • direction (ltr, rtl, inherit*)

    direction (ltr,rtl,继承*)

线数 (Lines)

To draw a line you first call the beginPath() method, then you provide a starting point with moveTo(x, y), and then you call lineTo(x, y) to make the line to that new coordinates set. You finally call stroke():

要绘制一条线,您首先调用beginPath()方法,然后提供一个带有moveTo(x, y)的起点,然后调用lineTo(x, y)以使该线成为该新坐标集。 您最终调用了stroke()

c.beginPath()
c.moveTo(10, 10)
c.lineTo(300, 300)
c.stroke()

The line is going to be colored according to the c.strokeStyle property value.

该行将根据c.strokeStyle属性值进行着色。

一个更复杂的例子 (A more complex example)

This code creates a canvas that generates 800 circles:

此代码创建一个画布,该画布生成800个圆圈:

Every circle is perfectly contained in the canvas, and its radius is randomized.

每个圆都完美地包含在画布中,并且其半径是随机的。

Any time you resize the window, the elements are regenerated.

每次调整窗口大小时,都会重新生成元素。

You can play around with on Codepen.

您可以在Codepen

const canvas = document.querySelector('canvas')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
const c = canvas.getContext('2d')

const circlesCount = 800

const colorArray = [
  '#046975',
  '#2EA1D4',
  '#3BCC2A',
  '#FFDF59',
  '#FF1D47'
]

const debounce = (func) => {
  let timer
  return (event) => {
    if (timer) { clearTimeout(timer) }
    timer = setTimeout(func, 100, event)
  }
}

window.addEventListener('resize', debounce(() => {
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight

  init()
}))

const init = () => {
  for (let i = 0; i < circlesCount; i++) {
    const radius = Math.random() * 20 + 1
    const x = Math.random() * (innerWidth - radius  * 2) + radius
    const y = Math.random() * (innerHeight - radius  * 2) + radius
    const dx = (Math.random() - 0.5) * 2
    const dy = (Math.random() - 0.5) * 2

    const circle = new Circle(x, y, dx, dy, radius)
    circle.draw()
  }
}

const Circle = function(x, y, dx, dy, radius) {
  this.x = x
  this.y = y
  this.dx = dx
  this.dy = dy
  this.radius = radius
  this.minRadius = radius
  this.color = colorArray[Math.floor(Math.random() * colorArray.length)]

  this.draw = function() {
    c.beginPath()
    c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false)
    c.strokeStyle = 'black'
    c.stroke()
    c.fillStyle = this.color
    c.fill()
  }
}

init()

另一个示例:在画布上设置元素动画 (Another example: animating elements on the canvas)

Based on the example above, we animate the elements using a loop. Every circle has its own “life” and moves within the borders of the canvas. When the border is reached it bounces back:

根据上面的示例,我们使用循环为元素设置动画。 每个圆圈都有自己的“生命”,并在画布的边界内移动。 到达边界后会反弹:

See the Pen HTML Canvas fun with circles, not interactive by Flavio Copes (@flaviocopes) on CodePen.

请参见Pen HTML Canvas带圆圈的乐趣,而不是由Flavio Copes( @flaviocopes )在CodePen上进行交互

We achieve this by using requestAnimationFrame() and slightly moving the image at every frame rendering iteration.

我们通过使用requestAnimationFrame()并在每次帧渲染迭代中略微移动图像来实现此目的。

与画布上的元素进行交互 (Interact with the elements on the canvas)

Here is the above example expanded to let you interact with the circles using the mouse.

这是上面的示例,已扩展为可让您使用鼠标与圈子互动。

When you hover the canvas, the items near your mouse will increase in size, and they will return back to normal when you move somewhere else:

当您将鼠标悬停在画布上时,鼠标附近的项目会变大,并且当您移动到其他地方时它们会恢复正常:

See the Pen HTML Canvas fun with circles by Flavio Copes (@flaviocopes) on CodePen.

CodePen查看 Flavio Copes( @flaviocopes )的带圆圈的Pen HTML Canvas乐趣

How does it work? Well, first I track the mouse position using 2 variables:

它是如何工作的? 好吧,首先我使用2个变量跟踪鼠标的位置:

let mousex = undefined
let mousey = undefined

window.addEventListener('mousemove', (e) => {
  mousex = e.x
  mousey = e.y
})

Then we use those variables inside the update() method of Circle, to determine if the radius should increase (or decrease):

然后,我们在Circle的update()方法中使用这些变量,以确定半径是否应增大(或减小):

if (mousex - this.x < distanceFromMouse && mousex - this.x > -distanceFromMouse && mousey - this.y < distanceFromMouse && mousey - this.y > -distanceFromMouse) {
  if (this.radius < maxRadius) this.radius += 1
} else {
  if (this.radius > this.minRadius) this.radius -= 1
}

distanceFromMouse is a value expressed in pixels (set to 200) that defines how far we want the circles to react to the mouse.

distanceFromMouse是一个以像素表示的值(设置为200),它定义了我们希望圆对鼠标做出React的距离。

性能 (Performance)

If you try to edit those projects above and add a bunch more circles and moving parts, you’ll probably notice performance issues. Browsers consume a lot of energy to render the canvas with animations and interactions, so pay attention so that the experience is not ruined on less performant machines than yours.

如果尝试在上方编辑这些项目并添加更多的圆和运动零件,则可能会注意到性能问题。 浏览器要花费大量精力来通过动画和交互来渲染画布,因此请注意,以免在性能比您低的机器上破坏体验。

In particular I had issues when trying to create a similar experience with emojis rather than circles, and I found that text takes a lot more power to render, and so it was sluggish pretty quickly.

尤其是在尝试使用表情符号而不是圆形创建类似体验时,我遇到了问题,并且我发现文本需要更多的渲染能力,因此很快就变慢了。

See the Pen HTML Canvas fun with Emojis by Flavio Copes (@flaviocopes) on CodePen.

CodePen查看 Flavio Copes( @flaviocopes )的Emojis Pen HTML Canvas的乐趣

This page on MDN lists many performance tips.

MDN上的此页面列出了许多性能提示。

结束语 (Closing words)

This was just an introduction to the possibilities of Canvas, an amazing tool that you can use to create incredible experiences on your web pages.

这只是对Canvas可能性的介绍,Canvas是一个了不起的工具,可用于在网页上创建令人难以置信的体验。

翻译自: https://flaviocopes.com/canvas/

canvas api

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值