返回

用JavaScript随机生成SVG雪花

前端

春节前后,冬奥盛会在如火如荼的进行,偶然间在微信朋友圈看到了一个类似于冬奥专属雪花的链接,进去一看发现只是简单地通过CSS来模拟雪花效果,网页底端有个种子值,如果想分享这个雪花还可以生成分享链接,带着好奇心,点开了生成分享链接,得到了另外一个种子值,由此我开始思索,如果使用JS来生成这样的雪花会是什么样呢?是不是可以形成SVG来分享雪花并且在之后的任意时间都可以随意调整生成雪花呢?

基于这样的想法,首先我需要一个库来提供SVG功能,从众多库中选择react-svg-canvas,然后开始实现核心代码。当然,作为初学者不会画复杂的雪花,所以先画一个最简单的雪花形状。通过搜索资料后,得到以下公式,了雪花最简单的样式。

M10 20H14L24 44H48L52 40H64L46 10H41L35 30H19Z

雪花有6片花瓣,所以要复制上面这段路径然后旋转60度、120度、180度、240度、300度,最后形成一个完整的雪花。注意每个花瓣都得调整起始点,否则它将会从(10,20)开始画而不是从外接圆上开始。所有的步骤完成后,然后我们就得到以下路径:

M10 20H14L24 44H48L52 40H64L46 10H41L35 30H19Z
M27 11L24 28H38L56 6H31L22 21Z
M17 7L38 33H10L26 11Z
M5 18L10 43H60L55 31Z
M12 23L20 5H44L39 22Z
M48 11L51 18H61L41 42Z

就这样,通过JavaScript随机生成SVG雪花成功了。

现在,用代码来实现一下这个过程。

import { SVGCanvas, Path } from 'react-svg-canvas';

const App = () => {
  const [seed, setSeed] = useState(0);
  const [snowflakes, setSnowflakes] = useState([]);

  const generateSnowflake = () => {
    // 生成随机种子
    let randomSeed = Math.random();
    if (seed) {
      randomSeed = seed;
    }

    // 创建雪花路径
    const snowflakePath = `M10 20H14L24 44H48L52 40H64L46 10H41L35 30H19Z
    M27 11L24 28H38L56 6H31L22 21Z
    M17 7L38 33H10L26 11Z
    M5 18L10 43H60L55 31Z
    M12 23L20 5H44L39 22Z
    M48 11L51 18H61L41 42Z`;

    // 旋转雪花路径
    const rotatedPaths = [];
    for (let i = 0; i < 6; i++) {
      const angle = i * 60;
      const rotatedPath = rotatePath(snowflakePath, angle);
      rotatedPaths.push(rotatedPath);
    }

    // 组合雪花路径
    const combinedPath = rotatedPaths.join(' ');

    // 创建雪花元素
    const snowflake = <Path path={combinedPath} stroke="black" strokeWidth="1" fill="none" />;

    // 更新雪花状态
    setSnowflakes([...snowflakes, snowflake]);
  };

  // 旋转路径函数
  const rotatePath = (path, angle) => {
    // 将路径转换为 SVGPathElement 对象
    const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    pathElement.setAttribute('d', path);

    // 创建 SVGMatrix 对象并应用旋转变换
    const matrix = SVGMatrix.fromTranslate(0, 0);
    matrix.rotate(angle * Math.PI / 180);

    // 应用变换并返回结果
    pathElement.transform.baseVal.appendItem(matrix);
    return pathElement.getAttribute('d');
  };

  return (
    <div>
      <SVGCanvas width={600} height={600} backgroundColor="white">
        {snowflakes}
      </SVGCanvas>
      <button onClick={generateSnowflake}>生成雪花</button>
    </div>
  );
};

export default App;

最后将SVG矢量雪花分享给朋友们欣赏,大家对此次雪花的效果非常满意,并且还想让我添加更多的功能,比如自定义雪花颜色、大小、数量等,未来我会继续完善这个项目,添加更多有趣的功能。