图形系统开发实战课程:基础篇——1.绘制基本图形


在这里插入图片描述

图形开发学院|GraphAnyWhere

第一章:绘制基本图形

本章的内容包括:

  • 绘制矩形
  • 绘制折线和多边形
  • 绘制圆和圆弧
  • 绘制椭圆和椭圆弧

1. 矩形

\quad 矩形是日常生活和工作中最常见到的图形,Canvas提供了非常简单的方式,只需一行代码就能够绘制矩形,其语法如下:

绘制矩形的边框:

ctx.strokeRect(x, y, width, height)

绘制填充的矩形:

ctx.fillRect(x, y, width, height)

\quad 在这两个方法中只需指定矩形的起始坐标(x,y)和矩形的宽和高,就能够绘制矩形。先看一个示例的运行效果图:
在这里插入图片描述

源代码如下:

<!DOCTYPE html>
<html>

<head>
    <title>绘制基本图形</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>

<body style="overflow: hidden; margin:0px;">
    <canvas id="canvas" width="1200" height="800"></canvas>
</body>
<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');

    // 绘制左侧矩形(描边)
    ctx.strokeRect(50, 50, 200, 100);

    // 绘制右侧填充矩形
    ctx.fillRect(350, 50, 200, 100);
</script>

</html>

\quad 这个示例中:

  • let canvas = document.getElementById('canvas')可取得页面中的canvas对象;
  • let ctx = canvas.getContext('2d');可取得Canvas对象的渲染上下文对象
  • ctx.strokeRect(50, 50, 200, 100)ctx.fillRect(350, 50, 200, 100)分别绘制了一个非填充的矩形和一个填充的矩形,其各参数分的含义如下:
    • 第一个参数表示矩形的起点横坐标为(x),左侧矩形的x=50, 右侧矩形的x=350
    • 第二个参数表示矩形的起点纵坐标为(y),两个矩形的y均为50
    • 第三个参数表示矩形的宽度(width),两个矩形的width均为200
    • 第四个参数表示矩形的高度(height),两个矩形的height均为100

\quad 坐标的原点在左上角,水平方向为x轴,垂直方向为y轴,各个坐标在图中的位置如下图所示:
在这里插入图片描述

\quad Canvas还提供了其他的一些api,可以调整矩形效果,例如使用不用颜色绘制矩形,指定矩形的边框大小等等,均是通过Canvas的渲染上下文对象进行赋值,这些api如下所示:

// 改变线宽
ctx.lineWidth = value; 
// 画笔颜色
ctx.strokeStyle = color; 
// 填充颜色
ctx.fillStyle = color;

其运行效果如下图所示:
在这里插入图片描述

源代码如下:

<!-- 略过html部分的内容-->
<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');

    // 绘制左侧矩形
    ctx.lineWidth = 10;
    ctx.strokeRect(100, 300, 200, 100);

    // 绘制右侧矩形
    ctx.lineWidth = 5; 
    ctx.fillStyle = "#0000FF"
    ctx.fillRect(400, 300, 200, 100);
    ctx.strokeStyle = "#FF0000"
    ctx.strokeRect(400, 300, 200, 100);
</script>

\quad 此外,Canvas的渲染上下文还提供了在路径中绘制矩形rect()清空一个矩形区域clearRect(),其参数与strokeRect()fillRect()完全一样,后续文章将会讲解路径的使用方法。清空一个矩形区域,将会实现让清除部分完全透明,通常用于清除Canvas原有内容,以下代码可清除整个Canvas中的内容:

ctx.clearRect(0, 0, canvas.width, canvas.height);

2. 折线和多边形

\quad 线段的应用非常广泛,不仅包含了普通的直线,还包括了折线,虚线等等,先看一个例子:
在这里插入图片描述

\quad 这个例子中我们使用Canvas绘制了四条直线,其中第一条最简单的直线,第二条直线增加了线宽属性,第三条直线增加了颜色属性,第四条直线为虚线,代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“渲染上下文”对象
    let ctx = canvas.getContext('2d');

    // 绘制简单直线
    ctx.beginPath();
    ctx.moveTo(50, 50);
    ctx.lineTo(450, 50);
    ctx.stroke();
    
    // 绘制加粗的直线
    ctx.beginPath();
    ctx.moveTo(50, 110);
    ctx.lineTo(450, 110);
    ctx.lineWidth=5;
    ctx.stroke();
    
    // 绘制蓝色直线
    ctx.beginPath();
    ctx.moveTo(50, 170);
    ctx.lineTo(450, 170);
    ctx.strokeStyle="blue";
    ctx.stroke();
    
    // 绘制虚线
    ctx.beginPath();
    ctx.moveTo(50, 230);
    ctx.lineTo(450, 230);
    ctx.setLineDash([20, 15]);
    ctx.stroke();
