zoukankan      html  css  js  c++  java
  • 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('达大厦')

    -

  • 相关阅读:
    sqloraclesharePool 天高地厚
    aspx工作原理 天高地厚
    【转载】VB ActiveX插件开发打包部署一条龙服务 天高地厚
    【转载】为高负载网络优化Nginx和Node.js 天高地厚
    几个重要的基本概念 天高地厚
    Delphi中取得汉字的首字母
    C#中将字符串转换为MD5
    使用RDLC报表(一)
    在Delphi中的TreeView中保存多个数据
    C#中将图片文件存至数组
  • 原文地址:https://www.cnblogs.com/fqh123/p/15450537.html
Copyright © 2011-2022 走看看