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.
554 lines • 17.9 kB
JavaScript
import Database from './Database';
import History from './History';
import EventBrowser from './EventBrowser';
import EventBus from './EventBus';
import Paint from './Paint';
import Config from './Config';
import Icons from './Icons';
import EventTable from './EventTable';
export default class Context {
constructor(containerOptions, options) {
Object.defineProperty(this, "eventBus", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "eventBrowser", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "eventTable", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "containerElement", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "stageElement", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "canvasElement", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "overlayerElement", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "editorElement", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "emptyElement", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "contextMenuElement", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "stageWidth", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "stageHeight", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "paint", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "icons", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "isInsideTargetContainer", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "mousedown", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "isPointer", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "rowResizing", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 行调整大小中
Object.defineProperty(this, "columnResizing", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 列调整大小中
Object.defineProperty(this, "scrollerMove", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 滚动条移动中
Object.defineProperty(this, "scrollerFocus", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 滚动条focus中
Object.defineProperty(this, "autofillMove", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 自动填充移动中
Object.defineProperty(this, "selectorMove", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 选择器移动中
Object.defineProperty(this, "adjustPositioning", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 调整位置中
Object.defineProperty(this, "editing", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 编辑中
Object.defineProperty(this, "onlyMergeCell", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 只有合并单元格
Object.defineProperty(this, "selectOnlyOne", {
enumerable: true,
configurable: true,
writable: true,
value: false
}); // 只选择一个
Object.defineProperty(this, "scrollY", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "scrollX", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "fixedLeftWidth", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "fixedRightWidth", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "maxColIndex", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "maxRowIndex", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "hoverRow", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "clickCell", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "focusCell", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "hoverCell", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "clickCellHeader", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "focusCellHeader", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "hoverCellHeader", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "body", {
enumerable: true,
configurable: true,
writable: true,
value: {
x: 0,
y: 0,
width: 0,
height: 0,
visibleHeight: 0,
visibleWidth: 0,
headIndex: 0,
tailIndex: 0,
visibleRows: [],
renderRows: [],
data: [],
}
});
Object.defineProperty(this, "footer", {
enumerable: true,
configurable: true,
writable: true,
value: {
x: 0,
y: 0,
width: 0,
height: 0,
visibleHeight: 0,
visibleWidth: 0,
renderRows: [],
}
});
Object.defineProperty(this, "header", {
enumerable: true,
configurable: true,
writable: true,
value: {
x: 0,
y: 0,
width: 0,
height: 0,
visibleHeight: 0,
visibleWidth: 0,
visibleLeafColumns: [],
leafCellHeaders: [],
renderLeafCellHeaders: [],
renderCellHeaders: [],
fixedLeftCellHeaders: [],
fixedRightCellHeaders: [],
renderCenterCellHeaders: [],
}
});
Object.defineProperty(this, "selector", {
enumerable: true,
configurable: true,
writable: true,
value: {
enable: false,
xArr: [-1, -1],
yArr: [-1, -1],
xArrCopy: [-1, -1],
yArrCopy: [-1, -1],
}
});
Object.defineProperty(this, "autofill", {
enumerable: true,
configurable: true,
writable: true,
value: {
enable: false,
xArr: [-1, -1],
yArr: [-1, -1],
}
});
Object.defineProperty(this, "database", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "history", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "config", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
const { containerElement, stageElement, canvasElement, overlayerElement, editorElement, emptyElement, contextMenuElement, } = containerOptions;
this.containerElement = containerElement;
stageElement.tabIndex = 0; // 设置为可获取焦点
this.stageElement = stageElement;
this.canvasElement = canvasElement;
this.overlayerElement = overlayerElement;
this.editorElement = editorElement;
this.emptyElement = emptyElement;
this.contextMenuElement = contextMenuElement;
this.config = new Config(options.config || {});
this.eventBus = new EventBus();
this.eventBrowser = new EventBrowser(this);
this.eventTable = new EventTable(this);
this.paint = new Paint(this.canvasElement);
this.database = new Database(this, options);
this.history = new History(this);
this.icons = new Icons(this);
}
setConfig(config) {
this.config = new Config(config);
}
setItemValueByEditor(rowKey, key, value, history = true, reDraw = true) {
// 启用合并单元格关联
if (this.config.ENABLE_MERGE_CELL_LINK) {
const rowIndex = this.database.getRowIndexForRowKey(rowKey);
const colIndex = this.database.getColIndexForKey(key);
if (rowIndex === undefined || colIndex === undefined)
return;
const cell = this.database.getVirtualBodyCell(rowIndex, colIndex);
if (cell) {
const { dataList } = cell.getSpanInfo();
const data = dataList.map((item) => ({ ...item, value }));
this.database.batchSetItemValue(data, history);
}
}
else {
this.database.setItemValue(rowKey, key, value, history, reDraw, true);
}
}
batchSetItemValueByEditor(_list, history) {
// 启用合并单元格关联
if (this.config.ENABLE_MERGE_CELL_LINK) {
const list = [];
_list.forEach((item) => {
const rowIndex = this.database.getRowIndexForRowKey(item.rowKey);
const colIndex = this.database.getColIndexForKey(item.key);
if (rowIndex === undefined || colIndex === undefined)
return;
const cell = this.database.getVirtualBodyCell(rowIndex, colIndex);
if (cell) {
const { dataList } = cell.getSpanInfo();
const data = dataList.map((list) => ({ ...list, value: item.value }));
list.push(...data);
}
});
// 去重
// const uniqueData = list.reduce((acc, curr) => {
// // 检查组合的 rowKey 和 key 是否已存在
// const exists = acc.some((item) => item.rowKey === curr.rowKey && item.key === curr.key);
// if (!exists) {
// acc.push(curr); // 如果不存在,则添加到结果数组中
// }
// return acc;
// }, [] as typeof list);
this.database.batchSetItemValue(list, history);
}
else {
this.database.batchSetItemValue(_list, history);
}
}
setFocusCell(cell) {
if (this.focusCell === cell)
return;
if (this.focusCell?.rowKey !== cell.rowKey) {
// 提前设置一下,保证rowFocusChange事件,能用focusCell
this.focusCell = cell;
this.emit('rowFocusChange', cell);
}
this.focusCell = cell;
this.emit('cellFocusChange', cell);
}
clearSelector() {
this.selector = {
enable: false,
xArr: [-1, -1],
yArr: [-1, -1],
xArrCopy: [-1, -1],
yArrCopy: [-1, -1],
};
}
clearAutofill() {
this.autofill = {
enable: false,
xArr: [-1, -1],
yArr: [-1, -1],
};
}
/**
* 获取选中的数据
* @returns
*/
getSelectedData() {
const rowsData = [];
const yArr = this.selector.yArr;
const xArr = this.selector.xArr;
let text = '';
for (let ri = 0; ri <= yArr[1] - yArr[0]; ri++) {
const cellsData = [];
for (let ci = 0; ci <= xArr[1] - xArr[0]; ci++) {
const rowIndex = ri + yArr[0];
const colIndex = ci + xArr[0];
const item = this.database.getItemValueForRowIndexAndColIndex(rowIndex, colIndex);
if (item) {
cellsData.push(item.value);
}
}
text += `${cellsData.join('\t')}\r`;
rowsData.push(cellsData);
}
text = text ? text.replace(/\r$/, '') : ' '; // 去掉最后一个\n,否则会导致复制到excel里多一行空白
return {
xArr,
yArr,
text,
value: rowsData,
};
}
setScroll(x, y) {
let scrollX = Math.floor(x);
const scrollMaxX = this.body.width - this.body.visibleWidth;
// x边界处理
if (scrollX < 0) {
scrollX = 0;
}
else if (scrollX > scrollMaxX) {
scrollX = scrollMaxX;
}
// y边界处理
let scrollY = Math.floor(y);
let scrollMaxY = this.body.height - this.body.visibleHeight;
if (!this.config.FOOTER_FIXED) {
scrollMaxY = this.body.height + this.footer.height - this.body.visibleHeight;
}
if (scrollY < 0) {
scrollY = 0;
}
else if (scrollY > scrollMaxY) {
scrollY = scrollMaxY;
}
this.emit('setScroll', scrollX, scrollY);
}
setScrollX(x) {
let scrollX = Math.floor(x);
const scrollMaxX = this.body.width - this.body.visibleWidth;
// 边界处理
if (scrollX < 0) {
scrollX = 0;
}
else if (scrollX > scrollMaxX) {
scrollX = scrollMaxX;
}
this.emit('setScrollX', scrollX);
}
setScrollY(y) {
// 边界处理
let scrollY = Math.floor(y);
let footerHeight = 0;
if (!this.config.FOOTER_FIXED) {
footerHeight = this.footer.height;
}
const scrollMaxY = this.body.height - this.body.visibleHeight + footerHeight;
if (scrollY < 0) {
scrollY = 0;
}
else if (scrollY > scrollMaxY) {
scrollY = scrollMaxY;
}
this.emit('setScrollY', scrollY);
}
isTarget() {
// 鼠标在容器内
return this.isInsideTargetContainer;
}
getOffset(e) {
const { left, top } = this.containerElement.getBoundingClientRect();
return {
offsetX: e.clientX - left,
offsetY: e.clientY - top,
};
}
hasEvent(event) {
return this.eventBus.has(event);
}
on(event, callback) {
this.eventBus.on(event, callback);
}
once(event, callback) {
this.eventBus.once(event, callback);
}
off(event, callback) {
this.eventBus.off(event, callback);
}
emit(event, ...args) {
this.eventBus.emit(event, ...args);
}
destroy() {
this.eventTable.destroy();
this.eventBrowser.destroy();
this.eventBus.destroy();
}
}
//# sourceMappingURL=Context.js.map