</script>

这个示例使用了Canvas的渲染上下文的以下几个方法:

ctx.beginPath()    // 开始路径
ctx.moveTo(x,y)    // 将路径起点移动到起始点(x,y)坐标
ctx.lineTo(x,y)    // 使用直线连接路径至终点(x,y)坐标
ctx.stroke()       // 绘制当前路径

\quad 绘制折线其实是由绘制“路径”这个功能实现的,其过程为:

  1. 开始绘制路径:ctx.beginPath()
  2. 将路径移动到起始点:ctx.moveTo(x, y)
  3. 使用直线连接路径至某个点:ctx.lineTo(x, y),如果需要可以继续使用直线连接路径至某个点
  4. 设置样式:
    指定线宽:ctx.lineWidth=5
    指定边框颜色:ctx.strokeColor=“red”
    指定填充颜色:ctx.fillColor=“#CCCCCC”
    使用虚线模式:ctx.setLineDash([10,10])
  5. 描边或填充
    描边:ctx.stroke()
    填充:ctx.fill();

下图标识了上述这四条直线的坐标值,可以更好的理解绘制直线的过程:

在这里插入图片描述

整个绘制的过程如下:

  • 1、将画笔移动到坐标(50,50),绘制直线至坐标(450,50);
  • 2、将画笔移动到坐标(50,110),绘制直线至坐标(450,110);
  • 3、将画笔移动到坐标(50,170),绘制直线至坐标(450,170);
  • 4、将画笔移动到坐标(50,230),绘制直线至坐标(450,230);
    在绘制过程中,可根据需要改变线宽或颜色等属性。

\quad 上述的几张效果图中均包含了灰色的网格线,这个网格线也是通过循环绘制直线功能来实现的,其代码如下:

/**
 * 绘制网格线
 * @param color 颜色
 * @param stepX x轴网格间距
 * @param stepY y轴网格间距
 */
function drawGrid(color, stepX, stepY) {
    ctx.save();
    ctx.beginPath();

    // 水平线
    for (var i = stepX; i < canvas.width; i += stepX) {
        ctx.moveTo(i, 0);
        ctx.lineTo(i, canvas.height)
    }

	// 垂直线
    for (var i = stepY; i < canvas.height; i += stepY) {
        ctx.moveTo(0, i);
        ctx.lineTo(canvas.width, i);
    }

    // 绘制
    ctx.lineWidth = 0.5;
    ctx.strokeStyle = color;
    ctx.stroke();
    ctx.restore();
}

我们在来看一个绘制折线图的例子:
在这里插入图片描述

实现的逻辑也很简单,其代码如下:

<script>
// 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    
    // 绘制坐标系
    ctx.lineWidth = 6;
    drawLine([[76, 45], [76, 285], [316, 285]]);
    ctx.stroke();
    drawLine([[90, 51], [76, 23], [62, 51], [90, 51]]);
    ctx.fill();
    drawLine([[310, 271], [338, 285], [310, 299], [310, 271]]);
    ctx.fill();
    
    // 绘制数据走向
    drawLine([[105, 256], [192, 169], [222, 227], [309, 140]]);
    ctx.strokeStyle = "blue";
    ctx.stroke();
    drawLine([[105, 215], [192, 110], [222, 157], [309, 52]]);
    ctx.strokeStyle = "red";
    ctx.stroke();

    /**
     * 绘制折线
     */
    function drawLine(pixel) {
        ctx.beginPath();
        ctx.moveTo(pixel[0][0], pixel[0][1]);
        for (let m = 1; m < pixel.length; m += 1) {
            ctx.lineTo(pixel[m][0], pixel[m][1]);
        }
    }
</script>

\quad 接下来我们讲解一下如何绘制虚线,绘制虚线是在设置样式时由ctx.setLineDash([])方法指定的,这个方法接受一个整数数组作为参数,其含义为:“虚线长度 空格长度 虚线长度 空格长度”,画布在绘制虚线时就会按照这个数组的长度信息重复绘制,使用不同的参数可得到不同的选线效果,我们看看以下示例:

