要通过canvas绘制图形,首先得获取到canvas的上下文对象。这个对象里提供了各种api供我们去绘制图形
<canvas width="800" height="500" id="mycanvas" style="border: 1px solid #ddd"></canvas>
let cnv = document.getElementById('mycanvas')
let ctx = cnv.getContext('2d')
绘制边框,线
ctx.moveTo(100,50) //起点坐标
ctx.lineTo(200,100) //终点坐标
ctx.lineWidth = 20 //线的粗细
ctx.strokeStyle = 'pink' //线的颜色
ctx.lineCap = 'round' //直线两端的样式 默认butt,圆形round,方形 square
ctx.stroke() //绘制线段
多个点连成一个图形
ctx.strokeStyle = 'red'
ctx.moveTo(100,100)
ctx.lineTo(200,100)
ctx.lineTo(200,200)
ctx.closePath() //闭合
填充颜色
ctx.fillStyle = 'yellow'
ctx.fill()
绘制图片
ctx.drawImage(image,图片左上角的x轴坐标,图片左上角的y轴坐标,图片的宽度,图片的高度)
第一个参数可以是一个img元素,可以是video等等,具体的自行百度
将canvas转成base64图片
ctx.toDataURL('image/png')
绘制一个圆
/**
* 绘制一个圆
* 绘制圆形之前必须先开辟路劲,绘制结束之后调用closePath闭合
* arc(圆心x坐标,圆心y坐标,半径,起始角度,结束角度) 起始角度是水平x轴开始
* 1°等于 Math.PI/180
* stroke绘制线条,fill绘制图形,可填充颜色
*/
ctx.arc(150, 100, 50, 120* Math.PI/180, 60 * Math.PI/180)
ctx.stroke()
ctx.fill()
绘制一个扇形
扇形其实就是在绘制原型的基础上,将画出的圆弧和原型点进行闭合
ctx.arc(150, 100, 50, 0, 60 * Math.PI/180) //这样能绘制出一个圆弧
ctx.lineTo(150,100) //这个坐标点为圆心坐标点
ctx.closePath() //闭合一下,就得到一个圆弧了,不过此时没有边框也没有填充颜色是看不到效果的
ctx.fillStyle = 'yellow'
ctx.fill()
加上这两行,就可以看到一个黄色的扇形了
几个需要注意的点,
1.stroke就是和线条相关的api,stroke()可以绘制线条,其他以stroke开头的api可以设置线条的样式
2.fill为填充相关api
3.当需要重新绘制一个图形的时候需要调用beginPath函数来开辟一个新的路劲,不然后续绘制的样式都会基于上一次绘制的东西上。举个例子
ctx.moveTo(100,50) //线的起始坐标X,Y
ctx.lineTo(200,100) //线的结束坐标X,Y
ctx.lineWidth = 20 //线的粗细
ctx.strokeStyle = 'pink' //线的颜色
ctx.lineCap = 'round' //直线两端的样式 默认butt,圆形round,方形 square
ctx.stroke() //连接两个坐标点
ctx.beginPath() //重新开辟一个路劲,不然所有的线会沿用同一个样式
ctx.moveTo(50,50) //线的起始坐标X,Y
ctx.lineTo(100,100) //线的结束坐标X,Y
ctx.lineWidth = 20 //线的粗细
ctx.strokeStyle = 'red' //线的颜色
ctx.lineCap = 'round' //直线两端的样式 默认butt,圆形round,方形 square
ctx.stroke() //连接两个坐标点
4.canvas的坐标系是这样的
edafb74caf78aca6133421e76b9ed28.jpg
附上几个小demo
canvas画一个仪表盘的进度条
其实就是绘制一个缺了角的圆,不填充颜色,然后然线条的粗细调大一点,再给线条一个颜色就行了
let oneAge = Math.PI / 180
ctx.beginPath()
let zhongdian = 120
ctx.lineWidth = 10
ctx.strokeStyle = 'pink'
ctx.lineCap = 'round'
ctx.fillStyle = 'pink'
let t = setInterval(()=>{
if(zhongdian==60){
clearInterval(t)
}else{
zhongdian+=10
if(zhongdian == 360){
zhongdian = 0
}
console.log(zhongdian)
ctx.beginPath()
ctx.fillStyle = 'pink'
ctx.arc(150,100,50,120*oneAge,zhongdian*oneAge)
ctx.stroke()
}
},30)
image.png
画一个大转盘,原理就是画扇形,再每个扇形的基础上读书递增,填满整个圆
let deg = Math.PI/180 //1°
ctx.strokeStyle = 'pink'
ctx.fillStyle = 'yellow'
for (let i = 0;i<12;i++){
ctx.beginPath()
ctx.arc(400,250,100,30*i*deg,30*(i+1)*deg)
ctx.lineTo(400,250)
ctx.closePath()
ctx.fill()
ctx.stroke()
}
ctx.beginPath()
ctx.strokeStyle='red'
ctx.moveTo(400,250)
ctx.lineTo(400,180)
ctx.stroke()
cnv.style.transition = '10s'
setTimeout(()=>{
cnv.style.transform = 'rotateZ(1250deg)'
},1000)
image.png
画一个建议的canvas签名板,原理就是监听鼠标移动事件,然后不停的去绘制线段,下一条线段的启示位置就是上一条线段的结束位置,这样就能无缝连接的绘制了
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
ctx.lineWidth = 10;
ctx.strokeStyle = '#333';
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
let isDrawing = false
let initX
let initY
// 事件监听
cnv.addEventListener('mousedown', (e) => {
isDrawing = true;
initX = e.offsetX;
initY = e.offsetY
});
cnv.addEventListener('mousemove', draw);
cnv.addEventListener('mouseup', () => isDrawing = false);
cnv.addEventListener('mouseout', () => isDrawing = false);
function draw(e) {
console.log(e)
if (!isDrawing) return;
ctx.beginPath()
//起点
ctx.moveTo(initX, initY)
//终点
ctx.lineTo(e.offsetX, e.offsetY)
ctx.stroke()
initX = e.offsetX
initY = e.offsetY
}
function clean(){
ctx.clearRect(0, 0, cnv.width, cnv.height);
}
image.png
canvas绘制长文本
原理就是利用measureText方法,判断当前填充的文字有没有超过最大宽度限制,
如果有,则说明填满一行了,那就另起一行接着开始绘制
let content = this.msg
let drawTxt = '' //需要被绘制的文本
let lineNum = 1 //行数
let drawIndex = 0 //文字索引
for (let i = 0; i < content.length; i++) {
drawTxt += content[i];
if (ctx.measureText(drawTxt).width >= 310) {
ctx.fillText(drawTxt.substr(0,drawTxt.length-1), 20, lineNum * 30);
drawIndex = i + 1;
lineNum += 1;
drawTxt = '';
} else {
// 内容绘制完毕,但是剩下的内容宽度不到lineMaxWidth
if (i === content.length - 1) {
ctx.fillText(drawTxt.substr(0,drawTxt.length-1), 20, lineNum * 30);
}
}
}
}
网友评论