argent-grid 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +69 -0
- package/.github/workflows/pages.yml +6 -12
- package/.storybook/main.ts +20 -0
- package/.storybook/preview.ts +18 -0
- package/.storybook/tsconfig.json +24 -0
- package/AGENTS.md +70 -27
- package/README.md +51 -34
- package/angular.json +66 -0
- package/biome.json +66 -0
- package/demo-app/e2e/selection-screenshot.spec.ts +20 -0
- package/docs/AG-GRID-COMPARISON.md +725 -0
- package/docs/CELL-RENDERER-GUIDE.md +241 -0
- package/docs/CONTEXT-MENU-GUIDE.md +371 -0
- package/docs/LIVE-DATA-OPTIMIZATIONS.md +497 -0
- package/docs/PERFORMANCE-OPTIMIZATIONS-PHASE1.md +162 -0
- package/docs/PERFORMANCE-REVIEW.md +571 -0
- package/docs/RESEARCH-STATUS.md +234 -0
- package/docs/STATE-PERSISTENCE-GUIDE.md +370 -0
- package/docs/STORYBOOK-REFACTOR.md +215 -0
- package/docs/STORYBOOK-STATUS.md +156 -0
- package/docs/TEST-COVERAGE-REPORT.md +276 -0
- package/docs/THEME-API-GUIDE.md +445 -0
- package/docs/THEME-API-PLAN.md +364 -0
- package/e2e/advanced.spec.ts +109 -0
- package/e2e/argentgrid.spec.ts +65 -0
- package/e2e/benchmark.spec.ts +52 -0
- package/e2e/cell-renderers.spec.ts +152 -0
- package/e2e/debug-streaming.spec.ts +31 -0
- package/e2e/dnd.spec.ts +73 -0
- package/e2e/screenshots.spec.ts +52 -0
- package/e2e/theming.spec.ts +35 -0
- package/e2e/visual.spec.ts +112 -0
- package/e2e/visual.spec.ts-snapshots/checkbox-renderer-mixed.png +0 -0
- package/e2e/visual.spec.ts-snapshots/debug.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-column-group-headers.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-default.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-empty-state.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-filter-popup.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-scroll-borders.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-sidebar-buttons.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-text-filter.png +0 -0
- package/e2e/visual.spec.ts-snapshots/grid-with-selection.png +0 -0
- package/e2e/visual.spec.ts-snapshots/rating-renderer-varied.png +0 -0
- package/package.json +21 -7
- package/plan.md +56 -28
- package/playwright.config.ts +38 -0
- package/setup-vitest.ts +10 -13
- package/src/lib/argent-grid.module.ts +10 -12
- package/src/lib/components/argent-grid.component.css +281 -321
- package/src/lib/components/argent-grid.component.html +295 -207
- package/src/lib/components/argent-grid.component.spec.ts +120 -160
- package/src/lib/components/argent-grid.component.ts +1193 -290
- package/src/lib/components/argent-grid.regressions.spec.ts +301 -0
- package/src/lib/components/argent-grid.selection.spec.ts +132 -0
- package/src/lib/components/set-filter/set-filter.component.spec.ts +191 -0
- package/src/lib/components/set-filter/set-filter.component.ts +307 -0
- package/src/lib/directives/ag-grid-compatibility.directive.ts +16 -26
- package/src/lib/directives/click-outside.directive.ts +19 -0
- package/src/lib/rendering/canvas-renderer.spec.ts +513 -0
- package/src/lib/rendering/canvas-renderer.ts +456 -452
- package/src/lib/rendering/live-data-handler.ts +110 -0
- package/src/lib/rendering/live-data-optimizations.ts +133 -0
- package/src/lib/rendering/render/blit.spec.ts +16 -27
- package/src/lib/rendering/render/blit.ts +48 -36
- package/src/lib/rendering/render/cells.spec.ts +132 -0
- package/src/lib/rendering/render/cells.ts +167 -28
- package/src/lib/rendering/render/column-utils.ts +95 -0
- package/src/lib/rendering/render/hit-test.ts +50 -0
- package/src/lib/rendering/render/index.ts +88 -76
- package/src/lib/rendering/render/lines.ts +53 -47
- package/src/lib/rendering/render/primitives.ts +423 -0
- package/src/lib/rendering/render/theme.spec.ts +8 -12
- package/src/lib/rendering/render/theme.ts +7 -10
- package/src/lib/rendering/render/types.ts +3 -2
- package/src/lib/rendering/render/walk.spec.ts +35 -38
- package/src/lib/rendering/render/walk.ts +94 -64
- package/src/lib/rendering/utils/damage-tracker.spec.ts +8 -7
- package/src/lib/rendering/utils/damage-tracker.ts +6 -18
- package/src/lib/rendering/utils/index.ts +1 -1
- package/src/lib/services/grid.service.set-filter.spec.ts +219 -0
- package/src/lib/services/grid.service.spec.ts +1241 -201
- package/src/lib/services/grid.service.ts +1204 -235
- package/src/lib/themes/parts/color-schemes.ts +132 -0
- package/src/lib/themes/parts/icon-sets.ts +258 -0
- package/src/lib/themes/theme-builder.ts +347 -0
- package/src/lib/themes/theme-quartz.ts +72 -0
- package/src/lib/themes/types.ts +238 -0
- package/src/lib/types/ag-grid-types.ts +573 -14
- package/src/public-api.ts +39 -9
- package/src/stories/Advanced.stories.ts +249 -0
- package/src/stories/ArgentGrid.stories.ts +301 -0
- package/src/stories/Benchmark.stories.ts +76 -0
- package/src/stories/CellRenderers.stories.ts +395 -0
- package/src/stories/Filtering.stories.ts +292 -0
- package/src/stories/Grouping.stories.ts +290 -0
- package/src/stories/Streaming.stories.ts +57 -0
- package/src/stories/Theming.stories.ts +137 -0
- package/src/stories/Tooltips.stories.ts +381 -0
- package/src/stories/benchmark-wrapper.component.ts +355 -0
- package/src/stories/story-utils.ts +88 -0
- package/src/stories/streaming-wrapper.component.ts +441 -0
- package/tsconfig.json +1 -0
- package/tsconfig.storybook.json +10 -0
- package/vitest.config.ts +9 -9
- package/demo-app/README.md +0 -70
- package/demo-app/angular.json +0 -78
- package/demo-app/e2e/benchmark.spec.ts +0 -53
- package/demo-app/e2e/demo-page.spec.ts +0 -77
- package/demo-app/e2e/grid-features.spec.ts +0 -269
- package/demo-app/package-lock.json +0 -14023
- package/demo-app/package.json +0 -36
- package/demo-app/playwright-test-menu.js +0 -19
- package/demo-app/playwright.config.ts +0 -23
- package/demo-app/src/app/app.component.ts +0 -10
- package/demo-app/src/app/app.config.ts +0 -13
- package/demo-app/src/app/app.routes.ts +0 -7
- package/demo-app/src/app/demo-page/demo-page.component.css +0 -313
- package/demo-app/src/app/demo-page/demo-page.component.html +0 -124
- package/demo-app/src/app/demo-page/demo-page.component.ts +0 -366
- package/demo-app/src/index.html +0 -19
- package/demo-app/src/main.ts +0 -6
- package/demo-app/tsconfig.json +0 -31
|
@@ -4,9 +4,17 @@
|
|
|
4
4
|
* Handles drawing of individual cells with prep/draw cycle optimization.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { ColDef, Column, GridApi, IRowNode } from '../../types/ag-grid-types';
|
|
8
|
+
import {
|
|
9
|
+
drawBadge,
|
|
10
|
+
drawButton,
|
|
11
|
+
drawCheckbox,
|
|
12
|
+
drawProgressBar,
|
|
13
|
+
drawRating,
|
|
14
|
+
drawSparkline,
|
|
15
|
+
} from './primitives';
|
|
9
16
|
import { getFontFromTheme } from './theme';
|
|
17
|
+
import { CellDrawContext, ColumnPrepResult, GridTheme } from './types';
|
|
10
18
|
|
|
11
19
|
/**
|
|
12
20
|
* Get value from object using path (e.g. 'pivotData.NY.salary')
|
|
@@ -14,8 +22,8 @@ import { getFontFromTheme } from './theme';
|
|
|
14
22
|
export function getValueByPath(obj: any, path: string): any {
|
|
15
23
|
if (!path || !obj) return undefined;
|
|
16
24
|
if (!path.includes('.')) return obj[path];
|
|
17
|
-
|
|
18
|
-
return path.split('.').reduce((acc, part) => acc
|
|
25
|
+
|
|
26
|
+
return path.split('.').reduce((acc, part) => acc?.[part], obj);
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
// ============================================================================
|
|
@@ -75,7 +83,7 @@ export function drawCell<TData = any>(
|
|
|
75
83
|
prep: ColumnPrepResult<TData>,
|
|
76
84
|
context: CellDrawContext<TData>
|
|
77
85
|
): void {
|
|
78
|
-
const {
|
|
86
|
+
const { rowNode } = context;
|
|
79
87
|
|
|
80
88
|
// Draw cell background
|
|
81
89
|
drawCellBackground(ctx, context);
|
|
@@ -109,23 +117,92 @@ export function drawCellBackground<TData = any>(
|
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
/**
|
|
112
|
-
* Draw cell content (text)
|
|
120
|
+
* Draw cell content (text or specialized renderer)
|
|
113
121
|
*/
|
|
114
122
|
export function drawCellContent<TData = any>(
|
|
115
123
|
ctx: CanvasRenderingContext2D,
|
|
116
|
-
|
|
124
|
+
_prep: ColumnPrepResult<TData>,
|
|
117
125
|
context: CellDrawContext<TData>
|
|
118
126
|
): void {
|
|
119
|
-
const { x, y, width, height, formattedValue, theme } = context;
|
|
127
|
+
const { x, y, width, height, value, formattedValue, theme, colDef, rowNode, api } = context;
|
|
128
|
+
|
|
129
|
+
// 1. Check for dedicated checkbox renderer or internal selection column
|
|
130
|
+
if (colDef?.cellRenderer === 'checkbox' || context.column.colId === 'ag-Grid-SelectionColumn') {
|
|
131
|
+
const isChecked = colDef?.cellRenderer === 'checkbox' ? !!value : !!rowNode?.selected;
|
|
132
|
+
const size = 14;
|
|
133
|
+
const bx = Math.floor(x + (width - size) / 2);
|
|
134
|
+
const by = Math.floor(y + (height - size) / 2);
|
|
135
|
+
|
|
136
|
+
drawCheckbox(ctx, bx, by, size, isChecked, theme);
|
|
137
|
+
return; // Dedicated checkbox column only shows checkbox
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 2. Check for sparkline
|
|
141
|
+
if (colDef?.sparklineOptions) {
|
|
142
|
+
drawSparkline(ctx, value, x, y, width, height, colDef.sparklineOptions);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 3. Check for progress bar
|
|
147
|
+
if (colDef?.progressOptions) {
|
|
148
|
+
drawProgressBar(ctx, Number(value), x, y, width, height, colDef.progressOptions);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 4. Check for badge
|
|
153
|
+
if (colDef?.badgeOptions) {
|
|
154
|
+
drawBadge(ctx, String(value ?? ''), x, y, width, height, colDef.badgeOptions);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 5. Check for button
|
|
159
|
+
if (colDef?.buttonOptions) {
|
|
160
|
+
const opts = colDef.buttonOptions;
|
|
161
|
+
const label =
|
|
162
|
+
typeof opts.label === 'function'
|
|
163
|
+
? opts.label({
|
|
164
|
+
value,
|
|
165
|
+
data: rowNode?.data,
|
|
166
|
+
node: rowNode!,
|
|
167
|
+
colDef: colDef!,
|
|
168
|
+
api: api!,
|
|
169
|
+
})
|
|
170
|
+
: opts.label;
|
|
171
|
+
drawButton(ctx, label, x, y, width, height, opts);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
120
174
|
|
|
175
|
+
// 6. Check for rating
|
|
176
|
+
if (colDef?.cellRenderer === 'rating' || colDef?.ratingOptions) {
|
|
177
|
+
drawRating(ctx, Number(value), x, y, width, height, colDef?.ratingOptions);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 7. Default: Text rendering
|
|
121
182
|
if (!formattedValue) return;
|
|
122
183
|
|
|
123
184
|
// Calculate text position with padding
|
|
124
185
|
const textX = x + theme.cellPadding;
|
|
125
186
|
const textY = y + height / 2; // Centered vertically
|
|
126
187
|
|
|
188
|
+
// Handle cellStyle color
|
|
189
|
+
let textColor = theme.textCell;
|
|
190
|
+
if (colDef?.cellStyle) {
|
|
191
|
+
const style =
|
|
192
|
+
typeof colDef.cellStyle === 'function'
|
|
193
|
+
? colDef.cellStyle({
|
|
194
|
+
value,
|
|
195
|
+
data: rowNode?.data,
|
|
196
|
+
node: rowNode!,
|
|
197
|
+
column: context.column,
|
|
198
|
+
api: api!,
|
|
199
|
+
})
|
|
200
|
+
: colDef.cellStyle;
|
|
201
|
+
if (style?.color) textColor = style.color;
|
|
202
|
+
}
|
|
203
|
+
|
|
127
204
|
// Set text properties
|
|
128
|
-
ctx.fillStyle =
|
|
205
|
+
ctx.fillStyle = textColor;
|
|
129
206
|
ctx.textBaseline = 'middle';
|
|
130
207
|
|
|
131
208
|
// Truncate text if needed
|
|
@@ -142,10 +219,10 @@ export function drawCellContent<TData = any>(
|
|
|
142
219
|
*/
|
|
143
220
|
export function drawGroupIndicators<TData = any>(
|
|
144
221
|
ctx: CanvasRenderingContext2D,
|
|
145
|
-
|
|
222
|
+
_prep: ColumnPrepResult<TData>,
|
|
146
223
|
context: CellDrawContext<TData>
|
|
147
224
|
): void {
|
|
148
|
-
const { x, y,
|
|
225
|
+
const { x, y, height, column, rowNode, theme } = context;
|
|
149
226
|
|
|
150
227
|
if (!rowNode) return;
|
|
151
228
|
|
|
@@ -174,7 +251,7 @@ export function drawGroupIndicators<TData = any>(
|
|
|
174
251
|
const size = theme.groupIndicatorSize;
|
|
175
252
|
const centerX = Math.floor(indicatorX + size / 2);
|
|
176
253
|
const centerY = Math.floor(indicatorY);
|
|
177
|
-
|
|
254
|
+
|
|
178
255
|
// Horizontal line
|
|
179
256
|
ctx.moveTo(Math.floor(indicatorX), centerY);
|
|
180
257
|
ctx.lineTo(Math.floor(indicatorX + size), centerY);
|
|
@@ -212,7 +289,7 @@ export function truncateText(
|
|
|
212
289
|
|
|
213
290
|
while (start < end) {
|
|
214
291
|
const mid = Math.floor((start + end) / 2);
|
|
215
|
-
const truncated = text.slice(0, mid)
|
|
292
|
+
const truncated = `${text.slice(0, mid)}...`;
|
|
216
293
|
|
|
217
294
|
if (ctx.measureText(truncated).width <= maxWidth) {
|
|
218
295
|
start = mid + 1;
|
|
@@ -221,16 +298,13 @@ export function truncateText(
|
|
|
221
298
|
}
|
|
222
299
|
}
|
|
223
300
|
|
|
224
|
-
return text.slice(0, Math.max(0, start - 1))
|
|
301
|
+
return `${text.slice(0, Math.max(0, start - 1))}...`;
|
|
225
302
|
}
|
|
226
303
|
|
|
227
304
|
/**
|
|
228
305
|
* Measure text width
|
|
229
306
|
*/
|
|
230
|
-
export function measureText(
|
|
231
|
-
ctx: CanvasRenderingContext2D,
|
|
232
|
-
text: string
|
|
233
|
-
): number {
|
|
307
|
+
export function measureText(ctx: CanvasRenderingContext2D, text: string): number {
|
|
234
308
|
return ctx.measureText(text).width;
|
|
235
309
|
}
|
|
236
310
|
|
|
@@ -240,7 +314,7 @@ export function measureText(
|
|
|
240
314
|
export function calculateColumnWidth<TData = any>(
|
|
241
315
|
ctx: CanvasRenderingContext2D,
|
|
242
316
|
column: Column,
|
|
243
|
-
|
|
317
|
+
_colDef: ColDef<TData> | null,
|
|
244
318
|
theme: GridTheme,
|
|
245
319
|
sampleData: any[],
|
|
246
320
|
maxRows: number = 100
|
|
@@ -278,6 +352,19 @@ export function calculateColumnWidth<TData = any>(
|
|
|
278
352
|
/**
|
|
279
353
|
* Get formatted cell value
|
|
280
354
|
*/
|
|
355
|
+
/**
|
|
356
|
+
* Strip HTML tags from string
|
|
357
|
+
* Supports basic cellRenderer that returns HTML strings
|
|
358
|
+
* Note: Only plain text is rendered - colors, backgrounds, etc. are NOT supported
|
|
359
|
+
*/
|
|
360
|
+
export function stripHtmlTags(html: string): string {
|
|
361
|
+
if (!html) return '';
|
|
362
|
+
return html
|
|
363
|
+
.replace(/<[^>]*>/g, '')
|
|
364
|
+
.replace(/\s+/g, ' ')
|
|
365
|
+
.trim();
|
|
366
|
+
}
|
|
367
|
+
|
|
281
368
|
export function getFormattedValue<TData = any>(
|
|
282
369
|
value: any,
|
|
283
370
|
colDef: ColDef<TData> | null,
|
|
@@ -289,6 +376,27 @@ export function getFormattedValue<TData = any>(
|
|
|
289
376
|
return '';
|
|
290
377
|
}
|
|
291
378
|
|
|
379
|
+
// Use custom cellRenderer if provided
|
|
380
|
+
if (colDef && typeof colDef.cellRenderer === 'function') {
|
|
381
|
+
try {
|
|
382
|
+
const result = colDef.cellRenderer({
|
|
383
|
+
value,
|
|
384
|
+
data,
|
|
385
|
+
node: rowNode,
|
|
386
|
+
colDef,
|
|
387
|
+
api,
|
|
388
|
+
});
|
|
389
|
+
// Handle both string and Promise<string> returns
|
|
390
|
+
if (typeof result === 'string') {
|
|
391
|
+
return stripHtmlTags(result);
|
|
392
|
+
}
|
|
393
|
+
// For async renderers, return value as string (will be updated on next render)
|
|
394
|
+
return String(value);
|
|
395
|
+
} catch (e) {
|
|
396
|
+
console.warn('Cell renderer error:', e);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
292
400
|
// Use custom formatter if provided
|
|
293
401
|
if (colDef && typeof colDef.valueFormatter === 'function') {
|
|
294
402
|
try {
|
|
@@ -311,6 +419,42 @@ export function getFormattedValue<TData = any>(
|
|
|
311
419
|
// BATCH CELL RENDERING
|
|
312
420
|
// ============================================================================
|
|
313
421
|
|
|
422
|
+
/**
|
|
423
|
+
* Get the value for a cell, respecting valueGetter if present
|
|
424
|
+
*/
|
|
425
|
+
export function getCellValue<TData = any>(
|
|
426
|
+
column: Column,
|
|
427
|
+
colDef: ColDef<TData> | null,
|
|
428
|
+
rowNode: IRowNode<TData>,
|
|
429
|
+
api: GridApi<TData>
|
|
430
|
+
): any {
|
|
431
|
+
// 1. Prioritize valueGetter
|
|
432
|
+
if (colDef?.valueGetter) {
|
|
433
|
+
if (typeof colDef.valueGetter === 'function') {
|
|
434
|
+
try {
|
|
435
|
+
return colDef.valueGetter({
|
|
436
|
+
data: rowNode.data,
|
|
437
|
+
node: rowNode,
|
|
438
|
+
colDef,
|
|
439
|
+
api,
|
|
440
|
+
column,
|
|
441
|
+
context: api.getGridOption('context'),
|
|
442
|
+
} as any);
|
|
443
|
+
} catch (e) {
|
|
444
|
+
console.warn('Value getter error:', e);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// Note: String expressions for valueGetter are not supported in the canvas renderer yet
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// 2. Fallback to field
|
|
451
|
+
if (column.field) {
|
|
452
|
+
return getValueByPath(rowNode.data, column.field);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return undefined;
|
|
456
|
+
}
|
|
457
|
+
|
|
314
458
|
/**
|
|
315
459
|
* Render all cells in a row
|
|
316
460
|
*/
|
|
@@ -337,14 +481,8 @@ export function renderRow<TData = any>(
|
|
|
337
481
|
if (!prep) continue;
|
|
338
482
|
|
|
339
483
|
const x = getCellX(column);
|
|
340
|
-
const value = column.
|
|
341
|
-
const formattedValue = getFormattedValue(
|
|
342
|
-
value,
|
|
343
|
-
prep.colDef,
|
|
344
|
-
rowNode.data,
|
|
345
|
-
rowNode,
|
|
346
|
-
api
|
|
347
|
-
);
|
|
484
|
+
const value = getCellValue(column, prep.colDef, rowNode, api);
|
|
485
|
+
const formattedValue = getFormattedValue(value, prep.colDef, rowNode.data, rowNode, api);
|
|
348
486
|
|
|
349
487
|
const context: CellDrawContext<TData> = {
|
|
350
488
|
ctx,
|
|
@@ -362,8 +500,9 @@ export function renderRow<TData = any>(
|
|
|
362
500
|
isSelected: options.isSelected || rowNode.selected,
|
|
363
501
|
isHovered: options.isHovered || false,
|
|
364
502
|
isEvenRow,
|
|
503
|
+
api,
|
|
365
504
|
};
|
|
366
505
|
|
|
367
506
|
drawCell(ctx, prep, context);
|
|
368
507
|
}
|
|
369
|
-
}
|
|
508
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Column Utilities for Canvas Renderer
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for column management and definition lookup.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ColDef, Column, ColumnGroup, GridApi } from '../../types/ag-grid-types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check if a column or column group is visible, respecting columnGroupShow
|
|
11
|
+
*/
|
|
12
|
+
export function isColumnVisible(item: Column | ColumnGroup): boolean {
|
|
13
|
+
if (item.columnGroupShow) {
|
|
14
|
+
const parent = item.parent;
|
|
15
|
+
if (parent) {
|
|
16
|
+
if (item.columnGroupShow === 'open') {
|
|
17
|
+
return parent.expanded;
|
|
18
|
+
}
|
|
19
|
+
if (item.columnGroupShow === 'closed') {
|
|
20
|
+
return !parent.expanded;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if ('children' in item) {
|
|
26
|
+
return item.children.some((child) => isColumnVisible(child));
|
|
27
|
+
}
|
|
28
|
+
return item.visible;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Find the Column Definition for a given Column
|
|
33
|
+
*/
|
|
34
|
+
export function getColumnDef<TData = any>(
|
|
35
|
+
column: Column,
|
|
36
|
+
gridApi: GridApi<TData>
|
|
37
|
+
): ColDef<TData> | null {
|
|
38
|
+
const allDefs = gridApi.getColumnDefs();
|
|
39
|
+
if (!allDefs) return null;
|
|
40
|
+
|
|
41
|
+
const targetId = column.colId;
|
|
42
|
+
const targetField = column.field?.toString();
|
|
43
|
+
|
|
44
|
+
for (const def of allDefs) {
|
|
45
|
+
if ('children' in def) {
|
|
46
|
+
const found = def.children.find((c) => {
|
|
47
|
+
const cDef = c as ColDef;
|
|
48
|
+
return (
|
|
49
|
+
cDef.colId === targetId ||
|
|
50
|
+
cDef.field?.toString() === targetId ||
|
|
51
|
+
(targetField && cDef.field?.toString() === targetField)
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
if (found) return found as ColDef<TData>;
|
|
55
|
+
} else {
|
|
56
|
+
const cDef = def as ColDef;
|
|
57
|
+
if (
|
|
58
|
+
cDef.colId === targetId ||
|
|
59
|
+
cDef.field?.toString() === targetId ||
|
|
60
|
+
(targetField && cDef.field?.toString() === targetField)
|
|
61
|
+
) {
|
|
62
|
+
return def as ColDef<TData>;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get X position for a column
|
|
71
|
+
*/
|
|
72
|
+
export function getColumnX(
|
|
73
|
+
targetCol: Column,
|
|
74
|
+
columnPositions: Map<string, number>,
|
|
75
|
+
scrollLeft: number,
|
|
76
|
+
leftPinnedWidth: number,
|
|
77
|
+
rightPinnedWidth: number,
|
|
78
|
+
viewportWidth: number
|
|
79
|
+
): number {
|
|
80
|
+
// Use cached column position (O(1) lookup)
|
|
81
|
+
const baseX = columnPositions.get(targetCol.colId) || 0;
|
|
82
|
+
|
|
83
|
+
// Adjust for pinned columns and scroll position
|
|
84
|
+
if (targetCol.pinned === 'left') {
|
|
85
|
+
return Math.floor(baseX);
|
|
86
|
+
} else if (targetCol.pinned === 'right') {
|
|
87
|
+
// When right-pinned, we need to know the offset from the right edge
|
|
88
|
+
// Our positions are accumulated from left to right.
|
|
89
|
+
// We need to find where the right-pinned section starts.
|
|
90
|
+
const rightPinnedStartX = Math.floor(viewportWidth - rightPinnedWidth);
|
|
91
|
+
return rightPinnedStartX + Math.floor(baseX - (viewportWidth - rightPinnedWidth));
|
|
92
|
+
} else {
|
|
93
|
+
return Math.floor(leftPinnedWidth - scrollLeft + (baseX - leftPinnedWidth));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hit Testing for Canvas Renderer
|
|
3
|
+
*
|
|
4
|
+
* Utilities for detecting which grid element is under a given coordinate.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Column } from '../../types/ag-grid-types';
|
|
8
|
+
import { HitTestResult } from './types';
|
|
9
|
+
import { getColumnAtX, getRowAtY } from './walk';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Perform a hit test on the grid
|
|
13
|
+
*/
|
|
14
|
+
export function performHitTest(
|
|
15
|
+
canvasX: number,
|
|
16
|
+
canvasY: number,
|
|
17
|
+
rowHeight: number,
|
|
18
|
+
scrollTop: number,
|
|
19
|
+
scrollLeft: number,
|
|
20
|
+
viewportWidth: number,
|
|
21
|
+
columns: Column[],
|
|
22
|
+
availableWidth?: number
|
|
23
|
+
): HitTestResult {
|
|
24
|
+
// Use walker utility for row detection
|
|
25
|
+
const rowIndex = getRowAtY(canvasY, rowHeight, scrollTop);
|
|
26
|
+
|
|
27
|
+
// Use walker utility for column detection
|
|
28
|
+
const result = getColumnAtX(columns, canvasX, scrollLeft, viewportWidth, availableWidth);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
rowIndex,
|
|
32
|
+
columnIndex: result.index,
|
|
33
|
+
column: result.column,
|
|
34
|
+
rowNode: null, // Should be populated by caller if needed
|
|
35
|
+
hitArea: result.column ? 'cell' : 'empty',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the horizontal offset of a center column
|
|
41
|
+
*/
|
|
42
|
+
export function getCenterColumnOffset(targetCol: Column, columns: Column[]): number {
|
|
43
|
+
const centerColumns = columns.filter((c) => !c.pinned);
|
|
44
|
+
let offset = 0;
|
|
45
|
+
for (const col of centerColumns) {
|
|
46
|
+
if (col === targetCol) return offset;
|
|
47
|
+
offset += col.width;
|
|
48
|
+
}
|
|
49
|
+
return offset;
|
|
50
|
+
}
|
|
@@ -4,102 +4,114 @@
|
|
|
4
4
|
* Exports all rendering-related modules.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
//
|
|
8
|
-
export {
|
|
9
|
-
Rectangle,
|
|
10
|
-
Point,
|
|
11
|
-
Size,
|
|
12
|
-
ScrollPosition,
|
|
13
|
-
PositionedColumn,
|
|
14
|
-
ColumnWalkCallback,
|
|
15
|
-
RowWalkCallback,
|
|
16
|
-
CellWalkCallback,
|
|
17
|
-
CellDrawContext,
|
|
18
|
-
ColumnPrepResult,
|
|
19
|
-
BlitResult,
|
|
20
|
-
BufferPair,
|
|
21
|
-
DamageType,
|
|
22
|
-
DirtyRegions,
|
|
23
|
-
GridTheme,
|
|
24
|
-
PartialTheme,
|
|
25
|
-
RenderState,
|
|
26
|
-
VisibleRange,
|
|
27
|
-
HitTestResult,
|
|
28
|
-
GridMouseEvent,
|
|
29
|
-
} from './types';
|
|
30
|
-
|
|
31
|
-
// Theme (re-export the DEFAULT_THEME and utilities)
|
|
32
|
-
export {
|
|
33
|
-
DEFAULT_THEME,
|
|
34
|
-
DARK_THEME,
|
|
35
|
-
THEME_PRESETS,
|
|
36
|
-
mergeTheme,
|
|
37
|
-
getFontFromTheme,
|
|
38
|
-
getRowTheme,
|
|
39
|
-
getCellBackgroundColor,
|
|
40
|
-
getThemePreset,
|
|
41
|
-
createTheme,
|
|
42
|
-
} from './theme';
|
|
43
|
-
|
|
44
|
-
// Walker functions
|
|
45
|
-
export {
|
|
46
|
-
walkColumns,
|
|
47
|
-
getPositionedColumns,
|
|
48
|
-
getPinnedWidths,
|
|
49
|
-
walkRows,
|
|
50
|
-
getVisibleRowRange,
|
|
51
|
-
getRowY,
|
|
52
|
-
walkCells,
|
|
53
|
-
getColumnAtX,
|
|
54
|
-
getColumnIndex,
|
|
55
|
-
getTotalColumnWidth,
|
|
56
|
-
getRowAtY,
|
|
57
|
-
isRowVisible,
|
|
58
|
-
calculateVisibleRange,
|
|
59
|
-
} from './walk';
|
|
60
|
-
|
|
7
|
+
// Live data optimizations
|
|
8
|
+
export { LiveDataOptimizations } from '../live-data-optimizations';
|
|
61
9
|
// Blitting optimization
|
|
62
10
|
export {
|
|
63
|
-
|
|
64
|
-
MAX_BLIT_DELTA_RATIO,
|
|
65
|
-
shouldBlit,
|
|
66
|
-
calculateBlit,
|
|
11
|
+
BlitState,
|
|
67
12
|
blitLastFrame,
|
|
13
|
+
calculateBlit,
|
|
68
14
|
createBufferPair,
|
|
69
|
-
swapBuffers,
|
|
70
15
|
displayBuffer,
|
|
16
|
+
MAX_BLIT_DELTA_RATIO,
|
|
17
|
+
MIN_BLIT_DELTA,
|
|
71
18
|
resizeBufferPair,
|
|
72
|
-
|
|
19
|
+
shouldBlit,
|
|
20
|
+
swapBuffers,
|
|
73
21
|
} from './blit';
|
|
74
|
-
|
|
75
22
|
// Cell rendering (explicit exports to avoid conflicts)
|
|
76
23
|
export {
|
|
77
|
-
|
|
78
|
-
prepColumns,
|
|
24
|
+
calculateColumnWidth,
|
|
79
25
|
drawCell,
|
|
80
26
|
drawCellBackground,
|
|
81
27
|
drawCellContent,
|
|
82
28
|
drawGroupIndicators,
|
|
83
|
-
|
|
84
|
-
measureText,
|
|
85
|
-
calculateColumnWidth,
|
|
29
|
+
getCellValue,
|
|
86
30
|
getFormattedValue,
|
|
87
31
|
getValueByPath,
|
|
32
|
+
measureText,
|
|
33
|
+
prepColumn,
|
|
34
|
+
prepColumns,
|
|
88
35
|
renderRow,
|
|
36
|
+
truncateText,
|
|
89
37
|
} from './cells';
|
|
90
|
-
|
|
38
|
+
// Column utilities
|
|
39
|
+
export * from './column-utils';
|
|
40
|
+
// Hit testing
|
|
41
|
+
export * from './hit-test';
|
|
91
42
|
// Grid lines
|
|
92
43
|
export {
|
|
93
|
-
drawCrispLine,
|
|
94
|
-
drawHorizontalLine,
|
|
95
|
-
drawVerticalLine,
|
|
96
|
-
drawRowLines,
|
|
97
|
-
drawColumnLines,
|
|
98
|
-
getColumnBorderPositions,
|
|
99
|
-
drawGridLines,
|
|
100
44
|
drawBorder,
|
|
101
45
|
drawCellSelectionBorder,
|
|
102
|
-
|
|
46
|
+
drawColumnLines,
|
|
47
|
+
drawCrispLine,
|
|
48
|
+
drawGridLines,
|
|
49
|
+
drawHorizontalLine,
|
|
103
50
|
drawPinnedRegionBorders,
|
|
104
51
|
drawPinnedRegionShadows,
|
|
105
|
-
|
|
52
|
+
drawRangeSelectionBorder,
|
|
53
|
+
drawRowLines,
|
|
54
|
+
drawVerticalLine,
|
|
55
|
+
getColumnBorderPositions,
|
|
56
|
+
} from './lines';
|
|
57
|
+
// Rendering primitives
|
|
58
|
+
export {
|
|
59
|
+
drawBadge,
|
|
60
|
+
drawButton,
|
|
61
|
+
drawCheckbox,
|
|
62
|
+
drawGroupIndicator,
|
|
63
|
+
drawProgressBar,
|
|
64
|
+
drawRating,
|
|
65
|
+
drawSparkline,
|
|
66
|
+
} from './primitives';
|
|
67
|
+
// Theme (re-export the DEFAULT_THEME and utilities)
|
|
68
|
+
export {
|
|
69
|
+
createTheme,
|
|
70
|
+
DARK_THEME,
|
|
71
|
+
DEFAULT_THEME,
|
|
72
|
+
getCellBackgroundColor,
|
|
73
|
+
getFontFromTheme,
|
|
74
|
+
getRowTheme,
|
|
75
|
+
getThemePreset,
|
|
76
|
+
mergeTheme,
|
|
77
|
+
THEME_PRESETS,
|
|
78
|
+
} from './theme';
|
|
79
|
+
// Types (base definitions)
|
|
80
|
+
export {
|
|
81
|
+
BlitResult,
|
|
82
|
+
BufferPair,
|
|
83
|
+
CellDrawContext,
|
|
84
|
+
CellWalkCallback,
|
|
85
|
+
ColumnPrepResult,
|
|
86
|
+
ColumnWalkCallback,
|
|
87
|
+
DamageType,
|
|
88
|
+
DirtyRegions,
|
|
89
|
+
GridMouseEvent,
|
|
90
|
+
GridTheme,
|
|
91
|
+
HitTestResult,
|
|
92
|
+
PartialTheme,
|
|
93
|
+
Point,
|
|
94
|
+
PositionedColumn,
|
|
95
|
+
Rectangle,
|
|
96
|
+
RenderState,
|
|
97
|
+
RowWalkCallback,
|
|
98
|
+
ScrollPosition,
|
|
99
|
+
Size,
|
|
100
|
+
VisibleRange,
|
|
101
|
+
} from './types';
|
|
102
|
+
// Walker functions
|
|
103
|
+
export {
|
|
104
|
+
calculateVisibleRange,
|
|
105
|
+
getColumnAtX,
|
|
106
|
+
getColumnIndex,
|
|
107
|
+
getPinnedWidths,
|
|
108
|
+
getPositionedColumns,
|
|
109
|
+
getRowAtY,
|
|
110
|
+
getRowY,
|
|
111
|
+
getTotalColumnWidth,
|
|
112
|
+
getVisibleRowRange,
|
|
113
|
+
isRowVisible,
|
|
114
|
+
walkCells,
|
|
115
|
+
walkColumns,
|
|
116
|
+
walkRows,
|
|
117
|
+
} from './walk';
|