在这里插入图片描述

完整的代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    
    // 绘制虚线n
    ctx.lineWidth=2;
    let y = 100;
    drawDashedLine([2, 2]);
    drawDashedLine([10, 10]);
    drawDashedLine([20, 5]);
    drawDashedLine([15, 4, 4, 4]);
    drawDashedLine([20, 4, 4, 4, 4, 4, 4, 4]);
    drawDashedLine([12, 4, 4]);
    
    function drawDashedLine(pattern) {
        ctx.beginPath();
        ctx.setLineDash(pattern);
        ctx.moveTo(500, y);
        ctx.lineTo(800, y);
        ctx.stroke();
        y += 40;
    }
</script>

\quad 多边形的绘制和绘制折线的过程非常相似,其区别是最后一个点需和第一个点的坐标重合,也可使用closePath()实现闭合折线。接下来我们看一个绘制多边形(五角星)的例子:

在这里插入图片描述

其源代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');

    // 建立五角星的绘制路径
    ctx.beginPath();
    ctx.moveTo(100, 20);
    ctx.lineTo(53, 164);
    ctx.lineTo(176, 76);
    ctx.lineTo(24, 76);
    ctx.lineTo(147, 164)
    ctx.closePath();

    // 绘制
    ctx.fillStyle = "red";
    ctx.fill();
</script>

\quad 在这个例子中,可以看到在moveTo()之后,接着lineTo()lineTo()……,就实现了多边形的绘制。
\quad 如果没有执行moveTo(),则表示从当前位置开始绘制,初始位置是坐标原点(0,0)。
\quad 这个例子中还执行了一个closePath()方法,表示从最后一个点至第一个点之间绘制一条直线,闭合了这段折线,首尾进行了相连,实现了多边形的绘制。

在建立路径后,需执行stroke()fill()命令,表示将路径绘制出来。

  • stroke()将会对路径进行描边,
  • fill()将会对路径进行填充。

3. 圆和圆弧

Canvas 2D API 提供了arc()命令,用于绘制圆或圆弧,其语法如下:

ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
参数名说明
x圆弧中心(圆心)的 x 轴坐标
y圆弧中心(圆心)的 y 轴坐标
radius圆弧的半径
startAngle圆弧的起始点,x 轴方向开始计算,单位以弧度表示
endAngle圆弧的终点,单位以弧度表示。
anticlockwise可选的Boolean值(默认值为: false),表示顺时针绘制圆弧,为 true表示逆时针绘制圆弧

\quad 圆的绘制也是通过建立路径开始的,我们通过几个例子,来了解各个参数的含义,首先看看绘制圆的示例,其运行效果如下图所示:
在这里插入图片描述

这个例子中绘制了一个带边框的圆和一个填充圆,其代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // 绘制背景网格线
    drawGrid('lightgray', 10, 10);

    // 绘制一个带边框的圆
    ctx.beginPath();
    ctx.arc(150, 150, 100, 0, 2 * Math.PI);
    ctx.lineWidth = 4;
    ctx.stroke();

    // 绘制一个蓝色填充的圆
    ctx.beginPath();
    ctx.arc(400, 150, 100, 0, 2 * Math.PI);
    ctx.fillStyle = "blue";
    ctx.fill();
</script>

我们挑选出关键的几条语句:

// 绘制一个带边框的圆
ctx.arc(150, 150, 100, 0, 2 * Math.PI);
ctx.stroke();

// 绘制一个蓝色填充的圆
ctx.arc(400, 150, 100, 0, 2 * Math.PI);
ctx.fill();

我们在回顾一下arc()的语法:

ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

\quad 前两个参数为圆心的坐标(x,y),第3个参数为圆的半径,下图显示圆心坐标和半径:
在这里插入图片描述

\quad 第4和第5个参数是圆的起始角度终止角度,上面这个例子中,指定开始角度为0,结束角度为2π,因此绘制的是一个完整的圆,而当开始角度至结束角度不到2π时,绘制的就是一个圆弧。需要特别提醒的是:我们之前在学校学习的时候,用到的角度单位通常是,例如30°/45°/60°/90°/180°/360°等等,而acr()中需使用弧度作为单位,我们知道一周的弧度数是2π(2πr/r),因此可以通过以下代码将角度转为弧度

/**
 * 将弧度转换为度
 * @param {number} angleInRadians 以弧度为单位的角度
 * @return {number} 角度(以度为单位)
 */
