zoukankan      html  css  js  c++  java
  • canvas第一天

         第一次接触canvas,<canvas></canvas>是html5出现的新标签,IE9开始支持,像所有的dom对象一样它有自己本身的属性、方法和事件,其中就有绘图的方法,js能够调用它来进行绘图。使用的领域涉及到小游戏的开发以及数据的可视化。

     一、两个概念:

        1、 绘图环境的含义:

             绘制图形所需的东西,就叫绘图环境。

        2、 路径的含义:

             路径是一个图形的轮廓,是对将来要绘制图形的一个规划。如果要让路径最终生效需要描边。

     二、使用canvas绘制图形

             canvas要展示的绘制效果是通过js来绘制的。

          1、准备工作:

           (1)需要获取一个绘图环境:

                通过canvasDOM元素提供的一个方法,getContext。

                var cvs = document.querySelector('canvas');

          (2)获取绘图环境的方法:

                 canvas.getContext( '2d' || 'webgl' )   传入2d代表获取一个2d绘图环境,传入3d代表获取一个3d绘图环境。

                 var ctx = cvs.getContext('2d');

         2、绘制图形

          (1)先移动钢笔到指定的位置

                 ctx.moveTo( 0, 0 );

          (2)画图形的路径( 绘制矩形 )           

                 ctx.lineTo(100, 0);
                 ctx.lineTo(100, 100);
                 ctx.lineTo(0, 100);
                 ctx.lineTo(0, 0);

          (3)描边

                 ctx.stroke();

      三、画布设置

            1、 画布的默认设置:

                 canvas画布默认大小为300*150。

            2、 动态设置画布的大小:

               (1)canvasDOM对象有一个width和height属性,通过修改这两个属性值,就可以动态设置画布的大小。因为canvas绘制的图形是位图(像素图),默认就是基于像素单位的(px),所以不用加单位。

                 例:cvs.width = 500;

                      cvs.height = 500;

               (2)动态设置画布大小会清除画布的内容,绘制图形之后,动态修改画布的大小,绘自动清除画布已经绘图的内容。

               (3)不要设置canvas样式中的宽高,因为会拉伸画布,原理和img设置样式宽高拉伸图片一样。直接设置<canvas width=" " height=" "></canvas>

       四、基于状态

            canvas绘图环境中的很多方法也是基于状态的,即修改了canvas绘图环境中的某些属性值, 相关连的一些方法最终的执行结果可能就会收到改变。

            案例:

    function Person( name, age ) {
                this.name = name;
                this.age = age;
            }
    
            // 这个方法就是基于状态(属性值)的
            Person.prototype.run = function() {
                if( this.age < 5 ) {
                    console.log('爬着跑');
                }else if( this.age >=5 && this.age < 16 ) {
                    console.log('跳着跑');
                }else if( this.age >=16 && this.age < 48 ) {
                    console.log('慢跑');
                }else {
                    console.log('拄着拐杖跑');
                }
            };
    
            var xiaofang = new Person('小芳', 12);
            var fangma = new Person('小芳妈', 37);
            var fangnai = new Person('小芳奶', 60);
    
            xiaofang.run();
            fangma.run();
            fangnai.run();

       五、描边色、填充、填充色及设置线宽

             1、 设置描边色

                (1) ctx.strokeStyle = css支持的所有颜色表示方式,这里都支持。

                     当修改了这个描边色之后,一些和描边相关的方法,再次调用时都会受到影响。

                (2)设置 描边色后要调动stroke()方法,新的图形才会显示。

                (3)多次绘制图形描边会把前面的覆盖。

                (4)解决上面出现的问题:清除路径

                      ctx.beginPath();

             2、填充 填充色

               (1)填充:ctx.fill();

               (2)设置填充色:ctx.fillStyle=css

            3、设置线宽

                (1)ctx.lineWidth=number;  注意:不用加"px"

                (2)设置线宽后,顶端会出现锯齿,防止锯齿出现:闭合路径。

                        绘制完路径后,调用closePath()方法,有了这个方法后,最后一条路径可以不用绘制了。

        六、 非零环绕原则

             1、作用:

                  用来判断路径围起来的图形,是在路径内,还是路径外。

             2、原理:

               (1) 在路径包含的区域内随便找一点,向外发送一条线,让这条线贯穿所有围绕该点的路径即可

               (2)开始一个计数器,初始值为0

               (3)开始计数,遇到顺时针围绕点的路径,数+1,遇到逆时针围绕点的路径,数-1

               (4)最终看看结果,如果不是0,那么认为这个块区域在路径包含之内

        七、 清除画布

              ctx.clearRect(起点x轴坐标,起点y轴坐标,清除区域的宽,清除区域的高);

              清除整个画布: ctx.clearRect(0 , 0 , cvs.width , cvs.height);

        八、小属性及虚线绘制介绍

               1、 线帽样式:

                     ctx.lineCap = 'butt' || 'round' || 'square'     默认值为butt

                     round用来设置圆头(圆的半径是线宽的一半),square是两段个加长线宽的一半。

               2、 焦点样式:

                    ctx.lineJoin = 'miter' || 'round' || 'bevel'     默认值为miter

                    设置箭头长度,该属性只在lineJoin为miter的时候有效:ctx.miterLimit

               3、 虚线

                 (1)设置虚线样式:

                        ctx.setLineDash([  ]);  注意:数组的长度是任意的,现实后空;可以传入一个参数,此时实空的长度一样。

                 (2)获取虚线样式:

                       ctx.getLineDash();

        九、 画弧路径:

                   ctx.arc( 圆心x轴坐标,圆心y轴坐标,半径,弧的起始位置,弧的结束位置,是否逆时针画(可选) )     默认是顺时针画弧。

                   案例:

    <canvas style="border: 1px solid red" width="500" height="500"></canvas>
        <script>
            var cvs = document.querySelector('canvas');
            var ctx = cvs.getContext('2d');
    
            // 角度转换为弧度
            function angleToRadian( angle ) {
                return Math.PI / 180 * angle;
            }
    
            // 顺时针从0度到90度画弧
            ctx.arc( 100, 100, 50, angleToRadian(0), angleToRadian(90) );
            ctx.stroke();
    
            // 逆时针从0度到90度画弧
            ctx.beginPath();
            ctx.arc( 300, 100, 50, angleToRadian(0), angleToRadian(90), true );
            ctx.stroke();

         十、 封装

                     1、 面向对象封装等腰三角形           

            // 绘制等腰三角形的方法
            function triangle( x, y, width, height, strokeStyle ) {
                /*
                * 实现思路:
                * 1、为了防止重绘之前的路径,先清除一下
                * 2、移动钢笔到图形起点
                * 3、画想要图形的路径
                * 4、设置描边色
                * 5、描边
                * */
                ctx.beginPath();
                ctx.moveTo( x, y );
                ctx.lineTo( x + width / 2, y + height );
                ctx.lineTo( x - width / 2, y + height );
                ctx.lineTo( x, y );
                ctx.strokeStyle = strokeStyle;
                ctx.stroke();
            }
    
            triangle( 100, 100, 100, 50, 'green' );

                   2、 面向对象封装

               

    // 等腰三角形的构造函数
            function Triangle( x, y, width, height, strokeStyle ) {
                this.x = x;
                this.y = y;
                this.width = width;
                this.height = height;
                this.strokeStyle = strokeStyle;
            }
    
            // 根据实例的属性绘制
            Triangle.prototype.draw = function() {
                /*
                 * 实现思路:
                 * 1、为了防止重绘之前的路径,先清除一下
                 * 2、移动钢笔到图形起点
                 * 3、画想要图形的路径
                 * 4、设置描边色
                 * 5、描边
                 * */
                ctx.beginPath();
                ctx.moveTo( this.x, this.y );
                ctx.lineTo( this.x + this.width / 2, this.y + this.height );
                ctx.lineTo( this.x - this.width / 2, this.y + this.height );
                ctx.lineTo( this.x, this.y );
                ctx.strokeStyle = this.strokeStyle;
                ctx.stroke();
            };
    
            var triangle1 = new SanJiaoXing( 100, 100, 100, 50, 'green' );
    
            triangle1.draw();

        十一、 绘制坐标系                  

     /*
            * constructor { LineChart } 折线图构造函数
            * param { ctx: Context } 绘图上下文
            * param { paddingArr: Array } 折线图到画布四边的距离,存储顺序为上右下左
            * param { arrowArr: Array } 折线图中箭头的宽和高
            * */
            function LineChart( ctx, paddingArr, arrowArr ) {
                this.ctx = ctx;
                this.paddingArr = paddingArr;
    
                this.arrowArr = arrowArr;
                this.arrowWidth = this.arrowArr[0];
                this.arrowHeight = this.arrowArr[1];
    
                // 计算上顶点的坐标
                this.vertexTop = {
                    x: this.paddingArr[ 3 ],
                    y: this.paddingArr[ 0 ]
                };
    
                // 计算原点的坐标
                this.origin = {
                    x: this.paddingArr[ 3 ],
                    y: this.ctx.canvas.height - this.paddingArr[ 2 ]
                };
    
                // 计算右顶点的坐标
                this.vertexRight = {
                    x: this.ctx.canvas.width - this.paddingArr[ 1 ],
                    y: this.ctx.canvas.height - this.paddingArr[ 2 ]
                };
            }
    
            // 置换原型
            LineChart.prototype = {
    
                constructor: LineChart,
    
                // 绘制坐标轴中的两条线
                drawLine: function() {
                    this.ctx.beginPath();
                    this.ctx.moveTo( this.vertexTop.x, this.vertexTop.y );
                    this.ctx.lineTo( this.origin.x, this.origin.y );
                    this.ctx.lineTo( this.vertexRight.x, this.vertexRight.y );
                    this.ctx.stroke();
                },
    
                // 绘制坐标轴中的两个箭头
                drawArrow: function() {
    
                    // 先绘制上面箭头
                    this.ctx.beginPath();
                    this.ctx.moveTo( this.vertexTop.x, this.vertexTop.y );
                    this.ctx.lineTo( this.vertexTop.x - this.arrowWidth / 2, this.vertexTop.y + this.arrowHeight );
                    this.ctx.lineTo( this.vertexTop.x, this.vertexTop.y + this.arrowHeight / 2 );
                    this.ctx.lineTo( this.vertexTop.x + this.arrowWidth / 2, this.vertexTop.y + this.arrowHeight );
                    this.ctx.closePath();
                    this.ctx.stroke();
    
                    // 再绘制右面箭头
                    this.ctx.beginPath();
                    this.ctx.moveTo( this.vertexRight.x, this.vertexRight.y );
                    this.ctx.lineTo( this.vertexRight.x - this.arrowHeight, this.vertexRight.y - this.arrowWidth / 2 );
                    this.ctx.lineTo( this.vertexRight.x - this.arrowHeight / 2, this.vertexRight.y );
                    this.ctx.lineTo( this.vertexRight.x - this.arrowHeight, this.vertexRight.y + this.arrowWidth / 2 );
                    this.ctx.closePath();
                    this.ctx.stroke();
                }
            };
    
            var lineChart = new LineChart( ctx, [ 20, 20, 20, 20 ], [ 10, 20 ] );
            lineChart.drawLine();
            lineChart.drawArrow();

        十二、 绘制折线图            

    /*
            * constructor { LineChart } 折线图构造函数
            * param { ctx: Context } 绘图上下文
            * param { paddingArr: Array } 折线图到画布四边的距离,存储顺序为上右下左
            * param { arrowArr: Array } 折线图中箭头的宽和高
            * param { data: Array } 存储了折线图中所需的数据
            * */
            function LineChart( ctx, paddingArr, arrowArr, data ) {
                this.ctx = ctx;
                this.paddingArr = paddingArr;
    
                this.arrowArr = arrowArr;
                this.arrowWidth = this.arrowArr[0];
                this.arrowHeight = this.arrowArr[1];
    
                this.data = data;
    
                // 计算上顶点的坐标
                this.vertexTop = {
                    x: this.paddingArr[ 3 ],
                    y: this.paddingArr[ 0 ]
                };
    
                // 计算原点的坐标
                this.origin = {
                    x: this.paddingArr[ 3 ],
                    y: this.ctx.canvas.height - this.paddingArr[ 2 ]
                };
    
                // 计算右顶点的坐标
                this.vertexRight = {
                    x: this.ctx.canvas.width - this.paddingArr[ 1 ],
                    y: this.ctx.canvas.height - this.paddingArr[ 2 ]
                };
    
                // 根据数据得到对应的坐标
                this.processData();
            }
    
            // 置换原型
            LineChart.prototype = {
    
                constructor: LineChart,
    
                // 绘制折线图
                draw: function() {
                    this.drawCoordinate();
                    this.drawArrow();
                    this.drawPoint();
                    this.drawLine();
                },
    
                // 绘制坐标轴中的两条线
                drawCoordinate: function() {
                    this.ctx.beginPath();
                    this.ctx.moveTo( this.vertexTop.x, this.vertexTop.y );
                    this.ctx.lineTo( this.origin.x, this.origin.y );
                    this.ctx.lineTo( this.vertexRight.x, this.vertexRight.y );
                    this.ctx.stroke();
                },
    
                // 绘制坐标轴中的两个箭头
                drawArrow: function() {
    
                    // 先绘制上面箭头
                    this.ctx.beginPath();
                    this.ctx.moveTo( this.vertexTop.x, this.vertexTop.y );
                    this.ctx.lineTo( this.vertexTop.x - this.arrowWidth / 2, this.vertexTop.y + this.arrowHeight );
                    this.ctx.lineTo( this.vertexTop.x, this.vertexTop.y + this.arrowHeight / 2 );
                    this.ctx.lineTo( this.vertexTop.x + this.arrowWidth / 2, this.vertexTop.y + this.arrowHeight );
                    this.ctx.closePath();
                    this.ctx.stroke();
    
                    // 再绘制右面箭头
                    this.ctx.beginPath();
                    this.ctx.moveTo( this.vertexRight.x, this.vertexRight.y );
                    this.ctx.lineTo( this.vertexRight.x - this.arrowHeight, this.vertexRight.y - this.arrowWidth / 2 );
                    this.ctx.lineTo( this.vertexRight.x - this.arrowHeight / 2, this.vertexRight.y );
                    this.ctx.lineTo( this.vertexRight.x - this.arrowHeight, this.vertexRight.y + this.arrowWidth / 2 );
                    this.ctx.closePath();
                    this.ctx.stroke();
                },
    
                // 把传入进来的数据转化为对应画布的坐标
                processData: function() {
    
                    // 用来存储转换后的坐标数据
                    this.processArr = [];
    
                    // 遍历所有的数据,依次转换为对应的坐标
                    for( var i = 0, len = this.data.length; i < len; i+=2 ) {
                        /*
                         * 数据转化为相当于画布的坐标:
                         * canvasX = this.origin.x + x
                         * canvasY = this.origin.y - y
                         * */
                        this.processArr.push( this.origin.x + this.data[ i ] );
                        this.processArr.push( this.origin.y - this.data[ i + 1 ] );
                    }
                },
    
                // 根据数据绘制相应的点
                drawPoint: function() {
                    var r = 4;
    
                    // 遍历所有的坐标,依次绘制点
                    for( var i = 0, len = this.processArr.length; i < len; i+=2 ) {
                        this.ctx.beginPath();
                        this.ctx.arc( this.processArr[ i ], this.processArr[ i + 1 ], r, 0, Math.PI*2 );
                        this.ctx.fill();
                    }
                },
    
                // 根据数据绘制折线
                drawLine: function() {
                    this.ctx.beginPath();
                    for( var i = 0, len = this.processArr.length; i < len; i+=2 ) {
                        this.ctx.lineTo( this.processArr[ i ], this.processArr[ i + 1 ] );
                    }
                    this.ctx.stroke();
                }
            };
    
            var lineChart = new LineChart( ctx, [ 20, 20, 20, 20 ], [ 10, 20 ], [ 10, 10, 30, 20, 50, 50, 60, 80, 100, 100 ] );
            lineChart.draw();

          总结:

                         

                

  • 相关阅读:
    [置顶] 利用CXF发布webService的小demo
    【转】VirtualBox下Ubuntu共享文件
    【转】你应该知道的十个VirtualBox技巧与高级特性
    【转】ubuntu 12.04英文版设置成中文版
    【转】Ubuntu安装基础教程
    【转】Ubuntu更改语言环境设置
    【转】【教程】实现Virtualbox中的XP虚拟机和主机Win7之间的共享文件夹
    【转】VIRTUALBOX导入已有.VDI文件步骤
    winhex的使用
    【转】VC MFC 如何删除文件,目录,文件夹
  • 原文地址:https://www.cnblogs.com/fatimah1214/p/6075598.html
Copyright © 2011-2022 走看看