From 4a022a2724521d842f72f679a3bc8ca2b0e244ea Mon Sep 17 00:00:00 2001 From: Hufe Date: Thu, 23 Mar 2023 18:01:32 +0800 Subject: [PATCH] fix: table tool render option --- src/editor/assets/css/table/table.css | 19 +++ src/editor/core/command/CommandAdapt.ts | 18 +-- src/editor/core/draw/Draw.ts | 8 +- .../core/draw/particle/table/TableTool.ts | 128 +++++++++++++----- src/editor/core/event/handlers/mousedown.ts | 4 +- src/editor/core/position/Position.ts | 9 +- 6 files changed, 134 insertions(+), 52 deletions(-) diff --git a/src/editor/assets/css/table/table.css b/src/editor/assets/css/table/table.css index 7b47297..a0b281e 100644 --- a/src/editor/assets/css/table/table.css +++ b/src/editor/assets/css/table/table.css @@ -82,4 +82,23 @@ z-index: 9; position: absolute; border: 1px dotted #000000; +} + +.ce-table-tool__border { + position: absolute; + z-index: 1; + background: transparent; + pointer-events: none; +} + +.ce-table-tool__border__row { + position: absolute; + cursor: row-resize; + pointer-events: auto; +} + +.ce-table-tool__border__col { + position: absolute; + cursor: col-resize; + pointer-events: auto; } \ No newline at end of file diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index 5add48e..e17161c 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -542,8 +542,7 @@ export class CommandAdapt { this.range.setRange(0, 0) // 重新渲染 this.draw.render({ curIndex: 0 }) - const position = this.position.getOriginalPositionList() - this.tableTool.render(element, position[index!]) + this.tableTool.render() } public insertTableBottomRow() { @@ -609,8 +608,7 @@ export class CommandAdapt { this.range.setRange(0, 0) // 重新渲染 this.draw.render({ curIndex: 0 }) - const position = this.position.getOriginalPositionList() - this.tableTool.render(element, position[index!]) + this.tableTool.render() } public insertTableLeftCol() { @@ -667,8 +665,7 @@ export class CommandAdapt { this.range.setRange(0, 0) // 重新渲染 this.draw.render({ curIndex: 0 }) - const position = this.position.getOriginalPositionList() - this.tableTool.render(element, position[index!]) + this.tableTool.render() } public insertTableRightCol() { @@ -725,8 +722,7 @@ export class CommandAdapt { this.range.setRange(0, 0) // 重新渲染 this.draw.render({ curIndex: 0 }) - const position = this.position.getOriginalPositionList() - this.tableTool.render(element, position[index!]) + this.tableTool.render() } public deleteTableRow() { @@ -962,8 +958,7 @@ export class CommandAdapt { const curIndex = startTd.value.length - 1 this.range.setRange(curIndex, curIndex) this.draw.render() - const position = this.position.getOriginalPositionList() - this.tableTool.render(element, position[index!]) + this.tableTool.render() } public cancelMergeTableCell() { @@ -1024,8 +1019,7 @@ export class CommandAdapt { const curIndex = curTd.value.length - 1 this.range.setRange(curIndex, curIndex) this.draw.render() - const position = this.position.getOriginalPositionList() - this.tableTool.render(element, position[index!]) + this.tableTool.render() } public tableTdVerticalAlign(payload: VerticalAlign) { diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 1b2450d..cff8c11 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -1319,10 +1319,10 @@ export class Draw { } else { this._immediateRender() } + const positionContext = this.position.getPositionContext() // 光标重绘 if (isSetCursor) { const positionList = this.position.getPositionList() - const positionContext = this.position.getPositionContext() if (positionContext.isTable) { const { index, trIndex, tdIndex } = positionContext const elementList = this.getOriginalElementList() @@ -1344,7 +1344,7 @@ export class Draw { const oldHeaderElementList = deepClone(this.header.getElementList()) const { startIndex, endIndex } = this.range.getRange() const pageNo = this.pageNo - const oldPositionContext = deepClone(this.position.getPositionContext()) + const oldPositionContext = deepClone(positionContext) const zone = this.zone.getZone() this.historyManager.execute(function () { self.zone.setZone(zone) @@ -1358,6 +1358,10 @@ export class Draw { } // 信息变动回调 nextTick(() => { + // 表格工具重新渲染 + if (isCompute && !this.isReadonly() && positionContext.isTable) { + this.tableTool.render() + } // 页面尺寸改变 if (this.listener.pageSizeChange) { this.listener.pageSizeChange(this.pageRowList.length) diff --git a/src/editor/core/draw/particle/table/TableTool.ts b/src/editor/core/draw/particle/table/TableTool.ts index 5751f0c..527d2a4 100644 --- a/src/editor/core/draw/particle/table/TableTool.ts +++ b/src/editor/core/draw/particle/table/TableTool.ts @@ -2,7 +2,6 @@ import { IElement } from '../../../..' import { EDITOR_PREFIX } from '../../../../dataset/constant/Editor' import { TableOrder } from '../../../../dataset/enum/table/TableTool' import { IEditorOption } from '../../../../interface/Editor' -import { IElementPosition } from '../../../../interface/Element' import { Position } from '../../../position/Position' import { Draw } from '../../Draw' @@ -11,13 +10,16 @@ interface IAnchorMouseDown { order: TableOrder; index: number; element: IElement; - position: IElementPosition; } export class TableTool { - private readonly translate = 18 - private minTdWidth = 20 + // 单元格最小宽度 + private readonly MIN_TD_WIDTH = 20 + // 行列工具相对表格偏移值 + private readonly ROW_COL_OFFSET = 18 + // 边框工具宽/高度 + private readonly BORDER_VALUE = 4 private draw: Draw private canvas: HTMLCanvasElement @@ -26,6 +28,7 @@ export class TableTool { private container: HTMLDivElement private toolRowContainer: HTMLDivElement | null private toolColContainer: HTMLDivElement | null + private toolBorderContainer: HTMLDivElement | null private anchorLine: HTMLDivElement | null private mousedownX: number private mousedownY: number @@ -39,6 +42,7 @@ export class TableTool { // x、y轴 this.toolRowContainer = null this.toolColContainer = null + this.toolBorderContainer = null this.anchorLine = null this.mousedownX = 0 this.mousedownY = 0 @@ -47,29 +51,43 @@ export class TableTool { public dispose() { this.toolRowContainer?.remove() this.toolColContainer?.remove() + this.toolBorderContainer?.remove() + this.toolRowContainer = null + this.toolColContainer = null + this.toolBorderContainer = null } - public render(element: IElement, position: IElementPosition) { + public render() { + const { isTable, index, trIndex, tdIndex } = this.position.getPositionContext() + if (!isTable) return + + // 销毁之前工具 this.dispose() - const { trIndex, tdIndex } = this.position.getPositionContext() + + // 渲染所需数据 const { scale } = this.options - const height = this.draw.getHeight() - const pageGap = this.draw.getPageGap() + const elementList = this.draw.getOriginalElementList() + const positionList = this.position.getOriginalPositionList() + const element = elementList[index!] + const position = positionList[index!] const { colgroup, trList } = element const { coordinate: { leftTop } } = position + const height = this.draw.getHeight() + const pageGap = this.draw.getPageGap() const prePageHeight = this.draw.getPageNo() * (height + pageGap) + const tableX = leftTop[0] + const tableY = leftTop[1] + prePageHeight const td = element.trList![trIndex!].tdList[tdIndex!] const rowIndex = td.rowIndex const colIndex = td.colIndex - // 计算表格行列信息 - const rowList = trList!.map(tr => tr.height) - const colList = colgroup!.map(col => col.width) - // 渲染行 + + // 渲染行工具 + const rowHeightList = trList!.map(tr => tr.height) const rowContainer = document.createElement('div') rowContainer.classList.add(`${EDITOR_PREFIX}-table-tool__row`) - rowContainer.style.transform = `translateX(-${this.translate * scale}px)` - for (let r = 0; r < rowList.length; r++) { - const rowHeight = rowList[r] * scale + rowContainer.style.transform = `translateX(-${this.ROW_COL_OFFSET * scale}px)` + for (let r = 0; r < rowHeightList.length; r++) { + const rowHeight = rowHeightList[r] * scale const rowItem = document.createElement('div') rowItem.classList.add(`${EDITOR_PREFIX}-table-tool__row__item`) if (r === rowIndex) { @@ -81,7 +99,6 @@ export class TableTool { this._mousedown({ evt, element, - position, index: r, order: TableOrder.ROW }) @@ -90,17 +107,18 @@ export class TableTool { rowItem.style.height = `${rowHeight}px` rowContainer.append(rowItem) } - rowContainer.style.left = `${leftTop[0]}px` - rowContainer.style.top = `${leftTop[1] + prePageHeight}px` + rowContainer.style.left = `${tableX}px` + rowContainer.style.top = `${tableY}px` this.container.append(rowContainer) this.toolRowContainer = rowContainer - // 渲染列 + // 渲染列工具 + const colWidthList = colgroup!.map(col => col.width) const colContainer = document.createElement('div') colContainer.classList.add(`${EDITOR_PREFIX}-table-tool__col`) - colContainer.style.transform = `translateY(-${this.translate * scale}px)` - for (let c = 0; c < colList.length; c++) { - const colHeight = colList[c] * scale + colContainer.style.transform = `translateY(-${this.ROW_COL_OFFSET * scale}px)` + for (let c = 0; c < colWidthList.length; c++) { + const colWidth = colWidthList[c] * scale const colItem = document.createElement('div') colItem.classList.add(`${EDITOR_PREFIX}-table-tool__col__item`) if (c === colIndex) { @@ -112,23 +130,70 @@ export class TableTool { this._mousedown({ evt, element, - position, index: c, order: TableOrder.COL }) } colItem.append(colItemAnchor) - colItem.style.width = `${colHeight}px` + colItem.style.width = `${colWidth}px` colContainer.append(colItem) } - colContainer.style.left = `${leftTop[0]}px` - colContainer.style.top = `${leftTop[1] + prePageHeight}px` + colContainer.style.left = `${tableX}px` + colContainer.style.top = `${tableY}px` this.container.append(colContainer) this.toolColContainer = colContainer + + // 渲染单元格边框拖拽工具 + const tableHeight = element.height! * scale + const tableWidth = element.width! * scale + const borderContainer = document.createElement('div') + borderContainer.classList.add(`${EDITOR_PREFIX}-table-tool__border`) + borderContainer.style.height = `${tableHeight}px` + borderContainer.style.width = `${tableWidth}px` + borderContainer.style.left = `${tableX}px` + borderContainer.style.top = `${tableY}px` + for (let r = 0; r < trList!.length; r++) { + const tr = trList![r] + for (let d = 0; d < tr.tdList.length; d++) { + const td = tr.tdList[d] + const rowBorder = document.createElement('div') + rowBorder.classList.add(`${EDITOR_PREFIX}-table-tool__border__row`) + rowBorder.style.width = `${td.width! * scale}px` + rowBorder.style.height = `${this.BORDER_VALUE}px` + rowBorder.style.top = `${(td.y! + td.height!) * scale - this.BORDER_VALUE / 2}px` + rowBorder.style.left = `${td.x! * scale}px` + rowBorder.onmousedown = (evt) => { + this._mousedown({ + evt, + element, + index: td.rowIndex!, + order: TableOrder.ROW + }) + } + borderContainer.appendChild(rowBorder) + const colBorder = document.createElement('div') + colBorder.classList.add(`${EDITOR_PREFIX}-table-tool__border__col`) + colBorder.style.width = `${this.BORDER_VALUE}px` + colBorder.style.height = `${td.height! * scale}px` + colBorder.style.top = `${td.y! * scale}px` + colBorder.style.left = `${(td.x! + td.width!) * scale - this.BORDER_VALUE / 2}px` + colBorder.onmousedown = (evt) => { + this._mousedown({ + evt, + element, + index: td.colIndex!, + order: TableOrder.COL + }) + } + borderContainer.appendChild(colBorder) + } + } + this.container.append(borderContainer) + this.toolBorderContainer = borderContainer } private _mousedown(payload: IAnchorMouseDown) { - const { evt, index, order, element, position } = payload + const { evt, index, order, element } = payload this.canvas = this.draw.getPage() const { scale } = this.options const width = this.draw.getWidth() @@ -190,8 +255,10 @@ export class TableTool { const curColWidth = colgroup[index].width // 最小移动距离计算 const moveColWidth = curColWidth + dx - if (moveColWidth < this.minTdWidth) { - dx = this.minTdWidth - curColWidth + const nextColWidth = colgroup[index + 1]?.width || 0 + // 如果移动距离小于最小宽度,或者大于当前列和下一列宽度之和则移动最小宽度 + if (moveColWidth < this.MIN_TD_WIDTH || moveColWidth > curColWidth + nextColWidth) { + dx = this.MIN_TD_WIDTH - curColWidth } // 最大移动距离计算 let moveTableWidth = 0 @@ -225,7 +292,6 @@ export class TableTool { } if (isChangeSize) { this.draw.render({ isSetCursor: false }) - this.render(element, position) } // 还原副作用 anchorLine.remove() @@ -251,4 +317,4 @@ export class TableTool { return { dx, dy } } -} \ No newline at end of file +} diff --git a/src/editor/core/event/handlers/mousedown.ts b/src/editor/core/event/handlers/mousedown.ts index fb4d196..37dd683 100644 --- a/src/editor/core/event/handlers/mousedown.ts +++ b/src/editor/core/event/handlers/mousedown.ts @@ -100,9 +100,7 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) { const tableTool = draw.getTableTool() tableTool.dispose() if (isTable && !isReadonly) { - const originalElementList = draw.getOriginalElementList() - const originalPositionList = position.getOriginalPositionList() - tableTool.render(originalElementList[index], originalPositionList[index]) + tableTool.render() } // 超链接 const hyperlinkParticle = draw.getHyperlinkParticle() diff --git a/src/editor/core/position/Position.ts b/src/editor/core/position/Position.ts index 16e830b..201695e 100644 --- a/src/editor/core/position/Position.ts +++ b/src/editor/core/position/Position.ts @@ -290,13 +290,14 @@ export class Position { let curPositionIndex = -1 // 判断是否在表格内 if (isTable) { + const { scale } = this.options const { td, tablePosition } = payload if (td && tablePosition) { const { leftTop } = tablePosition.coordinate - const tdX = td.x! + leftTop[0] - const tdY = td.y! + leftTop[1] - const tdWidth = td.width! - const tdHeight = td.height! + const tdX = td.x! * scale + leftTop[0] + const tdY = td.y! * scale + leftTop[1] + const tdWidth = td.width! * scale + const tdHeight = td.height! * scale if (!(tdX < x && x < tdX + tdWidth && tdY < y && y < tdY + tdHeight)) { return { index: curPositionIndex