function toDegrees(angleInRadians) {
    return (angleInRadians * 180) / Math.PI;
}

/**
 * 将度数转换为弧度
 * @param {number} angleInDegrees 以度为单位的角度
 * @return {number} 角度(弧度)
 */
function toRadians(angleInDegrees) {
    return (angleInDegrees * Math.PI) / 180;
}

\quad 接来下看一下圆弧的例子,运行效果如下图:
在这里插入图片描述

\quad 在这里例子中绘制了3段圆弧,绿色的半圆,红色的顺时针135°圆弧,蓝色的逆时针135°圆弧,下图中标注了坐标信息:
在这里插入图片描述

\quad 这三段弧线都是从0°开始,可以看出0°位于圆心右侧的x坐标轴上,默认时按顺时针方向绘制圆弧,如果anticlockwise=true则逆时针绘制圆弧。绘制这三段圆弧的源代码如下:

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // 绘制背景网格线
    drawGrid('lightgray', 10, 10);

    // 绘制一个绿色半圆
    ctx.lineWidth = 8;
    ctx.beginPath();
    ctx.arc(150, 150, 100, 0, Math.PI);
    ctx.strokeStyle = "green";
    ctx.stroke();
    
    // 绘制一个红色圆弧
    ctx.beginPath();
    ctx.arc(400, 150, 100, 0, 135 * Math.PI / 180, true);
    ctx.strokeStyle = "blue";
    ctx.stroke();

    // 绘制另一个蓝色圆弧
    ctx.beginPath();
    ctx.arc(400, 150, 100, 0, 135 * Math.PI / 180, false);
    ctx.strokeStyle = "red";
    ctx.stroke();
</script>

\quad 接下来我们来看一个有趣的例子,绘制一张笑脸,其效果和代码分别如下:
在这里插入图片描述

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // 绘制背景网格线
    drawGrid('lightgray', 10, 10);

    // 绘制笑脸
    drawFace(140, 140, 10);
    
    // 笑脸绘制函数
    function drawFace(x, y, size) {
        ctx.save();
        ctx.translate(x, y);
        ctx.beginPath();
        ctx.arc(0, 0, 10 * size, 0, Math.PI * 2, true);  // Outer circle
        ctx.fillStyle="yellow";
        ctx.fill();
        
        ctx.beginPath();
        ctx.arc(0, 0, 7 * size, 0, Math.PI, false);    // Mouth
        ctx.lineWidth = 4;
        ctx.strokeStyle = "rgb(0,0,0)";
        ctx.stroke();
        
        ctx.beginPath();
        ctx.arc(0 - 3 * size, 0 - 2.5 * size, size, 0, Math.PI * 2, true);  // Left eye
        ctx.moveTo(0 + 4 * size, 0 - 2.5 * size);
        ctx.arc(0 + 3 * size, 0 - 2.5 * size, size, 0, Math.PI * 2, true);  // Right eye
        ctx.fillStyle="black";
        ctx.fill();
        ctx.restore();
    }
</script>

4. 椭圆和椭圆弧

\quad 绘制椭圆和绘制圆的方法非常相似,也是从建立路径开始的,通过ellipse()命令来绘制椭圆或椭圆弧,其语法如下:

ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);
参数名说明
x椭圆圆心的 x 轴坐标
y椭圆圆心的 y 轴坐标
radiusX椭圆长轴的半径
radiusY椭圆短轴的半径
rotation椭圆的旋转角度,单位以弧度表示
startAngle将要绘制的起始点角度,从 x 轴测量,以弧度表示
endAngle椭圆将要绘制的结束点角度,以弧度表示
anticlockwise可选的Boolean值,如果为 true,逆时针绘制圆弧,反之,顺时针绘制

\quad 我们通过一个例子,来了解各个参数的含义,其运行效果如下图所示:
在这里插入图片描述

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');

    // 绘制左侧椭圆
    ctx.beginPath();
    ctx.ellipse(100, 100, 75, 50, 0, 0, 2 * Math.PI);
    ctx.stroke();
    
    // 绘制右侧椭圆
    ctx.beginPath();
    ctx.ellipse(300, 100, 50, 70, 0, 0, 2 * Math.PI);
    ctx.stroke();
    
    // 绘制辅助线
    ctx.beginPath()
    ctx.moveTo(0, 100)
    ctx.lineTo(850, 100);
    ctx.moveTo(100, 0);
    ctx.lineTo(100, 200)
    ctx.moveTo(300, 0);
    ctx.lineTo(300, 200)    
    ctx.setLineDash([4, 4]);
    ctx.stroke();
