feat: table cell background color
This commit is contained in:
@@ -53,6 +53,7 @@ export class Command {
|
|||||||
private static cancelMergeTableCell: CommandAdapt['cancelMergeTableCell']
|
private static cancelMergeTableCell: CommandAdapt['cancelMergeTableCell']
|
||||||
private static tableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign']
|
private static tableTdVerticalAlign: CommandAdapt['tableTdVerticalAlign']
|
||||||
private static tableBorderType: CommandAdapt['tableBorderType']
|
private static tableBorderType: CommandAdapt['tableBorderType']
|
||||||
|
private static tableTdBackgroundColor: CommandAdapt['tableTdBackgroundColor']
|
||||||
private static image: CommandAdapt['image']
|
private static image: CommandAdapt['image']
|
||||||
private static hyperlink: CommandAdapt['hyperlink']
|
private static hyperlink: CommandAdapt['hyperlink']
|
||||||
private static deleteHyperlink: CommandAdapt['deleteHyperlink']
|
private static deleteHyperlink: CommandAdapt['deleteHyperlink']
|
||||||
@@ -133,6 +134,7 @@ export class Command {
|
|||||||
Command.cancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt)
|
Command.cancelMergeTableCell = adapt.cancelMergeTableCell.bind(adapt)
|
||||||
Command.tableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt)
|
Command.tableTdVerticalAlign = adapt.tableTdVerticalAlign.bind(adapt)
|
||||||
Command.tableBorderType = adapt.tableBorderType.bind(adapt)
|
Command.tableBorderType = adapt.tableBorderType.bind(adapt)
|
||||||
|
Command.tableTdBackgroundColor = adapt.tableTdBackgroundColor.bind(adapt)
|
||||||
Command.image = adapt.image.bind(adapt)
|
Command.image = adapt.image.bind(adapt)
|
||||||
Command.hyperlink = adapt.hyperlink.bind(adapt)
|
Command.hyperlink = adapt.hyperlink.bind(adapt)
|
||||||
Command.deleteHyperlink = adapt.deleteHyperlink.bind(adapt)
|
Command.deleteHyperlink = adapt.deleteHyperlink.bind(adapt)
|
||||||
@@ -347,6 +349,10 @@ export class Command {
|
|||||||
return Command.tableBorderType(payload)
|
return Command.tableBorderType(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public executeTableTdBackgroundColor(payload: string) {
|
||||||
|
return Command.tableTdBackgroundColor(payload)
|
||||||
|
}
|
||||||
|
|
||||||
public executeHyperlink(payload: IElement) {
|
public executeHyperlink(payload: IElement) {
|
||||||
return Command.hyperlink(payload)
|
return Command.hyperlink(payload)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
public hyperlink(payload: IElement) {
|
||||||
const isReadonly = this.draw.isReadonly()
|
const isReadonly = this.draw.isReadonly()
|
||||||
if (isReadonly) return
|
if (isReadonly) return
|
||||||
|
|||||||
@@ -516,6 +516,10 @@ export class Draw {
|
|||||||
return this.tableTool
|
return this.tableTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getTableParticle(): TableParticle {
|
||||||
|
return this.tableParticle
|
||||||
|
}
|
||||||
|
|
||||||
public getHeader(): Header {
|
public getHeader(): Header {
|
||||||
return this.header
|
return this.header
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ElementType, IElement, TableBorder } from '../../../..'
|
import { ElementType, IElement, TableBorder } from '../../../..'
|
||||||
import { IEditorOption } from '../../../../interface/Editor'
|
import { IEditorOption } from '../../../../interface/Editor'
|
||||||
|
import { ITd } from '../../../../interface/table/Td'
|
||||||
import { ITr } from '../../../../interface/table/Tr'
|
import { ITr } from '../../../../interface/table/Tr'
|
||||||
import { deepClone } from '../../../../utils'
|
import { deepClone } from '../../../../utils'
|
||||||
import { RangeManager } from '../../../range/RangeManager'
|
import { RangeManager } from '../../../range/RangeManager'
|
||||||
@@ -16,10 +17,12 @@ interface IDrawTableBorderOption {
|
|||||||
|
|
||||||
export class TableParticle {
|
export class TableParticle {
|
||||||
|
|
||||||
|
private draw: Draw
|
||||||
private range: RangeManager
|
private range: RangeManager
|
||||||
private options: Required<IEditorOption>
|
private options: Required<IEditorOption>
|
||||||
|
|
||||||
constructor(draw: Draw) {
|
constructor(draw: Draw) {
|
||||||
|
this.draw = draw
|
||||||
this.range = draw.getRange()
|
this.range = draw.getRange()
|
||||||
this.options = draw.getOptions()
|
this.options = draw.getOptions()
|
||||||
}
|
}
|
||||||
@@ -41,7 +44,51 @@ export class TableParticle {
|
|||||||
return trList
|
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
|
const { ctx, startX, startY, width, height, isDrawFullBorder } = payload
|
||||||
ctx.beginPath()
|
ctx.beginPath()
|
||||||
const x = Math.round(startX)
|
const x = Math.round(startX)
|
||||||
@@ -58,6 +105,68 @@ export class TableParticle {
|
|||||||
ctx.translate(-0.5, -0.5)
|
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) {
|
public computeRowColInfo(element: IElement) {
|
||||||
const { colgroup, trList } = element
|
const { colgroup, trList } = element
|
||||||
if (!colgroup || !trList) return
|
if (!colgroup || !trList) return
|
||||||
@@ -192,44 +301,8 @@ export class TableParticle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render(ctx: CanvasRenderingContext2D, element: IElement, startX: number, startY: number) {
|
public render(ctx: CanvasRenderingContext2D, element: IElement, startX: number, startY: number) {
|
||||||
const { colgroup, trList, borderType } = element
|
this._drawBackgroundColor(ctx, element, startX, startY)
|
||||||
if (!colgroup || !trList || borderType === TableBorder.EMPTY) return
|
this._drawBorder(ctx, element, startX, startY)
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ export interface ITd {
|
|||||||
rowList?: IRow[];
|
rowList?: IRow[];
|
||||||
positionList?: IElementPosition[];
|
positionList?: IElementPosition[];
|
||||||
verticalAlign?: VerticalAlign;
|
verticalAlign?: VerticalAlign;
|
||||||
|
backgroundColor?: string;
|
||||||
mainHeight?: number; // 内容 + 内边距高度
|
mainHeight?: number; // 内容 + 内边距高度
|
||||||
realHeight?: number; // 真实高度(包含跨列)
|
realHeight?: number; // 真实高度(包含跨列)
|
||||||
realMinHeight?: number; // 真实最小高度(包含跨列)
|
realMinHeight?: number; // 真实最小高度(包含跨列)
|
||||||
|
|||||||
@@ -426,6 +426,9 @@ export function zipElementList(payload: IElement[]): IElement[] {
|
|||||||
if (td.verticalAlign) {
|
if (td.verticalAlign) {
|
||||||
zipTd.verticalAlign = td.verticalAlign
|
zipTd.verticalAlign = td.verticalAlign
|
||||||
}
|
}
|
||||||
|
if (td.backgroundColor) {
|
||||||
|
zipTd.backgroundColor = td.backgroundColor
|
||||||
|
}
|
||||||
tr.tdList[d] = zipTd
|
tr.tdList[d] = zipTd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user