Files

112 lines
2.6 KiB
Dart
Raw Permalink Normal View History

2026-07-14 11:11:36 +08:00
import '../contracts/danmaku.dart';
const int kDefaultHeatmapMinComments = 50;
const int kDefaultHeatmapBucketCount = 200;
class DanmakuHeatmapData {
final List<double> buckets;
final int bucketCount;
final int totalComments;
final int maxCount;
final bool visible;
const DanmakuHeatmapData({
required this.buckets,
required this.bucketCount,
required this.totalComments,
required this.maxCount,
required this.visible,
});
static const empty = DanmakuHeatmapData(
buckets: <double>[],
bucketCount: 0,
totalComments: 0,
maxCount: 0,
visible: false,
);
}
DanmakuHeatmapData computeHeatmap({
required List<DanmakuComment> comments,
required double durationSec,
int bucketCount = kDefaultHeatmapBucketCount,
int minComments = kDefaultHeatmapMinComments,
}) {
if (bucketCount <= 0) return DanmakuHeatmapData.empty;
if (durationSec <= 0) return DanmakuHeatmapData.empty;
final counts = List<int>.filled(bucketCount, 0);
int total = 0;
for (final c in comments) {
final t = c.time;
if (t < 0 || t > durationSec) continue;
var idx = (t / durationSec * bucketCount).floor();
if (idx >= bucketCount) idx = bucketCount - 1;
if (idx < 0) idx = 0;
counts[idx]++;
total++;
}
if (total < minComments) {
return DanmakuHeatmapData(
buckets: const <double>[],
bucketCount: bucketCount,
totalComments: total,
maxCount: 0,
visible: false,
);
}
var maxCount = 0;
for (final v in counts) {
if (v > maxCount) maxCount = v;
}
if (maxCount <= 0) {
return DanmakuHeatmapData(
buckets: const <double>[],
bucketCount: bucketCount,
totalComments: total,
maxCount: 0,
visible: false,
);
}
final buckets = List<double>.generate(
bucketCount,
(i) => counts[i] / maxCount,
growable: false,
);
return DanmakuHeatmapData(
buckets: buckets,
bucketCount: bucketCount,
totalComments: total,
maxCount: maxCount,
visible: true,
);
}
List<double> downsampleHeatmap(List<double> buckets, int targetCount) {
if (buckets.isEmpty || targetCount <= 0) return const <double>[];
if (targetCount >= buckets.length) return buckets;
final out = List<double>.filled(targetCount, 0.0);
final src = buckets.length;
for (var i = 0; i < targetCount; i++) {
final start = (i * src / targetCount).floor();
final end = ((i + 1) * src / targetCount).floor().clamp(start + 1, src);
var m = 0.0;
for (var j = start; j < end; j++) {
if (buckets[j] > m) m = buckets[j];
}
out[i] = m;
}
return out;
}