程序员的浪漫

8,129 阅读7分钟

why

为什么要做这个东西,这篇文章的起源

要追溯到今年2月14日摸鱼闲逛的时候看到了码上掘金活动。里面有个主题叫代码的浪漫,看到有同学用js来画爱心,我就想起了去年的一部电视剧《点燃我,温暖你》里的爱心。由于网上(github、谷歌)没有搜索到比较理想的前端代码,所以对这块有了兴趣。

加上之前一直想做类似的东西,一直又没开工,感觉现在正是时机成熟的时候。

what

这个东西有什么效果
这个东西怎么使用

展示效果

romantic.gif

进入主页会有个提示(主要是播放音乐需要用户触发一下),点击确定播放背景音乐,页面会绘制一个多色爱心跳动效果+心跳音、内容通过打字效果+打字音效果呈现,打完字关闭打字声音。

整个页面可以通过自定义页面进行配置。

可以直接通过码上掘金点击运行看效果。进入全屏页面效果更佳,你还可以fork到你的仓库自定义你想要的效果。

你还可以直接点开网址看效果,主要是适配手机,方便微信发送,pc可以开调试模式看。

怎么使用

点击底部自定义页面,就可以配置页面对应元素(提示、标题、内容、背景音乐、心跳颜色)

前面3个是必填属于文字展示,背景音乐可以是一个mp3的网络连接,心跳颜色就是css的color值(这里可以配置多个颜色,没跳动一次会切换一次颜色,多个颜色之间使用英文的逗号,隔断,理论上没有上限)

romantic1.gif

怎么分享给微信朋友

在自定义页面点击“分享到微信”会生成一个链接,但是这个链接很长,直接发出去不太友好,这个时候我们就需要发送一个图文连接会更好。这里不是我不做微信分享的功能啊,为了个微信分享专门接入sdk感觉不香。我们可以利用微信的bug来实现这个功能

微信有个bug,链接直接打开分享出去还是链接,参考一个gif。但是你在公众号发消息里面打开再分享就是图文了,参考第二个gif。

55.gif

romantic11.gif

how

怎么实现

爱心跳动

既然是复刻,那肯定要扒一扒电视剧上的代码了。

视频原版效果
aixin.gif

电视剧里代码的实现

电视剧其实已经给出了答案。代码出处:电视剧第5级,31分12秒。令人怀念的Visual Studio😄。

WeChat1c6178f523c004bb25161ac804f9e4b8.png

上面的就是用c++语言来实现爱心点位集的获取。整个函数可以得到一组由no_pieces数量个点组成的坐标容器(也就是数组)。no_pieces作为入参,代表画多少个点。通过参数方程式x = 16 sin^3 t, y = (13 cos t - 5 cos 2t - 2 cos 3t - cos 4t) 循环传入不同的角度,可以算出爱心的直角坐标点位。看来编剧也没有完全糊弄观众😄,用心了~

数学又有用武之地了,感觉以前学到知识能用来就像掉了的钱又找回来了一样,很开心😄。参数方程式解出来的图形就是个完美心形了。

WeChate0a7bb2f125961b445f2aecb29a7f26a.png

前端实现

前端实现技术主要是canvas来进行绘制。 具体可以看代码实现,我聊一下思路。

要实现跳动效果要考虑什么问题:

  1. 通过什么方式封装
  2. 怎么绘制爱心
  3. 怎么让爱心动起来
  4. 给爱心加上音乐
  5. 其他
通过什么方式封装

主要通过class封装,通过const heart = new Heart(参数); heart.draw()的形式来使用,这样封装的好处是可以在页面加载阶段就完成点位的生成,绘制的时候更快一点。

怎么绘制爱心

绘制通过canvas来实现,具体常用的方法如下:

