如题,使用es6写了一个弹幕组件,经过babelrc转换后symbol依旧不兼容低版本安卓浏览器,如何改写成es5语法呢?
html
// 初始化弹幕画布
var newdm = DanMu($('#live-barrager')[0], {
auto: true,
enableEvent: true
});
var data = {
"text": "测试数据",
"idx": Math.ceil(Math.random() * 100),
"time": new Date().getTime(),
"type": "slide"
};
newdm.inputData(data); //向弹幕插入数据
js代码:
(function(window, Math, undefined) {
const loop = Symbol("loop");
const init = Symbol("init"); //初始化
const requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
//普通弹幕
class constructDM {
constructor(cv, opts = {}) {
this.save = [];
this.canvas = cv;
this.cxt = cv.getContext('2d');
this.width = 0;
this.height = 0;
this.rows = {
slide: [],
top: [],
bottom: []
}; //存放不同类型弹幕的通道数
this.Tween = new Proxy(new Tween(), {
get: function(target, key) {
if (typeof target[key] == "function")
return target[key].bind(target);
return target[key];
}
}); //Tween时间曲线
this.leftTime = opts.leftTime || 2000; //头部、底部静止型弹幕的显示时长
this.space = opts.space || 5; //弹幕的行距
this.unitHeight = 0; //弹幕的高度
this.rowNum = 0; //通道行数
this.direction = opts.direction || "rtol"; //弹幕方向 ,默认从右往左
this.duration = opts.duration || 9000; //弹幕运动时间
this.type = opts.type || "quad"; //Tween算法种类,默认为quad(二次方)
this.timing = opts.timing || "linear"; //Tween时间曲线
this.startIndex = 0; //循环时的初始下标
this.looped = false; //是否已经经历过一次循环
this.changeStyle(opts);
}
//添加弹幕
add(obj) {
if (!obj) return;
//如果已经可以计算文本宽度,则直接进行计算
if (this.looped)
this.countWidth([obj]);
this.save.push(obj);
}
//清除所有弹幕
clear() {
this.save = [];
this.startIndex = 0;
}
//暂停
pause() {
this.paused = true;
}
//播放
run() {
this.paused = false;
}
//清屏
clearRect() {
this.cxt.clearRect(0, 0, this.width, this.height);
}
//修改类型
changeTiming(timing, type) {
this.type = type || "quad";
this.timing = timing || "linear";
}
//修改方向
changeDirection(direction) {
this.clear();
this.direction = direction || "rtol";
}
//合并字体
font() {
this.globalFont = this.globalStyle +
" " + this.globalWeight +
" " + this.globalSize +
" " + this.globalFamily;
}
//改变全局样式
changeStyle(opts = {}) {
//文本属性保存
this.globalSize = opts.fontSize || this.globalSize || "28px"; //字体大小
this.globalFamily = opts.fontFamily || this.globalFamily || "Microsoft Yahei"; //字体
this.globalStyle = opts.fontStyle || this.globalStyle || "normal"; //字体样式
this.globalWeight = opts.fontWeight || this.globalWeight || "normal"; //字体粗细
this.globalColor = opts.fontColor || this.globalColor || "#fff"; //字体颜色
this.opacity = opts.opacity || this.opacity || 1; //透明程度
//表示进行过一次全局样式变化
this.globalChanged = true;
}
//启用全局样式
initStyle(cxt) {
this.globalChanged = false;
//合并font属性
this.font();
//更新全局样式
cxt.font = this.globalFont;
cxt.textBaseline = "middle";
cxt.fillStyle = this.globalColor;
cxt.globalAlpha = this.opacity;
}
//重置弹幕
reset(resetIndex = 0) {
//resetIndex表示想要开始重置的弹幕的下标,系统想重置该值以后的弹幕
let [items, w, leftTime, i, item] = [this.save, this.width, this.leftTime, resetIndex];
for (; item = items[i++];) {
if (item.type == "slide") {
item.x = w;
item.rowRid = false;
} else {
item.leftTime = leftTime
}
item.pastTime = 0;
item.recovery = false;
}
this.startIndex = resetIndex;
}
//更新canvas size
getSize() {
this.width = this.canvas.width;
this.height = this.canvas.height;
this.deleteRow();
this.countRows();
this.globalChanged = true;
}
//消除item的row
deleteRow() {
let [items, i, item] = [this.save, 0];
for (; item = items[i++];) {
item.row = null;
}
}
//生成通道行
countRows() {
//保存临时变量
let unitHeight = parseInt(this.globalSize) + this.space;
let [rowNum, rows] = [
((this.height - 20) / unitHeight) >> 0,
this.rows
];
//重置通道
for (let key of Object.keys(rows)) {
rows[key] = [];
}
//重新生成通道
for (let i = 0; i < rowNum; i++) {
let obj = {
idx: i,
y: unitHeight * i + 20
};
rows.slide.push(obj);
i >= rowNum / 2 ? rows.bottom.push(obj) : rows.top.push(obj);
}
//更新实例属性
this.unitHeight = unitHeight;
this.rowNum = rowNum;
}
//获取通道
getRow(item) {
//如果该弹幕正在显示中,则返回其现有通道
if (item.row)
return item.row;
//获取新通道
const [rows, type] = [this.rows, item.type];
const row = (type != "bottom" ? rows[type].shift() : rows[type].pop());
//生成临时通道
const tempRow = this["getRow_" + type]();
if (row && item.type == "slide") {
item.duration -= (row.idx * 10); //调整速度
}
//返回分配的通道
return row || tempRow;
}
getRow_bottom() {
return {
y: 20 + this.unitHeight * ((Math.random() * this.rowNum / 2 + this.rowNum / 2) << 0),
speedChange: false,
tempItem: true
};
}
getRow_slide() {
return {
y: 20 + this.unitHeight * ((Math.random() * this.rowNum) << 0),
speedChange: true,
tempItem: true
};
}
getRow_top() {
return {
y: 20 + this.unitHeight * ((Math.random() * this.rowNum / 2) << 0),
speedChange: false,
tempItem: true
};
}
//计算宽度
countWidth(items, cxt = this.cxt) {
this.looped = true;
let [cw, i, item] = [this.width, 0];
for (; item = items[i++];) {
let w = cxt.measureText(item.text).width >> 0;
item.width = w;
item.height = parseInt(this.globalSize);
//更新初始 x
item.x = cw;
item.duration = this.duration; //赋值持续时间
item.pastTime = 0;
if (item.type != "slide") {
item.x = (cw - w) / 2;
item.leftTime = this.leftTime;
}
}
}
//更新每个弹幕的单独样式
updateStyle(item, cxt) {
cxt.font = this.globalStyle +
" " + this.globalWeight +
" " + item.fontSize +
" " + this.globalFamily;
cxt.fillStyle = item.color || this.globalColor;
}
//循环
update(w, h, time) {
let [items, cxt, Tween] = [this.save, this.cxt, this.Tween[this.type]];
this.globalChanged && this.initStyle(cxt); //初始化全局样式
!this.looped && this.countWidth(items); //计算文本宽度以及初始化位置(只执行一次)
if (this.paused) return false; //暂停
this.refresh(items); //更新初始下标startIndex
let [i, item] = [this.startIndex];
cxt.clearRect(0, 0, w, h);
for (; item = items[i++];) {
let iw = item.width;
let ds = this.getDiretionSettings(iw, w); //获取不同方向时的设置
this.step(item, time, ds, Tween, this.timing);
this.draw(item, cxt);
this.recovery(item, ds);
}
}
//计算
step(item, time, ds, Tween, timing) {
let [row, iw] = [this.getRow(item), item.width]; //取得通道
//如果通道已满,则新弹幕变更速度防止弹幕重叠
if (row.speedChange) {
row.speedChange = false;
item.duration -= ((Math.random() * 5000) >> 0);
}
item.pastTime += time;
//更新参数
item.leftTime ? item.leftTime -= time : "";
item.x = (item.type == "slide" && Tween(timing, item.pastTime, ds.start, ds.dist, item.duration)) || item.x;
item.y = item.y || row.y;
item.row = row;
}
//绘制
draw(item, cxt) {
//如果已经显示完成,则不显示
if (item.recovery || item.hide)
return false;
cxt.save();
if (item.change) {
this.updateStyle(item, cxt);
}
let [text, x, y] = [item.text, item.x, item.y];
cxt.fillText(text, x, y);
cxt.restore();
}
//回收弹幕和通道
recovery(item, ds) {
if (item.type == "slide") {
item.recovery = this.recoverySlide(item, ds);
return false;
}
item.recovery = this.recoveryStatic(item);
}
recoverySlide(item, ds) {
//回收slide类型
let x = item.x;
if (!item.rowRid && ds.flag(x) && !item.row.tempItem) {
this.rows[item.type].unshift(item.row);
item.rowRid = true; //表明该行已被释放
}
if (item.pastTime <= item.duration)
return false;
return true;
}
recoveryStatic(item) {
if (item.leftTime > 0)
return false;
let type = item.type;
if (!item.row.tempItem) {
this.rows[type].unshift(item.row);
item.row = null;
}
return true;
}
//更新下标
refresh(items) {
let [i, item, rows] = [this.startIndex, , this.rows];
//通道排序
for (let key of Object.keys(rows)) {
rows[key].sort(function(a, b) {
return a.y - b.y;
});
}
for (; item = items[i++];) {
if (!item.recovery) return false;
//更新下标并清除row
this.startIndex = i;
item.row = null;
}
}
//direction,不同方向的设定
getDiretionSettings(iw, w) {
if (this.direction == "ltor")
return {
start: -iw, //起点
dist: iw + w, //位移
flag: (x) => x >= iw //判断该弹幕是否显示完全
};
return {
start: w,
dist: -iw - w,
flag: (x) => x < w - iw
};
}
}
//Tween运动时间曲线
class Tween {
constructor() {
}
linear(t, b, c, d) {
return c * t / d + b;
}
quad(type, ...data) {
let linear = this.linear;
const trail = {
linear: linear,
easeIn: (t, b, c, d) => c * (t /= d) * t + b,
easeOut: (t, b, c, d) => -c * (t /= d) * (t - 2) + b,
easeInOut: (t, b, c, d) => {
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
return -c / 2 * ((--t) * (t - 2) - 1) + b;
}
}
return !!trail[type] && trail[type](...data);
}
cubic(type, ...data) {
let linear = this.linear;
const trail = {
linear: linear,
easeIn: (t, b, c, d) => c * (t /= d) * t * t + b,
easeOut: (t, b, c, d) => c * ((t = t / d - 1) * t * t + 1) + b,
easeInOut: (t, b, c, d) => {
if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
return c / 2 * ((t -= 2) * t * t + 2) + b;
}
}
return !!trail[type] && trail[type](...data);
}
quart(type, ...data) {
let linear = this.linear;
const trail = {
linear: linear,
easeIn: (t, b, c, d) => c * (t /= d) * t * t * t + b,
easeOut: (t, b, c, d) => -c * ((t = t / d - 1) * t * t * t - 1) + b,
easeInOut: (t, b, c, d) => {
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
}
}
return !!trail[type] && trail[type](...data);
}
quint(type, ...data) {
let linear = this.linear;
const trail = {
linear: linear,
easeIn: (t, b, c, d) => c * (t /= d) * t * t * t * t + b,
easeOut: (t, b, c, d) => c * ((t = t / d - 1) * t * t * t * t + 1) + b,
easeInOut: (t, b, c, d) => {
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
}
}
return !!trail[type] && trail[type](...data);
}
}
//main
class DMer {
//初始化
constructor(wrap, opts = {}) {
//datas
this.wrapper = wrap;
this.width = wrap.clientWidth;
this.height = wrap.clientHeight;
this.canvas = document.createElement("canvas");
this.normal = new constructDM(this.canvas, opts);
this.name = opts.name || "";
this.fps = 0;
//status
this.drawing = opts.auto || false;
//fn
this[init]();
this[loop]();
}
[init]() {
this.canvas.style.cssText = "position:absolute;z-index:100;top:0;left:0;";
this.setSize();
this.wrapper.appendChild(this.canvas);
}
//loop
[loop](normal = this.normal, prev = new Date().getTime()) {
let now = new Date().getTime();
if (!this.drawing) {
normal.clearRect();
return false;
} else {
let [w, h, time] = [this.width, this.height, now - prev];
this.fps = 1000 / time >> 0;
normal.update(w, h, time);
}
requestAnimationFrame(() => { this[loop](normal, now); });
}
// API
//添加数据
inputData(obj = {}) {
if (typeof obj != "object" || !obj.type) {
return false;
}
this.normal.add(obj);
}
//清除所有弹幕
clear() {
this.normal.clear();
}
//重置
reset(i, j) {
this.normal.reset(i);
}
//暂停
pause() {
this.normal.pause();
}
//继续
run() {
this.normal.run();
}
//设置宽高
setSize(w = this.width, h = this.height) {
if (!Number.isInteger(w) || w < 0 || !Number.isInteger(h) || h < 0)
return false;
this.width = w;
this.height = h;
this.canvas.width = w;
this.canvas.height = h;
this.normal.getSize();
}
//获取宽高
getSize() {
return {
width: this.width,
height: this.height
};
}
//改变全局样式
changeStyle(opts = {}) {
this.normal.changeStyle(opts);
}
//改变普通弹幕方向
changeDirection(direction) {
this.normal.changeDirection(direction);
}
//改变动画时间曲线
changeTiming(timing, type) {
this.normal.changeTiming(timing, type);
}
//启用
start() {
if (this.drawing)
return false;
this.drawing = true;
this[loop]();
}
//停止
stop() {
this.drawing = false;
}
//fps
getFPS() {
return this.fps;
}
}
let DanMu = function(wrapper, opts) {
let proxyDMer = new Proxy(new DMer(wrapper, opts), {
get: function(target, key) {
if (typeof target[key] == "function")
return target[key].bind(target);
return target[key];
}
});
let DM = proxyDMer;
return {
pause: DM.pause, //暂停
run: DM.run, //继续
start: DM.start, //运行
stop: DM.stop, //停止
changeStyle: DM.changeStyle, //修改普通弹幕全局样式
setSize: DM.setSize, //修改宽高
inputData: DM.inputData, //向普通弹幕插入数据
clear: DM.clear, //清除所有弹幕
reset: DM.reset, //重新从某个弹幕开始
getSize: DM.getSize, //获取宽高,
timing: DM.changeTiming, //修改timing
direction: DM.changeDirection, //修改弹幕方向
getFPS: DM.getFPS //获取fps
};
};
window.DanMu = DanMu;
if (typeof module != 'undefined' && module.exports) {
module.exports = DanMu;
} else if (typeof define == "function" && define.amd) {
define(function() { return DanMu; });
}
})(window, Math);