UNPKG

e-virt-table

Version:

A powerful data table based on canvas. You can use it as data grid、Microsoft Excel or Google sheets. It supports virtual scroll、cell edit etc.

544 lines 18.7 kB
import Context from './Context'; import Scroller from './Scroller'; import Header from './Header'; import Body from './Body'; import Footer from './Footer'; import Selector from './Selector'; import Autofill from './Autofill'; import Tooltip from './Tooltip'; import Editor from './Editor'; import Empty from './Empty'; import Overlayer from './Overlayer'; import ContextMenu from './ContextMenu'; import { mergeColCell, mergeRowCell, getSpanArrByRow, getSpanObjByColumn } from './util'; import './style.css'; import Loading from './Loading'; import { FinderBar } from './FinderBar'; export default class EVirtTable { constructor(target, options) { Object.defineProperty(this, "options", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "scroller", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "header", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "body", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "footer", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "selector", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "autofill", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "tooltip", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "editor", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "empty", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "overlayer", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "contextMenu", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "loading", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "finderBar", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "animationFrameId", { enumerable: true, configurable: true, writable: true, value: undefined }); Object.defineProperty(this, "animationFrameId2", { enumerable: true, configurable: true, writable: true, value: undefined }); Object.defineProperty(this, "ctx", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.options = options; const { overlayerElement, editorElement, emptyElement, contextMenuElement } = this.options; const containerElement = this.createContainer(target, overlayerElement, editorElement, emptyElement, contextMenuElement); this.ctx = new Context(containerElement, this.options); this.header = new Header(this.ctx); this.footer = new Footer(this.ctx); this.body = new Body(this.ctx); this.scroller = new Scroller(this.ctx); this.selector = new Selector(this.ctx); this.autofill = new Autofill(this.ctx); this.tooltip = new Tooltip(this.ctx); this.empty = new Empty(this.ctx); this.editor = new Editor(this.ctx); this.overlayer = new Overlayer(this.ctx); this.contextMenu = new ContextMenu(this.ctx); this.loading = new Loading(this.ctx); this.finderBar = new FinderBar(this.ctx); this.ctx.on('draw', () => { this.draw(); }); this.ctx.on('drawView', () => { this.draw(true); }); this.draw(); } createContainer(containerElement, _overlayerElement, _editorElement, _emptyElement, _contextMenuElement) { containerElement.className = 'e-virt-table-container'; const stageElement = document.createElement('div'); const canvasElement = document.createElement('canvas'); const overlayerElement = _overlayerElement || document.createElement('div'); stageElement.className = 'e-virt-table-stage'; containerElement.tabIndex = 0; canvasElement.className = 'e-virt-table-canvas'; overlayerElement.className = 'e-virt-table-overlayer'; overlayerElement.setAttribute('data-overlayer', _overlayerElement ? 'custom' : 'default'); const editorElement = _editorElement || document.createElement('div'); editorElement.className = 'e-virt-table-editor'; const emptyElement = _emptyElement; const contextMenuElement = _contextMenuElement; stageElement.appendChild(canvasElement); stageElement.appendChild(overlayerElement); containerElement.appendChild(stageElement); return { containerElement, stageElement, canvasElement, overlayerElement, editorElement, emptyElement, contextMenuElement, }; } draw(ignoreOverlayer = false) { if (this.animationFrameId) { cancelAnimationFrame(this.animationFrameId); } this.animationFrameId = requestAnimationFrame(() => { this.header.update(); this.footer.update(); this.body.update(); this.ctx.paint.clear(); this.body.draw(); this.footer.draw(); this.header.draw(); this.scroller.draw(); // 忽略重绘覆盖层,解决按下事件时,重绘覆盖层导致事件无法触发,目前只在Selector中按下事件使用 if (!ignoreOverlayer) { this.overlayer.draw(); } // 更新自动高度放在第二帧,避免影响绘制性能 if (this.animationFrameId2) { cancelAnimationFrame(this.animationFrameId2); } this.animationFrameId2 = requestAnimationFrame(() => { this.body.updateAutoHeight(); }); }); } loadConfig(_config) { this.ctx.config.init(_config); //重新加载config,初始化表格,但是默认不清除用户操作 this.ctx.database.init(false); this.header.init(); this.ctx.emit('draw'); } loadColumns(columns) { // 先关闭编辑 this.editor.doneEdit(); this.ctx.database.setColumns(columns); this.header.init(); this.ctx.emit('draw'); } loadData(data) { // 先关闭编辑 this.editor.doneEdit(); this.ctx.database.setData(data); this.header.init(); this.tooltip.hide(); this.ctx.emit('draw'); } loadFooterData(data) { this.ctx.database.setFooterData(data); this.ctx.emit('draw'); } setCustomHeader(customHeader, ignoreEmit = true) { this.ctx.database.setCustomHeader(customHeader, ignoreEmit); this.header.init(); this.ctx.emit('draw'); } getCustomHeader() { return this.header.getCustomHeader(); } setLoading(loading) { this.ctx.loading = loading; if (loading) { this.loading.show(); } else { this.loading.hide(); } } on(event, callback) { this.ctx.on(event, callback); } emit(event, ...args) { this.ctx.emit(event, ...args); } off(event, callback) { this.ctx.off(event, callback); } filterMethod(func) { this.ctx.database.setFilterMethod(func); //重新初始化表格,但是默认不清除用户操作 this.ctx.database.init(false); this.header.init(); this.ctx.emit('draw'); } editCell(rowIndex, colIndex) { this.editor.editCell(rowIndex, colIndex); } setItemValue(rowKey, key, value, history = true, reDraw = true, isEditor = false) { this.ctx.database.setItemValue(rowKey, key, value, history, reDraw, isEditor); } batchSetItemValue(list, history = true) { this.ctx.database.batchSetItemValue(list, history); } setItemValueByEditor(rowKey, key, value, history = true, reDraw = true) { this.ctx.setItemValueByEditor(rowKey, key, value, history, reDraw); this.editor.doneEdit(); } clearEditableData(value = null) { const xArr = [0, this.ctx.maxColIndex]; const yArr = [0, this.ctx.maxRowIndex]; return this.selector.clearSelectedData(xArr, yArr, false, value); } clearEditor() { this.editor.clearEditor(); } doLayout() { this.ctx.emit('draw'); } getChangedData() { return this.ctx.database.getChangedData(); } getChangedRows() { return this.ctx.database.getChangedRows(); } setCurrentRowByRowIndex(rowIndex) { this.ctx.currentCell = this.ctx.database.getVirtualBodyCell(rowIndex, 0); this.ctx.emit('draw'); } setCurrentRow(rowKey) { const column = this.ctx.database.getColumnByColIndex(0); if (!column) { return; } this.ctx.currentCell = this.ctx.database.getVirtualBodyCellByKey(rowKey, column.key); this.ctx.emit('draw'); } getCurrentRow() { const cell = this.ctx.currentCell; if (!cell) { return; } const rowData = { row: cell.row, rowIndex: cell.rowIndex, rowKey: cell.rowKey, }; return rowData; } clearValidate() { this.ctx.database.clearValidate(); this.ctx.emit('draw'); } validateFields(ValidateFields, scrollError = true) { return new Promise(async (resolve, reject) => { let errors = []; for (let i = 0; i < ValidateFields.length; i++) { const { rowKey, key } = ValidateFields[i]; const _errors = await this.ctx.database.getValidator(rowKey, key); if (Array.isArray(_errors) && _errors.length) { errors.push(_errors); } } if (errors.length) { reject(errors); if (scrollError) { const [err] = errors; if (Array.isArray(err) && err.length) { const [_err] = err; const { rowKey, key } = _err; this.scrollToRowkey(rowKey); this.scrollToColkey(key); } } this.ctx.emit('draw'); } else { resolve([]); this.ctx.emit('draw'); } }); } async validate(scrollError = true) { // 先关闭编辑 return new Promise(async (resolve, reject) => { try { const res = await this.getValidations(); resolve(res); } catch (errors) { // 滚动到错误位置,取第一个错误 if (scrollError && Array.isArray(errors) && errors.length) { const [err] = errors; if (Array.isArray(err) && err.length) { const [_err] = err; const { rowKey, key } = _err; const targetRow = this.ctx.database.getRowForRowKey(rowKey); if (targetRow) { const { parentRowKeys = [] } = targetRow; if (parentRowKeys && parentRowKeys.length) { this.setExpandRowKeys(parentRowKeys, true); } } this.scrollToRowkey(rowKey); this.scrollToColkey(key); } } reject(errors); } }); } setValidations(errors) { errors.forEach((item) => { const { rowIndex, key, message, rowKey } = item; if (rowIndex !== undefined && rowKey === undefined) { const _rowKey = this.ctx.database.getRowKeyForRowIndex(rowIndex); this.ctx.database.setValidationErrorByRowKey(_rowKey, key, message); } if (rowKey) { this.ctx.database.setValidationErrorByRowKey(rowKey, key, message); } }); // 滚动到错误位置,取第一个错误 if (errors && Array.isArray(errors) && errors.length) { const [err] = errors; if (err && err.rowKey) { this.scrollToRowkey(err.rowKey); this.scrollToColkey(err.key); } else if (err && err.rowIndex !== undefined && err.rowIndex >= 0 && err.key) { const { rowIndex, key } = err; this.scrollToRowIndex(rowIndex); this.scrollToColkey(key); } } } getValidations() { return new Promise(async (resolve, reject) => { const data = this.ctx.database.getAllRowsData(); const leafCellHeaders = this.ctx.header.leafCellHeaders; let errors = []; for (let i = 0; i < data.length; i++) { for (let y = 0; y < leafCellHeaders.length; y++) { const rowKey = this.ctx.database.getRowKeyByItem(data[i]); const leafCellHeader = leafCellHeaders[y]; const key = leafCellHeader.key; const _errors = await this.ctx.database.getValidator(rowKey, key); if (Array.isArray(_errors) && _errors.length) { errors.push(_errors); } } } if (errors.length) { reject(errors); this.ctx.emit('draw'); } else { resolve([]); this.ctx.emit('draw'); } }); } hasValidationError() { return this.ctx.database.hasValidationError(); } scrollTo(x, y) { this.scroller.setScroll(x, y); } scrollXTo(x) { this.scroller.setScrollX(x); } scrollToColkey(key) { this.scroller.scrollToColkey(key); } scrollToRowkey(key) { this.scroller.scrollToRowKey(key); } scrollToColIndex(colIndex) { this.scroller.scrollToColIndex(colIndex); } scrollToRowIndex(rowIndex) { this.scroller.scrollToRowIndex(rowIndex); } scrollYTo(y) { this.scroller.setScrollY(y); } setExpandRowKeys(keys, expand = true) { this.ctx.database.setExpandRowKeys(keys, expand); } getExpandRowKeys() { return this.ctx.database.getExpandRowKeys(); } clearSelection() { this.ctx.database.clearSelection(); this.ctx.emit('draw'); } toggleRowSelection(row) { const rowKey = this.ctx.database.getRowKeyByItem(row); this.ctx.database.toggleRowSelection(rowKey); this.ctx.emit('draw'); } setSelectionByRows(rows, selected = true) { rows.forEach((row) => { const rowKey = this.ctx.database.getRowKeyByItem(row); this.ctx.database.setRowSelection(rowKey, selected, false); }); this.ctx.emit('selectionChange', this.getSelectionRows()); this.ctx.emit('draw'); } setSelectionByRowKeys(keys, selected = true) { keys.forEach((key) => { this.ctx.database.setRowSelection(key, selected, false); }); this.ctx.emit('selectionChange', this.getSelectionRows()); this.ctx.emit('draw'); } toggleAllSelection() { this.ctx.database.toggleAllSelection(); this.ctx.emit('draw'); } toggleRowExpand(rowKey, expand) { this.ctx.database.expandItem(rowKey, expand); this.ctx.emit('draw'); } toggleExpandAll(expand) { this.ctx.database.expandAll(expand); this.ctx.emit('draw'); } getSelectionRows() { return this.ctx.database.getSelectionRows(); } getPositionForRowIndex(rowIndex) { return this.ctx.database.getPositionForRowIndex(rowIndex); } getCellValue(rowKey, key) { return this.ctx.database.getItemValue(rowKey, key); } getCellValueByIndex(rowIndex, colIndex) { return this.ctx.database.getItemValueForRowIndexAndColIndex(rowIndex, colIndex); } clearSort() { this.ctx.database.clearSort(); } clearMaxRowHeight() { this.ctx.database.clearMaxRowHeight(); } contextMenuHide() { this.contextMenu.hide(); } getUtils() { return { mergeColCell, mergeRowCell, getSpanArrByRow, getSpanObjByColumn, }; } getColumnByKey(key) { return this.ctx.database.getColumnByKey(key)?.column; } clearChangeData() { this.ctx.database.clearChangeData(); this.ctx.emit('draw'); } /** * 销毁 */ destroy() { this.overlayer.destroy(); this.empty.destroy(); this.editor.destroy(); this.tooltip.destroy(); this.selector.destroy(); this.autofill.destroy(); this.contextMenu.destroy(); this.loading.destroy(); this.finderBar.destroy(); this.ctx.destroy(); this.ctx.containerElement.remove(); } } //# sourceMappingURL=EVirtTable.js.map