<canvas id="heart"></canvas>
// 拿到节点
const canvas = document.querySelector('#heart');
// 设置宽高
canvas.height = 600;
canvas.width = 600;
// 创建一个2d画布
this.context = canvas.getContext('2d');
// 设置点位颜色
this.context.fillStyle = 'red'
// 在横坐标x、纵坐标y填充宽width高height的矩形
this.context.fillRect(x, y, width, height);
// 清理以横坐标x、纵坐标y开始绘制宽width高height矩形的点
this.context.clearRect(x, y, width, height);

通过调用fillRect,设置宽高相等随机设置1到3像素,可以绘制边长1到3像素的正方形小点。再重复调用这个方法就可以绘制出一副爱心粒子图了。

那具体应该怎么绘制呢?我们可以把整幅图分解成

  1. 爱心轮廓的点
  2. 爱心的内边框的点
  3. 爱心内部的点
  4. 爱心外部的点。

爱心轮廓的点就像下面这张图可以通过函数x = 16 sin^3 t, y = (13 cos t - 5 cos 2t - 2 cos 3t - cos 4t)传入角度来算出点位x、y坐标。把不同角度点位的坐标绘制出来就是一个轮廓图了。

WeChat8bc2860814c61d844185cb1a439f5c99.png

爱心的内边框的点是越靠近边缘点位越多,越往中心点位越少,这是不是和高中学的对数很像。假设x随机,y代表边缘到爱心中点的距离,那么随机几千个点90%以上的点位y应该是-1和-2。 那么我们就可以基于轮廓来获得向内扩散的点位。

WeChatac410e5c46b901fc9e879687c9ef3123.png

WeChat3a514393246cfaeab68c67222e84a601.png

通过调整倍数我们可以获得更靠近中心点的一个图案。

WeChatcdf4bb7623d88af9a8ec2e357afb47f0.png

外边框则是一个有宽度的粒子爱心,通过设定一个范围随机生成。

WeChatb407bc837bc95592b915db97e69b19e7.png

把上面所有点位合在一起就是一个爱心图。

WeChatfe927bb71daccc3d42718c379c9587e5.png

怎么让爱心动起来

动态效果就是多幅画面连续播放形成的效果。根据心脏跳动,我绘制了五幅不同大小心脏画面来实现心脏跳动的一个效果。这里绘制新画面需要用到clearRect清除上一个画面,因为点位也是随机的,所以也会有点位在运动的感觉。

给爱心加上音乐

在构造类的时候给dom节点增加auto标签,调用绘制的时候调用播放。这又体现了class的好处。

其他
  1. 不暴露的方法(需要用this)使用private,不暴露的方法(不使用this)用static。
  2. 通过width自动计算画布宽高和点位,算好比例就可以很好的实现。
  3. 每跳动一次换一次颜色,通过计算跳一次的画面数量每6副画面切换颜色即可。

打字效果

主要是dom操作+css效果,灵感来自码上掘金这个活动主页的代码。也是通过class实现,有加载动作使用class比较好。
一个个字体浮现是通过循环内容每200毫秒给节点增加一个字。
超出页面自动把滚动条移动到底部是在增加字过程中监听内容高度是不是超出了屏幕,超出了就移动滚动条位置到底部。

其他

配置化就是个表单的使用。
这里做了个基于时间戳+hash的免费验证码,每小时更新。有验证码就可以影藏作者信息~

后记

终于给这个篇章画上了句点。前前后后写代码加写文总共花费33个小时。这个其实是第二个版本了,第一个版本只是对心跳实现感兴趣。但是不太满意,就把之前发的文章删了。

也算开启了我这个系列的填坑之旅吧。一直打算把之前收到的礼物做成电子版,但一直没有契机。现在慢慢完成~

放到这个仓库GitHub - txp1035/romantic,感兴趣可以一起共建。还差电子日记、明星片、车票电子展示,电子版折叠爱心,回忆相册等等。

如果你觉得这篇文章还不错的话,求赞👍🏻,求收藏⭐️,求转发➡️,最重要的是点个关注➕,各位的支持就是我写文章的最大动力。最后,祝大家都拥有甜甜的爱情。