-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcanvas-barrage.js
187 lines (155 loc) · 6.02 KB
/
canvas-barrage.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
;
(function() {
/**
*
* @param {object, string} oCanvas
* @param {array} aBarrage
* @param {object} option
*
* option = {
* multiLine: boolean,
* diffSpeed: boolean,
* speed: number,
* interval: number,
* colorArr: array,
* fontSize: number
*
* }
*/
// 弹幕方法
var canvasBarrage = function(oCanvas, aBarrage, option) {
// 对传入数据进行处理
if (!oCanvas || !aBarrage || !aBarrage.length) {
return;
}
// 对传入option处理
option = option ? option : {
multiLine: false,
diffSpeed: false,
speed: 1,
// interval: number,
// colorArr: array,
// fontSize: number
};
// 对传入的canvas参数进行处理
if (typeof oCanvas === 'string') {
var canvas = document.querySelector(oCanvas);
canvasBarrage(canvas, aBarrage, option);
return;
}
var canvas = oCanvas;
var context = canvas.getContext('2d');
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
// 计数器,用于计算绘制次数
var lastCounter = 0;
var curCounter = 0;
// 存储弹幕实例
var store = {};
// 字体大小
var fontSize = option.fontSize || canvas.width / 30;
// 颜色数组
var colorArr = ['red', 'skyblue', 'yellow', 'orange'] || option.colorArr;
var colorArrLength = colorArr.length;
// 上条弹幕字符数
var lastBarrageLength = 0;
// 上个弹幕位置
var lastX = 0;
// 弹幕间隔
var interval = option.interval || fontSize * 5;
// 弹幕实例方法
var Barrage = function(obj, index) {
// 判断X位置,第一个弹幕与其他弹幕的位置设置区别
this.x = index === 0 ? canvas.width : lastX;
// 判断是否多行
// 不是多行则默认Y位置为字体大小
this.y = option.multiLine ? canvas.height * Math.random() : fontSize;
// 若多行Y位置的极限状态(上要留空一个字体大小的位置,下最大紧贴底部)
if (this.y < fontSize) {
this.y = fontSize;
} else if (this.y > canvas.height - fontSize) {
this.y = canvas.height - fontSize;
}
// 判断弹幕速度是否相同
this.speed = option.speed || 1;
this.moveX = option.diffSpeed ? this.speed + Math.random() * 3 : this.speed;
// 储存当前弹幕参数
this.params = obj;
// 定义当前弹幕的绘制方法
this.draw = function () {
var params = this.params;
// 弹幕的边框颜色
context.strokeStyle = colorArr[index % colorArrLength];
// 定义弹幕字体
context.font = fontSize + 'px "microsoft yahei", sans-serif';
// 弹幕的填充颜色
context.fillStyle = colorArr[index % colorArrLength];
// 填充弹幕(根据弹幕实例自身的x、y值)
context.fillText(params.value, this.x, this.y);
// 绘制弹幕轮廓(根据弹幕实例自身的x、y值)
context.strokeText(params.value, this.x, this.y);
};
// 储存当前弹幕的字符数
lastBarrageLength = obj.value.length;
// 储存当前弹幕长度加上间隔显示完的X位置
lastX = this.x + lastBarrageLength * fontSize + interval;
};
// 定义绘制弹幕方法
var draw = function () {
for (var index in store) {
// 取出弹幕实例
var barrage = store[index];
// 获取当前弹幕实例的字数
var textLength = barrage.params.value.length;
// 位置变化
barrage.x -= barrage.moveX;
// 判断弹幕的横向位置,到达极值则重置位置
// 没有到达极值则继续按照原来的参数绘制
if (barrage.x < -1 * textLength * fontSize) {
// 移动到画布外部时候从右侧开始继续位移
// 重置当前弹幕位置时,判断最后一条评论的位置,如果已经全部显示在屏幕上,则重新开始的评论从屏幕右侧开始;
// 如果没有显示,则在最后一条评论后一定间隔后开始。
// 获取最后一条弹幕当前的横向位置(通过绘制次数及每次变化的X值求出移动距离)
var nowLastX = lastX - barrage.moveX * (curCounter - lastCounter);
// 更新当前弹幕的横向位置
barrage.x = nowLastX < canvas.width ? canvas.width : nowLastX;
// 更新当前弹幕的垂直位置
barrage.y = option.multiLine ? canvas.height * Math.random() : fontSize;
if (barrage.y < fontSize) {
barrage.y = fontSize;
} else if ( barrage.y > canvas.height - fontSize ) {
barrage.y = canvas.height - fontSize;
}
// 更新当前弹幕的变化速度
barrage.moveX = option.diffSpeed ? barrage.speed + Math.random() * 3 : barrage.speed;
// 储存当前弹幕的字数长度
lastBarrageLength = textLength;
// 储存当前弹幕长度加上间隔显示完的X位置
lastX = barrage.x + lastBarrageLength * fontSize + interval;
// 更新计数器,记录当前弹幕重置时的计数器
lastCounter = curCounter;
}
// 执行绘制方法,绘制所有储存的弹幕实例
store[index].draw();
}
};
// 定义渲染方法
var render = function (timeStamp) {
// 更新计数器
curCounter++;
// 清除画布
context.clearRect(0, 0, canvas.width, canvas.height);
// 执行绘制方法,绘制所有弹幕实例
draw();
// 调用原生方法,根据当前屏幕帧率继续渲染
requestAnimationFrame(render);
};
// 处理弹幕数组创建弹幕实例
aBarrage.forEach(function (obj, index) {
store[index] = new Barrage(obj, index);
});
// 调用渲染方法
render();
};
window.canvasBarrage = canvasBarrage;
}());