Canvas学习笔记(一)-概述、直线图形和线条操作、面向对象的方式封装折线图、绘制正多边形

2021.1.29 Canvas(一)

Canvas学习笔记(一)

第一章 Canvas概述

什么是Canvas?

Canvas是HTML5新增的一个元素。Canvas又称为画布。
HTML5 <canvas> 元素用于图形的绘制,但只是图形容器,必须通过脚本 (通常是JavaScript)来完成。

HTML5 Canvas简单来说,就是一门使用JavaScript来操作Canvas元素的技术。使用Canvas元素来绘制图形,需要以下三步:

  1. 获取Canvas对象
  2. 获取上下文环境context
  3. 开始绘制图形

举例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        canvas {
            border: 1px solid black;
            /* 不建议 在样式设置尺寸 而在元素本身设置 */
            /* 如果在这里设置宽、高,相当于把原始300*150的画布图片拉大了 */
        }
    </style>
</head>

<body>
    <!-- 1.准备画布 -->
    <!-- 1.1 画布是白色的,而且默认300*150 -->
    <!-- 1.2 设置画布大小 -->
    <canvas width="600" height="400"></canvas>
    <!-- 2.准备绘制工具 -->
    <scrip>
        // 1.获取Canvas对象
        var myCanvas = document.querySelector('canvas');
        // 2.获取上下文环境context 既获取绘制工具箱
        var ctx = myCanvas.getContext('2d');
        // 3.开始绘制图形
        //3.1 移动画笔
        ctx.moveTo(100, 100);
        //3.2 绘制直线(轨迹/绘制路径),还看不见
        ctx.lineTo(200, 100);
        // 3.3 描边
        ctx.stroke();
    </scrip>
</body>

</html>

分析
在Canvas中,我们首先使用document.getElementById()方法来获取canvas对象(这是一个DOM对象),然后使用canvas对象的getContext(‘2d’)方法获取上下文环境对象context,最后再使用context对象的属性和方法来绘制各种图形。下文的代码将只记录最后用context对象的属性和方法绘制图形部分。

Note:以后学习的所有的图形的绘制,我们使用的都是context对象(上下文环境对象)的属性和方法。

第二章 直线图形和线条操作

Canvas坐标系

Canvas使用的坐标系是W3C坐标系:y轴正方向向下。

直线的绘制

一条直线

语法

ctx.moveTo(x1,y1);//画笔移到起点坐标
ctx.lineTo(x2,y2);//画线至终点坐标
ctx.stroke();//描线,否则无显示

关于线条存在的问题

  1. 默认的宽度是1px,但实际看上去是2px
  2. 默认的颜色是黑色,但实际看上去是灰色

产生原因
对齐的点是线的中心位置,会把线分成两个0.5px,显示的时候会不饱和增加宽度、稀释颜色。
解决方案:前后移动0.5px。

ctx.moveTo(100, 100.5);
ctx.lineTo(300, 100.5);
ctx.stroke();
两条平行线

语法

// 画平行线
ctx.moveTo(100, 100);
ctx.lineTo(300, 100);
ctx.moveTo(100, 200);
ctx.lineTo(300, 200);
ctx.stroke();
三条不同颜色不同宽度不同样式的平行折线
  • ctx.beginPath(); //用于解决样式覆盖问题
  • ctx.lineWidth = 10; //设置线条的宽度 ,默认单位是px,不用加引号,直接写数字
  • ctx.strokeStyle() = ‘颜色名’; //设置描边时的颜色
  • ctx.lineCap = ‘butt’; //设置线条帽子,有butt、square、round
  • ctx.lineJoin = ‘miter’; //设置线条拐点样式,有miter尖的,bevel削平的和round
//开启新路径
ctx.beginPath(); //开启新路径可以解决样式覆盖问题
//蓝色 10px
ctx.moveTo(100, 100);
ctx.lineTo(300, 100);
ctx.strokeStyle = 'blue'; //设置描边时的颜色
ctx.lineWidth = 10; //设置线的宽度,单位默认px
ctx.lineCap = 'butt'; //线条帽子默认样式 butt 没帽子
ctx.lineJoin = 'miter'; //线条拐点样式 miter 默认 尖的
ctx.stroke();

ctx.beginPath(); //开启新路径
//红色 20px
ctx.moveTo(100, 200);
ctx.lineTo(300, 200);
ctx.strokeStyle = 'red'; //设置描边时的颜色
ctx.lineWidth = 20; //设置线的宽度,单位默认px
ctx.lineCap = 'square'; //线条帽子 square 方形帽子,长度变长了
ctx.lineJoin = 'bevel'; //拐点样式 削平的
ctx.stroke();

