惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Forbes - Security
Forbes - Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
F
Fortinet All Blogs
B
Blog
T
The Blog of Author Tim Ferriss
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
Y
Y Combinator Blog
Microsoft Azure Blog
Microsoft Azure Blog
L
LangChain Blog
Recent Announcements
Recent Announcements
U
Unit 42
Martin Fowler
Martin Fowler
M
MIT News - Artificial intelligence
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Register - Security
The Register - Security
Recorded Future
Recorded Future
C
Check Point Blog
V
V2EX
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
酷 壳 – CoolShell
酷 壳 – CoolShell
F
Full Disclosure
小众软件
小众软件
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
爱范儿
爱范儿
P
Proofpoint News Feed
罗磊的独立博客
量子位
D
Docker
博客园_首页
D
DataBreaches.Net
Project Zero
Project Zero
博客园 - 司徒正美
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - Franky
Security Latest
Security Latest
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
N
Netflix TechBlog - Medium
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 三生石上(FineUI控件)
H
Hackread – Cybersecurity News, Data Breaches, AI and More
大猫的无限游戏
大猫的无限游戏

Jartto's blog

好久不见,我想和你聊聊! 用 Tauri+Rust+Yew 来构建你的跨端桌面应用 Docker 新书上市一周年 30s 就可以掌握的 Nginx 片段 了不起的 Istio 一文了解 Kubernetes Docker 边学边用 将博客搬至 CSDN WebP 方案分析与实践 Web「性能测试」知多少? 网站性能指标 - FMP 聚焦 Web 性能指标 TTI 破局:技术视野与规划 GitBook 和它有趣的插件 系统负载看不懂? 人工智能时代,Web 前端能做什么? CSS 渲染原理以及优化策略 网站优化,这些工具你一定用得着 程序员如何减少开发中的 Bug?
极简弹幕方案
Jartto · 2020-02-16 · via Jartto's blog

极简弹幕方案

发布在 技术博文 123 次阅读

重大的活动现场一般离不开 PPT 演示,可是如何有效和现场互动呢?这时候弹幕必不可少,静态的 PPT 就略显乏力。有没有一种好的方案可以二者兼得呢?

如何才能使 PPT 具有交互性,这是一个值得思考的问题!

可能很多童鞋想到了,如果使用「网页 PPT」 ,岂不是完美解决了这个问题。本节我们就来提供一种思路,用「PPT + 发射器 + Socket」 实现「极简弹幕方案」。

关于「网页 PPT」,可以查看我之前的文章「酷炫的 HTML5 网页 PPT」一探究竟。

一、效果演示

我们先通过一个简单的视屏演示一下效果:

相关代码:Demo 地址

二、方案概括

看完上面的演示,是不是迫不及待想知道答案,下面我们来逐步拆分。

先来看看代码结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.
├── README.md
├── mobile
│ ├── README.md
│ ├── node_modules
│ ├── package.json
│ ├── public
│ ├── src
│ └── yarn.lock
├── package.json
├── ppt
│ ├── css
│ ├── extras
│ ├── images
│ ├── index.html
│ ├── js
│ └── temp
├── server
│ ├── app.js
│ ├── data
│ ├── node_modules
│ ├── package-lock.json
│ └── package.json
└── yarn.lock

我们主要关注以下三个目录:

1.ppt
使用 impressjs 构建的项目,PPT 演讲「主屏」,主要演示内容区域,同时接收「服务端」推送弹幕信息。

2.mobile
移动端,下文称作「发射器」,主要用作现场用户互动向主屏发送弹幕消息。通过 Create React App 生成,技术栈是:React + Antd

3.server
服务端,主要接受用户弹幕,同时广报到主屏,使用 Socket 实现。

启动方式:

1.进入 server 目录,启动服务:

1
node app.js

此时会启动一个本机 IP 地址的服务。

2.进入 ppt 目录,使用 http-server 启动站点:

1
http-server

注意:接口地址需要替换成本机 IP 地址。

3.进入 mobile 目录,启动发射器:

1
yarn start

注意:请求接口需要使用本机 IP 地址。

Demo 比较简单,主要展示主流程,如果细节过程有问题,欢迎一起探讨。

三、主屏细节(核心代码)

主屏是主要演示版面,我们需要像下面这样作出 PPT,这里我们做了三个页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="impress" class="jartto" data-transition-duration="1000">

<div id="cover" class="step slide title" data-x="1000" data-y="1000">
<img src="temp/img/qrcode.png" />
</div>

<div id="award" class="step slide" data-x="2000" data-y="3000">
<h1>请开始你的表演~</h1>
</div>

<div id="change" class="step slide" data-x="2000" data-y="3000" data-scale="5">
<h1>切换 PPT</h1>
</div>

<div id="thank" class="step slide" data-rel-x="0" data-rel-y="3000" data-rotate="90" data-scale="2">
<img src="images/thanks.png" />
</div>

</div>

每个 div 就是一页 ppt,里面可以随意排版,data-x 控制位置,data-scale 控制缩放,data-rotate 控制旋转。

更多 API 文档,请参考如下文档:
1.酷炫的 HTML5 网页 PPT
2.文档地址

四、实现弹幕

为了更好的理解弹幕,我们来实现一个简版:
1.定义弹幕结构

