Canvas 2

作者: 向上而活 | 来源:发表于2019-07-05 18:25 被阅读0次

    1.使用Canvas进行绘图——绘制路径
    路径:Path,类似于Photoshop中的钢笔工具,可以绘制直线、各种曲线;但路径本身是不可见的,有三种用途:
    (1)创建选区(clip),对画布内容进行裁剪
    (2)进行描边(stroke),绘制任意形状的折线
    (3)进行填充(fill),填充出任意形状的图形
    相关函数:
    ctx.beginPath() 开始一条新的路径
    ctx.arc() 绘制一条圆形/椭圆/拱形路径
    ctx.moveTo(x,y) 移动到指定点
    ctx.lineTo(x,y) 从上一点到指定点绘制直线
    ctx.busierCurve() 绘制贝塞尔曲线
    ctx.closePath() 闭合路径
    ---------------------------------
    ctx.clip() 基于当前路径进行裁切
    ctx.stroke() 基于当前路径进行描边
    ctx.fill() 基于当前路径进行填充
    例子

    <h2>绘制路径——直线</h2>
      <canvas id="c3" width="500" height="400">
      </canvas>
      <script>
        var ctx = c3.getContext('2d');
    
        //开始路径
        ctx.beginPath();
    
        //绘制路径——X轴
        ctx.moveTo(50, 350);
        ctx.lineTo(450,350);
        ctx.lineTo(450-10,350+10);  //小箭头
        ctx.moveTo(450,350);
        ctx.lineTo(450-10,350-10);  //小箭头
        //ctx.strokeStyle = '#f00';
        //ctx.stroke();
    
    
        //绘制路径——Y轴
        //ctx.beginPath();
        ctx.moveTo(50, 350);
        ctx.lineTo(50,50);
        ctx.lineTo(50-10,50+10);  //小箭头
        ctx.moveTo(50,50);
        ctx.lineTo(50+10,50+10);  //小箭头
    
        //描边路径
        ctx.strokeStyle = '#00f';
        ctx.stroke();
    
      </script>
    
    <body>
      <h2>绘制路径——绘制圆环进度条</h2>
      <canvas id="c4" width="500" height="400">
      </canvas>
      <script>
        var ctx = c4.getContext('2d');
    
        //进度条的底色
        ctx.lineWidth = 20;
        ctx.strokeStyle = '#fff';
        ctx.beginPath();
        ctx.arc(250,200,100, 0, 2*Math.PI);
        ctx.stroke();
    //进度条颜色
        ctx.strokeStyle = '#0a0';
        var degree = 0;  //角度值
        var timer = setInterval(function(){
          degree+=3;
    
          ctx.beginPath();
          //ctx.arc(250,200,100,0,degree*Math.PI/180);
          ctx.arc(250,200,100,0-Math.PI/2,degree*Math.PI/180-Math.PI/2);
          ctx.stroke();
        },100);
      </script>
    </body>
    
    <body>
      <h2>绘制路径——圆拱形</h2>
      <canvas id="c6" width="500" height="400">
      </canvas>
      <script>
        var ctx = c6.getContext('2d');
    
        /**闭嘴**/
        function closeMouth(){
          ctx.beginPath();
          ctx.arc(250,200,100,0,2*Math.PI); //外环
          ctx.lineTo(250,200);  //横线
          ctx.stroke();
    
          ctx.beginPath();
          ctx.arc(250,150,25,0,2*Math.PI)//眼球
          ctx.fillStyle = '#abe';
          ctx.fill();
    
          ctx.beginPath();
          ctx.arc(250+18,142,5,0,2*Math.PI)//眼神光大
          ctx.fillStyle = '#fff';
          ctx.fill();
    
          ctx.beginPath();
          ctx.arc(250+12,133,3,0,2*Math.PI)//眼神光小
          ctx.fill();
        }
        //closeMouth();
    
    
        /**张嘴**/
        function openMouth(){
          ctx.beginPath();
          ctx.arc(250,200,100,Math.PI/4,7*Math.PI/4); //外环
          ctx.lineTo(250,200);  //上嘴唇
          ctx.closePath();  //闭合路径得到下嘴唇
          ctx.stroke();
    
          ctx.beginPath();
          ctx.arc(250,150,25,0,2*Math.PI)//眼球
          ctx.fillStyle = '#abe';
          ctx.fill();
    
          ctx.beginPath();
          ctx.arc(250+18,142,5,0,2*Math.PI)//眼神光大
          ctx.fillStyle = '#fff';
          ctx.fill();
    
          ctx.beginPath();
          ctx.arc(250+12,133,3,0,2*Math.PI)//眼神光小
          ctx.fill();
        }
        //openMouth();
    
        //使用定时器定期调用张嘴&闭嘴
        var isOpen = true; //当前是否为张嘴
        setInterval(function(){
            ctx.clearRect(0,0,500,400);
            if(isOpen){
              closeMouth();
              isOpen = false;
            }else {
              openMouth();
              isOpen = true;
            }
        },300)
      </script>
    </body>
    

    2.使用Canvas绘图——绘制图像
    提示:图像的定位点在自己的左上角
    ctx.drawImage( img, x, y ) //原始大小绘制
    ctx.drawImage( img, x, y, w, h ) //使用指定的宽高绘制图像——可能进行图像大小缩放
    注意:绘制图像时,必须等待图片异步加载完成
    var img = new Image();
    img.src = "xx.png"; //向服务器异步请求图片
    img.onload = function(){ //图片加载完成
    ctx.drawImage( img, x, y )
    }

    <body>
      <h2>绘制图像-随机位置与大小</h2>
      <canvas id="c7" width="500" height="500">
      </canvas>
      <script>
        var ctx = c7.getContext('2d');
    
        var img = new Image();
        img.src = 'img/star.png';
        img.onload = function(){
          for(var i=0; i<20; i++){
            var size = rn(20,150);//每个星星的大小都在20 150 之间
            ctx.drawImage(img, rn(0,500-size), rn(0,500-size), size, size)
          }
        }
    
        /**返回指定范围内的随机数**/
        function rn(min, max){
          return Math.random()*(max-min)-min;
          
        }
      </script>
    </body>
    

    图像的旋转问题:
    (1)Canvas中的旋转不是画布旋转!而是“绘图上下文(画笔)”旋转。
    ctx.rotate(deg)
    (2)旋转必须有一个轴点——默认是坐标轴的原点;若想以某个固定的点旋转,就必须平移画布的坐标原点:
    ctx.translate(x, y) //指定新的坐标轴原点

    <body>
      <h2>绘制图像</h2>
      <canvas id="c7" width="500" height="400">
      </canvas>
      <script>
        var ctx = c7.getContext('2d');
    
        var p2 = new Image();
        p2.src = "img/p2.png";
        var degree = 0; //当前旋转的角度值
        p2.onload = function(){
    
          setInterval(function(){
            degree+=5;
    
            /****绘制左上角的飞机****/
            ctx.clearRect(0,0,500,400);
            ctx.rotate(degree*Math.PI/180);
            ctx.drawImage(p2, -p2.width/2, -p2.height/2);
            ctx.rotate(-degree*Math.PI/180);//因为转动的是画笔,所以,画完这个飞机后,为了不影响画下一个飞机,还要把画笔转回来;
    
            /****绘制右上角的飞机****/
            ctx.translate(500, 0);//坐标原点平移到右上角
            ctx.rotate(degree*Math.PI/180);
            ctx.drawImage(p2,-p2.width/2,-p2.height/2);
            ctx.rotate(-degree*Math.PI/180);
            ctx.translate(-500,0);//坐标原点平移回左上角
    
    
            /****绘制左下角的飞机****/
            ctx.translate(0, 400);//坐标原点平移到左下角
            ctx.rotate(degree*Math.PI/180);
            ctx.drawImage(p2,-p2.width/2,-p2.height/2);
            ctx.rotate(-degree*Math.PI/180);
            ctx.translate(0,-400);//坐标原点平移回左上角
    
    
            /****绘制右下角的飞机****/
            ctx.translate(500,400);//坐标原点平移到右下角
            ctx.rotate(degree*Math.PI/180);
            ctx.drawImage(p2,-p2.width/2,-p2.height/2);
            ctx.rotate(-degree*Math.PI/180);
            ctx.translate(-500,-400);//坐标原点平移回左上角
    
          }, 100)
        }
    
      </script>
    </body>
    
    <body>
      <h2>可以随鼠标移动的飞机</h2>
      <canvas id="c7" width="400" height="600">
      </canvas>
      <script>
        var ctx = c7.getContext('2d');
    
        var p2 = new Image();
        p2.src = "img/p2.png";
        p2.onload = function(){
          var x = 200; //飞机的坐标
          var y = 500; //飞机的坐标
    
          setInterval(function(){
            //清除画布内容
            ctx.clearRect(0,0,400,600);
            //绘制飞机
            ctx.drawImage(p2, x-p2.width/2, y-p2.height/2);
          },100);
    
          //为Canvas元素绑定鼠标移动事件监听函数
          c7.onmousemove = function(e){
            x = e.offsetX;  //鼠标相对于画布的编译量
            y = e.offsetY;
          }
        }
    
      </script>
    </body>
    
    <body>
            <h2>使用Canvas模拟验证码图片</h2>
    
            <canvas id="vcode" width="90" height="26"></canvas>
            <span id="change">看不清,换一张</span>
            <script>
                var change = document.getElementById('change');
                change.onclick = function() {
                    doimg()
                };
    
                function doimg() {
                    var ctx = vcode.getContext('2d');
                    var w = vcode.width;
                    var h = vcode.height;
    
                    //填充一个矩形做背景
                    ctx.fillStyle = rc(180, 240);
                    ctx.fillRect(0, 0, w, h);
                    //绘制5个随机字符
                    var pool = 'ABCDEFGHJKLMNPQRSTWXY3456789';
                    ctx.textBaseline = 'bottom';
                    for (var i = 0; i < 5; i++) {
                        var x = 18 * i + 5; //文本的X
                        var y = h; //文本的Y
                        var c = pool[rn(0, pool.length)];
                        ctx.fillStyle = rc(30, 180); //文本颜色
                        ctx.font = rn(10, 30) + 'px Arial'; //文本大小
                        var deg = rn(-45, 45); //文本旋转
                        ctx.translate(x, y);
                        ctx.rotate(deg * Math.PI / 180);
                        ctx.fillText(c, 0, 0);
                        ctx.rotate(-deg * Math.PI / 180); //恢复到原来的角度
                        ctx.translate(-x, -y); //把画笔恢复到原位
                    }
    
                    //绘制5条干扰线
                    for (var i = 0; i < 5; i++) {
                        ctx.beginPath();
                        ctx.moveTo(rn(0, w), rn(0, h));
                        ctx.lineTo(rn(0, w), rn(0, h));
                        ctx.strokeStyle = rc(30, 180);
                        ctx.stroke();
                    }
    
                    //绘制50个杂色点——半径为1的圆
                    for (var i = 0; i < 50; i++) {
                        ctx.beginPath();
                        ctx.arc(rn(0, w), rn(0, h), 1, 0, 2 * Math.PI);
                        ctx.fillStyle = rc(30, 230);
                        ctx.fill();
                    }
                }
                doimg();
                //获取一个指定范围内随机数 random number
                function rn(min, max) {
                    return Math.floor(Math.random() * (max - min) + min);
                }
                //获取一个指定范围内随机颜色 random color
                function rc(min, max) {
                    var r = rn(min, max);
                    var g = rn(min, max);
                    var b = rn(min, max);
                    return `rgb(${r},${g},${b})`;
                }
            </script>
        </body>
    
    <body>
      <h2>使用Canvas+Audio实现一个播放器</h2>
      <audio src="res/bg.mp3"></audio>
      <canvas id="c2" width="400" height="500"></canvas>
      <script>
        var progress = 0;  //全局函数 每个函数都可以改变它 等到下面4个加载函数全部运行完,progress 的值增加到100 说明所有图片加载完成 就开始执行 startDraw()函数
    
        var bg = new Image();
        bg.src = 'img/bg.jpg';
        bg.onload = function(){
          console.log('1背景图片加载完成');
          progress += 20;
          if(progress===100){
            startDraw();
          }
        }
    
        var cover = new Image();
        cover.src = 'img/disc.png';
        cover.onload = function(){
          console.log('2封面图片加载完成');
          progress += 40;
          if(progress===100){
            startDraw();
          }
        }
    
        var play = new Image();
        play.src = 'img/play.png';
        play.onload = function(){
          console.log('3播放按钮图片加载完成');
          progress += 20;
          if(progress===100){
            startDraw();
          }
        }
    
        var pause = new Image();
        pause.src = 'img/pause.png';
        pause.onload = function(){
          console.log('4暂停按钮图片加载完成');
          progress += 20;
          if(progress===100){
            startDraw();  //总进度已到100,开始绘图
          }
        }
    
        function startDraw(){
          console.log('开始绘图')
          var ctx = c2.getContext('2d');
          //绘制背景图
          ctx.drawImage(bg, 0,0, c2.width, c2.height);
          //绘制黑色胶片
          ctx.beginPath();
          ctx.arc(c2.width/2,c2.height/2,100,0,2*Math.PI);
          ctx.fill();
          //绘制胶片封面图片  250-70.7
          var x = c2.width/2 - 100*Math.sin(Math.PI/4);
          var y = c2.height/2 - 100*Math.sin(Math.PI/4);//这两行代码是为了计算 胶片封面图片左上角的坐标(也可以理解为 从哪个点开始绘制)
          var w = 2*100*Math.sin(Math.PI/4);//胶片封面图片宽和高;
          ctx.drawImage(cover,x,y,w,w);
          //绘制播放按钮
          ctx.drawImage(play,x,y+180,w,w);
        }
    
        //为“播放按钮添加事件监听函数”——实际是为Canvas添加
        c2.onmousemove = function(e){
          var x = e.offsetX;
          var y = e.offsetY;
          var cx = 200;   //按钮的圆心
          var cy = 430;
          var r = 70.7;     //按钮的半径
          //计算此点到按钮圆心的距离是否小于半径
          if(Math.sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy))<=70.7){
            c2.style.cursor = 'pointer';
          }else {
            c2.style.cursor = 'default';
          }
        }
        //为“播放按钮添加事件监听函数”——实际是为Canvas添加
        c2.onclick = function(e){
          var x = e.offsetX;
          var y = e.offsetY;
          var cx = 200;   //按钮的圆心
          var cy = 430;
          var r = 70.7;     //按钮的半径
          //计算此点到按钮圆心的距离是否小于半径
          if(Math.sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy))<=70.7){
            console.log('按钮被点击了');
          }
        }
      </script>
    </body>
    

    3.总结:Canvas绘图技术相关属性和方法——重点
    ctx.fillStyle = 颜色/渐变色/样式;
    ctx.strokeStyle =颜色/渐变色/样式;
    ctx.font = "10px sanse-sarif";
    ctx.textBaseline = '';
    ctx.lineWidth = 1;


    (1)绘制矩形
    ctx.fillRect() ctx.strokeRect() ctx.clearRect()
    (2)绘制文本
    ctx.fillText() ctx.strokeText() ctx.measureText()
    (3)绘制路径
    ctx.beginPath()
    ctx.moveTo() ctx.lineTo() ctx.arc() ctx.rect()
    ctx.stroke() ctx.fill() ctx.clip()
    (4)绘制图像
    ctx.drawImage(img,x,y,[w],[h])
    ctx.rotate( deg )
    ctx.translate( x, y )

    4.基于Canvas的图表绘制框架/工具库
    (1)Chart.js —— 免费开源,有九类图表可供使用
    (2)Echart.js —— 免费的,百度提供,中文手册易上手
    (3)FusionCharts.js —— 收费的,功能强大

    5.第三方图表绘制工具——Chart.js的使用
    (1)寻找官网:http://www.chartjs.org
    (2)看官网介绍:
    Simple yet flexible JavaScript charting for developers
    (3)看官网提供的使用文档(API Document)
    http://www.chartjs.org/docs/
    (4)根据官网上的实例编写代码:
    <canvas id="c2" width="600" height="400"></canvas>
    <script src="js/Chart.js"></script>
    <script>
    new Chart(c2, {
    type: 'bar', //图表类型
    data: { }, //图表数据
    options: { } //可选参数
    });
    </script>

    1.补充知识点:
    若Canvas绘图中需要绘制多张图片,必须等待所有图片加载完成才能开始绘制;而每张图片的加载都是异步请求,彼此没有先后顺序,哪一张先加载完成完全无法预测。
    var progress = 0; //全局加载进度
    var img = new Image();
    img.src = 'xx.jpg';
    img.onload = function(){
    progress += 10; //该图片权重
    if(progress===100){
    startDraw();
    }
    }

    2.补充知识点:如何为Canvas中的某个图形/图像添加事件监听
    HTML中,只有标签/元素才能添加事件监听。
    Canvas绘图技术,只有一个标签——Canvas。
    为某个部分中的图形/图像添加事件监听,只能委托给Canvas,获取事件发生的坐标,是否处于目标图像/图形范围内。
    结论:为Canvas的某个图形/图像添加事件监听非常麻烦!

    相关文章

      网友评论

          本文标题:Canvas 2

          本文链接:https://www.haomeiwen.com/subject/armshctx.html