JSFiddle - React, Tailwind, and code Playground
HTML
<svg width="100%" height="100%" viewBox="0 0 800 600"></svg>
<p></p>
JavaScript
const svgNs = 'http://www.w3.org/2000/svg';
const p1inc = 2 * Math.PI / 57;
const p2inc = 2 * Math.PI / 74;
function radius(i, p1, p2) {
return 4 + 2 * Math.sin(i * 2 * Math.PI / (27 + 3 * Math.cos(p1))) + 2 * Math.cos(i * 2 * Math.PI / (11 + 5 * Math.sin(p2)));
}
var container = document.querySelector('svg');
for (var i = 0; i < 16; ++i)
container = container.appendChild(document.createElementNS(svgNs, 'g'));
for (var i = 0; i < 80*60; ++i) {
var x = (i / 80) | 0, y = (i % 80) | 0;
var circle = document.createElementNS(svgNs, 'circle');
circle.setAttribute('cx', x * 10 + 5);
circle.setAttribute('cy', y * 10 + 5);
circle.setAttribute('r', radius(i, 0, 0));
container.appendChild(circle);
}
var circles = document.getElementsByTagName('circle');
var phase1 = 0;
var phase2 = 0;
var samples = new Array();
var prevT = performance.now();
requestAnimationFrame(animate);
function animate() {
phase1 += p1inc;
phase2 += p2inc;
for (var i = 0, n = circles.length; i < n; ++i)
circles[i].setAttribute('r', radius(i, phase1, phase2));
var t = performance.now();
var elapsed = t - prevT;
if (samples.push(elapsed) > 100)
samples.shift();
var avg = samples.reduce(function(a, b) { return a + b; }) / samples.length;
document.querySelector('p').textContent = elapsed + " (" + samples.length + " sample avg: " + avg + ")";
prevT = t;
requestAnimationFrame(animate);
}