听说可达鸭特别火?六一教你怎么用可达鸭生产表情包

图片说明

听说你们没抢到可达鸭?不要紧!通过这个网站你就可以生成自己的可达鸭表情包啦:demo(请用PC端访问,svg在移动端上的兼容性太渣渣了,踩坑QAQ)

整体的demo分为画鸭子、生成gif、发布静态站点这三大块,让我们来逐步看看是怎么实现生成定制鸭鸭表情包的网站的嘎!

画鸭子

我们的可达鸭采用SVG进行绘制。采用SVG的原因是相比canvas,比较容易做手部的动画,喜欢3d的同学可以直接上three.js来做。

整个画面分为可达鸭、收音机、地面、贴纸4个部分。

可达鸭

可达鸭是整个画面中最复杂的部分,主要在于可达鸭的图形复杂,并且许多部分都是曲线的path围成的。

svg中画曲线主要有以下几种方式:

  • 椭圆弧线,svg中用A表示,需要起始点坐标,x轴、y轴半径,起始x轴方向,角度大小,旋转方向和重点坐标几个参数,对高中解析几何的复习非常有帮助。我们的可达鸭身体就是由两个半椭圆弧拼接而成的。
  • 二次贝塞尔曲线,svg中用Q表示,需要起始点坐标一个控制点,起始点、终止点分别到控制点的连线就是起始、终止部分的斜率,中间斜率平滑变更,就形成了曲线。我们可达鸭的脚部就全部都是用二次贝塞尔曲线实现的。

图片说明

  • 三次贝塞尔曲线,svg中用C表示,相比二次贝塞尔曲线多了一个控制点。我们可达鸭的手和嘴就有一部分是用三次贝塞尔曲线实现的。

图片说明

而像可达鸭的头发(圆角矩形)、眼睛(椭圆)则直接用svg的rect、ellipse、circle等图形画成的。

其实,像可达鸭这种左右对称的结构,很多部分,如手、眼、脚等都可以用defs来定义模板然后用use引用的方式产出。读者有兴趣的话可以试试改造下我们的代码。

收音机、地面与贴纸

画完可达鸭后,收音机、地面与贴纸就显得相对容易许多,因为整体都是规则图形。

收音机就是上圆角矩形-矩形-下圆角矩形3个图形拼接,在加上顶部同样类似圆角矩形的天线、矩形的按钮与圆形的喇叭。由于svg的rect不支持仅上部或下部变成圆角,因此我们通过4条边与两段圆弧线拼接而成。

而地面则更容易了,整体是两个椭圆+3朵小花,每朵小花都是由4瓣圆形花瓣+一个圆形花心构成。为了方便计算,我们绘制花瓣的时候都将花瓣放置成水平垂直的方向,并将花瓣+花心打包在一个g中,在g上直接用transform: rotate整体旋转。

贴纸则是直接通过text与rect拼成的。这里唯一的点在于我们希望text相对于rect是居中对齐的,而text是不支持类似text-align:center或transform: translate这样的居中方式的。但它提供了text-anchor和baseline-anchor这两个属性,让我们可以控制文本的锚点。我们将两个属性都设为了middle。

动画

由于我们使用的是svg,动画就显得非常简单,我们直接使用css animation属性定义手和贴纸的动画。回顾下animation对应的属性:

  • animation-name: 我们需要定义的keyframe的名字,这里叫duckHandLeft与duckHandRight
  • animation-duration: 时长,这里设置为2秒
  • animation-timing-function: 动画时间曲线,为了简单我们就直接采用了内置的ease
  • animation-delay: 延迟,这里设为0s
  • animation-iteration-count:循环次数,这里设置为infinite
  • animation-direction:动画方向,我们设置为alternate,这样我们只要在keyframe中定义一个方向的动画,让浏览器自动帮我们补充逆向的动画
  • animation-fill-mode:动画补充模式,我们设置为both让图形一开始就在起始位置。由于我们的动画是infinite因此backwards能起到相同的效果
  • animation-play-state:是否暂停,我们不需要暂停。

