likes
comments
collection
share

canvas 入门

作者站长头像
站长
· 阅读数 35

canvas 是 HTML5 新增的一个标签, 表示画布,canvas 也是 h5 的画布技术, 我们通过代码的方式在画布上描绘一个图像

canvas标签

要进行 canvas 绘图, 首先我们先要了解到 canvas 标签,是 html5 推出的一个标签 。

<html>
<head>
    ...
</head>
<body>
    <canvas></canvas>
</body>
</html>
  • canvas 默认是一个行内块元素
  • canvas 默认画布大小是 300 * 150
  • canvas 默认没有边框, 背景默认为无色透明

canvas画布大小

我们在绘图之前, 先要确定一个画布的大小,因为画布默认是按照比例调整,所以我们调整宽度或者高度的时候, 调整一个, 另一个自然会按照比例自己调整,我们也可以宽高一起调整

调整画布大小有两种方案

  • 第一种 : 通过 css 样式 ( 不推荐 )
<html>
<head>
    <style>
        canvas {
            width1000px;
            height500px;
        }
    </style>
</head>
<body>
    <canvas></canvas>
</body>
</html>
  • 第二种 : 通过标签属性 ( 推荐 )
<html>
<head>
    ...
</head>
<body>
    <canvas width="1000" height="500"></canvas>
</body>
</html>

** **

两种方案的区别 通过 css 样式的调整方案, 不推荐,是因为这个方案其实并没有设置了画布的大小,而是把原先 300 * 150 的画布, 将它的可视窗口变成了 1000 * 500 所以真实画布并没有放大, 只是可视程度变大了

举个例子 : 就是你把一个 300 * 150 的图片, 放大到 1000 * 500 的大小来看,所以这个方式我们极其不推荐。

canvas 入门

通过属性的调整方案, 推荐,这个才是真正的调整画布的的大小,也就是我们会在一个 1000 * 500 的画布上进行绘制

canvas 入门

画布的坐标 canvas 画布是和我们 css 的坐标系一样的,从 canvas 的左上角为 0 0 左边, 分别向右向下延伸为正方向

canvas 入门

canvas初体验

准备工作已经完成了, 我们可以开始体验一下绘制了,其实 canvas 画布很简单, 就和我们 windows 电脑的画板工具是一样的道理。

canvas 入门

思考 : 我们在 windows 这个画板上绘制内容的时候,我们一定是先选定一个工具 ( 画笔, 矩形, 圆形, ... ),设定好样式 ( 粗细, 颜色 ),然后开始绘制。

其实在 canvas 绘制也是一个道理,拿到一个画布工具箱,从工具箱中选定工具,设定样式,开始绘制,初体验步骤。

index.html

<html>
<head>
    ...
</head>
<body>
    <canvas id="canvas" width="600" height="300"></canvas>
    
    <script src="./index.js"></script>
</body>
</html>

** **

index.js

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
// 语法: canvas 元素.getContext('2d')
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制
// 2-1. 讲画笔移动到一个指定位置开始下笔
// 语法: 工具箱.moveTo(x轴坐标, y轴坐标)
ctx.moveTo(100100)

// 2-2. 将笔移动到一个指定位置, 画下一条轨迹
// 注意: 这里是没有显示的, 因为只是画了一个轨迹
// 语法: 工具箱.lineTo(x轴坐标, y轴坐标)
ctx.lineTo(300100)

// 2-3. 设定本条线的样式
// 设定线的宽度
// 语法: 工具箱.lineWidth = 数字
ctx.lineWidth = 10
// 设定线的颜色
// 语法: 工具箱.strokeStyle = '颜色'
ctx.strokeStyle = '#000'

// 2-4. 描边
// 把上边画下的痕迹按照设定好的样式描绘下来
// 语法: 工具箱.stroke()
ctx.stroke()

至此我们的第一个线段就绘制完毕, 画布上就会出现一条线段

  • 从坐标 ( 100, 100 ) 绘制到坐标 ( 300, 100 )

  • 线段长度为 200px

  • 线段宽度为 10px

  • 线段颜色为 '#000' ( 黑色 )

canvas 入门

canvas线宽颜色问题

刚才我们经过了初体验, 画了一个线段,看似没有问题, 也出现了线段, 但是其实内在是有一些问题的,我们先来观察,这次我们再来画一个线段

  • 从坐标 ( 100, 100 ) 绘制到坐标 ( 300, 100 )
  • 线段长度为 200px
  • 线段宽度为 1px
  • 线段颜色为 '#000' ( 黑色 )
// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制
ctx.moveTo(100100)

