• 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º 

    可参考:

    特殊值:

    30°
    45°
    60°
    90°
    120°
    135°
    150°
    180°
    270°
    360°
    弧度
    0
    π/6
    π/4
    π/3
    π/2
    2π/3
    3π/4
    5π/6
    π
    3π/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: {
             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: { 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();
  • 相关阅读:
    hdu 2200 Eddy's AC难题(简单数学。。)
    hdu 2201 熊猫阿波的故事(简单概率。。)
    hdu 2571 命运(水DP)
    hdu 2955 Robberies(背包DP)
    GDI+图形图像技术1
    C#笔记2__Char类、String类、StringBuilder类 / 正则表达式 /
    C#笔记1__命名空间 / 常量 / object / is、as、...?... :...
    VS2013快捷键及技巧 / 智能插件
    JAVA笔记15__TCP服务端、客户端程序 / ECHO程序 /
    JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池
  • 原文地址:https://www.cnblogs.com/moqiutao/p/13669549.html
Copyright © 2020-2023  润新知