111 lines
3.3 KiB
Markdown
111 lines
3.3 KiB
Markdown
# ngx-pretext-table
|
|
|
|
Variable-height virtual scrolling for PrimeNG `p-table`, powered by [@chenglou/pretext](https://github.com/chenglou/pretext).
|
|
|
|
PrimeNG's built-in virtual scroll only supports **fixed row heights** (`virtualScrollItemSize`). This library replaces it with pretext-calculated variable row heights — no DOM measurement, no layout thrashing, O(log n) scroll lookup.
|
|
|
|
## Install
|
|
|
|
```bash
|
|
npm install ngx-pretext-table @chenglou/pretext
|
|
```
|
|
|
|
## Usage
|
|
|
|
```typescript
|
|
import { Component } from '@angular/core';
|
|
import { TableModule } from 'primeng/table';
|
|
import {
|
|
PretextVirtualScrollDirective,
|
|
PretextScrollEvent,
|
|
PretextColumnDef,
|
|
} from 'ngx-pretext-table';
|
|
|
|
@Component({
|
|
standalone: true,
|
|
imports: [TableModule, PretextVirtualScrollDirective],
|
|
template: `
|
|
<div pretextVirtualScroll
|
|
[data]="data"
|
|
[columns]="columns"
|
|
[font]="'14px system-ui'"
|
|
[lineHeight]="20"
|
|
[rowPadding]="16"
|
|
[scrollHeight]="'500px'"
|
|
(visibleRangeChange)="onRange($event)">
|
|
|
|
<p-table [value]="visibleData" [scrollable]="false">
|
|
<ng-template pTemplate="body" let-row let-i="rowIndex">
|
|
<tr [style.height.px]="rowHeights[i]">
|
|
<td>{{ row.name }}</td>
|
|
<td>{{ row.description }}</td>
|
|
</tr>
|
|
</ng-template>
|
|
</p-table>
|
|
</div>
|
|
`,
|
|
})
|
|
export class MyComponent {
|
|
data = [/* your data */];
|
|
|
|
// field + available text width (column width minus padding)
|
|
columns: PretextColumnDef[] = [
|
|
{ field: 'name', width: 184 },
|
|
{ field: 'description', width: 384 },
|
|
];
|
|
|
|
visibleData: any[] = [];
|
|
rowHeights: number[] = [];
|
|
|
|
onRange(e: PretextScrollEvent) {
|
|
this.visibleData = this.data.slice(e.start, e.end);
|
|
this.rowHeights = e.rowHeights;
|
|
}
|
|
}
|
|
```
|
|
|
|
## API
|
|
|
|
### `PretextVirtualScrollDirective`
|
|
|
|
| Input | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `data` | `any[]` | required | Full data array |
|
|
| `columns` | `PretextColumnDef[]` | required | Column field + text width |
|
|
| `font` | `string` | `'14px system-ui'` | CSS font shorthand |
|
|
| `lineHeight` | `number` | `20` | Line height in px |
|
|
| `rowPadding` | `number` | `16` | Vertical padding per row |
|
|
| `minRowHeight` | `number` | `32` | Minimum row height |
|
|
| `rowGap` | `number` | `0` | Gap between rows |
|
|
| `scrollHeight` | `string` | `'400px'` | Viewport height |
|
|
| `bufferRows` | `number` | `5` | Buffer rows above/below |
|
|
|
|
| Output | Type | Description |
|
|
|--------|------|-------------|
|
|
| `visibleRangeChange` | `PretextScrollEvent` | Emits when visible range changes |
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `scrollToIndex(index, behavior?)` | Scroll to a specific row |
|
|
|
|
### `PretextRowHeightService`
|
|
|
|
Low-level service for direct control:
|
|
|
|
```typescript
|
|
const cache = service.prepareRows(data, columns, font);
|
|
const heights = service.calculateRowHeights(cache, columns, lineHeight, padding);
|
|
const positions = service.buildPositionIndex(heights);
|
|
const range = service.findVisibleRange(positions, scrollTop, viewportHeight);
|
|
```
|
|
|
|
## How it works
|
|
|
|
1. **Prepare** (once) — `@chenglou/pretext` segments text and measures via canvas
|
|
2. **Layout** (on resize) — pure arithmetic, ~0.0002ms per cell, no DOM access
|
|
3. **Scroll** (continuous) — O(log n) binary search in cumulative position arrays
|
|
|
|
## License
|
|
|
|
MIT
|