使用Fabric.js实现贝塞尔曲线波浪特效

使用Fabric.js实现贝塞尔曲线波浪特效一、前言 在观看本文之前推荐先看看这位朋友的文章(使用canvas实现贝塞尔曲线波浪特效),本文是在此基础上收到启发然后进行的变化,当然,观看与否不会影响接下来的阅读体验。 二、实现思路 其实整个波浪

一、前言

在观看本文之前推荐先看看这位朋友的文章(使用canvas实现贝塞尔曲线波浪特效),本文是在此基础上收到启发然后进行的变化,当然,观看与否不会影响接下来的阅读体验。

二、实现思路

其实整个波浪动画其实可以看成:在相对坐标系静止的视角下,一个正弦函数在直角坐标系上匀速平移时我们所观察到的效果。根据所选参照系的不同,我们也可以看成是:坐标系上有个点,我们在相对点静止的视角下,一个点在坐标系上按着正弦函数的规律来进行移动,此时我们所观察到的点走过的痕迹的变化就是波浪的动画效果。从绘制角度来说,就是我们要绘制一条曲线按照正弦函数的规律去变化。在canvas中,能让曲线以正弦函数方式绘制的其中一个方法就是使用canvas提供的贝塞尔曲线绘制方法。

canvas提供的贝塞尔曲线方法有很多变种,比如一次贝塞尔、二次贝塞尔、三次贝塞尔等等,在这里我们主要使用了三次贝塞尔,三次贝塞尔曲线有一个起点、终点和两个控制点。其他的在此不做讨论。

言归正传,来讲讲Fabric.js。Fabric.js 没有提供类似于canvas中的绘制贝塞尔曲线的API(quadraticCurveTobezierCurveTo等),但是在线段绘制类Path里,Fabric.js引入了SVG中path元素的线段绘制写法,而这就让我们在Fabric.js中绘制贝塞尔曲线的梦想得以触手可及。

在这里我们简单介绍一下SVG中path元素的部分语法:

2.1、M(moveto)移动和L(lineto)画直线

其中 M 表示移动到某点,L 表示画一条直接到某点,后面跟一个坐标点,建议格式如下:

"M x y" // M是命令:x横轴坐标、y纵轴坐标
"L x y" // L是命令:x横轴坐标、y纵轴坐标

2.2、 Z(cloasPath)闭合

结束点到开始点画一条直线,形成一个闭合的区域。

语法格式就是在字符串的最后写一个Z,表示闭合。

2.3、C(curveto)三次贝塞尔曲线

三次贝塞尔曲线有一个起点、终点和两个控制点,跟二次贝塞尔相比多了一个控制点,如图,P0、P3是起点和终点,P1、P2是控制点。

三次贝塞尔曲线.gif

// 起点(x0,y0),控制点1 (x1,y1),控制点2 (x2,y2),终点 (x3,y3)
" M x0 y0 C x1 y1, x2 y2, x3 y3 " 

介绍完了SVG语法之后我们来看看如何实现波浪的效果。

三、代码实现

3.1、运行环境

fabric v5.2.4

vue v3.2.25

3.2、画布搭建

HTML

<template>
  <div class="container">
    <canvas class="canvas" id="fabric" width="500" height="500"></canvas>
  </div>
</template>

SCSS

.container {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;

  .canvas {
    border: 1px solid #ccc;
  }
}

TS


interface WaveConfig {
  /** 波浪颜色 */
  colors: string[];
  /** 想要的波浪高度 */
  waveHeight: number;
}

const config:WaveConfig ={
  waveHeight: 240,
  colors: ['#44c7b399'],
};

const canvas = new fabric.StaticCanvas('fabric'); // 初始化绑定画布
const height = canvas.getHeight(); // 获取画布的高度
const width = canvas.getWidth(); // 获取画布的宽度
const waveHeight = height - config.waveHeight; // 波浪高度
let step = 0; // 位移长度

上述代码中的step变量代表点在x轴上走过的路程。

3.3、绘制贝塞尔曲线

接下来我们先利用Path类画出一条贝塞尔曲线。由于画线时我们需要获取点的y轴值,所以我们把step比作正弦函数的x,带入进正弦函数中拿到曲线对应的y值。

const angle = step * Math.PI / 180; // 由于step是长度,首先得转换成角度
const Y1 = Math.sin(angle) + waveHeight; // 拿到第一个控制点的高度
// 拿到第二个控制点的高度,也可以写成 Math.sin(angle + Math.PI / 2) + waveHeight
const Y2 = Math.cos(angle) + waveHeight;

