|
|
请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
《起源》一帖,播放器控制器使用纯画布制作。canvas是操作十分繁琐的HTML元素,它是个空板,需要JS(或其他语言)在上面一一绘制图形,还必须不停地擦除、重绘。
帖子的播放器效果,只不过如下图,看上去简简单单:
却:
(一)进度条需要画两个长条矩形(也可以画线条);
(二)画两处文本;
(三)画一个圆;
(四)画播放/暂停按钮需要绘制一个三角形、两个小矩形。
这四样,如果单独画每一样,那都不是问题(ctx 是画笔):
——画矩形:ctx.fillRect(x,y,w,h); 其中,xy为矩形左上角坐标,w是矩形长度,h是矩形高度;
——画文本:ctx.fillText(text,x,y); 其中,text 是文本,xy是文本绘制的起点坐标;
——画圆:ctx.arc(x,y,r,0,2*Math.PI); 其中,xy是圆心坐标,r是圆半径,0是起始弧度,2*Math.PI 是结束弧度;
——画三角形:用画线方法 lineTo() 画三条前后衔接的封闭线即可,lineTo(x1,y1) 要先 moveTo(x,y)。
可以将各种图形的画法封装成函数:
//画矩形
let drawRect = (x,y,ww,hh,color) => {
ctx.beginPath();
ctx.fillStyle = color;
ctx.fillRect(x,y,ww,hh);
};
//画文本
let drawTxt = (text,x,y,align,color) => {
ctx.beginPath();
ctx.font = '16px sans-serif';
ctx.textAlign = align;
ctx.textBaseline = 'middle';
ctx.fillStyle = color;
ctx.fillText(text,x,y);
};
//画圆
let drawCircle = (x,y,r,color) => {
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.arc(x,y,r,0,2*Math.PI);
ctx.stroke();
};
//画三角形
let drawTriangle = (x,y,len,color) => {
ctx.beginPath();
ctx.fillStyle = color;
ctx.moveTo(x,y);
ctx.lineTo(x, y+len);
ctx.lineTo(x+len, y + len/2);
ctx.lineTo(x,y);
ctx.fill();
};
然后将这些函数再封装成一个总封装。封装前为了方便设置一些交互所有变量,先声明一个对象用以存储用得上的变量:
//创建 player 实体对象
let player = {
prog: 0,
track: w,
color: ['#ff0000','#a9a9a9'],
cur: '00:00',
dur: '00:00',
};
接下来才封装各种画法:
//整体封装
let drawAll = () => {
ctx.clearRect(0,0,w,h);
let btnColor = btnFlag ? player.color[0] : player.color[1]; //按钮颜色
drawRect(0,10,w, 4, player.color[1]); // 画线 :track
drawRect(0,10,player.prog, 4, player.color[0]); //画线 : prog
drawTxt(player.cur,w/2-22,h-20,'right',player.color[1]); //文本 : 当前播放到
drawCircle(w/2,h-20,16,btnColor); //圆环
drawTxt(player.dur,w/2 + 22,h-20,'left',player.color[1]); //文本 : 总时长
//暂停|播放按钮
aud.paused ? drawTriangle(w/2-6,h-28,16,btnColor) : (drawRect(w/2-6, h-28,4,16,btnColor), drawRect(w/2+2, h-28,4,16,btnColor));
};
至此,运行函数 drawAll() 便能得出大概的播放控制器样式,前提是,我们需要补上一些声明和HTML相关标签(比如audio等)。
以上代码只是揭示《起源》所用到的插件的核心代码制作。播放控制器的完整代码如下:
- <style>
- #papa { margin: auto; padding: 12px; width: 600px; height: 400px; color: red; border: 1px solid olive; position: relative; }
- #canv { position: absolute; left: calc(50% - 150px); top: calc(50% - 50px); }
- </style>
- <div id="papa">
- <canvas id="canv" width="300" height="60"></canvas>
- <audio id="aud" src="https://music.163.com/song/media/outer/url?id=2005217155.mp3" autoplay></audio>
- </div>
- <script>
- let ctx = canv.getContext('2d');
- let w = canv.width, h = canv.height;
- let btnFlag = false;
- let player = {
- prog: 0,
- track: w,
- color: ['#ff0000','#a9a9a9'],
- cur: '00:00',
- dur: '00:00',
- };
- //画圆
- let drawCircle = (x,y,r,color) => {
- ctx.beginPath();
- ctx.strokeStyle = color;
- ctx.lineWidth = 2;
- ctx.arc(x,y,r,0,2*Math.PI);
- ctx.stroke();
- };
- //画三角形
- let drawTriangle = (x,y,len,color) => {
- ctx.beginPath();
- ctx.fillStyle = color;
- ctx.moveTo(x,y);
- ctx.lineTo(x, y+len);
- ctx.lineTo(x+len, y + len/2);
- ctx.lineTo(x,y);
- ctx.fill();
- };
- //画矩形
- let drawRect = (x,y,ww,hh,color) => {
- ctx.beginPath();
- ctx.fillStyle = color;
- ctx.fillRect(x,y,ww,hh);
- };
- //画文本
- let drawTxt = (text,x,y,align,color) => {
- ctx.beginPath();
- ctx.font = '16px sans-serif';
- ctx.textAlign = align;
- ctx.textBaseline = 'middle';
- ctx.fillStyle = color;
- ctx.fillText(text,x,y);
- };
- //整体封装
- let drawAll = () => {
- ctx.clearRect(0,0,w,h);
- let btnColor = btnFlag ? player.color[0] : player.color[1]; //按钮颜色
- drawRect(0,10,w, 4, player.color[1]); // track
- drawRect(0,10,player.prog, 4, player.color[0]); //画线 : prog
- drawTxt(player.cur,w/2-22,h-20,'right',player.color[1]); //文本 : 当前播放到
- drawCircle(w/2,h-20,16,btnColor); //圆环
- drawTxt(player.dur,w/2 + 22,h-20,'left',player.color[1]); //文本 : 总时长
- //暂停|播放按钮
- aud.paused ? drawTriangle(w/2-6,h-28,16,btnColor) : (drawRect(w/2-6, h-28,4,16,btnColor), drawRect(w/2+2, h-28,4,16,btnColor));
- };
- //时间信息格式化
- let toMin = (val) => {if (!val) return '00:00';val = Math.floor(val);let min = parseInt(val / 60), sec = parseFloat(val % 60);if (min < 10) min = '0' + min;if (sec < 10) sec = '0' + sec;return min + ':' + sec;};
- //鼠标指针滑过按钮判断依据
- let overBtn = (e) => Math.sqrt((e.offsetX-w/2) ** 2 + (e.offsetY-(h-20)) ** 2) < 16;
- //鼠标指针滑过进度条判断依据
- let overProg = (e) => e.offsetY > 0 && e.offsetY < 15;
- //鼠标指针滑过画布监视
- canv.onmousemove = (e) => {
- canv.style.cursor = overBtn(e) || overProg(e) ? 'pointer' : 'default';
- canv.title = overProg(e) ? toMin(e.offsetX*aud.duration/w) : '';
- overBtn(e) ? (btnFlag = true,drawAll()) : (btnFlag = false,drawAll());
- }
- //按钮和进度条单击
- canv.onclick = (e) => {
- if(overBtn(e)) {
- aud.paused ? aud.play() : aud.pause();
- drawAll();
- }
- if(overProg(e)) {
- aud.currentTime = aud.duration * e.offsetX / w;
- }
- }
- //audio进度监视
- aud.addEventListener('timeupdate', () => {
- player.prog = aud.currentTime * w /aud.duration;
- player.cur = toMin(aud.currentTime);
- player.dur = toMin(aud.duration);
- drawAll();
- });
- drawAll();
- </script>
复制代码
|
评分
-
| 参与人数 3 | 威望 +130 |
金钱 +260 |
经验 +130 |
收起
理由
|
红影
| + 50 |
+ 100 |
+ 50 |
赞一个! |
小辣椒
| + 50 |
+ 100 |
+ 50 |
赞一个! |
风中飞尘
| + 30 |
+ 60 |
+ 30 |
很给力! |
查看全部评分
|