ctx.beginPath(); //开启新路径
//绿色 30px
ctx.moveTo(100, 300);
ctx.lineTo(300, 300);
ctx.strokeStyle = 'green'; //设置描边时的颜色
ctx.lineWidth = 30; //设置线的宽度,单位默认px
ctx.lineCap = 'round'; //线条帽子 round 圆形帽子
ctx.lineJoin = 'round'; //拐点样式 圆的
ctx.stroke();
        
绘制虚线
  • ctx.setLineDash([]); //设置虚线属性
  • ctx.getLineDash(); //获得虚线排列方式
  • ctx.lineDashOffset=20; //设置虚线偏移量
// 画虚线
ctx.moveTo(100, 100.5);
ctx.lineTo(300, 100.5);
ctx.setLineDash([5, 10, 15]); //这个数组参数是用来描述虚线的排列方式的
//获取虚线排列方式
console.log(ctx.getLineDash()); //[5, 10, 15, 5, 10, 15]因为实虚交替
//如果是正的值 往后偏移(横左竖下)
//如果是负的值 往前偏移(横右竖上)
ctx.lineDashOffset = 20;
ctx.stroke();
绘制一个填充的三角形

绘制三角形的本质:绘制三条直线首尾相连。

// 1.绘制三角形
ctx.moveTo(100, 100);
ctx.lineTo(200, 100);
ctx.lineTo(200, 200);
//起始点和lineTo的结束点无法完全闭合 缺角
//使用canvas的自动闭合
//ctx.lineTo(100, 100);
ctx.closePath(); //关闭路径 与beginPath()没有一点关系。
ctx.lineWidth = 10;
// 2.描边
//ctx.stroke();
// 3.填充
ctx.fill();
绘制一个中间镂空的正方形

非零填充规则:看一块区域是否填充

  1. 从这个区域拉一条直线
  2. 看和这条直线相交的轨迹
  3. 如果顺时针轨迹 +1
  4. 如果逆时针轨迹 -1
  5. 所有轨迹的值计算出来
  6. 如果计算出来的结果非零,那么填充
  7. 如果是0,那么不填充
// 1.绘制两个正方形,一大200一小100,套在一起
ctx.moveTo(100, 100);
ctx.lineTo(300, 100);
ctx.lineTo(300, 300);
ctx.lineTo(100, 300);
ctx.closePath();

ctx.moveTo(150, 150);
ctx.lineTo(150, 250);
ctx.lineTo(250, 250);
ctx.lineTo(250, 150);//注意这两个正方形绘制时画笔的方向一顺一逆
ctx.closePath();

//ctx.stroke();
ctx.fillStyle = 'red';
ctx.fill();
绘制一个从黑到白的渐变矩形

思路:面由线构成,线由点构成

// 绘制一个矩形
/* ctx.moveTo(100, 100);
ctx.lineTo(355, 100);
ctx.lineWidth = 30; 
//颜色的填充:从黑到白的渐变颜色
ctx.strokeStyle='#fff';*/

