import React , { Component } from 'react' ; import { View , StyleSheet , PanResponder , PanResponderInstance , GestureResponderEvent , PanResponderGestureState , StyleProp , TextStyle , ViewStyle , } from 'react-native' ; import { Utils } from 'tuya-panel-kit' ; import Bright from './Bright' ; import Temperature from './Temp' ; const { convertX : cx } = Utils . RatioUtils ; interface White { temperature : number ; brightness : number ; } interface Position { x : number ; y : number ; dx ? : number ; dy ? : number ; } const defaultProps = { /**
     * 值
     */ value : { temperature : 0 , brightness : 1000 } as White , /**
     * 最小亮度
     */ minBright : 10 , /**
     * 最大亮度
     */ maxBright : 1000 , /**
     * 亮度步长
     */ stepBright : 1 , /**
     * 最小色温
     */ minTemperaure : 0 , /**
     * 最大色温
     */ maxTemperaure : 1000 , /**
     * 色温步长
     */ stepTemperaure : 1 , /**
     * 组件尺寸
     */ size : cx ( 344 ) , /**
     * 轨道宽度
     */ trackWidth : cx ( 27 ) , /**
     * 亮度label
     */ brightLabel : 'Brightness' , /**
     * 彩光label
     */ temperatureLabel : 'Temperature' , /**
     * 是否禁用
     */ disabled : false , param v onGrant ( v ) { } , param v onMove ( v ) { } , param v onRelease ( v ) { } , param v onChange ( v ) { } , } ; type Props = { /**
     * 组件样式
     */ style ? : StyleProp < ViewStyle > ; /**
     * 组件文字样式
     */ textStyle ? : StyleProp < TextStyle > ; /**
     * 格式化百分比
     */ formatPercent ? : ( v : number ) => number ; } & Readonly < typeof defaultProps > ; export default class HueBrightSlider extends Component < Props > { static defaultProps = defaultProps ; constructor ( props ) { super ( props ) ; this . tempValue = this . props . value ; this . position . x = this . brightToCoor ( this . tempValue . brightness ) ; this . position . y = this . brightToCoor ( this . tempValue . temperature ) ; this . panResponder = PanResponder . create ( { onStartShouldSetPanResponder : this . handleStartPanResponder , onPanResponderTerminationRequest : ( ) => ! this . moving , onPanResponderGrant : this . onGrant , onPanResponderMove : this . onMove , onPanResponderRelease : this . onRelease , onPanResponderReject : this . handleTerminate , onPanResponderTerminate : this . handleTerminate , } ) ; } componentWillReceiveProps ( nextProps ) { if ( ! this . locked ) { const { value : { temperature , brightness } , } = nextProps ; this . position . x = this . brightToCoor ( brightness ) ; this . position . y = this . temperatureToCoor ( temperature ) ; } } shouldComponentUpdate ( ) { return ! this . locked ; } onGrant = ( e ) => { this . props . onGrant ( this . props . value ) ; this . moving = true ; this . locked = true ; } ; onMove = ( e , gesture ) => { if ( this . moving ) { const { dx , dy } = gesture ; if ( this . direction !== 0 ) { const { locationX , locationY } = e . nativeEvent ; this . handleMove ( { x : locationX , y : locationY , dx , dy } , this . props . onMove , false ) ; } else if ( Math . abs ( dx ) > 10 ) { this . direction = 1 ; } else if ( Math . abs ( dy ) > 10 ) { this . direction = - 1 ; } } } ; onRelease = ( e , gesture ) => { if ( this . moving && this . direction !== 0 ) { const { locationX , locationY } = e . nativeEvent ; const { dx , dy } = gesture ; this . handleMove ( { x : locationX , y : locationY , dx , dy } , this . props . onRelease , true ) ; } this . direction = 0 ; this . moving = false ; this . locked = false ; } ; private panResponder : PanResponderInstance ; private moving = false ; private locked = false ; private direction : 1 | - 1 | 0 = 0 ; private tempValue : White ; private brightRef : Bright ; private temperatureRef : Temperature ; private position : Position = { x : 0 , y : 0 } ; handleStartPanResponder = ( e ) => { if ( this . props . disabled ) { return false ; } return true ; } ; handleTerminate = ( ) => { this . moving = false ; this . locked = false ; } ; handleMove ( pos , callback , isEnd = false ) { const { direction } = this ; const { onChange , value , size } = this . props ; const isHorizontal = direction === 1 ; const { dx , dy } = pos ; const temp = { ... value } ; if ( isHorizontal ) { const x = Math . min ( size , Math . max ( this . position . x + dx , 0 ) ) ; const bright = this . coorToBright ( x ) ; this . brightRef . update ( bright ) ; temp . brightness = bright ; if ( isEnd ) { this . position . x = this . brightToCoor ( bright ) ; } } else { const y = Math . min ( size , Math . max ( this . position . y + dy , 0 ) ) ; const hue = this . coorToTemperature ( y ) ; this . temperatureRef . update ( hue ) ; temp . temperature = hue ; if ( isEnd ) { this . position . y = this . temperatureToCoor ( hue ) ; } } if ( this . notEqualColour ( temp , this . tempValue ) ) { this . tempValue = temp ; onChange ( temp ) ; } callback ( temp ) ; } notEqualColour ( c1 , c2 ) { return c1 . brightness !== c2 . brightness || c1 . temperature !== c2 . temperature ; } coorToBright ( x ) { const { minBright , maxBright , stepBright , size } = this . props ; const bright = ( x * ( maxBright - minBright ) ) / size ; return Math . min ( maxBright , Math . round ( bright / stepBright ) * stepBright + minBright ) ; } brightToCoor ( bright ) { const { minBright , maxBright , size } = this . props ; return ( ( bright - minBright ) * size ) / ( maxBright - minBright ) ; } coorToTemperature ( y ) { const { size , minTemperaure , maxTemperaure , stepTemperaure } = this . props ; const bright = ( 1 - y / size ) * ( maxTemperaure - minTemperaure ) ; return Math . min ( maxTemperaure , Math . round ( bright / stepTemperaure ) * stepTemperaure + minTemperaure ) ; } temperatureToCoor ( temp ) { const { size , minTemperaure , maxTemperaure } = this . props ; return ( 1 - ( temp - minTemperaure ) / ( maxTemperaure - minTemperaure ) ) * size ; } render ( ) { const { size , textStyle , brightLabel , temperatureLabel , formatPercent , trackWidth , value , minBright , maxBright , minTemperaure , maxTemperaure , } = this . props ; return ( < View style = { [ styles . container , { width : size + 16 , height : size + 16 } ] } pointerEvents = "box-only" { ... this . panResponder . panHandlers } > < Bright ref = { ( ref ) => { this . brightRef = ref ; } } label = { brightLabel } textStyle = { textStyle } trackWidth = { trackWidth } size = { size } bright = { value . brightness } min = { minBright } max = { maxBright } formatPercent = { formatPercent } / > < View style = { { position : 'absolute' , height : size + 16 , justifyContent : 'center' } } > < Temperature ref = { ( ref ) => { this . temperatureRef = ref ; } } label = { temperatureLabel } textStyle = { textStyle } trackWidth = { trackWidth } size = { size } temp = { value . temperature } min = { minTemperaure } max = { maxTemperaure } / > < /View> < /View>); } } const styles = StyleSheet . create ( { container : { alignItems : 'center' , justifyContent : 'center' , } , } ) ;