import { RectangularMarkerGrips } from './RectangularMarkerGrips' ; import { BaseMarker } from '../BaseMarker' ; import { ResizeGrip } from '../BaseMarker/ResizeGrip' ; import { SvgHelper } from '../../renderer/SvgHelper' ; import { WhitePage } from '../../whiteboard/WhitePage' ; import { PositionType } from '../../utils/layout' ; import { MarkerSnap } from '../../whiteboard/AbstractWhiteboard/snap' ; export class RectangularMarker extends BaseMarker { public static createMarker = ( page ? ) : RectangularMarker => { const marker = new RectangularMarker ( ) ; marker . page = page ; marker . init ( ) ; return marker ; } ; protected MIN_SIZE = 5 ; private controlBox : SVGGElement ; private readonly CB_DISTANCE = 10 ; private controlRect : SVGRectElement ; private controlGrips : RectangularMarkerGrips ; private activeGrip : ResizeGrip | null ; /** Getter & Setter */ public captureSnap ( ) { const snap = super . captureSnap ( ) ; snap . rectSnap = { width : this . width , height : this . height , } ; return snap ; } public applySnap ( snap ) { super . applySnap ( snap ) ; if ( snap . rectSnap ) { const { width , height } = snap . rectSnap ; if ( width && height ) { this . width = width ; this . height = height ; this . adjustControlBox ( ) ; } } } public endManipulation ( ) { super . endManipulation ( ) ; this . isResizing = false ; this . activeGrip = null ; } public select ( ) { super . select ( ) ; this . controlBox . style . display = '' ; } public deselect ( ) { super . deselect ( ) ; this . controlBox . style . display = 'none' ; } protected init ( ) { super . init ( ) ; this . addControlBox ( ) ; if ( this . page && this . page . mode === 'mirror' ) { this . controlBox . style . display = 'none' ; } } protected resizeByEvent ( dx , dy , pos ) { this . activeGrip = this . controlGrips [ pos ] ; this . resize ( dx , dy ) ; } protected resize ( dx , dy , onPosition ? ) { let translateX = 0 ; let translateY = 0 ; switch ( this . activeGrip ) { case this . controlGrips . topLeft : this . width -= dx ; this . height -= dy ; translateX += dx ; translateY += dy ; this . x += dx ; this . y += dy ; if ( onPosition ) { onPosition ( 'topLeft' ) ; } break ; case this . controlGrips . bottomLeft : this . width -= dx ; this . height += dy ; translateX += dx ; this . x += dx ; if ( onPosition ) { onPosition ( 'bottomLeft' ) ; } break ; case this . controlGrips . topRight : this . width += dx ; this . height -= dy ; translateY += dy ; this . y += dy ; if ( onPosition ) { onPosition ( 'topRight' ) ; } break ; case this . controlGrips . bottomRight : this . width += dx ; this . height += dy ; if ( onPosition ) { onPosition ( 'bottomRight' ) ; } break ; case this . controlGrips . centerLeft : this . width -= dx ; translateX += dx ; this . x += dx ; if ( onPosition ) { onPosition ( 'centerLeft' ) ; } break ; case this . controlGrips . centerRight : this . width += dx ; if ( onPosition ) { onPosition ( 'centerRight' ) ; } break ; case this . controlGrips . topCenter : this . height -= dy ; translateY += dy ; this . y += dy ; if ( onPosition ) { onPosition ( 'topCenter' ) ; } break ; case this . controlGrips . bottomCenter : this . height += dy ; if ( onPosition ) { onPosition ( 'bottomCenter' ) ; } break ; default : break ; } if ( this . width < this . MIN_SIZE ) { const offset = this . MIN_SIZE - this . width ; this . width = this . MIN_SIZE ; if ( translateX !== 0 ) { translateX -= offset ; } } if ( this . height < this . MIN_SIZE ) { const offset = this . MIN_SIZE - this . height ; this . height = this . MIN_SIZE ; if ( translateY !== 0 ) { translateY -= offset ; } } if ( translateX !== 0 || translateY !== 0 ) { const translate = this . visual . transform . baseVal . getItem ( 0 ) ; translate . setMatrix ( translate . matrix . translate ( translateX , translateY ) ) ; this . visual . transform . baseVal . replaceItem ( translate , 0 ) ; } this . adjustControlBox ( ) ; } /** Init Comps */ private addControlBox = ( ) => { this . controlBox = SvgHelper . createGroup ( [ [ 'class' , 'fc-whiteboard-rect-control-box' ] , ] ) ; const translate = SvgHelper . createTransform ( ) ; translate . setTranslate ( - this . CB_DISTANCE / 2 , - this . CB_DISTANCE / 2 ) ; this . controlBox . transform . baseVal . appendItem ( translate ) ; this . addToVisual ( this . controlBox ) ; this . controlRect = SvgHelper . createRect ( this . width + this . CB_DISTANCE , this . height + this . CB_DISTANCE , [ [ 'class' , 'fc-whiteboard-rect-control-rect' ] ] ) ; this . controlBox . appendChild ( this . controlRect ) ; this . controlGrips = new RectangularMarkerGrips ( ) ; this . addControlGrips ( ) ; } ; private adjustControlBox = ( ) => { this . controlRect . setAttribute ( 'width' , ( this . width + this . CB_DISTANCE ) . toString ( ) ) ; this . controlRect . setAttribute ( 'height' , ( this . height + this . CB_DISTANCE ) . toString ( ) ) ; this . positionGrips ( ) ; } ; private addControlGrips = ( ) => { this . controlGrips . topLeft = this . createGrip ( ) ; this . controlGrips . topCenter = this . createGrip ( ) ; this . controlGrips . topRight = this . createGrip ( ) ; this . controlGrips . centerLeft = this . createGrip ( ) ; this . controlGrips . centerRight = this . createGrip ( ) ; this . controlGrips . bottomLeft = this . createGrip ( ) ; this . controlGrips . bottomCenter = this . createGrip ( ) ; this . controlGrips . bottomRight = this . createGrip ( ) ; this . positionGrips ( ) ; } ; private createGrip = ( ) : ResizeGrip => { const grip = new ResizeGrip ( ) ; grip . visual . transform . baseVal . appendItem ( SvgHelper . createTransform ( ) ) ; this . controlBox . appendChild ( grip . visual ) ; grip . visual . addEventListener ( 'mousedown' , this . gripMouseDown ) ; grip . visual . addEventListener ( 'mousemove' , this . gripMouseMove ) ; grip . visual . addEventListener ( 'mouseup' , this . gripMouseUp ) ; grip . visual . addEventListener ( 'touchstart' , this . onTouch , { passive : false , } ) ; grip . visual . addEventListener ( 'touchend' , this . onTouch , { passive : false } ) ; grip . visual . addEventListener ( 'touchmove' , this . onTouch , { passive : false } ) ; return grip ; } ; /** Event Handlers */ protected onTouch ( ev ) { super . onTouch ( ev ) ; } private gripMouseDown = ( ev ) => { this . isResizing = true ; this . activeGrip = this . controlGrips . findGripByVisual ( ev . target as SVGGraphicsElement ) || null ; this . previousMouseX = ev . screenX ; this . previousMouseY = ev . screenY ; ev . stopPropagation ( ) ; } ; private gripMouseUp = ( ev ) => { this . isResizing = false ; this . activeGrip = null ; ev . stopPropagation ( ) ; } ; private gripMouseMove = ( ev ) => { if ( this . isResizing ) { this . manipulate ( ev ) ; } } ; /** UI Position */ private positionGrips = ( ) => { const gripSize = this . controlGrips . topLeft . GRIP_SIZE ; const left = - gripSize / 2 ; const top = left ; const cx = ( this . width + this . CB_DISTANCE ) / 2 - gripSize / 2 ; const cy = ( this . height + this . CB_DISTANCE ) / 2 - gripSize / 2 ; const bottom = this . height + this . CB_DISTANCE - gripSize / 2 ; const right = this . width + this . CB_DISTANCE - gripSize / 2 ; this . positionGrip ( this . controlGrips . topLeft . visual , left , top ) ; this . positionGrip ( this . controlGrips . topCenter . visual , cx , top ) ; this . positionGrip ( this . controlGrips . topRight . visual , right , top ) ; this . positionGrip ( this . controlGrips . centerLeft . visual , left , cy ) ; this . positionGrip ( this . controlGrips . centerRight . visual , right , cy ) ; this . positionGrip ( this . controlGrips . bottomLeft . visual , left , bottom ) ; this . positionGrip ( this . controlGrips . bottomCenter . visual , cx , bottom ) ; this . positionGrip ( this . controlGrips . bottomRight . visual , right , bottom ) ; } ; private positionGrip = ( grip , x , y ) => { const translate = grip . transform . baseVal . getItem ( 0 ) ; translate . setTranslate ( x , y ) ; grip . transform . baseVal . replaceItem ( translate , 0 ) ; } ; }