2
\$\begingroup\$

Desired output: Animate the wave forms, but use less resources.

Any bugs: There are no bugs that I know of.

I tied searching google for "use less setIntervals in my project" and found this code

function interval(func, wait, times){ var interv = function(w, t){ return function(){ if(typeof t === "undefined" || t-- > 0){ setTimeout(interv, w); try{ func.call(null); } catch(e){ t = 0; throw e.toString(); } } }; }(wait, times); setTimeout(interv, wait); }; 

Usage: This replaces all of the setIntervals but the waves do not look random.

interval(function(){ peak_wave( Math.floor((Math.random() * (30) + 1)) , Math.floor((Math.random() * (200) + 150))); peak_wave( Math.floor((Math.random() * (30) + 1)) , Math.floor((Math.random() * (200) + 150))); },1200, 999); 

Problem: The code is a resource hog. I am looking for a way to optimize JavaScript (if JavaScript is the issue.)

Research: Looked for ways to reduce the number of set intervals I am using.

What I’ve tried: Setup a loop that creates the set intervals but I ran into the Issue where javascript blows through all the setintervals and they all start at the time time and fire at once. That is a HUGE resource issue.

Inspiration: YouTube: enter image description here Link to video: https://www.youtube.com/watch?v=-475XHUgkiQ&t=22782s&ab_channel=APMusic

My Code: CodePen.io: enter image description here Link to codepen.io: https://codepen.io/ac0ua/pen/BaReZEx

Thank you. Any help would be appreciated. I want to learn.

