Canvas:掌握贝塞尔曲线与封装路径

news2024/10/6 4:11:38

想象一下,用几行代码就能创造出如此逼真的图像和动画,仿佛将艺术与科技完美融合,前端开发的Canvas技术正是这个数字化时代中最具魔力的一环,它不仅仅是网页的一部分,更是一个无限创意的画布,一个让你的想象力自由驰骋的平台。

目录

初识canvas

路径绘制

贝塞尔曲线

封装路径(Path2D)

初识canvas

身为一个WEB开发人员,肯定都是想着能够开发出酷炫和激动人心的应用程序来,想开发出很多动画特效,例如黑客帝国的数字,彩色炫酷的例子动效。也可以实现各种图画面板,如实现类似于photoshop的web在线图像编辑。各种酷炫的表单等等,接下来我们通过一段简单的代码来了解如何实现一个画布:

通过canvas标签创建一个画布,通过getContext函数设置2d画笔,然后通过fillRect函数创建一个画布的位置与大小,代码如下:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制图形,矩形 fillRect(x, y, width, height) 参数位置x,位置y,宽度,高度
        ctx.fillRect(100, 200, 300, 300);
    </script>
</body>

执行代码在浏览器打开的界面得到的结果如下所示,可以看到我们在浏览器得到一个黑色的区域,在这我们可以看到,我们在canvas设置的宽高是画布的初始宽高,这里可以传递实际宽高,相当于一张图片有一个初始宽高,可以对这张图片进行放大缩小操作:

当然我们也可以对 fillRect 函数继续拆开来书写,代码如下达到的效果是一样的:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制图形
        ctx.rect(100, 200, 300, 300); // 绘制矩形
        ctx.fillStyle = "red"; // 填充颜色
        ctx.fill(); // 填充
    </script>
</body>

如果想要清除画布中的样式的话,可以采用clearRect函数的方法进行,这里做一个简单的代码示例:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制图形
        ctx.fillRect(100, 100, 200, 200);
        let height = 0
        let t1 = setInterval(() => {
            height++
            ctx.clearRect(0, 0, canvas.clientWidth, height);
            if (height > canvas.clientHeight) {
                clearInterval(t1)
            }
        }, 10)
    </script>
</body>

得到的效果如下所示:

浏览器兼容性:至今已经2024年了,我相信大家的电脑浏览器已经普遍是最新版本的浏览器,除非长期使用比较古老的浏览器或者说很久都没有更新过浏览器的人来说,可能存在不兼容canvas的情况。因为只有canvas才有getContext函数,所以这里我们也可以对canvas做一个判断:

let canvas = document.getElementById("canvas");
// 判断是否有getContext
if (canvas.getContext) {
    console.log("当前浏览器不支持canvas,请下载最新浏览器");
}

当然这里我们也可以直接写在canvas标签中,因为如果canvas不能被识别的情况下会将canvas作为一个普通的标签进行执行,所以会直接呈现canvas标签内部的内容:

<canvas id="canvas" width="600" height="400">
    当前浏览器不支持canvas,请下载最新浏览器
    <a href="www.baidu.com">立即下载</a>
</canvas>

当然canvas还有许多API函数可以使用,如果忘记的话,可以查阅 MDN ,进行查看:

路径绘制

在我们设置画布的时候,画布内部是有规定的坐标的,我们可以通过拿到特定的坐标可以绘制一个特定的曲线,所以我们需要告诉canvas的画笔坐标的落点是在哪里?我们要在什么样的位置画什么样的图案。

在我们开始画图之前,我们需要了解一下画布栅格(canvasgrid)以及坐标空间,如下图所示,canvas元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas元素中的一像素。

栅格的起点为左上角(坐标为(0,0)),所有元素的位置都相对于原点定位,所以图中蓝色方形左上角的坐标为距离左边(X轴)×像素,距离上边(Y轴)y像素(坐标为(x,y)):

绘制矩形:可以通过strokeRect函数进行,这里通过如下代码示例进行演示:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制图形,路径绘制矩形 strokeRect(x1, y1, 矩形宽度, 矩形高度)
        ctx.strokeRect(100, 100, 200, 100);
    </script>
</body>

在页面得到的结果如下所示:

绘制圆形:当然如果想绘制圆形的话可以采用如下的代码方式,使用arc函数绘制圆弧传递6个参数即可:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制圆弧 圆形x坐标 y坐标 半径 起始角度 结束角度 顺时针/逆时针(默认顺时针)
        console.log(Math.PI / 2)
        ctx.arc(300, 200, 50, 0, Math.PI / 2, true) 
        ctx.stroke()
    </script>
</body>

得到的画面如下所示:

如果想绘制一个简单的笑脸的话,可以采用如下的方式进行,因为canvas是连续的,也就是画笔是不会自动抬起而是一直画下去,这里需要我们手动的指定画笔的抬起进行书写样式,具体代码如下所示:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制圆脸
        ctx.beginPath(); // 开始绘制
        ctx.arc(75, 75, 50, 0, Math.PI * 2);
        ctx.stroke()
        ctx.closePath(); // 闭合路径

        ctx.beginPath();
        // 绘制嘴巴
        ctx.arc(75, 75, 35, 0, Math.PI);
        ctx.stroke()
        ctx.closePath(); 

        ctx.beginPath();
        // 绘制左眼
        ctx.arc(60, 65, 5, 0, Math.PI * 2);
        ctx.stroke()
        ctx.closePath(); 

        ctx.beginPath();
        // 绘制右眼
        ctx.arc(90, 65, 5, 0, Math.PI * 2);
        ctx.closePath(); 
        ctx.stroke()
    </script>
</body>

绘制线段:如果想绘制一条从当前位置到指定x以及y位置的直线,可以采用的方式是lineTo方法:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制线段
        ctx.moveTo(300, 200); // 起点
        ctx.lineTo(350, 250); // 终点 起点
        ctx.lineTo(350, 200); // 终点 起点
        ctx.lineTo(300, 200); // 终点
        ctx.stroke();
    </script>
</body>

最终呈现的效果如下所示:

绘制圆弧:当然这里我们也可以通过arcTo方法进行绘制圆弧,给出如下代码示例:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 绘制线段
        ctx.moveTo(300, 200); // 第一个点
        ctx.arcTo(300, 250, 250, 250, 25); // 第二个和第三个点以及圆弧半径 
        ctx.stroke();
    </script>
</body>

其大致的意思如下,三个点组成的线段相切得到的圆弧片段就是我们想要的:

贝塞尔曲线

贝塞尔曲线是一种数学曲线,通常用于在计算机图形学和计算机辅助设计(CAD)中绘制平滑曲线,它由法国工程师皮埃尔·贝塞尔(Pierre Bézier)在20世纪60年代提出并广泛应用于汽车工业的设计中,贝塞尔曲线通过控制点(称为贝塞尔控制点)来定义曲线的形状,其形式简单且易于计算,因此在计算机图形学中得到了广泛应用,如绘制曲线、字体设计、动画制作等领域,在canvas中贝塞尔曲线也是被广泛应用,本文就其做一个简单的概述供大家学习了解:

二次贝塞尔曲线:由三个控制点定义,形状相对简单。

1)由三个控制点定义:起始点P0,控制点P1,终点P2。

2)曲线不经过P1点,但P1点影响曲线的形状。

3)用途:二次贝塞尔曲线通常用于较简单的曲线绘制和动画路径。

这边我们可以做一个气泡聊天框进行一个简单的练习,详细的代码如下所示:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");      
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 初始起点
        ctx.moveTo(200, 300)
        // 绘制二次贝塞尔曲线
        /*  二次贝塞尔曲线 ctx.quadraticCurveTo(cx, cy, x, y) 中,四个参数的含义如下:
            cx: 控制点的 x 坐标。这个点影响曲线的弯曲方向和弧度。
            cy: 控制点的 y 坐标。与 cx 一起决定了曲线的形状。
            x: 曲线的终点 x 坐标。这是曲线将要到达的目标点。
            y: 曲线的终点 y 坐标。与 x 一起决定了曲线的最终位置。
        */
        ctx.quadraticCurveTo(150, 300, 150, 200); 
        ctx.quadraticCurveTo(150, 100, 300, 100); 
        ctx.quadraticCurveTo(450, 100, 450, 200); 
        ctx.quadraticCurveTo(450, 300, 250, 300); 
        ctx.quadraticCurveTo(250, 350, 150, 350); 
        ctx.quadraticCurveTo(200, 350, 200, 300); 
        ctx.stroke()
    </script>
</body>

程序的效果如下所示,效果还不错:

三次贝塞尔曲线:由四个控制点定义,更能描述复杂的曲线。

1)由四个控制点定义:起始点P0,控制点P1,控制点P2,终点P3。

2)曲线经过起始点P0和终点P3,但不一定经过控制点P1和P2。

3)用途:三次贝塞尔曲线比二次更灵活,适用于更复杂的曲线绘制,如字体设计、CAD绘图、动画路径等。

