用canvas画布做圆环音乐播放器
本帖最后由 马黑黑 于 2022-8-23 10:42 编辑在画布上画圆,用 arc 方法,它至少需要 5 个参数,下面给出完整参数:
context.arc(①圆心X坐标, ②圆心Y坐标, ③半径, ④开始角度, ⑤结束角度, ⑥方向);
①②③参数赋值容易理解,不多说;④开始角度默认是 0,位于圆的最右边的坐标处;⑤结束角度,画圆的话是360°,与开始角度(0°)重合;⑥方向取值是 true 或 false,布尔值,用以规定画圆的走向,缺省时是顺时针方向(本例适用缺省设置)。
画圆是做圆环进度的基础,这里再重点说说参数 ④ 开始角度 和 参数 ⑤ 结束角度。圆的角度需要用的圆周率PI,在JS中表达为 Math.PI。比如,我们从 0 开始画圆,参数 ④ 就用 0 表示,它的完整算式是 0 * Math.PI / 180,参数 ⑤ 即结束角度就是360°,算式为2 * Math.PI 。圆环进度条习惯上不从圆的最右边开始,而是从顶部开始的,也就是回退了 90°,所以,圆环进度条的参数 ④ 算式为 -90 * Math.PI / 180,参数 ⑤ 即结束角度将表示当前进度,假设是 angle 度,则它的算式要相应变成 (angle - 90) * Math.PI / 180,以对应已经不是 0° 的开始点。
以上是用画布做圆环进度条的基础。记住:它是针对画布的 arc() 画弧法,角度计算除了 0 以外,必须用 PI 算式而不是直接给出角度值。下面开始编写一个画进度条的函数:
function drawCircle() {
ctx.clearRect(0, 0, w, h); //每次重新绘制前清空画布
ctx.beginPath(); //路径开启,用于绘制轨迹圆环
ctx.strokeStyle = '#eee'; //画布颜色
ctx.lineWidth = 8; //圆环的厚度
ctx.arc(w/2, h/2, w/2 - 4, 0, 2 * Math.PI); //绘制轨迹圆环,w、h是画布宽高
ctx.stroke(); //给上述虚拟圆环着色(用 fill() 方法画的是实现圆)
ctx.beginPath(); //开始新路径 :用于绘制进度圆环
ctx.strokeStyle = '#EA0001'; //画布颜色
ctx.arc(w/2, h/2, w/2 - 4, -90 * Math.PI / 180, (angle - 90) * Math.PI / 180); //画圆环(angle变量实现已声明)
ctx.stroke(); //上色
ctx.fillStyle = '#eee'; //改变画笔颜色 :用于绘制文本
ctx.font = '14px sans-serif'; //字体设置
ctx.textAlign = 'center'; //文本水平对齐(center 时,以圆心X坐标为基准)
ctx.textBaseline = 'middle'; //文本垂直对齐(middle 时,以圆心X坐标为基准)
ctx.fillText(prog, w/2, h/2); //绘制文本,prog 是实现声明的字串变量,文本绘制在圆心处
}
这个函数初始时要运行一次,以便对不自动播放媒体的浏览器友好一些,否则播放器界面出不来。然后,一切交给 audio 的播放情况决定,即,我们在监听 audio 播放器的 timeupdate 事件时改变 angle 和 prog 变量值并调用上述函数以驱使进度条的更新。
为了便于理解,附上《花心》帖子的全部代码:
<style>
#papa { margin: auto; width: 1024px; height: 640px; background: #ccc url('https://638183.freep.cn/638183/t22/51/hx.webp') no-repeat center/cover; box-shadow: 3px 3px 20px #000; position: relative; }
#player { position: absolute; left: 458px; top: 78px; cursor: pointer; }
#hx { position: absolute;left : calc(50% - 180px); top: 10px; }
</style>
<div id="papa">
<img id="hx" src="https://638183.freep.cn/638183/t22/51/hx.png" alt="" />
<canvas id="player"></canvas>
</div>
<script>
let ctx = player.getContext('2d'),
w = h = player.width = player.height = 120,
prog = '点这播放',
angle = 0,
aud = new Audio();
ctx.arc(50,50,40,0, 2*Math.PI);
ctx.stroke();
aud.src = 'https://music.163.com/song/media/outer/url?id=5035947.mp3';
aud.loop = true;
aud.autoplay = true;
drawCircle();
player.onclick = () => aud.paused ? aud.play() : aud.pause();
aud.addEventListener('timeupdate', () => {
angle = 360 * aud.currentTime / aud.duration;
prog = toMin(aud.currentTime) + ' | ' + toMin(aud.duration);
drawCircle();
});
function drawCircle() {
ctx.clearRect(0, 0, w, h);
ctx.beginPath();
ctx.strokeStyle = '#eee';
ctx.lineWidth = 8;
ctx.arc(w/2, h/2, w/2 - 4, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = '#EA0001';
ctx.arc(w/2, h/2, w/2 - 4, -90 * Math.PI / 180, (angle - 90) * Math.PI / 180);
ctx.stroke();
ctx.fillStyle = '#eee';
ctx.font = '14px sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(prog, w/2, h/2);
}
function toMin(val) {
if(!val) return '00:00';
val = Math.floor(val);
let min = parseInt(val / 60);
let sec = parseFloat(val % 60);
if(min < 10) min = '0' + min;
if(sec < 10) sec = '0' + sec;
return min + ':' + sec;
}
</script>
原来不但进度圆环是用画布画出来的,连文本也是呢{:4_187:} 监听 audio 播放器的 timeupdate 事件,就是最后那段代码吧? 红影 发表于 2022-8-23 09:49
监听 audio 播放器的 timeupdate 事件,就是最后那段代码吧?
有点英语基础的话,应该看得出来,这个才是监听 timeupdate 事件:
aud.addEventListener('timeupdate', () => {
angle = 360 * aud.currentTime / aud.duration;
prog = toMin(aud.currentTime) + ' | ' + toMin(aud.duration);
drawCircle();
}); 红影 发表于 2022-8-23 09:44
原来不但进度圆环是用画布画出来的,连文本也是呢
文本啰嗦而已,容易的 来学习。 马黑黑 发表于 2022-8-23 09:58
有点英语基础的话,应该看得出来,这个才是监听 timeupdate 事件:
aud.addEventListener('timeupdate ...
呵呵,我的英语很差的{:4_173:} 马黑黑 发表于 2022-8-23 10:42
文本啰嗦而已,容易的
直接输入多好。 红影 发表于 2022-8-23 16:44
直接输入多好。
那你在自己的美图秀秀里直接输入看看 红影 发表于 2022-8-23 16:44
呵呵,我的英语很差的
这会影响对代码的理解 马黑黑 发表于 2022-8-23 17:15
那你在自己的美图秀秀里直接输入看看
图片上家文字就不能改了,代码的能修改啊。我说的是用CSS直接输入,不用画布的方式。 马黑黑 发表于 2022-8-23 17:15
这会影响对代码的理解
那是,不过用于代码的单词毕竟不多,慢慢也就熟悉了,问题也不大。 红影 发表于 2022-8-23 20:55
那是,不过用于代码的单词毕竟不多,慢慢也就熟悉了,问题也不大。
强记总是可以的,毕竟学过,淡忘了一些而已 红影 发表于 2022-8-23 20:54
图片上家文字就不能改了,代码的能修改啊。我说的是用CSS直接输入,不用画布的方式。
用啥都可以 马黑黑 发表于 2022-8-23 21:12
强记总是可以的,毕竟学过,淡忘了一些而已
常用的总是会知道的,就像一些设备是外文说明书,有些人说难,我就这样说的。 马黑黑 发表于 2022-8-23 21:13
用啥都可以
嗯嗯,知道了。 红影 发表于 2022-8-23 21:36
嗯嗯,知道了。
{:4_180:} 红影 发表于 2022-8-23 21:36
常用的总是会知道的,就像一些设备是外文说明书,有些人说难,我就这样说的。
接触多了就会记住的 马黑黑 发表于 2022-8-23 21:50
接触多了就会记住的
是的,学一种语言难,但只是掌握特定的名称没那么难。 红影 发表于 2022-8-24 21:05
是的,学一种语言难,但只是掌握特定的名称没那么难。
我们一般是这么要求:可以不会说,但有一定的阅读能力