// 线是由点构成的
ctx.lineWidth = 30;
for (let i = 0; i < 255; i++) {
    ctx.beginPath();
    ctx.moveTo(100 + i, 100);
    ctx.lineTo(101 + i, 100);
    ctx.strokeStyle = 'rgb(' + i + ',' + i + ',' + i + ')';
    ctx.stroke();
}
采用面向对象的方式绘制折线图
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas width="600" height="400"></canvas>
    <script>
        //采用面向对象的方法利用canvas绘制折线图
        //1.要有对象,先有构造函数
        var LineChart = function(ctx) { //构造函数首字母要大写
                // 获取上下文(绘图工具)
                this.ctx = ctx || document.querySelector('canvas').getContext('2d');
                // 获取画布的大小
                this.canvasWidth = this.ctx.canvas.width;
                this.canvasHeight = this.ctx.canvas.height;
                // 网格的大小
                this.gridSize = 10;
                // 坐标系的间距
                this.space = 20;
                // 坐标原点
                this.x0 = this.space;
                this.y0 = this.canvasHeight - this.space;
                // 箭头的大小
                this.arrowSize = 10;
                // 绘制点的大小
                this.dottedSize = 6;
                // 点的坐标 和数据有关系 数据可视化

            }
            //2.定义对象的行为方法(使用原型)
        LineChart.prototype.init = function(data) {
            this.drawGrid();
            this.drawAxis();
            this.drawDotted(data);
        };
        //绘制网格的行为
        LineChart.prototype.drawGrid = function() {
            //x方向的线
            var xLineTotal = Math.floor(this.canvasHeight / this.gridSize);
            for (var i = 0; i < xLineTotal; i++) {
                this.ctx.beginPath();
                this.ctx.moveTo(0, i * this.gridSize - 0.5);
                this.ctx.lineTo(this.canvasWidth, i * this.gridSize - 0.5);
                this.ctx.strokeStyle = '#ddd';
                this.ctx.stroke();
            }
            //y方向的线
            var yLineTotal = Math.floor(this.canvasWidth / this.gridSize);
            for (var i = 0; i < yLineTotal; i++) {
                this.ctx.beginPath();
                this.ctx.moveTo(i * this.gridSize - 0.5, 0);
                this.ctx.lineTo(i * this.gridSize - 0.5, this.canvasHeight);
                this.ctx.strokeStyle = '#ddd';
                this.ctx.stroke();
            }
        };
        //绘制坐标系的行为
        LineChart.prototype.drawAxis = function() {
            //绘制x轴
            this.ctx.beginPath();
            this.ctx.moveTo(this.x0, this.y0);
            this.ctx.lineTo(this.canvasWidth - this.space, this.y0);
            this.ctx.lineTo(this.canvasWidth - this.space - this.arrowSize, this.y0 + this.arrowSize / 2);
            this.ctx.lineTo(this.canvasWidth - this.space - this.arrowSize, this.y0 - this.arrowSize / 2);
            this.ctx.lineTo(this.canvasWidth - this.space, this.y0)
            this.ctx.fill();
            this.ctx.strokeStyle = '#000';
            this.ctx.stroke();
            //绘制y轴
            this.ctx.beginPath();
            this.ctx.moveTo(this.x0, this.y0);
            this.ctx.lineTo(this.space, this.space);
            this.ctx.lineTo(this.space + this.arrowSize / 2, this.space + this.arrowSize);
            this.ctx.lineTo(this.space - this.arrowSize / 2, this.space + this.arrowSize);
            this.ctx.lineTo(this.space, this.space);
            this.ctx.fill();
            this.ctx.strokeStyle = '#000';
            this.ctx.stroke();
        };
        //绘制点的行为
        LineChart.prototype.drawDotted = function(data) {
            //1.数据的坐标 需要转换成 canvas坐标
            var that = this; //细节(理解一下回调函数和this指向问题)
            var prevCanvasX = 0;
            var prevCanvasY = 0;
            data.forEach(function(item, i) { //i是数据数组的索引号,而item是数组里的每个对象
                //canvasX = 原点的坐标 + 数据的坐标
                var canvasX = that.x0 + item.x;
                //canvasY = 原点的坐标 - 数据的坐标
                var canvasY = that.y0 - item.y;
                //2.再进行点的绘制
                that.ctx.beginPath();
                that.ctx.moveTo(canvasX - that.dottedSize / 2, canvasY - that.dottedSize / 2);
                that.ctx.lineTo(canvasX + that.dottedSize / 2, canvasY - that.dottedSize / 2);
                that.ctx.lineTo(canvasX + that.dottedSize / 2, canvasY + that.dottedSize / 2);
                that.ctx.lineTo(canvasX - that.dottedSize / 2, canvasY + that.dottedSize / 2);
                that.ctx.closePath();
                that.ctx.fill();
                //3.把线连起来
                //当是第一个点的时候,起点是 x0 y0;
                //当不是第一个点的时候,起点是 上一个点;
                if (i == 0) {
                    that.ctx.beginPath();
                    that.ctx.moveTo(that.x0, that.y0);
                    that.ctx.lineTo(canvasX, canvasY);
                    that.ctx.stroke();
                } else {
                    //上一个的
                    that.ctx.beginPath();
                    that.ctx.moveTo(prevCanvasX, prevCanvasY);
                    that.ctx.lineTo(canvasX, canvasY);
                    that.ctx.stroke();
                }
                //记录当前的坐标,因为下一次要用
                prevCanvasX = canvasX;
                prevCanvasY = canvasY;
            })
        };
        //3.初始化
        var data = [{
            x: 100,
            y: 120
        }, {
            x: 200,
            y: 160,
        }, {
            x: 300,
            y: 240
        }, {
            x: 400,
            y: 320
        }, {
            x: 500,
            y: 80
        }];
        var lineChart = new LineChart();
        lineChart.init(data);
    </script>
</body>

图形的绘制

