Kros的博客 Kros的博客
首页
  • CSS
  • 工具
  • Vue
  • js
  • Vue3
  • 算法
  • 折腾笔记
一言
  • 分类
  • 标签
  • 归档
码云

Kros

凡心所向,素履以往,生如逆旅,一苇以航
首页
  • CSS
  • 工具
  • Vue
  • js
  • Vue3
  • 算法
  • 折腾笔记
一言
  • 分类
  • 标签
  • 归档
码云
  • CSS

  • JavaScript

  • 工具

  • Vue

    • vue批量引入组件
    • vue中watch用法
    • vue使用基础JSX语法
    • vue首页白屏
    • vue长列表优化
    • 模板文件中script、template、style存在必要性
    • popup弹窗组件
    • 使用$mount和extend扩展vue
    • 扩展toast合并popup(按需加载)
    • canvas实现弧形进度条
    • vue中使用CSS Modules
    • vue实现无限轮播图
    • vue半圆形菜单
    • 纯CSS实现圆形进度条
    • v-model简单实现
    • vue带箭头下拉框
    • vue事件修饰符
    • vue鼠标悬浮显示提示文字
    • vue添加发布版本号方法
    • vue配置全局样式文件
    • vue在env development中设置全局变量不生效
    • vue引入less或scss全局变量
    • vue中使用Keepalive
    • vue2为什么只支持一个根节点
    • vue打包优化分析工具—webpack-bundle-analyzer
    • vue使用echarts(按需加载)
    • echarts柱形图重合堆叠
    • vue使用draggable实现多列拖拽(解决空列不能拖拽问题)
    • vue禁止三方库打包到bundle中
    • npm run serve运行背后的思考
    • vxe-table树结构不允许insert
    • vue组件延迟加载
    • 多页面应用配置
    • vue项目常用优化
    • vue实现拖动拼图验证码
    • vue虚拟dom
    • canvas心形动画
    • canvas绘制玫瑰曲线
    • element表单validateField验证部分字段
    • element日期选择限制今天以后并精确到小时
    • 前端使用JSEncrypt和node-rsa进行rsa加密传输和接收解密
    • elementui日期选择器生日只选择月和日不选择年并隐藏年份
    • el-upload组件第二次点击手动submit时不生效
    • element表单内输入框使用@keyup enter native回车时会刷新页面
  • antdv踩坑记录

  • Vue3

  • 前端
  • Vue
kros
2023-02-28

canvas绘制玫瑰曲线

玫瑰曲线是指以一点为中心均匀分布花瓣的图形,是数学之美的完美体现 要想在程序中画出玫瑰曲线,这里有几个基础概念要先了解

1、玫瑰曲线表达式

x = r * Math.sin(n * angle) * Math.cos(angle)
y = r * Math.sin(n * angle) * Math.sin(angle)
1
2

表达式中存在两个常量r和n,r代表花瓣分布半径、n代表花瓣系数需为正数,angle代表当前曲线角度

2、闭合周期 闭合周期指绘制完整图形需要的角度,例如圆的闭合周期是2*PI,玫瑰曲线的闭合周期与它的系数n相关,具体如下

  • n为奇数:Math.PI
  • n为偶数:Math.PI * 2
  • n为分数L/M(L和M不能同时为偶数,需为最简分数):
  • L和M同时为奇数时闭合周期: Math.PI * M
  • L和M存在偶数时闭合周期: Math.PI * M * 2 有了以上两个为基础,我们就可以在程序中使用canvas来绘制玫瑰曲线了

# 第一步:获取x、y坐标

const getX = (t: number) => {   //获取玫瑰线的X坐标
  return 100 * Math.sin(L.value/M.value*t)*Math.cos(t);
}

const getY = (t: number) => {  //获取玫瑰线的Y坐标
  return 100 * Math.sin(L.value/M.value*t)*Math.sin(t);
}
1
2
3
4
5
6
7

# 第二步:计算闭合周期

根据上面闭合周期规则计算完整玫瑰曲线的闭合周期,整数情况下默认分母为1,代码如下:

const getFactor = () => {
  let lmPurify = purify(L.value, M.value)
  console.log(lmPurify)
  if (lmPurify[1] == 1) {
    // 正整数
    if (lmPurify[0] % 2 == 0) {
      // 偶数
      period.value = Math.PI * 2
    } else {
      // 奇数
      period.value = Math.PI
    }
    return lmPurify[0]
  } else {
    if (lmPurify[0] % 2 == 0 || lmPurify[1] % 2 == 0) {
      // 
      period.value = Math.PI * lmPurify[1] * 2
    } else {
      period.value = Math.PI * lmPurify[1]
    }
    return lmPurify[0] + '/' + lmPurify[1]
  }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

*注意:*计算闭合周期前需要将分子分母最简化,所以这里首先执行了purify函数

/* 最简分数 */
const purify = (l: number, m: number) => {
  let x, y;
  let son = l,mother = m;
  let j = 2;
  while (j <= son && j <= mother) {
    x = son / j;
    y = mother / j;
    ++j;
    if ((x + '').indexOf('.') == -1 && (y + '').indexOf('.') == -1) {
        son = x;
        mother = y;
        j = 2;
    }
  }
  return [son, mother];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 第三步:使用canvas绘制

  • 绘制前调用getFactor计算闭合周期
  • 设定每次移动举例Math.PI/180(越小越清晰)并清空画布、移动到初始位置
  • 判断已绘制的弧度是否达到闭合周期period,达到则停止绘制,未到达到则重复步骤
const draw = () => {
  getFactor()
  let drawing = document.getElementById("drawing") as HTMLCanvasElement; //获取canvas元素
  drawing.width = 500; //设置画布大小
  drawing.height = 500;
  if (drawing.getContext){  //获取绘图上下文
    let context = drawing.getContext("2d"),
      radian = 0,   //设置初始弧度
      radian_add = Math.PI/180;  //设置弧度增量
    if (context != null) {
      context.clearRect(0, 0, 500, 500);
      context.beginPath();  //开始绘图
      context.translate(250,250);  //设置绘图原点
      context.moveTo(getX(radian),getY(radian)); //移动绘图游标至原点
      while(radian <= period.value){  //每增加一次弧度,绘制一条线
        radian += radian_add;
        let X = getX(radian);
        let Y = getY(radian);
        context.lineTo(X,Y);
      }
      context.strokeStyle = "red";  //设置描边样式
      context.stroke();  //对路径描边
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

效果如下:

rose

# 优化:使用计时器实现动态绘制

修改上面绘制顺序,每移动一步就绘制颜色并延迟下一步绘制,代码如下:

const drawAnim = () => {
  getFactor()
  let drawing = document.getElementById("drawing") as HTMLCanvasElement; //获取canvas元素
  drawing.width = 500; //设置画布大小
  drawing.height = 500;
  if (drawing.getContext){  //获取绘图上下文
    let context = drawing.getContext("2d"),
      radian = 0,   //设置初始弧度
      radian_add = Math.PI/360;  //设置弧度增量
    if (context != null) {
      context.beginPath();  //开始绘图
      context.translate(250 + getX(radian),250 + getY(radian));  //设置绘图原点
      context.strokeStyle = "red";  //设置描边样式
      let timer: number;
      let lineFunc = () => {
        radian += radian_add;
        let X = getX(radian);
        let Y = getY(radian);
        context?.lineTo(X,Y);						
        context?.stroke();  //对路径描边
        
        if (radian > period.value) {
          clearInterval(timer)
        }
      }
      timer = setInterval(lineFunc, 5)
    }
    
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

rose-anim

完整代码自取

上次更新: 2025/09/05, 8:09:00
canvas心形动画
element表单validateField验证部分字段

← canvas心形动画 element表单validateField验证部分字段→

最近更新
01
Find the next perfect square
09-05
02
Regex validate PIN code
09-05
03
Find the odd int
09-05
更多文章>
Theme by Vdoing | Copyright © 2020-2025 kros king
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
icon-heart-o icon-heart icon-infinity icon-pause icon-play link next prev