zl程序教程

您现在的位置是:首页 >  前端

当前栏目

JavaScript 声波

2023-09-11 14:22:55 时间

这里写图片描述

<html>
    <head>
        <meta charset="utf8">
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=2.0 initial-scale=1.0, user-scalable=yes">
        <meta name="keywords" content="acoustic wave propagation">
        <meta name="description" content="声波传播,能量不断衰减,从而导致振幅先增大后减小,最终归零">
        <title>声波传播(acoustic wave propagation)</title>
        <style>
            body {
                color: white;
                background-color: #333;
                font-size: 16px;
            }
            controlDiv {
                margin: 40px auto;
            }
            label {
                /* 变为block之后后面的元素才会换行排列 */
                display: block;
            }
            input[type=range] {
                display: block;
            }
            #canvas {
                display: block;
                margin: 0 auto;
            }
        </style>
    </head>
    <body>
        <div id="controlDiv">
            <label id="attenuationCoefficientLabel">衰减系数: 2</label>
            <label>(越大, 边缘衰减的就越多, 震动宽度相应也越窄)</label>
            <input id="attenuationCoefficientRange" type="range" min="1" max="10" step="1" value="2"/>
            <label id="halfWaveCountLabel">半波长个数-1: 3</label>
            <input id="halfWaveCountRange" type="range" min="0" max="10" step="1" value="3"/>
            <label id="amplitudePercentageLabel">振幅: 3%</label>
            <input id="amplitudePercentageRange" type="range" min="0" max="100" step="1" value="90"/>
            <label id="radianStepLabel">角速度: 0.05</label>
            <label>(速度开始从右到左,先加快后减慢,最后变成左到右)</label>
            <input id="radianStepRange" type="range" min="0" max="3.15" step="0.01" value="0.05"/>
        </div>
        <canvas id="canvas">Your browser can not support canvas</canvas>
        <script>
            var doublePI = Math.PI * 2;
            var canvas;
            var ctx;

            //画布的高度的一半
            var halfCanvasHeight = 100;
            //水平边距
            var horizontalMargin = 150; 

            //衰减系数(越大, 边缘衰减的就越多, 震动宽度相应也越窄)
            var attenuationCoefficient = 2;
            //半波长个数-1
            var halfWaveCount = 3;
            //振幅是画布高度的一般的百分比[0,1]
            var amplitudePercentage = 0.9;
            //每帧增加的弧度[0,2PI](作用于sin曲线, 正值相当于原点右移, 曲线左移)
            var radianStep = 0.05;

            //当前弧度的偏移
            var radianOffset = 0;
            //画布宽度
            var canvasWidth;

            function init() {
                canvas = document.getElementById("canvas");
                ctx = canvas.getContext("2d");

                var attenuationCoefficientLabel = document.getElementById("attenuationCoefficientLabel");
                var attenuationCoefficientRange = document.getElementById("attenuationCoefficientRange");
                var halfWaveCountLabel = document.getElementById("halfWaveCountLabel");
                var halfWaveCountRange = document.getElementById("halfWaveCountRange");
                var amplitudePercentageRangeLabel = document.getElementById("amplitudePercentageRangeLabel");
                var amplitudePercentageRangeRange = document.getElementById("amplitudePercentageRangeRange");
                var radianStepLabel = document.getElementById("radianStepLabel");
                var radianStepRange = document.getElementById("radianStepRange");

                attenuationCoefficientRange.addEventListener("change", function() {
                    attenuationCoefficient = parseInt(event.target.value);
                    attenuationCoefficientLabel.innerHTML = "衰减系数AC: " + attenuationCoefficient;
                });
                halfWaveCountRange.addEventListener("change", function() {
                    halfWaveCount = parseInt(event.target.value);
                    halfWaveCountLabel.innerHTML = "半波长个数-1: " + halfWaveCount;
                });
                amplitudePercentageRange.addEventListener("change", function() {
                    amplitudePercentage = parseInt(event.target.value) / 100;
                    amplitudePercentageLabel.innerHTML = "振幅: " + event.target.value + "%";
                });
                radianStepRange.addEventListener("change", function() {
                    radianStep = parseFloat(event.target.value);
                    radianStepLabel.innerHTML = "角速度: " + radianStep;
                });

                window.addEventListener("resize", onResize);

                canvas.height = halfCanvasHeight * 2;
                onResize();
                loop();
            }

            function onResize() {
                //元素的大小不能加单位, 单位默认就是像素, 而style中的长度要加单位
                canvasWidth = canvas.width = window.innerWidth - horizontalMargin;
            }

            //设K=attenuationCoefficient, 计算信号衰减 (4K/(4K+x^4))^2K<=1 (x belong [-K,K])
            function calcAttenuation(x) {
                return Math.pow(4 * attenuationCoefficient / (4 * attenuationCoefficient + Math.pow(x, 4)), 2 * attenuationCoefficient);
            }

            //heightPercentage为振幅的显示比例
            function drawAcousticWave(heightPercentage, alpha, lineWidth) {
                ctx.strokeStyle = "white";
                ctx.globalAlpha = alpha;
                ctx.lineWidth = lineWidth || 1;
                ctx.beginPath();
                ctx.moveTo(0, halfCanvasHeight);
                var x,y;
                for(var i=-attenuationCoefficient; i<=attenuationCoefficient; i+=0.01) {
                    //i是当前位置相对于整个长度的比率( x=width*(i+K)/(2*K))
                    x = canvasWidth * (i + attenuationCoefficient) / (2 * attenuationCoefficient);
                    //加offset相当于把sin曲线向右平移
                    y = halfCanvasHeight + halfCanvasHeight * amplitudePercentage * calcAttenuation(i) * heightPercentage * Math.sin(halfWaveCount * i + radianOffset);
                    ctx.lineTo(x, y);
                }
                ctx.stroke();
            }

            function loop() {
                radianOffset = (radianOffset + radianStep) % doublePI;
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                drawAcousticWave(1, 1, 2);
                for(var i=2; i<4; i++) {
                    var reciprocal = 1 / i;
                    drawAcousticWave(reciprocal, reciprocal/2);
                    drawAcousticWave(-reciprocal, reciprocal/2);
                }
                requestAnimationFrame(loop);
            }

            init();
        </script>
    </body>
</html>

这里写图片描述