寫在最前
本次分享一下使用canvas來進行視頻播放并且添加彈幕功能。
歡迎關注我的博客,不定期更新中——
效果圖
示例源碼見:源碼地址
[圖片上傳失敗...(image-63478a-1512320133960)]
可以看到上方為一段視頻奇唤,下面是用canvas來重新繪制的視頻,并且支持動態(tài)的添加彈幕伦意。
canvas載入視頻
canvas中的drawImage
方法繪制圖片所需要的數(shù)據(jù)源不單單是某張圖片咒唆,同樣可以是使用視頻的某一幀來進行繪制。就像這樣:
var video = document.getElementById('video')
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var ctx.drawImage(video, 0, 0, width, height);//當視頻開始播放后觸發(fā)這個方法可以開始繪制視頻
為什么通過canvas繪制視頻茶鹃?
因為canvas提供了getImageData
&& putImageData
方法使得操作者可以動態(tài)得來更改每一幀圖像的顯示狀態(tài)涣雕,如果你知道它應該怎么變:)
比如像MDN中提到的可以對上面這段視頻中的黃色背景進行色調(diào)的變化:mdn示例地址
this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
let frame = this.ctx1.getImageData(0, 0, this.width, this.height);
let l = frame.data.length / 4;
for (let i = 0; i < l; i++) {
let r = frame.data[i * 4 + 0];
let g = frame.data[i * 4 + 1];
let b = frame.data[i * 4 + 2];
if (g > 100 && r > 100 && b < 43)
frame.data[i * 4 + 3] = 0; //將視頻黃色部分的透明度進行了變化
}
this.ctx2.putImageData(frame, 0, 0);
視頻中效果截圖如下:
更多關于canvas的圖像操作可以參考下面這兩篇文章:
基于canvas的圖像處理可以實現(xiàn)很強大的功能,比如濾鏡啊之類的~
騰訊的Aolly Team團隊出品的AlloyImage - 基于HTML5技術的專業(yè)圖像處理庫就是個很好的范例闭翩。作者就搞不明白那些高深的東西了挣郭,什么拉普拉斯算子,各種算子:)
彈幕功能
彈幕功能分為兩部分:
- 監(jiān)聽新彈幕的推送
- 渲染彈幕到頁面
監(jiān)聽新彈幕的推送
通過維護一個彈幕數(shù)組來實時去渲染每一個彈幕字條的應有位置疗韵。而何時更新這個數(shù)組兑障,為了解耦作者使用了發(fā)布訂閱的方式來進行數(shù)組的更新。當然這里并不是一定要使用這種模式蕉汪,只不過作者剛剛學習完所以拿來用一下而已疯汁。千萬別噴我:)
var Event = (function(){
var list = {},
listen,
trigger,
remove;
listen = function(key,fn){ /收集監(jiān)聽事件
if(!list[key]) {
list[key] = [];
}
list[key].push(fn);
};
trigger = function(){/觸發(fā)后依次執(zhí)行回調(diào)
var key = Array.prototype.shift.call(arguments),
fns = list[key];
if(!fns || fns.length === 0) {
return false;
}
for(var i = 0, fn; fn = fns[i++];) {
fn.apply(this,arguments);
}
};
remove = function(key,fn){
var fns = list[key];
if(!fns) {
return false;
}
if(!fn) {
fns && (fns.length = 0);
}else {
for(var i = fns.length - 1; i >= 0; i--){
var _fn = fns[i];
if(_fn === fn) {
fns.splice(i,1);
}
}
}
};
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();
//調(diào)用方式
Event.listen('data', addNewWord)
$('#submit').click(function() { //點擊發(fā)送后便觸發(fā)data事件
var data = $('input').val()
Event.trigger('data', {
value: data,
})
})
function addNewWord (data) {
var newWord = new Barrage(this.canvas, this.ctx, data) //構建新的彈幕實例
wordObj.push(newWord)
},
渲染彈幕到頁面
聲明了一個彈幕的構造函數(shù)绽族,內(nèi)部包含了其各種屬性并且在原型鏈中添加了draw方法來進行繪制:
function Barrage(canvas, ctx, data) {
this.width = canvas.width
this.height = canvas.height
this.ctx = ctx
this.color = data.color || '#'+Math.floor(Math.random()*16777215).toString(16) //隨機顏色
this.value = data.value
this.x = this.width //x坐標
this.y = Math.random() * this.height
this.speed = Math.random() + 0.5
this.fontSize = Math.random() * 10 + 12
}
Barrage.prototype.draw = function() {
if(this.x < -200) {
return
} else {
this.ctx.font = this.fontSize + 'px "microsoft yahei", sans-serif';
this.ctx.fillStyle = this.color
this.x = this.x - this.speed
this.ctx.fillText(this.value, this.x, this.y)
}
}
最后
慣例po作者的博客碘橘,不定時更新中——
有問題歡迎在issues下交流阔籽。