import { fabric } from 'fabric' ; import { FabricEvent , FabricObject , WorkareaObject } from '../utils' ; import Handler from './Handler' ; class GuidelineHandler { handler : Handler ; verticalLines : { x ? : number ; y1 ? : number ; y2 ? : number ; } [ ] ; horizontalLines : { y ? : number ; x1 ? : number ; x2 ? : number ; } [ ] ; ctx : CanvasRenderingContext2D ; viewportTransform : number [ ] ; aligningLineOffset = 5 ; aligningLineMargin = 4 ; aligningLineWidth = 1 ; aligningLineColor = 'rgb(255, 0, 0)' ; zoom = 1 ; constructor ( handler ) { this . handler = handler ; this . initialize ( ) ; } /**
     * Initialize guideline handler
     *
     */ public initialize ( ) { if ( this . handler . guidelineOption . enabled ) { this . handler . canvas . on ( { 'before:render' : this . beforeRender , 'after:render' : this . afterRender , } ) ; } else { this . handler . canvas . off ( { 'before:render' : this . beforeRender , 'after:render' : this . afterRender , } ) ; } this . ctx = this . handler . canvas . getSelectionContext ( ) ; this . aligningLineOffset = 5 ; this . aligningLineMargin = 4 ; this . aligningLineWidth = 1 ; this . aligningLineColor = 'rgb(255, 0, 0)' ; this . viewportTransform = this . handler . canvas . viewportTransform ; this . zoom = 1 ; this . verticalLines = [ ] ; this . horizontalLines = [ ] ; } author salgum1114
      public destroy ( ) { this . handler . canvas . off ( { 'before:render' : this . beforeRender , 'after:render' : this . afterRender , } ) ; } param { FabricEvent } _opt public beforeRender = ( _opt ) => { this . handler . canvas . clearContext ( this . handler . guidelineHandler . ctx ) ; } ; param { FabricEvent } _opt public afterRender = ( _opt ) => { for ( let i = this . handler . guidelineHandler . verticalLines . length ; i -- ; ) { this . handler . guidelineHandler . drawVerticalLine ( this . handler . guidelineHandler . verticalLines [ i ] ) ; } for ( let i = this . handler . guidelineHandler . horizontalLines . length ; i -- ; ) { this . handler . guidelineHandler . drawHorizontalLine ( this . handler . guidelineHandler . horizontalLines [ i ] ) ; } this . handler . guidelineHandler . verticalLines . length = 0 ; this . handler . guidelineHandler . horizontalLines . length = 0 ; } ; drawVerticalLine = ( coords ) => { this . drawLine ( coords . x + 0.5 , coords . y1 > coords . y2 ? coords . y2 : coords . y1 , coords . x + 0.5 , coords . y2 > coords . y1 ? coords . y2 : coords . y1 ) ; } ; drawHorizontalLine = ( coords ) => { this . drawLine ( coords . x1 > coords . x2 ? coords . x2 : coords . x1 , coords . y + 0.5 , coords . x2 > coords . x1 ? coords . x2 : coords . x1 , coords . y + 0.5 ) ; } ; drawLine = ( x1 , y1 , x2 , y2 ) => { const { ctx , aligningLineWidth , aligningLineColor , viewportTransform , zoom } = this ; ctx . save ( ) ; ctx . lineWidth = aligningLineWidth ; ctx . strokeStyle = aligningLineColor ; ctx . beginPath ( ) ; ctx . moveTo ( x1 * zoom + viewportTransform [ 4 ] , y1 * zoom + viewportTransform [ 5 ] ) ; ctx . lineTo ( x2 * zoom + viewportTransform [ 4 ] , y2 * zoom + viewportTransform [ 5 ] ) ; ctx . stroke ( ) ; ctx . restore ( ) ; } ; isInRange = ( v1 , v2 ) => { const { aligningLineMargin } = this ; v1 = Math . round ( v1 ) ; v2 = Math . round ( v2 ) ; for ( let i = v1 - aligningLineMargin , len = v1 + aligningLineMargin ; i <= len ; i ++ ) { if ( i === v2 ) { return true ; } } return false ; } ; movingGuidelines = ( target ) => { const canvasObjects = this . handler . canvas . getObjects ( ) as FabricObject [ ] ; const activeObjectCenter = target . getCenterPoint ( ) ; const activeObjectLeft = activeObjectCenter . x ; const activeObjectTop = activeObjectCenter . y ; const activeObjectBoundingRect = target . getBoundingRect ( ) ; const activeObjectHeight = activeObjectBoundingRect . height / this . viewportTransform [ 3 ] ; const activeObjectWidth = activeObjectBoundingRect . width / this . viewportTransform [ 0 ] ; let horizontalInTheRange = false ; let verticalInTheRange = false ; const { _currentTransform : transform } = this . handler . canvas as any ; if ( ! transform ) { return ; } for ( let i = canvasObjects . length ; i -- ; ) { if ( canvasObjects [ i ] === target || canvasObjects [ i ] . superType === 'port' || canvasObjects [ i ] . superType === 'link' || ! canvasObjects [ i ] . evented ) { continue ; } const objectCenter = canvasObjects [ i ] . getCenterPoint ( ) ; const objectLeft = objectCenter . x ; const objectTop = objectCenter . y ; const objectBoundingRect = canvasObjects [ i ] . getBoundingRect ( ) ; const objectHeight = objectBoundingRect . height / this . viewportTransform [ 3 ] ; const objectWidth = objectBoundingRect . width / this . viewportTransform [ 0 ] ; if ( this . isInRange ( objectLeft , activeObjectLeft ) ) { verticalInTheRange = true ; if ( canvasObjects [ i ] . id === 'workarea' ) { const y1 = - 5000 ; const y2 = 5000 ; this . verticalLines . push ( { x : objectLeft , y1 , y2 , } ) ; } else { this . verticalLines . push ( { x : objectLeft , y1 : objectTop < activeObjectTop ? objectTop - objectHeight / 2 - this . aligningLineOffset : objectTop + objectHeight / 2 + this . aligningLineOffset , y2 : activeObjectTop > objectTop ? activeObjectTop + activeObjectHeight / 2 + this . aligningLineOffset : activeObjectTop - activeObjectHeight / 2 - this . aligningLineOffset , } ) ; } target . setPositionByOrigin ( new fabric . Point ( objectLeft , activeObjectTop ) , 'center' , 'center' ) ; } if ( this . isInRange ( objectLeft - objectWidth / 2 , activeObjectLeft - activeObjectWidth / 2 ) ) { verticalInTheRange = true ; if ( canvasObjects [ i ] . id === 'workarea' ) { const workarea = canvasObjects [ i ] as WorkareaObject ; const y1 = - 5000 ; const y2 = 5000 ; let x = objectLeft - objectWidth / 2 ; if ( workarea . layout === 'fullscreen' ) { x = 0 ; } this . verticalLines . push ( { x , y1 , y2 , } ) ; } else { this . verticalLines . push ( { x : objectLeft - objectWidth / 2 , y1 : objectTop < activeObjectTop ? objectTop - objectHeight / 2 - this . aligningLineOffset : objectTop + objectHeight / 2 + this . aligningLineOffset , y2 : activeObjectTop > objectTop ? activeObjectTop + activeObjectHeight / 2 + this . aligningLineOffset : activeObjectTop - activeObjectHeight / 2 - this . aligningLineOffset , } ) ; } target . setPositionByOrigin ( new fabric . Point ( objectLeft - objectWidth / 2 + activeObjectWidth / 2 , activeObjectTop ) , 'center' , 'center' ) ; } if ( this . isInRange ( objectLeft + objectWidth / 2 , activeObjectLeft + activeObjectWidth / 2 ) ) { verticalInTheRange = true ; if ( canvasObjects [ i ] . id === 'workarea' ) { const workarea = canvasObjects [ i ] as WorkareaObject ; const y1 = - 5000 ; const y2 = 5000 ; let x = objectLeft + objectWidth / 2 ; if ( workarea . layout === 'fullscreen' ) { x = this . handler . canvas . getWidth ( ) ; } this . verticalLines . push ( { x , y1 , y2 , } ) ; } else { this . verticalLines . push ( { x : objectLeft + objectWidth / 2 , y1 : objectTop < activeObjectTop ? objectTop - objectHeight / 2 - this . aligningLineOffset : objectTop + objectHeight / 2 + this . aligningLineOffset , y2 : activeObjectTop > objectTop ? activeObjectTop + activeObjectHeight / 2 + this . aligningLineOffset : activeObjectTop - activeObjectHeight / 2 - this . aligningLineOffset , } ) ; } target . setPositionByOrigin ( new fabric . Point ( objectLeft + objectWidth / 2 - activeObjectWidth / 2 , activeObjectTop ) , 'center' , 'center' ) ; } if ( this . isInRange ( objectTop , activeObjectTop ) ) { horizontalInTheRange = true ; if ( canvasObjects [ i ] . id === 'workarea' ) { const x1 = - 5000 ; const x2 = 5000 ; this . horizontalLines . push ( { y : objectTop , x1 , x2 , } ) ; } else { this . horizontalLines . push ( { y : objectTop , x1 : objectLeft < activeObjectLeft ? objectLeft - objectWidth / 2 - this . aligningLineOffset : objectLeft + objectWidth / 2 + this . aligningLineOffset , x2 : activeObjectLeft > objectLeft ? activeObjectLeft + activeObjectWidth / 2 + this . aligningLineOffset : activeObjectLeft - activeObjectWidth / 2 - this . aligningLineOffset , } ) ; } target . setPositionByOrigin ( new fabric . Point ( activeObjectLeft , objectTop ) , 'center' , 'center' ) ; } if ( this . isInRange ( objectTop - objectHeight / 2 , activeObjectTop - activeObjectHeight / 2 ) ) { horizontalInTheRange = true ; if ( canvasObjects [ i ] . id === 'workarea' ) { const workarea = canvasObjects [ i ] as WorkareaObject ; const x1 = - 5000 ; const x2 = 5000 ; let y = objectTop - objectHeight / 2 ; if ( workarea . layout === 'fullscreen' ) { y = 0 ; } this . horizontalLines . push ( { y , x1 , x2 , } ) ; } else { this . horizontalLines . push ( { y : objectTop - objectHeight / 2 , x1 : objectLeft < activeObjectLeft ? objectLeft - objectWidth / 2 - this . aligningLineOffset : objectLeft + objectWidth / 2 + this . aligningLineOffset , x2 : activeObjectLeft > objectLeft ? activeObjectLeft + activeObjectWidth / 2 + this . aligningLineOffset : activeObjectLeft - activeObjectWidth / 2 - this . aligningLineOffset , } ) ; } target . setPositionByOrigin ( new fabric . Point ( activeObjectLeft , objectTop - objectHeight / 2 + activeObjectHeight / 2 ) , 'center' , 'center' ) ; } if ( this . isInRange ( objectTop + objectHeight / 2 , activeObjectTop + activeObjectHeight / 2 ) ) { horizontalInTheRange = true ; if ( canvasObjects [ i ] . id === 'workarea' ) { const workarea = canvasObjects [ i ] as WorkareaObject ; const x1 = - 5000 ; const x2 = 5000 ; let y = objectTop + objectHeight / 2 ; if ( workarea . layout === 'fullscreen' ) { y = this . handler . canvas . getHeight ( ) ; } this . horizontalLines . push ( { y , x1 , x2 , } ) ; } else { this . horizontalLines . push ( { y : objectTop + objectHeight / 2 , x1 : objectLeft < activeObjectLeft ? objectLeft - objectWidth / 2 - this . aligningLineOffset : objectLeft + objectWidth / 2 + this . aligningLineOffset , x2 : activeObjectLeft > objectLeft ? activeObjectLeft + activeObjectWidth / 2 + this . aligningLineOffset : activeObjectLeft - activeObjectWidth / 2 - this . aligningLineOffset , } ) ; } target . setPositionByOrigin ( new fabric . Point ( activeObjectLeft , objectTop + objectHeight / 2 - activeObjectHeight / 2 ) , 'center' , 'center' ) ; } } if ( ! horizontalInTheRange ) { this . horizontalLines . length = 0 ; } if ( ! verticalInTheRange ) { this . verticalLines . length = 0 ; } } ; scalingGuidelines = ( _target ) => { } ; } export default GuidelineHandler ;