在这里我们选取画布对称分布的两个位置为控制点的x

const X1 = width / 3;
const X2 = width / 3 * 2;

接下来绘制我们的贝塞尔曲线

const line = new fabric.Path(` M 0 ${waveHeight + Y1} C ${X1} ${waveHeight + Y1}, ${X2} ${waveHeight + Y2}, ${width} ${waveHeight + Y2} L ${width} ${height} L 0 ${height} L 0 ${height / 2 + Y1} Z`,
    { fill: config.colors[0], stroke: '' });

最后让step改变,以启动我们的波浪动画

  let step = 0;
  interval = setInterval(() => {
    // 清空画布
    canvas.clear();
    step += config.value.speed; // 控制波浪的变化速度
    const angle = step * Math.PI / 180;
    const Y1 = Math.sin(angle) + waveHeight;
    const Y2 = Math.cos(angle) + waveHeight;
    const X1 = width / 3;
    const X2 = width / 3 * 2;
    const line = new fabric.Path(` M 0 ${waveHeight + Y1} C ${X1} ${waveHeight + Y1}, ${X2} ${waveHeight + Y2}, ${width} ${waveHeight + Y2} L ${width} ${height} L 0 ${height} L 0 ${height / 2 + Y1} Z`,
      { fill: config.colors[0], stroke: '' });
    // 添加到画布中
    canvas.add(line);
  }, 15);

四、完整代码

到此一个基本的动画就完成了,我们可以在上面进行拓展,通过调整一些参数来改变波浪动画的细节效果,例如波浪速度、波浪起伏高度、波浪条数等等。

HTML

<template>
  <div class="container">
    <canvas class="canvas" id="fabric" width="500" height="500"></canvas>
  </div>
</template>

SCSS

.container {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;

  .canvas {
    border: 1px solid #ccc;
  }
}

TS

import { fabric } from "fabric";
import { onMounted, ref, onBeforeUnmount } from "vue";

onMounted(() => {
  const canvas = new fabric.StaticCanvas('fabric');
  const height = canvas.getHeight();
  const width = canvas.getWidth();
  const waveTrajectory = config.value.waveTrajectory; // 波浪运动轨迹
  const waveFluctuate = config.value.waveFluctuate; // 波浪起伏高度
  const waveHeight = height - config.value.waveHeight; // 波浪高度
  waterStartMove();
});

onBeforeUnmount(() => {
  clearInterval(interval);
})

interface WaveConfig {
  /** 波浪条数 */
  lines: number;
  /** 波浪颜色 */
  colors: string[];
  /** 波浪高度 */
  waveHeight: number;
  /** 波浪的变化速度 */
  speed: number;
  /** 波浪运动轨迹 */
  waveTrajectory: number;
  /** 波浪的起伏高度 */
  waveFluctuate: number;
}

const config = ref<WaveConfig>({
  lines: 2,
  waveHeight: 240,
  colors: ['#44c7b399', '#44c7b34d'],
  speed: 2,
  waveTrajectory: 90,
  waveFluctuate: 8
});

let interval: any;

/** * 让水动起来 */
function waterStartMove(): void {
    let step = 0;
    // 清空
    canvas.clear();
    step += config.value.speed; // 控制波浪的变化速度
    for (let i = 0; i < config.value.lines; i++) {
      const angle = (step + i * waveTrajectory / config.value.lines) * Math.PI / 180;
      const deltaHeight = Math.sin(angle) * waveFluctuate;
      const deltaHeightRight = Math.cos(angle) * waveFluctuate;
      const line = new fabric.Path(` M 0 ${waveHeight + deltaHeight} C ${width / 3} ${waveHeight + deltaHeight - waveFluctuate}, ${width / 3 * 2} ${waveHeight + deltaHeightRight - waveFluctuate}, ${width} ${waveHeight + deltaHeightRight} L ${width} ${height} L 0 ${height} L 0 ${height / 2 + deltaHeight} Z`,
        { fill: config.value.colors[i], stroke: '' });
      canvas.add(line);
    }
    requestAnimationFrame(() => {
      waterStartMove();
    });
}

五、参考链接

vue3+ts canvas实现贝塞尔曲线波浪特效

svg中path贝塞尔曲线和圆弧

贝塞尔曲线 – 中文维基百科

JSDoc: Class: Path

今天的文章使用Fabric.js实现贝塞尔曲线波浪特效分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/21946.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注