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.
349 lines • 13.7 kB
JavaScript
import Cell from './Cell';
import CellHeader from './CellHeader';
export default class EventTable {
constructor(ctx) {
Object.defineProperty(this, "ctx", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "visibleHoverCell", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "resizeObserver", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.ctx = ctx;
this.init();
}
init() {
// 监听窗口大小变化
this.resizeObserver = new ResizeObserver(() => {
this.ctx.emit('resetHeader');
this.ctx.emit('resizeObserver');
});
this.resizeObserver.observe(this.ctx.containerElement);
// 按下事件
this.ctx.on('mousedown', (e) => {
// 左边点击
if (e.button !== 0) {
return;
}
// 是否忙碌,进行其他操作
if (this.isBusy(e)) {
return;
}
const { offsetY, offsetX } = this.ctx.getOffset(e);
const y = offsetY;
const x = offsetX;
this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => {
this.ctx.focusCellHeader = cell;
this.ctx.emit('cellHeaderMousedown', cell, e);
});
this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => {
this.ctx.setFocusCell(cell);
this.ctx.emit('cellMousedown', cell, e);
});
});
this.ctx.on('click', (e) => {
// 左边点击
if (e.button !== 0) {
return;
}
// 是否忙碌,进行其他操作
if (this.isBusy(e)) {
return;
}
const y = this.ctx.getOffset(e).offsetY;
const x = this.ctx.getOffset(e).offsetX;
this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => {
this.ctx.clickCellHeader = cell;
this.ctx.emit('cellHeaderClick', cell, e);
// selection事件
this.selectionClick(cell);
});
this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => {
this.ctx.clickCell = cell;
this.ctx.emit('cellClick', cell, e);
// selection事件
this.selectionClick(cell);
// 树事件
this.treeClick(cell);
});
});
this.ctx.on('dblclick', (e) => {
// 左边点击
if (e.button !== 0) {
return;
}
// 是否忙碌,进行其他操作
if (this.isBusy(e)) {
return;
}
const y = this.ctx.getOffset(e).offsetY;
const x = this.ctx.getOffset(e).offsetX;
this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => {
this.ctx.emit('cellHeaderDblclick', cell, e);
});
this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => {
this.ctx.clickCell = cell;
this.ctx.emit('cellDblclick', cell, e);
});
});
this.ctx.on('contextMenu', (e) => {
if (this.isBusy(e)) {
return;
}
const { offsetY, offsetX } = this.ctx.getOffset(e);
const y = offsetY;
const x = offsetX;
this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => {
this.ctx.emit('cellHeaderContextMenuClick', cell, e);
});
this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => {
this.ctx.emit('cellContextMenuClick', cell, e);
});
});
this.ctx.on('mousemove', (e) => {
// 是否忙碌,进行其他操作
if (this.isBusy(e)) {
return;
}
const y = this.ctx.getOffset(e).offsetY;
const x = this.ctx.getOffset(e).offsetX;
this.handleHeaderEvent(x, y, this.ctx.header.renderCellHeaders, (cell) => {
this.ctx.emit('cellHeaderMouseenter', cell, e);
// 移出事件
if (this.ctx.hoverCellHeader && this.ctx.hoverCellHeader !== cell) {
this.ctx.emit('cellHeaderMouseleave', this.ctx.hoverCellHeader, e);
}
// selection头部事件
this.imageEnterAndLeave(cell, e);
if (this.ctx.hoverCellHeader === cell) {
return;
}
this.ctx.hoverCellHeader = cell;
this.ctx.emit('cellHeaderHoverChange', cell);
});
// 可视区
this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => {
// selection移入移除事件
this.imageEnterAndLeave(cell, e);
// this.ctx.emit("visibleCellHoverChange", cell, e);
if (this.visibleHoverCell !== cell) {
this.ctx.emit('visibleCellMouseleave', cell, e);
this.visibleHoverCell = cell;
this.ctx.emit('visibleCellHoverChange', cell, e);
}
}, true);
// 正常
this.handleBodyEvent(x, y, this.ctx.body.renderRows, (cell) => {
this.ctx.emit('cellMouseenter', cell, e);
// 移出事件
if (this.ctx.hoverCell && this.ctx.hoverCell !== cell) {
this.ctx.emit('cellMouseleave', this.ctx.hoverCell, e);
}
if (this.ctx.hoverCell === cell)
return;
if (this.ctx.hoverCell?.rowKey !== cell.rowKey) {
this.ctx.hoverCell = cell;
this.ctx.hoverRow = this.ctx.body.renderRows.find((item) => item.rowKey === cell.rowKey);
this.ctx.emit('rowHoverChange', this.ctx.hoverRow, cell, e);
this.ctx.emit('drawView');
}
this.ctx.hoverCell = cell;
this.ctx.emit('cellHoverChange', cell, e);
});
});
}
/**
*选中点击
* @param cell
*/
selectionClick(cell) {
// 鼠标移动到图标上会变成pointer,所以这里判断是否是pointer就能判断出是图标点击的
const isSelection = ['selection', 'index-selection'].includes(cell.type) && this.ctx.isPointer;
if (!isSelection) {
return;
}
// 点击头部
if (cell instanceof CellHeader) {
if (cell.drawImageName === 'checkbox-uncheck' || cell.drawImageName === 'checkbox-indeterminate') {
this.ctx.database.toggleAllSelection();
}
else if (cell.drawImageName === 'checkbox-check') {
this.ctx.database.clearSelection();
}
}
else {
// 点击body
// 是否可点击
const selectable = this.ctx.database.getRowSelectable(cell.rowKey);
if (!selectable) {
return;
}
this.ctx.database.toggleRowSelection(cell.rowKey);
}
}
/**
* 树点击
* @param cell
*/
treeClick(cell) {
// 鼠标移动到图标上会变成pointer,所以这里判断是否是pointer就能判断出是图标点击的
if (cell.type === 'tree' && this.ctx.isPointer) {
const row = this.ctx.database.getRowForRowKey(cell.rowKey);
const { expand = false, expandLazy = false } = row || {};
const { EXPAND_LAZY, EXPAND_LAZY_METHOD } = this.ctx.config;
// 懒加载且有懒加载方法,不是展开的不是已经加载过的
if (EXPAND_LAZY && EXPAND_LAZY_METHOD && !expand && !expandLazy) {
if (typeof EXPAND_LAZY_METHOD === 'function') {
this.ctx.database.expandLoading(cell.rowKey, true);
const expandLazyMethod = EXPAND_LAZY_METHOD;
expandLazyMethod({
row: cell.row,
rowIndex: cell.rowIndex,
colIndex: cell.colIndex,
column: cell.column,
value: cell.getValue(),
})
.then((res) => {
this.ctx.database.setExpandChildren(cell.rowKey, res);
this.ctx.database.expandLoading(cell.rowKey, false);
this.ctx.emit('expandChange', this.ctx.database.getExpandRowKeys());
})
.catch((err) => {
this.ctx.database.expandLoading(cell.rowKey, false);
console.error(err);
});
}
// 懒加载
}
else {
const isExpand = this.ctx.database.getIsExpand(cell.rowKey);
this.ctx.database.expandItem(cell.rowKey, !isExpand);
this.ctx.emit('expandChange', this.ctx.database.getExpandRowKeys());
}
}
}
/**
* 图标进入和离开事件,包括选中,展开,提示图标等
* @param cell
* @param e
*/
imageEnterAndLeave(cell, e) {
const { offsetY, offsetX } = this.ctx.getOffset(e);
const y = offsetY;
const x = offsetX;
if (x > cell.drawImageX &&
x < cell.drawImageX + cell.drawImageWidth &&
y > cell.drawImageY &&
y < cell.drawImageY + cell.drawImageHeight) {
this.ctx.stageElement.style.cursor = 'pointer';
this.ctx.isPointer = true;
// body cell 选中图标
if (cell instanceof Cell && ['selection', 'index-selection'].includes(cell.type)) {
// body cell 需要处理是否可选
const selectable = this.ctx.database.getRowSelectable(cell.rowKey);
if (!selectable) {
this.ctx.stageElement.style.cursor = 'not-allowed';
}
}
}
else {
this.ctx.isPointer = false;
if (this.ctx.stageElement.style.cursor === 'pointer') {
this.ctx.stageElement.style.cursor = 'default';
}
}
}
isBusy(e) {
const { offsetY, offsetX } = this.ctx.getOffset(e);
const y = offsetY;
const x = offsetX;
if (!this.ctx.isTarget(e)) {
return true;
}
// 行调整大小中不处理
if (this.ctx.stageElement.style.cursor === 'row-resize') {
return true;
}
// 列调整大小中不处理
if (this.ctx.stageElement.style.cursor === 'col-resize') {
return true;
}
// 列调整大小中不处理
if (this.ctx.columnResizing) {
return true;
}
// 行调整大小中不处理
if (this.ctx.rowResizing) {
return true;
}
const { SCROLLER_TRACK_SIZE } = this.ctx.config;
// 滚动条移动不处理
if (this.ctx.scrollerMove) {
return true;
}
// 滚动条悬浮不处理
if (this.ctx.scrollerFocus) {
return true;
}
// 点击滚动条不处理
if (y > this.ctx.stageHeight - SCROLLER_TRACK_SIZE) {
return true;
}
// 点击滚动条不处理
if (x > this.ctx.stageWidth - SCROLLER_TRACK_SIZE) {
return true;
}
return false;
}
handleBodyEvent(x, y, renderRows, callback, visible = false) {
if (!this.isInsideBody(y)) {
return;
}
for (const row of renderRows) {
// 优先处理固定列
const cells = row.fixedCells.concat(row.noFixedCells);
for (const cell of cells) {
const drawX = cell.getDrawX();
const drawY = cell.getDrawY();
if (visible) {
if (x > drawX && x < drawX + cell.visibleWidth && y > drawY && y < drawY + cell.visibleHeight) {
callback(cell);
return; // 找到后直接返回
}
}
else if (x > drawX && x < drawX + cell.width && y > drawY && y < drawY + cell.height) {
callback(cell);
return; // 找到后直接返回
}
}
}
}
handleHeaderEvent(x, y, renderCellHeaders, callback) {
for (const cell of renderCellHeaders) {
const drawX = cell.getDrawX();
const drawY = cell.getDrawY();
if (x > drawX && x < drawX + cell.width && y > drawY && y < drawY + cell.height) {
callback(cell);
return; // 找到后直接返回
}
}
}
isInsideBody(y) {
return y > this.ctx.body.y && y < this.ctx.body.y + this.ctx.body.visibleHeight;
}
destroy() {
this.resizeObserver.unobserve(this.ctx.stageElement);
}
}
//# sourceMappingURL=EventTable.js.map