Skip to content

Commit 0fe45af

Browse files
author
Taois
committed
feat: 修复bug
1 parent a6a8a9f commit 0fe45af

File tree

5 files changed

+800
-2
lines changed

5 files changed

+800
-2
lines changed

data/douyu/danmu.html

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<!DOCTYPE html>
2+
<html lang="zh-CN">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>弹幕系统</title>
7+
<style>
8+
body {
9+
margin: 0;
10+
padding: 0;
11+
background: transparent;
12+
overflow: hidden;
13+
}
14+
#danmu-container {
15+
position: fixed;
16+
width: 100vw;
17+
height: 100vh;
18+
overflow: hidden;
19+
pointer-events: none;
20+
}
21+
.danmu-item {
22+
position: absolute;
23+
white-space: nowrap;
24+
font-size: 16px;
25+
line-height: 1.3;
26+
text-shadow: 1px 1px 2px rgba(0,0,0,0.7);
27+
will-change: transform;
28+
backface-visibility: hidden;
29+
pointer-events: auto;
30+
}
31+
</style>
32+
</head>
33+
<body>
34+
<div id="danmu-container"></div>
35+
<script>
36+
(function() {
37+
// 核心配置
38+
const CONFIG = {
39+
rowCount: 8, // 弹幕行数
40+
rowHeight: 26, // 行高
41+
baseSpeed: 150, // 基准速度(px/s)
42+
maxLoad: 5, // 单行最大负载
43+
speedBoost: 0.3, // 速度增益系数
44+
spacingRatio: 0.6 // 间距比例
45+
};
46+
47+
const container = document.getElementById('danmu-container');
48+
const socket = new WebSocket('ws://{{hostname}}/dy-dm');
49+
50+
// 智能分配系统
51+
class SmartAllocator {
52+
constructor() {
53+
// 关键修改:初始化时固定行号从上到下
54+
this.rows = Array.from({length: CONFIG.rowCount}, (_, index) => ({
55+
index: index, // 行号0对应最上方
56+
active: 0,
57+
lastPos: 0,
58+
speed: CONFIG.baseSpeed
59+
}));
60+
this.canvas = document.createElement('canvas');
61+
this.ctx = this.canvas.getContext('2d');
62+
}
63+
64+
// 核心分配算法
65+
allocateRow(text) {
66+
const textWidth = this.measureText(text);
67+
68+
// 第一阶段:寻找空行(优先上方)
69+
const emptyRows = this.rows
70+
.filter(r => r.active === 0)
71+
.sort((a, b) => a.index - b.index); // 按行号升序排列
72+
73+
if (emptyRows.length > 0) {
74+
return emptyRows[0].index;
75+
}
76+
77+
// 第二阶段:寻找最空闲行(优先上方)
78+
const minActive = Math.min(...this.rows.map(r => r.active));
79+
const candidateRows = this.rows
80+
.filter(r => r.active === minActive)
81+
.sort((a, b) => a.index - b.index);
82+
83+
return candidateRows[0].index;
84+
}
85+
86+
updateRow(rowIndex, delta) {
87+
const row = this.rows.find(r => r.index === rowIndex);
88+
row.active += delta;
89+
row.speed = CONFIG.baseSpeed * (1 + (row.active / CONFIG.maxLoad) * CONFIG.speedBoost);
90+
row.lastPos = Date.now();
91+
}
92+
93+
measureText(text) {
94+
this.ctx.font = '16px sans-serif';
95+
return this.ctx.measureText(text).width;
96+
}
97+
}
98+
99+
// 弹幕引擎(已修改)
100+
class DanmuEngine {
101+
constructor() {
102+
this.allocator = new SmartAllocator();
103+
this.elementPool = [];
104+
}
105+
106+
launch(text) {
107+
const element = this.getElement(text);
108+
const textWidth = this.allocator.measureText(text);
109+
const row = this.allocator.allocateRow(text);
110+
111+
this.allocator.updateRow(row, +1);
112+
this.animate(element, row, textWidth);
113+
}
114+
115+
getElement(text) {
116+
const el = this.elementPool.pop() || document.createElement('div');
117+
el.className = 'danmu-item';
118+
el.textContent = text;
119+
el.style.color = `hsl(${Math.random()*360},70%,60%)`;
120+
return el;
121+
}
122+
123+
animate(element, row, textWidth) {
124+
const startX = container.clientWidth;
125+
const yPos = row * CONFIG.rowHeight; // 行号0对应最上方
126+
127+
element.style.transform = `translateX(${startX}px)`;
128+
element.style.top = `${yPos}px`;
129+
container.appendChild(element);
130+
131+
const speed = this.allocator.rows.find(r => r.index === row).speed;
132+
const startTime = Date.now();
133+
134+
const animateFrame = () => {
135+
const elapsed = Date.now() - startTime;
136+
const progress = elapsed / ((startX + textWidth) / speed * 1000);
137+
138+
if (progress < 1) {
139+
const x = startX - (startX + textWidth) * progress;
140+
element.style.transform = `translateX(${x}px)`;
141+
requestAnimationFrame(animateFrame);
142+
} else {
143+
this.recycle(element, row);
144+
}
145+
};
146+
requestAnimationFrame(animateFrame);
147+
}
148+
149+
recycle(element, row) {
150+
this.allocator.updateRow(row, -1);
151+
element.remove();
152+
this.elementPool.push(element);
153+
}
154+
}
155+
156+
// 初始化系统
157+
const engine = new DanmuEngine();
158+
159+
// WebSocket处理
160+
socket.onmessage = event => {
161+
const text = String(event.data).trim().substring(0, 100);
162+
text && engine.launch(text);
163+
};
164+
165+
// 窗口自适应
166+
window.addEventListener('resize', () => {
167+
container.style.width = window.innerWidth + 'px';
168+
container.style.height = window.innerHeight + 'px';
169+
});
170+
171+
window.addEventListener('beforeunload', () => {
172+
socket.close();
173+
});
174+
})();
175+
</script>
176+
</body>
177+
</html>

libs/dsGlobal.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
// globalThis.JSONbig = JSONbig; // 必须在drpyS.js里引入
2828

2929
// 网络请求工具 - 提供HTTP请求功能
30+
import {getFirstLetter} from "../utils/pinyin-tool.js";
31+
3032
globalThis.reqs = reqs;
3133

3234
// 加密工具库 - 提供各种加密算法和数字签名功能
@@ -90,10 +92,11 @@ globalThis.WebSocketServer = WebSocketServer;
9092
globalThis.setResult = setResult;
9193

9294
// ds沙箱文件读写函数
93-
globalThis.pathLib = pathLib;
95+
// globalThis.pathLib = pathLib;
9496

9597
// UA
9698
globalThis.MOBILE_UA = MOBILE_UA;
9799
globalThis.PC_UA = PC_UA;
98100
// 其他常用
99-
globalThis.$js = $js;
101+
globalThis.$js = $js;
102+
globalThis.getFirstLetter = getFirstLetter;

0 commit comments

Comments
 (0)