mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-23 05:41:20 -08:00
36 lines
1.4 KiB
TypeScript
36 lines
1.4 KiB
TypeScript
import type { DanmuItem, HeatmapPoint } from './types'
|
|
|
|
export const MAX_HEATMAP_POINTS = 0xFFFFFFFF
|
|
|
|
function upperBound(values: readonly number[], value: number): number {
|
|
let start = 0
|
|
let end = values.length
|
|
while (start < end) {
|
|
const middle = Math.floor((start + end) / 2)
|
|
// The binary-search interval guarantees middle is an existing index.
|
|
if (values[middle]! <= value)
|
|
start = middle + 1
|
|
else end = middle
|
|
}
|
|
return start
|
|
}
|
|
|
|
export function sampleHeatmap(queue: readonly Pick<DanmuItem, 'time'>[], width: number, duration: number, sampling: number): HeatmapPoint[] {
|
|
if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(duration) || duration <= 0
|
|
|| !Number.isFinite(sampling) || sampling <= 0 || Math.floor(width / sampling) + 1 > MAX_HEATMAP_POINTS) { return [] }
|
|
const times = queue.map(item => item.time).filter(time => typeof time === 'number' && !Number.isNaN(time)).sort((a, b) => a - b)
|
|
const points: HeatmapPoint[] = []
|
|
const gap = duration / width
|
|
if (!Number.isFinite(gap))
|
|
return []
|
|
// Keep the old floating-point x progression and strict-left/inclusive-right bins.
|
|
for (let x = 0; x <= width; x += sampling) {
|
|
if (points.length >= MAX_HEATMAP_POINTS || x + sampling === x)
|
|
return []
|
|
const left = x * gap
|
|
const right = (x + sampling) * gap
|
|
points.push([x, upperBound(times, right) - upperBound(times, left)])
|
|
}
|
|
return points
|
|
}
|