什么是canvas
HTML5的 canvas 元素使用 JavaScript 在网页上绘制图像
画布是一个矩形区域 你可以控制其每一像素 canvas 拥有多种绘制路径 矩形 字符 以及添加图像的方法
体验Canvas
向HTML5 页面添加canvas 元素 规定元素的 id 宽度和高度
<canvas id='canvas' width='300px' height='300px'></canvas>
var canvas=document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100,100)
绘制直线 (轨迹 绘制路径)看不见
val.lineTo(200,100)
描边
val.stroke()
绘制平行线 和 线模糊
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100, 100.5)
//绘制直线 (轨迹 绘制路径)看不见
val.lineTo(200, 100.5)
//描边
val.moveTo(100,200)
val.lineTo(300,200)
val.stroke()
/*关于线条问题*/
// 默认的宽度是多少 1px
// 默认的颜色是什么 黑色
//产生的原因: 对齐的点是线的中心位置 会把线分成两个.5px 显示的会不饱和和增加宽度
//解决方案 前后移动.5px
开启新路径 beginPath
开启新路径 beginPath 解决样式重叠
- 画的每一条边都是一样的
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100, 100.5)
//绘制直线 (轨迹 绘制路径)看不见
val.lineTo(150, 200)
//描边
val.moveTo(100,100.5)
val.lineTo(50,200)
val.moveTo(150, 200)
val.lineTo(50,200)
val.strokeStyle ='red'
val.lineWidth =5
val.stroke()
- 如何才能让每条边不一样
(存在问题 线与线的连接点 没有完全重合 有缺角)原因是 连接的是线的中心点
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100, 100.5)
//绘制直线 (轨迹 绘制路径)看不见
val.lineTo(150, 200)
val.strokeStyle ='green'
val.lineWidth =5
val.stroke()
val.beginPath();
val.moveTo(100,100.5)
val.lineTo(50,200)
val.strokeStyle ='orange'
val.stroke()
val.lineWidth =5
val.beginPath();
val.moveTo(150, 200)
val.lineTo(50,200)
val.strokeStyle ='red'
val.lineWidth =5
val.stroke()
解决缺角问题
val.closePath(); 关闭路径
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100, 100.5)
//绘制直线 (轨迹 绘制路径)看不见
val.lineTo(150, 200)
val.strokeStyle ='green'
val.lineWidth =5
val.stroke()
val.beginPath();
val.moveTo(100,100.5)
val.lineTo(50,200)
val.strokeStyle ='orange'
val.stroke()
val.lineWidth =5
val.beginPath();
val.moveTo(150, 200)
val.lineTo(50,200)
val.closePath();
val.strokeStyle ='red'
val.lineWidth =5
val.stroke()
注意: val.lineTo 线条坐标点和 val.lineTo() 两条线条坐标点 相连是没有缺角的
非零规则 镂空
非零规则
1、看一块区域是否填充
2、从这个区域拉一条棉线
3、看和这条直线相交的轨迹
4、如果顺时针轨迹+1
5、如果逆时针轨迹-1
6、所有的轨迹的值计算出来
7、计算的值非零 那么填充
8、如果是0那么不填充 (两个正方形公共区域)

注意:如果计算值为 -1 -2 他也是非零
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZtL3GV3-1616667451800)(C:\Users\123\AppData\Roaming\Typora\typora-user-images\image-20210322122542775.png)]](https://i-blog.csdnimg.cn/blog_migrate/f088167a37aa22c47a68d5b25db86178.png)
注意坐标点
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100, 100)
val.lineTo(300,100)
val.lineTo(300,300)
val.lineTo(100,300)
val.closePath();
// val.fill()
// val.stroke()
val.moveTo(150,150)
val.lineTo(150,250)
val.lineTo(250,250)
val.lineTo(250,150)
val.closePath();
// val.stroke()
val.fillStyle = 'red'
val.fill()
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmJk6Wba-1616667451811)(C:\Users\123\AppData\Roaming\Typora\typora-user-images\image-20210322132026136.png)]](https://i-blog.csdnimg.cn/blog_migrate/eb81d9a1e068241cc468ef65c8cfb5e1.png)
API总结
- lineWidth 线条 默认 1px
- lineCap 线末端类型 (but默认)round square
- lineJoin 相交线的拐点 miter(默认) round bevel
- strokeStyle 线的颜色
- fillStyle 填充颜色
- setLineDash() 设置虚线
- getLineDash() 获取虚线宽度集合
- lineDashOffset 设置虚线偏移量 (负值向右移动)
虚线
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100, 100)
val.lineTo(300,100)
// [5,10] 数组是用来描述你的排列方式 实线的宽度 空隙的宽度
val.setLineDash([5,10])
val.stroke()
- 不规则的虚线

