canvas动态画贝塞尔曲线

canvas实现动态贝塞尔曲线效果,实现如下:

1、接口:

interface lineParams {
  start: Array;
  end: Array;
  curveness: number;
  percent: number;
}
export { lineParams };

2、js代码:

import React, { useRef, useEffect } from 'react';
import { lineParams } from './model';

const LineAnimate = () => {
  let canvas: any = null;
  let ctx: any = null;
  let percent: number = 0;
  const canvasWrapRef = useRef(null);
  const canvasRef = useRef(null);
  // canvas初始化
  const initCanvas = () => {
    const canvasWrap = canvasWrapRef.current;
    canvas = canvasRef.current;
    canvas.height = canvasWrap.offsetHeight;
    canvas.width = canvasWrap.offsetWidth;
    ctx = canvas.getContext('2d');
  };
  /**
   * 绘制一条曲线路径
   * @param  {Object} ctx canvas渲染上下文
   * @param  {Array} start 起点
   * @param  {Array} end 终点
   * @param  {number} curveness 曲度(0-1)
   * @param  {number} percent 绘制百分比(0-100)
   */
  const drawCurvePath = ({ start, end, curveness, percent }) => {
    const cp: Array = [
      (start[0] + end[0]) / 2 - (start[1] - end[1]) * curveness,
      (start[1] + end[1]) / 2 - (end[0] - start[0]) * curveness,
    ];

    const t: number = percent / 100;

    const p0: Array = start;
    const p1: Array = cp;
    const p2: Array = end;
    // 向量
    const v01: Array = [p1[0] - p0[0], p1[1] - p0[1]];
    // 向量
    const v12: Array = [p2[0] - p1[0], p2[1] - p1[1]];

    const q0: Array = [p0[0] + v01[0] * t, p0[1] + v01[1] * t];
    const q1: Array = [p1[0] + v12[0] * t, p1[1] + v12[1] * t];
    // 向量
    const v: Array = [q1[0] - q0[0], q1[1] - q0[1]];

    const b: Array = [q0[0] + v[0] * t, q0[1] + v[1] * t];

    ctx.moveTo(p0[0], p0[1]);

    ctx.quadraticCurveTo(q0[0], q0[1], b[0], b[1]);
  };
  // 画坐标轴
  const drawCoordinate = () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.strokeStyle = '#ccc';
    ctx.fillStyle = '#ccc';
    // 画x轴
    ctx.moveTo(32, canvas.height - 32);
    ctx.lineTo(canvas.width - 32, canvas.height - 32);
    // 画x轴坐标三角形
    ctx.moveTo(canvas.width - 40, canvas.height - 32);
    ctx.lineTo(canvas.width - 40, canvas.height - 36);
    ctx.lineTo(canvas.width - 32, canvas.height - 32);
    ctx.lineTo(canvas.width - 40, canvas.height - 28);
    ctx.lineTo(canvas.width - 40, canvas.height - 32);
    // 画y轴
    ctx.moveTo(32, canvas.height - 32);
    ctx.lineTo(32, 32);
    // 画y轴坐标三角形
    ctx.moveTo(32, 40);
    ctx.lineTo(28, 40);
    ctx.lineTo(32, 32);
    ctx.lineTo(36, 40);
    ctx.lineTo(32, 40);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();
  };
  // 绘制贝塞尔曲线
  const drawQuadraticLine = () => {
    const params: lineParams = {
      start: [32, canvas.height - 32],
      end: [canvas.width - 32, 48],
      curveness: -0.3,
      percent,
    };
    ctx.beginPath();
    ctx.strokeStyle = '#b17ffe';
    ctx.lineWidth = 1;
    drawCurvePath(params);

    percent = (percent + 1) % 100;
    if (percent === 0) {
      setTimeout(() => {
        percent = 0;
        drawCoordinate();
      }, 500);
    }
    ctx.stroke();
    requestAnimationFrame(drawQuadraticLine);
  };
  useEffect(() => {
    initCanvas();
    drawCoordinate();
    drawQuadraticLine();
  }, []);
  return (
    
); }; export default LineAnimate;

3、css代码:

{
    border: 1px solid #e8eaec;
    display: inline-block;
    height: 176px;
    margin-right: 32px;
    vertical-align: top;
    width: 176px;
    &:hover {
      box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
    }
}

4、效果图:

canvas动态画贝塞尔曲线_第1张图片

随笔小结,不喜勿喷,谢谢。

你可能感兴趣的:(canvas)