import { MiBrushAttrs , MiBrushRepaintConfig , MiTools , MiToolsSyncData , Tools } from '@components/canvas/Tools' ; import { Canvas } from '@components/canvas/Canvas' ; import { Point } from '@components/canvas/Point' ; import { Utils } from '@components/canvas/Utils' ; import { MiRectConfig } from '@components/canvas/shapes/Rect' ; export interface MiArrowConfig { start : { x : number ; y : number ; } ; vertex : { center : { x : number ; y : number ; } ; left : { x : number ; y : number ; } ; right : { x : number ; y : number ; } ; mid : { left : { x : number ; y : number ; } ; right : { x : number ; y : number ; } ; } ; } ; } export class Arrow extends Tools implements MiTools { name = 'arrow' ; angle = 25 ; radian = 0 ; edgeLength = 50 ; divisor = 5 ; start = new Point ( 0 , 0 ) ; end = new Point ( 0 , 0 ) ; polygon : MiArrowConfig = { start : { x : 0 , y : 0 } , vertex : { center : { x : 0 , y : 0 } , left : { x : 0 , y : 0 } , right : { x : 0 , y : 0 } , mid : { left : { x : 0 , y : 0 } , right : { x : 0 , y : 0 } } } } ; param canvas constructor ( canvas ) { super ( canvas ) ; Tools . instances [ this . name ] = this ; Object . defineProperty ( this , 'arrowLength' , { get ( ) { return Tools . thickness / 2 < 10 ? 10 : Tools . thickness / 2 ; } } ) ; } param args draw < A extends MiToolsSyncData [ ] > ( ... args ) { const data = args [ 0 ] as MiToolsSyncData , start = new Point ( ( data . start as Point ) . x , ( data . start as Point ) . y ) , end = new Point ( ( data . end as Point ) . x , ( data . end as Point ) . y ) ; this . getArrowCord ( start , end ) ; this . getSizeCord ( ) ; const polygon = { ... this . polygon } ; this . rendering ( polygon , data . attrs , data . config ) ; } param polygon param attrs param config protected rendering ( polygon , attrs ? , config ? ) { const ctx = config ?. ctx ?? this . getCurrentContext ( ) ; this . resetCtxAttrs ( ctx , attrs ) ; const points = Utils . deepCopy ( this . getArrowRect ( polygon ) ) , tempPolygon = Utils . deepCopy ( polygon ) , rectangle = ( { ... config ?. rect } ?? { } ) as MiRectConfig ; 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 ) { const tempPoints = this . moving ( points , config . move ) ; /** 当前绘图临时坐标 */ tempPolygon . start = tempPoints [ 0 ] ; tempPolygon . vertex . mid . right = tempPoints [ 1 ] ; tempPolygon . vertex . right = tempPoints [ 2 ] ; tempPolygon . vertex . center = tempPoints [ 3 ] ; tempPolygon . vertex . left = tempPoints [ 4 ] ; tempPolygon . vertex . mid . left = tempPoints [ 5 ] ; /** 矩形 */ rectangle . x += config . move . x ; rectangle . y += config . move . y ; } } } if ( config ?. selection ) this . drawChoiceRect ( ctx , rectangle ) ; else this . drawArrow ( ctx , tempPolygon ) ; ctx . restore ( ) ; } param ctx param polygon protected drawArrow ( ctx ? , polygon ? ) { ctx = ctx ?? this . getBufferContext ( ) ; ctx . beginPath ( ) ; polygon = polygon ?? this . polygon ; ctx . moveTo ( polygon . start . x , polygon . start . y ) ; ctx . lineTo ( polygon . vertex . mid . right . x , polygon . vertex . mid . right . y ) ; ctx . lineTo ( polygon . vertex . right . x , polygon . vertex . right . y ) ; ctx . lineTo ( polygon . vertex . center . x , polygon . vertex . center . y ) ; ctx . lineTo ( polygon . vertex . left . x , polygon . vertex . left . y ) ; ctx . lineTo ( polygon . vertex . mid . left . x , polygon . vertex . mid . left . y ) ; ctx . closePath ( ) ; ctx . fill ( ) ; } param start param end protected getRadian ( start , end ) { this . radian = Math . atan2 ( end . y - start . y , end . x - start . x ) / Math . PI * 180 ; this . setArrowSizeDefault ( 50 , 25 ) ; this . setArrowSize ( start , end ) ; } param start param end protected getArrowCord ( start , end ) { this . polygon . start . x = start . x ; this . polygon . start . y = start . y ; this . polygon . vertex . center . x = end . x ; this . polygon . vertex . center . y = end . y ; this . getRadian ( start , end ) ; this . polygon . vertex . left . x = end . x - this . edgeLength * Math . cos ( Math . PI / 180 * ( this . radian + this . angle ) ) ; this . polygon . vertex . left . y = end . y - this . edgeLength * Math . sin ( Math . PI / 180 * ( this . radian + this . angle ) ) ; this . polygon . vertex . right . x = end . x - this . edgeLength * Math . cos ( Math . PI / 180 * ( this . radian - this . angle ) ) ; this . polygon . vertex . right . y = end . y - this . edgeLength * Math . sin ( Math . PI / 180 * ( this . radian - this . angle ) ) ; } param polygon protected getArrowRect ( polygon ? ) { polygon = polygon ?? this . polygon ; return [ new Point ( polygon . start . x , polygon . start . y ) , new Point ( polygon . vertex . mid . right . x , polygon . vertex . mid . right . y ) , new Point ( polygon . vertex . right . x , polygon . vertex . right . y ) , new Point ( polygon . vertex . center . x , polygon . vertex . center . y ) , new Point ( polygon . vertex . left . x , polygon . vertex . left . y ) , new Point ( polygon . vertex . mid . left . x , polygon . vertex . mid . left . y ) ] ; } return protected getSizeCord ( polygon ? ) { polygon = polygon ?? this . polygon ; const midPoint = { x : 0 , y : 0 } ; midPoint . x = ( polygon . vertex . right . x + polygon . vertex . left . x ) / 2 ; midPoint . y = ( polygon . vertex . right . y + polygon . vertex . left . y ) / 2 ; this . polygon . vertex . mid . left . x = ( polygon . vertex . left . x + midPoint . x ) / 2 ; this . polygon . vertex . mid . left . y = ( polygon . vertex . left . y + midPoint . y ) / 2 ; this . polygon . vertex . mid . right . x = ( polygon . vertex . right . x + midPoint . x ) / 2 ; this . polygon . vertex . mid . right . y = ( polygon . vertex . right . y + midPoint . y ) / 2 ; } param angle param edgeLength protected setArrowSizeDefault ( angle , edgeLength ) { this . angle = angle ; this . edgeLength = edgeLength ; } return protected setArrowSize ( start ? , end ? ) { start = start ?? this . start ; end = end ?? this . end ; const distance = end . distance ( start ) ; if ( distance < 250 ) { this . angle = this . angle / 2 ; this . edgeLength = this . edgeLength / 2 ; } else if ( distance < 500 ) { this . angle = this . angle * distance / 500 ; this . edgeLength = this . edgeLength * distance / 500 ; } } param event protected drawBegin ( event ) { this . setCtxAttrs ( ) ; this . getCurrentContext ( ) . lineWidth = this . getThickness ( this . divisor ) ; this . start = this . createPoint ( event . clientX , event . clientY ) ; this . buffer = this . createBuffer ( this . getThickness ( this . divisor ) ) ; this . drawUpdate ( event ) ; } param event protected drawUpdate ( event ) { const point = this . createPoint ( event . clientX , event . clientY ) ; const distance = point . distance ( this . start ) ; if ( distance >= Tools . distance ) { this . end = point ; this . getArrowCord ( this . start , this . end ) ; this . getSizeCord ( ) ; this . drawArrow ( ) ; } } param event protected drawEnd ( event ) { this . resetBuffer ( ( ) => { /** 渲染 */ this . getArrowCord ( this . start , this . end ) ; this . getSizeCord ( ) ; this . drawArrow ( this . getCurrentContext ( ) ) ; /** 记录用于选择判断的方形并存储 */ this . drawRectWorker ( this . getArrowRect ( ) , ( rect ) => { const params = { ... this . getDefaultSyncData ( ) , attrs : { ... this . getCtxAttrs ( ) } , start : { ... this . start } , end : { ... this . end } , rect , tool : this . name } as MiToolsSyncData ; this . saveLayerData ( params ) ; Tools . setTraces ( ) ; } ) ; } ) ; } }