canvas画布圆形进度条播放器半拉子项目预览
<canvas id="audCanv" width="400" height="240" style="margin: 20px auto; display: block; background: #333;"></canvas><audio id="aud" src="https://music.163.com/song/media/outer/url?id=29999537" autoplay loop></audio>
<script>
const ww = audCanv.width, hh = audCanv.height;
const ctx = audCanv.getContext('2d');
var _play = 0, _change = 0;
class Audio {
constructor(ctx,config) {
this.ctx = ctx;
this.cf = config;
this.cx = config.w / 2;
this.cy = config.h - config.size / 2 - 20;
this.r = config.size / 2;
};
drawUi(text,value,flag) {
this.ctx.clearRect(0, 0, this.cf.w, this.cf.h);
this.ctx.lineCap = 'round';
this.ctx.lineWidth = 10;
this.ctx.strokeStyle = 'rgba(192,192,192,.95)';
ctx.beginPath();
this.ctx.arc(this.cx, this.cy, this.r, 0, Math.PI * 2);
this.ctx.stroke();
this.ctx.strokeStyle = 'rgba(255,250,250,.85)';
ctx.beginPath();
this.ctx.arc(this.cx, this.cy, this.r, 1.5 * Math.PI, Math.PI * (2 * value + 1.5));
this.ctx.stroke();
this.ctx.fillStyle = 'rgba(255,250,250,.85)';
if(flag) {
this.ctx.beginPath();
this.ctx.moveTo(this.cx - 10, this.cy - 10);
this.ctx.lineTo(this.cx - 10, this.cy + 10);
this.ctx.lineTo(this.cx + 10, this.cy);
this.ctx.closePath();
this.ctx.fill();
}else{
this.ctx.fillStyle = 'white';
this.ctx.beginPath();
this.ctx.fillRect(this.cx - 10, this.cy - 10, 4, 20);
this.ctx.fillRect(this.cx + 4, this.cy - 10, 4, 20);
}
this.ctx.font = 'normal 13px sans-serif';
this.ctx.textAlign = 'center';
this.ctx.textBaseline = 'middle';
this.ctx.beginPath();
this.ctx.fillText(text, this.cx, this.cy + 35);
this.ctx.fill();
};
};
var option = {w: ww, h: hh, size: 140};
var _aud = new Audio(ctx,option);
_aud.drawUi('00:00/00:00',0,0);
aud.ontimeupdate = () => {
var val = aud.currentTime / aud.duration;
var txt = s2m(aud.currentTime) + '/' + s2m(aud.duration);
_aud.drawUi(txt, val, aud.paused);
};
audCanv.onclick = (e) => {
if(_play) aud.paused ? aud.play() : aud.pause();
if(_change) {
var deg = Math.atan2(e.offsetY - _aud.cy, e.offsetX - _aud.cx) * 180 / Math.PI;
deg += (e.offsetX < _aud.cx && e.offsetY < _aud.cy) ? 450 : 90;
aud.currentTime = aud.duration * deg / 360;
};
};
audCanv.onmousemove = (e) => {
var _ex = e.offsetX,
_ey = e.offsetY,
_cx = _aud.cx,
_cy = _aud.cy,
r1 = 10,
r2 = _aud.r + 10; //+10: lineWidth
if(innerCircle(_ex, _ey, _cx, _cy, r2) && innerCircle(_ex, _ey, _cx, _cy, r2 - 20) === false) {
_change = 1;
_play = 0;
} else {
_change = 0;
_play = 0;
}
if(innerCircle(_ex, _ey, _cx, _cy, r1)) {
_change = 0;
_play = 1;
}
audCanv.style.cursor = ['default', 'pointer'];
audCanv.title = !_change && !_play ? '' : _change ? '调节进度' : aud.paused ? '播放' : '暂停';
};
var innerCircle = (ex,ey,cx,cy,r) => Math.sqrt((ex - cx) ** 2 + (ey - cy) ** 2) <= r;
var s2m = (s) => (Math.floor(s / 60)).toString().padStart(2, '0') + ':' + (Math.floor(s % 60)).toString().padStart(2, '0');
</script> 代码:
<canvas id="audCanv" width="400" height="240" style="margin: 20px auto; display: block; background: #333;"></canvas>
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=29999537" autoplay loop></audio>
<script>
const ww = audCanv.width, hh = audCanv.height;
const ctx = audCanv.getContext('2d');
var _play = 0, _change = 0;
class Audio {
constructor(ctx,config) {
this.ctx = ctx;
this.cf = config;
this.cx = config.w / 2;
this.cy = config.h - config.size / 2 - 20;
this.r = config.size / 2;
};
drawUi(text,value,flag) {
this.ctx.clearRect(0, 0, this.cf.w, this.cf.h);
this.ctx.lineCap = 'round';
this.ctx.lineWidth = 10;
this.ctx.strokeStyle = 'rgba(192,192,192,.95)';
ctx.beginPath();
this.ctx.arc(this.cx, this.cy, this.r, 0, Math.PI * 2);
this.ctx.stroke();
this.ctx.strokeStyle = 'rgba(255,250,250,.85)';
ctx.beginPath();
this.ctx.arc(this.cx, this.cy, this.r, 1.5 * Math.PI, Math.PI * (2 * value + 1.5));
this.ctx.stroke();
this.ctx.fillStyle = 'rgba(255,250,250,.85)';
if(flag) {
this.ctx.beginPath();
this.ctx.moveTo(this.cx - 10, this.cy - 10);
this.ctx.lineTo(this.cx - 10, this.cy + 10);
this.ctx.lineTo(this.cx + 10, this.cy);
this.ctx.closePath();
this.ctx.fill();
}else{
this.ctx.fillStyle = 'white';
this.ctx.beginPath();
this.ctx.fillRect(this.cx - 10, this.cy - 10, 4, 20);
this.ctx.fillRect(this.cx + 4, this.cy - 10, 4, 20);
}
this.ctx.font = 'normal 13px sans-serif';
this.ctx.textAlign = 'center';
this.ctx.textBaseline = 'middle';
this.ctx.beginPath();
this.ctx.fillText(text, this.cx, this.cy + 35);
this.ctx.fill();
};
};
var option = {w: ww, h: hh, size: 140};
var _aud = new Audio(ctx,option);
_aud.drawUi('00:00/00:00',0,0);
aud.ontimeupdate = () => {
var val = aud.currentTime / aud.duration;
var txt = s2m(aud.currentTime) + '/' + s2m(aud.duration);
_aud.drawUi(txt, val, aud.paused);
};
audCanv.onclick = (e) => {
if(_play) aud.paused ? aud.play() : aud.pause();
if(_change) {
var deg = Math.atan2(e.offsetY - _aud.cy, e.offsetX - _aud.cx) * 180 / Math.PI;
deg += (e.offsetX < _aud.cx && e.offsetY < _aud.cy) ? 450 : 90;
aud.currentTime = aud.duration * deg / 360;
};
};
audCanv.onmousemove = (e) => {
var _ex = e.offsetX,
_ey = e.offsetY,
_cx = _aud.cx,
_cy = _aud.cy,
r1 = 10,
r2 = _aud.r + 10; //+10: lineWidth
if(innerCircle(_ex, _ey, _cx, _cy, r2) && innerCircle(_ex, _ey, _cx, _cy, r2 - 20) === false) {
_change = 1;
_play = 0;
} else {
_change = 0;
_play = 0;
}
if(innerCircle(_ex, _ey, _cx, _cy, r1)) {
_change = 0;
_play = 1;
}
audCanv.style.cursor = ['default', 'pointer'];
audCanv.title = !_change && !_play ? '' : _change ? '调节进度' : aud.paused ? '播放' : '暂停';
};
var innerCircle = (ex,ey,cx,cy,r) => Math.sqrt((ex - cx) ** 2 + (ey - cy) ** 2) <= r;
var s2m = (s) => (Math.floor(s / 60)).toString().padStart(2, '0') + ':' + (Math.floor(s % 60)).toString().padStart(2, '0');
</script>
Math.atan2(),返回从原点 (0,0) 到 (x,y) 点的线段与 x 轴正方向之间的平面角度 (弧度值),也就是 Math.atan2(y,x);换言之, math.atan2(y,x) 返回给定的 y 及 x 坐标值的反正切值 atan(y / x),以弧度为单位,结果是在 -pi 和 pi 之间。我们这里使用它来处理进度条被点击时点击点与进度的关系,通过角度来实现。
在svg相类似的播放器中,我们也用到了这个 Math.atan2() 这个播放器好像以前有这样的样式的,我收藏在最喜欢的播放器之一中{:4_173:} 小辣椒 发表于 2024-5-27 12:30
这个播放器好像以前有这样的样式的,我收藏在最喜欢的播放器之一中
容易做的 马黑黑 发表于 2024-5-27 12:40
容易做的
这个播放器做双语歌词用了几次 小辣椒 发表于 2024-5-27 12:43
这个播放器做双语歌词用了几次
挺好用的吧 问老师,如果音乐只有0.4左右这个播放器要否调整? 进来看到一个漂亮的小播。。。我点个赞。。 马黑黑 发表于 2024-5-27 12:20
Math.atan2(),返回从原点 (0,0) 到 (x,y) 点的线段与 x 轴正方向之间的平面角度 (弧度值),也就是 Math.at ...
看了一眼烧脑,溜了溜了。。 半拉子工程,这个名字起得好。。
看上去毛坯可以正常使用,缺点软装{:4_170:}
南无月 发表于 2024-5-27 18:02
半拉子工程,这个名字起得好。。
看上去毛坯可以正常使用,缺点软装
{:4_172:} 南无月 发表于 2024-5-27 18:02
看了一眼烧脑,溜了溜了。。
比较高端的数学知识点 南无月 发表于 2024-5-27 18:01
进来看到一个漂亮的小播。。。我点个赞。。
感谢点赞 梦江南 发表于 2024-5-27 14:12
问老师,如果音乐只有0.4左右这个播放器要否调整?
这个现在还不太合适投入使用环节 马黑黑 发表于 2024-5-27 18:06
感谢点赞
天经地义的事儿不用费劲儿谢{:4_170:} 马黑黑 发表于 2024-5-27 18:06
比较高端的数学知识点
那我就放心的忽略了,反正看不懂{:4_170:} 马黑黑 发表于 2024-5-27 18:05
{:4_173:}等精装 南无月 发表于 2024-5-27 20:08
那我就放心的忽略了,反正看不懂
需要至少大学本科五年的学历 南无月 发表于 2024-5-27 20:08
等精装
出来了,回家看看去