这里我们可以借助三次贝塞尔曲线做一个简单的爱心:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");      
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        // 初始起点
        ctx.moveTo(300, 200)
        /* 
            第一个控制点和第二个控制点是曲线弯曲方向的关键点
            第三个控制点 终点是曲线最终到达的目标点
        */
        ctx.bezierCurveTo(350, 150, 400, 200, 300, 300); 
        ctx.bezierCurveTo(200, 200, 250, 150, 300, 200); 
        ctx.stroke()
    </script>
</body>

程序的效果如下所示,效果还不错:

二次和三次贝塞尔曲线在计算机图形学中广泛用于平滑曲线的生成和路径控制,它们被用来设计字体、绘制图形、创建动画路径、制作CAD图形等,其简单的数学形式和良好的平滑性使它们成为计算机图形学中不可或缺的工具之一。

封装路径(Path2D)

在canvas中,Path2D是一个对象用来存储和重用路径描述信息,从而方便地绘制相同或类似的路径多次,尤其适合于需要频繁使用复杂路径的场景,这里我们做一个简单的概述:

通过如下代码把路径存在2d对象中,下次想要操作这个路径,就直接把2d对象传给fill或者描边方法就行了,如下给出代码示例:

<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        let canvas = document.getElementById("canvas");      
        // 获取2维画笔,上下文对象
        let ctx = canvas.getContext("2d");
        let heartPath = new Path2D();
        
        // 初始起点
        heartPath.moveTo(300, 200)
        heartPath.bezierCurveTo(350, 150, 400, 200, 300, 300); 
        heartPath.bezierCurveTo(200, 200, 250, 150, 300, 200); 
        ctx.stroke(heartPath)

        let chatPath = new Path2D();
        chatPath.moveTo(200, 300)
        chatPath.quadraticCurveTo(150, 300, 150, 200); 
        chatPath.quadraticCurveTo(150, 100, 300, 100); 
        chatPath.quadraticCurveTo(450, 100, 450, 200); 
        chatPath.quadraticCurveTo(450, 300, 250, 300); 
        chatPath.quadraticCurveTo(250, 350, 150, 350); 
        chatPath.quadraticCurveTo(200, 350, 200, 300); 
        ctx.stroke(chatPath)
        ctx.fill(heartPath)
    </script>
</body>

页面呈现的效果如下所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1885632.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT中QDomDocument读写XML文件

一、XML文件 <?xml version"1.0" encoding"UTF-8"?> <Begin><Type name"zhangsan"><sex>boy</sex><school>Chengdu</school><age>18</age><special>handsome</special>&l…

Android自动化测试实践:uiautomator2 核心功能与应用指南

Android自动化测试实践&#xff1a;uiautomator2 核心功能与应用指南 uiautomator2 是一个用于Android应用的自动化测试Python库&#xff0c;支持多设备并行测试操作。它提供了丰富的API来模拟用户对App的各种操作&#xff0c;如安装、卸载、启动、停止以及清除应用数据等。此外…

maven设置阿里云镜像源(加速)

一、settings.xml介绍 settings.xml是maven的全局配置文件&#xff0c;maven的配置文件存在三个地方 项目中的pom.xml&#xff0c;这个是pom.xml所在项目的局部配置文件用户配置&#xff1a;${user.home}/.m2/settings.xml全局配置&#xff1a;${M2_HOME}/conf/settings.xml 优…

3.js - 纹理的 magfilter、minFilter、各向异性过滤(各项异性解决倾斜模糊问题)

效果图&#xff0c;就是一个PlaneGeometry&#xff0c;加了一个贴图&#xff0c;再设置下面这些属性&#xff0c;你就放大缩小着看吧&#xff0c;反正我看不出什么来 代码 // ts-nocheck // 引入three.js import * as THREE from three // 导入轨道控制器 import { OrbitContro…

4、音视频封装格式---FLV

FLV FLV是一种容器封装格式&#xff0c;是由Adobe公司发布和维护的&#xff0c;用于将视频编码流与音频编码流进行封装。对于任意一种封装格式&#xff0c;都有其头部区域与数据区域&#xff0c;在FLV中&#xff0c;称之为FLV Header与Body。 对于FLV Header&#xff0c;一个FL…

31 C++11

本节目标 c11简介列表初始化变量类型推导范围for循环新增加容器右值新的类功能可变参数模板 1. c11简介 在2003年标准委员会提交了一份计数勘误表&#xff08;简称TC1&#xff09;&#xff0c;使得c03这个名字已经取代了c98称为c11之前的最新的c标准名称。不过由于c03&#x…

【桌面微信多开】

桌面微信多开 步骤一&#xff1a;新建txt步骤二&#xff1a;保存修改为.bat步骤三&#xff1a;双击运行程序步骤四&#xff1a;多次点击微信 步骤一&#xff1a;新建txt echo offstart /d "D:\program\WeChat\" WeChat.exestart /d "D:\program\WeChat\" …