var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
val.moveTo(100, 100)
val.lineTo(300,100)
// [5,10] 数组是用来描述你的排列方式 实线的宽度 空隙的宽度
// 获取的是不重复的那段位置
val.setLineDash([5,10,5])
// 如果是正的值 往后偏移
// 如果是负的值 往前偏移
val.lineDashOffset = '-20'
val.stroke()
绘制渐变矩形

原理:线是由一个个点组成的
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
for (let i = 0; i < 255; i++) {
val.beginPath()
val.lineWidth='20'
val.moveTo(100 + i - 1, 100)
val.lineTo(300 + i, 100)
val.strokeStyle = `rgb(${i},${i},${i})`
val.stroke()
}
绘制网格
原理: 折线图也是由不同的点组成
- 网格的大小
- 有多少条X轴上的线
- 有多少条Y轴上的线
- 遍历形式去画

var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
let key = 30;
let x = Math.floor(canvas.width / key)
let y = Math.floor(canvas.height/ key)
console.log(y);
for(var i =1;i<x ; i++){
val.beginPath()
val.moveTo(key*i,0)
val.lineTo(key*i ,600)
val.strokeStyle ='red'
val.stroke()
}
for(let d =1; d<y ; d++){
val.beginPath()
val.moveTo(0,key*d)
val.lineTo(600,key*d)
val.strokeStyle = 'red'
val.stroke()
}
绘制坐标系
- 画坐标系 确定原点
- 确定距离画布旁边的距离
- 确定坐标轴的长度
- 确定箭头的大小 是个等腰三角形
- 绘制箭头填充


<canvas id='canvas' width="600px" height="600px" style="border: 1px solid #ccc;"></canvas>
var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
let key = 12;
let x = Math.floor(canvas.width / key)
let y = Math.floor(canvas.height / key)
console.log(y);
// 画 x 轴
for (var i = 1; i < x; i++) {
val.beginPath()
val.moveTo(key * i, 0)
val.lineTo(key * i, 600)
val.strokeStyle = '#ccc'
val.stroke()
}
// 画 Y 轴
for (let d = 1; d < y; d++) {
val.beginPath()
val.moveTo(0, key * d)
val.lineTo(600, key * d)
val.strokeStyle = '#ccc'
val.stroke()
}
val.beginPath()
var coording = {
x: 100,
y: 100
}
// 画点尺寸
var dottedSize = 12;
val.moveTo(coording.x - dottedSize / 2, coording.y - dottedSize / 2)
val.lineTo(coording.x + dottedSize / 2, coording.y - dottedSize / 2)
val.lineTo(coording.x + dottedSize / 2, coording.y + dottedSize / 2)
val.lineTo(coording.x - dottedSize / 2, coording.y + dottedSize / 2)
val.fillStyle = 'blue'
val.fill()
// 数学坐标系 x 轴
val.beginPath()
val.moveTo(key, canvas.height - key)
val.lineTo(canvas.width - key, canvas.height - key)
val.strokeStyle = 'blue'
val.lineWidth = '3'
val.stroke()
// 数学坐标系 x 轴 箭头
val.beginPath()
val.lineTo(canvas.width - key, canvas.height - key)
val.lineTo(canvas.width - key - 10, canvas.height - key - 10)
val.lineTo(canvas.width - key - 10, canvas.height - key + 10)
// val.lineWidth = '3'
val.fillStyle = 'red'
val.fill()
// val.stroke()
//画数学坐标系的 Y轴
val.beginPath()
val.moveTo(key, canvas.height - key)
val.lineTo(key,key)
val.lineWidth = '3'
val.strokeStyle = 'blue'
val.stroke()
val.beginPath()
val.moveTo(key,key)
val.lineTo(key+10, key+10)
val.lineTo(0, key+10)
// val.strokeStyle = 'red'
val.fillStyle = 'red'
val.fill()
// val.stroke()
绘制坐标点
- 绘制点
- 点的尺寸
- 以坐标中心绘制点

