import { MiBrushAttrs , MiBrushRepaintConfig , MiTools , MiToolsSyncData , Tools } from '@components/canvas/Tools' ; import { Canvas } from '@components/canvas/Canvas' ; import { Point } from '@components/canvas/Point' ; import { MiRectConfig } from '@components/canvas/shapes/Rect' ; export class Rect extends Tools implements MiTools { name = 'rect' ; start ! : Point ; solid = false ; rect : MiRectConfig = { x : 0 , y : 0 , width : 0 , height : 0 } ; param canvas constructor ( canvas ) { super ( canvas ) ; Tools . instances [ this . name ] = this ; } param args draw < A extends MiToolsSyncData [ ] > ( ... args ) { const data = args [ 0 ] as MiToolsSyncData , rect = this . setRect ( data . end as Point , data . start , true ) as MiRectConfig ; this . rendering ( { ... rect , solid : data . solid } , data . attrs , data . config ) ; } param rect param attrs param config protected rendering ( rect ? , attrs ? , config ? ) { rect = rect ?? { ... this . rect } ; const ctx = config ?. ctx ?? this . getCurrentContext ( ) ; this . resetCtxAttrs ( ctx , attrs ) ; const rectangle = ( { ... config ?. rect } ?? { } ) as MiRectConfig , tempRect = { ... rect } ; ctx . save ( ) ; if ( config ) { /** 无限画布 */ if ( config . origin ) ctx . translate ( config . origin . x , config . origin . y ) ; /** 移动 */ if ( config . move ) { const isMoving = config . move . x !== 0 || config . move . y !== 0 ; if ( isMoving ) { tempRect . x += config . move . x ; tempRect . y += config . move . y ; rectangle . x += config . move . x ; rectangle . y += config . move . y ; } } } if ( config ?. selection ) this . drawChoiceRect ( ctx , rectangle ) ; else this . drawRect ( ctx , tempRect ) ; ctx . restore ( ) ; } param ctx param rect protected drawRect ( ctx ? , rect ? ) { ctx = ctx ?? this . getBufferContext ( ) ; const solid = rect ? rect . solid : this . solid ; rect = rect ?? this . rect ; ctx . beginPath ( ) ; ctx . rect ( rect . x , rect . y , rect . width , rect . height ) ; ctx . closePath ( ) ; if ( solid ) ctx . fill ( ) ; else ctx . stroke ( ) ; } param point param start param back protected setRect ( point , start ? , back = false ) { start = start ?? this . start ; let rect ! ; /** 右上角移动 */ if ( point . x > start . x && point . y < start . y ) { rect = { x : start . x , y : point . y , width : point . x - start . x , height : start . y - point . y } ; } /** 右下角移动 */ if ( point . x > start . x && point . y > start . y ) { rect = { x : start . x , y : start . y , width : point . x - start . x , height : point . y - start . y } ; } /** 左上角移动 */ if ( point . x < start . x && point . y < start . y ) { rect = { x : point . x , y : point . y , width : start . x - point . x , height : start . y - point . y } ; } /** 左下角移动 */ if ( point . x < start . x && point . y > start . y ) { rect = { x : point . x , y : start . y , width : start . x - point . x , height : point . y - start . y } ; } if ( rect !== undefined ) { if ( back ) return rect ; else this . rect = rect ; } } return protected resetRect ( ) { this . rect = { x : 0 , y : 0 , width : 0 , height : 0 } ; } param event protected drawBegin ( event ) { this . start = this . createPoint ( event . clientX , event . clientY ) ; this . resetRect ( ) ; this . buffer = this . createBuffer ( ) ; this . drawUpdate ( event ) ; } param event protected drawUpdate ( event ) { const point = this . createPoint ( event . clientX , event . clientY ) , distance = point . distance ( this . start ) ; if ( distance >= Tools . distance ) { this . setRect ( point ) ; this . drawRect ( ) ; } } param event protected drawEnd ( event ) { this . resetBuffer ( ( ) => { /** 重置 CTX 属性 (避免同步等情况下被覆盖) */ const attrs = { ... this . getCtxAttrs ( ) } , ctx = this . getCurrentContext ( ) ; this . resetCtxAttrs ( ctx , attrs ) ; /** 绘制 */ this . drawRect ( ctx ) ; /** 记录用于选择判断的方形并存储 */ const end = this . createPoint ( event . clientX , event . clientY ) , rect = this . getRect ( { ... this . rect } ) ; const params = { ... this . getDefaultSyncData ( ) , attrs , start : { ... this . start } , end , rect , solid : this . solid , tool : this . name } as MiToolsSyncData ; this . saveLayerData ( params ) ; Tools . setTraces ( ) ; } ) ; } }