import { DragDirection, IndexColumn } from '@/lib/types'; import { GroupPin, GroupSelection } from '@/lib/types/group'; import { isBetween } from '@/lib/utils/math'; import { CELL_CALCULATING, CELL_CALCULATING_BOTTOM, CELL_CALCULATING_LEFT, CELL_CALCULATING_RIGHT, CELL_CALCULATING_TOP, CELL_SELECTED, CELL_SELECTED_BOTTOM, CELL_SELECTED_LEFT, CELL_SELECTED_RIGHT, CELL_SELECTED_TOP, } from '@/lib/constants/dom-class'; import { Store } from '@/lib/store'; export class ClassCalculator { private selectionClassCache: Record; private calculatingClassCache: Record; private readonly store: Store; private readonly pin: IndexColumn['pin']; private readonly columnIndex: number; private readonly rowIndex: number; constructor(store: Store, pin: IndexColumn['pin'], columnIndex: number, rowIndex: number) { this.selectionClassCache = null; this.calculatingClassCache = null; this.store = store; this.pin = pin; this.columnIndex = columnIndex; this.rowIndex = rowIndex; } public getClass() { // 如果 selection 不在改变中,则意味着不需要额外计算使用上次的缓存即可(拖拽同理) let selectionClass: Record; let calculatingClass: Record; if (!this.store.state.selectionStatus.changing && this.selectionClassCache) { selectionClass = this.selectionClassCache; } else { selectionClass = this.calculateSelection(this.getSelectionArea()); this.selectionClassCache = selectionClass; } if (!this.store.state.dragCalculateStatus.changing && this.calculatingClassCache) { calculatingClass = this.selectionClassCache; } else { calculatingClass = this.calculateDragCalculation( this.getCalculatingArea(), this.store.state.dragCalculateStatus.direction, ); this.calculatingClassCache = calculatingClass; } return { ...selectionClass, ...calculatingClass, }; } private getCalculatingArea() { if (this.pin === GroupPin.left) { return this.store.state.dragCalculateStatus.leftArea; } if (this.pin === GroupPin.scroll) { return this.store.state.dragCalculateStatus.scrollArea; } return this.store.state.dragCalculateStatus.rightArea; } private getSelectionArea() { if (this.pin === GroupPin.left) { return this.store.state.selectionStatus.leftArea; } if (this.pin === GroupPin.scroll) { return this.store.state.selectionStatus.scrollArea; } return this.store.state.selectionStatus.rightArea; } private calculateSelection(selectionArea: GroupSelection) { return this.calculateAreaClass(selectionArea, { activeClass: CELL_SELECTED, topClass: CELL_SELECTED_TOP, bottomClass: CELL_SELECTED_BOTTOM, leftClass: CELL_SELECTED_LEFT, rightClass: CELL_SELECTED_RIGHT, }); } private calculateDragCalculation(calculatingArea: GroupSelection, direction: DragDirection) { const baseClazz = this.calculateAreaClass(calculatingArea, { activeClass: CELL_CALCULATING, topClass: CELL_CALCULATING_TOP, bottomClass: CELL_CALCULATING_BOTTOM, leftClass: CELL_CALCULATING_LEFT, rightClass: CELL_CALCULATING_RIGHT, }); const banClazz = this.calculateDragBan(direction); return { ...baseClazz, ...banClazz, }; } private calculateDragBan(direction: DragDirection) { if (direction === DragDirection.top) { return { [CELL_CALCULATING_BOTTOM]: false }; } if (direction === DragDirection.bottom) { return { [CELL_CALCULATING_TOP]: false }; } if (direction === DragDirection.left) { return { [CELL_CALCULATING_RIGHT]: false }; } return { [CELL_CALCULATING_LEFT]: false }; } private calculateAreaClass( area: GroupSelection, { activeClass, topClass, bottomClass, leftClass, rightClass, }: { activeClass: string; topClass: string; bottomClass: string; leftClass: string; rightClass: string; }, ) { if (!area || !area.hit) return null; const betweenColumn = isBetween(area.column); const betweenRow = isBetween(area.row); const isLeftLink = () => { return ( (this.pin === GroupPin.scroll && ['left', 'all'].includes(area.link)) || (this.pin === GroupPin.right && 'scroll' === area.link) ); }; const isRightLink = () => (this.pin === GroupPin.scroll && ['right', 'all'].includes(area.link)) || (this.pin === GroupPin.left && 'scroll' === area.link); return { [activeClass]: betweenColumn(this.columnIndex) && betweenRow(this.rowIndex), [topClass]: area.row[0] === this.rowIndex, [bottomClass]: area.row[1] === this.rowIndex, [leftClass]: !isLeftLink() && area.column[0] === this.columnIndex, [rightClass]: !isRightLink() && area.column[1] === this.columnIndex, }; } }