Код
<!DOCTYPE html>
<html class=''>
<head>
<meta charset='UTF-8'>
<title>Phyllotactic Dancing </title>
<meta name="robots" content="noindex">
</head>
<body>
<style class="cp-pen-styles">
svg {
display: block;
margin-left: auto;
margin-right: auto;
}
</style>
<svg></svg>
<script src='https://cdnjs.cloudflare.com/ajax/libs/pizzicato/0.6.0/Pizzicato.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js'></script>
<script>
const path = 'https://alemangui.github.io/audio/piano-electro.mp3' // Прямая ссылка на .mp3 файл
const sound = new Pz.Sound({
source: 'file',
options: {
path: path,
loop: true
}
}, () => onSoundLoaded())
function onSoundLoaded() {
const width = Math.min(window.innerHeight, window.innerWidth)
const height = width
const numberOfPoints = width
const radius = 10
let analyser
let radiusScale
let colorScale
let displayData
setupAnalyser()
setupVisualization()
setupScale()
sound.play()
window.requestAnimationFrame(() => draw())
function setupAnalyser() {
analyser = Pz.context.createAnalyser()
analyser.fftSize = nextPowerOf2(numberOfPoints) * 4
displayData = new Uint8Array(analyser.frequencyBinCount)
sound.connect(analyser)
}
function setupVisualization() {
const svg = d3.select('svg')
.attr('width', width)
.attr('height', height)
const points = d3.range(numberOfPoints).map(phyllotaxis(radius))
svg.append('g').selectAll('circle')
.data(points)
.enter()
.append('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', 1)
}
function setupScale() {
radiusScale = d3.scaleSqrt().domain([0, 255]).range([1, 8])
colorScale = d3.scaleSqrt().domain([0, 255]).range(['#673ab7', '#e91e63'])
}
function draw() {
analyser.getByteFrequencyData(displayData)
const lowerCut = 0.15
const upperCut = 0.1
let data = displayData.slice(displayData.length * lowerCut, displayData.length - displayData.length * upperCut)
d3.select('svg > g').selectAll('circle')
.data(data)
.attr('r', d => radiusScale(d))
.attr('fill', d => colorScale(d))
window.requestAnimationFrame(() => draw())
}
function phyllotaxis(radius) {
const theta = Math.PI * (3 - Math.sqrt(5))
return i => {
let r = radius * Math.sqrt(i)
let a = theta * i
return {
x: width / 2 + r * Math.cos(a),
y: height / 2 + r * Math.sin(a)
}
}
}
function nextPowerOf2(number) {
return Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)))
}
}
</script>
</body>
</html>