Canvas:掌握颜色线条与图像文字设置

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

目录

颜色样式设置

线条样式设置

图像样式设置

文字样式设置


颜色样式设置

设置基础样式:除了绘制简单的图形,填充线条的样式外,我们还可以给图形进行一个上色处理,对颜色样式进行一个简单的设置,如果我们可以设置一下线条的颜色:

<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); // 设置线条为红色,支持16进制,rgb(a) 等格式ctx.strokeStyle='red';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.strokeStyle='blue';ctx.stroke(chatPath)</script>
</body>

得到的效果如下所示:

设置渐变样式:如果想设置渐变的样式的话,可以通过调用createLinearGradient函数创建

1)线性渐变:后添加在0-1之间的某个数值点位上设置颜色,从开始坐标到结束坐标进行颜色样式的渐变效果展示,代码示例如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 绘制矩形let linearGradient = ctx.createLinearGradient(100, 200, 400, 500); // 创建线性渐变linearGradient.addColorStop(0, "red"); // 添加颜色 从第一个坐标开始linearGradient.addColorStop(0.5, "yellow"); // 添加颜色 从中间开始linearGradient.addColorStop(1, "blue"); // 添加颜色 从最后一个坐标结束ctx.fillStyle = linearGradient; // 设置填充样式ctx.fillRect(100, 200, 300, 300);</script>
</body>

最终得到的结果如下所示:

当然如果想看到渐变效果动态的变化,没问题,这里我们设置一下渲染函数,动态的改变某一位置的颜色渐变效果,示例代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");let index = 0;function render() {// 把上一次的绘制结果清除ctx.clearRect(0, 0, 600, 400);index += 0.01if (index > 1) {index = 0;}let linearGradient = ctx.createLinearGradient(100, 200, 400, 500); // 创建线性渐变linearGradient.addColorStop(0, "red"); // 添加颜色 从第一个坐标开始linearGradient.addColorStop(index, "#008c8c"); // 添加颜色 从中间开始linearGradient.addColorStop(1, "blue"); // 添加颜色 从最后一个坐标结束ctx.fillStyle = linearGradient; // 设置填充样式ctx.fillRect(100, 200, 300, 300);requestAnimationFrame(render);}requestAnimationFrame(render);</script>
</body>

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

2)镜像渐变:如果想创建镜像渐变的话,可以通过两个坐标表示内外圆,然后设置渐变效果,示例代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 绘制圆/*参数依次是 (x0, y0, r0, x1, y1, r1),表示两个圆之间的渐变。在这里:(300, 200, 0) 表示内圆的中心坐标 (x0, y0) 是 (300, 200),半径 r0 是 0,即一个点。(300, 200, 100) 表示外圆的中心坐标 (x1, y1) 是 (300, 200),半径 r1 是 100。*/let radiaGradient = ctx.createRadialGradient(300, 200, 0, 300, 200, 100);radiaGradient.addColorStop(0, 'red');radiaGradient.addColorStop(0.3, '#ffcccc');radiaGradient.addColorStop(1, 'blue');ctx.fillStyle = radiaGradient;ctx.fillRect(0, 0, 600, 400);</script>
</body>

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

当然这里我们可以通过设置俩个球心,实现一个3d地球的效果,示例代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 绘制圆let radiaGradient = ctx.createRadialGradient(250, 150, 10, 300, 200, 100);radiaGradient.addColorStop(0, '#fff');radiaGradient.addColorStop(1, 'blue');ctx.fillStyle = radiaGradient;ctx.arc(300, 200, 100, 0, Math.PI * 2); // 绘制圆ctx.fill() // 填充</script>
</body>

最终呈现的效果如下:

3)圆锥渐变:如果想实现圆锥渐变的话,可以使用createConicGradient函数进行操作,示例代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 绘制扇形渐变let coneGradient = ctx.createConicGradient(0, 300, 200);coneGradient.addColorStop(0, 'red');coneGradient.addColorStop(1, 'blue');ctx.fillStyle = coneGradient;ctx.fillRect(0, 0, 600, 400) // 填充</script>
</body>

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

