JavaScript全解析——canvas 入门(下)

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()


复制代码

●接下来, 我们开始设置两端样式
语法: 工具箱.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()


复制代码

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

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

// 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.stroke()
ctx.beginPath()

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

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


复制代码

●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 中, 一旦你画出封闭图形以后
●我们不光可以描边, 也可以进行填充, 也就是填满颜色
●先来画一个矩形吧

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

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

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


复制代码

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

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

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

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)

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



复制代码

●这样, 就会按照我们绘制的路线, 以填充的形式出现一个封闭图形
●注意 : 填充的时候可以不进行图形闭合, 会自动闭合图形以后进行填充
●填充的时候也可以设置填充颜色的设置

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

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

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)

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


复制代码

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

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

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

// 2. 开始绘制第一个线段
// 第一个线段
ctx.moveTo(100, 100)
ctx.lineTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(100, 200)

// 自动闭合图形
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 的填充规则叫做 非零填充

例子
●一下子可能说不明白, 我们先来看一个例子
●绘制一个 "回" 形
●注意一个细节 :
○我们绘制的过程
○里面的小正方形我们会按照 顺时针 的方向绘制
○外面的大正方形我们也会按照 顺时针 的方向绘制

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

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

// 2. 开始绘制里面的小正方形
ctx.moveTo(200, 100)
ctx.lineTo(300, 100)
ctx.lineTo(300, 200)
ctx.lineTo(200, 200)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(150, 50)
ctx.lineTo(350, 50)
ctx.lineTo(350, 250)
ctx.lineTo(150, 250)
ctx.stroke()


复制代码

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

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

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

// 2. 开始绘制里面的小正方形
ctx.moveTo(200, 100)
ctx.lineTo(300, 100)
ctx.lineTo(300, 200)
ctx.lineTo(200, 200)
// ctx.lineWidth = 2
// ctx.strokeStyle = '#000'
// ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(150, 50)
ctx.lineTo(350, 50)
ctx.lineTo(350, 250)
ctx.lineTo(150, 250)
// ctx.stroke()

// 4. 填充
ctx.fill()


复制代码

●我们发现, 两个都被填充了
●这是因为, 在填充的时候, 就是会一次性把所有的内容都会填充好
●注意 :
○和是否闭合路径 ( 工具箱.closePath() ) 没有关系
○和里外正方形的绘制先后顺序没有关系
●那是怎么回事呢 ?

例子
●先不管是怎么回事, 我们再来看一个例子
●还是绘制一个 "回" 形
●注意一个细节 :
○我们绘制的过程
○里面的小正方形我们会按照 逆时针 的方向绘制
○外面的大正方形我们也会按照 顺时针 的方向绘制

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

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

// 2. 开始绘制里面的小正方形
ctx.moveTo(200, 100)
ctx.lineTo(200, 200)
ctx.lineTo(300, 200)
ctx.lineTo(300, 100)
ctx.lineWidth = 2
ctx.strokeStyle = '#000'
ctx.stroke()

// 3. 开始绘制外面的大正方形
ctx.moveTo(150, 50)
ctx.lineTo(350, 50)
ctx.lineTo(350, 250)
ctx.lineTo(150, 250)
ctx.stroke()


复制代码

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

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

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

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

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

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

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

●这就是最后填充好的样子

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值