diff --git a/src/editor/core/command/Command.ts b/src/editor/core/command/Command.ts index dddbaa5..a0a5328 100644 --- a/src/editor/core/command/Command.ts +++ b/src/editor/core/command/Command.ts @@ -53,6 +53,7 @@ export class Command { private static cancelMergeTableCell: CommandAdapt['cancelMergeTableCell'] private static tableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign'] private static tableBorderType: CommandAdapt['tableBorderType'] + private static tableTdBackgroundColor: CommandAdapt['tableTdBackgroundColor'] private static image: CommandAdapt['image'] private static hyperlink: CommandAdapt['hyperlink'] private static deleteHyperlink: CommandAdapt['deleteHyperlink'] @@ -133,6 +134,7 @@ export class Command { Command.cancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt) Command.tableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt) Command.tableBorderType = adapt.tableBorderType.bind(adapt) + Command.tableTdBackgroundColor = adapt.tableTdBackgroundColor.bind(adapt) Command.image = adapt.image.bind(adapt) Command.hyperlink = adapt.hyperlink.bind(adapt) Command.deleteHyperlink = adapt.deleteHyperlink.bind(adapt) @@ -347,6 +349,10 @@ export class Command { return Command.tableBorderType(payload) } + public executeTableTdBackgroundColor(payload: string) { + return Command.tableTdBackgroundColor(payload) + } + public executeHyperlink(payload: IElement) { return Command.hyperlink(payload) } diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts index 2094051..36da2ae 100644 --- a/src/editor/core/command/CommandAdapt.ts +++ b/src/editor/core/command/CommandAdapt.ts @@ -1151,6 +1151,25 @@ export class CommandAdapt { }) } + public tableTdBackgroundColor(payload: string) { + const isReadonly = this.draw.isReadonly() + if (isReadonly) return + const rowCol = this.draw.getTableParticle().getRangeRowCol() + if (!rowCol) return + for (let r = 0; r < rowCol.length; r++) { + const row = rowCol[r] + for (let c = 0; c < row.length; c++) { + const col = row[c] + col.backgroundColor = payload + } + } + const { endIndex } = this.range.getRange() + this.range.setRange(endIndex, endIndex) + this.draw.render({ + isCompute: false + }) + } + public hyperlink(payload: IElement) { const isReadonly = this.draw.isReadonly() if (isReadonly) return diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 06d7070..9dfe731 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -516,6 +516,10 @@ export class Draw { return this.tableTool } + public getTableParticle(): TableParticle { + return this.tableParticle + } + public getHeader(): Header { return this.header } diff --git a/src/editor/core/draw/particle/table/TableParticle.ts b/src/editor/core/draw/particle/table/TableParticle.ts index f8b78a5..20b81d2 100644 --- a/src/editor/core/draw/particle/table/TableParticle.ts +++ b/src/editor/core/draw/particle/table/TableParticle.ts @@ -1,5 +1,6 @@ import { ElementType, IElement, TableBorder } from '../../../..' import { IEditorOption } from '../../../../interface/Editor' +import { ITd } from '../../../../interface/table/Td' import { ITr } from '../../../../interface/table/Tr' import { deepClone } from '../../../../utils' import { RangeManager } from '../../../range/RangeManager' @@ -16,10 +17,12 @@ interface IDrawTableBorderOption { export class TableParticle { + private draw: Draw private range: RangeManager private options: Required constructor(draw: Draw) { + this.draw = draw this.range = draw.getRange() this.options = draw.getOptions() } @@ -41,7 +44,51 @@ export class TableParticle { return trList } - private _drawBorder(payload: IDrawTableBorderOption) { + public getRangeRowCol(): ITd[][] | null { + const { isTable, index, trIndex, tdIndex } = this.draw.getPosition().getPositionContext() + if (!isTable) return null + const { isCrossRowCol, startTdIndex, endTdIndex, startTrIndex, endTrIndex } = this.range.getRange() + const originalElementList = this.draw.getOriginalElementList() + const element = originalElementList[index!] + const curTrList = element.trList! + // 非跨列直接返回光标所在单元格 + if (!isCrossRowCol) { + return [[curTrList[trIndex!].tdList[tdIndex!]]] + } + let startTd = curTrList[startTrIndex!].tdList[startTdIndex!] + let endTd = curTrList[endTrIndex!].tdList[endTdIndex!] + // 交换起始位置 + if (startTd.x! > endTd.x! || startTd.y! > endTd.y!) { + [startTd, endTd] = [endTd, startTd] + } + const startColIndex = startTd.colIndex! + const endColIndex = endTd.colIndex! + (endTd.colspan - 1) + const startRowIndex = startTd.rowIndex! + const endRowIndex = endTd.rowIndex! + (endTd.rowspan - 1) + // 选区行列 + const rowCol: ITd[][] = [] + for (let t = 0; t < curTrList.length; t++) { + const tr = curTrList[t] + const tdList: ITd[] = [] + for (let d = 0; d < tr.tdList.length; d++) { + const td = tr.tdList[d] + const tdColIndex = td.colIndex! + const tdRowIndex = td.rowIndex! + if ( + tdColIndex >= startColIndex && tdColIndex <= endColIndex + && tdRowIndex >= startRowIndex && tdRowIndex <= endRowIndex + ) { + tdList.push(td) + } + } + if (tdList.length) { + rowCol.push(tdList) + } + } + return rowCol.length ? rowCol : null + } + + private _drawOuterBorder(payload: IDrawTableBorderOption) { const { ctx, startX, startY, width, height, isDrawFullBorder } = payload ctx.beginPath() const x = Math.round(startX) @@ -58,6 +105,68 @@ export class TableParticle { ctx.translate(-0.5, -0.5) } + private _drawBorder(ctx: CanvasRenderingContext2D, element: IElement, startX: number, startY: number) { + const { colgroup, trList, borderType } = element + if (!colgroup || !trList || borderType === TableBorder.EMPTY) return + const { scale } = this.options + const tableWidth = element.width! * scale + const tableHeight = element.height! * scale + const isExternalBorderType = borderType === TableBorder.EXTERNAL + ctx.save() + // 渲染边框 + this._drawOuterBorder({ + ctx, + startX, + startY, + width: tableWidth, + height: tableHeight, + isDrawFullBorder: isExternalBorderType + }) + if (!isExternalBorderType) { + // 渲染表格 + for (let t = 0; t < trList.length; t++) { + const tr = trList[t] + for (let d = 0; d < tr.tdList.length; d++) { + const td = tr.tdList[d] + const width = td.width! * scale + const height = td.height! * scale + const x = Math.round(td.x! * scale + startX + width) + const y = Math.round(td.y! * scale + startY) + ctx.translate(0.5, 0.5) + // 绘制线条 + ctx.beginPath() + ctx.moveTo(x, y) + ctx.lineTo(x, y + height) + ctx.lineTo(x - width, y + height) + ctx.stroke() + ctx.translate(-0.5, -0.5) + } + } + } + ctx.restore() + } + + private _drawBackgroundColor(ctx: CanvasRenderingContext2D, element: IElement, startX: number, startY: number) { + const { trList } = element + if (!trList) return + const { scale } = this.options + for (let t = 0; t < trList.length; t++) { + const tr = trList[t] + for (let d = 0; d < tr.tdList.length; d++) { + const td = tr.tdList[d] + if (!td.backgroundColor) continue + ctx.save() + const width = td.width! * scale + const height = td.height! * scale + const x = Math.round(td.x! * scale + startX) + const y = Math.round(td.y! * scale + startY) + ctx.fillStyle = td.backgroundColor + ctx.fillRect(x, y, width, height) + ctx.restore() + } + } + } + public computeRowColInfo(element: IElement) { const { colgroup, trList } = element if (!colgroup || !trList) return @@ -192,44 +301,8 @@ export class TableParticle { } public render(ctx: CanvasRenderingContext2D, element: IElement, startX: number, startY: number) { - const { colgroup, trList, borderType } = element - if (!colgroup || !trList || borderType === TableBorder.EMPTY) return - const { scale } = this.options - const tableWidth = element.width! * scale - const tableHeight = element.height! * scale - const isExternalBorderType = borderType === TableBorder.EXTERNAL - ctx.save() - // 渲染边框 - this._drawBorder({ - ctx, - startX, - startY, - width: tableWidth, - height: tableHeight, - isDrawFullBorder: isExternalBorderType - }) - if (!isExternalBorderType) { - // 渲染表格 - for (let t = 0; t < trList.length; t++) { - const tr = trList[t] - for (let d = 0; d < tr.tdList.length; d++) { - const td = tr.tdList[d] - const width = td.width! * scale - const height = td.height! * scale - const x = Math.round(td.x! * scale + startX + width) - const y = Math.round(td.y! * scale + startY) - ctx.translate(0.5, 0.5) - // 绘制线条 - ctx.beginPath() - ctx.moveTo(x, y) - ctx.lineTo(x, y + height) - ctx.lineTo(x - width, y + height) - ctx.stroke() - ctx.translate(-0.5, -0.5) - } - } - } - ctx.restore() + this._drawBackgroundColor(ctx, element, startX, startY) + this._drawBorder(ctx, element, startX, startY) } } \ No newline at end of file diff --git a/src/editor/interface/table/Td.ts b/src/editor/interface/table/Td.ts index a44df44..1e8105b 100644 --- a/src/editor/interface/table/Td.ts +++ b/src/editor/interface/table/Td.ts @@ -19,6 +19,7 @@ export interface ITd { rowList?: IRow[]; positionList?: IElementPosition[]; verticalAlign?: VerticalAlign; + backgroundColor?: string; mainHeight?: number; // 内容 + 内边距高度 realHeight?: number; // 真实高度(包含跨列) realMinHeight?: number; // 真实最小高度(包含跨列) diff --git a/src/editor/utils/element.ts b/src/editor/utils/element.ts index 28dc917..aa6e6f2 100644 --- a/src/editor/utils/element.ts +++ b/src/editor/utils/element.ts @@ -426,6 +426,9 @@ export function zipElementList(payload: IElement[]): IElement[] { if (td.verticalAlign) { zipTd.verticalAlign = td.verticalAlign } + if (td.backgroundColor) { + zipTd.backgroundColor = td.backgroundColor + } tr.tdList[d] = zipTd } }