canvas温习

-

参考地址:https://www.runoob.com/w3cnote/html5-canvas-intro.html

这篇文章系统的把canvas的api罗列出来,可以很清晰的了解到canvas能够做哪些事情。学习canvas真的看这一偏就够了,推荐。

练习代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<canvas id="canvas" width="1000" height="1000"></canvas>
<body>
<script>
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
// 画矩形
ctx.clearRect(0,0,300,300)
ctx.fillStyle = "red";
ctx.fillRect(0, 0 , 100, 100);
ctx.clearRect(0,0,50,50)
ctx.strokeStyle = 'yellow';
ctx.strokeRect(100,100 ,100,100);
// 画线(多条)
ctx.strokeStyle= "red";
ctx.beginPath()
ctx.moveTo(100,0);
ctx.lineTo(150,0);
ctx.lineTo(150,50);
// ctx.closePath();//不封闭
ctx.stroke();//发起描边
// 画闭合图形(划线) 需用到closePath
ctx.beginPath();
ctx.strokeStyle= "green"
ctx.moveTo(150,0)
ctx.lineTo(200,0);
ctx.lineTo(200,50);
ctx.closePath();//闭合
ctx.stroke();
// 绘制填充三角形
ctx.fillStyle= "red"
ctx.beginPath();
ctx.moveTo(200,0)
ctx.lineTo(250,0)
ctx.lineTo(250,50)
ctx.fill();//填充命令  会自动调用closepath
// 绘制圆弧
ctx.beginPath()
ctx.arc(275,25,25,0,Math.PI / 2,false);// 圆心:275 、 25 半径:25 起始角度 0 结束角度 90 顺时针:false
ctx.stroke()
// 绘制圆弧 通过两条线的切线画弧线
ctx.beginPath()
ctx.moveTo(310,0) //起始点
ctx.arcTo(310,50,360,50,25) //控制点1:310 、 50 控制点2:360 、 50 半径:25
ctx.lineTo(360,50) //结束点 360 、 50
ctx.stroke()

// 把以上3个点标出来
ctx.beginPath()
ctx.fillStyle = 'black'
ctx.fillRect(310,0,10,10)
ctx.fillRect(310,50,10,10)
ctx.fillRect(360,50,10,10)
ctx.fill()
// 标注3个点的文字
ctx.beginPath()
ctx.fillStyle = "green"
ctx.strokeStyle = "green"
ctx.font= "14px 宋体"
ctx.fillText("起始点",310,10)
ctx.fillText("控制点1",310,50)
ctx.strokeText("控制点2",360,50)
// 绘制二次赛贝尔曲线 起始点、控制点、结束点
ctx.beginPath()
ctx.moveTo(400,0) // 起始点 400 、 0
ctx.quadraticCurveTo(400, 50, 450, 50); // 控制点 400 、 50 结束点:450 、 50
ctx.stroke()

// 样式调整
// fillStyle 填充颜色
// strokeStyle 描边颜色

// lineWidth 线宽
ctx.lineWidth = 20; //以起始点到结束掉为中心 上下各占一半
ctx.beginPath()
ctx.moveTo(450, 10)
ctx.lineTo(500,10)
ctx.stroke()

// 线条末端样式 butt:以方形结束(默认)、round:线段末端以原型结束 、 square:末端以方形结束,末端会多出线条宽度一半的厚度的方形
var lineCaps = ["butt", "round", "square"];
lineCaps.forEach((item,index) => {
  ctx.beginPath()
  ctx.moveTo(520 + (40  * index) ,30)
  ctx.lineTo(520 + (40 * index), 50)
  ctx.lineCap = item;
  ctx.lineWidth = 20;
  ctx.strokeStyle = 'black'
  ctx.stroke()
})
// 画参考线
ctx.beginPath()
ctx.moveTo(520,30)
ctx.lineTo(600,30)

ctx.moveTo(520,50)
ctx.lineTo(600,50)

ctx.lineWidth = 1;
ctx.strokeStyle=  'red'
ctx.stroke()

// lineJoin 设置线条结合处的样式  round:圆角 、 bevel:平角 、 miter:默认 直角
var lineJoin = ['round', 'bevel', 'miter'];
lineJoin.forEach((item,index) => {
  ctx.lineWidth = 10;
  ctx.strokeStyle = 'green'
  ctx.lineJoin = item;
  ctx.beginPath();
  ctx.moveTo(650, 0 + index * 50);
  ctx.lineTo(700, 50 + index * 50);
  ctx.lineTo(750, 0 + index * 50);
  ctx.lineTo(800, 50 + index * 50);
  ctx.lineTo(850, 0 + index * 50);
  ctx.stroke();
})
// 虚线 
// setLineDash 方法接受一个数组,来指定线段长度与间隙
// lineDashOffset属性设置起始偏移量
ctx.beginPath()
ctx.lineWidth = 1
ctx.lineJoin = 'miter';
ctx.setLineDash([20, 5]);  // [实线长度, 间隙长度]
ctx.lineDashOffset = 0;
ctx.strokeRect(900, 30, 80, 80);

