Skip to content

Commit

Permalink
AG-7887 Angular batch framework comps (ag-grid#9981)
Browse files Browse the repository at this point in the history
* Batch angular cell renderers

* Inline framework loop to simplify duration handling

* Inline single method

* Use active flag to reduce duplication

* Add performance-test page to store examples

* Break out of framework loop if the grid body scrolled.

* update comment

* Add tactical robots.txt fix for now.

* Review changes

* Set rendering engine readonly
  • Loading branch information
StephenCooper authored Feb 28, 2025
1 parent d720185 commit 0e8dc48
Show file tree
Hide file tree
Showing 23 changed files with 719 additions and 139 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div class="test-container" style="height: 100%; display: flex; flex-direction: column">
<div>
<button onclick="onSetData()">Set Data</button>
<button onclick="onClearData()">Clear Data</button>
<button onclick="onScroll()">Scroll</button>
<span id="output">Time taken:</span>
</div>
<div id="myGrid" style="flex-grow: 1"></div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import type { ColDef, GridApi, GridOptions } from 'ag-grid-community';
import { ClientSideRowModelModule, ModuleRegistry, ValidationModule, createGrid } from 'ag-grid-community';

import { MissionResultRenderer } from './missionResultRenderer_typescript';

ModuleRegistry.registerModules([ClientSideRowModelModule, ValidationModule /* Development Only */]);

const repeat = (arr: any[], n: number) => Array(n).fill(arr).flat();

const cols: ColDef[] = [
{ field: 'athlete' },
{ field: 'gold' },
{ field: 'silver' },
{ field: 'bronze' },
{ field: 'total' },
{ field: 'age' },
{ field: 'country' },
{ field: 'sport' },
{ field: 'year' },
{ field: 'date' },
];

let gridApi: GridApi<IOlympicData>;

const gridOptions: GridOptions<IOlympicData> = {
columnDefs: repeat(cols, 10),
suppressColumnVirtualisation: true,
rowBuffer: 300,
defaultColDef: {
initialWidth: 100,
cellRenderer: MissionResultRenderer,
},
rowData: [],
};

function outputText(time?: number) {
const text = `Time taken: ${time ? Math.round(time) + 'ms' : '....'}`;
console.log(text);
document.querySelector<HTMLElement>('#output')!.innerText = text;
}

function onScroll() {
const start = performance.now();
outputText();
requestIdleCallback(() => {
outputText(performance.now() - start);
});
const eBodyViewport = document.querySelector<HTMLElement>('.ag-body-viewport')!;
const currScroll = eBodyViewport.scrollTop;
eBodyViewport.scroll(0, currScroll! + 5000);
}

function onClearData() {
const start = performance.now();
outputText();
requestIdleCallback(() => {
outputText(Math.round(performance.now() - start));
});
gridApi!.setGridOption('rowData', []);
}

function onSetData() {
const start = performance.now();
outputText();
requestIdleCallback(() => {
outputText(performance.now() - start);
});
gridApi!.setGridOption('rowData', repeat(data, 100));
}

// setup the grid after the page has finished loading
document.addEventListener('DOMContentLoaded', () => {
const gridDiv = document.querySelector<HTMLElement>('#myGrid')!;
gridApi = createGrid(gridDiv, gridOptions);
});

const data: IOlympicData[] = [
{
athlete: 'Michael Phelps',
age: 23,
country: 'United States',
sport: 'Swimming',
year: 2008,
date: '24/08/2008',
gold: 8,
silver: 0,
bronze: 0,
total: 8,
},
{
athlete: 'Michael Phelps',
age: 19,
country: 'United States',
sport: 'Swimming',
year: 2004,
date: '29/08/2004',
gold: 6,
silver: 0,
bronze: 2,
total: 8,
},
{
athlete: 'Michael Phelps',
age: 27,
country: 'United States',
sport: 'Swimming',
year: 2012,
date: '12/08/2012',
gold: 4,
silver: 2,
bronze: 0,
total: 6,
},
{
athlete: 'Natalie Coughlin',
age: 25,
country: 'United States',
sport: 'Swimming',
year: 2008,
date: '24/08/2008',
gold: 1,
silver: 2,
bronze: 3,
total: 6,
},
{
athlete: 'Aleksey Nemov',
age: 24,
country: 'Russia',
sport: 'Gymnastics',
year: 2000,
date: '01/10/2000',
gold: 2,
silver: 1,
bronze: 3,
total: 6,
},
{
athlete: 'Alicia Coutts',
age: 24,
country: 'Australia',
sport: 'Swimming',
year: 2012,
date: '12/08/2012',
gold: 1,
silver: 3,
bronze: 1,
total: 5,
},
{
athlete: 'Missy Franklin',
age: 17,
country: 'United States',
sport: 'Swimming',
year: 2012,
date: '12/08/2012',
gold: 4,
silver: 0,
bronze: 1,
total: 5,
},
{
athlete: 'Ryan Lochte',
age: 27,
country: 'United States',
sport: 'Swimming',
year: 2012,
date: '12/08/2012',
gold: 2,
silver: 2,
bronze: 1,
total: 5,
},
{
athlete: 'Allison Schmitt',
age: 22,
country: 'United States',
sport: 'Swimming',
year: 2012,
date: '12/08/2012',
gold: 3,
silver: 1,
bronze: 1,
total: 5,
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';

import type { ICellRendererAngularComp } from 'ag-grid-angular';
import type { ICellRendererParams } from 'ag-grid-community';

interface MissionCellRendererParams extends ICellRendererParams {
src?: (params: boolean) => string;
}

@Component({
selector: 'app-mission-result-renderer',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<span :class="missionSpan">
@if (value()) {
<img [alt]="value()" [src]="value()" [height]="30" :class="missionIcon" />
}
</span>
`,
styles: [
'img { width: auto; height: auto; } span {display: flex; height: 100%; justify-content: center; align-items: center} ',
],
})
export class MissionResultRenderer implements ICellRendererAngularComp {
value = signal<string>('');
agInit(params: MissionCellRendererParams): void {
this.refresh(params);
}

refresh(params: MissionCellRendererParams): boolean {
if (params.src) {
this.value.set(params.src(params.value));
} else {
const defaultSrc = `https://www.ag-grid.com/example-assets/icons/${
params.value ? 'tick-in-circle' : 'cross-in-circle'
}.png`;
this.value.set(defaultSrc);
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

import type { CustomCellRendererProps } from 'ag-grid-react';

interface MissionCellRendererParams extends CustomCellRendererProps {
src?: (params: boolean) => string;
}

export default (params: MissionCellRendererParams) => {
const defaultImgSrc = `https://www.ag-grid.com/example-assets/icons/${
params.value ? 'tick-in-circle' : 'cross-in-circle'
}.png`;
const imgSrc = params.src ? params.src(params.value) : defaultImgSrc;

return <span className="missionSpan">{<img alt={`${params.value}`} src={imgSrc} className="missionIcon" />}</span>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { ICellRendererComp, ICellRendererParams } from 'ag-grid-community';

interface MissionCellRendererParams extends ICellRendererParams {
src?: (params: boolean) => string;
}

export class MissionResultRenderer implements ICellRendererComp {
eGui!: HTMLSpanElement;

init(params: MissionCellRendererParams) {
const icon: HTMLImageElement = document.createElement('img');
if (params.src) {
icon.src = params.src(params.value);
} else {
icon.src = `https://www.ag-grid.com/example-assets/icons/${
params.value ? 'tick-in-circle' : 'cross-in-circle'
}.png`;
}
icon.setAttribute('class', 'missionIcon');

this.eGui = document.createElement('span');
this.eGui.setAttribute('class', 'missionSpan');
this.eGui.appendChild(icon);
}

getGui() {
return this.eGui;
}

// Required: Get the cell to refresh.
refresh(params: ICellRendererParams): boolean {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export default {
template: `
<span class="missionSpan">
<img
:alt="params.value"
:src="cellValue"
class="missionIcon"
/>
</span>
`,
data: function () {
return {
cellValue: '',
};
},
beforeMount() {
if (this.params.src) {
this.cellValue = this.params.src(this.params.value);
} else {
this.cellValue = `https://www.ag-grid.com/example-assets/icons/${
this.params.value ? 'tick-in-circle' : 'cross-in-circle'
}.png`;
}
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.example-wrapper {
display: flex;
flex-direction: column;
height: 100%;
}

#myGrid {
flex: 1 1 0px;
width: 100%;
}

.missionSpan {
display: flex;
justify-content: center;
height: 100%;
align-items: center;
}

.missionIcon {
width: auto;
height: auto;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div class="test-container" style="height: 100%; display: flex; flex-direction: column">
<div>
<button onclick="onSetData()">Set Data</button>
<button onclick="onClearData()">Clear Data</button>
<button onclick="onScroll()">Scroll</button>
<span id="output">Time taken:</span>
</div>
<div id="myGrid" style="flex-grow: 1"></div>
</div>
Loading

0 comments on commit 0e8dc48

Please sign in to comment.