Compare commits
10 Commits
7ecabc04b9
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d5e665f349 | |||
| 5a65a4ae1f | |||
| bbf8c7a580 | |||
| d3ccadba6e | |||
| a022916e7a | |||
| 914f76b0b9 | |||
| 1112bcbbe4 | |||
| dddd5e91d8 | |||
| 88f5acdb59 | |||
| a8fbe3931d |
@@ -494,7 +494,7 @@
|
||||
|
||||
// 模式0:频谱柱状图(居中对称 + 镜像)
|
||||
function drawSpectrum() {
|
||||
const barCount = bufferLength / 2;
|
||||
const barCount = bufferLength; // 使用全部频段 bin,保留高频
|
||||
const barWidth = (width * 0.8) / barCount;
|
||||
const gap = 2;
|
||||
const maxBarHeight = height * 0.35;
|
||||
|
||||
+581
-949
File diff suppressed because it is too large
Load Diff
@@ -205,17 +205,6 @@
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
/* 震动效果 */
|
||||
.shake {
|
||||
animation: shake 0.15s ease-out;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translate(0, 0); }
|
||||
25% { transform: translate(-3px, 2px); }
|
||||
50% { transform: translate(2px, -3px); }
|
||||
75% { transform: translate(-2px, -1px); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -738,12 +727,6 @@
|
||||
hue: hue
|
||||
}));
|
||||
}
|
||||
|
||||
// 屏幕微震
|
||||
if (bass > 0.5) {
|
||||
document.body.classList.add('shake');
|
||||
setTimeout(() => document.body.classList.remove('shake'), 150);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新和绘制流星
|
||||
|
||||
@@ -792,47 +792,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 扫描环(速度感环) ====================
|
||||
let rings = [];
|
||||
|
||||
function spawnRing() {
|
||||
rings.push({
|
||||
radius: 10,
|
||||
maxRadius: Math.max(width, height) * 0.8,
|
||||
life: 1,
|
||||
decay: 0.008,
|
||||
hue: 200 + Math.random() * 20,
|
||||
width: 2 + Math.random() * 2
|
||||
});
|
||||
}
|
||||
|
||||
function updateAndDrawRings(bass) {
|
||||
for (let i = rings.length - 1; i >= 0; i--) {
|
||||
const r = rings[i];
|
||||
r.radius += 8 + bass * 15;
|
||||
r.life -= r.decay;
|
||||
|
||||
if (r.life <= 0 || r.radius > r.maxRadius) {
|
||||
rings.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.globalAlpha = r.life * 0.3;
|
||||
ctx.strokeStyle = `hsl(${r.hue}, 15%, 70%)`;
|
||||
ctx.lineWidth = r.width * r.life;
|
||||
ctx.shadowBlur = 15;
|
||||
ctx.shadowColor = 'rgba(255, 255, 255, 0.4)';
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, r.radius, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 主渲染循环 ====================
|
||||
let lastTime = 0;
|
||||
let ringTimer = 0;
|
||||
let warpLineTimer = 0;
|
||||
let speedValue = 0;
|
||||
|
||||
@@ -899,20 +860,6 @@
|
||||
}
|
||||
updateAndDrawWarpLines(bass, treble);
|
||||
|
||||
// 生成和绘制扫描环(无声音时不生成)
|
||||
if (avg > 0.03) {
|
||||
ringTimer += dt;
|
||||
const ringInterval = Math.max(200, 800 - avg * 500 - bass * 300);
|
||||
if (ringTimer > ringInterval) {
|
||||
ringTimer = 0;
|
||||
spawnRing();
|
||||
}
|
||||
if (isBeat && bass > 0.4) {
|
||||
spawnRing();
|
||||
}
|
||||
}
|
||||
updateAndDrawRings(bass);
|
||||
|
||||
// 节拍粒子爆发
|
||||
if (isBeat && bass > 0.3) {
|
||||
spawnParticles(0.5 + bass);
|
||||
|
||||
@@ -895,7 +895,7 @@ function drawFreqBars(high) {
|
||||
const gap = W / barCount * 0.4;
|
||||
|
||||
for (let i = 0; i < barCount; i++) {
|
||||
const freqIdx = Math.floor(i / barCount * (freqData.length * 0.6));
|
||||
const freqIdx = Math.floor(i / barCount * (freqData.length - 1)); // 覆盖全部频段,保留高频
|
||||
const val = freqData[freqIdx] / 255;
|
||||
const barH = val * H * 0.35;
|
||||
const x = i * (barWidth + gap) + gap * 0.5;
|
||||
|
||||
+562
-478
File diff suppressed because it is too large
Load Diff
@@ -360,7 +360,7 @@ function drawGrid(time) {
|
||||
function drawSkyline() {
|
||||
if (!freqArray) return;
|
||||
const binCount = analyser.frequencyBinCount;
|
||||
const usable = Math.floor(binCount * 0.6);
|
||||
const usable = binCount; // 覆盖全部频段,保留高频
|
||||
const barCount = 80;
|
||||
const barW = W / barCount;
|
||||
const baseY = H * 0.9;
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>音频可视化</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #111;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: 4px;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.cell {
|
||||
position: relative;
|
||||
background: #111;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cell iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cell select {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
z-index: 10;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 2px 6px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
}
|
||||
|
||||
.cell:hover select {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="grid" id="grid"></div>
|
||||
<script>
|
||||
// 可供选择的页面列表
|
||||
const pages = [
|
||||
'1.html', '2.html', '3.html', '4.html',
|
||||
'5.html', '6.html', '7.html', '8.html',
|
||||
];
|
||||
|
||||
// 4 个格子默认显示的页面
|
||||
const defaults = ['2.html', '6.html', '7.html', '8.html'];
|
||||
|
||||
const grid = document.getElementById('grid');
|
||||
|
||||
defaults.forEach((current) => {
|
||||
|
||||
const cell = document.createElement('div');
|
||||
|
||||
cell.className = 'cell';
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
|
||||
iframe.src = current;
|
||||
|
||||
const select = document.createElement('select');
|
||||
|
||||
pages.forEach((p) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = p;
|
||||
opt.textContent = p;
|
||||
if (p === current) opt.selected = true;
|
||||
select.appendChild(opt);
|
||||
});
|
||||
|
||||
// 切换时更新对应 iframe
|
||||
select.addEventListener('change', () => { iframe.src = select.value; });
|
||||
|
||||
cell.appendChild(select);
|
||||
cell.appendChild(iframe);
|
||||
grid.appendChild(cell);
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user