盛夏荷塘
本帖最后由 马黑黑 于 2022-8-22 20:18 编辑 <br /><br /><style>#papa { left: -214px; /*margin: auto;*/ width: 1024px; height: 640px; display: grid; place-items: center; background: teal url('https://638183.freep.cn/638183/t22/hl/vv.webp') no-repeat center/cover; box-shadow: 3px 3px 20px #000; position: relative; z-index: 3; }
#canv { position: absolute; bottom: 30px; cursor: pointer; box-reflect: below 0 linear-gradient(transparent, transparent 50%, rgba(255,255,255,.3)); -webkit-box-reflect: below 0 linear-gradient(transparent, transparent 50%, rgba(255,255,255,.3)); }
#lrcbox { position: absolute; left: 15px; top: 10px; font: bold 30px / 40px sans-serif; color: darkgreen; text-shadow: 1px 1px 2px #000, 10px 10px 10px rgba(0, 0, 0, .35); user-select: none; }
</style>
<div id="papa">
<canvas id="canv"></canvas>
<span id="lrcbox">盛夏荷塘</span>
</div>
<script>
let ctx = canv.getContext('2d'),
w = canv.width = 80,
h = canv.height = 60,
lines = [],
total = 20,
lineWidth = (w - 2 * total) / total,
aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=490949412.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 = 60;
line.color = 'purple';
line.draw();
}
function change() {
ctx.clearRect(0,0,w,h);
for(let item of lines) {
item.color = '#' + Math.random().toString(16).substr(-6);
item.y2 = h - (Math.random() * h);
item.draw();
}
}
change();
</script>
本帖是canvas画布频谱播放器的试用,代码如下(全):
<style>
#papa { left: -214px; /*margin: auto;*/ width: 1024px; height: 640px; display: grid; place-items: center; background: teal url('https://638183.freep.cn/638183/t22/hl/vv.webp') no-repeat center/cover; box-shadow: 3px 3px 20px #000; position: relative; z-index: 3; }
#canv { position: absolute; bottom: 30px; cursor: pointer; box-reflect: below 0 linear-gradient(transparent, transparent 50%, rgba(255,255,255,.3)); -webkit-box-reflect: below 0 linear-gradient(transparent, transparent 50%, rgba(255,255,255,.3)); }
#lrcbox { position: absolute; left: 15px; top: 10px; font: bold 30px / 40px sans-serif; color: darkgreen; text-shadow: 1px 1px 2px #000, 10px 10px 10px rgba(0, 0, 0, .35); user-select: none; }
</style>
<div id="papa">
<canvas id="canv"></canvas>
<span id="lrcbox">盛夏荷塘</span>
</div>
<script>
let ctx = canv.getContext('2d'),
w = canv.width = 80,
h = canv.height = 60,
lines = [],
total = 20,
lineWidth = (w - 2 * total) / total,
aud = new Audio();
aud.src = 'https://music.163.com/song/media/outer/url?id=490949412.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 = 60;
line.color = 'purple';
line.draw();
}
function change() {
ctx.clearRect(0,0,w,h);
for(let item of lines) {
item.color = '#' + Math.random().toString(16).substr(-6);
item.y2 = h - (Math.random() * h);
item.draw();
}
}
</script>
相比CSS+HTML标签构建的频谱播放按钮,JS部分的代码多了一些。画布上的操作,JS代码量也难以节省。它的优势是,DOM节点大大减少。
画布频谱相关解释:
https://www.huachaowang.com/forum.php?mod=viewthread&tid=62358&extra=page%3D1 这里再解释一下几个重要变量:
let ctx = canv.getContext('2d'),
w = canv.width = 80, //画布宽度在此设定
h = canv.height = 60, //画布高度在此设定
lines = [], //装载频谱线条的数组
total = 20, //频谱线条总数
lineWidth = (w - 2 * total) / total, //频谱线条的厚度:根据画布宽度和线数决定
aud = new Audio(); 本帖最后由 马黑黑 于 2022-8-22 07:55 编辑
关于线条厚度:
lineWidth = (w - 2 * total) / total;
(画布宽度 - 线条总数的2倍)÷ 线条总数,(80-2*20)/20 = 2,线条的厚度是2,会很细,不过,画布用 stroke 方法画线,会多出边缘部分,两侧各占 1 个单位 共 2 个单位,即表现出来的线条真实厚度其实是 4 个单位(程序以2个单位计)。什么单位?像素。
然后,初始化每根线条横向位置时,我们的计算要配套上面的式子,
line.x1 = j * lineWidth + j*2 + lineWidth / 2 + 1;
j 是循环语句的步进变量,从 0 开始,如此,第一根线在画布上的水平方向位置是,
0*2+0*2+2/2+1 = 2,
它从 2px 处开始。最后一根线,j 是 19,它的 x1 位置,
19*2+19*2+2/19+1 = 77.1052631579
这个值很接近右边边缘了,再加上①线宽,②画布的一些不好描述的怪异特性,基本上所有的线条居中平铺在了画布的水平方向了,且线条彼此间一些一定的距离。 需要验证 5# 所描述的,大家可以在本地测试时在 CSS 中给 #canv 加入,
border: 1px solid;
再改变 total 数量为较少(比如5),如此,能更方便地观测效果。 有意思。这个得好好研究一下了。老黑早晨好!{:4_190:} 马黑黑 发表于 2022-8-22 07:53
关于线条厚度:
lineWidth = (w - 2 * total) / total;
前面就对这个间隔的算法没弄明白,现在也不去管了,就按这个计算就好{:4_173:} 我单位网有问题,没法听到网易云,等晚上回家再欣赏了{:4_187:} 弄成那天那从中间开屏的是不是更好看些{:4_173:} 樵歌 发表于 2022-8-22 10:46
弄成那天那从中间开屏的是不是更好看些
那是东篱的东宫才这样开合的 红影 发表于 2022-8-22 10:17
前面就对这个间隔的算法没弄明白,现在也不去管了,就按这个计算就好
差不多的 红影 发表于 2022-8-22 10:37
我单位网有问题,没法听到网易云,等晚上回家再欣赏了
音乐有特点 加林森 发表于 2022-8-22 08:52
有意思。这个得好好研究一下了。老黑早晨好!
数学基础好的话一看就能明白 马黑黑 发表于 2022-8-22 11:10
数学基础好的话一看就能明白
我数学不好。所以比较吃力的。 加林森 发表于 2022-8-22 11:17
我数学不好。所以比较吃力的。
数学基础不扎实,做帖时的很多计算智能蒙了 马黑黑 发表于 2022-8-22 12:18
数学基础不扎实,做帖时的很多计算智能蒙了
就是啊。 黑黑新的小频谱播放器{:4_178:} 黑黑精彩连连,小辣椒跟不上了{:4_189:} 小辣椒 发表于 2022-8-22 17:41
黑黑新的小频谱播放器
和过去的频谱没多大区别,仅在实现元素不同