web视频编辑时需要一个时间标尺,方案采用:canvas 完成刻度回话和比例缩放处理
效果
需求:
- 需要一个表示时间刻度尺,并在刻度上显示时间;
- 点击刻度可以获得当前的时间;
- 50%比例以下按1/50 方式显示时间,50以上按约定时间序列构成的抛物线递进显示
- 允许在5%带100%调节比例尺大小;
- 允许传入时间获得当前的刻度位置坐标点;
问题:
1、时间和长度如何转换?
2、不同比例,这个比例函数是什么?
源码
<!DOCTYPE html>
<html>
<style>
.btn-rate{
top:5px;
}
</style>
<body>
<div>
<canvas id="ruler"></canvas>
<div class="btn-rate">
<input id='rate' type='text' value="50"></input>%
<button onClick='changRate(1)'> </button><button onClick='changRate(-1)'>-</button>
</div>
</div>
</body>
<script>
(function (scope){
// el 操作组件,标尺长度
var ruler=function(el,cfg){
this.el = el; //画布对象
this.cfg = cfg; //组件配置
this.post ={x:0,y:0}; //当前鼠标位置
this.currentTime =0; //当前鼠标位置
this.init(el,cfg);
return this;
}
ruler.prototype={
// 初始化对象
init:function(){
//标尺参数
this.bgColor= this.cfg.color ||'#000000'; //背景黑色
this.width = parseInt(this.cfg.width) || 2000; //标尺宽度
this.height = parseInt(this.cfg.height) || 70; //标尺高度
//标尺刻度参数
this.lineColor= this.cfg.lineColor ||'#C0C0C0'; //线的颜色
this.lineMaxHeight= parseInt(this.cfg.lineMaxHeight) || 20 //最大高度
this.lineTopHeight= parseInt(this.cfg.lineTopHeight) || 20 //离标尺上边距离
this.lineWidth = parseInt(this.cfg.lineWidth) || 2 //刻线宽度
this.lineTxtTop = parseInt(this.cfg.lineTxtTop) || 10 //刻线底端和刻度文字间距
//时间有关参数,用于长度转换成时间
this.rateTemp = parseInt(this.cfg.rate) || 50; //默认: 50% 比例
this.lineSpace = parseInt(this.cfg.lineSpace) || 10; //默认:在50倍比例尺下,1刻线间距10个像素,10像素=1秒
this.timeUnit = parseInt(this.cfg.timeUnit) || 1 ; //默认: 标尺单位 默认秒
//获取一个实际使用的比例关系:rate
this.computeRate();
//初始化一个标尺
this.ctx = this.initCanvas();
this.drawLine(this.ctx);
},
computeRate:function(){
if(this.rateTemp >50){
var t = (this.rateTemp-50)/5
//this.rate =( 0.04*Math.pow(this.rateTemp,2)-1.8*this.rateTemp )*0.1; //
this.rate = (10*(t 1) (1 t)*t)*10/100
}else{
this.rate = this.rateTemp / 50
}
},
//初始化:画布
initCanvas:function(){
var ctx = this.el.getContext('2d'); //
ctx.canvas.width = this.width;
ctx.canvas.height = this.height;
ctx.fillStyle = this.bgcolor;
ctx.fillRect(0, 0,this.width,this.height);
ctx.stroke();
let that=this;
//添加点击事件:获取当前坐标,到时用于转换成当前的时间
this.el.addEventListener("click" , function(e){
that.post.x = e.clientX;
that.post.y = e.clientY;
that.currentTime = that.getTimeByXy(e.clientX,that)
//console.log('ruler--click:',that.formartTime(that.currentTime))
})
return ctx;
},
// 设置比例尺: 10% 50% 设置比例尺影响时间
setRate:function(rate){
if(rate<=0){rate=50} ;// 在时间转坐标过程这个rate 最为被除数 不可以等于0或者小于0的
this.rateTemp = parseInt(rate)
this.computeRate();
//重新初始化刻度尺
this.ctx=this.initCanvas();
this.drawLine(this.ctx);
},
//画标尺刻度线
drawLine:function(ctx){
ctx.beginPath();
ctx.strokeStyle = this.lineColor; //设置线条的样式颜色
ctx.lineWidth = this.lineWidth; //设置描边的线宽
//开始x坐标
var x = 0;
//开始y坐标
var y = this.lineMaxHeight this.lineTopHeight;
//最小刻线长度
var minlen = this.lineMaxHeight/4;
var dh = minlen;//当前刻线长度
for(var i=0;i<this.width/this.lineSpace;i ){
x = i*this.lineSpace; //当前x点位置: i*分割 初始位置
dh =minlen;
// 如果是10的倍数
if(i%5==0){
dh = this.lineMaxHeight/1.5 ; //逢5刻度:刻度长度
if(i==0){
dh = this.lineMaxHeight; //逢10刻度长度
//将坐标转成时间
ctx.save() //保存环境
ctx.translate(x,y this.lineTxtTop); //坐标移动
//画:时间文本
this.drawTxt(ctx,this.formartTime(this.getTimeByXy(x,this)));
ctx.restore();//恢复环境
}
}
ctx.moveTo(x, y); //开始点
ctx.lineTo(x, y-dh); //结束点: y点减出当前刻线高度
}
ctx.stroke();
ctx.closePath()
},
//通过坐标点获取当前的时间值:统一转换成秒
getTimeByXy:function(x,that){
return parseInt(that.rate*x/(that.lineSpace));
},
//通过时间获取当前坐标: time 单位为秒
getPostBytime:function(time){
return parseInt(time*that.lineSpace/that.rate);
},
//将时间转成:00:00.00 (分钟:秒)
formartTime:function(curTime){
let b = curTime.toString().split(".");
let f = b[1] || '00'; //小数位数
let theTime = parseInt(b[0]); //需要转换的时间秒
let second = 0; //秒
let minute = 0; //分
let hour = 0; //小时
if(theTime > 60) {
minute = parseInt(theTime/60);
second = parseInt(theTime`); //求余
if(minute>60){
hour = parseInt(minute/60);
minute = parseInt(minute`); //求余
}
}else{
second = curTime;
}
//时间补零操作
var prefixZero= function(num,n){
return (Array(n).join(0) num).slice(-n);
};
return prefixZero(minute,2) ':' prefixZero(second,2) '.' f
},
//画一个文本在屏幕的某个位置
drawTxt:function(ctx,str,pos){
ctx.font = "10px sans-serif";//设置字体大小
ctx.textAlign = "center";
ctx.textBaseline = "top";
ctx.fillStyle = "#FFFFFF"; //白色字体
ctx.fillText(str,0,0);
}
}
scope.Ruler=ruler;
})(window)
// 获取
var el=document.getElementById("ruler");
// 配置参数
var cfg={'name':'ruler','length':60}
var ruler=new Ruler(el,cfg);
var rate =1;
var t=1
function changRate(value){
let el = document.getElementById("rate");
let rate = parseInt(el.value)
if(value>0){
//缩小
rate = rate t;
}else{
//放大
rate = rate - t;
}
// 比例大于100设置为100
if(rate>100){rate=100;}
// 比例小于5 设置为5
if(rate<5){rate=5;}
el.value = rate;
if(rate<=0){rate=1}
console.log('ruler--changRate',rate)
ruler.setRate(rate);
}
</script>
</html>
源码说明:
1、关于50%以下:按1/50每格显示时间
this.rate = this.rateTemp / 50
2、关于50%以上按规定时间序列显示时间
var t = (this.rateTemp-50)/5
//this.rate =( 0.04*Math.pow(this.rateTemp,2)-1.8*this.rateTemp )*0.1; //
this.rate = (10*(t 1) (1 t)*t)*10/100
以上两个公式都是正确的,注释掉的公式来自excle 二叉法拟函数获得
实际使用函数是个人推导出来,见下图
图片中A:表示不同的比例尺
A‘ 表示我要在不同比例时在刻度尺第10格要显示的的内容;
例如: 50% 比例尺 在第十个 显示: 10 秒
例如: 65% 比例尺 在第十个 显示: 52 秒
3、关于时间格式:00:00.00 (分:秒)
我们将在web上可编辑的视频的长度定位在1个小时以内,为此秒的小数去两位显示,以下函数非常关键
formartTime:function(curTime){
let b = curTime.toString().split(".");
let f = b[1] || '00'; //小数位数
.....
}
4、本js采用匿名函数方式编写,便于在webpack中打包和模块化使用
5、数据类型转换很重要:parseInt
6、画标尺刻度线主要方法
drawLine:function(ctx){ ....}
该方法中才有了:坐标平移方法化刻度时间,这个方法挺好用;但是在坐标系改变时需要对上下文环境进行存储,于是才有了这个两个方法
ctx.save() //保存环境
。。。。 //代码省略
ctx.restore();//恢复环境
,