Canvas学习笔记 | 多个示例详细讲述Canvas变形操作,干货
liebian365 2025-01-13 15:21 10 浏览 0 评论
前言
大家好,我是汪小成。最近在学习Canvas。这篇文章是我学习Canvas变形操作时记的笔记,欢迎大家审阅。
简介
在Canvas中有如下三个基本变形操作:
- 图形平移:translate(x, y)
- 图形缩放:scale(x, y)
- 图形旋转:rotate(deg)
图形平移
在Canvas中,我们使用translate()方法来平移图形。图形平移指的是将图形沿x轴或y轴进行直线运行。平移不会改变图形的形状和大小。
语法
ctx.translate(x, y);
说明
x表示图形在x轴方向移动的距离,默认单位为px。当x为正数时,图形沿x轴正方向移动;当x为负数时,图形沿x轴反方向移动。 y表示图形在y轴方向移动的距离,默认单位为px。当y为正数时,图形沿y轴正方向移动;当y为负数时,图形沿y轴反方向移动。
示例一:简单示例
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>平移图形</title>
</head>
<body>
<canvas id="canvas" width="200" height="150"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(30, 30, 50, 40);
ctx.translate(50, 50);
ctx.fillStyle = "yellow";
ctx.fillRect(30, 30, 50, 40);
};
</script>
</body>
</html>
效果图:
说明:
上面的示例中,我们先绘制了一个红色的矩形,然后调用translate()方法将矩形在x轴方向和y轴方向分别平移50px,即黄色矩形的位置。平移操作,本质上来讲,是平移坐标系。
还有一点需要注意的是,translate()方法必须在fillRect()方法之前调用才有效。
先进行平移操作,然后绘制需要平移的图形。
示例二:连续平移
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>连续平移</title>
</head>
<body>
<canvas id="canvas" width="300" height="250"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(30, 30, 50, 40);
ctx.save();
ctx.translate(50, 50);
ctx.fillStyle = "yellow";
ctx.fillRect(30, 30, 50, 40);
ctx.restore();
ctx.save();
ctx.translate(100, 100);
ctx.fillStyle = "blue";
ctx.fillRect(30, 30, 50, 40);
ctx.restore();
};
</script>
</body>
</html>
效果图:
说明:
在平移图形前,我们调用了context.save()方法保存当前状态;在平移操作完成后,我们调用context.restore()方法恢复之前保存的状态`。这么做的目的是让每一次平移操作都以最初的状态为最根本的参照物。
图形缩放
在Canvas中,我们使用scale()方法对图形进行缩放操作。这里的“缩放”包含“缩小”和“放大”两层含义。
语法
ctx.scale(x, y);
说明
x表示图形在x轴方向的缩放倍数。y表示图形在y轴方向的缩放倍数。x和y一般情况下都是正数。 当x或y取值为0~1之间时,图形会缩小;当x或y取值大于1时,图形会被放大。
示例
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>图形缩放</title>
</head>
<body>
<canvas id="canvas" width="200" height="150"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
// 1、获取 Canvas 对象
var canvas = document.getElementById("canvas");
// 2、获取上下文环境对象
var ctx = canvas.getContext("2d");
// 绘制图形
ctx.fillStyle = "#faeab3";
ctx.fillRect(30, 30, 60, 60);
// 缩放操作:将图形放大1.5倍
ctx.scale(1.5, 1.5);
ctx.fillStyle = "#ff0000";
ctx.fillRect(30, 30, 60, 60);
};
</script>
</body>
</html>
效果图:
本示例中,我们使用scale(1.5, 1.5)将图形放大了1.5倍。从效果图中,我们可以看出,图形左上角的坐标也放大了1.5位。是因为scale()方法除了会改变图形的大小之外,还会改变诸如线条宽度、左上角坐标等其他属性。
图形旋转
在Canvas中,我们使用rotate()方法旋转图形。
语法
ctx.rotate(angle);
说明
参数angle表示图形的旋转角度。取值范围为 -Math.PI * 2 ~ Math.PI * 2。当angle小于0时,图形顺时针旋转;当angle大小0时,图形逆时针旋转。
示例一:图形旋转简单示例
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>图形旋转</title>
</head>
<body>
<canvas id="canvas" width="200" height="150"
style="border: 1px dashed #333333"></canvas>
<script>
window.onload = function () {
// 1、获取 Canvas 对象
var canvas = document.getElementById("canvas");
// 2、获取上下文环境对象
var ctx = canvas.getContext("2d");
// 绘制图形
ctx.fillStyle = "#ff0000";
ctx.fillRect(100, 30, 50, 20);
ctx.rotate(30 * Math.PI /180);
// 为了方便比较,我们重新绘制了原来图形
ctx.fillStyle = "#faeab3";
ctx.fillRect(50, 30, 50, 20);
};
</script>
</body>
</html>
效果图:
默认情况下,图形旋转时是以Canvas坐标原点为旋转中心的。如果我们想要以(x, y)为中心旋转,需要先使用translate(x, y)平移图形,然后旋转图形就是以(x, y)为中心旋转了。
示例二:旋转的半圆
这个示例相对来说有点复杂,我们先来看下效果图。
实现步骤:
- 绘制半圆;
- 让半圆旋转起来;
- 选取不同的圆心;
- 绘制多个半圆,并让这些半圆旋转起来。
步骤1、绘制半圆
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 4, 0, Math.PI, true);
ctx.strokeStyle = "white";
ctx.stroke();
步骤2、让半圆旋转起来
// 画布尺寸
let size = 800;
let canvas = document.getElementById("canvas");
canvas.width = canvas.height = size;
let ctx = canvas.getContext("2d");
// 半圆开始绘制的角度,用于控制半圆旋转
let angle = 0;
function draw() {
window.requestAnimationFrame(draw);
ctx.clearRect(0, 0, size, size);
console.log("angle: " + angle);
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 4, angle, Math.PI + angle, true);
ctx.strokeStyle = "white";
ctx.stroke();
angle += 0.02;
}
window.requestAnimationFrame(draw);
步骤3、选取不同的圆心
let size = 800;
// 圆心的数量
let num = 8;
let canvas = document.getElementById("canvas");
canvas.width = canvas.height = size;
let ctx = canvas.getContext("2d");
// 画布中央位置
var center = {
x: canvas.width / 2,
y: canvas.height / 2,
};
// 半径
let radius = 200;
// 初始角度
let angle = 0;
(function frame() {
ctx.fillStyle = "#ff0000";
for (let i = 0; i < num; i++) {
const x = center.x + radius * Math.cos(Math.PI * 0.25 * i);
const y = center.y + radius * Math.sin(Math.PI * 0.25 * i);
// 圆心没有必要绘制出来,这里只是为了便于展示。
ctx.beginPath();
ctx.arc(x, y, 12, 0, 2 * Math.PI, true);
ctx.fill();
}
})();
步骤4、绘制多个半圆,并让这些半圆旋转起来。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>图形旋转</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
window.onload = function () {
let size = 800;
let num = 8;
let canvas = document.getElementById("canvas");
canvas.width = canvas.height = size;
let ctx = canvas.getContext("2d");
var center = {
x: canvas.width / 2,
y: canvas.height / 2,
};
// 半径
let radius = 200;
// 初始角度
let angle = 0;
(function frame() {
window.requestAnimationFrame(frame);
// 拖尾效果
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#ff0000";
for (let i = 0; i < num; i++) {
const x = center.x + radius * Math.cos(Math.PI * 0.25 * i);
const y = center.y + radius * Math.sin(Math.PI * 0.25 * i);
// 绘制圆形
ctx.beginPath();
ctx.arc(
x,
y,
size / 4,
angle + Math.PI * 0.25 * i,
Math.PI + angle + Math.PI * 0.25 * i,
false
);
ctx.lineWidth = 3;
ctx.strokeStyle = "hsl(" + angle * 60 + "deg,80%,50%)";
ctx.stroke();
angle += 0.008;
}
})();
};
</script>
<style>
* {
margin: 0;
padding: 0;
}
body {
background-color: black;
display: flex;
vertical-align: middle;
justify-content: center;
}
</style>
</body>
</html>
上面的这段代码就是“旋转的半圆”示例程序的完整代码了。
附:清空画布&拖尾效果
清空画布
在Canvas中,我们使用clearRect()方法清空整个画布。
语法:
ctx.clearRect(0, 0, canvas.width, canvas.height);
拖尾效果
我们在绘制一些动画效果时有时候可能会需要使用拖尾效果让动画更美观一点。拖尾效果可以通过如下代码实现:
ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)