本文共 12119 字,大约阅读时间需要 40 分钟。
canvas api
Tip: also check my tutorials , , and
提示:还请查看我的教程, , , 以及
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绘制的元素。
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 , so we can use document.querySelector()
:
现在,可以使用通过JavaScript来访问我们的画布,因此我们可以使用document.querySelector()
:
const canvas = document.querySelector('canvas')
You do that in CSS:
您可以在CSS中执行此操作:
canvas { background-color: lightblue;}
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.innerWidthcanvas.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}))
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
, somectx
- it’s a common way to shortcut “context”一些将上下文分配给名为
c
的变量,一些ctx
这是快捷方式“ context”的常用方法
The method returns a drawing context on the canvas, according to the type that you pass as parameter.
根据您作为参数传递的类型, 方法返回画布上的绘图上下文。
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
bitmaprenderer
与使用
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,则浏览器知道画布没有透明背景,可以加快渲染速度。
With the context we can now draw elements.
有了上下文,我们现在可以绘制元素。
We have several methods to do so. We can draw:
我们有几种方法可以做到这一点。 我们可以得出:
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) }}
As mentioned you can draw many things:
如前所述,您可以画出很多东西:
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 .
让我们看看其中的一些矩形和文本,以了解事物的工作原理。 您可以在找到所有所需的API。
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:
使用fillStyle
和strokeStyle
属性可以更改任何图形的填充和描边颜色。 它们接受任何有效CSS颜色,包括字符串和RGB计算:
c.strokeStyle = `rgb(255, 255, 255)`c.fillStyle = `white`
You have 3 methods:
您有3种方法:
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()
将区域设置为透明:
Drawing text is similar to rectangles. You have 2 methods
绘图文本类似于矩形。 你有两种方法
which let you write text on the canvas.
让您在画布上写文字。
x
and y
refer to the bottom-left corner.
x
和y
指的是左下角。
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,继承*)
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
属性值进行着色。
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 .
您可以在上 。
const canvas = document.querySelector('canvas')canvas.width = window.innerWidthcanvas.height = window.innerHeightconst c = canvas.getContext('2d')const circlesCount = 800const 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()
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 by Flavio Copes () on .
请参见Pen 由Flavio Copes( )在上进行 。
We achieve this by using and slightly moving the image at every frame rendering iteration.
我们通过使用并在每次帧渲染迭代中略微移动图像来实现此目的。
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 by Flavio Copes () on .
在上 Flavio Copes( )的的Pen 。
How does it work? Well, first I track the mouse position using 2 variables:
它是如何工作的? 好吧,首先我使用2个变量跟踪鼠标的位置:
let mousex = undefinedlet mousey = undefinedwindow.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的距离。
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 by Flavio Copes () on .
在上 Flavio Copes( )的 Pen 。
lists many performance tips.
列出了许多性能提示。
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是一个了不起的工具,可用于在网页上创建令人难以置信的体验。
翻译自:
canvas api
转载地址:http://ztqgb.baihongyu.com/