import * as SpriteSpin from '../core' ; import * as Utils from '../utils' ; ( ( ) => { const NAME = 'zoom' ; interface ZoomState { source : string [ ] ; stage : any ; oldX : number ; oldY : number ; currentX : number ; currentY : number ; clickTime : number ; doubleClickTime : number ; useWheel : boolean | number ; useClick : number ; pinFrame : boolean ; } function getState ( data ) { return SpriteSpin . getPluginState ( data , NAME ) as ZoomState ; } function getOption ( data , name , fallback ) { return name in data ? data [ name ] : fallback ; } function onInit ( e , data ) { const state = getState ( data ) ; state . source = getOption ( data , 'zoomSource' , data . source ) ; state . useWheel = getOption ( data , 'zoomUseWheel' , false ) ; state . useClick = getOption ( data , 'zoomUseClick' , true ) ; state . pinFrame = getOption ( data , 'zoomPinFrame' , true ) ; state . doubleClickTime = getOption ( data , 'zoomDoubleClickTime' , 500 ) ; state . stage = state . stage || Utils . $ ( "<div class='zoom-stage'></div>" ) ; state . stage . css ( { width : '100%' , height : '100%' , top : 0 , left : 0 , bottom : 0 , right : 0 , position : 'absolute' } ) . appendTo ( data . target ) . hide ( ) ; } function onDestroy ( e , data ) { const state = getState ( data ) ; if ( state . stage ) { state . stage . remove ( ) ; delete state . stage ; } } function updateInput ( e , data ) { const state = getState ( data ) ; if ( ! state . stage . is ( ':visible' ) ) { return ; } e . preventDefault ( ) ; if ( state . pinFrame ) { SpriteSpin . flag ( data , 'dragging' , false ) ; } const cursor = Utils . getCursorPosition ( e ) ; const x = cursor . x / data . width ; const y = cursor . y / data . height ; if ( state . oldX == null ) { state . oldX = x ; state . oldY = y ; } if ( state . currentX == null ) { state . currentX = x ; state . currentY = y ; } let dx = x - state . oldX ; let dy = y - state . oldY ; state . oldX = x ; state . oldY = y ; if ( e . type . match ( /touch/ ) ) { dx = - dx ; dy = - dy ; } state . currentX = Utils . clamp ( state . currentX + dx , 0 , 1 ) ; state . currentY = Utils . clamp ( state . currentY + dy , 0 , 1 ) ; SpriteSpin . updateFrame ( data , data . frame , data . lane ) ; } function onClick ( e , data ) { const state = getState ( data ) ; if ( ! state . useClick ) { return ; } e . preventDefault ( ) ; const clickTime = new Date ( ) . getTime ( ) ; if ( ! state . clickTime ) { state . clickTime = clickTime ; return ; } const timeDelta = clickTime - state . clickTime ; if ( timeDelta > state . doubleClickTime ) { state . clickTime = clickTime ; return ; } state . clickTime = undefined ; if ( toggleZoom ( data ) ) { updateInput ( e , data ) ; } } function onMove ( e , data ) { const state = getState ( data ) ; if ( state . stage . is ( ':visible' ) ) { updateInput ( e , data ) ; } } function onDraw ( e , data ) { const state = getState ( data ) ; const index = data . lane * data . frames + data . frame ; const source = state . source [ index ] ; const spec = Utils . findSpecs ( data . metrics , data . frames , data . frame , data . lane ) ; let x = state . currentX ; let y = state . currentY ; if ( x == null ) { x = state . currentX = 0.5 ; y = state . currentY = 0.5 ; } if ( source ) { x = Math . floor ( x * 100 ) ; y = Math . floor ( y * 100 ) ; state . stage . css ( { 'background-repeat' : 'no-repeat' , 'background-image' : `url('${ source }')` , 'background-position' : `${ x }% ${ y }%` } ) ; } else if ( spec . sheet && spec . sprite ) { const sprite = spec . sprite ; const sheet = spec . sheet ; const src = data . source [ sheet . id ] ; const left = - Math . floor ( sprite . sampledX + x * ( sprite . sampledWidth - data . width ) ) ; const top = - Math . floor ( sprite . sampledY + y * ( sprite . sampledHeight - data . height ) ) ; const width = sheet . sampledWidth ; const height = sheet . sampledHeight ; state . stage . css ( { 'background-image' : `url('${ src }')` , 'background-position' : `${ left }px ${ top }px` , 'background-repeat' : 'no-repeat' , '-webkit-background-size' : `${ width }px ${ height }px` , '-moz-background-size' : `${ width }px ${ height }px` , '-o-background-size' : `${ width }px ${ height }px` , 'background-size' : `${ width }px ${ height }px` } ) ; } } function toggleZoom ( data ) { const state = getState ( data ) ; if ( ! state . stage ) { throw new Error ( 'zoom module is not initialized or is not available.' ) ; } if ( state . stage . is ( ':visible' ) ) { showZoom ( data ) ; } else { hideZoom ( data ) ; return true ; } return false ; } function showZoom ( data ) { const state = getState ( data ) ; state . stage . fadeOut ( ) ; data . stage . fadeIn ( ) ; } function hideZoom ( data ) { const state = getState ( data ) ; state . stage . fadeIn ( ) ; data . stage . fadeOut ( ) ; } function wheel ( e , data ) { const state = getState ( data ) ; if ( ! data . loading && state . useWheel ) { const we = e . originalEvent as WheelEvent ; let signY = we . deltaY === 0 ? 0 : we . deltaY > 0 ? 1 : - 1 ; if ( typeof state . useWheel === 'number' ) { signY *= state . useWheel ; } if ( state . stage . is ( ':visible' ) && signY > 0 ) { e . preventDefault ( ) ; showZoom ( data ) ; } if ( ! state . stage . is ( ':visible' ) && signY < 0 ) { e . preventDefault ( ) ; hideZoom ( data ) ; } } } SpriteSpin . registerPlugin ( NAME , { name : NAME , mousedown : onClick , touchstart : onClick , mousemove : onMove , touchmove : onMove , wheel : wheel , onInit : onInit , onDestroy : onDestroy , onDraw : onDraw } ) ; SpriteSpin . extendApi ( { toggleZoom : function ( ) { toggleZoom ( this . data ) ; } } ) ; } ) ( ) ;