线条样式设置

在上面我们讲解到了canvas的颜色样式的设置,那么如果我们想对canvas的线条进行一个样式的修改应该如何操作呢?这里开始进行一个简单的讲述,给出如下场景的修改线条样式的函数:

lineWidth = value:设置线条宽度。代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置线条function draw() {for (let i = 0; i < 10; i++) {ctx.lineWidth = i + 1;ctx.beginPath(); // 开始一条新路径ctx.moveTo(5+i*14, 5); // 移动到起点ctx.lineTo(5+i*14, 140) // 绘制一条到终点ctx.stroke();}}draw();</script>
</body>

线宽是指给定路径的中心到两边的粗细。换句话说就是在路径的两边各绘制线宽的一半,因为画布的坐标并不和像素直接对应,当需要获得精确的水平或垂直线的时候要特别注意。

lineCap = type:设置线条末端样式。代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");// 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置线条function draw() {var lineCap = ['butt', 'round', 'square'];// 创建路径ctx.strokeStyle = '#09f';ctx.beginPath();ctx.moveTo(10, 10);ctx.lineTo(140, 10);ctx.moveTo(10, 140);ctx.lineTo(140, 140);ctx.stroke();// 画线条ctx.strokeStyle = 'black';for (var i = 0; i < lineCap.length; i++) {ctx.lineWidth = 15;ctx.lineCap = lineCap[i];ctx.beginPath();ctx.moveTo(25 + i * 50, 10);ctx.lineTo(25 + i * 50, 140);ctx.stroke();}}draw();</script>
</body>

这里绘制了三条直线,分别赋予不同的 lineCap 值,还有两条辅助线,为了可以看得更清楚它们之间的区别,三条线的起点终点都落在辅助线上。最左边的线用了默认的 butt 。可以注意到它是与辅助线齐平的。中间的是 round 的效果,端点处加上了半径为一半线宽的半圆。右边的是 square 的效果,端点处加上了等宽且高度为一半线宽的方块:

lineJoin = type:设置线条与线条间接接合处的样式。代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");// 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置线条function draw() {var lineJoin = ['round', 'bevel', 'miter'];ctx.lineWidth = 10;for (var i = 0; i < lineJoin.length; i++) {ctx.lineJoin = lineJoin[i];ctx.beginPath();ctx.moveTo(-5, 5 + i * 40);ctx.lineTo(35, 45 + i * 40);ctx.lineTo(75, 5 + i * 40);ctx.lineTo(115, 45 + i * 40);ctx.lineTo(155, 5 + i * 40);ctx.stroke();}}draw();</script>
</body>

这里用三条折线来做例子,分别设置不同的 lineJoin 值。最上面一条是 round 的效果,边角处被磨圆了,圆的半径等于线宽。中间和最下面一条分别是 bevel 和 miter 的效果。当值是 miter 的时候,线段会在连接处外侧延伸直至交于一点:

setLineDash(segments):设置当前虚线样式。代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");// 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置线条ctx.moveTo(150, 150)ctx.lineTo(300, 200)ctx.lineTo(450, 150)// 设置虚线ctx.setLineDash([10, 20])ctx.stroke()</script>
</body>

setLineDash 方法接受一个数组,来指定线段与间隙的交替:

lineDashOffset = value:设置当前虚线样式的起始偏移量。

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");// 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置线条let index = 0function render() {ctx.clearRect(0, 0, 600, 400);index++if (index > 40) {index = 0}ctx.moveTo(150, 150)ctx.lineTo(300, 200)ctx.lineTo(450, 150)// 设置虚线ctx.setLineDash([40, 20])// 设置偏移量ctx.lineDashOffset = indexctx.stroke()requestAnimationFrame(render) // 动画渲染}render()</script>
</body>

设置线条的移动:

shadowOffsetXshadowOffsetYshadowBlurshadowColor:设置阴影。代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");// 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置线条let index = 0function render() {ctx.clearRect(0, 0, 600, 400);index++if (index > 40) {index = 0}ctx.moveTo(150, 150)ctx.lineTo(300, 200)ctx.lineTo(450, 150)// 设置阴影ctx.shadowOffsetX = 10 // 阴影偏移量ctx.shadowOffsetY = 10 // 阴影偏移量ctx.shadowBlur = 5 // 阴影模糊度ctx.shadowColor = "rgba(255, 100, 10, 1)" // 阴影颜色// 设置虚线ctx.setLineDash([40, 20])// 设置偏移量ctx.lineDashOffset = indexctx.stroke()requestAnimationFrame(render) // 动画渲染}render()</script>
</body>

效果如下:

图像样式设置

canvas更有意思的一项特性就是图像操作能力,可以用于动态的图像合成或者作为图形的背景,以及游戏界面(Sprites)等等。浏览器支持的任意格式的外部图片都可以使用,比如 PNG、GIF 或者JPEG,你甚至可以将同一个页面中其他 canvas 元素生成的图片作为图片源。

patterns图案填充:在上面我们讲解到了对画面进行一个颜色的填充,把画面填充成某一个固定的颜色或者说是一个渐变的颜色,那如果我想填充的不是渐变的颜色,而是一个个图像呢?这里我们就需要借助patterns这个属性来实现了,如下给出示例代码:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 创建图案样式let img = new Image();img.src = "./1.jpg"// 加载图片img.onload = function(){// 创建图案对象 createPattern(图片对象, 重复方式)let pattern = ctx.createPattern(img, "repeat");ctx.fillStyle = pattern;ctx.fillRect(0, 0, 600, 400);}</script>
</body>

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

drawImage:对图片进行缩放,裁剪操作:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 创建图案样式let img = new Image();img.src = "./1.jpg"// 加载图片img.onload = function(){// 第一种绘制图片方式:参数是:图片资源,以及水平和垂直位置// ctx.drawImage(img, 0, 0) // 第二种绘制图片方式:参数是:图片资源,以及水平和垂直位置,以及缩放宽高600和400// ctx.drawImage(img, 0, 0, 600, 400) // 第三种绘制图片方式:参数是:图片资源,以及裁剪的起点位置和矩形宽高,以及裁剪以及水平和垂直位置,以及缩放宽高600和400ctx.drawImage(img, 1040, 100, 1500, 720, 0, 0, 600, 400) }</script>
</body>

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

当然drawImage函数也是可以对视频进行相应操作的,这里简单赘述一下,示例代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><video src="./1.mp4" controls style="width: 400px; height: auto;" hidden></video><button id="btn">播放 / 暂停</button><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置图像视频let video = document.querySelector("video");video.src = "./1.mp4";let btn = document.getElementById("btn");btn.onclick = function () {if (video.paused) {video.play();render();} else {video.pause();}}// 添加logolet img = new Image();img.src = "./1.jpg";// 渲染函数function render() {ctx.drawImage(video, 0, 0, 600, 400); // 绘制视频ctx.drawImage(img, 500, 350, 100, 50); // 绘制logorequestAnimationFrame(render);}</script>
</body>

效果如下:

文字样式设置

canvas提供了两种方法来渲染文本,这里做一个简单的介绍,如下:

fillText(text, x, y [, maxWidth]):在指定的 (x,y) 位置填充指定的文本,绘制的最大宽度是可选的。代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置文字ctx.font = "30px Arial";// 设置填充渲染文字ctx.fillText("Hello World", 10, 30);</script>
</body>

strokeText(text, x, y [, maxWidth]):在指定的 (x,y) 位置绘制文本边框,绘制的最大宽度是可选的。代码如下:

<body><canvas id="canvas" width="600" height="400"></canvas><script>let canvas = document.getElementById("canvas");      // 获取2维画笔,上下文对象let ctx = canvas.getContext("2d");// 设置文字ctx.font = "30px Arial";// 设置文字颜色ctx.strokeStyle='red';// 设置文本对齐方式, 默认是 leftctx.textAlign = "center";// 设置基线对齐方式, 默认是 topctx.textBaseline = "middle";// 设置文本方向,默认是 ltrctx.direction = "rtl";// 设置填充渲染文字ctx.strokeText("Hello World!", 300, 200);</script>
</body>

上面代码同时给出了常用的文字操作方式,这里做一个简单的举例,最终得到的效果如下:

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

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

相关文章

回溯 | Java | LeetCode 39, 40, 131 做题总结

Java Arrays.sort(数组) //排序 不讲究顺序的解答&#xff0c;都可以考虑一下排序是否可行。 39. 组合总和 错误解答 在写的时候需要注意&#xff0c;sum - candidates[i];很重要&#xff0c;也是回溯的一部分。 解答重复了。是因为回溯的for循环理解错了。 class Solutio…

使用OpenCV与PySide(PyQt)的视觉检测小项目练习

OpenCV 提供了丰富的图像处理和计算机视觉功能&#xff0c;可以实现各种复杂的图像处理任务&#xff0c;如目标检测、人脸识别、图像分割等。 PyQt(或PySide)是一个创建GUI应用程序的工具包&#xff0c;它是Python编程语言和Qt库的成功融合。Qt库是最强大的GUI库之一。Qt的快速…

【开放集目标检测】Grounding DINO

一、引言 论文&#xff1a; Grounding DINO: Grounding DINO: Marrying DINO with Grounded Pre-Training for Open-Set Object Detection 作者&#xff1a; IDEA 代码&#xff1a; Grounding DINO 注意&#xff1a; 该算法是在Swin Transformer、Deformable DETR、DINO基础上…

逆变器学习笔记(三)

DCDC电源芯片外围器件选型_dcdc的comp补偿-CSDN博客、 1.芯片的COMP引脚通常用于补偿网络&#xff1a; 芯片的COMP引脚通常用于补偿网络&#xff0c;在控制环路中发挥重要作用。COMP引脚接电容和电阻串联接地&#xff0c;主要是为了稳定控制环路、调整环路响应速度和滤波噪声…

java Lock接口

在 Java 中&#xff0c;Lock 接口的实现类ReentrantLock 类提供了比使用 synchronized 方法和代码块更广泛的锁定机制。 简单示例&#xff1a; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExampl…

关闭vue3中脑瘫的ESLine

在创建vue3的时候脑子一抽选了ESLine,然后这傻卵子ESLine老是给我报错 博主用的idea开发前端 ,纯粹是用不惯vscode 关闭idea中的ESLine,这个只是取消红色波浪线, 界面中的显示 第二步,在vue.config.js中添加 lintOnSave: false 到这里就ok了,其他的我试过了一点用没有

阿里云 OSS - 开通到使用、服务端签名直传(前后端代码 + 效果演示)

目录 开始 OSS 相关术语须知 阿里云 OSS 开通 阿里云 OSS 使用 官方文档教程 实战开发 阿里云 OSS 自动配置 环境配置 实战开发 服务端签名直传 概述 代码实现 开始 OSS 相关术语须知 中文 英文 说明 存储空间 Bucket 存储空间是您用于存储对象&#xff08;Ob…

DB-GPT-PaperReading

DB-GPT: Empowering Database Interactions with Private Large Language Models 1. 基本介绍 DB-GPT 旨在理解自然语言查询,提供上下文感知响应,并生成高精度的复杂 SQL 查询,使其成为从新手到专家的用户不可或缺的工具。DB-GPT 的核心创新在于其私有 LLM 技术,该技术在…

FL Studio 2024 发布,添加 FL Cloud 插件、AI 等功能

作为今年最受期待的音乐制作 DAW 更新之一&#xff0c;FL Studio 2024发布引入了新功能&#xff0c;同时采用了新的命名方式&#xff0c;从现在起将把发布年份纳入其名称中。DAW 的新增功能包括在 FL Cloud 中添加插件、AI 驱动的音乐创作工具和 FL Studio 的新效果。 FL Cloud…

ThinkPHP定时任务是怎样实现的?

接到一个需求&#xff1a;定时检查设备信息&#xff0c;2分钟没有心跳的机器&#xff0c;推送消息给相关人员&#xff0c;用thinkphp5框架&#xff0c;利用框架自带的任务功能与crontab配合来完成定时任务。 第一步&#xff1a;分析需求 先写获取设备信息&#xff0c;2分钟之…

力扣双指针算法题目:快乐数

目录 1.题目 2.思路解析 3.代码展示 1.题目 . - 力扣&#xff08;LeetCode&#xff09; 2.思路解析 题目意思是将一个正整数上面的每一位拿出来&#xff0c;然后分别求平方&#xff0c;最后将这些数字的平方求和得到一个数字&#xff0c;如此循环&#xff0c;如果在此循环中…

【做一道算一道】和为 K 的子数组

给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2 示例 2&#xff1a; 输入&#xff1a;nums [1,2,3],…

前端面试题8

基础知识 解释一下什么是跨域问题&#xff0c;以及如何解决&#xff1f; 跨域问题是由于浏览器的同源策略限制了从一个源加载的网页脚本访问另一个源的数据。解决方法包括使用JSONP、CORS&#xff08;跨源资源共享&#xff09;、设置代理服务器等。 描述一下事件冒泡和事件捕获…

Flutter-实现悬浮分组列表

在本篇博客中&#xff0c;我们将介绍如何使用 Flutter 实现一个带有分组列表的应用程序。我们将通过 CustomScrollView 和 Sliver 组件来实现该功能。 需求 我们需要实现一个分组列表&#xff0c;分组包含固定的标题和若干个列表项。具体分组如下&#xff1a; 水果动物职业菜…

BigDecimal(double)和BigDecimal(String)有什么区别?BigDecimal如何精确计数?

BigDecimal(double)和BigDecimal(String)的区别 double是不精确的&#xff0c;所以使用一个不精确的数字来创建BigDecimal&#xff0c;得到的数字也是不精确的。如0.1这个数字&#xff0c;double只能表示他的近似值。所以&#xff0c;当我们使用new BigDecimal(0.1)创建一个Bi…

golang验证Etherscan上的智能合约

文章目录 golang验证Etherscan上的智能合约为什么要验证智能合约如何使用golang去验证合约获取EtherscanAPI密钥Verify Source Code接口Check Source Code Verification Status接口演示示例及注意事项网络问题无法调用Etherscan接口&#xff08;最重要的步骤&#xff09; golan…

归并排序的实现(递归与非递归)

概念 基本思想&#xff1a;归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使…

揭秘Conda:Python开发者必备的包管理神器

conda 简介 Conda 是一个开源的包管理系统和环境管理系统&#xff0c;用于安装和管理软件包以及创建和维护不同的软件环境。 它最初是为 Python 语言设计的&#xff0c;但现在已经支持多种编程语言&#xff0c;包括 R、Ruby、Lua、Scala 等。 1、Anaconda&#xff1a;是一个…

GPIO配置-PIN_Speed的理解

在使用STM32的GPIO 口配置时&#xff0c;经常会疑惑应该选用什么样的配置模式&#xff0c;本文谈谈对pin_speed的理解。 根据数据手册可得&#xff0c;STM32提供10MHz,2MHz和50MHz三种输出速度的配置&#xff0c;三种配置的应用场景是怎么样的&#xff1f;。 1.为什么要配置引…

[护网训练]原创应急响应靶机整理集合

前言 目前已经出了很多应急响应靶机了&#xff0c;有意愿的时间&#xff0c;或者正在准备国护的师傅&#xff0c;可以尝试着做一做已知的应急响应靶机。 关于后期&#xff1a; 后期的应急响应会偏向拓扑化&#xff0c;不再是单单一台机器&#xff0c;也会慢慢完善整体制度。…