feat: table border tool

pr675
Hufe921 3 years ago committed by Hufe
parent f64a620b22
commit 5c529b76ca

@ -84,20 +84,20 @@
border: 1px dotted #000000; border: 1px dotted #000000;
} }
.ce-table-tool__line { .ce-table-tool__border {
position: absolute; position: absolute;
z-index: 1; z-index: 1;
background: transparent; background: transparent;
pointer-events: none; pointer-events: none;
} }
.ce-table-tool__rline__resize { .ce-table-tool__border__row {
position: absolute; position: absolute;
cursor: row-resize; cursor: row-resize;
pointer-events: auto; pointer-events: auto;
} }
.ce-table-tool__cline__resize { .ce-table-tool__border__col {
position: absolute; position: absolute;
cursor: col-resize; cursor: col-resize;
pointer-events: auto; pointer-events: auto;

@ -1319,10 +1319,10 @@ export class Draw {
} else { } else {
this._immediateRender() this._immediateRender()
} }
const positionContext = this.position.getPositionContext()
// 光标重绘 // 光标重绘
if (isSetCursor) { if (isSetCursor) {
const positionList = this.position.getPositionList() const positionList = this.position.getPositionList()
const positionContext = this.position.getPositionContext()
if (positionContext.isTable) { if (positionContext.isTable) {
const { index, trIndex, tdIndex } = positionContext const { index, trIndex, tdIndex } = positionContext
const elementList = this.getOriginalElementList() const elementList = this.getOriginalElementList()
@ -1344,7 +1344,7 @@ export class Draw {
const oldHeaderElementList = deepClone(this.header.getElementList()) const oldHeaderElementList = deepClone(this.header.getElementList())
const { startIndex, endIndex } = this.range.getRange() const { startIndex, endIndex } = this.range.getRange()
const pageNo = this.pageNo const pageNo = this.pageNo
const oldPositionContext = deepClone(this.position.getPositionContext()) const oldPositionContext = deepClone(positionContext)
const zone = this.zone.getZone() const zone = this.zone.getZone()
this.historyManager.execute(function () { this.historyManager.execute(function () {
self.zone.setZone(zone) self.zone.setZone(zone)
@ -1358,6 +1358,10 @@ export class Draw {
} }
// 信息变动回调 // 信息变动回调
nextTick(() => { nextTick(() => {
// 表格工具重新渲染
if (isCompute && !this.isReadonly() && positionContext.isTable) {
this.tableTool.render()
}
// 页面尺寸改变 // 页面尺寸改变
if (this.listener.pageSizeChange) { if (this.listener.pageSizeChange) {
this.listener.pageSizeChange(this.pageRowList.length) this.listener.pageSizeChange(this.pageRowList.length)

@ -2,7 +2,6 @@ import { IElement } from '../../../..'
import { EDITOR_PREFIX } from '../../../../dataset/constant/Editor' import { EDITOR_PREFIX } from '../../../../dataset/constant/Editor'
import { TableOrder } from '../../../../dataset/enum/table/TableTool' import { TableOrder } from '../../../../dataset/enum/table/TableTool'
import { IEditorOption } from '../../../../interface/Editor' import { IEditorOption } from '../../../../interface/Editor'
import { IElementPosition } from '../../../../interface/Element'
import { Position } from '../../../position/Position' import { Position } from '../../../position/Position'
import { Draw } from '../../Draw' import { Draw } from '../../Draw'
@ -11,13 +10,16 @@ interface IAnchorMouseDown {
order: TableOrder; order: TableOrder;
index: number; index: number;
element: IElement; element: IElement;
position: IElementPosition;
} }
export class TableTool { 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 draw: Draw
private canvas: HTMLCanvasElement private canvas: HTMLCanvasElement
@ -26,8 +28,8 @@ export class TableTool {
private container: HTMLDivElement private container: HTMLDivElement
private toolRowContainer: HTMLDivElement | null private toolRowContainer: HTMLDivElement | null
private toolColContainer: HTMLDivElement | null private toolColContainer: HTMLDivElement | null
private toolBorderContainer: HTMLDivElement | null
private anchorLine: HTMLDivElement | null private anchorLine: HTMLDivElement | null
private toolBox: HTMLDivElement | null
private mousedownX: number private mousedownX: number
private mousedownY: number private mousedownY: number
@ -40,8 +42,8 @@ export class TableTool {
// x、y轴 // x、y轴
this.toolRowContainer = null this.toolRowContainer = null
this.toolColContainer = null this.toolColContainer = null
this.toolBorderContainer = null
this.anchorLine = null this.anchorLine = null
this.toolBox = null
this.mousedownX = 0 this.mousedownX = 0
this.mousedownY = 0 this.mousedownY = 0
} }
@ -49,30 +51,43 @@ export class TableTool {
public dispose() { public dispose() {
this.toolRowContainer?.remove() this.toolRowContainer?.remove()
this.toolColContainer?.remove() this.toolColContainer?.remove()
this.toolBox?.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() this.dispose()
const { trIndex, tdIndex } = this.position.getPositionContext()
// 渲染所需数据
const { scale } = this.options const { scale } = this.options
const height = this.draw.getHeight() const elementList = this.draw.getOriginalElementList()
const pageGap = this.draw.getPageGap() const positionList = this.position.getOriginalPositionList()
const element = elementList[index!]
const position = positionList[index!]
const { colgroup, trList } = element const { colgroup, trList } = element
const { coordinate: { leftTop } } = position const { coordinate: { leftTop } } = position
const height = this.draw.getHeight()
const pageGap = this.draw.getPageGap()
const prePageHeight = this.draw.getPageNo() * (height + pageGap) const prePageHeight = this.draw.getPageNo() * (height + pageGap)
const tableX = leftTop[0]
const tableY = leftTop[1] + prePageHeight
const td = element.trList![trIndex!].tdList[tdIndex!] const td = element.trList![trIndex!].tdList[tdIndex!]
const rowIndex = td.rowIndex const rowIndex = td.rowIndex
const colIndex = td.colIndex 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') const rowContainer = document.createElement('div')
rowContainer.classList.add(`${EDITOR_PREFIX}-table-tool__row`) rowContainer.classList.add(`${EDITOR_PREFIX}-table-tool__row`)
rowContainer.style.transform = `translateX(-${this.translate * scale}px)` rowContainer.style.transform = `translateX(-${this.ROW_COL_OFFSET * scale}px)`
for (let r = 0; r < rowList.length; r++) { for (let r = 0; r < rowHeightList.length; r++) {
const rowHeight = rowList[r] * scale const rowHeight = rowHeightList[r] * scale
const rowItem = document.createElement('div') const rowItem = document.createElement('div')
rowItem.classList.add(`${EDITOR_PREFIX}-table-tool__row__item`) rowItem.classList.add(`${EDITOR_PREFIX}-table-tool__row__item`)
if (r === rowIndex) { if (r === rowIndex) {
@ -84,7 +99,6 @@ export class TableTool {
this._mousedown({ this._mousedown({
evt, evt,
element, element,
position,
index: r, index: r,
order: TableOrder.ROW order: TableOrder.ROW
}) })
@ -93,17 +107,18 @@ export class TableTool {
rowItem.style.height = `${rowHeight}px` rowItem.style.height = `${rowHeight}px`
rowContainer.append(rowItem) rowContainer.append(rowItem)
} }
rowContainer.style.left = `${leftTop[0]}px` rowContainer.style.left = `${tableX}px`
rowContainer.style.top = `${leftTop[1] + prePageHeight}px` rowContainer.style.top = `${tableY}px`
this.container.append(rowContainer) this.container.append(rowContainer)
this.toolRowContainer = rowContainer this.toolRowContainer = rowContainer
// 渲染列 // 渲染列工具
const colWidthList = colgroup!.map(col => col.width)
const colContainer = document.createElement('div') const colContainer = document.createElement('div')
colContainer.classList.add(`${EDITOR_PREFIX}-table-tool__col`) colContainer.classList.add(`${EDITOR_PREFIX}-table-tool__col`)
colContainer.style.transform = `translateY(-${this.translate * scale}px)` colContainer.style.transform = `translateY(-${this.ROW_COL_OFFSET * scale}px)`
for (let c = 0; c < colList.length; c++) { for (let c = 0; c < colWidthList.length; c++) {
const colHeight = colList[c] * scale const colWidth = colWidthList[c] * scale
const colItem = document.createElement('div') const colItem = document.createElement('div')
colItem.classList.add(`${EDITOR_PREFIX}-table-tool__col__item`) colItem.classList.add(`${EDITOR_PREFIX}-table-tool__col__item`)
if (c === colIndex) { if (c === colIndex) {
@ -115,83 +130,70 @@ export class TableTool {
this._mousedown({ this._mousedown({
evt, evt,
element, element,
position,
index: c, index: c,
order: TableOrder.COL order: TableOrder.COL
}) })
} }
colItem.append(colItemAnchor) colItem.append(colItemAnchor)
colItem.style.width = `${colHeight}px` colItem.style.width = `${colWidth}px`
colContainer.append(colItem) colContainer.append(colItem)
} }
colContainer.style.left = `${leftTop[0]}px` colContainer.style.left = `${tableX}px`
colContainer.style.top = `${leftTop[1] + prePageHeight}px` colContainer.style.top = `${tableY}px`
this.container.append(colContainer) this.container.append(colContainer)
this.toolColContainer = colContainer this.toolColContainer = colContainer
if (!trList?.length) return // 渲染单元格边框拖拽工具
const tableHeight = element.height! * scale
// 绘制边框拖拽 const tableWidth = element.width! * scale
const LINE_THRESHOLD_VALUE = 3 const borderContainer = document.createElement('div')
const tableHeight = rowList.reduce((pre, cur) => pre + cur, 0) borderContainer.classList.add(`${EDITOR_PREFIX}-table-tool__border`)
const tableWidth = colList.reduce((pre, cur) => pre + cur, 0) borderContainer.style.height = `${tableHeight}px`
borderContainer.style.width = `${tableWidth}px`
// 渲染工具外部容器 borderContainer.style.left = `${tableX}px`
const tableLineTool = document.createElement('div') borderContainer.style.top = `${tableY}px`
tableLineTool.classList.add(`${EDITOR_PREFIX}-table-tool__line`) for (let r = 0; r < trList!.length; r++) {
tableLineTool.style.height = tableHeight * scale + 'px' const tr = trList![r]
tableLineTool.style.width = tableWidth * scale + 'px' for (let d = 0; d < tr.tdList.length; d++) {
tableLineTool.style.left = `${leftTop[0]}px` const td = tr.tdList[d]
tableLineTool.style.top = `${leftTop[1] + prePageHeight}px` const rowBorder = document.createElement('div')
rowBorder.classList.add(`${EDITOR_PREFIX}-table-tool__border__row`)
for (let i = 0, len = trList.length || 0; i < len; i++) { rowBorder.style.width = `${td.width! * scale}px`
const tr = trList[i] rowBorder.style.height = `${this.BORDER_VALUE}px`
for (let j = 0; j < tr.tdList.length; j++) { rowBorder.style.top = `${(td.y! + td.height!) * scale - this.BORDER_VALUE / 2}px`
const td = tr.tdList[j] rowBorder.style.left = `${td.x! * scale}px`
const rowLine = document.createElement('div') rowBorder.onmousedown = (evt) => {
rowLine.classList.add(`${EDITOR_PREFIX}-table-tool__rline__resize`)
rowLine.dataset.rowIndex = `${td.rowIndex}`
rowLine.style.width = td.width! * scale + 'px'
rowLine.style.height = LINE_THRESHOLD_VALUE + 'px'
rowLine.style.top = td.y! * scale + td.height! * scale - LINE_THRESHOLD_VALUE / 2 + 'px'
rowLine.style.left = td.x! * scale + 'px'
rowLine.onmousedown = (evt) => {
this._mousedown({ this._mousedown({
evt, evt,
element, element,
position, index: td.rowIndex!,
index: td.rowIndex || 0,
order: TableOrder.ROW order: TableOrder.ROW
}) })
} }
tableLineTool.appendChild(rowLine) borderContainer.appendChild(rowBorder)
const colBorder = document.createElement('div')
const colLine = document.createElement('div') colBorder.classList.add(`${EDITOR_PREFIX}-table-tool__border__col`)
colLine.classList.add(`${EDITOR_PREFIX}-table-tool__cline__resize`) colBorder.style.width = `${this.BORDER_VALUE}px`
colLine.dataset.colIndex = `${td.colIndex}` colBorder.style.height = `${td.height! * scale}px`
colLine.style.height = td.height! * scale + 'px' colBorder.style.top = `${td.y! * scale}px`
colLine.style.width = LINE_THRESHOLD_VALUE + 'px' colBorder.style.left = `${(td.x! + td.width!) * scale - this.BORDER_VALUE / 2}px`
colLine.style.left = td.x! * scale + (td.width! * scale) - LINE_THRESHOLD_VALUE / 2 + 'px' colBorder.onmousedown = (evt) => {
colLine.style.top = td.y! * scale + 'px'
colLine.onmousedown = (evt) => {
this._mousedown({ this._mousedown({
evt, evt,
element, element,
position, index: td.colIndex!,
index: td.colIndex || 0,
order: TableOrder.COL order: TableOrder.COL
}) })
} }
tableLineTool.appendChild(colLine) borderContainer.appendChild(colBorder)
} }
} }
this.container.append(borderContainer)
this.toolBox = tableLineTool this.toolBorderContainer = borderContainer
this.container.append(tableLineTool)
} }
private _mousedown(payload: IAnchorMouseDown) { private _mousedown(payload: IAnchorMouseDown) {
const { evt, index, order, element, position } = payload const { evt, index, order, element } = payload
this.canvas = this.draw.getPage() this.canvas = this.draw.getPage()
const { scale } = this.options const { scale } = this.options
const width = this.draw.getWidth() const width = this.draw.getWidth()
@ -253,10 +255,10 @@ export class TableTool {
const curColWidth = colgroup[index].width const curColWidth = colgroup[index].width
// 最小移动距离计算 // 最小移动距离计算
const moveColWidth = curColWidth + dx const moveColWidth = curColWidth + dx
const nextColWidth = colgroup[index + 1]?.width const nextColWidth = colgroup[index + 1]?.width || 0
// 如果移动距离小于最小宽度,或者大于当前列和下一列宽度之和,那么就不移动 // 如果移动距离小于最小宽度,或者大于当前列和下一列宽度之和则移动最小宽度
if (moveColWidth < this.minTdWidth || moveColWidth > curColWidth + nextColWidth) { if (moveColWidth < this.MIN_TD_WIDTH || moveColWidth > curColWidth + nextColWidth) {
dx = this.minTdWidth - curColWidth dx = this.MIN_TD_WIDTH - curColWidth
} }
// 最大移动距离计算 // 最大移动距离计算
let moveTableWidth = 0 let moveTableWidth = 0
@ -290,7 +292,6 @@ export class TableTool {
} }
if (isChangeSize) { if (isChangeSize) {
this.draw.render({ isSetCursor: false }) this.draw.render({ isSetCursor: false })
this.render(element, position)
} }
// 还原副作用 // 还原副作用
anchorLine.remove() anchorLine.remove()

@ -100,9 +100,7 @@ export function mousedown(evt: MouseEvent, host: CanvasEvent) {
const tableTool = draw.getTableTool() const tableTool = draw.getTableTool()
tableTool.dispose() tableTool.dispose()
if (isTable && !isReadonly) { if (isTable && !isReadonly) {
const originalElementList = draw.getOriginalElementList() tableTool.render()
const originalPositionList = position.getOriginalPositionList()
tableTool.render(originalElementList[index], originalPositionList[index])
} }
// 超链接 // 超链接
const hyperlinkParticle = draw.getHyperlinkParticle() const hyperlinkParticle = draw.getHyperlinkParticle()

Loading…
Cancel
Save