// 绘制文本
// fillText 填充文本
// strokeText 表变文本
// 文本样式  font 、 textAlign 、 textAlign 、 textBaseline 、 
ctx.font = '50px 宋体'
ctx.fillStyle = 'orange'
ctx.fillText('填充字体',0,250,200);// 文本、x、y、maxWidth(可选)

ctx.strokeStyle = 'blue'
ctx.strokeText('描边字体',200,250,200)// 文本、 x、y 、 maxWidth(可选)

// 画图 drawImage(img,x,y,width,height)
// 如果是网络图片,需要在图片加载完再绘制
let img = new Image();
img.src = '../cesium/data/image/1.jpg'
img.onload = () => {
  // ctx.drawImage(img,0,0) // 按图片原始宽高、以原点为起点,绘制在canvas上
  ctx.drawImage(img,400,-250,100,50) //缩放 把图片整体缩放,绘制在某一个位置
  ctx.drawImage(img,400,100,100,50,550,-250,100,50)// slice切片;默认图片以原点(0,0)位置,按图片的原宽高绘制在canvas上,前4个参数是在图片的某一位置截取一定宽高的区域,后4个参数是,把截取的图片放在canvas画布的某一个位置并设置宽高
}

// 状态的保存和恢复 savs 、 restore
// 每次save都会把当前的状态想栈中push
// 每次restore,都会把栈最后面的pop出去,
ctx.fillRect(650,200,50,50);
ctx.save()
ctx.fillStyle = 'red'
ctx.fillRect(700,200,50,50)
ctx.save()
ctx.fillStyle = '#000'
ctx.fillRect(750,200,50,50)
ctx.restore();//加载之前的状态 恢复到最近这一次save的状态 也就是 fillStyle = red
ctx.fillRect(800,200,50,50)

// 变形 translate 用来移动canvas的原点到指定位置
ctx.save()
ctx.translate(0,250)//坐标原点移动到 0 、 250 
ctx.save()
ctx.setLineDash([]);//恢复成实线
ctx.strokeRect(0, 0, 100, 100)

ctx.translate(110,0)//坐标原点在当前的基础上向右移动110 也就是初始的(110,250)
ctx.strokeRect(0, 0, 100, 100)
ctx.save()
ctx.restore()
ctx.restore()
ctx.restore() //原点恢复到初始的 0 、0
ctx.strokeRect(0, 0, 100, 100)

// 旋转 rotate(angle)    顺时针   旋转的圆点为坐标原点
ctx.fillStyle = "red";
ctx.save()
ctx.setLineDash([])
ctx.translate(250,250) //坐标原点移动到 250、 250
ctx.rotate(Math.PI / 180 * 45); // 顺时针旋转45度
ctx.strokeRect(0,0,60,60) // 要在旋转后画,否则 旋转将不生效

ctx.restore() //恢复到之前的状态  原点在0、0 且坐标系不旋转
ctx.setLineDash([])
ctx.strokeRect(350,250,100,100)
ctx.save()

// 缩放 scale(x,y) x,y坐标放大多少倍  1.2表示放大1.2倍  0.5表示缩小一半
ctx.scale(2,2)
ctx.strokeRect(225,125,50,50); //未放大前的参数为 450 、 250 、 100 、 100

ctx.restore();//恢复到放大前的状态
ctx.strokeRect(550,250,100,100);

// 合成
ctx.font='50px 楷体'
ctx.strokeStyle='red'
ctx.fillText('合成',0,400)
ctx.font='10px 楷体'
ctx.fillStyle='blue'
ctx.fillText('男儿当自强',200,400)
ctx.beginPath()
ctx.lineWidth = 1;
ctx.moveTo(0,405)
ctx.lineTo(1000,405)
ctx.closePath()
ctx.stroke()
ctx.save()
// globalCompositeOperation  
// source-over: 后画的把之前的覆盖 默认值
// source-in: 只显示重叠区域
// source-out: 只显示新图像的未与老图像重叠的部分
// source-atop: 新图像仅仅显示与老图像重叠区域。老图像仍然可以显示。
// destination-over:新图像在老图像下面
// destination-in: 仅仅新老图像重叠部分的老图像被显示,其他区域全部透明。
// destination-out: 仅仅老图像与新图像没有重叠的部分。 注意显示的是老图像的部分区域。
// destination-atop:老图像仅仅仅仅显示重叠部分,新图像会显示在老图像的下面。
// lighter:保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的) blue: #0000ff + red: #ff0000 = #ff00ff
// darken: 保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的) blue: #0000ff + red: #ff0000 = #000000
// xor: 重叠部分会变成透明。
// copy: 只有新图像会被保留,其余的全部被清除(边透明)。
ctx.translate(0,450)//将坐标原点设置在 0 、 250
ctx.save()
ctx.font = '20px 楷体'
ctx.fillText('默认 source-over',0,-10)