// 2-2. 将笔移动到一个指定位置, 画下一条轨迹
ctx.lineTo(300100)

// 2-3. 设定本条线的样式
// 设定线的宽度
ctx.lineWidth = 10
// 设定线的颜色
ctx.strokeStyle = '#000'

// 2-4. 描边
ctx.stroke()

canvas 入门

效果出现了, 没有什么问题,只是看上去不太像 1px, 而且颜色有些浅,不着急, 我们再来画一个线段。

  • 从坐标 ( 100, 100 ) 绘制到坐标 ( 300, 100 )

  • 线段长度为 200px

  • 线段宽度为 2px

  • 线段颜色为 '#000' ( 黑色 )

canvas 入门

这个时候问题就出现了,两次画出来的线段, 一次设置 1px 一次设置 2px,感觉上 线宽度 一样,两次画出来的线段, 两次都是设置为 '#000' 的颜色,但是感觉上颜色不太一样。

canvas 入门

这是因为浏览器在描述内容的时候, 最小的描述单位是 1px,我们来模拟一下浏览器绘制的内容,假设这是我们浏览器描述的画布中的像素点。

canvas 入门

我们来做一个坐标的标记

canvas 入门

现在呢不关注线的长度和坐标, 我们就画一个宽度为 1px 的线段

canvas 入门

我们来剖析一下问题,因为在描绘这个线段的时候, 会把线段的最中心点放在这个像素点位上,也就是说, 在描述线宽的时候, 实际上会从 0.5px 的位置绘制到 1.5px 的位置,合计描述宽度为 1px,但是浏览器的最小描述为 1px,这里说的不是最小宽度为 1px, 是浏览器不能在非整数像素开始描述,也就是说浏览器没办法从 0.5 开始绘制, 也没有办法绘制到 1.5 停止,那么就只能是从 0 开始绘制到 2,所以线宽就会变成 2px 了。

因为本身一个像素的黑色被强制拉伸到两个像素宽度, 所以颜色就会变浅,就像我们一杯墨水, 倒在一个杯子里面就是黑色,但是到在一个杯子里面的时候, 又倒进去一杯水, 颜色就会变浅,实际描绘出来的样子。

canvas 入门

这就变成了我们刚才看到的样子,所以, 我们在进行 canvas 绘制内容的时候, 涉及到线段的时候,我们一般不会把线段宽度设置成奇数, 一般都是偶数的。

canvas绘制平行线

刚才我们绘制了线段, 接下来我们来绘制一个平行线, 也就是两个线段,小伙伴: " 一个简单的效果, 想到就搞 "

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制第二个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

没有问题, 效果实现了。

canvas 入门

接下来, 咱们稍微增加一下需求,第一个线段线宽 2px, 黑色,第二个线段线宽 10px, 红色。这也简单啊, 稍微修改一下

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制第二个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 10
ctx.strokeStyle = 'red'
ctx.stroke()

canvas 入门

这是什么鬼, 为什么两个线段都变了, 不是应该只改变一个吗 ?

这是因为我们并没有告诉他这是两个不一样的线段,所以在设置线段样式的时候, 会默认按照最后一次设置的样式来绘制所有的线段,我们要想让第一个线段绘制完毕以后, 和第二个没有关系,我们需要告诉画布, 我的这个线段结束了, 后面的不要和我扯上关系.

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 结束之前的绘制内容
// 语法: 工具箱.beginPath()
ctx.beginPath()

// 4.. 开始绘制第二个线段
ctx.moveTo(100, 100)
ctx.lineTo(300, 100)
ctx.lineWidth = 10
ctx.strokeStyle = 'red'
ctx.stroke()

canvas 入门

这样才是我们的需求

canvas绘制三角形

