当前位置: 首页 > news >正文

前端canvas——赛贝尔曲线

曲线之美,不在于曲线本身,而在于用的人。

所以就有了这期赛贝尔曲线。

新规矩,先上个GIT。

效果图


 

开局一张图,代码全靠编。

代码

画骨

先想着怎么画一个心形吧,等你想好了,就知道怎么画了。

首先就还是JS创建Canvas,因为这样有代码提示。

        const canvas = document.createElement('canvas')canvas.width = canvas.height = 600document.body.append(canvas)

接着就是调用三阶的赛贝尔曲线,什么是三阶?

除了命名上不同,还有参考点个数不同——二阶的就一个参考点,三阶有很多个。

众所周知,心形其实是一个不规则的曲线,所以一个是不行的,至少不那么好看。

咱们就用三阶:

            ctx.beginPath()ctx.moveTo(300, 200)ctx.bezierCurveTo(40, 20, 0, 460, 300, 500)ctx.moveTo(300, 200)ctx.bezierCurveTo(560, 20, 600, 460, 300, 500)ctx.closePath()ctx.stroke()

里面的参考点坐标,自己想怎么来就怎么来。

前提是能看出来这是一个心形就OK了,看不出来也没关系,咱们最重要的在于怎么写动画。

如果你按照我的代码写,最终运行的效果中间是有一根线的,你可以stroke()两次,但是我“老奸巨猾”,选择了让画笔颜色消失。

当然啦,你也可以用fill(),这个是最好的。

我的宗旨:

道路千万条

这样,边框的颜色就没有了——因为边框没有了。

上色(可选)

画完这个,就得上色了。

上色很简单,你可以创建一个最简单的线性渐变色,然后fillStyle直接赋值即可。

你也可以追求花里胡哨,选择径向渐变,甚至是放射性渐变。

我这里选择径向渐变,代码就不给了,“心”的颜色取决于你喜欢什么色。

模糊(可选)

如果你跟我一样,Very Strong(跟我念,sizhuang)。

那你还可以上个模糊,模糊很简单,就四个参数,直接一股脑全巴拉巴拉写完就OK了:

            ctx.shadowColor = '#ccc' // 模糊颜色ctx.shadowOffsetX = 12 // 模糊坐标ctx.shadowOffsetY = 18ctx.shadowBlur = 58 // 模糊度数

对了,忘记告诉你了,模糊要在fill()和stroke()之前进行,要不然你铁定显示不出模糊效果。

模糊度数越高,你越看不清楚阴影。

至于取值,看你喜欢什么样的模糊效果,有投影的效果,有完全模糊的效果,都看你喜欢。

封装函数

封装函数都会吧?

-为什么要封装?

-为了后续调用。

对了,记得写个具名函数。

为了好理解,函数名我起init()——这都是学人的,美其名曰:企业级标准。

跳动的心

下面就是最困难的了——怎么让这个静止的心跳动起来了。

其实也很简单,那就是先把旧的图案去掉,换上新的。

道理就是这么个理,但是实现起来就很抽筋:

我们知道,心跳动是什么?

是一个过程,有来有回的。

你不能光来不回吧?

所以咱们得划定个范围,让“心”这个图案在这个范围内不停播放。

问:需要几个变量?

答:两个。