</script>

\quad 从这个例子可以看出,绘制椭圆ctx.ellipse()由中心点坐标、x方向半径、y方向半径、起始角度、终止角度等几个参数绘制而成,其参数和圆的绘制非常相似。
比较特殊的是绘制椭圆多了一个旋转角度参数:

ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);

\quad 通过一个示例了解一下这个参数,其运行效果和源代码分别如下:
在这里插入图片描述

<script>
    // 从页面中获取画布对象
    let canvas = document.getElementById('canvas');
    // 从画布中获取“2D渲染上下文”对象
    let ctx = canvas.getContext('2d');
    // 绘制背景网格线
    drawGrid('lightgray', 10, 10);

    // 绘制红色椭圆
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.ellipse(120, 120, 110, 50, 0, 0, 2 * Math.PI);
    ctx.strokeStyle = "red";
    ctx.stroke();

    // 绘制蓝色椭圆
    ctx.beginPath();
    ctx.ellipse(120, 120, 110, 50, 60 * Math.PI / 180, 0, 2 * Math.PI);
    ctx.strokeStyle = "blue";
    ctx.stroke();

    // 绘制绿色椭圆
    ctx.beginPath();
    ctx.ellipse(120, 120, 110, 50, 120 * Math.PI / 180, 0, 2 * Math.PI);
    ctx.strokeStyle = "green";
    ctx.stroke();
</script>

\quad 在这里示例中,三个椭圆除旋转角度外,其他参数均相同,可以看出椭圆以圆心为中心点进行了旋转。

5 本章小结

\quad 本节讲解了如何在Canvas绘制矩形、线、多边形、圆、椭圆等内容,并讲解了绘制边和填充、设置线宽、设置颜色等内容,本节内容使用了Canvas 2D API以下方法:

参数名说明
strokeRect()绘制一个矩形的边框
fillRect()绘制一个填充的矩形
rect()在路径中绘制矩形
clearRect()清除指定矩形区域,让清除部分完全透明
beginPath()开始一个新的路径
closePath()将笔点返回到当前子路径起始点
moveTo()将一个新的子路径的起始点移动到 (x,y) 坐标
lineTo()绘制直线(使用直线连接子路径的终点到 x,y 坐标)
arc()绘制圆弧路径
ellipse()绘制椭圆路径
stroke()绘制当前或已经存在的路径
fill()填充当前或已存在的路径

同时也使用了Canvas 2D API修改了绘图时的以下样式:

参数名说明
strokeStyle描述画笔(绘制图形)颜色或者样式的属性
fillStyle描述填充时颜色和样式的属性
lineWidth设置线段宽度的属性
setLineDash()填充线时使用虚线模式

练习一下

基本形状
  • 练习1:绘制一个绿色的(green),填充的,大小为整个画布的矩形;
  • 练习2:绘制一个金色的(gold),填充的,大小为100的圆;
  • 练习3:绘制一条蓝色的(blue),长度为200, 粗细为6的带箭头的线;
七巧板

\quad 七巧板是由五个三角形、一个平行四边形和一个正方形组成,以下是七巧板中各块板的坐标,使用这些数据可以绘制出下面这个图形,你也动手试一试吧。

[
    { "coords": [[100, 50], [340, 50], [220, 170]], "fillColor": "#caff67" },
    { "coords": [[100, 50], [220, 170], [100, 290]], "fillColor": "#67becf" },
    { "coords": [[340, 50], [340, 170], [280, 230], [280, 110]], "fillColor": "#ef3d61" },
    { "coords": [[280, 110], [280, 230], [220, 170]], "fillColor": "#f9f51a" },
    { "coords": [[220, 170], [280, 230], [220, 290], [160, 230]], "fillColor": "#a54c09" },
    { "coords": [[160, 230], [220, 290], [100, 290]], "fillColor": "#fa8ccc" },
    { "coords": [[340, 170], [340, 290], [220, 290]], "fillColor": "#f6ca29" }
]

在这里插入图片描述

相关资料

系列教程及代码资料:https://GraphAnyWhere.com
图形系统开发实战课程:基础篇——图形系统概述


作者信息

作者 : 图形开发学院
CSDN: https://blog.csdn.net/2301_81340430?type=blog
官网:https://graphanywhere.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值