This repository has been archived on 2025-05-21. You can view files and clone it, but cannot push or open issues or pull requests.
2025-04-20 18:46:48 +08:00

229 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
录音 Recorder扩展动态波形显示
https://github.com/xiangyuecn/Recorder
*/
(function(factory){
var browser=typeof window=="object" && !!window.document;
var win=browser?window:Object; //非浏览器环境Recorder挂载在Object下面
var rec=win.Recorder,ni=rec.i18n;
factory(rec,ni,ni.$T,browser);
}(function(Recorder,i18n,$T,isBrowser){
"use strict";
var WaveView=function(set){
return new fn(set);
};
var ViewTxt="WaveView";
var fn=function(set){
var This=this;
var o={
/*
elem:"css selector" //自动显示到dom并以此dom大小为显示大小
//或者配置显示大小手动把waveviewObj.elem显示到别的地方
,width:0 //显示宽度
,height:0 //显示高度
H5环境以上配置二选一
compatibleCanvas: CanvasObject //提供一个兼容H5的canvas对象需支持getContext("2d")支持设置width、height支持drawImage(canvas,...)
,width:0 //canvas显示宽度
,height:0 //canvas显示高度
非H5环境使用以上配置
*/
scale:2 //缩放系数应为正整数使用2(3? no!)倍宽高进行绘制,避免移动端绘制模糊
,speed:9 //移动速度系数,越大越快
,phase:21.8 //相位,调整了速度后,调整这个值得到一个看起来舒服的波形
,fps:20 //绘制帧率调整后也需调整phase值
,keep:true //当停止了input输入时是否保持波形设为false停止后将变成一条线
,lineWidth:3 //线条基础粗细
//渐变色配置:[位置css颜色...] 位置: 取值0.0-1.0之间
,linear1:[0,"rgba(150,96,238,1)",0.2,"rgba(170,79,249,1)",1,"rgba(53,199,253,1)"] //线条渐变色1从左到右
,linear2:[0,"rgba(209,130,255,0.6)",1,"rgba(53,199,255,0.6)"] //线条渐变色2从左到右
,linearBg:[0,"rgba(255,255,255,0.2)",1,"rgba(54,197,252,0.2)"] //背景渐变色,从上到下
};
for(var k in set){
o[k]=set[k];
};
This.set=set=o;
var cCanvas="compatibleCanvas";
if(set[cCanvas]){
var canvas=This.canvas=set[cCanvas];
}else{
if(!isBrowser)throw new Error($T.G("NonBrowser-1",[ViewTxt]));
var elem=set.elem;
if(elem){
if(typeof(elem)=="string"){
elem=document.querySelector(elem);
}else if(elem.length){
elem=elem[0];
};
};
if(elem){
set.width=elem.offsetWidth;
set.height=elem.offsetHeight;
};
var thisElem=This.elem=document.createElement("div");
thisElem.style.fontSize=0;
thisElem.innerHTML='<canvas style="width:100%;height:100%;"/>';
var canvas=This.canvas=thisElem.querySelector("canvas");
if(elem){
elem.innerHTML="";
elem.appendChild(thisElem);
};
};
var scale=set.scale;
var width=set.width*scale;
var height=set.height*scale;
if(!width || !height){
throw new Error($T.G("IllegalArgs-1",[ViewTxt+" width=0 height=0"]));
};
canvas.width=width;
canvas.height=height;
var ctx=This.ctx=canvas.getContext("2d");
This.linear1=This.genLinear(ctx,width,set.linear1);
This.linear2=This.genLinear(ctx,width,set.linear2);
This.linearBg=This.genLinear(ctx,height,set.linearBg,true);
This._phase=0;
};
fn.prototype=WaveView.prototype={
genLinear:function(ctx,size,colors,top){
var rtv=ctx.createLinearGradient(0,0,top?0:size,top?size:0);
for(var i=0;i<colors.length;){
rtv.addColorStop(colors[i++],colors[i++]);
};
return rtv;
}
,genPath:function(frequency,amplitude,phase){
//曲线生成算法参考 https://github.com/HaloMartin/MCVoiceWave/blob/f6dc28975fbe0f7fc6cc4dbc2e61b0aa5574e9bc/MCVoiceWave/MCVoiceWaveView.m#L268
var rtv=[];
var This=this,set=This.set;
var scale=set.scale;
var width=set.width*scale;
var maxAmplitude=set.height*scale/2;
for(var x=0;x<=width;x+=scale) {
var scaling=(1+Math.cos(Math.PI+(x/width)*2*Math.PI))/2;
var y=scaling*maxAmplitude*amplitude*Math.sin(2*Math.PI*(x/width)*frequency+phase)+maxAmplitude;
rtv.push(y);
}
return rtv;
}
,input:function(pcmData,powerLevel,sampleRate){
var This=this;
This.sampleRate=sampleRate;
This.pcmData=pcmData;
This.pcmPos=0;
This.inputTime=Date.now();
This.schedule();
}
,schedule:function(){
var This=this,set=This.set;
var interval=Math.floor(1000/set.fps);
if(!This.timer){
This.timer=setInterval(function(){
This.schedule();
},interval);
};
var now=Date.now();
var drawTime=This.drawTime||0;
if(now-drawTime<interval){
//没到间隔时间,不绘制
return;
};
This.drawTime=now;
//切分当前需要的绘制数据
var bufferSize=This.sampleRate/set.fps;
var pcm=This.pcmData;
var pos=This.pcmPos;
var len=Math.max(0, Math.min(bufferSize,pcm.length-pos));
var sum=0;
for(var i=0;i<len;i++,pos++){
sum+=Math.abs(pcm[pos]);
};
This.pcmPos=pos;
//推入绘制
if(len || !set.keep){
This.draw(Recorder.PowerLevel(sum, len));
}
if(!len && now-This.inputTime>1300){
//超时没有输入,干掉定时器
clearInterval(This.timer);
This.timer=0;
}
}
,draw:function(powerLevel){
var This=this,set=This.set;
var ctx=This.ctx;
var scale=set.scale;
var width=set.width*scale;
var height=set.height*scale;
var speedx=set.speed/set.fps;
var phase=This._phase-=speedx;//位移速度
var phase2=phase+speedx*set.phase;
var amplitude=powerLevel/100;
var path1=This.genPath(2,amplitude,phase);
var path2=This.genPath(1.8,amplitude,phase2);
//开始绘制图形
ctx.clearRect(0,0,width,height);
//绘制包围背景
ctx.beginPath();
for(var i=0,x=0;x<=width;i++,x+=scale) {
if (x==0) {
ctx.moveTo(x,path1[i]);
}else {
ctx.lineTo(x,path1[i]);
};
};
i--;
for(var x=width-1;x>=0;i--,x-=scale) {
ctx.lineTo(x,path2[i]);
};
ctx.closePath();
ctx.fillStyle=This.linearBg;
ctx.fill();
//绘制线
This.drawPath(path2,This.linear2);
This.drawPath(path1,This.linear1);
}
,drawPath:function(path,linear){
var This=this,set=This.set;
var ctx=This.ctx;
var scale=set.scale;
var width=set.width*scale;
ctx.beginPath();
for(var i=0,x=0;x<=width;i++,x+=scale) {
if (x==0) {
ctx.moveTo(x,path[i]);
}else {
ctx.lineTo(x,path[i]);
};
};
ctx.lineWidth=set.lineWidth*scale;
ctx.strokeStyle=linear;
ctx.stroke();
}
};
Recorder[ViewTxt]=WaveView;
}));