画完了线段, 咱们就来画一个简单的图形, 画一个三角形,其实就是由三个线段组成, 用三个线段围成一个封闭图形即可

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 三角形第一个点
ctx.moveTo(100100)
// 三角形第二个点
ctx.lineTo(200100)
// 三角形第三个点
ctx.lineTo(200200)
// 回到第一个点
ctx.lineTo(100100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
// 描边
ctx.stroke()

canvas 入门

看似没啥问题, 一个三角形就出来了,但是我们仔细观察一下三角形的第一个角。

canvas 入门

因为这是两个线段, 只是画到了一个点, 不可能重叠出一个 尖儿~~,这个时候, 我们就不能这样绘制三角形了,当我们要绘制闭合图形的时候,我们不要手动绘制最后一个路径, 而是描述出形状,通过 canvas 让它自动闭合。

首先, 我们绘制出形状, 不要闭合最终路径

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 三角形第一个点
ctx.moveTo(100100)
// 三角形第二个点
ctx.lineTo(200100)
// 三角形第三个点
ctx.lineTo(200200)

ctx.lineWidth = 2
ctx.strokeStyle = '#000'
// 描边
ctx.stroke()

canvas 入门

接下来, 让 canvas 来帮我们闭合这个封闭图形

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
ctx.moveTo(100100)
ctx.lineTo(200100)
ctx.lineTo(200200)

// 自动闭合图形
// 语法: 工具箱.closePath()
ctx.closePath()

ctx.lineWidth = 2
ctx.strokeStyle = '#000'
// 描边
ctx.stroke()

canvas 入门

这个时候, 我们发现一个正常的三角形就出现了 注意 : 闭合路径,closePath() 这个方法,是从当前坐标点, 直接用线段的方式连接到 modeTo() 的位置,也就是从当前坐标点直接连接到开始坐标点。


canvas线段两端的样式

canvas 中, 是可以设置线段两端的样子的,我们先来画三个平行线

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(100, 150)
ctx.lineTo(200, 150)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(100, 200)
ctx.lineTo(200, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

canvas 入门

接下来, 我们开始设置两端样式

  • 语法: 工具箱.lineCap = '值'
  • 值 : => butt 无 => round 圆 => square 方
// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 两端样式设置为 butt
ctx.lineCap = 'butt'

ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(100, 150)
ctx.lineTo(200, 150)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 两端样式设置为 round
ctx.lineCap = 'round'

ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(100, 200)
ctx.lineTo(200, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 两端样式设置为 'square'
ctx.lineCap = 'square'

ctx.stroke()
ctx.beginPath()

canvas 入门

square 和 round 会让线段稍稍变长,线段端点样式的颜色会和线段颜色保持一致

canvas线段拐点的样式

canvas 在绘制线段拐角的时候, 会自动进行闭合拐角,我们也可以通过设置, 来设置一下拐角的样子,先来绘制三个带有拐角的线段。

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100100)
ctx.lineTo(200150)
ctx.lineTo(100200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(200100)
ctx.lineTo(300150)
ctx.lineTo(200200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(300100)
ctx.lineTo(400150)
ctx.lineTo(300200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'
ctx.stroke()
ctx.beginPath()

canvas 入门

canvas 对于线段拐点默认的样式就是尖角拐点,我们可以进行一些设置来改变

  • 语法: 工具箱.lineJoin = '值'

  • 值:

    => miter 默认尖角拐点

    => round 创建圆角拐点

    => bevel 创建斜角拐点

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 150)
ctx.lineTo(100, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 默认拐点
ctx.lineJoin = 'miter'

ctx.stroke()
ctx.beginPath()

// 第二个线段
ctx.moveTo(200, 100)
ctx.lineTo(300, 150)
ctx.lineTo(200, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 圆角拐点
ctx.lineJoin = 'round'

ctx.stroke()
ctx.beginPath()

// 第三个线段
ctx.moveTo(300, 100)
ctx.lineTo(400, 150)
ctx.lineTo(300, 200)
ctx.lineWidth = 10
ctx.strokeStyle = '#000'

// 斜角拐点
ctx.lineJoin = 'bevel'

ctx.stroke()
ctx.beginPath()

canvas 入门

canvas填充

在 canvas 中, 一旦你画出封闭图形以后,我们不光可以描边, 也可以进行填充, 也就是填满颜色,先来画一个矩形吧。

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100100)
ctx.lineTo(200100)
ctx.lineTo(200200)
ctx.lineTo(100200)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.closePath()
ctx.stroke()

canvas 入门

我们这里用的是描边( 工具箱.stroke() ),是按照痕迹把路线描绘下来,在 canvas 内, 除了描边, 还有一个叫做填充,咱们再来一个矩形, 这次我们不进行描边, 而是进行填充。

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100100)
ctx.lineTo(200100)
ctx.lineTo(200200)
ctx.lineTo(100200)

// 3. 填充
// 语法: 工具箱.fill()
ctx.fill()

canvas 入门

这样, 就会按照我们绘制的路线, 以填充的形式出现一个封闭图形

注意 : 填充的时候可以不进行图形闭合, 会自动闭合图形以后进行填充,填充的时候也可以设置填充颜色的设置。

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100100)
ctx.lineTo(200100)
ctx.lineTo(200200)
ctx.lineTo(100200)

// 3. 填充
// 3-1. 填充颜色设置
// 语法: 工具箱.fillStyle = '值'
ctx.fillStyle = 'skyblue'
// 3-2. 填充
ctx.fill()

canvas 入门

填充是可以和描边一起使用的

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100100)
ctx.lineTo(200100)
ctx.lineTo(200200)
ctx.lineTo(100200)

// 自动闭合图形
ctx.closePath()

// 3. 描边
// 3-1. 设置描边样式
ctx.lineWidth = 4
ctx.strokeStyle = 'orange'
// 3-2. 描边
ctx.stroke()

// 4. 填充
// 4-1. 填充颜色设置
ctx.fillStyle = 'skyblue'
// 4-2. 填充
ctx.fill()

canvas 入门

canvas的填充规则

我们发现, 到现在为止, canvas 的绘制, 描边, 填充都很简单,但是接下来的内容可能稍微复杂一些了,我们要说一下 canvas 的填充规则,我们管 canvas 的填充规则叫做 非零填充

例子 一下子可能说不明白, 我们先来看一个例子,绘制一个 "回" 形

注意一个细节 : 我们绘制的过程,里面的小正方形我们会按照 顺时针 的方向绘制,外面的大正方形我们也会按照 顺时针 的方向绘制。

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制里面的小正方形
ctx.moveTo(200100)
ctx.lineTo(300100)
ctx.lineTo(300200)
ctx.lineTo(200200)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(15050)
ctx.lineTo(35050)
ctx.lineTo(350250)
ctx.lineTo(150250)
ctx.stroke()

canvas 入门

两个正方形都是这个方向绘制的, 我们接下来把描边的线去掉,我们来进行一下填充看看。

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制里面的小正方形
ctx.moveTo(200100)
ctx.lineTo(300100)
ctx.lineTo(300200)
ctx.lineTo(200200)
// ctx.lineWidth = 2
// ctx.strokeStyle = '#000'
// ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(15050)
ctx.lineTo(35050)
ctx.lineTo(350250)
ctx.lineTo(150250)
// ctx.stroke()

// 4. 填充
ctx.fill()

canvas 入门

我们发现, 两个都被填充了,这是因为, 在填充的时候, 就是会一次性把所有的内容都会填充好

注意 : 和是否闭合路径 ( 工具箱.closePath() ) 没有关系,和里外正方形的绘制先后顺序没有关系。那是怎么回事呢 ?

例子 先不管是怎么回事, 我们再来看一个例子,还是绘制一个 "回" 形 注意一个细节 :

我们绘制的过程,里面的小正方形我们会按照 逆时针 的方向绘制,外面的大正方形我们也会按照 顺时针 的方向绘制

// 0. 获取到页面上的 canvas 标签元素节点
const canvasEle = document.querySelector('#canvas')

// 1. 获取当前这个画布的工具箱
const ctx = canvasEle.getContext('2d')

// 2. 开始绘制里面的小正方形
ctx.moveTo(200100)
ctx.lineTo(200200)
ctx.lineTo(300200)
ctx.lineTo(300100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(15050)
ctx.lineTo(35050)
ctx.lineTo(350250)
ctx.lineTo(150250)
ctx.stroke()

canvas 入门

这回两个矩形绘制的时候, 方向不一样了,我们再来填充一次试试看

canvas 入门

我们会发现, 和刚才填充出来的结果不一样了,这又是怎么回事呢 ?难道和顺时针逆时针有关系吗 ?

非零填充 其实我们的填充和顺时针逆时针有关系, 但是不是简单的顺逆时针的问题 概念 : 从任何一个区域向画布最外层移动,按照经历最短边计算,其中经历的顺时针的边记录为 +1,经历逆时针的边记录为 -1,只要最终总和不为 零, 那么该区域填充,如果最终总和为 零, 那么该区域不填充,听起来很麻烦, 咱们来画布上看一下效果就好了,这次我们绘制一个稍微复杂一些的图形。

canvas 入门

这是两个矩形对接在一起, 一个是顺时针绘制, 一个是逆时针绘制,我们来分析一下看看,首先, 最左侧封闭图形。

canvas 入门

如果走最短的路线出来的话, 会经历一条顺时针的边,记录为 +1,最终为 +1,所以该区域填充,然后, 最右侧封闭图形。

canvas 入门

经历最短路线出来的话, 会经历一条逆时针的边,记录为 -1,最终为 -1,所以该区域填充,最后, 中间的封闭图形。

canvas 入门

经历最短路线出来的会, 必然会经历一条顺时针的边和一条逆时针的边,顺时针记录为 +1,逆时针记录为 -1,最终为 0,所以该区域不填充,此时我们对当前图形进行填充后观察。

canvas 入门

这就是最后填充好的样子

转载自:https://juejin.cn/post/7251792725070757947
评论
请登录