diff --git a/docs/en/guide/option.md b/docs/en/guide/option.md index a11904e..845d617 100644 --- a/docs/en/guide/option.md +++ b/docs/en/guide/option.md @@ -60,7 +60,7 @@ interface IEditorOption { scrollContainerSelector?: string // scroll container selector. default: document wordBreak?: WordBreak // Word and punctuation breaks: No punctuation in the first line of the BREAK_WORD &The word is not split, and the line is folded after BREAK_ALL full according to the width of the character. default: BREAK_WORD watermark?: IWatermark // Watermark{data:string; color?:string; opacity?:number; size?:number; font?:string;} - control?: IControlOption // Control {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string;} + control?: IControlOption // Control {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string;} checkbox?: ICheckboxOption // Checkbox {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; fontStyle?: string;} cursor?: ICursorOption // Cursor style. {width?: number; color?: string; dragWidth?: number; dragColor?: string;} title?: ITitleOption // Title configuration.{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;} diff --git a/docs/en/guide/schema.md b/docs/en/guide/schema.md index 3871784..af32558 100644 --- a/docs/en/guide/schema.md +++ b/docs/en/guide/schema.md @@ -84,6 +84,7 @@ interface IElement { postfix?: string; minWidth?: number; underline?: boolean; + border?: boolean; extension?: unknown; indentation?: ControlIndentation; deletable?: boolean; diff --git a/docs/guide/option.md b/docs/guide/option.md index ea17b3b..449075d 100644 --- a/docs/guide/option.md +++ b/docs/guide/option.md @@ -60,7 +60,7 @@ interface IEditorOption { scrollContainerSelector?: string // 滚动区域选择器。默认:document wordBreak?: WordBreak // 单词与标点断行:BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认:BREAK_WORD watermark?: IWatermark // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;} - control?: IControlOption // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string;} + control?: IControlOption // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: string;} checkbox?: ICheckboxOption // 复选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; fontStyle?: string;} cursor?: ICursorOption // 光标样式。{width?: number; color?: string; dragWidth?: number; dragColor?: string;} title?: ITitleOption // 标题配置。{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;} diff --git a/docs/guide/schema.md b/docs/guide/schema.md index 88cfe3b..c533eb0 100644 --- a/docs/guide/schema.md +++ b/docs/guide/schema.md @@ -84,6 +84,7 @@ interface IElement { postfix?: string; minWidth?: number; underline?: boolean; + border?: boolean; extension?: unknown; indentation?: ControlIndentation; deletable?: boolean; diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 959c1e8..2a007bd 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -1096,6 +1096,14 @@ export class Draw { return el.actualSize || el.size || this.options.defaultSize } + public getElementRowMargin(el: IElement) { + const { defaultBasicRowMarginHeight, defaultRowMargin, scale } = + this.options + return ( + defaultBasicRowMarginHeight * (el.rowMargin || defaultRowMargin) * scale + ) + } + public computeRowList(payload: IComputeRowListPayload) { const { innerWidth, elementList, isPagingMode = false } = payload const { defaultSize, defaultRowMargin, scale, tdPadding, defaultTabWidth } = @@ -1695,13 +1703,7 @@ export class Draw { const { rowList, pageNo, elementList, positionList, startIndex, zone } = payload const isPrintMode = this.mode === EditorMode.PRINT - const { - scale, - tdPadding, - defaultBasicRowMarginHeight, - defaultRowMargin, - group - } = this.options + const { scale, tdPadding, group } = this.options const { isCrossRowCol, tableId } = this.range.getRange() let index = startIndex for (let i = 0; i < rowList.length; i++) { @@ -1803,6 +1805,26 @@ export class Draw { this.textParticle.complete() } } + // 边框绘制(目前仅支持控件) + if (element.control?.border) { + // 不同控件边框立刻绘制 + if ( + preElement?.control?.border && + preElement.controlId !== element.controlId + ) { + this.control.drawBorder(ctx) + } + // 当前元素位置信息记录 + const rowMargin = this.getElementRowMargin(element) + this.control.recordBorderInfo( + x, + y + rowMargin, + element.metrics.width, + curRow.height - 2 * rowMargin + ) + } else if (preElement?.control?.border) { + this.control.drawBorder(ctx) + } // 下划线记录 if (element.underline || element.control?.underline) { // 上下标元素下划线单独绘制 @@ -1815,10 +1837,7 @@ export class Draw { this.underline.render(ctx) } // 行间距 - const rowMargin = - defaultBasicRowMarginHeight * - (element.rowMargin || defaultRowMargin) * - scale + const rowMargin = this.getElementRowMargin(element) // 元素向左偏移量 const offsetX = element.left || 0 // 上下标元素y轴偏移值 @@ -1954,8 +1973,9 @@ export class Draw { positionList[curRow.startIndex] ) } - // 绘制文字、下划线、删除线 + // 绘制文字、边框、下划线、删除线 this.textParticle.complete() + this.control.drawBorder(ctx) this.underline.render(ctx) this.strikeout.render(ctx) // 绘制批注样式 diff --git a/src/editor/core/draw/control/Control.ts b/src/editor/core/draw/control/Control.ts index 1da5020..c2818d0 100644 --- a/src/editor/core/draw/control/Control.ts +++ b/src/editor/core/draw/control/Control.ts @@ -33,6 +33,7 @@ import { RangeManager } from '../../range/RangeManager' import { Draw } from '../Draw' import { CheckboxControl } from './checkbox/CheckboxControl' import { ControlSearch } from './interactive/ControlSearch' +import { ControlBorder } from './richtext/Border' import { SelectControl } from './select/SelectControl' import { TextControl } from './text/TextControl' @@ -41,6 +42,7 @@ interface IMoveCursorResult { newElement: IElement } export class Control { + private controlBorder: ControlBorder private draw: Draw private range: RangeManager private listener: Listener @@ -51,6 +53,8 @@ export class Control { private activeControl: IControlInstance | null constructor(draw: Draw) { + this.controlBorder = new ControlBorder(draw) + this.draw = draw this.range = draw.getRange() this.listener = draw.getListener() @@ -760,4 +764,12 @@ export class Control { } return zipElementList(controlElementList) } + + public recordBorderInfo(x: number, y: number, width: number, height: number) { + this.controlBorder.recordBorderInfo(x, y, width, height) + } + + public drawBorder(ctx: CanvasRenderingContext2D) { + this.controlBorder.render(ctx) + } } diff --git a/src/editor/core/draw/control/richtext/Border.ts b/src/editor/core/draw/control/richtext/Border.ts new file mode 100644 index 0000000..934a822 --- /dev/null +++ b/src/editor/core/draw/control/richtext/Border.ts @@ -0,0 +1,52 @@ +import { DeepRequired } from '../../../../interface/Common' +import { IEditorOption } from '../../../../interface/Editor' +import { IElementFillRect } from '../../../../interface/Element' +import { Draw } from '../../Draw' + +export class ControlBorder { + protected borderRect: IElementFillRect + private options: DeepRequired + + constructor(draw: Draw) { + this.borderRect = this.clearBorderInfo() + this.options = draw.getOptions() + } + + public clearBorderInfo() { + this.borderRect = { + x: 0, + y: 0, + width: 0, + height: 0 + } + return this.borderRect + } + + public recordBorderInfo(x: number, y: number, width: number, height: number) { + const isFirstRecord = !this.borderRect.width + if (isFirstRecord) { + this.borderRect.x = x + this.borderRect.y = y + this.borderRect.height = height + } + this.borderRect.width += width + } + + public render(ctx: CanvasRenderingContext2D) { + if (!this.borderRect.width) return + const { + scale, + control: { borderWidth, borderColor } + } = this.options + const { x, y, width, height } = this.borderRect + ctx.save() + ctx.translate(0, 1 * scale) + ctx.lineWidth = borderWidth * scale + ctx.strokeStyle = borderColor + ctx.beginPath() + ctx.rect(x, y, width, height) + ctx.stroke() + ctx.restore() + this.clearBorderInfo() + } +} diff --git a/src/editor/dataset/constant/Control.ts b/src/editor/dataset/constant/Control.ts index da24297..48e407c 100644 --- a/src/editor/dataset/constant/Control.ts +++ b/src/editor/dataset/constant/Control.ts @@ -4,5 +4,7 @@ export const defaultControlOption: Readonly> = { placeholderColor: '#9c9b9b', bracketColor: '#000000', prefix: '{', - postfix: '}' + postfix: '}', + borderWidth: 1, + borderColor: '#000000' } diff --git a/src/editor/interface/Control.ts b/src/editor/interface/Control.ts index afdfd7b..60d1e5b 100644 --- a/src/editor/interface/Control.ts +++ b/src/editor/interface/Control.ts @@ -47,6 +47,7 @@ export interface IControlBasic { postfix?: string minWidth?: number underline?: boolean + border?: boolean extension?: unknown indentation?: ControlIndentation } @@ -61,6 +62,8 @@ export interface IControlOption { bracketColor?: string prefix?: string postfix?: string + borderWidth?: number + borderColor?: string } export interface IControlInitOption {