基于vue3.0和element-plus的组件库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

149 lines
3.6 KiB

/**
* useRuntimeHeightAugment
*
* For columns with custom cellRenderer that return {vnode, minHeight, minWidth},
* we need to measure actual DOM height after render and maintain a running
* average per column to self-adjust row heights.
*/
import { ref, reactive, type Ref } from "vue";
const SAMPLE_THRESHOLD = 5; // Minimum samples before updating average
const RECOMPUTE_THRESHOLD = 0.1; // 10% shift triggers recompute
export interface HeightSample {
columnKey: string;
height: number;
timestamp: number;
}
export interface ColumnHeightStats {
columnKey: string;
samples: number[];
average: number;
count: number;
}
export function useRuntimeHeightAugment() {
// Map from columnKey -> stats
const columnStats = reactive<Map<string, ColumnHeightStats>>(new Map());
// Pending samples not yet incorporated
const pendingSamples = ref<HeightSample[]>([]);
/**
* Record a measured height for a specific column's cell
*/
function recordHeight(columnKey: string, height: number) {
pendingSamples.value.push({
columnKey,
height,
timestamp: Date.now(),
});
}
/**
* Flush pending samples and update running averages
* Returns true if any column's average changed significantly
*/
function flushSamples(): boolean {
if (pendingSamples.value.length === 0) return false;
const changed: string[] = [];
// Group samples by column
const grouped = new Map<string, number[]>();
for (const sample of pendingSamples.value) {
const existing = grouped.get(sample.columnKey) || [];
existing.push(sample.height);
grouped.set(sample.columnKey, existing);
}
// Update stats for each column
for (const [columnKey, heights] of grouped) {
let stats = columnStats.get(columnKey);
if (!stats) {
stats = {
columnKey,
samples: [],
average: 0,
count: 0,
};
columnStats.set(columnKey, stats);
}
// Add new samples
stats.samples.push(...heights);
stats.count += heights.length;
// Keep only last 20 samples per column for running average
if (stats.samples.length > 20) {
stats.samples = stats.samples.slice(-20);
}
// Recompute average
const newAverage =
stats.samples.reduce((sum, h) => sum + h, 0) / stats.samples.length;
// Check if change is significant
if (stats.count >= SAMPLE_THRESHOLD) {
const oldAverage = stats.average;
if (oldAverage > 0 && Math.abs(newAverage - oldAverage) / oldAverage > RECOMPUTE_THRESHOLD) {
changed.push(columnKey);
}
}
stats.average = newAverage;
}
// Clear pending
pendingSamples.value = [];
return changed.length > 0;
}
/**
* Get the current estimated height for a column
*/
function getColumnHeight(columnKey: string): number {
const stats = columnStats.get(columnKey);
return stats?.average ?? 44; // Default fallback
}
/**
* Get all column heights as a map
*/
function getAllColumnHeights(): Map<string, number> {
const result = new Map<string, number>();
for (const [key, stats] of columnStats) {
result.set(key, stats.average || 44);
}
return result;
}
/**
* Reset stats for a column
*/
function resetColumn(columnKey: string) {
columnStats.delete(columnKey);
}
/**
* Reset all stats
*/
function resetAll() {
columnStats.clear();
pendingSamples.value = [];
}
return {
columnStats,
pendingSamples,
recordHeight,
flushSamples,
getColumnHeight,
getAllColumnHeights,
resetColumn,
resetAll,
};
}