ctx.fillStyle='blue'
ctx.fillRect(0,0,100,100)
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle='red'
ctx.fillRect(50,50,100,100)
ctx.save()

// 裁剪路径 clip()
// ​把已经创建的路径转换成裁剪路径。
// 裁剪路径的作用是遮罩。只显示裁剪路径内的区域,裁剪路径外的区域会被隐藏。
// 注意 clip() 只能遮罩在这个方法调用之后绘制的图像,如果是 clip() 方法调用之前绘制的图像,则无法实现遮罩。
ctx.beginPath()
ctx.fillText('裁剪 clip',200,-10)
ctx.arc(250,50,50,0,Math.PI * 2);//顺时针
ctx.save();
ctx.clip();

ctx.fillStyle = 'blue'
ctx.fillRect(200,0,100,100)
ctx.restore()//恢复裁剪之前的状态

ctx.fillRect(300,0,100,100)

// 动画  我们可以用 setInterval 、 setTimeOut 、 requestAnimationFrame 不断的画canvas,实现动画
ctx.save()
let sun,earth,moon,sunLoadSuccess = false,earthLoadSuccess = false,moonLoadSuccess = false;
let init = () => { //初始化
  ctx.translate(400,0);//将坐标原点移动到 400 、 0
  ctx.save()
  ctx.clearRect(0, 0, 400, 400); //清空所有的内容
  ctx.fillStyle = 'black' //画一张400 * 400 的画布
  ctx.fillRect(0,0,400,400)
  sun = new Image();
  earth = new Image();
  moon = new Image();
  sun.src = '../cesium/data/image/sun.jpg'
  earth.src = '../cesium/data/image/earth.jpg'
  moon.src = '../cesium/data/image/moon.jpg'
  sun.onload = () => {
    sunLoadSuccess = true;
    draw()
  }
  earth.onload = () => {
    earthLoadSuccess = true;
    draw()
  }
  moon.onload = () => {
    moonLoadSuccess = true;
    draw()
  }
}
init()
var draw = () => {
  if (sunLoadSuccess && earthLoadSuccess && moonLoadSuccess){
    ctx.clearRect(0, 0, 400, 400); //清空所有的内容
    ctx.fillStyle = 'black' //画一张400 * 400 的画布
    ctx.fillRect(0,0,400,400)
    ctx.save()
    ctx.translate(150,150);//圆心 移动到 150 、 150
    // 把太阳图片的四角用圆裁剪掉
    ctx.arc(50,50,50,0,Math.PI * 2);
    ctx.save()
    ctx.clip()
    ctx.save()
    ctx.restore()//取消裁剪
    //绘制太阳
    ctx.drawImage(sun, 0, 0, 100, 100);
    ctx.restore()
    // 绘制地球轨道
    ctx.translate(50,50);//圆心 移动50 、 50
    ctx.beginPath()
    ctx.strokeStyle = "rgba(255,255,0,0.5)";
    ctx.arc(0,0,100,0,Math.PI * 2)
    ctx.stroke()
    // 绘制地球
    let time = new Date();
    ctx.rotate(2 * Math.PI / 60 * time.getSeconds() + 2 * Math.PI / 60000 * time.getMilliseconds())
    ctx.translate(-100, 0);
    ctx.beginPath()
    // 裁剪一下地球
    ctx.arc(0,0,14,0,Math.PI * 2);
    ctx.save()
    ctx.clip()
    ctx.drawImage(earth, -15, -15,30,30)
    ctx.restore()
    // 绘制月球轨道
    ctx.beginPath();
    ctx.strokeStyle = "rgba(255,255,255,.3)";
    ctx.arc(0, 0, 40, 0, 2 * Math.PI);
    ctx.stroke();
    //绘制月球
    ctx.rotate(2 * Math.PI / 6 * time.getSeconds() + 2 * Math.PI / 6000 * time.getMilliseconds());
    ctx.translate(40, 0);
    ctx.drawImage(moon, -3.5, -3.5);
    ctx.restore()
  }
  requestAnimationFrame(draw)
};
draw()



</script>
</body>
</html>

将所有的案例画在一张canvas画布上面。

效果:

 其它:

isPointInPath:判断当前点是否在 绘制区域内

ctx.rect(20,20,150,100);
if (ctx.isPointInPath(100,100))
{
    ctx.stroke();
};
measureText: 检查文字宽度
ctx.measureText('达大厦')

-

原文地址:https://www.cnblogs.com/fqh123/p/15450537.html