UNPKG

@progress/kendo-angular-grid

Version:

Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.

215 lines (214 loc) 7.52 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Injectable, EventEmitter } from '@angular/core'; import { zip } from 'rxjs'; import { take } from 'rxjs/operators'; import { leafColumns } from '../columns/column-common'; import * as i0 from "@angular/core"; /** * @hidden */ const isLocked = column => column.parent ? isLocked(column.parent) : !!column.locked; /** * @hidden */ const resizeArgs = (column, extra) => Object.assign({ columns: leafColumns([column]), locked: isLocked(column) }, extra); /** * @hidden */ const measure = (col, gridEl) => { const rowIndex = col.level + 1; const selector = `tr[aria-rowindex="${rowIndex}"] > th[aria-colindex="${col.leafIndex + 1}"], tr[aria-rowindex="${rowIndex}"] > th[data-kendo-grid-column-index="${col.leafIndex}"]`; const headerCell = gridEl.querySelector(selector); if (headerCell) { const headerCellWidth = headerCell.offsetWidth; if (headerCellWidth > 0) { return headerCellWidth; } } return 0; }; /** * @hidden */ export class ColumnResizingService { changes = new EventEmitter(); adjacentColumn; areColumnsReordered = false; isShiftPressed = false; originalWidth; draggedGroupColumn; resizedColumns; autoFitResize = false; column; tables = []; batch = null; start(column) { this.trackColumns(column); const columns = (this.column.isColumnGroup ? [column] : []) .concat(leafColumns([column])); this.changes.emit({ columns: columns, locked: isLocked(this.column), type: 'start' }); } resizeColumns(deltaPercent) { const action = resizeArgs(this.column, { deltaPercent, type: 'resizeColumn' }); this.changes.emit(action); } resizeTable(column, delta) { const action = resizeArgs(column, { delta, type: 'resizeTable' }); this.changes.emit(action); } resizedColumn(state) { this.resizedColumns.push(state); } end() { this.changes.emit({ columns: [], resizedColumns: this.resizedColumns, type: 'end' }); this.restoreInitialMaxMinWidths(); this.adjacentColumn = null; this.draggedGroupColumn = null; this.autoFitResize = false; } registerTable(tableMetadata) { this.tables.push(tableMetadata); const unregisterTable = () => { this.tables.splice(this.tables.indexOf(tableMetadata), 1); }; return unregisterTable; } measureColumns(info) { if (this.batch !== null) { this.batch.push(...info); } else { this.autoFitBatch(info, () => this.end()); } } autoFit(...columns) { const nonLockedColumns = columns.filter(column => !column.isLocked); this.autoFitStart(nonLockedColumns); this.autoFitBatch(this.batch, () => { if (nonLockedColumns.length < columns.length) { const lockedColumns = columns.filter(column => column.isLocked); this.autoFitStart(lockedColumns); this.autoFitBatch(this.batch, () => this.end()); } else { this.end(); } }); } autoFitToGrid(gridEl, scrollbarWidth, ...columns) { const gridWidth = gridEl.clientWidth - scrollbarWidth - 1; if (gridWidth <= 0) { return; } const columnsWidths = columns.map(c => measure(c, gridEl)); const totalColumnsWidth = columnsWidths.reduce((sum, w) => sum + w, 0); if (totalColumnsWidth === 0 || Math.abs(totalColumnsWidth - gridWidth) <= 1) { return; } this.start(columns[0]); const calculateNewWidths = (columnsWidths) => { const totalWidth = columnsWidths.reduce((s, w) => s + w, 0); const nonZeroColumns = columnsWidths.filter(w => w > 0).length; const diff = (gridWidth - totalWidth) / nonZeroColumns; const newWidths = columnsWidths.slice(); newWidths.forEach((w, i) => { newWidths[i] = Math.max(0, w + diff); }); return newWidths; }; let newWidths = calculateNewWidths(columnsWidths); const newTotal = newWidths.reduce((s, w) => s + w, 0); if (newTotal !== gridWidth) { newWidths = calculateNewWidths(newWidths); } columns.forEach((col, idx) => { const oldWidth = columnsWidths[idx]; const newWidth = newWidths[idx]; col.width = newWidth; this.resizedColumn({ column: col, oldWidth, newWidth }); }); const totalNew = newWidths.reduce((s, w) => s + w, 0); const tableDelta = totalNew - totalColumnsWidth; if (tableDelta < 0) { this.resizeTable(columns[0], tableDelta); } this.end(); } trackColumns(column) { this.resizedColumns = []; this.column = column; } autoFitStart(columns) { this.batch = []; this.resizedColumns = []; if (columns.length === 0) { return; } const locked = columns[0].isLocked; this.changes.emit({ type: 'start', columns, locked }); this.changes.emit({ type: 'triggerAutoFit', columns, locked }); } autoFitBatch(info, onComplete) { const locked = info.length > 0 ? info[0].column.isLocked : false; const observables = this.tables .filter(table => table.locked === locked) .map(table => table.autoFit(info)); zip(...observables) .pipe(take(1)) .subscribe(widths => { this.changes.emit({ columns: info.map(i => i.column), type: 'autoFitComplete', widths, locked }); if (onComplete) { onComplete(); } }); this.batch = null; } restoreInitialMaxMinWidths() { if (this.adjacentColumn) { this.adjacentColumn.maxResizableWidth = this.adjacentColumn.initialMaxResizableWidth; this.adjacentColumn.minResizableWidth = this.adjacentColumn.initialMinResizableWidth; } if (this.column) { this.column.maxResizableWidth = this.column.initialMaxResizableWidth; this.column.minResizableWidth = this.column.initialMinResizableWidth; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ColumnResizingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ColumnResizingService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ColumnResizingService, decorators: [{ type: Injectable }] });