矩形
  • rect(x,y,w,h) //没有独立路径
  • strokeRect(x,y,w,h) //有独立路径,不影响别的绘制
  • fillRect(x,y,w,h) //有独立路径,不影响别的绘制
  • clearRect(x,y,w,h) //擦除矩形区域
// 绘制矩形的轨迹(不填充或描边就看不见)且不是独立路径
ctx.rect(100, 100, 200, 100);
// 填充或描边
ctx.fillStyle = 'green';
ctx.strokeStyle = 'red'
ctx.stroke();
ctx.fill(); 

// 绘制矩形,并且有自己的独立路径,相当于开头自带beginPath()
ctx.strokeRect(100, 100, 200, 100);
ctx.fillRect(300, 100, 200, 100);

//清除矩形的内容,擦除矩形部分区域
ctx.clearRect(200, 110, 200, 80);
用渐变方案绘制一个渐变的矩形
//fillStyle 'pink' '#000' 'rgb()' 'rgba()'
//也可以使用一个渐变的方案来填充矩形
//canvas中创建一个渐变方案
//渐变是有长度的(x0,y0,x1,y1)x0,y0是起始点,x1y1是结束点
var linearGradient = ctx.createLinearGradient(100, 100, 500, 100);
linearGradient.addColorStop(0, 'pink'); //0是指在百分之零的位置
linearGradient.addColorStop(0.5, 'red'); //0.5是指在百分之五十的位置
linearGradient.addColorStop(1, 'blue'); //1是指在百分之百的位置
//ctx.fillStyle = 'pink';以前是放颜色现在是放渐变方案
ctx.fillStyle = linearGradient;
ctx.fillRect(100, 100, 400, 100);

//pink----->blue
//回想线性渐变------>要素:方向 起始颜色 结束颜色
//通过两个点的坐标可以控制 渐变方向
绘制正多边形

1.封装成函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas width="600" height="400"></canvas>
    <script>
        var myCanvas = document.querySelector('canvas');
        var ctx = myCanvas.getContext('2d');

        function creatPolygon(ctx, n, dx, dy, size) {
            ctx.beginPath();
            var degree = (2 * Math.PI) / n;
            for (var i = 0; i < n; i++) {
                var x = Math.cos(i * degree);
                var y = Math.sin(i * degree);
                //ctx.moveTo(0, 0);
                ctx.lineTo(x * size + dx, y * size + dy);

            }
            ctx.closePath();

        }
        creatPolygon(ctx, 36, 100, 75, 50);
        ctx.fillStyle = 'hotpink';
        ctx.fill();
    </script>
</body>

</html>

2.封装成对象

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>

<body>
    <canvas width="600" height="400"></canvas>
    <script>
        //采用面向对象的方法利用canvas绘制正多边形
        //1.要有对象,先有构造函数
        var CreatePolygon = function(n, dx, dy, size, color, ctx) {
                // 获取上下文(绘图工具)
                this.ctx = ctx || document.querySelector('canvas').getContext('2d');
                // 获取多边形边数
                this.n = n;
                // 获取多边形中心位置
                this.dx = dx;
                this.dy = dy;
                // 获取多边形顶点距离多边形中心长度大小
                this.size = size;
                // 获取多边形填充的颜色
                this.color = color || 'black';
            }
        //2.设置对象的行为,绘制一个正多边形
        CreatePolygon.prototype.fill = function() {
            this.ctx.beginPath();
            var degree = (2 * Math.PI) / this.n;
            for (var i = 0; i < this.n; i++) {
                var x = Math.cos(i * degree);
                var y = Math.sin(i * degree);
                //ctx.moveTo(0, 0);
                this.ctx.lineTo(x * this.size + this.dx, y * this.size + this.dy);
            }
            this.ctx.closePath();
            this.ctx.fillStyle = this.color;
            this.ctx.fill();
        };
        CreatePolygon.prototype.stroke = function() {
            this.ctx.beginPath();
            var degree = (2 * Math.PI) / this.n;
            for (var i = 0; i < this.n; i++) {
                var x = Math.cos(i * degree);
                var y = Math.sin(i * degree);
                //ctx.moveTo(0, 0);
                this.ctx.lineTo(x * this.size + this.dx, y * this.size + this.dy);
            }
            this.ctx.closePath();
            this.ctx.strokeStyle = this.color;
            this.ctx.stroke();
        };

        //3.初始化
        var createPolygon = new CreatePolygon(6, 200, 200, 70, 'yellow');
        createPolygon.stroke();
        createPolygon.fill();
    </script>
</body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值