ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

一个浪漫又悲情的爱情故事——笛卡尔心形线

2020-06-02 19:05:16  阅读:607  来源: 互联网

标签:方程 心形 canvas 悲情 context var 爱情故事 心形线 Math


说明

写这篇文章是因为某天看到这样一个公式 r=a(1-cosθ) ,我上网搜了下,原来是笛卡尔心形线的极坐标方程,这个方程里面的确有一个浪漫又悲情的爱情故事,感兴趣的朋友可以点这里看看,而至于这个故事是真是假,这 并不重要。

而这篇文章的目的是要用前端的方式,画出笛卡尔心形线。
本来我想,这么经典的公式,网上应该已经有人实现过了吧。
我搜了搜,不得不佩服网友们,有 Java 实现的有 C# 实现的也有 canvas 实现的还能用 ECharts 画 ,可以学习学习。

好的,开始正文!
先来了解下心形线

心形线,是一个圆上的固定一点在它绕着与其相切且半径相同的另外一个圆周滚动时所形成的轨迹,因其形状像心形而得名。

图片描述

因为 canvas 是直角坐标系的,所以先来看

平面直角坐标系 画法

先贴出网上搜来的 心形线的平面直角坐标系方程表达式
分别为 x^2+y^2+a*x=a*sqrt(x^2+y^2)x^2+y^2-a*x=a*sqrt(x^2+y^2

为什么会有两个方程表达式?
因为心形线的水平方向 和 垂直方向 对应的方程表达式不同,而用相同的方程表达式画的心形线,把每个点的 x 坐标和 y 坐标交换下,又会改变方向,所以会有两个方程表达式。

图片描述

好了,开始画吧,看看这位朋友的做法
思路
根据方程表达式得到所有点的坐标,然后把每个点连接起来,然后填充,最后就行成一个心形了。

参数方程

x=a*(2*sin(t)+sin(2*t))
y=a*(2*cos(t)+cos(2*t))

x,y 分别表示一个点的 x 坐标 和 y 坐标,
a:是一个常数,用来控制心形的大小,
t :代表 弧度
t 的取值范围:-pi<=t<=pi 或 0<=t<=2*pi

代码

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
    <canvas width="400" height="400"></canvas>

    <script>
        var canvas = document.querySelector('canvas');
        var context = canvas.getContext('2d');  
        context.lineWidth = 3;
        // 将画布的原点(0,0),移动到(200,200)
        // 移动原点是为了能让整个心形显示出来
        context.translate(200,200); 

        // t 代表弧度
        var t=0;
        // maxt 代表 t 的最大值
        var maxt = 2*Math.PI;
        // vt 代表 t 的增量
        var vt = 0.01;
        // 需要循环的次数
        var maxi = Math.ceil(maxt/vt);
        // 保存所有点的坐标的数组
        var pointArr=[];
        // x 用来暂时保存每次循环得到的 x 坐标
        var x=0;
        // y 用来暂时保存每次循环得到的 y 坐标
        var y=0;

        // 根据方程得到所有点的坐标
        for(var i=0;i<=maxi;i++){
            // x=a*(2*sin(t)+sin(2*t))
            x=50*(2*Math.sin(t)+Math.sin(2*t));

            // y=a*(2*cos(t)+cos(2*t))
            y=50*(2*Math.cos(t)+Math.cos(2*t));
            t+=vt;
            pointArr.push([x,y]); 
        }

        // 根据点的坐标,画出心形线
        context.moveTo(pointArr[0][0],pointArr[0][1]);
        draw();
        function draw(){
            context.fillStyle='#c00';
            // 把每个点连接起来
            for(var i=1;i<pointArr.length;i++){
                x = pointArr[i][0];
                y = pointArr[i][1];
                context.lineTo(x,y);
            }
            context.fill();
        }
    </script>
 </body>
</html>

效果图

图片描述

平面直角坐标系 画法 (空心心形)

上面的代码是画一个实心的心形,当然我们也可以画空心的,只需要做出一点点的修改就可以。
我们只需要改改 draw( ) 函数就好,把原来的 fill( ) 方法,改为 stroke( ) 方法,并且把 strokeStyle 设置了颜色就行了。

function draw(){
    //context.fillStyle='#c00';
    context.strokeStyle='#c00';
    // 把每个点连接起来
    for(var i=1;i<pointArr.length;i++){
        x = pointArr[i][0];
        y = pointArr[i][1];
        context.lineTo(x,y);
    }
    //context.fill();
    context.stroke();
}

图片描述

极坐标系画法

极坐标系是这样的

图片描述

极坐标系中确定一个点的位置,靠的是极点(图中点O),和 角度 来确定的。
更多关于极坐标系的知识,可以看看这里

看看这位朋友的做法
思路
根据极坐标方程 r=a(1+sinθ) ,得到 r ,以 r 作为半径,根据 r 连续的去画圆弧,画完一圈后,心形就出来了。

心形线 极坐标方程
r=a(1+sinθ)

代码

<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
</head>

<body>
  <canvas width="400" height="400"></canvas>

  <script>
    var canvas = document.querySelector('canvas');
    var context = canvas.getContext('2d');
    // 将画布的原点(0,0),移动到(200,100)
    // 移动原点是为了能让整个心形显示出来
    context.translate(200, 100);

    // 画心形
    draw();
    function draw() {
      // 画圆弧时,圆的半径
      var r = 0;
      //  start 代表画弧线时的 起始角
      var start = 0;
      //  end 代表画弧线时的 结束角
      var end = 0;
      //  一个常数,用来控制心形的大小
      var a = 100;

      context.fillStyle = '#e21f27';
      //连续的画圆弧
      for (var q = 0; q < 500; q++) {
        start += Math.PI * 2 / 500;
        // 当 结束角 是 Math.PI * 2 时也就是已经画了一圈了,心形就出来了
        end = start + Math.PI * 2 / 500;
        // 根据极坐标方程 r=a(1+sinθ),得到 r(半径)
        r = a * (1 + Math.sin(start)); 
        // 画弧线
        context.arc(0, 0, r, start, end, false);
      }
      context.fill();
    }
  </script>
</body>
</html>

效果图

图片描述

极坐标系 画法 (空心心形)

用极坐标系 画法,画空心心形,也是一样的需要改改 draw( ) 函数,把原来的 fill( ) 方法,改为 stroke( ) 方法,并且把 strokeStyle 设置了颜色就行了。

function draw() {
  var r = 0;
  var start = 0;
  var end = 0;
  var a = 100;

  //context.fillStyle = '#e21f27';
  context.strokeStyle = '#e21f27';
  for (var i = 0; i < 500; i++) {
    start += Math.PI * 2 / 500;
    end = start + Math.PI * 2 / 500;
    r = a * (1 + Math.sin(start)); 
    context.arc(0, 0, r, start, end, false);
  }
  //context.fill();
  // 改用 stroke() 方法
  context.stroke();   
}

图片描述

可能你会觉得这样的心形并不好看。
看看这个参数方程吧!

x=16 * (sin(t)) ^ 3;
y=13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)。