var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
//移动画笔 (从哪个坐标轴 开始画)
let key = 12;
let x = Math.floor(canvas.width / key)
let y = Math.floor(canvas.height/ key)
console.log(y);
for(var i =1;i<x ; i++){
val.beginPath()
val.moveTo(key*i,0)
val.lineTo(key*i ,600)
val.strokeStyle ='red'
val.stroke()
}
for(let d =1; d<y ; d++){
val.beginPath()
val.moveTo(0,key*d)
val.lineTo(600,key*d)
val.strokeStyle = 'red'
val.stroke()
}
val.beginPath()
// 参照的坐标点
var coording ={
x:100,
y:100
}
// 点尺寸
var dottedSize = 12;
val.moveTo( coording.x- dottedSize/2,coording.y - dottedSize/2)
val.lineTo(coording.x + dottedSize/2,coording.y - dottedSize /2)
val.lineTo(coording.x + dottedSize/2,coording.y + dottedSize / 2)
val.lineTo(coording.x - dottedSize/2,coording.y + dottedSize/2)
val.fillStyle = 'blue'
val.fill()
折线图-完整版-面向对象

<canvas id='canvas' width="400px" height="400px" style="border: 1px solid;"></canvas>
class Canvas {
constructor(option) {
let { canvas, data } = option
canvas = canvas || document.querySelector('#canvas')
this.ctx = canvas.getContext('2d')
// 坐标系的宽度
this.width = canvas.width
// 坐标系的高度
this.height = canvas.height
// 坐标系的间距
this.space = 15
// 坐标点的大小
this.dot = 5
// 遍历的行数
this.x = Math.floor(this.width / this.space)
this.y = Math.floor(this.height / this.space)
// 绘制网格
this.drawGrid()
// 绘制坐标系
this.drawCsys()
// 绘制坐标点
this.drawPoint(data)
}
// 绘制网格
drawGrid() {
let x = this.x, y = this.y;
let space = this.space;
// 绘制 x 轴
for (let i = 1; i <= x; i++) {
this.ctx.beginPath()
this.ctx.moveTo(i * space, 0)
this.ctx.lineTo(i * space, this.height)
this.ctx.strokeStyle = '#eee'
this.ctx.stroke()
// 绘制 Y 轴
this.ctx.beginPath()
this.ctx.moveTo(0, i * space)
this.ctx.lineTo(this.width, i * space)
this.ctx.strokeStyle = '#eee'
this.ctx.stroke()
}
}
// 绘制坐标系
drawCsys() {
// X 轴 数学坐标系
this.ctx.beginPath()
this.ctx.moveTo(this.space, this.height - this.space)
this.ctx.lineTo(this.width - this.space - 5, this.height - this.space)
this.ctx.lineWidth = '5'
this.ctx.strokeStyle = 'red'
this.ctx.stroke()
this.ctx.closePath()
// 绘制箭头 X
this.ctx.beginPath()
this.ctx.moveTo(this.width - this.space, this.height - this.space)
this.ctx.lineTo(this.width - this.space - 12, this.height - this.space - 12)
this.ctx.lineTo(this.width - this.space - 12, this.height - this.space + 12)
this.ctx.fillStyle = 'red'
this.ctx.fill()
this.ctx.closePath()
// Y 轴 数学坐标系
this.ctx.beginPath()
this.ctx.moveTo(this.space, this.height - this.space)
this.ctx.lineTo(this.space, this.space + 5)
this.ctx.lineWidth = '5'
this.ctx.strokeStyle = 'red'
this.ctx.stroke()
// 绘制箭头 Y
this.ctx.moveTo(this.space, this.space)
this.ctx.lineTo(0, this.space + 12)
this.ctx.lineTo(this.space + 12, this.space + 12)
this.ctx.fillStyle = 'red'
this.ctx.fill()
this.ctx.closePath()
}
// 绘制坐标点
drawPoint(data) {
// 数据坐标点 要转换成 canvas坐标点
// 进行点的绘制 再把线连起来
// 以坐标原点进行转换
// x = 原点坐标 + 数据坐标
// y = 原点坐标 - 数据坐标
let preX, preY;
data.forEach((element, index) => {
// debugger
this.ctx.beginPath()
this.ctx.moveTo(element.x + this.space, this.height - this.space - element.y)
this.ctx.lineTo(element.x + this.space - this.dot, this.height - this.space - element.y)
this.ctx.lineTo(element.x + this.space - this.dot, this.height - this.space - element.y + this.dot)
this.ctx.lineTo(element.x + this.space, this.height - this.space - element.y + this.dot)
this.ctx.fillStyle = 'red'
this.ctx.fill()
this.ctx.closePath()
// debugger
// 绘制线条
if (index != 0) {
this.ctx.beginPath()
this.ctx.moveTo(preX, preY)
this.ctx.lineTo(element.x + this.space, this.height - this.space - element.y)
this.ctx.lineWidth = '1'
this.ctx.stroke()
this.ctx.closePath()
}
preX = element.x + this.space, preY = this.height - this.space - element.y;
});
}
}
new Canvas({
canvas,
data
})
绘制距形
- rect(x,y,w,h) 没有独立路径
- strokeReact(x,y,w,h)有独立路径
- fillReact(x,y,w,h)有独立路径 不影响别的绘制
- clearReact(x,y,w,h) 擦除矩形区域
矩形线性渐变
- 渐变要素 : 1、方向 2、起始颜色 3、结束颜色
- 通过两个点 可以确定方向
- 也可以使用一个渐变方案填充矩形
- 创建一个渐变的方案