1
<div class="jartto_demo">我是弹幕</div>

2.定义移动动画

1
2
3
4
5
6
7
8
9
10
11
@keyframes barrager{
from{
left:100%;
transform:translateX(0);
transform:translate3d(0, 0, 0);
}
to{
left:0;
transform:translate3d(-100%, 0, 0);
}
}

注意,使用 translate3d 可以开启 GPU 硬件加速,会比 translateX 更流畅一些。

关于硬件加速,可以关注我之前写的一篇文章:详谈层合成(composite)

3.使用动画

1
2
3
4
.jartto_demo{
position:absolute;
animation: barrager 5s linear 0s;
}

OK,我们通过三步实现了一个简单的弹幕动画。那么问题来了,弹幕都是随机位置,随机速度,随机颜色出现在屏幕上的,这个该如何实现呢?

4.随机弹幕出现位置

1
2
3
let window_height = $(window).height() - 150;
bottom = Math.floor(Math.random() * window_height + 40);
code = code.replace(" bottom:{bottom}, //距离底部高度,单位px,默认随机 \n", '');

5.随机弹幕颜色

1
2
let color = `#${Math.floor(Math.random() * (2 << 23)).toString(16)}`; 
console.log(color);

好了,大功告成,我们顺手加上 Socket 事件监听。

6.事件监听
为了拿到用户发送过来的弹幕,我们需要做一个事件监听(接收服务端数据):
首先,引入 socket.io.js 文件:

1
<script type="text/javascript" src="http://{jartto.ip}/socket.io/socket.io.js"></script>
1
2
3
4
5
const socket = io('http://{jartto.ip}');
socket.on('server-push', function (data) {
console.log('news message >>>>>>>>', data.message);
run(data.message);
});

当我们监听到 server-push 事件的时候,run 函数就会初始化弹幕方法,随机生成一条弹幕,在屏幕滑过。

五、发射器细节(核心代码)

发射器就非常简单了,我们使用 Create React App 初始化项目,在 src/app.js 中写入一个表单(这里以 React 为例,Vue 也是大同小异):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div className="app-box">
<div className="form-box">
<Form.Item {...formItemLayout} label="">
{getFieldDecorator('msg', {
rules: [
{
required: true,
message: '请输入内容',
},
],
})(<Input size="large" placeholder="发送消息,嗨起来~" />)}
</Form.Item>
<Form.Item {...formTailLayout} >
<Button className="btns" shape="round" icon="close" size="large" onClick={this.cancle}>取消</Button>
<Button type="primary" shape="round" icon="check" size="large" onClick={this.check}>发送</Button>
</Form.Item>
</div>
</div>

用户在输入框输入消息,向我们的服务器发送请求,很简单,就不赘述了。效果图可以参考下面:
Demo 效果图

请注意,此处为了演示效果,我将三端同框了。

六、服务端细节(核心代码)

服务端比较简单,使用 Express 初始化一个 Node 项目,向 app.js 写入如下内容:
1.启动 Socket 服务:

1
2
3
4
5
6
7
8
const express = require('express'),
bodyParser = require('body-parser'),
socket = require('socket.io'),
fs = require('fs');

const app = express();
const PORT = 4000;
const io = socket(app.listen(PORT, () => console.log(`start on port ${PORT}`)));

2.监听 Socket 连接,接收用户发送数据,将数据写入本地 JSON 文件,并广播到 server-push 事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
io.on('connection', sockets => {
console.log('连接成功!');
app.post('/api/send', (req, res, next) => {

let info = JSON.stringify(req.body.msg);

fs.writeFile('./data/jartto.json', `${info},\n`,
{flag:'a',encoding:'utf-8',mode:'0666'},function(err){
if(err) {
console.log('文件写入失败');
res.status(500).send('Error');
} else {
sockets.broadcast.emit('server-push', { message: req.body.msg });
res.status(200).send('Done');
}
})

})

sockets.on('disconnect', () => {
console.log('User Disconnected');
})
});

3.当然,我们也可以存入数据库做持久化,以下演示存入 MySQL 核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
io.on('connection', sockets => {
console.log('连接成功!');
app.post('/api/send', (req, res, next) => {
let {ua, msg} = req.body.msg;
req.getConnection(function(err, cnt) {

let query = cnt.add('INSERT INTO (ua, msg)', {ua, msg}, function(err, rows) {
if (err) {
console.log("Error inserting : %s ",err );
return next(err);
}

sockets.broadcast.emit('server-push', { message: req.body.msg });
res.status(200).send('Done');
})
})

})

sockets.on('disconnect', () => {
console.log('User Disconnected');
})
});

4.启动服务

1
node app.js

我们的服务端就启动起来了,访问地址是你的主机 IP4000 端口。

七、总结

本文我们从零到一搭建了一个完整的弹幕方案,涉及到三部分:主屏,发射器和服务端,旨在为小伙伴们提供一套极简的设计思路。通过 Demo 我们可以简单的串联一个全栈项目,做更多有趣的事情。

文章最后,打个小广告吧。如果你想搭上在线教育的快车,快速成长,不妨加入我们。一起成长,一起学习,一起挑战更多有趣的事情,「跟谁学-高途课堂」欢迎你,请将简历私我~