mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-28 18:41:20 -08:00
refactor(danmuku): [PKG-DANMUKU-06] migrate runtime and preserve public types
This commit is contained in:
1 parent
abc8008da7
commit
24b883d862
64 files changed
+14020
-633
No files matched your search
@@ -0,0 +1,154 @@
|
||||
import type { PlacementMessage, PlacementReply, PlacementRequest, PlacementRow, VisibleDanmu } from './worker-types'
|
||||
|
||||
function getDanmuTop({ target, visibles, clientWidth, clientHeight, marginBottom, marginTop, antiOverlap }: PlacementRequest): number | undefined {
|
||||
// 弹幕最大高度
|
||||
const maxTop = clientHeight - marginBottom
|
||||
|
||||
// 过滤同模式的弹幕,即每种模式各不影响
|
||||
const danmus: PlacementRow[] = visibles
|
||||
.filter(item => item.mode === target.mode && item.top <= maxTop)
|
||||
.sort((prev, next) => prev.top - next.top)
|
||||
|
||||
// 如果没有同模式的弹幕,直接返回
|
||||
if (danmus.length === 0) {
|
||||
if (target.mode === 2) {
|
||||
return maxTop - target.height
|
||||
}
|
||||
else {
|
||||
return marginTop
|
||||
}
|
||||
}
|
||||
|
||||
// 上下各加一个虚拟弹幕,方便计算
|
||||
danmus.unshift({
|
||||
type: 'top',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: marginTop,
|
||||
width: clientWidth,
|
||||
speed: 0,
|
||||
distance: clientWidth,
|
||||
})
|
||||
|
||||
danmus.push({
|
||||
type: 'bottom',
|
||||
top: maxTop,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: marginBottom,
|
||||
width: clientWidth,
|
||||
speed: 0,
|
||||
distance: clientWidth,
|
||||
})
|
||||
|
||||
// 查找是否有多余的缝隙足以容纳当前弹幕
|
||||
if (target.mode === 2) {
|
||||
// 倒序查找
|
||||
for (let index = danmus.length - 2; index >= 0; index -= 1) {
|
||||
const item = danmus[index]!
|
||||
const prev = danmus[index + 1]!
|
||||
const itemBottom = item.top + item.height
|
||||
const diff = prev.top - itemBottom
|
||||
if (diff >= target.height) {
|
||||
return prev.top - target.height
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 顺序查找
|
||||
for (let index = 1; index < danmus.length; index += 1) {
|
||||
const item = danmus[index]!
|
||||
const prev = danmus[index - 1]!
|
||||
const prevBottom = prev.top + prev.height
|
||||
const diff = item.top - prevBottom
|
||||
if (diff >= target.height) {
|
||||
return prevBottom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const topMap: VisibleDanmu[][] = []
|
||||
for (let index = 1; index < danmus.length - 1; index += 1) {
|
||||
// The loop excludes the two virtual boundary rows inserted above.
|
||||
const item = danmus[index] as VisibleDanmu
|
||||
if (topMap.length) {
|
||||
const last = topMap[topMap.length - 1]!
|
||||
if (last[0]!.top === item.top) {
|
||||
last.push(item)
|
||||
}
|
||||
else {
|
||||
topMap.push([item])
|
||||
}
|
||||
}
|
||||
else {
|
||||
topMap.push([item])
|
||||
}
|
||||
}
|
||||
|
||||
if (antiOverlap) {
|
||||
switch (target.mode) {
|
||||
case 0: {
|
||||
const result = topMap.find((list) => {
|
||||
return list.every((danmu) => {
|
||||
if (clientWidth < danmu.distance)
|
||||
return false
|
||||
if (target.speed < danmu.speed)
|
||||
return true
|
||||
const overlapTime = danmu.right / (target.speed - danmu.speed)
|
||||
if (overlapTime > danmu.time)
|
||||
return true
|
||||
return false
|
||||
})
|
||||
})
|
||||
|
||||
return result && result[0] ? result[0].top : undefined
|
||||
}
|
||||
|
||||
// 静止弹幕没有重叠问题
|
||||
case 1:
|
||||
case 2:
|
||||
return undefined
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (target.mode) {
|
||||
case 0:
|
||||
topMap.sort((prev, next) => {
|
||||
const nextMinRight = Math.min(...next.map(item => item.right))
|
||||
const prevMinRight = Math.min(...prev.map(item => item.right))
|
||||
return nextMinRight * next.length - prevMinRight * prev.length
|
||||
})
|
||||
break
|
||||
case 1:
|
||||
case 2:
|
||||
topMap.sort((prev, next) => {
|
||||
const nextMaxWidth = Math.max(...next.map(item => item.width))
|
||||
const prevMaxWidth = Math.max(...prev.map(item => item.width))
|
||||
return prevMaxWidth * prev.length - nextMaxWidth * next.length
|
||||
})
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return topMap[0]![0]!.top
|
||||
}
|
||||
}
|
||||
|
||||
onmessage = (event: MessageEvent<PlacementMessage>) => {
|
||||
const { data } = event
|
||||
if (!data.id || !data.type)
|
||||
return
|
||||
|
||||
const fns = { getDanmuTop }
|
||||
const fn = fns[data.type]
|
||||
const result = fn(data)
|
||||
|
||||
globalThis.postMessage({
|
||||
result,
|
||||
id: data.id,
|
||||
} satisfies PlacementReply)
|
||||
}
|
||||
Reference in new issue
Block a user