生成GIF

在生成gif上我们选择了gif.js库

选择这个库的原因为:

  1. star数比较多
  2. 这个库可以接受canvas作为帧
  3. API比较简洁

在上一part中,我们产出的是一个大大的svg,gif.js不能接受dom元素作为参数,那我们就需要先将svg转成canvas,这个时候就需要另一个库html-to-image出场了!

首先,我们需要将svg component用forwardRef包一层,接着,再在页面上放置一个看不到的svg用来生成动画帧,详细的生成的代码逻辑可以看注释。

useEffect(() => {
  if (!exporting || !svgRef.current) {
    return;
  }
  toCanvas(svgRef.current as unknown as HTMLElement).then((canvas) => {
    canvasList.push(canvas);
    // 当到最后一个帧时,开始导出gif
    if (rotateDeg === MAX_ROTATE_DEG) {
      const gif = new GIF({
        width: 460,
        height: 400,
        workerScript: gifWorkerUrl,
      });

      // 增加正序动画帧
      gif.addFrame(canvasList[0]);
      for (let i = 0; i < canvasList.length; i++) {
        gif.addFrame(canvasList[i], {
          // 第一帧停留得比较久
          delay: i === 0 ? BIG_DELAY : DELAY_STEP,
        });
      }
      // 增加逆序动画帧
      gif.addFrame(canvasList[canvasList.length - 1], { delay: BIG_DELAY });
      for (let i = 0; i < canvasList.length; i++) {
        gif.addFrame(canvasList[canvasList.length - 1 - i], {
          delay: i === 0 ? BIG_DELAY : DELAY_STEP,
        });
      }
      gif.addFrame(canvasList[0], { delay: BIG_DELAY });
      gif.on("finished", function (blob) {
        setExporting(false);
        setCanvasList([]);
        setRotateDeg(0);
                // 下载生成好的gif
        window.open(URL.createObjectURL(blob));
      });
      gif.render();
    } else {
      setRotateDeg(rotateDeg + STEP);
    }
  });
}, [rotateDeg, exporting]);

比较好奇的是,没有找到接入提供dom元素、动画时间长度、帧率就直接生成gif的库,我们讨论了一下,觉得如果实现这么一个库,问题在于:如果是比较复杂的dom元素,html-to-image需要一定时间,可能会导致页面卡住或者htmlToCanvas无法在规定帧率内完成,导致帧率变低或者丢帧。

如果要实现这个库的话,可以考虑在指定帧数内只记录下dom元素内的所有位置信息,把这些信息异步html-to-image,再使用gif.js生成gif图。(如果有同学有使用过这样的库,也可以评论一下

发布部署

在代码上传到github后,我们需要一个站点来展示静态资源~

首先想到的github自带提供的部署静态资源的功能,选择repository进入settings,可以看到有一个pages tab

图片说明

但是实际尝试后觉得对于站点托管非常难用!(如果是我不会用的话可以在评论区指出

  1. 无法便捷的push代码就触发,只能配置actions
  2. 打包之后的相对路径很迷
  3. 文件夹只能选root或者docs,不可以指定文件夹

兜兜转转看到一篇比较好的介绍站点托管的文章https://github.com/lmk123/blog/issues/55

主要推荐这两个站点

图片说明
Netlify和Vercel(也就now)我们都尝试了一下,都非常的顺滑

  1. 不收费(这很重要!!)
  2. 可以直接关联github
  3. build后deploy基本无需配置
  4. 监测push代码后自动job

大家可以根据偏好选择使用哪一个~本文的demo链接就是由Vercel托管的l

我们的github仓库地址:https://github.com/just-00/psyduck

图片说明

#前端##娱乐##搞笑##技术栈#
全部评论
楼主厉害,佩服
点赞 回复 分享
发布于 2022-06-03 21:15

相关推荐

代码飞升_不回私信人...:别这样贬低自己,降低预期,放平心态,跟昨天的自己比。做好自己,反而会效率更高心态更好,加油兄弟
点赞 评论 收藏
分享
11-20 13:39
已编辑
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务