var canvas = document.querySelector('#canvas')
// 获取上下文 绘制工具箱
var val = canvas.getContext('2d')
// 两个点确定渐变的方向
// var linear = val.createLinearGradient(0, 0, 400, 400);
var linear = val.createLinearGradient(0, 400, 400, 400);
linear.addColorStop(0, 'pink');
linear.addColorStop(.5, 'blue');
linear.addColorStop(1, 'red');
// 填充
val.fillStyle = linear
val.fillRect(0, 0, 400, 400);
圆的绘制
-
什么是弧度 是一个长度单位
-
一个弧度怎么去描述 一个圆有过少个弧度 2*π
-
一个弧度有多长 一个弧度 是一个半径的长度
-
角度: 一个圆是 360度
-
半径 以一个点为中心多长为半径
-
周长 2πr
结论: 一个角度等于多少弧度 π/180
- 绘制圆弧
- 确定圆形 坐标 x y
- x 圆形横坐标
- y 圆形纵坐标
- 确定起始绘制位置和结束绘制的位置 确定弧的长度和位置
- 取绘制的方向 direction 默认是顺时针
- ctx.arc()
在中心位置画一个半径150px的圆弧右下角
var myCanvas =document.querySelector('canvas')
var ctx = myCanvas.getCantext('2d')
var w = ctx.canvas.width;
var h = ctx.canvas.height;
// 坐标 半径 弧度起始位置 和 结束位置
ctx.arc(w/2,h/2,150,0,Math.PI/2) // Math.PI 代表就是π
PI
ctx.stroke();

扇形
在中心位置画一个半径150px的圆弧右上角 扇形 描边 填充
var myCanvas =document.querySelector('canvas')
var ctx = myCanvas.getCantext('2d')
var w = ctx.canvas.width;
var h = ctx.canvas.height;
// 坐标 半径 弧度起始位置 和 结束位置
ctx.arc(w/2,h/2,150,0,-Math.PI/2,true) // Math.PI 代表就是π
PI
ctx.stroke();

- 如何闭合路径 (效果确是弓形 应该提前确定起始点)
......................
ctx.arc(w/2,h/2,150,0,-Math.PI/2) // Math.PI 代表就是π
ctx.closePath();
ctx.stroke();
-
效果如下

-
优化
// 把起点放在圆心位置
ctx。moveTo(w/2,h/2);
ctx.arc(w/2,h/2,150,0,-Math.PI/2,true) // Math.PI 代表就是π
ctx.closePath();
ctx.stroke();