根据这个参数方程,用上面说的平面直角坐标系的画法,把代码里的方程换一下,就可以画出这样的心形。
图片描述

代码

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
    <canvas width="400" height="400"></canvas>

    <script>
        var canvas = document.querySelector('canvas');
        var context = canvas.getContext('2d');  
        context.lineWidth = 3;
        // 将画布的原点(0,0),移动到(200,200)
        // 移动原点是为了能让整个心形显示出来
        context.translate(200,200); 

        // t 代表弧度
        var t=0;
        // vt 代表 t 的增量
        var vt = 0.01;
        // maxt 代表 t 的最大值
        var maxt = 2*Math.PI;
        // 需要循环的次数
        var maxi = Math.ceil(maxt/vt);
        // 保存所有点的坐标的数组
        var pointArr=[];
        // 控制心形大小
        var size = 10;
        // x 用来暂时保存每次循环得到的 x 坐标
        var x=0;
        // y 用来暂时保存每次循环得到的 y 坐标
        var y=0;

        // 根据方程得到所有点的坐标
        for(var i=0;i<=maxi;i++){
            // x=16 * (sin(t)) ^ 3;
            var x = 16 * Math.pow(Math.sin(t),3);
            // y=13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)
            var y = 13 * Math.cos(t) - 5 * Math.cos(2 * t) -2 * Math.cos(3 * t)- Math.cos(4 * t);
            t+=vt;
            pointArr.push([x*size,-y*size]); 
        }

        // 根据点的坐标,画出心形线
        context.moveTo(pointArr[0][0],pointArr[0][1]);
        draw();
        function draw(){
            context.fillStyle='#c00';
            // 把每个点连接起来
            for(var i=1;i<pointArr.length;i++){
                x = pointArr[i][0];
                y = pointArr[i][1];
                context.lineTo(x,y);
            }
            context.fill();
        }
    </script>
 </body>
</html>

也许我们还可以再做点什么,比如加点动画,看看下面这个吧。

图片描述
这里下载源码,里面已经加了很详细的注释了。

总结

这篇文章主要是说用笛卡尔心形线方程画心形,但是想要画出心形的方式绝对是多种多样的,单纯的用CSS也可以,复杂点 用贝塞尔曲线也能画出来,大家不妨去试试,说不定又有什么新发现呢。

前端简单说

标签:方程,心形,canvas,悲情,context,var,爱情故事,心形线,Math
来源: https://www.cnblogs.com/10manongit/p/13033073.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有