@rustle/danmuku
Version:
一个使用 dom + css 构建的弹幕库
1,289 lines (1,146 loc) • 39.5 kB
JavaScript
/*!
* Danmuku.js v0.1.5
* (c) 2019-2020 Imtaotao
* Released under the MIT License.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.Danmuku = factory());
}(this, function () { 'use strict';
function Timeline(manager) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var _manager$opts = manager.opts,
limit = _manager$opts.limit,
forceRender = _manager$opts.forceRender;
if (opts.forceRender) {
manager.setOptions({
limit: Infinity,
forceRender: true
});
}
return {
preEmiter: null,
timeStore: {},
specialTimeStore: {},
add: function add(timestamp, cfg, hooks, isForward) {
if (!this.timeStore[timestamp]) {
this.timeStore[timestamp] = [{
cfg: cfg,
hooks: hooks,
isForward: isForward
}];
} else {
this.timeStore[timestamp].push({
cfg: cfg,
hooks: hooks,
isForward: isForward
});
}
},
addSpecial: function addSpecial(timestamp, cfg) {
if (!this.specialTimeStore[timestamp]) {
this.specialTimeStore[timestamp] = [cfg];
} else {
this.specialTimeStore[timestamp].push(cfg);
}
},
emit: function emit(timestamp, clearOld) {
var ordinaryData = this.timeStore[timestamp];
var specialData = this.specialTimeStore[timestamp];
if (ordinaryData) {
ordinaryData.forEach(function (_ref) {
var cfg = _ref.cfg,
hooks = _ref.hooks,
isForward = _ref.isForward;
manager.send(cfg, hooks, isForward);
});
}
if (specialData) {
manager.sendSpecial(specialData);
}
if (clearOld) {
var clear = function clear(data) {
var keys = Object.keys(data);
if (keys.length > 0) {
for (var i = 0; i < keys.length; i++) {
var time = keys[i];
if (time < timestamp && data[time]) {
delete data[time];
}
}
}
};
clear(this.timeStore);
clear(this.specialTimeStore);
}
},
emitInterval: function emitInterval(timestamp, clearOld) {
if (timestamp !== preEmiter) {
this.preEmiter = timestamp;
this.emit(timestamp, clearOld);
}
},
destroy: function destroy() {
this.preEmiter = null;
this.timeStore = {};
this.specialTimeStore = {};
manager.setOptions({
limit: limit,
forceRender: forceRender
});
}
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
}
function _toArray(arr) {
return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest();
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
function warning(condition, message) {
if (condition) return;
throw new Error("Warning: ".concat(message));
}
function callHook(hooks, name) {
var args = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
if (hooks && typeof hooks[name] === 'function') {
return hooks[name].apply(null, args);
}
return null;
}
function createKey() {
return Math.random().toString(36).substr(2, 8);
}
function toNumber(val) {
return typeof val === 'number' ? val : typeof val === 'string' ? Number(val.replace('px', '')) : NaN;
}
function isRange(_ref, val) {
var _ref2 = _slicedToArray(_ref, 2),
a = _ref2[0],
b = _ref2[1];
if (val === a || val === b) return true;
var min = Math.min(a, b);
var max = min === a ? b : a;
return min < val && val < max;
}
function upperCase(_ref3) {
var _ref4 = _toArray(_ref3),
first = _ref4[0],
remaing = _ref4.slice(1);
return first.toUpperCase() + remaing.join('');
}
function timeSlice(len, fn) {
var i = -1;
var start = performance.now();
var run = function run() {
while (++i < len) {
if (fn() === false) {
break;
}
var cur = performance.now();
if (cur - start > 13) {
start = cur;
setTimeout(run);
break;
}
}
};
run();
}
var raf = window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : setTimeout;
function nextFrame(fn) {
raf(function () {
raf(fn);
});
}
var transitionProp = 'transition';
var transitionEndEvent = 'transitionend';
var transitionDuration = 'transitionDuration';
if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
transitionProp = 'WebkitTransition';
transitionEndEvent = 'webkitTransitionEnd';
transitionDuration = 'webkitTransitionDuration';
}
function whenTransitionEnds(node) {
return new Promise(function (resolve) {
var isCalled = false;
var end = function end() {
node.removeEventListener(transitionEndEvent, onEnd);
resolve();
};
var onEnd = function onEnd() {
if (!isCalled) {
isCalled = true;
end();
}
};
node.addEventListener(transitionEndEvent, onEnd);
});
}
var Barrage =
/*#__PURE__*/
function () {
function Barrage(itemData, hooks, time, manager, globalHooks) {
_classCallCheck(this, Barrage);
var RuntimeManager = manager.RuntimeManager;
var _manager$opts = manager.opts,
direction = _manager$opts.direction,
container = _manager$opts.container;
this.node = null;
this.hooks = hooks;
this.paused = false;
this.moveing = false;
this.data = itemData;
this.duration = time;
this.isSpecial = false;
this.trajectory = null;
this.manager = manager;
this.direction = direction;
this.container = container;
this.isChangeDuration = false;
this.globalHooks = globalHooks;
this.RuntimeManager = RuntimeManager;
this.key = itemData.key || createKey();
this.position = {
y: null
};
this.timeInfo = {
pauseTime: 0,
startTime: null,
prevPauseTime: null,
currentDuration: time
};
this.create();
}
_createClass(Barrage, [{
key: "getMovePercent",
value: function getMovePercent() {
var _this$timeInfo = this.timeInfo,
pauseTime = _this$timeInfo.pauseTime,
startTime = _this$timeInfo.startTime,
prevPauseTime = _this$timeInfo.prevPauseTime;
var currentTime = this.paused ? prevPauseTime : Date.now();
return (currentTime - startTime - pauseTime) / 1000 / this.duration;
}
}, {
key: "getMoveDistance",
value: function getMoveDistance() {
if (!this.moveing) return 0;
var percent = this.getMovePercent();
var containerWidth = this.RuntimeManager.containerWidth + this.getWidth();
return percent * containerWidth;
}
}, {
key: "getHeight",
value: function getHeight() {
return this.node && this.node.clientHeight || 0;
}
}, {
key: "getWidth",
value: function getWidth() {
return this.node && this.node.clientWidth || 0;
}
}, {
key: "getSpeed",
value: function getSpeed() {
var duration = this.timeInfo.currentDuration;
var containerWidth = this.RuntimeManager.containerWidth + this.getWidth();
return duration == null || containerWidth == null ? 0 : containerWidth / duration;
}
}, {
key: "create",
value: function create() {
this.node = document.createElement('div');
callHook(this.hooks, 'create', [this, this.node]);
callHook(this.globalHooks, 'barrageCreate', [this, this.node]);
}
}, {
key: "append",
value: function append() {
warning(this.container, 'Need container element.');
if (this.node) {
this.container.appendChild(this.node);
callHook(this.hooks, 'append', [this, this.node]);
callHook(this.globalHooks, 'barrageAppend', [this, this.node]);
}
}
}, {
key: "remove",
value: function remove(noCallHook) {
warning(this.container, 'Need container element.');
if (this.node) {
this.container.removeChild(this.node);
if (!noCallHook) {
callHook(this.hooks, 'remove', [this, this.node]);
callHook(this.globalHooks, 'barrageRemove', [this, this.node]);
}
}
}
}, {
key: "deletedInMemory",
value: function deletedInMemory() {
var index = -1;
var trajectory = this.trajectory;
var showBarrages = this.manager.showBarrages;
if (trajectory && trajectory.values.length > 0) {
index = trajectory.values.indexOf(this);
if (~index) trajectory.values.splice(index, 1);
}
if (showBarrages && showBarrages.length > 0) {
index = showBarrages.indexOf(this);
if (~index) showBarrages.splice(index, 1);
}
}
}, {
key: "destroy",
value: function destroy() {
this.remove();
this.moveing = false;
this.deletedInMemory();
callHook(this.hooks, 'destroy', [this, this.node]);
callHook(this.globalHooks, 'barrageDestroy', [this, this.node]);
this.node = null;
}
}, {
key: "pause",
value: function pause() {
if (!this.moveing || this.paused) return;
var moveDistance = this.getMoveDistance();
if (!Number.isNaN(moveDistance)) {
this.paused = true;
this.timeInfo.prevPauseTime = Date.now();
if (this.direction === 'right') {
moveDistance *= -1;
}
this.node.style[transitionDuration] = '0s';
this.node.style.transform = "translateX(".concat(moveDistance, "px)");
}
}
}, {
key: "resume",
value: function resume() {
if (!this.moveing || !this.paused) return;
this.paused = false;
this.timeInfo.pauseTime += Date.now() - this.timeInfo.prevPauseTime;
this.timeInfo.prevPauseTime = null;
var isNegative = this.direction === 'left' ? 1 : -1;
var containerWidth = this.RuntimeManager.containerWidth + this.getWidth();
var remainingTime = (1 - this.getMovePercent()) * this.duration;
this.timeInfo.currentDuration = remainingTime;
this.node.style[transitionDuration] = "".concat(remainingTime, "s");
this.node.style.transform = "translateX(".concat(containerWidth * isNegative, "px)");
}
}, {
key: "reset",
value: function reset() {
this.remove(true);
this.deletedInMemory();
this.paused = false;
this.moveing = false;
this.trajectory = null;
this.position = {
y: null
};
this.timeInfo = {
pauseTime: 0,
startTime: null,
prevPauseTime: null,
currentDuration: this.duration
};
}
}]);
return Barrage;
}();
var RuntimeManager =
/*#__PURE__*/
function () {
function RuntimeManager(opts) {
_classCallCheck(this, RuntimeManager);
var container = opts.container,
rowGap = opts.rowGap,
height = opts.height;
var styles = getComputedStyle(container);
if (!styles.position || styles.position === 'none' || styles.position === 'static') {
container.style.position = 'relative';
}
this.opts = opts;
this.rowGap = rowGap;
this.singleHeight = height;
this.containerElement = container;
this.containerWidth = toNumber(styles.width);
this.containerHeight = toNumber(styles.height);
this.init();
}
_createClass(RuntimeManager, [{
key: "init",
value: function init() {
this.container = [];
this.rows = parseInt(this.containerHeight / this.singleHeight);
for (var i = 0; i < this.rows; i++) {
var start = this.singleHeight * i;
var end = this.singleHeight * (i + 1) - 1;
this.container.push({
values: [],
gaps: [start, end]
});
}
}
}, {
key: "resize",
value: function resize() {
var styles = getComputedStyle(this.containerElement);
this.containerWidth = toNumber(styles.width);
this.containerHeight = toNumber(styles.height);
this.rows = parseInt(this.containerHeight / this.singleHeight);
var container = [];
for (var i = 0; i < this.rows; i++) {
var start = this.singleHeight * i;
var end = this.singleHeight * (i + 1) - 1;
var gaps = [start, end];
if (this.container[i]) {
this.container[i].gaps = gaps;
container.push(this.container[i]);
} else {
container.push({
gaps: gaps,
values: []
});
}
}
this.container = container;
}
}, {
key: "getLastBarrage",
value: function getLastBarrage(barrages, lastIndex) {
for (var i = barrages.length - 1; i >= 0; i--) {
var barrage = barrages[i - lastIndex];
if (barrage && !barrage.paused) {
return barrage;
}
}
return null;
}
}, {
key: "getRandomIndex",
value: function getRandomIndex(exclude) {
var randomIndex = Math.floor(Math.random() * this.rows);
return exclude.includes(randomIndex) ? this.getRandomIndex(exclude) : randomIndex;
}
}, {
key: "getTrajectory",
value: function getTrajectory() {
var alreadyFound = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
if (alreadyFound.length === this.container.length) {
if (this.opts.forceRender) {
var _index = Math.floor(Math.random() * this.rows);
return this.container[_index];
} else {
return null;
}
}
var index = this.getRandomIndex(alreadyFound);
var currentTrajectory = this.container[index];
var lastBarrage = this.getLastBarrage(currentTrajectory.values, 0);
if (this.rowGap <= 0 || !lastBarrage) {
return currentTrajectory;
}
alreadyFound.push(index);
if (lastBarrage.moveing) {
var distance = lastBarrage.getMoveDistance();
var spacing = this.rowGap > 0 ? this.rowGap + lastBarrage.getWidth() : this.rowGap;
return distance > spacing ? currentTrajectory : this.getTrajectory(alreadyFound);
}
return this.getTrajectory(alreadyFound);
}
}, {
key: "computingDuration",
value: function computingDuration(prevBarrage, currentBarrage) {
var prevWidth = prevBarrage.getWidth();
var currentWidth = currentBarrage.getWidth();
var prevSpeed = prevBarrage.getSpeed();
var currentSpeed = currentBarrage.getSpeed();
var acceleration = currentSpeed - prevSpeed;
if (acceleration <= 0) {
return null;
}
var distance = prevBarrage.getMoveDistance() - currentWidth - prevWidth;
var meetTime = distance / acceleration;
if (meetTime >= currentBarrage.duration) {
return null;
}
var remainingTime = (1 - prevBarrage.getMovePercent()) * prevBarrage.duration;
var currentFixTime = currentWidth * remainingTime / this.containerWidth;
return remainingTime + currentFixTime;
}
}, {
key: "move",
value: function move(barrage, manager) {
var _this = this;
var node = barrage.node;
var prevBarrage = this.getLastBarrage(barrage.trajectory.values, 1);
node.style.top = "".concat(barrage.position.y, "px");
return new Promise(function (resolve) {
nextFrame(function () {
var width = barrage.getWidth();
var isNegative = barrage.direction === 'left' ? 1 : -1;
var containerWidth = _this.containerWidth + width;
if (prevBarrage && _this.rowGap > 0 && prevBarrage.moveing && !prevBarrage.paused) {
var fixTime = _this.computingDuration(prevBarrage, barrage);
if (fixTime !== null) {
if (isRange(_this.opts.times, fixTime)) {
barrage.duration = fixTime;
barrage.isChangeDuration = true;
barrage.timeInfo.currentDuration = fixTime;
} else {
barrage.reset();
node.style.top = null;
manager.stashBarrages.unshift(barrage);
return;
}
}
}
node.style.opacity = 1;
node.style.pointerEvents = manager.isShow ? 'auto' : 'none';
node.style.visibility = manager.isShow ? 'visible' : 'hidden';
node.style.transform = "translateX(".concat(isNegative * containerWidth, "px)");
node.style[transitionProp] = "transform linear ".concat(barrage.duration, "s");
node.style["margin".concat(upperCase(barrage.direction))] = "-".concat(width, "px");
barrage.moveing = true;
barrage.timeInfo.startTime = Date.now();
callHook(barrage.hooks, 'move', [barrage, node]);
callHook(barrage.globalHooks, 'barrageMove', [barrage, node]);
resolve(whenTransitionEnds(node));
});
});
}
}, {
key: "moveSpecialBarrage",
value: function moveSpecialBarrage(barrage, manager) {
var _this2 = this;
var node = barrage.node,
opts = barrage.opts;
node.style.position = 'absolute';
node.style.display = 'inline-block';
node.style.pointerEvents = manager.isShow ? 'auto' : 'none';
node.style.visibility = manager.isShow ? 'visible' : 'hidden';
return new Promise(function (resolve) {
var _opts$position = opts.position(barrage),
_opts$position$x = _opts$position.x,
x = _opts$position$x === void 0 ? 0 : _opts$position$x,
_opts$position$y = _opts$position.y,
y = _opts$position$y === void 0 ? 0 : _opts$position$y;
var setStyle = function setStyle(a, b) {
return "translateX(".concat(a, "px) translateY(").concat(b, "px)");
};
node.style.transform = setStyle(x, y);
nextFrame(function () {
barrage.moveing = true;
barrage.timeInfo.startTime = Date.now();
barrage.startPosition = {
x: x,
y: y
};
if (opts.direction === 'none') {
var fn = function fn() {
barrage.moveTimer.clear();
barrage.moveTimer = null;
resolve();
};
var timer = setTimeout(fn, opts.duration * 1000);
barrage.moveTimer = {
callback: fn,
clear: function clear() {
clearTimeout(timer);
timer = null;
}
};
} else {
var endPosition = opts.direction === 'left' ? _this2.containerWidth : -barrage.getWidth();
node.style.transform = setStyle(endPosition, y);
node.style[transitionProp] = "transform linear ".concat(opts.duration, "s");
resolve(whenTransitionEnds(node));
}
callHook(barrage.hooks, 'move', [barrage, node]);
callHook(manager.opts.hooks, 'barrageMove', [barrage, node]);
});
});
}
}]);
return RuntimeManager;
}();
var SpecialBarrage =
/*#__PURE__*/
function () {
function SpecialBarrage(manager, opts) {
_classCallCheck(this, SpecialBarrage);
this.opts = opts;
this.node = null;
this.paused = false;
this.moveing = false;
this.isSpecial = true;
this.manager = manager;
this.container = manager.opts.container;
this.RuntimeManager = manager.RuntimeManager;
this.hooks = opts.hooks;
this.data = opts.data || null;
this.key = opts.key || createKey();
this.moveTimer = null;
this.timeInfo = {
pauseTime: 0,
startTime: null,
prevPauseTime: null,
currentDuration: opts.duration
};
this.startPosition = {
x: null,
y: null
};
}
_createClass(SpecialBarrage, [{
key: "getHeight",
value: function getHeight() {
return this.node && this.node.clientHeight || 0;
}
}, {
key: "getWidth",
value: function getWidth() {
return this.node && this.node.clientWidth || 0;
}
}, {
key: "create",
value: function create() {
this.node = document.createElement('div');
callHook(this.hooks, 'create', [this, this.node]);
callHook(this.manager.opts.hooks, 'barrageCreate', [this, this.node]);
}
}, {
key: "getMovePercent",
value: function getMovePercent() {
var _this$timeInfo = this.timeInfo,
pauseTime = _this$timeInfo.pauseTime,
startTime = _this$timeInfo.startTime,
prevPauseTime = _this$timeInfo.prevPauseTime;
var currentTime = this.paused ? prevPauseTime : Date.now();
return (currentTime - startTime - pauseTime) / 1000 / this.opts.duration;
}
}, {
key: "getMoveDistance",
value: function getMoveDistance(direction, startPosition) {
if (!this.moveing) return 0;
var percent = this.getMovePercent();
if (direction === 'none') {
return startPosition;
}
if (direction === 'left') {
var realMoveDistance = (this.RuntimeManager.containerWidth - startPosition) * percent;
return startPosition + realMoveDistance;
} else {
var allMoveDistance = startPosition + this.getWidth();
return startPosition - allMoveDistance * percent;
}
}
}, {
key: "pause",
value: function pause() {
if (!this.moveing || this.paused) return;
this.paused = true;
this.timeInfo.prevPauseTime = Date.now();
var direction = this.opts.direction;
if (direction === 'none') {
if (this.moveTimer) {
this.moveTimer.clear();
}
} else {
var _this$startPosition = this.startPosition,
x = _this$startPosition.x,
y = _this$startPosition.y;
var moveDistance = this.getMoveDistance(direction, x);
this.node.style[transitionDuration] = '0s';
this.node.style.transform = "translateX(".concat(moveDistance, "px) translateY(").concat(y, "px)");
}
}
}, {
key: "resume",
value: function resume() {
if (!this.moveing || !this.paused) return;
this.paused = false;
this.timeInfo.pauseTime += Date.now() - this.timeInfo.prevPauseTime;
this.timeInfo.prevPauseTime = null;
var direction = this.opts.direction;
var remainingTime = (1 - this.getMovePercent()) * this.opts.duration;
if (direction === 'none') {
var fn = this.moveTimer.callback || function () {};
var timer = setTimeout(fn, remainingTime * 1000);
this.moveTimer.clear = function () {
clearTimeout(timer);
timer = null;
};
} else {
var _this$startPosition2 = this.startPosition,
x = _this$startPosition2.x,
y = _this$startPosition2.y;
var endPosition = this.opts.direction === 'left' ? this.RuntimeManager.containerWidth : -this.getWidth();
this.node.style[transitionDuration] = "".concat(remainingTime, "s");
this.node.style.transform = "translateX(".concat(endPosition, "px) translateY(").concat(y, "px)");
}
}
}, {
key: "append",
value: function append() {
warning(this.container, 'Need container element.');
if (this.node) {
this.container.appendChild(this.node);
callHook(this.hooks, 'append', [this, this.node]);
callHook(this.manager.opts.hooks, 'barrageAppend', [this, this.node]);
}
}
}, {
key: "remove",
value: function remove() {
warning(this.container, 'Need container element.');
if (this.node) {
this.container.removeChild(this.node);
callHook(this.hooks, 'remove', [this, this.node]);
callHook(this.manager.opts.hooks, 'barrageRemove', [this, this.node]);
}
}
}, {
key: "destroy",
value: function destroy() {
this.remove();
this.moveing = false;
var index = this.manager.specialBarrages.indexOf(this);
if (~index) {
this.manager.specialBarrages.splice(index, 1);
}
if (this.moveTimer) {
this.moveTimer.clear();
this.moveTimer = null;
}
callHook(this.hooks, 'destroy', [this, this.node]);
callHook(this.manager.opts.hooks, 'barrageDestroy', [this, this.node]);
this.node = null;
}
}]);
return SpecialBarrage;
}();
function createSpecialBarrage(manager) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
opts = Object.assign({
hooks: {},
duration: 0,
direction: 'none',
position: function position() {
return {
x: 0,
y: 0
};
}
}, opts);
return new SpecialBarrage(manager, opts);
}
var BarrageManager =
/*#__PURE__*/
function () {
function BarrageManager(opts) {
_classCallCheck(this, BarrageManager);
this.opts = opts;
this.loopTimer = null;
this.plugins = new Map();
this.showBarrages = [];
this.stashBarrages = [];
this.specialBarrages = [];
this.isShow = opts.isShow;
this.container = opts.container;
this.RuntimeManager = new RuntimeManager(opts);
}
_createClass(BarrageManager, [{
key: "send",
value: function send(data, hooks, isForward) {
if (Array.isArray(data)) {
data = data.map(function (item) {
return {
data: item,
hooks: hooks
};
});
} else {
data = [{
data: data,
hooks: hooks
}];
}
if (this.assertCapacity(data.length)) return false;
isForward ? this.stashBarrages.unshift.apply(this.stashBarrages, data) : this.stashBarrages.push.apply(this.stashBarrages, data);
callHook(this.opts.hooks, 'send', [this, data]);
return true;
}
}, {
key: "sendSpecial",
value: function sendSpecial(data) {
var _this = this;
if (!this.runing) return false;
if (!Array.isArray(data)) data = [data];
if (this.assertCapacity(data.length)) return false;
for (var i = 0; i < data.length; i++) {
if (callHook(this.opts.hooks, 'willRender', [this, data[i], true]) !== false) {
var _ret = function () {
var barrage = createSpecialBarrage(_this, data[i]);
if (barrage.opts.duration <= 0 || _this.showLength + 1 > _this.opts.limit) {
return "continue";
}
barrage.create();
barrage.append();
_this.specialBarrages.push(barrage);
_this.RuntimeManager.moveSpecialBarrage(barrage, _this).then(function () {
barrage.destroy();
if (_this.length === 0) {
callHook(_this.opts.hooks, 'ended', [_this]);
}
});
}();
if (_ret === "continue") continue;
}
}
callHook(this.opts.hooks, 'sendSpecial', [this, data]);
return true;
}
}, {
key: "show",
value: function show() {
if (!this.isShow) {
this.isShow = true;
this.each(function (barrage) {
if (barrage.node) {
barrage.node.style.visibility = 'visible';
barrage.node.style.pointerEvents = 'auto';
}
callHook(barrage.hooks, 'show', [barrage, barrage.node]);
});
callHook(this.opts.hooks, 'show', [this]);
}
}
}, {
key: "hidden",
value: function hidden() {
if (this.isShow) {
this.isShow = false;
this.each(function (barrage) {
if (barrage.node) {
barrage.node.style.visibility = 'hidden';
barrage.node.style.pointerEvents = 'none';
}
callHook(barrage.hooks, 'hidden', [barrage, barrage.node]);
});
callHook(this.opts.hooks, 'hidden', [this]);
}
}
}, {
key: "each",
value: function each(callback) {
if (typeof callback === 'function') {
var i = 0;
for (; i < this.specialBarrages.length; i++) {
callback(this.specialBarrages[i], i);
}
for (i = 0; i < this.showBarrages.length; i++) {
var barrage = this.showBarrages[i];
if (barrage.moveing) {
callback(barrage, i);
}
}
}
}
}, {
key: "stop",
value: function stop(noCallHook) {
if (this.loopTimer) {
clearTimeout(this.loopTimer);
this.loopTimer = null;
if (!noCallHook) {
callHook(this.opts.hooks, 'stop', [this]);
}
}
}
}, {
key: "start",
value: function start(noCallHook) {
var _this2 = this;
var core = function core() {
_this2.loopTimer = setTimeout(function () {
_this2.renderBarrage();
core();
}, _this2.opts.interval * 1000);
};
this.stop(true);
core();
if (!noCallHook) {
callHook(this.opts.hooks, 'start', [this]);
}
}
}, {
key: "setOptions",
value: function setOptions(opts) {
if (opts) {
this.opts = Object.assign(this.opts, opts);
if ('interval' in opts) {
this.stop(true);
this.start(true);
}
if ('height' in opts) {
this.RuntimeManager.singleHeight = opts.height;
this.RuntimeManager.resize();
}
if ('rowGap' in opts) {
this.RuntimeManager.rowGap = opts.rowGap;
}
callHook(this.opts.hooks, 'setOptions', [this, opts]);
}
}
}, {
key: "resize",
value: function resize() {
this.RuntimeManager.resize();
callHook(this.opts.hooks, 'resize', [this]);
}
}, {
key: "clear",
value: function clear() {
this.stop();
this.each(function (barrage) {
return barrage.remove();
});
this.showBarrages = [];
this.stashBarrages = [];
this.specialBarrages = [];
this.RuntimeManager.container = [];
this.RuntimeManager.resize();
callHook(this.opts.hooks, 'clear', [this]);
}
}, {
key: "clone",
value: function clone(opts) {
opts = opts ? Object.assign(this.opts, opts) : this.opts;
return new this.constructor(opts);
}
}, {
key: "use",
value: function use(fn) {
warning(typeof fn === 'function', 'Plugin must be a function.');
if (this.plugins.has(fn)) {
return this.plugins.get(fn);
}
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var result = fn.apply(void 0, [this].concat(args));
this.plugins.set(fn, result);
return result;
}
}, {
key: "assertCapacity",
value: function assertCapacity(n) {
var res = n + this.length > this.opts.capacity;
if (res) {
callHook(this.opts.hooks, 'capacityWarning', [this]);
console.warn("The number of barrage is greater than \"".concat(this.opts.capacity, "\"."));
}
return res;
}
}, {
key: "renderBarrage",
value: function renderBarrage() {
var _this3 = this;
if (this.stashBarrages.length > 0) {
var _this$RuntimeManager = this.RuntimeManager,
rows = _this$RuntimeManager.rows,
rowGap = _this$RuntimeManager.rowGap;
var length = this.opts.limit - this.showLength;
if (rowGap > 0 && length > rows) {
length = this.RuntimeManager.rows;
}
if (this.opts.forceRender || length > this.stashBarrages.length) {
length = this.stashBarrages.length;
}
if (length > 0 && this.runing) {
timeSlice(length, function () {
var currentBarrage = _this3.stashBarrages.shift();
if (callHook(_this3.opts.hooks, 'willRender', [_this3, currentBarrage, false]) !== false) {
var needStop = _this3.initSingleBarrage(currentBarrage.data, currentBarrage.hooks);
if (needStop) {
return false;
}
}
});
callHook(this.opts.hooks, 'render', [this]);
}
}
}
}, {
key: "initSingleBarrage",
value: function initSingleBarrage(data, hooks) {
var _this4 = this;
var barrage = data instanceof Barrage ? data : this.createSingleBarrage(data, hooks);
var newBarrage = barrage && this.sureBarrageInfo(barrage);
if (newBarrage) {
newBarrage.append();
this.showBarrages.push(newBarrage);
newBarrage.trajectory.values.push(newBarrage);
this.RuntimeManager.move(newBarrage, this).then(function () {
newBarrage.destroy();
if (_this4.length === 0) {
callHook(_this4.opts.hooks, 'ended', [_this4]);
}
});
} else {
this.stashBarrages.unshift(barrage);
return true;
}
}
}, {
key: "createSingleBarrage",
value: function createSingleBarrage(data, hooks) {
var _this$opts$times = _slicedToArray(this.opts.times, 2),
max = _this$opts$times[0],
min = _this$opts$times[1];
var time = Number(max === min ? max : (Math.random() * (max - min) + min).toFixed(0));
if (time <= 0) return null;
return new Barrage(data, hooks, time, this, Object.assign({}, this.opts.hooks, {
barrageCreate: this.setBarrageStyle.bind(this)
}));
}
}, {
key: "sureBarrageInfo",
value: function sureBarrageInfo(barrage) {
var trajectory = this.RuntimeManager.getTrajectory();
if (!trajectory) return null;
barrage.trajectory = trajectory;
barrage.position.y = trajectory.gaps[0];
return barrage;
}
}, {
key: "setBarrageStyle",
value: function setBarrageStyle(barrage, node) {
var _this$opts = this.opts,
_this$opts$hooks = _this$opts.hooks,
hooks = _this$opts$hooks === void 0 ? {} : _this$opts$hooks,
direction = _this$opts.direction;
node.style.opacity = 0;
node.style[direction] = 0;
node.style.position = 'absolute';
node.style.display = 'inline-block';
node.style.pointerEvents = this.isShow ? 'auto' : 'none';
node.style.visibility = this.isShow ? 'visible' : 'hidden';
callHook(hooks, 'barrageCreate', [barrage, node]);
}
}, {
key: "stashLength",
get: function get() {
return this.stashBarrages.length;
}
}, {
key: "specialLength",
get: function get() {
return this.specialBarrages.length;
}
}, {
key: "showLength",
get: function get() {
return this.showBarrages.length + this.specialBarrages.length;
}
}, {
key: "length",
get: function get() {
return this.showBarrages.length + this.specialBarrages.length + this.stashBarrages.length;
}
}, {
key: "containerWidth",
get: function get() {
return this.RuntimeManager.containerWidth;
}
}, {
key: "containerHeight",
get: function get() {
return this.RuntimeManager.containerHeight;
}
}, {
key: "runing",
get: function get() {
return this.loopTimer !== null;
}
}]);
return BarrageManager;
}();
function createBarrageManager() {
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
opts = Object.assign({
hooks: {},
limit: 100,
height: 50,
rowGap: 50,
isShow: true,
capacity: 1024,
times: [5, 10],
interval: 1,
direction: 'right',
forceRender: false
}, opts);
return new BarrageManager(opts);
}
var index = {
Timeline: Timeline,
create: createBarrageManager
};
return index;
}));