Xilinx FPGA:vivado利用单端RAM/串口传输数据实现自定义私有协议

一、项目要求 实现自定义私有协议&#xff0c;如&#xff1a;pc端产生数据&#xff1a;02 56 38 &#xff0c;“02”代表要发送数据的个数&#xff0c;“56”“38”需要写进RAM中。当按键信号到来时&#xff0c;将“56”“38”读出返回给PC端。 二、信号流向图 三、状态…

MessageBox的作用与用法

在C# &#xff08; Windows Forms &#xff09;中&#xff0c;MessageBox 的所有常用用法如下&#xff1a; 1. 显示一个简单的消息框 MessageBox.Show("这是一个简单的消息框。");2. 显示带标题的消息框 MessageBox.Show("这是一个带标题的消息框。", &…

美国服务器租用详细介绍与租用流程

在数字化时代&#xff0c;服务器租用已成为许多企业和个人拓展业务、存储数据的重要选择。美国作为全球科技发展的前沿阵地&#xff0c;其服务器租用服务也备受瞩目。下面&#xff0c;我们将详细介绍美国服务器租用的相关知识及租用流程。 一、美国服务器租用简介 美国服务器租…

PDI-kettle工具连接本地虚拟机Ubuntu上的数据库

PDI 配置ubuntu数据库配置Kettle工具 PDI版本&#xff1a;9.4 Ubuntu2204&#xff1a;10.11.8-MariaDB-0ubuntu0.24.04.1 Ubuntu 24.04 配置ubuntu数据库 安装 apt install -y mariadb-server配置监听地址 cat > /etc/mysql/mariadb.conf.d/99-kettle.cnf << EOF …

结构体------“成绩排序”---冒泡----与“输出最高成绩”区别

从大到小或者从小到大排序----冒泡排序---双重循环i,j 比较的时候用的是 排序的时候用的是整体 stu [ j1 ] 和 stu [ j ] 我写错为下面这个&#xff0c;交换的只是学生的出生日期&#xff0c;没有交换整体 #include<stdio.h> #include<string.h>struct student{ch…

MySQL 8.0新特性INTERSECT和EXCEPT用于集合运算

MySQL8.0.31 新版本的推出&#xff0c;MySQL增加了对SQL标准INTERSECT和EXCEPT运算符的支持。 1、INTERSECT INTERSECT输出多个SELECT语句查询结果中的共有行。INTERSECT运算符是ANSI/ISO SQL标准的一部分(ISO/IEC 9075-2:2016(E))。 我们运行两个查询&#xff0c;第一个会列…

仰邦BX.K协议对接

背景 使用BX 6K控制卡控制诱导屏显示剩余车位数&#xff0c;由于控制卡和服务端不在一个局域网内&#xff0c;所以不能使用官网提供的案例&#xff0c;官网提供的案例为控制卡为TCP Server&#xff0c;服务端为TCP Client&#xff0c;因此需要开发此程序&#xff0c;服务端左右…

docker mysql cpu100% cpu打满排查 mysql cpu爆了 mysql cpu 100%问题排查

1. docker 启动了一个mysql 实例&#xff0c;近期忽然发现cpu100% 如下图所示 命令&#xff1a; top 2.进入容器内排查&#xff1a; docker exec mysql&#xff08;此处可以是docker ps -a 查找出来的image_id&#xff09; -it /bin/bash cd /var/log cat mysqld.log 容器内m…

Android LayoutInflater 深度解析

在 Android 开发中&#xff0c;LayoutInflater 是一个非常重要的工具。它允许我们从 XML 布局文件中动态地创建 View 对象&#xff0c;从而使得 UI 的创建和管理更加灵活。本文将深入解析 android.view.LayoutInflater&#xff0c;包括它的基本用法、常见问题以及高级用法。 什…

Java高级重点知识点-19-Lambda

文章目录 Lambda表达式函数式编程思想Lambda表达式写法代码讲解 Lambda表达式 函数式编程思想 强调做什么&#xff0c;而不是以什么形式做。 以函数式接口Runnable为例讲解&#xff1a; public class LambdaDemo {public static void main(String[] args) {Runnable runnab…

学习无人机飞行技术,有哪些就业方向?

随着无人机技术的不断进步和应用领域的拓展&#xff0c;研发创新人才的需求也将不断增加&#xff0c;那就业前景还是很广阔的。学习无人机飞行技术后&#xff0c;有以下多个就业方向可供选择&#xff1a; 1. 无人机操作员&#xff1a; - 负责操控和监控无人机飞行&#xff0c;…

第57期|GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…