一个是步进量,一个是方向:

                if (scaleFactor >= 1.08 || scaleFactor <= 0.98) {scaleDirection *= (-1) // 改变缩放方向}

GIF图中是有个循环播放的效果的。

怎么循环呢?总不能用while吧?

好像又不是不行,就是你控制不了时间啊。

而且while很容易控制不住,死循环就炸鸡了。

既然提到时间了,那就用setInterval——定时器咯。

跟我拼写:s-e-t-I-n-t-e-r-v-a-l,setInterval。

思想工作完成,开始写函数,函数名写啥?

        function bounce() {let scaleFactor = 1let scaleDirection = 1setInterval(() => {ctx.clearRect(-300, -300, 600, 600)scaleFactor += 0.01 * scaleDirectionif (scaleFactor >= 1.08 || scaleFactor <= 0.98) {scaleDirection *= (-1)}// 应用变换并重新绘制心形ctx.save() // 保存当前画布状态ctx.scale(scaleFactor, scaleFactor)init() // 重新绘制心形ctx.restore() // 恢复画布到保存的状态}, 50)}

这个时间啊,就看你们自己调整了。

太快,不好看;太慢,又好像die了。

所以,你自己把握一下啦。

写完函数之后,记得调用函数,这样,咱们的动画就做好啦。

总结

又到了收工的时候,不知道你发现没发现,这个心居然不是原地跳动的。

这个怎么办捏?

当然是要付费学习的啦。

Tips:定位用一下啦。

最后给出所有代码:

    <script>const canvas = document.createElement('canvas')canvas.width = canvas.height = 600document.body.append(canvas)const ctx = canvas.getContext('2d')function init(){// 彩damn:先在这里改一下定位,然后下面的所有坐标位置都要修改ctx.beginPath()ctx.moveTo(300, 200)ctx.bezierCurveTo(40, 20, 0, 460, 300, 500)ctx.moveTo(300, 200)ctx.bezierCurveTo(560, 20, 600, 460, 300, 500)ctx.closePath()ctx.fill()}function bounce() {let scaleFactor = 1let scaleDirection = 1setInterval(() => {ctx.clearRect(0, 0, 600, 600)scaleFactor += 0.01 * scaleDirectionif (scaleFactor >= 1.08 || scaleFactor <= 0.98) {scaleDirection *= (-1)}// 应用变换并重新绘制心形ctx.save() // 保存当前画布状态ctx.scale(scaleFactor, scaleFactor)// ctx.translate(0, 0) // 彩damn:这个再次改变坐标轴的原点,配合上面。init() // 重新绘制心形ctx.restore() // 恢复画布到保存的状态}, 50)}bounce()</script>

-问:居中效果不会喔。

-答:是不是margin: auto不起作用啊。

-问:是喔,你怎么知道gie?

-答:Canvas是什么元素?不是块元素嘛,这个时候你要改变它的形状啊,用display嘛。

-问:你的效果这么piao亮gie?

-答:用了径向渐变、加了模糊效果,canvas水平居中效果、图案居中缩放。

居中缩放,学一下了喂。 

再见啦。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Android笔试面试题AI答之Android系统与综合类(1)
  • 面试问题记录:
  • 技术实践—微前端技术应用
  • 秋招突击——7/24——知识补充——JVM类加载机制
  • iPhone 17系列取消17 Plus版本?新一代苹果手机迎来新变革
  • 支持向量机 及其分类案例详解(附Python 代码)
  • DNS域名解析服务器
  • Python高维度大型气象矩阵存储策略分享
  • FastAPI(七十八)实战开发《在线课程学习系统》接口开发-- 评论
  • 数字图像处理笔记(三) ---- 傅里叶变换的基本原理
  • ExcelJS:轻松实现Excel文件的读取、操作与写入
  • Redisson中的RBlockingQueue的使用场景及例子
  • java-jvm-软引用
  • 嵌入式C++、STM32、ROS系统和MQTT协议通讯:智能农业灌溉系统项目设计思路(代码示例)
  • 数据结构之深入理解简单选择排序:原理、实现与示例(C,C++)
  • 【Linux系统编程】快速查找errno错误码信息
  • Flannel解读
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • k个最大的数及变种小结
  • Markdown 语法简单说明
  • Python利用正则抓取网页内容保存到本地
  • Python学习之路13-记分
  • vagrant 添加本地 box 安装 laravel homestead
  • windows-nginx-https-本地配置
  • Yii源码解读-服务定位器(Service Locator)
  • 编写符合Python风格的对象
  • 程序员最讨厌的9句话,你可有补充?
  • 构建工具 - 收藏集 - 掘金
  • 机器学习学习笔记一
  • 记录一下第一次使用npm
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 如何在 Tornado 中实现 Middleware
  • 深入浅出webpack学习(1)--核心概念
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 思维导图—你不知道的JavaScript中卷
  • 赢得Docker挑战最佳实践
  • RDS-Mysql 物理备份恢复到本地数据库上
  • ​2020 年大前端技术趋势解读
  • #QT(一种朴素的计算器实现方法)
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (南京观海微电子)——I3C协议介绍
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (原)Matlab的svmtrain和svmclassify
  • (转)ORM
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • (转载)虚函数剖析
  • .FileZilla的使用和主动模式被动模式介绍
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .NET Windows:删除文件夹后立即判断,有可能依然存在