<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
<title>音乐可视化</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>title</h1>
<ul class="type" id="type">
<li data-type="dot">Dot</li>
<li data-type="column" class="selected">Column</li>
</ul>
<p>
Volume<input id="volume" type="range" min="0" max="100" value="50" />
</p>
</header>
<div class="left">
<ul id="list">
<li>background_m.mp3</li>
<li>menu.mp3</li>
</ul>
</div>
<div class="right" id="box"></div>
<script src="../jquery-2.1.1.min.js"></script>
<script src="index.js"></script>
</body>
</html>
@charset "UTF-8";
*{
padding: 0;
margin: 0;
box-sizing: border-box;
/*为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制*/
}
html,body{
height: 100%;
}
body{
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
background: #000;
color: #fff;
text-align: center;
}
header, .right, .left{
position: absolute;
}
header{
left: 10px;
top: 10px;
right: 10px;
height: 150px;
/*border: solid #fff 1px;*/
}
header h1{
font-size: 40px;
height: 60px;
line-height: 60px;
}
header .type{
display: inline-block;
}
header .type:after{
display: block;
content: "";
clear: both; /*在左右两侧均不允许浮动元素*/
}
header .type li{
list-style-type: none;
float: left;
height: 30px;
line-height: 30px;
width: 80px;
border-top: solid 1px #fff;
border-right: solid 1px #fff;
border-bottom: solid 1px #fff;
cursor: pointer;
}
header .type li:first-child{
border-left: 1px solid #fff;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
header .type li:last-child{
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
header .type li.selected{
background-color: #fff;
color: black;
}
.left{
left: 10px;
top: 170px;
bottom: 10px;
width: 15%;
border: solid #fff 1px;
overflow: auto;
}
.left ul{
overflow: auto;
}
.left ul li{
height: 30px;
line-height: 30px;
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
/*超出显示为省略号*/
}
.left ul li.selected{
color: green;
}
.right{
top: 170px;
right: 10px;
bottom: 10px;
/*calc() 函数用于动态计算长度值,运算符前后都需要保留一个空格*/
left: calc(15% + 20px);
left: -webkit-calc(15% + 20px);
/*border: solid #fff 1px;*/
}
input[type="range"]{
/*滑条*/
-webkit-appearance: none;
height: 8px;
background: #999;
border-radius: 10px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb{
/*滑块*/
-webkit-appearance: none;
height: 12px;
width: 12px;
background: #fff;
border-radius: 100%;
}
input[type="range"]::-moz-range-track{
height: 8px;
background: #999;
border-radius: 10px;
border: none;
}
input[type="range"]::-moz-range-thumb{
height: 12px;
width: 12px;
background: #fff;
border: none;
border-radius: 100%;
}
@media screen and (max-width: 800px),screen and (max-height: 500px){
body{
font-size: 12px;
}
header{
height: 80px;
}
header h1{
font-size: 24px;
height: 34px;
line-height: 34px;
}
header .type li{
height: 16px;
line-height: 16px;
width: 50px;
}
.left, .right{
top: 100px;
}
}
var lis = $("#list li");
for (var i = 0; i < lis.length; i++){
lis[i].onclick = function () {
for (var j = 0; j < lis.length; j++){
lis[j].className = "";
}
this.className = "selected";
load(this.innerText);
};
}
//指定一个音频上下文
var ac = new (window.AudioContext || window.webkitAudioContext)();
var xhr = new XMLHttpRequest();
var gainNode = ac[ac.createGain?"createGain":"createGainNode"]();
gainNode.connect(ac.destination);
var analyer = ac.createAnalyser(); //音频分析对象
var size = 32; // 柱子的数量 不能小于16
analyer.fftSize = size * 2;
analyer.connect(gainNode);
var source = null;//用来判断是否当前有已播放歌曲
var count = 0; //避免快速切歌时带来同时播放几首歌的bug
var box = $("#box")[0];
var height, width;
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
box.appendChild(canvas);
var Dots = []; //圆的数组
function random(m, n) {
return Math.round(Math.random() * (n - m) + m);//m至n之间的一个数
}
function getDots() {
Dots = [];
for (var i = 0; i < size; i++){
var x = random(0, width);
var y = random(0, height);
var color = "rgba("+random(0, 255)+","+random(0, 255)+","+random(0, 255)+",0.1)";
Dots.push({
x: x,
y: y,
dx: random(1, 2),
color: color,
cap: 0
});
}
}
var line;
function resize() {
height = box.clientHeight;
width = box.clientWidth;
canvas.height = height;
canvas.width = width;
line = ctx.createLinearGradient(0, 0, 0, height);
line.addColorStop(0, "red");
line.addColorStop(0.5, "yellow");
line.addColorStop(1, "green");
getDots();
}
//onresize 事件会在窗口或框架被调整大小时发生
resize();
window.onresize = resize;
function draw(arr) {
ctx.clearRect(0, 0, width, height);
var w = width / size; //每个矩形的宽
var cw = w * 0.6;
var capH = cw > 10 ? 10 : cw; //小帽的高度
ctx.fillStyle = line;
for (var i = 0; i < size; i++){
var o = Dots[i];
if (draw.type == "column"){
var h = arr[i] / 256 * height; //每个矩形的高
ctx.fillRect(w * i, height - h, cw, h);
ctx.fillRect(w * i, height - (o.cap + capH), cw, capH);
o.cap --;
if (o.cap < 0){
o.cap = 0;
}
if (h > 0 && o.cap < h + 40){
o.cap = h + 40 > height - capH ? height - capH : h + 40;
}
} else if (draw.type == "dot"){
ctx.beginPath();
var r = 10 + arr[i] / 256 * (height > width ? width : height) / 10;
ctx.arc(o.x, o.y, r, 0, Math.PI*2, true);
var g = ctx.createRadialGradient(o.x, o.y, 0, o.x, o.y, r);//径向渐变,圆心到半径大小
g.addColorStop(0, "#fff");
g.addColorStop(1, o.color);
ctx.fillStyle = g;
ctx.fill();
o.x += o.dx;
o.x = o.x > width ? 0 : o.x;
}
}
}
draw.type = "column"; //给draw方法添加一个type属性
var types = $("#type li");
for (var i = 0; i < types.length; i++){
types[i].onclick = function () {
for (var j = 0; j < types.length; j++){
types[j].className = "";
}
this.className = "selected";
draw.type = this.getAttribute("data-type");
}
}
function load(url) {
var n = ++count;
source && source[source.stop ? "stop" : "noteOff"]();
xhr.abort();
xhr.open("GET", "./music/" + url);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
if (n != count)return;
ac.decodeAudioData(xhr.response,function (buffer) {
if (n != count)return;
var bufferSource = ac.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.connect(analyer);
bufferSource[bufferSource.start ? 'start' : 'noteOn'](0);
source = bufferSource;
},function (err) {
console.log(err);
});
};
xhr.send();
}
function visualizer() {
var arr = new Uint8Array(analyer.frequencyBinCount);
// console.log(arr);
requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame;
function v() {
analyer.getByteFrequencyData(arr);
requestAnimationFrame(v);
// console.log(arr);
draw(arr);
}
requestAnimationFrame(v);
}
visualizer();
//改变音量大小
function changeVolume(percent) {
gainNode.gain.value = percent * percent;
}
$("#volume")[0].onchange = function () {
changeVolume(this.value/this.max);
};
//执行默认50音量大小
$("#volume")[0].onchange();