/**
 * 滚轮类,是显示选择器可选项的滚轮体，3D模式型的，有透视效果
 */ import $ from '../util/domUtil' ; import { em } from '../em' ; import animationUtil from '../util/animationUtil' ; import constant from '../constant' ; import { Col } from '../Col' ; import { Picker } from '../Picker' ; import { IOptions } from '../API' ; import { AWheel } from './AWheel' ; declare function require < T > ( name ) ; const tick = require < { ( ) : { play ( ) ; } ; } > ( "../tick/tick" ) ( ) ; export class Wheel extends AWheel { private maxDistance = 0 ; private minDistance = 0 ; private em : ( ) => number = em ; private offsetTop = 0 ; private originalDistance = 0 ; private lastIndexDistance = 0 ; private changeMaxDistance = 0 ; private distance = 0 ; private animationId = - 1 ; private speed = 0 ; private timeStamp = 0 ; private lastY = 0 ; private isDraging = false ; constructor ( picker , col , option , index ) { super ( ) ; this . picker = picker ; this . option = option ; this . index = index ; this . dom = $ ( `<div class="picker-wheel">
                <div class="picker-label"><span class="picker-text"></span></div>
                <ul></ul>
                <div class="picker-label"><span class="picker-text"></span></div>
            </div>` ) . css ( 'height' , constant . WHEEL_HEIGHT / 100 + 'em' ) ; this . contains = this . dom . find ( 'ul' ) ; this . setDistance ( 0 ) ; this . labelKey = col . labelKey ; this . itemValueKey = col . valueKey ; var that = this ; function startDrag ( event ) { var target = event . currentTarget ; that . offsetTop = 0 ; while ( target ) { that . offsetTop += target . offsetTop ; var target = target . parentElement ; } var offsetY = event . touches ? event . touches [ 0 ] . clientY - that . offsetTop : event . clientY - that . offsetTop ; that . startDrag ( offsetY ) ; } this . dom [ 0 ] . addEventListener ( "touchstart" , startDrag ) ; this . dom [ 0 ] . addEventListener ( "mousedown" , startDrag ) ; function drag ( event ) { var offsetY = event . touches ? event . touches [ 0 ] . clientY - that . offsetTop : event . clientY - that . offsetTop ; that . drag ( offsetY ) ; } this . dom [ 0 ] . addEventListener ( "touchmove" , drag ) ; this . dom [ 0 ] . addEventListener ( "mousemove" , drag ) ; function endDrag ( ) { that . endDrag ( ) ; } this . dom [ 0 ] . addEventListener ( "touchend" , endDrag ) ; this . dom [ 0 ] . addEventListener ( "mouseup" , endDrag ) ; this . dom [ 0 ] . addEventListener ( "mouseleave" , endDrag ) ; this . initMouseWheel ( ) ; this . setSuffix ( col . suffix ) ; this . setPrefix ( col . prefix ) ; this . setOptions ( col . options , null , true ) ; } param { number } offsetY startDrag ( offsetY ) { this . lastY = ( constant . WHEEL_HEIGHT / 2 - offsetY / this . em ( ) ) * - 1 ; this . timeStamp = Date . now ( ) ; this . isDraging = true ; this . offsetTop = this . dom [ 0 ] . offsetTop ; this . originalDistance = this . distance ; this . changeMaxDistance = 0 ; this . lastIndexDistance = this . selectedIndex ; for ( var parent = this . dom [ 0 ] . parentElement ; parent ; parent = parent . parentElement ) { this . offsetTop += parent . offsetTop ; } animationUtil . stopAnimation ( this . animationId ) ; } param { number } offsetY drag ( offsetY ) { if ( ! this . isDraging ) { return ; } var y = ( constant . WHEEL_HEIGHT / 2 - offsetY / this . em ( ) ) * - 1 ; var changeDistance = this . lastY - y ; var distance = changeDistance + this . distance ; this . changeMaxDistance = Math . max ( Math . abs ( this . originalDistance - distance ) , this . changeMaxDistance ) ; this . setDistance ( distance ) ; this . lastY = y ; if ( changeDistance ) { this . speed = changeDistance / ( Date . now ( ) - this . timeStamp ) ; } else { this . speed = 0 ; } this . timeStamp = Date . now ( ) ; } /**
     * 拖拽结束
     */ endDrag ( ) { if ( ! this . isDraging ) { return ; } var changeDistance = this . speed * Math . abs ( this . speed ) * 8 * constant . WHEEL_TRANSITION_TIME ; var distance = changeDistance + this . distance ; var selectedIndex = this . calcSelectedIndexByDistance ( distance ) ; this . selectIndex ( selectedIndex , true ) ; this . isDraging = false ; this . lastY = 0 ; this . speed = 0 ; } param { any [ ] } list param { * } selectedValue param { boolean } isInti setOptions ( list , selectedValue , isInti = false ) { var that = this ; list = list || [ ] ; if ( Array . isArray ( list ) ) { that . contains . html ( "" ) ; this . list = list ; } else { throw new TypeError ( "list is not a array." ) ; } this . valueHashMap = { } ; this . maxDistance = constant . WHEEL_ITEM_HIGHT * ( Math . max ( 0 , this . list . length - 1 ) ) ; var i = 0 , label ; this . list . forEach ( function ( item , index ) { if ( typeof item === 'object' ) { label = item [ that . labelKey ] ; that . valueHashMap [ item [ that . itemValueKey ] ] = i ; } else { label = item ; that . valueHashMap [ item ] = i ; } var li = $ ( "<li></li>" ) . css ( 'top' , `${ constant . WHEEL_ITEM_HIGHT / 100 * i }em` ) ; li . append ( $ ( '<span class="picker-text"></span>' ) . text ( label ) ) ; var distance = constant . WHEEL_ITEM_HIGHT * - index ; li . data ( "distance" , distance ) ; li . data ( "index" , i ) ; that . contains . append ( li ) ; var clickHandle = function ( event ) { if ( that . changeMaxDistance < 0.1 ) { that . isDraging = false ; that . lastY = 0 ; that . speed = 0 ; that . selectIndex ( index , true ) ; event . stopPropagation ( ) ; event . preventDefault ( ) ; } } ; li [ 0 ] . addEventListener ( 'mouseup' , clickHandle ) ; li [ 0 ] . addEventListener ( 'touchend' , clickHandle ) ; i ++ ; } ) ; if ( isInti ) { if ( list . length > 0 ) { this . selectedIndex = 0 ; if ( typeof list [ 0 ] === 'object' ) { this . selectedValue = this . list [ 0 ] [ this . itemValueKey ] ; } else { this . selectedValue = this . list [ 0 ] ; } } else { this . selectedIndex = - 1 ; this . selectedValue = undefined ; } return ; } if ( list . length > 0 ) { if ( selectedValue != null && this . valueHashMap [ selectedValue ] != null ) { this . selectOption ( selectedValue ) ; } else if ( this . valueHashMap [ this . selectedValue ] != null ) { this . selectOption ( this . selectedValue ) ; } else { this . selectIndex ( 0 ) ; } } else { this . selectedIndex = - 1 ; this . selectedValue = undefined ; } } param index param showAnimation protected selectIndex ( index , showAnimation = false ) { var distance = this . calcDistanceBySelectedIndex ( index ) ; animationUtil . stopAnimation ( this . animationId ) ; if ( showAnimation ) { var start = 0 , during = 50 , that = this ; var _run = function ( ) { start ++ ; var _Distance = animationUtil . easeOut ( start , that . distance , distance - that . distance , during ) ; if ( Math . abs ( _Distance - distance ) < 1 ) { _Distance = distance ; } that . setDistance ( _Distance ) ; if ( _Distance != distance ) { that . animationId = animationUtil . startAnimation ( _run ) ; } else { var oldSelectedIndex = that . selectedIndex ; that . selectedIndex = index ; that . selectedValue = that . list [ index ] ; if ( typeof that . selectedValue == 'object' ) { that . selectedValue = that . selectedValue [ that . itemValueKey ] ; } if ( oldSelectedIndex != that . selectedIndex ) that . toggleSelected ( that . selectedIndex , that . selectedValue ) ; } } ; that . animationId = animationUtil . startAnimation ( _run ) ; } else { var oldSelectedIndex = this . selectedIndex ; this . setDistance ( distance ) ; this . selectedIndex = index ; this . selectedValue = this . list [ index ] ; if ( typeof this . selectedValue == 'object' ) { this . selectedValue = this . selectedValue [ this . itemValueKey ] ; } if ( oldSelectedIndex != this . selectedIndex ) this . toggleSelected ( this . selectedIndex , this . selectedValue ) ; } } param { number } distance returns { number } private setDistance ( distance ) { distance = this . rangeDistance ( distance ) ; if ( this . option . hasVoice && this . picker . visible ) { var lastIndexDistance = this . lastIndexDistance ; var index = this . calcSelectedIndexByDistance ( distance ) ; if ( lastIndexDistance != index ) { if ( this . option . hasVoice ) { tick . play ( ) ; } } this . lastIndexDistance = index ; } var translateValue = "translate3d(0, " + ( constant . WHEEL_HEIGHT / 2 - constant . WHEEL_ITEM_HIGHT / 2 - distance ) / 100 + "em, 0)" ; this . contains . css ( "-webkit-transform" , translateValue ) . css ( "transform" , translateValue ) ; this . distance = distance ; return distance ; } param distance { number } returns { number } private calcSelectedIndexByDistance ( distance ) { distance = this . rangeDistance ( distance ) ; return Math . round ( Math . abs ( distance / constant . WHEEL_ITEM_HIGHT ) ) ; } param Distance { number } returns { number } private calcDistanceBySelectedIndex ( index ) { return index * constant . WHEEL_ITEM_HIGHT ; } param distance { number } returns { number } private rangeDistance ( distance ) { distance = Math . max ( this . minDistance , distance ) ; distance = Math . min ( this . maxDistance , distance ) ; return distance ; } /**
    * 获取被选值
    */ getValue ( ) { return this . selectedValue ; } param text private setSuffix ( text ) { this . dom . find ( '.picker-label .picker-text' ) . eq ( 1 ) . text ( text ) ; } param text private setPrefix ( text ) { this . dom . find ( '.picker-label .picker-text' ) . eq ( 0 ) . text ( text ) ; } }