JS之Math.sin与Math.cos介绍及应用-实现鼠标点击后的烟花效果
基本介绍
Math.sin(x) :x 的正玄值。返回值在 -1.0 到 1.0 之间;
Math.cos(x) :x 的余弦值。返回的是 -1.0 到 1.0 之间的数;
其中函数中是x是指“弧度”而非角度。
弧度定义:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当这段弧长正好等于圆的半径时,两条射线的夹角大小为1弧度(单位:rad)。
角度定义:两条射线从圆心向圆周射出,形成一个夹角和夹角正对的一段弧。当弧长正好等于圆周长的360分之一时,两条射线的夹角的大小为1度。(单位: º)
如图所示:
角度转弧度(弧度计算公式):2π / 360 = π / 180 ≈ 0.0174rad, 即: 度数 * (π / 180) = 弧度
弧度转角度(角度计算公式): 360 / 2π = 180 / π ≈ 57.3º, 即: 弧度 * (180 / π) = 度数
// 将30º转为弧度rad 30º * (π / 180)= 0.523320 rad // 将0.523320rad转为度º 0.523320rad * (180 / π) = 29.9992352688º
可参考:
特殊值:
度
|
0°
|
30°
|
45°
|
60°
|
90°
|
120°
|
135°
|
150°
|
180°
|
270°
|
360°
|
弧度
|
0
|
π/6
|
π/4
|
π/3
|
π/2
|
2π/3
|
3π/4
|
5π/6
|
π
|
3π/2
|
2π
|
正弦函数和余弦函数的图像如图所示:
实例
实例1:如何得到圆上每个点的坐标?
解决思路:根据三角形的正玄、余弦来得值;
假设一个圆的圆心坐标是(a,b),半径为r,
则圆上每个点的X坐标=a + Math.sin(2*Math.PI / 360) * r ;Y坐标=b + Math.cos(2*Math.PI / 360) * r ;
实例2:如何求时钟的秒针转动一圈的轨迹?
假设秒针的初始值(起点)为12点钟方向,圆心的坐标为(a,b)。
解决思路:一分钟为60秒,一个圆为360°,所以平均每秒的转动角度为 360°/60 = 6°;
for(var times=0; times<60; times++) { var hudu = (2*Math.PI / 360) * 6 * times; var X = a + Math.sin(hudu) * r; var Y = b - Math.cos(hudu) * r // 注意此处是“-”号,因为我们要得到的Y是相对于(0,0)而言的。 }
注意:
1、本例是以“12点为起点, 角度增大时为顺时针方向“,求X坐标和Y坐标的方法是:
X坐标=a + Math.sin(角度 * (Math.PI / 180)) * r ;
Y坐标=b - Math.cos(角数 * (Math.PI / 180)) * r ;
2、一般“3点为起点, 角度增大时为逆时针方向“,求X坐标和Y坐标的方法是:
X坐标 = a + Math.cos(角度 * (Math.PI / 180)) * r;
Y坐标 = b - Math.sin(角度 * (Math.PI / 180)) * r;
实例3:使用Math.sin与Math.cos实现鼠标点击后的烟花效果
cursor-effects.js网上代码:
class Circle { constructor({ origin, speed, color, angle, context }) { this.origin = origin this.position = { ...this.origin } this.color = color this.speed = speed this.angle = angle this.context = context this.renderCount = 0 } draw() { this.context.fillStyle = this.color this.context.beginPath() this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2) this.context.fill() } move() { this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3) this.renderCount++ } } class Boom { constructor ({ origin, context, circleCount = 10, area }) { this.origin = origin this.context = context this.circleCount = circleCount this.area = area this.stop = false this.circles = [] } randomArray(range) { const length = range.length const randomIndex = Math.floor(length * Math.random()) return range[randomIndex] } randomColor() { const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F'] return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) } randomRange(start, end) { return (end - start) * Math.random() + start } init() { for(let i = 0; i < this.circleCount; i++) { const circle = new Circle({ context: this.context, origin: this.origin, color: this.randomColor(), angle: this.randomRange(Math.PI - 1, Math.PI + 1), speed: this.randomRange(1, 6) }) this.circles.push(circle) } } move() { this.circles.forEach((circle, index) => { if (circle.position.x > this.area.width || circle.position.y > this.area.height) { return this.circles.splice(index, 1) } circle.move() }) if (this.circles.length == 0) { this.stop = true } } draw() { this.circles.forEach(circle => circle.draw()) } } class CursorSpecialEffects { constructor() { this.computerCanvas = document.createElement('canvas') this.renderCanvas = document.createElement('canvas') this.computerContext = this.computerCanvas.getContext('2d') this.renderContext = this.renderCanvas.getContext('2d') this.globalWidth = window.innerWidth this.globalHeight = window.innerHeight this.booms = [] this.running = false } handleMouseDown(e) { const boom = new Boom({ origin: { x: e.clientX, y: e.clientY }, context: this.computerContext, area: { width: this.globalWidth, height: this.globalHeight } }) boom.init() this.booms.push(boom) this.running || this.run() } handlePageHide() { this.booms = [] this.running = false } init() { const style = this.renderCanvas.style style.position = 'fixed' style.top = style.left = 0 style.zIndex = '999999999999999999999999999999999999999999' style.pointerEvents = 'none' style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight document.body.append(this.renderCanvas) window.addEventListener('mousedown', this.handleMouseDown.bind(this)) window.addEventListener('pagehide', this.handlePageHide.bind(this)) } run() { this.running = true if (this.booms.length == 0) { return this.running = false } requestAnimationFrame(this.run.bind(this)) this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight) this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight) this.booms.forEach((boom, index) => { if (boom.stop) { return this.booms.splice(index, 1) } boom.move() boom.draw() }) this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight) } } const cursorSpecialEffects = new CursorSpecialEffects() cursorSpecialEffects.init()
优化后的代码:
class Circle { constructor({origin,context,color,angle,speed}) { this.position = {...origin}; this.context = context; this.color = color; this.angle = angle; this.speed = speed; this.renderCount = 0; } draw() { this.context.fillStyle = this.color; this.context.beginPath(); this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2, false); this.context.fill(); } move() { this.position.x += Math.sin(this.angle) * this.speed; this.position.y += Math.cos(this.angle) * this.speed + this.renderCount * 0.3; this.renderCount ++; } } class Boom { constructor({origin,context,area,circleNum = 10}) { this.origin = origin; this.context = context; this.area = area; this.circleNum = circleNum; this.circles = []; this.stop = false; } randomColor() { const rang = '89ABCDEF'; const num = 6; let resultStr = ''; for(let i = 0, num = 6; i < num; i++) { resultStr += rang.charAt(Math.floor(rang.length * Math.random())); } return '#' + resultStr; } randomRange(start,end) { return start + Math.random() * (end - start) } init() { for(let i = 0; i < this.circleNum; i++) { const circle = new Circle({ origin: this.origin, context: this.context, color: this.randomColor(), angle: this.randomRange(Math.PI / 2, Math.PI * 3 / 2), speed: this.randomRange(1,6) }) this.circles.push(circle); } } move() { for(let i = 0; i < this.circles.length; i++) { const curCircle = this.circles[i]; if(curCircle.x >= this.area.width || curCircle.y >= this.area.height) { this.circles.splice(i,1); i--; continue; } curCircle.move(); } if(this.circles.length === 0) { this.stop = true; } } draw() { this.circles.forEach((circle) => circle.draw()); } } class MouseClickEffect { constructor() { this.drawCanvas = document.createElement('canvas'); this.drawContext = this.drawCanvas.getContext('2d'); const style = this.drawCanvas.style; style.left = style.top = 0; style.position = 'fixed'; style.zIndex = '999999999'; style.pointerEvents = 'none'; this.drawCanvas.width = this.globalWidth = window.innerWidth; this.drawCanvas.height = this.globalHeight = window.innerHeight; document.body.appendChild(this.drawCanvas); this.booms = []; this.running = false; window.addEventListener('mousedown', this.handleMouseDown.bind(this)); window.addEventListener('resize',this.changeWindow.bind(this)); } handleMouseDown(e) { const boom = new Boom({ origin: {x: e.clientX, y: e.clientY}, area: {width: this.globalWidth, height: this.globalHeight}, context: this.drawContext }); boom.init(); this.booms.push(boom); this.running || this.run(); } changeWindow() { this.booms = []; this.running = false; this.drawCanvas.width = this.globalWidth = window.innerWidth; this.drawCanvas.height = this.globalHeight = window.innerHeight; this.drawContext.clearRect(0, 0, this.globalWidth, this.globalHeight); } run() { this.running = true; if(this.booms.length === 0) { return this.running = false; } requestAnimationFrame(this.run.bind(this)); this.drawContext.clearRect(0, 0, this.globalWidth, this.globalHeight); for(let i = 0; i < this.booms.length; i++) { const boom = this.booms[i]; if(boom.stop) { this.booms.splice(i, 1); i--; continue; } boom.move(); boom.draw(); } } } new MouseClickEffect();