把圆分成若干等份
var myCanvas =document.querySelector('canvas')
var ctx = myCanvas.getCantext('2d')
var w = ctx.canvas.width;
var h = ctx.canvas.height;
var num = 6;
// 一份多少弧度
var angle = Math.PI *2 / 6;
// 圆点坐标
var x0 = w/2
var y0 = h/2
// 获取随机颜色
var getRandomColor = function (){
var r = Math.floor(Math.random()*256);
var g = Math.floor(Math.random()*256);
var b = Math.floor(Math.random()*256);
return `rgb(${r},${g},${b})`
}
// 上一次结束位置 等于这次的起始位置
var startAngle = 0
for (var i =0 ; i<num ; i++){
var starAngle = i *angle;
var endangle = (i +1) * angle;
ctx.beginPath();
//移到坐标圆点
ctx.moveTo(x0,y0)
ctx.arc(x0,y0,150,starAngle,endangle)
// 随机颜色
ctx.fillStyle = {getRandomColor();
ctx.fill()
}
封装饼图
var w = ctx.canvas.width;
var h = ctx.canvas.height;
// 圆点坐标
var x0 = w/2
var y0 = h/2
//在饼图表示出来
var data= [5,30,10,9]
// 需要把数据转出弧度
var angleList = [];
var total = 0;
data.forEach((item,index)=>{
total = item;
})
// 在第二次转化成弧度时候就可以去绘制扇形 减少一次遍历
data.forEach((item,index)=>{
var angle =Math.PI *2*(item/total);
angleList.push(angle);
})
//根据弧度绘制扇形
var startAngle = 0;
angleList.forEach((item,i)=>{
// 上一次绘制的结束弧度等于当前次的起始弧度
var endAngle = startAngle + item;
ctx.beginPath();
ctx.moveTo(x0,y0,150, startAngle, endAngle);
// 记录当前的结束位置作为下一次的起始位置
starAngle = endAngle
})

绘制文本
- ctx.fontt = ‘微软雅黑’ 设置字体
- strokeText()
- fillText(text,x,y,maxWidth)
- text 要绘制的文本
- x,y文本绘制的坐标(文本左下角)
- maxWidth 设置文本最大宽度 可选参数
- ctx.textAlign文本水平对齐方式 相对绘制坐标来说的
- left
- center
- right
- start 默认
- end
- ctx.direction属性 css(rtl , ltr) start 和 end 于此相关
- 如果是ltr,start和left 表现一致
- 如果是rtl, start 和 right 表现一致
- ctx.textBaseline 设置基线 (垂直对齐方式)
- top 文本的基线处于文本的正上方 并且有一定的距离
- middle 文本的基线处于文本的正中间
- bottom 文本的基线处于文本的正上方 并且和文本粘合
- alphabetic 和 bottom 相似 但是不一样
- measure ext() 获取文本宽度 obj.width
var myCanvas = document.querySelector('canvas')
var ctx = myCanvas.getCantext('2d')
// 1、在画布的中心绘制一段文字
// 2、声明一段文字
var str = ‘你吃了吗’;
- 居中对齐

- 右对齐

<canvas id="canvas" style="display:block;margin:0 auto;width: 300px; height:300px; border: 1px solid red;"></canvas>
var canvas = document.querySelector('#canvas');
var ctx = canvas.getContext('2d')
// 声明一段文字
var str = '你吃了'
// 确定画布的中心
var w = ctx.canvas.width;
var h = ctx.canvas.height;
console.log(w,h);
// 画一个十字架 在画布的中心
ctx.beginPath();
ctx.moveTo(0,h/2-0.5);
ctx.lineTo(w,h/2 - 0.5);
ctx.moveTo(w/2-0.5,0);
ctx.lineTo(w/2 -0.5 , h);
ctx.strokeStyle = '#eee'
ctx.stroke()
// 绘制文本;
ctx.beginPath()
ctx.strokeStyle = '#000'
var x0 = w/2;
var y0 = h/2;
// 注意起点位置在文字的左下角
// 对齐的基准是其实坐标
// 有文本的属性 尺寸 字体 左右对齐方式 垂直对齐的方式
ctx.font ="40px 微软雅黑"; // 同时设置两个值生效
ctx.textAlign = 'right'
ctx.strokeText(str,x0,y0);
1万+

被折叠的 条评论
为什么被折叠?



