重学 javascript 之三角函数

重学 javascript 之三角函数

Tags
Javascript
Math
Published
Mar 18, 2020

起因

最近有一个需求,需要在一个环形图上面根据角度画一条标线。
类似这样:
notion image
第一个想法就是用三角函数算出起点和终点的坐标,无奈数学都还给老师了,就按照记忆里的三角函数知识补了补课。
但是落到代码上的时候发现,javascript Math.sin()Math.cos() 的表现好像和预期不太一样?
 

弧度制

第一个问题是Math.sin(x:number):number 接收的参数 x 不是在 CSS 中常用的角度单位 Deg,是角度的弧度表示。
首先 度(deg)弧度(rad) 都是平面角的单位。
单位弧度定义为圆弧长度等于半径时的圆心角。
notion image
根据公式圆的周长为 2πr。所以一个圆的弧度为 2π。
一个圆的角度是360°。所以 2πrad = 360°,πrad = 180°。1rad 也就等于 180°/π,约57.3°。
搞清楚了角度和弧度的转换,就可以使用前端比较熟悉的角度为单位来封装组件了。
 

三角函数的单位圆定义

知道了入参代表的含义,我们还需要知道Math.sin(x:number):number 返回值代表的含义。
Math.sin(x:number):number 方法返回一个 -1 到 1 之间的数值,想弄清楚这个数值代表的含义,需要知道一个知识点,三角函数的单位圆定义。
 
在直角三角形中,正弦、余弦以及其它三角函数只有当角度大于 0 且小于 π/2 (这里的 π/2 为弧度,即 90°) 时才有意义。
但是,在单位圆上,对于任意的实数角度,这些函数都有直观的意义。如图:
 
notion image
 
 
正弦函数与余弦函数可以用如下方法定义。
notion image
设圆心为(0,0),这里的 x、y 就是当圆的半径为 1 时,点以圆心为坐标系的坐标。
 

落到 canvas 上

环形图是使用图表库画的,不需要我操心。
但是想在 canvas 中画一条线,就需要知道起点和终点相对于 canvas 的计算机坐标系的坐标。
 
我们需要对三角函数的单位圆坐标系进行转换和平移。平移的过程如下。
  1. 首先要改变 y 轴方向,计算机坐标系的 y 轴正值朝下,圆的坐标系的 y 轴正值朝上,所以要 y = -y。
  1. 之后就是将坐标系平移到左上,x 和 y 都要加上圆心在计算机坐标系上的位置,得出的就是计算机坐标系的坐标。
 

demo

代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <canvas id="canvas" width="300" height="300"></canvas> <div style="width: 300px; text-align: center" id="text"></div> <script defer> function renderMarkLine(deg) { // 以 12 点钟方向为起点的顺时针角度,这样比较容易理解。 deg = deg || 0; const canvasElement = document.getElementById("canvas"); const context = canvasElement.getContext("2d"); context.clearRect(0, 0, canvasElement.width, canvasElement.height); const center = [150, 150]; const radius = 100; context.strokeStyle = "#000"; context.lineWidth = 10; // 画环 context.beginPath(); context.arc(center[0], center[1], radius, 0, 2 * Math.PI); context.stroke(); // 画标线 const clockwiseDeg = (360 + (90 - deg)) % 360; const clockwiseRad = (clockwiseDeg / 180) * Math.PI; // 圆坐标系中的坐标 const markLineStart = [ radius * 0.8 * Math.cos(clockwiseRad), radius * 0.8 * Math.sin(clockwiseRad), ]; const markLineEnd = [ radius * 1.2 * Math.cos(clockwiseRad), radius * 1.2 * Math.sin(clockwiseRad), ]; // 计算机坐标系中的坐标 const canvasMarkLineStart = [ center[0] + markLineStart[0], center[1] - markLineStart[1], ]; const canvasMarkLineEnd = [ center[0] + markLineEnd[0], center[1] - markLineEnd[1], ]; // 绘制标线 context.beginPath(); context.strokeStyle = "red"; context.moveTo(...canvasMarkLineStart); context.lineTo(...canvasMarkLineEnd); context.stroke(); } let deg = 0; const textElement = document.getElementById("text"); function render() { renderMarkLine(deg); textElement.textContent = `deg: ${deg}`; } render(); setInterval(() => { deg += 30; render(); }, 1500); </script> </body> </html>
 
参考资料:
  1. https://zh.wikipedia.org/wiki/单位圆
  1. https://zh.wikipedia.org/wiki/弧度

Loading Comments...