@leafer-ui/display
Version:
552 lines (340 loc) • 14.5 kB
text/typescript
import { ILeaferCanvas, IPathDrawer, IPathCommandData, IHitType, INumber, IBoolean, IString, IPathString, IExportFileType, IPointData, ICursorType, IMaskType, IEraserType, IValue, IWindingRule, IPathCreator, IFourNumber, IBoundsData, IFlowType, IGap, IFlowWrap, IAxis, IConstraint, IAutoBoxData, IFlowBoxType, IPointGap, IFlowAlign, IFlowAxisAlign, IFindCondition, IAutoSize, IRangeSize, IAlign, IUnitPointData, IObject, IScaleData, IUnitData, IPathCommandObject, ITransition, IFilter, ILeaferImage, IScaleFixed, IDragBoundsType } from '@leafer/interface'
import { Leaf, PathDrawer, surfaceType, dimType, dataType, positionType, scrollType, boundsType, pathType, scaleType, rotationType, opacityType, visibleType, sortType, maskType, dataProcessor, registerUI, useModule, rewrite, rewriteAble, UICreator, PathCorner, hitType, strokeType, PathConvert, eraserType, cursorType, autoLayoutType, pen, naturalBoundsType, pathInputType, MathHelper, Plugin, DataHelper, affectRenderBoundsType, isString, isNumber } from '@leafer/core'
import { IUI, IShadowEffect, IBlurEffect, IStrokeAlign, IStrokeJoin, IStrokeCap, IBlendMode, IDashPatternString, IShadowString, IGrayscaleEffect, IUIData, IGroup, IStrokeWidthString, ICornerRadiusString, IUIInputData, IExportOptions, IExportResult, IFill, IStroke, IArrowStyle, IFindUIMethod, ILeafer, IEditorConfig, IEditorConfigFunction, IEditToolFunction, IKeyframe, IAnimation, IAnimate, IStates, IStateName, IAnimateType, IStateStyle, IColorString, IAnimateList } from '@leafer-ui/interface'
import { effectType, zoomLayerType } from '@leafer-ui/decorator'
import { UIData } from '@leafer-ui/data'
import { UIBounds, UIRender } from '@leafer-ui/display-module'
import { Export, Paint, PathArrow } from '@leafer-ui/external'
export class UI<TInputData = IUIInputData> extends Leaf<TInputData> implements IUI { // tip: rewrited Box
declare public __: IUIData
declare public proxyData?: IUIInputData // need rewrite getter
declare public __proxyData?: IUIInputData
public get app(): ILeafer { return this.leafer && this.leafer.app }
declare public leafer?: ILeafer
declare public parent?: IGroup
public zoomLayer: IGroup
public get isFrame(): boolean { return false }
declare public children?: IUI[]
// ---
// id
public id?: IString
public name?: IString
public className?: IString
// layer
public blendMode?: IBlendMode
public opacity?: INumber
public visible?: IBoolean | 0
public locked?: IBoolean
// @leafer-in/bright will rewrite
public dim?: IBoolean | INumber // 是否弱化内容,可设置具体透明度
public dimskip?: IBoolean // 跳过弱化,突出显示内容,不受dim影响
public bright?: IBoolean // 突出显示内容,并置顶渲染,不受dim影响
public zIndex?: INumber
public mask?: IBoolean | IMaskType
public eraser?: IBoolean | IEraserType
// position
public x?: INumber
public y?: INumber
// size
public width?: INumber
public height?: INumber
// scale
public scaleX?: INumber
public scaleY?: INumber
// rotate
public rotation?: INumber
// skew
public skewX?: INumber
public skewY?: INumber
// offset
public offsetX?: INumber
public offsetY?: INumber
// scroll
public scrollX?: INumber
public scrollY?: INumber
// center
public origin?: IAlign | IUnitPointData
public around?: IAlign | IUnitPointData
// image
public lazy?: IBoolean // load image / compute paint
public pixelRatio?: INumber
public renderSpread?: IFourNumber // 强行扩大渲染边界
// path
public path?: IPathCommandData | IPathCommandObject[] | IPathString
public windingRule?: IWindingRule
public closed?: boolean
// @leafer-in/flow rewrite
public flow?: IFlowType
public padding?: IFourNumber
public gap?: IGap | IPointGap
public flowAlign?: IFlowAlign | IFlowAxisAlign
public flowWrap?: IFlowWrap
public itemBox?: IFlowBoxType
public inFlow?: IBoolean
public autoWidth?: IAutoSize
public autoHeight?: IAutoSize
public lockRatio?: IBoolean
public autoBox?: IAutoBoxData | IConstraint
public widthRange?: IRangeSize
public heightRange?: IRangeSize
// drag
public draggable?: IBoolean | IAxis
public dragBounds?: IBoundsData | 'parent'
dragBoundsType?: IDragBoundsType
public editable?: IBoolean
// hit
public hittable?: IBoolean
public hitFill?: IHitType
public hitStroke?: IHitType
public hitBox?: IBoolean
public hitChildren?: IBoolean
public hitSelf?: IBoolean
public hitRadius?: INumber
public cursor?: ICursorType | ICursorType[]
// ---
// fill
public fill?: IFill
// stroke
public stroke?: IStroke
public strokeAlign?: IStrokeAlign
public strokeWidth?: IFourNumber | IStrokeWidthString
public strokeWidthFixed?: IScaleFixed
public strokeCap?: IStrokeCap
public strokeJoin?: IStrokeJoin
public dashPattern?: INumber[] | IDashPatternString
public dashOffset?: INumber
public miterLimit?: INumber
// @leafer-in/arrow rewrite
public startArrow?: IArrowStyle
public endArrow?: IArrowStyle
// corner
public cornerRadius?: IFourNumber | ICornerRadiusString
public cornerSmoothing?: INumber
// effect
public shadow?: IShadowEffect | IShadowEffect[] | IShadowString
public innerShadow?: IShadowEffect | IShadowEffect[] | IShadowString
public blur?: INumber | IBlurEffect
public backgroundBlur?: INumber | IBlurEffect
public grayscale?: INumber | IGrayscaleEffect
public filter?: IFilter | IFilter[]
// @leafer-in/animate rewrite
public animation?: IAnimation | IAnimation[]
public animationOut?: IAnimation | IAnimation[]
public transition?: ITransition
public transitionOut?: ITransition
// @leafer-in/motion-path rewrite
public motionPath?: boolean
public motionPrecision?: INumber
public motion?: INumber | IUnitData
public motionRotation?: INumber | IBoolean
// @leafer-in/state rewrite
public states?: IStates
public state?: IStateName
public selected?: IBoolean
public disabled?: IBoolean
public normalStyle?: IStateStyle
public hoverStyle?: IStateStyle
public pressStyle?: IStateStyle
public focusStyle?: IStateStyle
public selectedStyle?: IStateStyle
public disabledStyle?: IStateStyle
public placeholderStyle?: IStateStyle
public placeholderColor?: IColorString
public placeholderDelay?: INumber
public button?: IBoolean
// @leafer-in/editor rewrite
public editConfig: IEditorConfig
public editOuter: string
public editInner: string
// 预留给用户使用的数据对象
public data: IObject
public set scale(value: INumber | IPointData) { MathHelper.assignScale(this as IScaleData, value) }
public get scale(): INumber | IPointData { return this.__.scale }
public get isAutoWidth(): boolean { const t = this.__; return t.__autoWidth || t.autoWidth as boolean }
public get isAutoHeight(): boolean { const t = this.__; return t.__autoHeight || t.autoHeight as boolean }
public useFastShadow?: boolean // 将忽略 stroke 产生的阴影,只对单个 fill 有效
public __box?: IUI // 背景box, 一般用于文本背景框
public __animate?: IAnimate | IAnimateList
public get pen(): IPathCreator {
const { path } = this.__
pen.set(this.path = path || [])
if (!path) this.__drawPathByBox(pen)
return pen
}
// data
public reset(_data?: IUIInputData): void { }
// @leafer-in/animate and @leafer-in/state will rewrite
public set(data: IUIInputData, _transition?: ITransition | 'temp'): void {
if (data) Object.assign(this, data)
}
public get(name?: string | string[] | IUIInputData): IUIInputData | IValue {
return isString(name) ? this.__.__getInput(name) : this.__.__getInputData(name)
}
public createProxyData(): IUIInputData { return undefined }
// hit rewrite
public find(_condition: number | string | IFindCondition | IFindUIMethod, _options?: any): IUI[] { return Plugin.need('find') }
public findTag(tag: string | string[]): IUI[] { return this.find({ tag }) }
public findOne(_condition: number | string | IFindCondition | IFindUIMethod, _options?: any): IUI | undefined { return Plugin.need('find') }
public findId(id: number | string): IUI | undefined { return this.findOne({ id }) }
// path
public getPath(curve?: boolean, pathForRender?: boolean): IPathCommandData {
this.__layout.update()
let path = pathForRender ? this.__.__pathForRender : this.__.path
if (!path) pen.set(path = []), this.__drawPathByBox(pen)
return curve ? PathConvert.toCanvasData(path, true) : path
}
public getPathString(curve?: boolean, pathForRender?: boolean, floatLength?: number): IPathString {
return PathConvert.stringify(this.getPath(curve, pathForRender), floatLength)
}
public load(): void {
this.__.__computePaint() // 手动加载图片
}
public __onUpdateSize(): void {
if (this.__.__input) {
const data = this.__;
(data.lazy && !this.__inLazyBounds && !Export.running) ? data.__needComputePaint = true : data.__computePaint()
}
}
public __updateRenderPath(): void {
const data = this.__
if (data.path) {
data.__pathForRender = data.cornerRadius ? PathCorner.smooth(data.path, data.cornerRadius, data.cornerSmoothing) : data.path
if (data.__useArrow) PathArrow.addArrows(this)
} else data.__pathForRender && (data.__pathForRender = undefined)
}
public __drawRenderPath(canvas: ILeaferCanvas): void {
canvas.beginPath()
this.__drawPathByData(canvas, this.__.__pathForRender)
}
public __drawPath(canvas: ILeaferCanvas): void {
canvas.beginPath()
this.__drawPathByData(canvas, this.__.path)
}
public __drawPathByData(drawer: IPathDrawer, data: IPathCommandData): void {
data ? PathDrawer.drawPathByData(drawer, data) : this.__drawPathByBox(drawer)
}
public __drawPathByBox(drawer: IPathDrawer): void {
const { x, y, width, height } = this.__layout.boxBounds
if (this.__.cornerRadius) {
const { cornerRadius } = this.__
drawer.roundRect(x, y, width, height, isNumber(cornerRadius) ? [cornerRadius] : cornerRadius) // 修复微信浏览器bug, 后续需进一步优化
} else drawer.rect(x, y, width, height)
}
public drawImagePlaceholder(canvas: ILeaferCanvas, _image?: ILeaferImage): void {
Paint.fill(this.__.placeholderColor, this, canvas) // 图片占位符
}
// @leafer-in/animate rewrite
public animate(keyframe?: IUIInputData | IKeyframe[] | IAnimation | IAnimation[], _options?: ITransition, _type?: IAnimateType, _isTemp?: boolean): IAnimate {
this.set(keyframe as IUIInputData)
return Plugin.need('animate')
}
public killAnimate(_type?: IAnimateType, _nextStyle?: IUIInputData): void { }
// create
// @leafer-in/export will rewrite
public export(_filename: IExportFileType | string, _options?: IExportOptions | number | boolean): Promise<IExportResult> {
return Plugin.need('export')
}
public syncExport(_filename: IExportFileType | string, _options?: IExportOptions | number | boolean): IExportResult {
return Plugin.need('export')
}
public clone(data?: IUIInputData): this {
const json = DataHelper.clone(this.toJSON())
if (data) Object.assign(json, data)
return UI.one(json) as this
}
// this 参数定义,在编译的时候会移除
static one<T extends UI>(this: new (...args: any[]) => T, data: IUIInputData, x?: number, y?: number, width?: number, height?: number): T {
return UICreator.get(data.tag || this.prototype.__tag, data, x, y, width, height) as T
}
static registerUI(): void {
registerUI()(this)
}
static registerData(data: IUIData): void {
dataProcessor(data)(this.prototype)
}
// @leafer-in/editor rewrite
static setEditConfig(_config: IEditorConfig | IEditorConfigFunction): void { }
static setEditOuter(_toolName: string | IEditToolFunction): void { }
static setEditInner(_editorName: string | IEditToolFunction): void { }
public destroy(): void {
this.fill = this.stroke = null
if (this.__animate) this.killAnimate()
super.destroy()
}
}