我是歌谣 放弃很难 坚持一定很酷
2021继续加油

目录结构

文件地址
源码地址后面可见
在这里插入图片描述

源码文件

index.css

body {
margin: 0;
}

.container {
width: 1000px;
margin: 0 auto;
}

.video-wrapper {
position: relative;
}

.video-wrapper video {
width: 100%;
}

.video-wrapper canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 563px;
}

.video-wrapper .tool-box {
height: 38px;
}

.video-wrapper input,
.video-wrapper button {
height: 100%;
margin-right: 15px;
vertical-align: middle;
outline: none;
border: none;
box-sizing: border-box;
border-radius: 5px;
}

.video-wrapper .danmu-input {
width: 300px;
border: 1px solid #ccc;
}

.video-wrapper .danmu-btn {
color: #fff;
background-color: orange;
}

danmu.js

import { getTextWidth, getTextPosition } from ‘./utils’;

class Danmu {
constructor (danmu, fCtx) {
this.content = danmu.content;
this.runTime = danmu.runTime;
this.danmu = danmu;
this.ctx = fCtx;
}

initialize () {
this.color = this.danmu.color || this.ctx.color;
this.speed = this.danmu.speed || this.ctx.speed;
this.fontSize = 30;
this.width = getTextWidth(this.content, this.fontSize);
getTextPosition(this.ctx.canvas, this.fontSize, this);
}

render () {
this.ctx.canvasCtx.font = this.fontSize + ‘px Microsoft Yahei’;
this.ctx.canvasCtx.fillStyle = this.color;
this.ctx.canvasCtx.fillText(this.content, this.X, this.Y);
}
}

export default Danmu;

index.js

import { isObject, isArray } from ‘./utils’;
import Danmu from ‘./Danmu’;

class VideoDanmu {
constructor (video, canvas, options) {
if (!video || !canvas || !options || !isObject(options)) return;
if (!options.danmuData || !isArray(options.danmuData)) return;

this.video = video;
this.canvas = canvas;
this.canvasCtx = canvas.getContext('2d');
this.canvas.width = video.offsetWidth;
this.canvas.height = video.offsetHeight;

this.danmuPaused = true;

Object.assign(this, options, {
  speed: 2,
  runTime: 0,
  color: '#fff'
});

this.danmuPool = this.createDanmuPool();
this.render();

}

createDanmuPool () {
return this.danmuData.map(dm => new Danmu(dm, this));
}

render () {
this.clearRect();
this.renderDanmu();
!this.danmuPaused && requestAnimationFrame(this.render.bind(this));
}

renderDanmu () {
let currentTime = this.video.currentTime;

this.danmuPool.map((danmu) => {
  if (!danmu.stopRender && currentTime >= danmu.runTime) {
     if (!danmu.isInitialized) {
       danmu.initialize();
       danmu.isInitialized = true;
     }
     danmu.X -= danmu.speed;
     danmu.render();

     if (danmu.X <= danmu.width * -1) {
       danmu.stopRender = true;
     }
  }
})

}

reset () {
this.clearRect();
let currentTime = this.video.currentTime;

this.danmuPool.map((danmu) => {
  danmu.stopRender = false;

  if (currentTime <= danmu.runTime) {
    danmu.isInitialized = false;
  } else {
    danmu.stopRender = true;
  }
})

}

add (data) {
this.danmuPool.push(new Danmu(data, this));
}

clearRect () {
this.canvasCtx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}

export default VideoDanmu;


util.js

function isObject (value) {
const type = Object.prototype.toString.call(value);
return type === ‘[object Object]’;
}

function isArray (value) {
return Array.isArray(value);
}

function getTextWidth (content, fontSize) {
const _span = document.createElement(‘span’);
_span.innerText = content;
_span.style.fontSize = fontSize + ‘px’;
_span.style.position = ‘absolute’;
document.body.appendChild(_span);
let width = _span.offsetWidth;
document.body.removeChild(_span);
return width;
}

function getTextPosition (wrapper, fontSize, ctx) {
const X = wrapper.width;
let Y = wrapper.height * Math.random();

Y < fontSize && (Y = fontSize);
Y > wrapper.height - fontSize && (Y = wrapper.height - fontSize);

ctx.X = X;
ctx.Y = Y;
}

export {
isObject,
isArray,
getTextWidth,
getTextPosition
}

index.js

import VideoDanmu from ‘./danmu’;

const danmuData = [
{
content: ‘我真的好喜欢这首钢琴曲’,
runTime: 10,
speed: 2,
color: ‘red’
},
{
content: ‘这首钢琴曲是红猪里的一去不复返的时光’,
runTime: 0,
speed: 4,
color: ‘orange’
},
{
content: ‘久石让是我最崇拜的音乐家之一’,
runTime: 15,
speed: 4,
color: ‘green’
}
]

😭(doc) => {

const oDanmuVideo = doc.getElementById(‘J_danmuVideo’),
oDanmuCanvas = doc.getElementById(‘J_danmuCanvas’),
oDanmuBtn = doc.getElementsByClassName(‘danmu-btn’)[0],
oDanmuInput = doc.getElementsByClassName(‘danmu-input’)[0],
oColorInput = doc.getElementsByClassName(‘color-input’)[0];

const init = () => {
window.videoDanmu = new VideoDanmu(
oDanmuVideo,
oDanmuCanvas,
{
danmuData
}
)
bindEvent();
}

function bindEvent () {
oDanmuVideo.addEventListener(‘play’, handleVideoPlay, false);
oDanmuVideo.addEventListener(‘pause’, handleVideoPause, false);
oDanmuVideo.addEventListener(‘seeked’, handleVideoSeek, false);
oDanmuBtn.addEventListener(‘click’, handleToolClick, false);
}

function handleVideoPlay () {
videoDanmu.danmuPaused = false;
videoDanmu.render();
}

function handleVideoPause () {
videoDanmu.danmuPaused = true;
}

function handleVideoSeek () {
videoDanmu.reset();
}

function handleToolClick () {
if (videoDanmu.danmuPaused) return;

const inputValue = oDanmuInput.value.trim();

if (!inputValue.length) return;

const colorValue = oColorInput.value,
      runTime = oDanmuVideo.currentTime;

const _data = {
  content: inputValue,
  color: colorValue,
  runTime
}

videoDanmu.add(_data);
oDanmuInput.value = '';

}

init();

})(document);

## 主文件

Document
发送弹幕
## 运行结果
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021021714473891.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzM5MjQ4OQ==,size_16,color_FFFFFF,t_70)

## 源码地址
[源码地址](https://gitee.com/geyaoisgeyao/small-cases-of-daily-learning/tree/master/)