From d89218a916fce5a7b7b6bf27fa4663ecc4d15cf6 Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Sun, 4 Aug 2024 21:31:00 +0800 Subject: [PATCH] feat: add line number option #734 --- docs/en/guide/option.md | 40 ++++++++++++++------- docs/guide/option.md | 14 ++++++++ src/editor/core/draw/Draw.ts | 16 ++++++++- src/editor/core/draw/frame/LineNumber.ts | 43 +++++++++++++++++++++++ src/editor/dataset/constant/LineNumber.ts | 11 ++++++ src/editor/dataset/enum/LineNumber.ts | 4 +++ src/editor/index.ts | 4 ++- src/editor/interface/Editor.ts | 2 ++ src/editor/interface/LineNumber.ts | 10 ++++++ src/editor/interface/Row.ts | 1 + src/editor/utils/option.ts | 9 ++++- 11 files changed, 138 insertions(+), 16 deletions(-) create mode 100644 src/editor/core/draw/frame/LineNumber.ts create mode 100644 src/editor/dataset/constant/LineNumber.ts create mode 100644 src/editor/dataset/enum/LineNumber.ts create mode 100644 src/editor/interface/LineNumber.ts diff --git a/docs/en/guide/option.md b/docs/en/guide/option.md index b2c6557..06bfe11 100644 --- a/docs/en/guide/option.md +++ b/docs/en/guide/option.md @@ -71,6 +71,7 @@ interface IEditorOption { background?: IBackgroundOption // Background option. {color?:string; image?:string; size?:BackgroundSize; repeat?:BackgroundRepeat; applyPageNumbers?:number[]}。default: {color: '#FFFFFF'} lineBreak?: ILineBreakOption // LineBreak option. {disabled?:boolean; color?:string; lineWidth?:number;} separator?: ISeparatorOption // Separator option. {lineWidth?:number; strokeStyle?:string;} + lineNumber?: ILineNumberOption // LineNumber option. {size?:number; font?:string; color?:string; disabled?:boolean; right?:number} } ``` @@ -109,11 +110,11 @@ interface IFooter { ```typescript interface IPageNumber { bottom?: number // The size from the bottom of the page.default: 60 - size?: number // font size.default: 12 - font?: string // font.default: Microsoft YaHei - color?: string // font color.default: #000000 - rowFlex?: RowFlex // Line alignment.default: CENTER - format?: string // Page number format.default: {pageNo}。example:{pageNo}/{pageCount} + size?: number // font size. default: 12 + font?: string // font. default: Microsoft YaHei + color?: string // font color. default: #000000 + rowFlex?: RowFlex // Line alignment. default: CENTER + format?: string // Page number format. default: {pageNo}。example:{pageNo}/{pageCount} numberType?: NumberType // The numeric type. default: ARABIC disabled?: boolean // Whether to disable startPageNo?: number // Start page number.default: 1 @@ -127,10 +128,10 @@ interface IPageNumber { ```typescript interface IWatermark { data: string // text. - color?: string // color.default: #AEB5C0 - opacity?: number // transparency.default: 0.3 - size?: number // font size.default: 200 - font?: string // font.default: Microsoft YaHei + color?: string // color. default: #AEB5C0 + opacity?: number // transparency. default: 0.3 + size?: number // font size. default: 200 + font?: string // font. default: Microsoft YaHei } ``` @@ -139,9 +140,22 @@ interface IWatermark { ```typescript interface IPlaceholder { data: string // text. - color?: string // color.default: #DCDFE6 - opacity?: number // transparency.default: 1 - size?: number // font size.default: 16 - font?: string // font.default: Microsoft YaHei + color?: string // color. default: #DCDFE6 + opacity?: number // transparency. default: 1 + size?: number // font size. default: 16 + font?: string // font. default: Microsoft YaHei +} +``` + +## LineNumber Configuration + +```typescript +interface ILineNumberOption { + size?: number // font size. default: 12 + font?: string // font. default: Microsoft YaHei + color?: string // color. default: #000000 + disabled?: boolean // Whether to disable. default: false + right?: number // Distance from the main text. default: 20 + type?: LineNumberType // Number type (renumber each page, consecutive numbering). default: continuity } ``` diff --git a/docs/guide/option.md b/docs/guide/option.md index 6ed887d..8fdc3c3 100644 --- a/docs/guide/option.md +++ b/docs/guide/option.md @@ -71,6 +71,7 @@ interface IEditorOption { background?: IBackgroundOption // 背景配置。{color?:string; image?:string; size?:BackgroundSize; repeat?:BackgroundRepeat; applyPageNumbers?:number[]}。默认:{color: '#FFFFFF'} lineBreak?: ILineBreakOption // 换行符配置。{disabled?:boolean; color?:string; lineWidth?:number;} separator?: ISeparatorOption // 分隔符配置。{lineWidth?:number; strokeStyle?:string;} + lineNumber?: ILineNumberOption // 行号配置。{size?:number; font?:string; color?:string; disabled?:boolean; right?:number} } ``` @@ -145,3 +146,16 @@ interface IPlaceholder { font?: string // 字体。默认:Microsoft YaHei } ``` + +## 行号配置 + +```typescript +interface ILineNumberOption { + size?: number // 字体大小。默认:12 + font?: string // 字体。默认:Microsoft YaHei + color?: string // 颜色。默认:#000000 + disabled?: boolean // 是否禁用。默认:true + right?: number // 距离正文距离。默认:20 + type?: LineNumberType // 编号类型(每页重新编号、连续编号)。默认:连续编号 +} +``` diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 5c1d311..d3ecd7e 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -101,6 +101,7 @@ import { ImageDisplay } from '../../dataset/enum/Common' import { PUNCTUATION_REG } from '../../dataset/constant/Regular' import { LineBreakParticle } from './particle/LineBreakParticle' import { MouseObserver } from '../observer/MouseObserver' +import { LineNumber } from './frame/LineNumber' export class Draw { private container: HTMLDivElement @@ -138,6 +139,7 @@ export class Draw { private tableParticle: TableParticle private tableTool: TableTool private pageNumber: PageNumber + private lineNumber: LineNumber private waterMark: Watermark private placeholder: Placeholder private header: Header @@ -213,6 +215,7 @@ export class Draw { this.tableParticle = new TableParticle(this) this.tableTool = new TableTool(this) this.pageNumber = new PageNumber(this) + this.lineNumber = new LineNumber(this) this.waterMark = new Watermark(this) this.placeholder = new Placeholder(this) this.header = new Header(this, data.header) @@ -549,6 +552,10 @@ export class Draw { return this.lineBreakParticle } + public getTextParticle(): TextParticle { + return this.textParticle + } + public getHeaderElementList(): IElement[] { return this.header.getElementList() } @@ -1194,6 +1201,7 @@ export class Draw { ascent: 0, elementList: [], startIndex: 0, + rowIndex: 0, rowFlex: elementList?.[0]?.rowFlex || elementList?.[1]?.rowFlex }) } @@ -1645,6 +1653,7 @@ export class Draw { startIndex: i, elementList: [rowElement], ascent, + rowIndex: curRow.rowIndex + 1, rowFlex: elementList[i]?.rowFlex || elementList[i + 1]?.rowFlex, isPageBreak: element.type === ElementType.PAGE_BREAK } @@ -2186,7 +2195,8 @@ export class Draw { private _drawPage(payload: IDrawPagePayload) { const { elementList, positionList, rowList, pageNo } = payload - const { inactiveAlpha, pageMode, header, footer, pageNumber } = this.options + const { inactiveAlpha, pageMode, header, footer, pageNumber, lineNumber } = + this.options const innerWidth = this.getInnerWidth() const ctx = this.ctxList[pageNo] // 判断当前激活区域-非正文区域时元素透明度降低 @@ -2247,6 +2257,10 @@ export class Draw { if (this.elementList.length <= 1 && !this.elementList[0]?.listId) { this.placeholder.render(ctx) } + // 渲染行数 + if (!lineNumber.disabled) { + this.lineNumber.render(ctx, pageNo) + } } private _disconnectLazyRender() { diff --git a/src/editor/core/draw/frame/LineNumber.ts b/src/editor/core/draw/frame/LineNumber.ts new file mode 100644 index 0000000..305f875 --- /dev/null +++ b/src/editor/core/draw/frame/LineNumber.ts @@ -0,0 +1,43 @@ +import { LineNumberType } from '../../../dataset/enum/LineNumber' +import { DeepRequired } from '../../../interface/Common' +import { IEditorOption } from '../../../interface/Editor' +import { Draw } from '../Draw' + +export class LineNumber { + private draw: Draw + private options: DeepRequired + + constructor(draw: Draw) { + this.draw = draw + this.options = draw.getOptions() + } + + public render(ctx: CanvasRenderingContext2D, pageNo: number) { + const { + scale, + lineNumber: { color, size, font, right, type } + } = this.options + const textParticle = this.draw.getTextParticle() + const margins = this.draw.getMargins() + const positionList = this.draw.getPosition().getOriginalMainPositionList() + const pageRowList = this.draw.getPageRowList() + const rowList = pageRowList[pageNo] + ctx.save() + ctx.fillStyle = color + ctx.font = `${size * scale}px ${font}` + for (let i = 0; i < rowList.length; i++) { + const row = rowList[i] + const { + coordinate: { leftBottom } + } = positionList[row.startIndex] + const seq = type === LineNumberType.PAGE ? i + 1 : row.rowIndex + 1 + const textMetrics = textParticle.measureText(ctx, { + value: `${seq}` + }) + const x = margins[3] - (textMetrics.width + right) * scale + const y = leftBottom[1] - textMetrics.actualBoundingBoxAscent * scale + ctx.fillText(`${seq}`, x, y) + } + ctx.restore() + } +} diff --git a/src/editor/dataset/constant/LineNumber.ts b/src/editor/dataset/constant/LineNumber.ts new file mode 100644 index 0000000..141d034 --- /dev/null +++ b/src/editor/dataset/constant/LineNumber.ts @@ -0,0 +1,11 @@ +import { ILineNumberOption } from '../../interface/LineNumber' +import { LineNumberType } from '../enum/LineNumber' + +export const defaultLineNumberOption: Readonly> = { + size: 12, + font: 'Microsoft YaHei', + color: '#000000', + disabled: true, + right: 20, + type: LineNumberType.CONTINUITY +} diff --git a/src/editor/dataset/enum/LineNumber.ts b/src/editor/dataset/enum/LineNumber.ts new file mode 100644 index 0000000..53e689b --- /dev/null +++ b/src/editor/dataset/enum/LineNumber.ts @@ -0,0 +1,4 @@ +export enum LineNumberType { + PAGE = 'page', + CONTINUITY = 'continuity' +} diff --git a/src/editor/index.ts b/src/editor/index.ts index d8dd3c0..2cb398c 100644 --- a/src/editor/index.ts +++ b/src/editor/index.ts @@ -52,6 +52,7 @@ import { deepClone, splitText } from './utils' import { BackgroundRepeat, BackgroundSize } from './dataset/enum/Background' import { TextDecorationStyle } from './dataset/enum/Text' import { mergeOption } from './utils/option' +import { LineNumberType } from './dataset/enum/LineNumber' export default class Editor { public command: Command @@ -169,7 +170,8 @@ export { ControlIndentation, BackgroundRepeat, BackgroundSize, - TextDecorationStyle + TextDecorationStyle, + LineNumberType } // 对外类型 diff --git a/src/editor/interface/Editor.ts b/src/editor/interface/Editor.ts index 0dcb176..8be2278 100644 --- a/src/editor/interface/Editor.ts +++ b/src/editor/interface/Editor.ts @@ -24,6 +24,7 @@ import { IWatermark } from './Watermark' import { IZoneOption } from './Zone' import { ISeparatorOption } from './Separator' import { ITableOption } from './table/Table' +import { ILineNumberOption } from './LineNumber' export interface IEditorData { header?: IElement[] @@ -89,6 +90,7 @@ export interface IEditorOption { background?: IBackgroundOption lineBreak?: ILineBreakOption separator?: ISeparatorOption + lineNumber?: ILineNumberOption } export interface IEditorResult { diff --git a/src/editor/interface/LineNumber.ts b/src/editor/interface/LineNumber.ts new file mode 100644 index 0000000..7b4dfe1 --- /dev/null +++ b/src/editor/interface/LineNumber.ts @@ -0,0 +1,10 @@ +import { LineNumberType } from '../dataset/enum/LineNumber' + +export interface ILineNumberOption { + size?: number + font?: string + color?: string + disabled?: boolean + right?: number + type?: LineNumberType +} diff --git a/src/editor/interface/Row.ts b/src/editor/interface/Row.ts index c8bc6f6..c77cf36 100644 --- a/src/editor/interface/Row.ts +++ b/src/editor/interface/Row.ts @@ -19,4 +19,5 @@ export interface IRow { offsetX?: number elementList: IRowElement[] isWidthNotEnough?: boolean + rowIndex: number } diff --git a/src/editor/utils/option.ts b/src/editor/utils/option.ts index 0121a20..7441fd0 100644 --- a/src/editor/utils/option.ts +++ b/src/editor/utils/option.ts @@ -16,6 +16,7 @@ import { defaultTableOption } from '../dataset/constant/Table' import { defaultTitleOption } from '../dataset/constant/Title' import { defaultWatermarkOption } from '../dataset/constant/Watermark' import { defaultZoneOption } from '../dataset/constant/Zone' +import { defaultLineNumberOption } from '../dataset/constant/LineNumber' import { IBackgroundOption } from '../interface/Background' import { ICheckboxOption } from '../interface/Checkbox' import { DeepRequired } from '../interface/Common' @@ -35,6 +36,7 @@ import { ITableOption } from '../interface/table/Table' import { ITitleOption } from '../interface/Title' import { IWatermark } from '../interface/Watermark' import { IZoneOption } from '../interface/Zone' +import { ILineNumberOption } from '../interface/LineNumber' import { EditorMode, PageMode, @@ -114,6 +116,10 @@ export function mergeOption( ...defaultSeparatorOption, ...options.separator } + const lineNumberOptions: Required = { + ...defaultLineNumberOption, + ...options.lineNumber + } return { mode: EditorMode.EDIT, @@ -173,6 +179,7 @@ export function mergeOption( zone: zoneOptions, background: backgroundOptions, lineBreak: lineBreakOptions, - separator: separatorOptions + separator: separatorOptions, + lineNumber: lineNumberOptions } }