新年祈福弹幕墙

新年祈福弹幕墙

综合说他们需要一个新年祈福弹幕墙, 安排一下. 今年疲于应付产品奇奇怪怪的需求, 年末能响应这么一个能立刻得到反馈的简单小功能还挺高兴.

需求及方案确定

  1. 弹幕播放:网上有一些成熟的方案或插件, 这里使用了较为简易的js操作dom实现. 两个细节要求:

    • 弹幕不互相遮挡:网上暂停播放动画的方案都较为复杂. 我们记录每条泳道播放的结束时间即可, 每次向预计结束时间最早(已结束)的泳道装填.

    • 尽量铺满屏幕:缩短每条弹幕装填间隙.

  2. 背景音乐:自动循环播放

  3. 热闹的动效: 使用了来自codepen的代码Countdown to New Year , 它包含

    • 星光背景

    • 塑料烟花: 使用canvas实现的烟花很炫, 但是在非暗黑背景时会有轨迹, 我们使用了这套html+css的方案

  4. 未实现的内容:扫码发送弹幕等

代码实现

项目目录

项目目录

裸项目三件套:index.html script.js style.css, 使用Jquery插件

弹幕

  1. 读取文件

    理论上应该写一套从Excel读取的方法, 但我手头没写过现成的工具方法. 就使用在线工具复制粘贴Excel转换成json, ,用的是bing搜索出来的第一个在线Excel转JSON工具 - UU在线工具

    若有需要可参考xlsx.core.min.js

    转换出来的文件复制到wish.js中存储, vscode自动帮我把json转js了. 如果使用json存储的话需要写一个request获. 。

  2. 弹幕播放

    index.html中添加barrage

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <title>新年许愿墙</title>
    <link
    href="https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap"
    rel="stylesheet"
    />

    <link rel="stylesheet" href="./style.css" />
    </head>
    <body>
    <div class="copyright">xxxxxx技术支持</div>
    <div id="barrage">
    </div>
    <!-- partial -->
    <script src="./jquery.min.js"></script>
    <script src="./wish.js"></script>
    <script src="./script.js"></script>
    </body>
    </html>

    script.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
    var barrageStrs = [];

    function readWorkbookFromLocalFile() {
    for (let i = 0; i < wishList.length; i++) {
    barrageStrs.push(wishList[i].sum);
    barrageStrs.push(wishList[i].content);
    }
    }

    $(function () {
    var $barrage = $('#barrage');
    readWorkbookFromLocalFile();
    var colors = [
    '#F2EF8b',
    '#f9cb8b',
    '#DDF0ED',
    '#ebb10d',
    '#ffa60f',
    '#f2e68b',
    '#f9bd10',
    '#f2ce2b',
    '#fba414',
    '#f0d695',
    '#EEE8AB',
    '#f09c5a',
    '#fbb957',
    '#DEA681',
    '#f7c173',
    '#f9e98b',
    '#f9bd10',
    '#f4ce69',
    '#fca106',
    ];
    var channelList = new Array(9).fill(0);
    var secondCount = 0;
    var timer = setInterval(() => {
    /**
    * 泳道计算, 减小碰撞.
    * 如果有硬性完全不遮挡的要求, 这里改为index在channel<min的时候才取,
    如果没有符合条件(index返回-1)的项,这一轮计时器结束,不进行后续操作
    */

    index = channelList.findIndex((channel) => channel === Math.min(...channelList);
    const str = barrageStrs[secondCount % barrageStrs.length];
    channelList[index] = Math.ceil(secondCount + str.length / 5);
    let barrage = new Barrage({
    str: str,
    x: window.innerHeight * 0.3 + 60 * index,
    y: 0,
    color: colors[random(0, colors.length - 1)],
    parent: $barrage,
    });
    barrage.move();
    secondCount++;
    }, 600); // 调整每条新弹幕填充的时间
    });
    function Barrage({ str: str, x: x, y: y, color: color, parent: parent }) {
    var that = this;
    this.text = str;
    this.pos = {
    x: x + 500,
    y: y,
    };
    this.state = false;
    this.entity = $('<span>');
    this.entity.text(str).css({
    position: 'absolute',
    top: x,
    right: y,
    color: color,
    fontSize: random(24, 60) + 'px',
    fontWeight: 'bold',
    maxWidth: '10px',
    whiteSpace: 'nowrap',
    });

    this.speed = 2;
    parent.append(this.entity);
    this.move = function () {
    that.state = true;
    this.show();
    var timer = setInterval(() => {
    var left = parseInt(that.entity.css('left'));
    if (left < -6000) {
    clearInterval(timer);
    that.hide();
    that.entity.remove();
    }
    var right = parseInt(that.entity.css('right'));
    right += that.speed;
    that.speed += 0.02;
    that.entity.css({ right: right });
    }, 25);
    };
    this.show = () => {
    that.entity.show();
    };
    this.hide = () => {
    that.entity.hide();
    };
    this.hide();
    }
    function random(min, max) {
    return Math.floor(min + Math.random() * (max - min));
    }

背景音乐

背景音乐播放需要注意的是Chrome会在用户未进行页面操作时禁止play()的操作, 所以写了个傻瓜的循环计时器

index.html

1
2
3
4
<video id="vd">
<source src="./chun_jie_xu_qu.mp3" type="video/mp4" />
<source src="./chun_jie_xu_qu.ogg" type="video/ogg" />
</video>
1
2
3
4
5
6
7
8
9
10
11
12
function toggleSound() {
undefined;
var music = document.getElementById('vd'); //获取ID
if (music.paused) {
//判读是否播放
music.paused = false;
music.play(); //没有就播放
}
}
$(function (){
setInterval('toggleSound()', 1000);
})

其他动效

Countdown to New Year使用了haml和sass, 又学到一套模板html的写法 !

不需使用也别慌, 使用codepen export该项目, 傻瓜照搬dist目录下的原生三件套代码即可.

背景和其他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
html {
height: 100%;
overflow: hidden;
}

body {
background: url(./back.png) center no-repeat;
background-size: 100% 100%;
margin: 0;
font-family: 'Roboto Mono', monospace;
height: 100%;
overflow: hidden;
}
.copyright {
position: absolute;
bottom: 40px;
left: 20px;
color: #f9e98b;
}

完成

祝大家2023新年快乐! 一切顺利!

title:新年祈福弹幕墙

author:Anne416wu

link:https://www.annewqx.top/posts/57945/

publish time:2023-01-04

update time:2023-01-04


 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×