html5: Canvas 绘制基本图形
从绘制直线 到 路径
Jack Lee 的 CSDN 博客
邮箱 :291148484@
CSDN 主页:/qq_28550263?spm=1001.2101.3001.5343
本文地址:/qq_28550263/article/details/123661151
目 录相关文章推荐:
Flutter框架: 使用Canvas绘制直线
1. Canvas 相关概念
1.1 什么是Canvas1.2 Canvas坐标系1.3 Canvas元素 1.3.1 基本用法1.3.2 在 TypeScript 中的用法
2. Canvas 绘制直线
2.1 直线与路径:从绘制基本线段开始 2.1.1CanvasRenderingContext2D对象的moveTo()
方法2.1.2CanvasRenderingContext2D对象的lineTo()
方法2.1.3CanvasRenderingContext2D对象的stroke()
方法 2.2. Canvas 绘制矩形 2.2.1 通过路径绘制矩形2.2.2 通过 CanvasRenderingContext2D 对象的矩形方法 2.2.2.1rect
(x, y, width, height) 方法2.2.2.2fillRect
(x, y, width, height)2.2.2.3strokeRect
(x, y, width, height)2.2.2.4clearRect
(x, y, width, height)
3 Canvas 路径
3.1 什么是 Canvas 路径3.2 操作 Canvas 路径的方法 3.2.1beginPath
() 方法3.2.2closePath
() 方法3.2.3bezierCurveTo
() 方法3.2.4quadraticCurveTo
() 方法3.2.5arc
() 方法3.2.6arcTo
() 方法3.2.7ellipse
() 方法3.2.8rect
() 方法3.2.9fill
() 方法3.2.10drawFocusIfNeeded
() 方法3.2.11scrollPathIntoView
() 方法3.2.12clip
() 方法3.2.13isPointInPath
() 方法3.2.14isPointInStroke
() 方法
4. Canvas实战:多边形与组合图形的绘制
4.1 绘制五边形4.2 绘制一个五角星4.3 绘制房屋
1. Canvas 相关概念
1.1 什么是Canvas
Canvas是 HTML5 的 2D图形技术之一,是一门纯JavaScript操作的图形技术。另一个是2D图形技术为 SVG。这两者的区别在于:
1.2 Canvas坐标系
Canvas使用的坐标系是W3C坐标系这与数学中的直角坐标系中的区别在于,数学直角坐标系y轴
正方向向上,而W3C坐标系中的y轴
正方向向下:
1.3 Canvas元素
1.3.1 基本用法
Canvas 使用一个通过JavaScript 和 HTML的<canvas>元素来绘制图形的方式,以下是 HTML 中的一个Canvas元素:
<canvas id="canvas" width="300" height="200"></canvas>
要操作Canvas绘图首先要获取 HTML <canvas> 元素的引用,然后获取这个元素的context,需要依次使用以下方法:
如获取上面id
属性值为canvas
的上下文对象(context):
const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');
在 HTML 中,你需要指定canvas
元素的宽度和高度作为你的画布大小,宽度和高度都为纯数字。
1.3.2 在 TypeScript 中的用法
在TypeScript中你需要指定类型。在这里,getElementById()
方法返回的类型应该被断言为HTMLCanvasElement而非直接断言成普通的HTMLElement。
HTMLCanvasElement接口提供用于操作元素布局和表示的属性和方法。HTMLCanvasElement接口还继承了HTMLElement接口的属性和方法。
<canvas id="canvas" width="300" height="200" ></canvas><script lang="ts">let canvas = document.getElementById("canvas") as HTMLCanvasElement;let ctx = canvas.getContext("2d") as CanvasRenderingContext2D;</script>
2. Canvas 绘制直线
2.1 直线与路径:从绘制基本线段开始
不同于 SVG, 只支持两种形式的图形绘制:矩形和路径(由一系列点连成的直线段)。所有其他类型的图形都是通过一条或者多条路径组合而成的。不过,我们拥有众多路径生成的方法让复杂图形的绘制成为了可能。
我们可以使用以下两个方法来配合绘制直线:
var canvas = document.getElementById("canvas");var ctx = canvas.getContext("2d");ctx.beginPath();ctx.moveTo(50,50);ctx.lineTo(200, 50);ctx.stroke();
2.1.1CanvasRenderingContext2D对象的moveTo()
方法
将一个新的子路径的起始点
移动到(x,y)坐标的方法。
语法
void ctx.moveTo(x, y);
2.1.2CanvasRenderingContext2D对象的lineTo()
方法
使用直线连接子路径的终点到x,y坐标的方法(并不会真正地绘制)
语法
void ctx.lineTo(x, y);
参数
2.1.3CanvasRenderingContext2D对象的stroke()
方法
使用非零环绕规则,根据当前的画线样式,绘制当前或已经存在的路径的方法。
语法
void ctx.stroke();void ctx.stroke(path);
参数
2.2. Canvas 绘制矩形
2.2.1 通过绘制直线的方法绘制矩形
ctx.beginPath();ctx.strokeStyle = 'red';ctx.moveTo(0,0);ctx.lineTo(160,0);ctx.lineTo(160,100);ctx.lineTo(0,100);ctx.lineTo(0,0);ctx.stroke();
效果如下:
2.2.2 通过 CanvasRenderingContext2D 对象的矩形方法
2.2.2.1rect
(x, y, width, height) 方法
创建矩形路径的方法,矩形的起点位置是 (x, y) ,尺寸为 width 和 height。矩形的4个点通过直线连接,子路径做为闭合的标记,所以你可以填充或者描边矩形。
语法
void ctx.rect(x, y, width, height);
例如
ctx.beginPath();ctx.rect(10, 30, 200, 100);ctx.fill();
效果如下:
2.2.2.2fillRect
(x, y, width, height)
CanvasRenderingContext2D.fillRect()
函数是Canvas 2D API 绘制填充矩形的方法。当前渲染上下文中的fillStyle 属性决定了对这个矩形对的填充样式。
这个方法是直接在画布上绘制填充,并不修改当前路径,所以在这个方法后面调用 fill() 或者stroke()方法并不会对这个方法有什么影响。
语法
void ctx.fillRect(x, y, width, height);
参数:
x
:矩形起始点的 x 轴坐标。y
:矩形起始点的 y 轴坐标。width
:矩形的宽度。height
:矩形的高度。
fillRect()
方法绘制一个填充了内容的矩形,这个矩形的开始点(左上点)在(x, y) ,它的宽度和高度分别由width
和height
确定,填充样式由当前的fillStyle 决定。
例如
ctx.fillStyle = 'yellow';ctx.fillRect(60, 20, 200, 100);
效果如下:
2.2.2.3strokeRect
(x, y, width, height)
该方法使用当前的绘画样式,描绘一个起点在 (x, y) 、宽度为 w 、高度为 h 的矩形的方法。
语法
void ctx.strokeRect(x, y, width, height);
例如
ctx.shadowColor = '#5F9CFA';ctx.shadowBlur = 30;ctx.lineJoin = 'bevel';ctx.lineWidth = 15;ctx.strokeStyle = '#5FFA7A';ctx.strokeRect(30, 30, 90, 90);
效果如下:
2.2.2.4clearRect
(x, y, width, height)
该方法通过把像素设置为透明以达到擦除一个矩形区域的目的。
语法
void ctx.clearRect(x, y, width, height);
例如
除整个画布:
ctx.clearRect(0, 0, canvas.width, canvas.height);
清除画布一个区域显现出矩形:
// 绘制背景色ctx.beginPath();ctx.fillStyle = '#eca601';ctx.fillRect(0, 0, canvas.width, canvas.height);// 绘制矩形清除区域ctx.clearRect(10, 10, 120, 100);
效果如下:
3 Canvas 路径
3.1 什么是 Canvas 路径
在Canvas中除了下一节中的矩形提供了直接绘制方法,其它的所有Canvas基本图形,包括上一小节中的直线,以及圆形、弧线、贝塞尔曲线,都是以路径为基础进行绘制的。
3.2 操作 Canvas 路径的方法
1. 操作路径
2. 绘制路径
3.2.1beginPath
() 方法
清空子路径列表开始一个新的路径。当你想创建一个新的路径时,调用此方法。
语法
void ctx.beginPath();
例如
// 第一条路径ctx.beginPath();ctx.strokeStyle = 'blue';ctx.moveTo(30,30);ctx.lineTo(0,200);ctx.stroke();// 第二条路径ctx.beginPath();ctx.strokeStyle = '#FE5B5C';ctx.moveTo(30,30);ctx.lineTo(120,120);ctx.stroke();
效果如下:
效果图(其中边框是为了展示canvas画布区域有意添加上去的)
3.2.2closePath
() 方法
该方法 将笔点返回到当前子路径起始点。它尝试从当前点到起始点绘制一条直线。 如果图形已经是封闭的或者只有一个点,那么此方法不会做任何操作。
语法
void ctx.closePath();
例子
不使用该方法时:
ctx.beginPath();ctx.strokeStyle = 'blue';ctx.moveTo(0,0);ctx.lineTo(200,20);ctx.lineTo(120,120);ctx.stroke();
效果如下:
效果图(其中边框是为了展示canvas画布区域有意添加上去的)
使用该方法返回到当前子路径起始点后:
ctx.beginPath();ctx.strokeStyle = 'blue';ctx.moveTo(0,0);ctx.lineTo(200,20);ctx.lineTo(120,120);ctx.closePath(); // 绘制三角形的最后一条线ctx.stroke();
效果如下:
效果图(其中边框是为了展示canvas画布区域有意添加上去的)
3.2.3bezierCurveTo
(cp1x, cp1y, cp2x, cp2y, x, y) 方法
该方法用于绘制三次贝赛尔曲线路径。
贝塞尔曲线它是依据四个位置任意的点坐标绘制出的一条光滑曲线。它通过控制曲线上的四个点(起始点、终止点以及两个相互分离的中间点)来创造、编辑图形。
其中起重要作用的是位于曲线中央的控制线。这条线是虚拟的,中间与贝塞尔曲线交叉,两端是控制端点。移动两端的端点时贝塞尔曲线改变曲线的曲率(弯曲的程度);移动中间点(也就是移动虚拟的控制线)时,贝塞尔曲线在起始点和终止点锁定的情况下做均匀移动。
语法
void ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
例如:
ctx.beginPath();ctx.moveTo(20,20);ctx.bezierCurveTo(230, 30, 150, 60, 50, 100);ctx.stroke();// 绘制相关点ctx.fillStyle = 'blue';ctx.fillRect(20, 20, 10, 10);// 起点ctx.fillRect(50, 100, 10, 10);// 终点ctx.fillStyle = 'red';ctx.fillRect(230, 30, 10, 10);// 控制点1ctx.fillRect(150, 70, 10, 10);// 控制点2
效果如下:
3.2.4quadraticCurveTo
(cpx, cpy, x, y) 方法
该方法是 Canvas 2D API 新增二次贝塞尔曲线路径的方法。它需要2个点。 第一个点是控制点
,第二个点是终点
。起始点
是当前路径最新的点,当创建二次贝赛尔曲线之前,可以使用moveTo()
方法进行改变。
语法
void ctx.quadraticCurveTo(cpx, cpy, x, y);
例如
ctx.beginPath();ctx.moveTo(50, 20);ctx.quadraticCurveTo(230, 30, 50, 100);ctx.stroke();ctx.fillStyle = 'blue';ctx.beginPath();ctx.arc(50, 20, 5, 0, 2 * Math.PI); // 起始点ctx.arc(50, 100, 5, 0, 2 * Math.PI); // 终点ctx.fill();ctx.fillStyle = 'red';ctx.beginPath();ctx.arc(230, 30, 5, 0, 2 * Math.PI); // 控制点ctx.fill();
效果如下:
3.2.5arc
(x, y, radius, startAngle, endAngle, anticlockwise) 方法
该方法用于绘制圆弧路径。 圆弧路径的圆心在 (x, y) 位置,半径为 r ,根据anticlockwise (默认为顺时针)指定的方向从 startAngle 开始绘制,到 endAngle 结束。
语法
void ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
例如:
ctx.beginPath();ctx.arc(50, 50, 50, 0, 2 * Math.PI);ctx.stroke();
效果如下:
3.2.6arcTo
(x1, y1, x2, y2, radius) 方法
该方法根据控制点和半径绘制圆弧路径,使用当前的描点(前一个moveTo或lineTo等函数的止点)。根据当前描点与给定的控制点1连接的直线,和控制点1与控制点2连接的直线,作为使用指定半径的圆的切线,画出两条切线之间的弧线路径。
语法
void ctx.arcTo(x1, y1, x2, y2, radius);
例如
ctx.setLineDash([])ctx.beginPath();ctx.moveTo(150, 20);ctx.arcTo(150,100,50,20,30);ctx.stroke();ctx.fillStyle = 'blue';ctx.fillRect(150, 20, 10, 10); // 基本点ctx.fillStyle = 'red';ctx.fillRect(150, 100, 10, 10); // 控制点1ctx.fillRect(50, 20, 10, 10); // 控制点2ctx.setLineDash([5,5])ctx.moveTo(150, 20);ctx.lineTo(150,100);ctx.lineTo(50, 20);ctx.stroke();ctx.beginPath();ctx.arc(120,38,30,0,2*Math.PI);ctx.stroke();
效果如下:
3.2.7ellipse
(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise) 方法
语法
void ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);
3.2.8fill
() 方法
该方法根据当前的填充样式,填充当前或已存在的路径的方法。采取非零环绕或者奇偶环绕规则。
语法
void ctx.fill();void ctx.fill(fillRule);void ctx.fill(path, fillRule);
参数
例子
ctx.beginPath();ctx.strokeStyle = 'blue';ctx.moveTo(0,0);ctx.lineTo(200,90);ctx.lineTo(120,120);ctx.closePath();ctx.stroke();ctx.fill();
效果如下:
3.2.10drawFocusIfNeeded
() 方法
该方法用来给当前路径或特定路径绘制焦点
的方法,如果给定的元素获取了焦点。
语法
void ctx.drawFocusIfNeeded(element);void ctx.drawFocusIfNeeded(path, element);
例如
<canvas id="canvas" width="300" height="200" ><input id="button" type="range" min="1" max="12"></canvas><script lang="ts">let canvas = document.getElementById("canvas") as HTMLCanvasElement;let ctx = canvas.getContext("2d") as CanvasRenderingContext2D;let button = document.getElementById("button") as HTMLElement ;</script>
效果如下:
3.2.11scrollPathIntoView
() 方法
该方法将当前或给定的路径滚动到窗口的方法。类似于Element.scrollIntoView()
。
语法
void ctx.scrollPathIntoView();void ctx.scrollPathIntoView(path);
例如
ctx.beginPath();ctx.fillRect(10, 10, 30, 30);ctx.scrollPathIntoView();
3.2.12clip
() 方法
语法
void ctx.clip();void ctx.clip(fillRule);void ctx.clip(path, fillRule);
例如
ctx.beginPath();ctx.arc(100, 100, 50, 0, Math.PI*2, false);ctx.clip();ctx.fillRect(0, 0, 100,100);
效果如下:
3.2.13isPointInPath
() 方法
语法
boolean ctx.isPointInPath(x, y);boolean ctx.isPointInPath(x, y, fillRule);boolean ctx.isPointInPath(path, x, y);boolean ctx.isPointInPath(path, x, y, fillRule);
返回值
一个Boolean值:
例子
ctx.rect(50, 50, 50, 50);ctx.stroke();let _ = ctx.isPointInPath(10, 10)console.log(_); // true
控制台输出为:true
效果如下:
3.2.14isPointInStroke
() 方法
语法
boolean ctx.isPointInStroke(x, y);boolean ctx.isPointInStroke(path, x, y);
返回值
一个Boolean值:
例子
ctx.rect(50, 50, 50, 50);ctx.stroke();let _ = ctx.isPointInStroke(10, 10)console.log(_); // false
控制台输出为:false
效果如下:
4. Canvas实战:多边形与组合图形的绘制
4.1 绘制五边形
ctx.beginPath();ctx.lineWidth = 5;ctx.strokeStyle = 'blue';ctx.moveTo(100, 0); ctx.lineTo(195, 69);ctx.lineTo(159, 181);ctx.lineTo(41, 181);ctx.lineTo(5, 69);ctx.closePath();ctx.stroke();
效果如下:
4.2 绘制一个五角星
ctx.beginPath();ctx.lineWidth = 5;ctx.strokeStyle = 'blue';ctx.beginPath(); ctx.moveTo(100, 0);ctx.lineTo(159, 181);ctx.lineTo(5, 69);ctx.lineTo(195, 69);ctx.lineTo(41, 181); ctx.closePath();ctx.stroke();
效果如下:
4.3 绘制房屋
// 线条宽度ctx.lineWidth = 5;ctx.beginPath();// 绘制屋顶ctx.moveTo(50, 95);ctx.lineTo(150, 20);ctx.lineTo(250, 95);ctx.closePath();ctx.stroke();ctx.strokeRect(100, 95, 100, 100); // 绘制墙ctx.fillRect(130, 135, 40, 60); // 绘制门
效果如下: