在canvas画布上用线条做频谱播放器
代码及解释如下:<style>
#canv { position: absolute; cursor: pointer; }
</style>
<canvas id="canv"></canvas>
<script>
let ctx = canv.getContext('2d'), //画笔
w = canv.width = 80, //画布宽度
h = canv.height = 60, //画布高度
lines = [], //线条数组
total = 10, //线条总数
lineWidth = (w - 2 * total) / total, //线条厚度
aud = new Audio(); //播放器
aud.src = 'https://music.163.com/song/media/outer/url?id=16434054.mp3'; //音乐地址
aud.loop = true; //循环播放
aud.autoplay = true; //自动播放
aud.addEventListener('timeupdate', change); //监听播放进度 :驱动频谱
canv.onclick = () => aud.paused ? aud.play() : aud.pause(); //画布单击事件 :控制暂停、播放
//创建线条对象 :以便批量处理
function Line(x1,y1,x2,y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
lines.push(this); //加入 lines 数组
}
//线条对象的绘制函数
Line.prototype.draw = function() {
ctx.beginPath(); //开启路径
ctx.strokeStyle = this.color; //绘制颜色
ctx.lineWidth = lineWidth; //画笔粗细 :等于线条厚度
ctx.moveTo(this.x1, this.y1); //移动画笔到 x1、y1位置
ctx.lineTo(this.x2,this.y2); //绘制线条到 x2、y2
ctx.stroke(); //上色
}
// 批量生成并绘制线条
for(let j = 0; j < total; j ++) { //按预设线条总数
let line = new Line(); //建立Line对象实例 line
line.x1 = j * lineWidth + j*2 + lineWidth / 2 + 1; //实例 line 的x1 :其算法令每个线条拉开一定距离
line.y1 = h; //y1等于画布高度
line.x2 = line.x1; //x2等于x1
line.y2 = 50; //y2 :这个值后面会动态变化,这里是为不支持自动播放准备一个统一的高度
line.color = '#' + Math.random().toString(16).substr(-6); //首次出现的随机颜色:后面还会变化
line.draw(); //绘制线条
}
//线条动态变化函数
function change() {
ctx.clearRect(0,0,canv.width,canv.height); //每次刷新清除一次画布
for(let item of lines) { //线条数组每个元素
item.color = '#' + Math.random().toString(16).substr(-6); //随机得到16进制颜色
item.y2 = h - (Math.random() * h); //y2随机值 :高度减去(0至0.999...)*高度
item.draw(); //绘制线条
}
}
</script>
本帖最后由 马黑黑 于 2022-8-22 21:43 编辑 <br /><br /><style>
#canv { position: absolute; cursor: pointer; }
</style>
<p>效果如下。说明:由于有些浏览器设置问题,不支持媒体的自动播放,若此,此播放器仅凭监听 timeupdate 事件驱动频谱会有问题,播放器不会出现。故此,我们需要首次运行一次函数 change() ,可以放在 JS 代码的最后一行: <br><br>change(); <br><br></p>
<canvas id="canv"></canvas>
<script>
let ctx = canv.getContext('2d'),
w = canv.width = 80,
h = canv.height = 60,
lines = [],
total = 10,
lineWidth = (w - 2 * total) / total,
aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=16434054.mp3'; //音乐地址
aud.loop = true;
aud.autoplay = true;
aud.addEventListener('timeupdate', change);
canv.onclick = () => aud.paused ? aud.play() : aud.pause();
function Line(x1,y1,x2,y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
lines.push(this);
}
Line.prototype.draw = function() {
ctx.beginPath();
ctx.strokeStyle = this.color;
ctx.lineWidth = lineWidth;
ctx.moveTo(this.x1, this.y1);
ctx.lineTo(this.x2,this.y2);
ctx.stroke();
}
for(let j = 0; j < total; j ++) {
let line = new Line();
line.x1 = j * lineWidth + j*2 + lineWidth / 2 + 1;
line.y1 = h;
line.x2 = line.x1;
line.y2 = 50;
line.color = '#' + Math.random().toString(16).substr(-6);
line.draw();
}
function change() {
ctx.clearRect(0,0,canv.width,canv.height);
for(let item of lines) {
item.color = '#' + Math.random().toString(16).substr(-6);
item.y2 = h - (Math.random() * h);
item.draw();
}
}
change();
</script>
如果需要倒影,可在 #canv {} 加入:
-webkit-box-reflect: below 0 linear-gradient(transparent, transparent 50%, rgba(255,255,255,.3));
但火狐至今仍不支持 box-reflect 画布也能做频谱播放器,这个好{:4_187:} 红影 发表于 2022-8-21 18:34
画布也能做频谱播放器,这个好
这个也不用担心背景问题 line.x1 = j * lineWidth + j*2 + lineWidth / 2 + 1; 这个没看懂,为什么是这样的算法? 本帖最后由 马黑黑 于 2022-8-21 20:07 编辑
红影 发表于 2022-8-21 18:54
line.x1 = j * lineWidth + j*2 + lineWidth / 2 + 1; 这个没看懂,为什么是这样的算法?
这个算法,基于x1,就是画笔要画一根线条前移动到的位置,也是线条的起始{x,y}坐标值的x值。
线是横向排列的。线有厚度,所以,① 基于起点X坐标,第 j 根线必须在 j*lineWidth;② 我想每根线拉开一定距离,且头尾两根线不贴合边缘,那么,根据前面 lineWidth 的定义,即(画布宽度 - 2 * 线条总数)/线条总数 的定义,再加 j*2 + lineWidth / 2 + 1。如此,便能均匀地把 total 根线横向安置在画布里。不这样做处理,线条会挤在一起,甚至会在同一个地方重复画线条。
这是算法,有些算法是根据上下文进行具体应对的。 醉美水芙蓉 发表于 2022-8-21 20:09
欣赏学习黑黑老师新教材!
{:4_180:} 学习学习 马黑黑 发表于 2022-8-21 20:03
这个算法,基于x1,就是画笔要画一根线条前移动到的位置,也是线条的起始{x,y}坐标值的x值。
线是横向 ...
嗯,怪不得线宽的取值也用了算法,而不是直接赋值。谢谢黑黑解答{:4_204:} 红影 发表于 2022-8-22 16:19
嗯,怪不得线宽的取值也用了算法,而不是直接赋值。谢谢黑黑解答
不考虑画布尺寸的话,也可以直接赋值的 马黑黑 发表于 2022-8-22 17:03
不考虑画布尺寸的话,也可以直接赋值的
如果直接复制,后面的间隔的算法也要更改了吧? 红影 发表于 2022-8-22 21:10
如果直接复制,后面的间隔的算法也要更改了吧?
一般来说总要有个算法,像x1,它是排列线条的依据,每根线条必须在前一根的右边不远处。 马黑黑 发表于 2022-8-22 21:31
一般来说总要有个算法,像x1,它是排列线条的依据,每根线条必须在前一根的右边不远处。
嗯嗯,否则就无法均匀排布了。 红影 发表于 2022-8-23 15:52
嗯嗯,否则就无法均匀排布了。
是的 马黑黑 发表于 2022-8-23 17:24
是的
等消暑完了,我也来学做个{:4_187:} 红影 发表于 2022-8-23 21:12
等消暑完了,我也来学做个
挺好
页:
[1]