feat: add radio and checkbox vertical align setting
Co-authored-by: Hufe921 <huangyunfeihufe@hotmail.com>
This commit is contained in:
@@ -60,8 +60,8 @@ interface IEditorOption {
|
|||||||
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
|
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;}
|
watermark?: IWatermark // Watermark{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
||||||
control?: IControlOption // Control {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: 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; strokeStyle?: string;}
|
checkbox?: ICheckboxOption // Checkbox {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
radio?: IRadioOption // Radio {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string;}
|
radio?: IRadioOption // Radio {width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
cursor?: ICursorOption // Cursor style. {width?: number; color?: string; dragWidth?: number; dragColor?: 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;}
|
title?: ITitleOption // Title configuration.{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
||||||
placeholder?: IPlaceholder // Placeholder text
|
placeholder?: IPlaceholder // Placeholder text
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ interface IEditorOption {
|
|||||||
wordBreak?: WordBreak // 单词与标点断行:BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认:BREAK_WORD
|
wordBreak?: WordBreak // 单词与标点断行:BREAK_WORD首行不出现标点&单词不拆分、BREAK_ALL按字符宽度撑满后折行。默认:BREAK_WORD
|
||||||
watermark?: IWatermark // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
watermark?: IWatermark // 水印信息。{data:string; color?:string; opacity?:number; size?:number; font?:string;}
|
||||||
control?: IControlOption // 控件信息。 {placeholderColor?:string; bracketColor?:string; prefix?:string; postfix?:string; borderWidth?: number; borderColor?: 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; strokeStyle?: string;}
|
checkbox?: ICheckboxOption // 复选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
radio?: IRadioOption // 单选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string;}
|
radio?: IRadioOption // 单选框信息。{width?:number; height?:number; gap?:number; lineWidth?:number; fillStyle?:string; strokeStyle?: string; verticalAlign?: VerticalAlign;}
|
||||||
cursor?: ICursorOption // 光标样式。{width?: number; color?: string; dragWidth?: number; dragColor?: 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;}
|
title?: ITitleOption // 标题配置。{ defaultFirstSize?: number; defaultSecondSize?: number; defaultThirdSize?: number defaultFourthSize?: number; defaultFifthSize?: number; defaultSixthSize?: number;}
|
||||||
placeholder?: IPlaceholder // 编辑器空白占位文本
|
placeholder?: IPlaceholder // 编辑器空白占位文本
|
||||||
|
|||||||
@@ -1912,13 +1912,25 @@ export class Draw {
|
|||||||
element.controlComponent === ControlComponent.CHECKBOX
|
element.controlComponent === ControlComponent.CHECKBOX
|
||||||
) {
|
) {
|
||||||
this.textParticle.complete()
|
this.textParticle.complete()
|
||||||
this.checkboxParticle.render(ctx, element, x, y + offsetY)
|
this.checkboxParticle.render({
|
||||||
|
ctx,
|
||||||
|
x,
|
||||||
|
y: y + offsetY,
|
||||||
|
index: j,
|
||||||
|
row: curRow
|
||||||
|
})
|
||||||
} else if (
|
} else if (
|
||||||
element.type === ElementType.RADIO ||
|
element.type === ElementType.RADIO ||
|
||||||
element.controlComponent === ControlComponent.RADIO
|
element.controlComponent === ControlComponent.RADIO
|
||||||
) {
|
) {
|
||||||
this.textParticle.complete()
|
this.textParticle.complete()
|
||||||
this.radioParticle.render(ctx, element, x, y + offsetY)
|
this.radioParticle.render({
|
||||||
|
ctx,
|
||||||
|
x,
|
||||||
|
y: y + offsetY,
|
||||||
|
index: j,
|
||||||
|
row: curRow
|
||||||
|
})
|
||||||
} else if (element.type === ElementType.TAB) {
|
} else if (element.type === ElementType.TAB) {
|
||||||
this.textParticle.complete()
|
this.textParticle.complete()
|
||||||
} else if (
|
} else if (
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
|
import { NBSP, ZERO } from '../../../dataset/constant/Common'
|
||||||
|
import { VerticalAlign } from '../../../dataset/enum/VerticalAlign'
|
||||||
import { DeepRequired } from '../../../interface/Common'
|
import { DeepRequired } from '../../../interface/Common'
|
||||||
import { IEditorOption } from '../../../interface/Editor'
|
import { IEditorOption } from '../../../interface/Editor'
|
||||||
import { IElement } from '../../../interface/Element'
|
import { IElement } from '../../../interface/Element'
|
||||||
import { IRowElement } from '../../../interface/Row'
|
import { IRow, IRowElement } from '../../../interface/Row'
|
||||||
import { Draw } from '../Draw'
|
import { Draw } from '../Draw'
|
||||||
|
|
||||||
|
interface ICheckboxRenderOption {
|
||||||
|
ctx: CanvasRenderingContext2D
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
row: IRow
|
||||||
|
index: number
|
||||||
|
}
|
||||||
|
|
||||||
export class CheckboxParticle {
|
export class CheckboxParticle {
|
||||||
private draw: Draw
|
private draw: Draw
|
||||||
private options: DeepRequired<IEditorOption>
|
private options: DeepRequired<IEditorOption>
|
||||||
@@ -28,17 +38,41 @@ export class CheckboxParticle {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(
|
public render(payload: ICheckboxRenderOption) {
|
||||||
ctx: CanvasRenderingContext2D,
|
const { ctx, x, index, row } = payload
|
||||||
element: IRowElement,
|
let { y } = payload
|
||||||
x: number,
|
|
||||||
y: number
|
|
||||||
) {
|
|
||||||
const {
|
const {
|
||||||
checkbox: { gap, lineWidth, fillStyle, strokeStyle },
|
checkbox: { gap, lineWidth, fillStyle, strokeStyle, verticalAlign },
|
||||||
scale
|
scale
|
||||||
} = this.options
|
} = this.options
|
||||||
const { metrics, checkbox } = element
|
const { metrics, checkbox } = row.elementList[index]
|
||||||
|
// 垂直布局设置
|
||||||
|
if (
|
||||||
|
verticalAlign === VerticalAlign.TOP ||
|
||||||
|
verticalAlign === VerticalAlign.MIDDLE
|
||||||
|
) {
|
||||||
|
let nextIndex = index + 1
|
||||||
|
let nextElement: IRowElement | null = null
|
||||||
|
while (nextIndex < row.elementList.length) {
|
||||||
|
nextElement = row.elementList[nextIndex]
|
||||||
|
if (nextElement.value !== ZERO && nextElement.value !== NBSP) break
|
||||||
|
nextIndex++
|
||||||
|
}
|
||||||
|
// 以后一个非空格元素为基准
|
||||||
|
if (nextElement) {
|
||||||
|
const {
|
||||||
|
metrics: { boundingBoxAscent, boundingBoxDescent }
|
||||||
|
} = nextElement
|
||||||
|
const textHeight = boundingBoxAscent + boundingBoxDescent
|
||||||
|
if (textHeight > metrics.height) {
|
||||||
|
if (verticalAlign === VerticalAlign.TOP) {
|
||||||
|
y -= boundingBoxAscent - metrics.height
|
||||||
|
} else if (verticalAlign === VerticalAlign.MIDDLE) {
|
||||||
|
y -= (textHeight - metrics.height) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// left top 四舍五入避免1像素问题
|
// left top 四舍五入避免1像素问题
|
||||||
const left = Math.round(x + gap * scale)
|
const left = Math.round(x + gap * scale)
|
||||||
const top = Math.round(y - metrics.height + lineWidth)
|
const top = Math.round(y - metrics.height + lineWidth)
|
||||||
|
|||||||
@@ -199,9 +199,16 @@ export class ListParticle {
|
|||||||
height: height * scale
|
height: height * scale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.draw
|
this.draw.getCheckboxParticle().render({
|
||||||
.getCheckboxParticle()
|
ctx,
|
||||||
.render(ctx, checkboxRowElement, x - gap * scale, y)
|
x: x - gap * scale,
|
||||||
|
y,
|
||||||
|
index: 0,
|
||||||
|
row: {
|
||||||
|
...row,
|
||||||
|
elementList: [checkboxRowElement, ...row.elementList]
|
||||||
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
let text = ''
|
let text = ''
|
||||||
if (startElement.listType === ListType.UL) {
|
if (startElement.listType === ListType.UL) {
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
|
import { NBSP, ZERO } from '../../../dataset/constant/Common'
|
||||||
|
import { VerticalAlign } from '../../../dataset/enum/VerticalAlign'
|
||||||
import { DeepRequired } from '../../../interface/Common'
|
import { DeepRequired } from '../../../interface/Common'
|
||||||
import { IEditorOption } from '../../../interface/Editor'
|
import { IEditorOption } from '../../../interface/Editor'
|
||||||
import { IElement } from '../../../interface/Element'
|
import { IElement } from '../../../interface/Element'
|
||||||
import { IRowElement } from '../../../interface/Row'
|
import { IRow, IRowElement } from '../../../interface/Row'
|
||||||
import { Draw } from '../Draw'
|
import { Draw } from '../Draw'
|
||||||
|
|
||||||
|
interface IRadioRenderOption {
|
||||||
|
ctx: CanvasRenderingContext2D
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
row: IRow
|
||||||
|
index: number
|
||||||
|
}
|
||||||
|
|
||||||
export class RadioParticle {
|
export class RadioParticle {
|
||||||
private draw: Draw
|
private draw: Draw
|
||||||
private options: DeepRequired<IEditorOption>
|
private options: DeepRequired<IEditorOption>
|
||||||
@@ -28,17 +38,41 @@ export class RadioParticle {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(
|
public render(payload: IRadioRenderOption) {
|
||||||
ctx: CanvasRenderingContext2D,
|
const { ctx, x, index, row } = payload
|
||||||
element: IRowElement,
|
let { y } = payload
|
||||||
x: number,
|
|
||||||
y: number
|
|
||||||
) {
|
|
||||||
const {
|
const {
|
||||||
radio: { gap, lineWidth, fillStyle, strokeStyle },
|
radio: { gap, lineWidth, fillStyle, strokeStyle, verticalAlign },
|
||||||
scale
|
scale
|
||||||
} = this.options
|
} = this.options
|
||||||
const { metrics, radio } = element
|
const { metrics, radio } = row.elementList[index]
|
||||||
|
// 垂直布局设置
|
||||||
|
if (
|
||||||
|
verticalAlign === VerticalAlign.TOP ||
|
||||||
|
verticalAlign === VerticalAlign.MIDDLE
|
||||||
|
) {
|
||||||
|
let nextIndex = index + 1
|
||||||
|
let nextElement: IRowElement | null = null
|
||||||
|
while (nextIndex < row.elementList.length) {
|
||||||
|
nextElement = row.elementList[nextIndex]
|
||||||
|
if (nextElement.value !== ZERO && nextElement.value !== NBSP) break
|
||||||
|
nextIndex++
|
||||||
|
}
|
||||||
|
// 以后一个非空格元素为基准
|
||||||
|
if (nextElement) {
|
||||||
|
const {
|
||||||
|
metrics: { boundingBoxAscent, boundingBoxDescent }
|
||||||
|
} = nextElement
|
||||||
|
const textHeight = boundingBoxAscent + boundingBoxDescent
|
||||||
|
if (textHeight > metrics.height) {
|
||||||
|
if (verticalAlign === VerticalAlign.TOP) {
|
||||||
|
y -= boundingBoxAscent - metrics.height
|
||||||
|
} else if (verticalAlign === VerticalAlign.MIDDLE) {
|
||||||
|
y -= (textHeight - metrics.height) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// left top 四舍五入避免1像素问题
|
// left top 四舍五入避免1像素问题
|
||||||
const left = Math.round(x + gap * scale)
|
const left = Math.round(x + gap * scale)
|
||||||
const top = Math.round(y - metrics.height + lineWidth)
|
const top = Math.round(y - metrics.height + lineWidth)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ICheckboxOption } from '../../interface/Checkbox'
|
import { ICheckboxOption } from '../../interface/Checkbox'
|
||||||
|
import { VerticalAlign } from '../enum/VerticalAlign'
|
||||||
|
|
||||||
export const defaultCheckboxOption: Readonly<Required<ICheckboxOption>> = {
|
export const defaultCheckboxOption: Readonly<Required<ICheckboxOption>> = {
|
||||||
width: 14,
|
width: 14,
|
||||||
@@ -6,5 +7,6 @@ export const defaultCheckboxOption: Readonly<Required<ICheckboxOption>> = {
|
|||||||
gap: 5,
|
gap: 5,
|
||||||
lineWidth: 1,
|
lineWidth: 1,
|
||||||
fillStyle: '#5175f4',
|
fillStyle: '#5175f4',
|
||||||
strokeStyle: '#ffffff'
|
strokeStyle: '#ffffff',
|
||||||
|
verticalAlign: VerticalAlign.BOTTOM
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { IRadioOption } from '../../interface/Radio'
|
import { IRadioOption } from '../../interface/Radio'
|
||||||
|
import { VerticalAlign } from '../enum/VerticalAlign'
|
||||||
|
|
||||||
export const defaultRadioOption: Readonly<Required<IRadioOption>> = {
|
export const defaultRadioOption: Readonly<Required<IRadioOption>> = {
|
||||||
width: 14,
|
width: 14,
|
||||||
@@ -6,5 +7,6 @@ export const defaultRadioOption: Readonly<Required<IRadioOption>> = {
|
|||||||
gap: 5,
|
gap: 5,
|
||||||
lineWidth: 1,
|
lineWidth: 1,
|
||||||
fillStyle: '#5175f4',
|
fillStyle: '#5175f4',
|
||||||
strokeStyle: '#000000'
|
strokeStyle: '#000000',
|
||||||
|
verticalAlign: VerticalAlign.BOTTOM
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { VerticalAlign } from '../dataset/enum/VerticalAlign'
|
||||||
|
|
||||||
export interface ICheckbox {
|
export interface ICheckbox {
|
||||||
value: boolean | null
|
value: boolean | null
|
||||||
code?: string
|
code?: string
|
||||||
@@ -11,4 +13,5 @@ export interface ICheckboxOption {
|
|||||||
lineWidth?: number
|
lineWidth?: number
|
||||||
fillStyle?: string
|
fillStyle?: string
|
||||||
strokeStyle?: string
|
strokeStyle?: string
|
||||||
|
verticalAlign?: VerticalAlign
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { VerticalAlign } from '../dataset/enum/VerticalAlign'
|
||||||
|
|
||||||
export interface IRadio {
|
export interface IRadio {
|
||||||
value: boolean | null
|
value: boolean | null
|
||||||
code?: string
|
code?: string
|
||||||
@@ -11,4 +13,5 @@ export interface IRadioOption {
|
|||||||
lineWidth?: number
|
lineWidth?: number
|
||||||
fillStyle?: string
|
fillStyle?: string
|
||||||
strokeStyle?: string
|
strokeStyle?: string
|
||||||
|
verticalAlign?: VerticalAlign
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user