前言
课件地址
课堂目标
1.理解合成的原理。
2.可以灵活熟练的合成图像。
知识点
1.透明度合成 globalAlpha
2.路径裁剪 clip()
3.全局合成 globalCompositeOperation
1-透明度合成 globalAlpha
globalAlpha 就是全局对象的透明度,全局对象就是canvas 的上下文对象。 使用方法:ctx.globalAlpha=0.6;
代码示例:
ctx.save();
ctx.globalAlpha=0.5;
ctx.fillRect(50,50,400,200);
ctx.fillRect(150,150,400,200);
ctx.restore();
ctx.fillRect(250,250,400,200);
注意:globalAlpha 要和颜色里的rgba 区别一下。
rgba 控制的是某种颜色的透明度;
globalAlpha 相当于是让整个画布变透明了。
2-路径裁剪 clip
路径裁剪就是在画布上设置一个路径,让我们之后绘制的图像只显示在这个路径之中。
路径裁剪的步骤:
- 定义路径
- ctx.clip()
- 绘制其它图形
代码示例:
ctx.beginPath();
ctx.arc(300,300,100,0,Math.PI*2);
ctx.stroke();
ctx.clip();
ctx.fillRect(300,300,100,100);
3-全局合成 globalCompositeOperation
全局合成是canvas 画布中的已绘图像和将绘图像的融合方式。
我们可以从形状和色彩两方面解读全局合成。
以下图为例,说一下全局合成的步骤。
全局合成步骤:
- 先画一个黄色的正方形
- 设置全局合成的属性
- 再绘制一个绿色的圆
合成示例-刮刮乐
刮刮乐的绘制步骤:
1.用css 在canvas 中添加一个背景。
2.在canvas 中绘制一张遮罩图。
3.在canvas 画布中实现手绘效果。
4.将手绘效果与遮罩做destination-out 合成。
整体代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,user-scalable=no">
<title>刮刮乐</title>
<style>
body{margin: 0;overflow: hidden}
#canvas{
margin: 100px;
background-image: url("./images/ggl-back.png");
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas=document.getElementById('canvas');
const ctx=canvas.getContext('2d');
/*图像尺寸,遮罩图和背景图尺寸一样*/
const [width,height]=[395,188];
canvas.width=385;
canvas.height=188;
/*建立图像源*/
const img=new Image();
img.src='./images/ggl-mask.png';
img.onload=function(){
/*绘制遮罩层*/
ctx.drawImage(img,0,0);
};
/*
* 线对象 Line
* ctx 上下文对象
* drawing 是否正在绘图
*
* 鼠标按下 moveTo(x,y)
* 记录正在绘图的状态 drawing
* 保存状态
* 设置全局合成属性globalCompositeOperation 为destination-out
* 线宽lineWidth为30
* moveTo()设置路径起点
* 鼠标移动 lineTo(x,y)
* lineTo()绘制下一个点
* stroke()描边
* 鼠标抬起 restore()
* 状态还原
* 取消正在绘图的状态
* */
class Line{
constructor(ctx){
this.ctx=ctx;
this.drawing=false;
}
moveTo(x,y){
const {ctx}=this;
this.drawing=true;
ctx.save();
ctx.lineWidth=30;
ctx.globalCompositeOperation='destination-out';
ctx.moveTo(x,y);
}
lineTo(x,y){
const {ctx}=this;
ctx.lineTo(x,y);
ctx.stroke();
}
restore(){
this.ctx.restore();
this.drawing=false;
}
}
/*实例化线对象 Line*/
const line=new Line(ctx);
/*==========鼠标事件===========*/
/*鼠标按下*/
canvas.addEventListener('mousedown',function(event){
//鼠标左键按下
if(event.buttons===1) {
//获取鼠标位置
const {x, y} = getMousePos(event);
//绘制起点
line.moveTo(x,y);
}
});
/*鼠标移动*/
canvas.addEventListener('mousemove',function(event){
//鼠标左键按下且处于绘图状态
if(event.buttons===1&&line.drawing) {
//获取鼠标位置
const {x, y} = getMousePos(event);
//绘制下一个点
line.lineTo(x,y);
}
});
/*鼠标抬起*/
canvas.addEventListener('mouseup',function(event){
//鼠标左键按下
if(event.buttons===1) {
//状态还原
line.restore();
}
});
//获取鼠标在canvas中的位置
function getMousePos(event){
//获取鼠标位置
const {clientX,clientY}=event;
//获取canvas 边界位置
const {top,left}=canvas.getBoundingClientRect();
//计算鼠标在canvas 中的位置
const x=clientX-left;
const y=clientY-top;
return {x,y};
}
</script>
</body>
</html>
总结
已绘制到canvas 上的图像不可被修改,只能被覆盖或擦除。
路径裁剪是基于路径的一种合成方式,它只能使用路径设置裁剪区域,如果是文字的话,就无效。
透明度合成和全局合成都是基于像素的操作。