"use strict"; function peak_wave(wave_id, wave_height) { //console.log(wave_height); var wave = document.getElementsByClassName('w' + wave_id); var wave_height_buffer = wave_height; var a = 0; var i = 0; var counter = 0; var color = "white"; const waveLeftSide_arr = range(wave_id - 10, 10).reverse(); const waveRightSide_arr = range(wave_id + 1, 10); if (wave) { wave[0].style.height = wave_height + "px"; wave[0].style.background = color; wave[0].classList.toggle("l-active"); wave[1].style.height = wave_height + "px"; wave[1].style.background = color; wave[1].classList.toggle("r-active"); } var firstWaveClass = ""; for (let i of waveLeftSide_arr) { if (i <= -1) { i = 0 } counter = counter + 5 wave_height = wave_height - 10 - counter; const targetElement = document.querySelector('.w' + i); if (targetElement) { // var color = "yellowgreen"; document.getElementsByClassName('w' + i)[0].style.height = (wave_height) + "px"; document.getElementsByClassName('w' + i)[0].style.background = color; document.getElementsByClassName('w' + i)[1].style.height = (wave_height) + "px"; document.getElementsByClassName('w' + i)[1].style.background = color; } } wave_height = wave_height_buffer; counter = 0 for (let a of waveRightSide_arr) { if (a <= -1) { a = 0 } counter = counter + 5 wave_height = wave_height - 10 - counter; const targetElement = document.querySelector('.w' + a); if (targetElement) { if (firstWaveClass == "") { firstWaveClass = "w" + a; } // var color = "deeppinnk"; document.getElementsByClassName('w' + a)[0].style.height = (wave_height) + "px"; document.getElementsByClassName('w' + a)[0].style.background = color; document.getElementsByClassName('w' + a)[1].style.height = (wave_height) + "px"; document.getElementsByClassName('w' + a)[1].style.background = color; } } } function doesExist(class_name) { var element = document.getElementsByClassName(class_name) if (element > 0) { return true; } else { return false; } } setInterval(function() { var els = document.getElementsByClassName("wave"); for (var i = 0; i < els.length; i++) { // var NewHeight = els[i].offsetHeight - 10; // if(NewHeight <= 0){NewHeight = 0 } els[i].style.height = 0 + "px"; els[i].style.background = "white"; els[i].classList.remove("l-active"); els[i].classList.remove("r-active"); } }, 500); var circle = document.getElementsByClassName("circle")[0]; setInterval(function() { circle.style.transform = 'rotate(' + Math.floor((Math.random() * (180) + 1)) + 'deg)'; }, 120); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))); }, 1200); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))) }, 1300); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))) }, 1400); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))) }, 1500); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))) }, 100600); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))) }, 100700); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))) }, 100800); setInterval(function() { peak_wave(Math.floor((Math.random() * (30) + 1)), Math.floor((Math.random() * (200) + 150))) }, 100900); //peak_wave(50, 300); function range(start, count) { if (arguments.length == 1) { count = start; start = 0; } var foo = []; for (var i = 0; i < count; i++) { foo.push(start + i); } return foo; }
/* default template -- enable SCSS*/ html, body { width: 100%; height: 100%; margin: 0; padding: 0; background: #424242; color: white; font-family: bungee; display: flex; flex-direction: column; } html:before, body:before { content: " "; position: absolute; top: -40px; left: -60px; width: 50%; height: 400px; border-radius: 50%; background: linear-gradient(to bottom right, deepskyblue 20%, deepskyblue 50%, white 80%); filter: blur(80px); mix-blend-mode: overlay; } html header, body header { width: 100%; display: grid; place-items: center; } html section, body section { width: 100%; display: grid; place-items: center; } html section #wrapper, body section #wrapper { display: flex; place-items: center; flex-wrap: nowrap; justify-content: center; height: 200px; width: 80%; position: relative; margin-inline: 20px; } html section #wrapper:after, body section #wrapper:after { content: ""; position: absolute; background: white; background: radial-gradient(circle, white 26%, rgba(2, 0, 36, 0) 95%); height: 3px; width: 100%; } html section #wrapper #left-wrapper, body section #wrapper #left-wrapper { display: flex; flex-wrap: nowrap; justify-content: space-around; align-items: center; width: 45%; height: 100px; } html section #wrapper #left-wrapper span, body section #wrapper #left-wrapper span { display: inline-block; width: 5px; background: white; transition: height 0.3s cubic-bezier(0.83, 1.5, 0.63, -0.71); } html section #wrapper #right-wrapper, body section #wrapper #right-wrapper { display: flex; flex-wrap: nowrap; justify-content: space-around; align-items: center; width: 45%; height: 100px; } html section #wrapper #right-wrapper span, body section #wrapper #right-wrapper span { display: inline-block; min-width: 2px; background: white; transition: height 0.3s cubic-bezier(0.83, 1.5, 0.63, -0.71); } html section #wrapper .l-active, body section #wrapper .l-active { position: relative; } html section #wrapper .l-active:before, body section #wrapper .l-active:before { content: ""; margin-left: -100px; position: absolute; top: 50%; transform: translateY(-50%); height: 60%; width: 100px; border-top-left-radius: 25% 10%; border-bottom-left-radius: 25% 10%; background: radial-gradient(circle at 100% 53%, yellow 15%, #00bcd4 34%, rgba(238, 130, 238, 0) 100%); filter: blur(10px); z-index: 1; mix-blend-mode: overlay; transistion: 0.3s ease; } html section #wrapper .l-active:after, body section #wrapper .l-active:after { content: ""; margin-left: -250px; position: absolute; top: 50%; transform: translateY(-50%); height: 30%; width: 200px; border-top-left-radius: 25% 10%; border-bottom-left-radius: 25% 10%; background: radial-gradient(circle at 100% 53%, #ff00ef 15%, #005cd4 34%, rgba(238, 130, 238, 0) 100%); filter: blur(20px); z-index: 1; mix-blend-mode: overlay; transistion: 0.4s ease; } html section #wrapper .r-active, body section #wrapper .r-active { position: relative; } html section #wrapper .r-active:before, body section #wrapper .r-active:before { content: ""; margin-right: 100px; position: absolute; top: 50%; transform: translateY(-50%); height: 60%; width: 100px; border-top-left-radius: 25% 10%; border-bottom-left-radius: 25% 10%; background: radial-gradient(circle at 0% 53%, yellow 34%, #00bcd4 15%, rgba(238, 130, 238, 0) 100%); filter: blur(10px); z-index: 1; mix-blend-mode: overlay; transistion: 0.3s ease; } html section #wrapper .r-active:after, body section #wrapper .r-active:after { content: ""; margin-right: 250px; position: absolute; top: 50%; transform: translateY(-50%); height: 30%; width: 200px; border-top-left-radius: 25% 10%; border-bottom-left-radius: 25% 10%; background: radial-gradient(circle at 0% 53%, #ff00ef 34%, #005cd4 15%, rgba(238, 130, 238, 0) 100%); filter: blur(20px); z-index: 1; mix-blend-mode: overlay; transistion: 0.4s ease; } html section #wrapper .circle, body section #wrapper .circle { box-sizing: border-box; width: 100px; aspect-ratio: 1/1; border-radius: 50%; border: 10px solid white; position: relative; z-index: 2; display: grid; place-items: center; background: conic-gradient(from 90deg at 50% 50%, #ffff00 2%, #00bcd4 7%, #ee82ee 21%, #ffffff 26%, #ffffff 41%, #ffffff 49%, #fffc00 51%, #00bcd4 64%, #ee82ee 72%, #ffffff 77%, #ffffff 100%); transform: rotate(10deg); transition: all 0.2s cubic-bezier(0.83, 1.5, 0.63, -0.71); } html section #wrapper .circle .outter-record, body section #wrapper .circle .outter-record { box-sizing: border-box; width: 65px; height: 65px; border-radius: 50%; border: 5px solid white; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: grid; place-items: center; background: conic-gradient(from 90deg at 50% 50%, #ffff00 2%, #00bcd4 7%, #ee82ee 21%, #ffffff 26%, #ffffff 41%, #ffffff 49%, #fffc00 51%, #00bcd4 64%, #ee82ee 72%, #ffffff 77%, #ffffff 100%); } html section #wrapper .circle .outter-record .inner-record, body section #wrapper .circle .outter-record .inner-record { background: white; box-sizing: border-box; width: 45px; height: 45px; border-radius: 50%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: grid; place-items: center; } html footer, body footer { width: 100%; display: grid; place-items: center; } html h1, body h1 { color: deepskyblue; } html h1 span, body h1 span { color: yellowgreen; } html h1 font, body h1 font { color: yellowgreen; font-family: Montserrat; font-weight: 700; } html h2, body h2 { color: deepskyblue; font-family: Montserrat; } html h2 span, body h2 span { color: yellowgreen; } html h2 font, body h2 font { color: yellowgreen; font-weight: 700; } /* default template end */ .wave { background: deepskyblue; }
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Bungee&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;700&display=swap" rel="stylesheet"> <header> <h1>Audio <span>Candy</span></h1> </header> <Section> <h2>CSS<span> / </span>Javascript <font> Animation</font> </h2> <div id="wrapper"> <div id="left-wrapper"> <span class="wave w50">&nbsp;</span> <span class="wave w49">&nbsp;</span> <span class="wave w48">&nbsp;</span> <span class="wave w47">&nbsp;</span> <span class="wave w46">&nbsp;</span> <span class="wave w45">&nbsp;</span> <span class="wave w44">&nbsp;</span> <span class="wave w43">&nbsp;</span> <span class="wave w42">&nbsp;</span> <span class="wave w41">&nbsp;</span> <span class="wave w40">&nbsp;</span> <span class="wave w39">&nbsp;</span> <span class="wave w38">&nbsp;</span> <span class="wave w37">&nbsp;</span> <span class="wave w36">&nbsp;</span> <span class="wave w35">&nbsp;</span> <span class="wave w34">&nbsp;</span> <span class="wave w33">&nbsp;</span> <span class="wave w32">&nbsp;</span> <span class="wave w31">&nbsp;</span> <span class="wave w30">&nbsp;</span> <span class="wave w29">&nbsp;</span> <span class="wave w28">&nbsp;</span> <span class="wave w27">&nbsp;</span> <span class="wave w26">&nbsp;</span> <span class="wave w25">&nbsp;</span> <span class="wave w24">&nbsp;</span> <span class="wave w23">&nbsp;</span> <span class="wave w22">&nbsp;</span> <span class="wave w21">&nbsp;</span> <span class="wave w20">&nbsp;</span> <span class="wave w19">&nbsp;</span> <span class="wave w18">&nbsp;</span> <span class="wave w17">&nbsp;</span> <span class="wave w16">&nbsp;</span> <span class="wave w15">&nbsp;</span> <span class="wave w14">&nbsp;</span> <span class="wave w13">&nbsp;</span> <span class="wave w12">&nbsp;</span> <span class="wave w11">&nbsp;</span> <span class="wave w10">&nbsp;</span> <span class="wave w9">&nbsp;</span> <span class="wave w8">&nbsp;</span> <span class="wave w7">&nbsp;</span> <span class="wave w6">&nbsp;</span> <span class="wave w5">&nbsp;</span> <span class="wave w4">&nbsp;</span> <span class="wave w3">&nbsp;</span> <span class="wave w2">&nbsp;</span> <span class="wave w1">&nbsp;</span> </div> <div class="circle"> <div class="outter-record"> <div class="inner-record"> </div> </div> </div> <div id="right-wrapper"> <span class="wave w1">&nbsp;</span> <span class="wave w2">&nbsp;</span> <span class="wave w3">&nbsp;</span> <span class="wave w4">&nbsp;</span> <span class="wave w5">&nbsp;</span> <span class="wave w6">&nbsp;</span> <span class="wave w7">&nbsp;</span> <span class="wave w8">&nbsp;</span> <span class="wave w9">&nbsp;</span> <span class="wave w10">&nbsp;</span> <span class="wave w11">&nbsp;</span> <span class="wave w12">&nbsp;</span> <span class="wave w13">&nbsp;</span> <span class="wave w14">&nbsp;</span> <span class="wave w15">&nbsp;</span> <span class="wave w16">&nbsp;</span> <span class="wave w17">&nbsp;</span> <span class="wave w18">&nbsp;</span> <span class="wave w19">&nbsp;</span> <span class="wave w20">&nbsp;</span> <span class="wave w21">&nbsp;</span> <span class="wave w22">&nbsp;</span> <span class="wave w23">&nbsp;</span> <span class="wave w24">&nbsp;</span> <span class="wave w25">&nbsp;</span> <span class="wave w26">&nbsp;</span> <span class="wave w27">&nbsp;</span> <span class="wave w28">&nbsp;</span> <span class="wave w29">&nbsp;</span> <span class="wave w30">&nbsp;</span> <span class="wave w31">&nbsp;</span> <span class="wave w32">&nbsp;</span> <span class="wave w33">&nbsp;</span> <span class="wave w34">&nbsp;</span> <span class="wave w35">&nbsp;</span> <span class="wave w36">&nbsp;</span> <span class="wave w37">&nbsp;</span> <span class="wave w38">&nbsp;</span> <span class="wave w39">&nbsp;</span> <span class="wave w40">&nbsp;</span> <span class="wave w41">&nbsp;</span> <span class="wave w42">&nbsp;</span> <span class="wave w43">&nbsp;</span> <span class="wave w44">&nbsp;</span> <span class="wave w45">&nbsp;</span> <span class="wave w46">&nbsp;</span> <span class="wave w47">&nbsp;</span> <span class="wave w48">&nbsp;</span> <span class="wave w49">&nbsp;</span> <span class="wave w50">&nbsp;</span> </div> </div> </Section> <footer>James learning </footer>

\$\endgroup\$
2

1 Answer 1

3
\$\begingroup\$

CSS Animation

Complex CSS animation suffers from a performance problem as it is a general-purpose solution to what often is a very optimization-focused problem.

You have 100 animated elements. From CSS's view point each element represents a separate uncoordinated animation, each of which requires animating, rendering, and compositing. This works against the GPU which is optimized to render a few highly complex items, rather than many simple items.

Because CSS is such a generalized animation engine you also tend to lose fine control.

Animation tends to get stuck to a set of static, pre-computed sequences.

Review

JavaScript

The function peak_wave is preforming very slow DOM queries inside what should be performance-oriented loops.

Store the result of queries in variables once when you code starts, then use the stored values to reference the elements rather than use the document tree queries inside performance critical code.

JS Style

  • Good to see that you use strict mode.

  • JS naming convention is to use camelCase not snake_case

  • Don't repeat code.

    • The function peak_wave has two near identical for loops. These loops should be as a separate function

    • The functions in 8 of the setInterval callbacks are identical. They should be one function.

      Example

      const randomLevel = () => { peakWave(Math.random() * 30 + 1 | 0, Math.random() * 200 + 150 | 0); } [1200,1300,1400,1500,10600,10700,10800,10900].forEach(time => { setInterval(randomLevel, time) }); 
  • You have code that is never called doesExist. Never include silent code.

  • The are many places where you have too many () for example Math.floor((Math.random() * (30) + 1)) can be Math.floor(Math.random() * 30 + 1)

Alternative

I will not rewrite your code as it is too inefficient. Rather I present an alternative approach that requires no CSS animation at all.

Use 2D canvas.

Ideally for the best result the animation should be rendered using a WebGL2 context derived from the Canvas element. However WebGL is very verbose and requires a lot of support code just to get started.

The CanvasRenderingContext2D is an excellent API for animation and can deliver very complex animations well beyond what even the best CSS can deliver.

The example

Below is an example that is similar to the functionality of your code.

It adds a canvas and uses the 2D API to render the animation.

To highlight the addition complexity I have made the level bars as dynamic as possible. There are also dozens of setup options that allow quick and easy modifications that would take a long time if you add to change the CSS, HTML, and JS.

const barsDefault = { // colors Must be 4 char CSS hash color eg `#F00` is red count: 60, meanSize: 16, // number of bars per mean bucket (mean is used for bg glows) glowDecay: 0.3, // pulls down mean bucket values glows: [ ["#F00", "#40F", "#00F", "#00F", "#00F", "#00F"], ["#0F0", "#0F8", "#06F", "#00F", "#00F", "#00F"], ["#40F", "#00F", "#00F", "#00F"], ], centerRadius: 35, decay: 0.1, innerHeightPad: 10, color: "#FFF", // Must be 4 char CSS hash color barWidth: 0.6, // fraction of bar space to contain bar centerBarWidth: 10, centerInset: 0.9, // as fraction of radius centerInsetWidth: 0.2, // as fraction of radius centerInsetAng: 0.5, // as fraction of 180 deg centerRotateMax: 10, // as fraction of 180 deg barFeq: 1 / 8, // odds per frame of new position barPeakWidth: 10, // max number of bars to spread movement. Must be whole number barPeakWidthMin: 2, // min number of bars to spread movement. Must be whole number >= 1 barPeakSlide: 3, // twice Max rate that level drive slides along bars barLevel: 1 / 12, // Max bar volume add barLevelComp: 1 / 2, // drives bar volume compressor n. Is logarithmic. Where 0 < n < Infinity, louder as nit gets smaller levelDriveDecay: 0.01, // rate that level drivers decay Must be 0 < n <= 1 levelDriveMin: 0.05, // min level drive. Below this level driver turns off. Must be 0 < n glowOffsetRate: 0.001, // as radians per frame glowAlpha: 0.3, }; // Math Helper util const polarArg = (ang, dist, x = 0, y = 0) => ([Math.cos(ang) * dist + x, Math.sin(ang) * dist + y]); const eCurve = (v, p = 2, vp) => v < 0 ? 0 : v > 1 ? 1 : (vp = v ** p) / (vp + (1 - v) ** p); const PI = Math.PI, TAU = PI * 2; requestAnimationFrame(renderLoop); const bars = Bars(canvasContainer); addEventListener("resize", bars.resize); function renderLoop() { bars.update(); bars.draw(); requestAnimationFrame(renderLoop); } function Bars(container, config = {}) { var bounds, w, h; const canvas = document.createElement("canvas") const ctx = canvas.getContext("2d"); container.appendChild(canvas); function resize() { bounds = container.getBoundingClientRect(); w = bounds.width; h = bounds.height; Object.assign(Object.assign(canvas, { width: w, height: h }).style, { position: "absolute", top: "0px", left:"0px" }); ctx.lineCap = ctx.lineJoin = "round"; centerBar = ctx.createLinearGradient(0, 0,w, 0); centerBar.addColorStop(0, setup.color + "0"); centerBar.addColorStop(0.2, setup.color + "A"); centerBar.addColorStop(0.4, setup.color + "F"); centerBar.addColorStop(0.6, setup.color + "F"); centerBar.addColorStop(0.8, setup.color + "A"); centerBar.addColorStop(1, setup.color + "0"); } const setup = { ...barsDefault, ...config, }; resize(); const levels = new Array(setup.count).fill(0); const levelDrivers = []; const meanSize = setup.count /setup.meanSize | 0; const means = new Array(setup.count / meanSize | 0).fill(0); var rotate = 0, rotatePos = 0, rotateDelta = 0, totalLevel = 0, glowAng1 = 0, glowAng2 = 0; // create center bar gradient var centerBar; // create background glow gradients const glows = means.map((m, i) => { const g = ctx.createRadialGradient(0, 0, 4, 0, 0, h * 0.5); const cols = setup.glows[i % setup.glows.length]; cols.forEach((col, i) => { const alpha = Math.min(1, Math.max(0, i / (cols.length -1))); g.addColorStop(alpha, col + ((1-eCurve(alpha)) * 15 | 0).toString(16)); }); return g; }); // create center Circle const centerCircle = new Path2D(); { const cc = centerCircle; const CR = setup.centerRadius, CR1 = CR * setup.centerInset, CR2 = CR * (setup.centerInset - setup.centerInsetWidth); const ANG = setup.centerInsetAng * 0.5 * PI; cc.arc(0, 0, CR + 1, 0, TAU); cc.moveTo(...polarArg(-ANG, CR1)) cc.arc(0, 0, CR1, -ANG, ANG); cc.arc(0, 0, CR2, ANG, -ANG, true); cc.moveTo(...polarArg(PI - ANG, CR1)) cc.arc(0, 0, CR1, PI - ANG, PI + ANG); cc.arc(0, 0, CR2, PI + ANG, PI - ANG, true); } return Object.freeze({ update() { updateCenter(); updateBars(); }, draw() { ctx.setTransform(1,0,0,1,0,0); ctx.clearRect(0, 0, w, h); ctx.fillStyle = setup.color; drawGlows(); drawCircle(); drawBars(); }, resize, }); function updateBars() { var i = setup.count, pos, level, move, bPW, head = 0, tail = 0; const decay = 1 - setup.decay; totalLevel = 0; // global to Bars while (i--) { means[i / meanSize | 0] += levels[i]; totalLevel += levels[i]; levels[i] *= decay; } if (Math.random() < setup.barFeq) { const pos = setup.count * Math.random() | 0; const level = Math.random() ** setup.barLevelComp * setup.barLevel; levelDrivers.push([ pos, level, (Math.random() - 0.5) * setup.barPeakSlide, Math.random() * (setup.barPeakWidth - setup.barPeakWidthMin) + setup.barPeakWidthMin | 0, ]); } while (head < levelDrivers.length) { const lDrive = levelDrivers[head++]; [pos, level, move, bPW] = lDrive; // bPW for bar Peak Width lDrive[0] = pos += move; pos |= 0; pos >= 0 && pos < setup.count && (levels[pos] = Math.min(1, levels[pos] + level)); i = 1; while (i < bPW) { const levelAdd = eCurve(1 - i / bPW) * level; pos + i < setup.count && (levels[pos + i] = Math.min(1, levels[pos + i] + levelAdd)); pos - i >= 0 && (levels[pos - i] = Math.min(1, levels[pos - i] + levelAdd)); i++; } lDrive[1] = (level *= 1 - setup.levelDriveDecay); if (level > setup.levelDriveMin && pos + bPW >= 0 && pos - bPW < setup.count) { levelDrivers[tail++] = lDrive; } } levelDrivers.length = tail; } function updateCenter() { rotatePos = ((totalLevel / setup.count) - 0.5) * setup.centerRotateMax * PI; rotate += (rotateDelta = (rotateDelta += (rotatePos - rotate) * 0.03) * 0.6); } function drawBars() { const cw = w * 0.5, ch = h * 0.5; var i = setup.count, j = 0; var xl = cw - setup.centerRadius, xr = cw + setup.centerRadius, x = 0; const cr = setup.centerRadius; const damp = setup.count * 0.3; const xs = xl / setup.count, xw = xs * setup.barWidth; const hScale = ch - setup.innerHeightPad; ctx.fillStyle = centerBar; ctx.fillRect( 0, (h - setup.centerBarWidth) * 0.5, cw - setup.centerRadius, setup.centerBarWidth ); ctx.fillRect( cw + setup.centerRadius, (h - setup.centerBarWidth) * 0.5, cw - setup.centerRadius, setup.centerBarWidth ); ctx.strokeStyle = centerBar;//setup.color; ctx.lineWidth = xw; ctx.beginPath(); while (i--) { const lh = (j < damp ? 1-((damp-j) / damp) ** 2 : 1) * levels[i] * hScale; if(lh > 0.5) { const r = x * 4 + cr; const lhr = lh / r; // add lhr + 0.0001 to start angle to fix miter artifact ctx.moveTo(...polarArg(lhr + 0.0001, r, xl + cr - x * 3, ch)) ctx.arc (xl + cr - x * 3, ch, r, lhr, -lhr, true); ctx.moveTo(...polarArg(PI + lhr + 0.0001, r, xr - cr + x * 3, ch)) ctx.arc (xr - cr + x * 3, ch, r, PI + lhr, PI - lhr, true); } j ++; x += xs; } ctx.stroke(); } function drawGlows() { var i = means.length, j = 1; const ch = h * 0.5; const xs = w * 0.5 / (means.length + 1); var x = 0; ctx.globalCompositeOperation = "lighter"; while (i--) { var m = Math.min(1, (means[i] / meanSize)) ** 2; means[i] *= setup.glowDecay; const xx = Math.cos(glowAng1 * (i + 1)) * ch * 0.5; const yy = Math.sin((glowAng2 += m * 0.01) * j ); ctx.setTransform( m, 0, 0, m, w * 0.5 + xx + x * (i % 2 ? -1 : 1), yy * ch * 0.25 + h * 0.5 ); ctx.globalAlpha = (1- ((yy * (1-m)) ** 4)) * setup.glowAlpha; ctx.fillStyle = glows[i]; ctx.beginPath(); ctx.arc(0, 0, h * 0.5, 0, TAU); ctx.fill(); x += xs; j += 0.2; } glowAng1 += 2 * setup.glowOffsetRate; glowAng2 += 3 * setup.glowOffsetRate; ctx.globalCompositeOperation = "source-over"; ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.globalAlpha = 1; } function drawCircle() { ctx.fillStyle = setup.color; const ax = Math.cos(rotate); const ay = Math.sin(rotate); ctx.setTransform(ax, ay, -ay, ax, w * 0.5, h * 0.5); ctx.fill(centerCircle, "evenodd"); ctx.setTransform(1, 0, 0, 1, 0, 0); } }
#container { background-image: radial-gradient(circle at 40px 40px, rgba(157,227,255,1) 0%, rgba(60,152,240,1) 24%, rgba(44,73,105,1) 56%, rgba(12,1,66,1) 94%, rgba(0,0,1,1) 100%); font-family: Arial Black; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; } h1, h2 { text-align: center; font-size: xx-large; } h1 { color: #8CF;font-size: xxx-large} h2 { color: #8F4} #canvasContainer { position: absolute; top: 29%; left: 0px; height: 70%; width: 100%; } canvas { mix-blend-mode: lighten; }
<div id="container"> <h1>Audio <span>Candy</span></h1> <h2>2D Canvas Animation</font> <div id="canvasContainer"></div> </div>

\$\endgroup\$
2
  • \$\begingroup\$Two things please: It is so smooth, looks great! (1) It looks like you used circles for the bars. Is it possible to use squares? I am going to look at this weekend. (2) I want to do the work but I might need help would I post my help questions here or in Stack Overflow?\$\endgroup\$
    – JamesB
    CommentedAug 26, 2021 at 9:58
  • \$\begingroup\$Could you take a look at this for me? Same subject modified code. stackoverflow.com/questions/69060401/…\$\endgroup\$
    – JamesB
    CommentedSep 14, 2021 at 11:55

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.