import React , { Component } from 'react' ; import _ from 'lodash' ; import { View , ViewStyle } from 'react-native' ; import StorageUtils from '../../../utils/storage' ; import RectPicker , { ValidBound , ILinear , ILinearColors , Point , defaultProps as baseDefualt , } from './RectPicker' ; import Slider , { IBrightOption } from './Slider' ; export interface IWhite { brightness : number ; temperature : number ; } const defaultProps = { ... baseDefualt , brightOption : { } as IBrightOption , value : { brightness : 500 , temperature : 500 } as IWhite , lossSliderColor : 'rgba(255,255,255,0.4)' , hideBright : false , version direction : 'leftBottom' as 'leftBottom' | 'leftTop' | 'rightBottom' | 'rightTop' | 'left' | 'right' | 'top' | 'bottom' , bgs : [ { offset : '0%' , stopColor : '#FF9F3E' , stopOpacity : 1 } , { offset : '50%' , stopColor : '#FFFFFF' , stopOpacity : 1 } , { offset : '53%' , stopColor : '#FFFFFF' , stopOpacity : 1 } , { offset : '100%' , stopColor : '#B4D0FF' , stopOpacity : 1 } , ] as ILinearColors [ ] , onGrant ( v , option ? ) { } , onMove ( v , option ? ) { } , onRelease ( v , option ? ) { } , onPress ( v , option ? ) { } , } ; interface TempStorageData { temperature : number ; position : Point ; } type DefaultProps = { style ? : ViewStyle ; rectStyle ? : ViewStyle ; storageKey ? : string ; } & Readonly < typeof defaultProps > ; type WhiteProps = DefaultProps ; let storageKeyIndex = 0 ; export default class WhitePicker extends Component < WhiteProps , IWhite > { static defaultProps = defaultProps ; constructor ( props ) { super ( props ) ; const { storageKey , value : { brightness , temperature } , } = this . props ; this . state = { brightness , temperature } ; if ( ! storageKey ) { this . storageKey = `temperature_key_${ storageKeyIndex ++ }` ; } else { this . storageKey = storageKey ; } } componentWillReceiveProps ( nextProps ) { const { value : { temperature , brightness } , } = nextProps ; if ( temperature !== this . props . value . temperature ) { this . setState ( { temperature } ) ; this . thumbPosition = this . autoTemperaturePosition ( temperature ) ; this . currentTemperature = temperature ; } if ( brightness !== this . props . value . brightness && brightness !== this . state . brightness ) { this . setState ( { brightness } ) ; } } shouldComponentUpdate ( nextProps , nextState ) { return ! _ . isEqual ( nextProps , this . props ) || ! _ . isEqual ( nextState , this . state ) ; } onBrightGrant = ( ) => { const { brightness , temperature } = this . state ; this . firPropsEvent ( this . props . onGrant , { brightness , temperature } , { isChangeBright : true } ) ; } ; onBrightMove = ( brightness ) => { const { temperature } = this . state ; this . firPropsEvent ( this . props . onMove , { temperature , brightness } , { isChangeBright : true } ) ; } ; onBrightRelease = ( brightness ) => { const { temperature } = this . state ; this . setState ( { temperature , brightness } ) ; this . firPropsEvent ( this . props . onRelease , { temperature , brightness } , { isChangeBright : true } ) ; } ; onBrightPress = ( brightness ) => { const { temperature } = this . state ; this . setState ( { temperature , brightness } ) ; this . firPropsEvent ( this . props . onPress , { temperature , brightness } , { isChangeBright : true } ) ; } ; getBgs ( ) { const { direction , bgs } = this . props ; let x1 = '0%' ; let y1 = '100%' ; let x2 = '100%' ; let y2 = '0%' ; switch ( direction ) { case 'leftTop' : x1 = '0%' ; y1 = '0%' ; x2 = '100%' ; y2 = '100%' ; break ; case 'rightBottom' : x1 = '100%' ; y1 = '100%' ; x2 = '0%' ; y2 = '0%' ; break ; case 'rightTop' : x1 = '100%' ; y1 = '0%' ; x2 = '0%' ; y2 = '100%' ; break ; case 'left' : x1 = '0%' ; y1 = '0%' ; x2 = '100%' ; y2 = '0%' ; break ; case 'right' : x1 = '100%' ; y1 = '0%' ; x2 = '0%' ; y2 = '0%' ; break ; case 'top' : x1 = '0%' ; y1 = '0%' ; x2 = '0%' ; y2 = '100%' ; break ; case 'bottom' : x1 = '0%' ; y1 = '100%' ; x2 = '0%' ; y2 = '0%' ; break ; default : break ; } return [ { x1 , y1 , x2 , y2 , colors : bgs } ] as ILinear [ ] ; } getNormalVector ( { width , height , x , y } ) { switch ( this . props . direction ) { case 'leftTop' : return { x : width , y : height , originX : x , originY : y } ; case 'rightBottom' : return { x : - width , y : - height , originX : width + x , originY : height + y } ; case 'rightTop' : return { x : - width , y : height , originX : width + x , originY : y } ; case 'left' : return { x : width , y : 0 , originX : x , originY : height / 2 + y } ; case 'right' : return { x : - width , y : 0 , originX : width + x , originY : height / 2 + y } ; case 'top' : return { x : 0 , y : height , originX : width / 2 + x , originY : y } ; case 'bottom' : return { x : 0 , y : - height , originX : width / 2 + x , originY : height + y } ; default : return { x : width , y : - height , originX : x , originY : height + y } ; } } setValue ( { temperature , brightness } ) { this . thumbPosition = this . autoTemperaturePosition ( temperature ) ; this . currentTemperature = temperature ; this . setState ( { temperature , brightness } ) ; } initData = async ( validBound ) => { let cacheEnabled = true ; if ( ! _ . isEqual ( validBound , this . pickerBound ) ) { cacheEnabled = false ; } const { temperature } = this . state ; const data = ( await StorageUtils . getDevItem ( this . storageKey ) ) as TempStorageData ; if ( data && data . temperature === temperature && cacheEnabled ) { this . thumbPosition = data . position ; this . currentTemperature = temperature ; } else { this . thumbPosition = this . autoTemperaturePosition ( temperature , validBound ) ; this . currentTemperature = temperature ; } this . pickerBound = validBound ; } ; autoTemperaturePosition ( temperature , validBound ? ) { let position ; if ( this . pickerRef ) { position = this . pickerRef . valueToCoor ( { temperature } ) ; } else { position = this . valueToCoor ( { temperature , brightness : this . state . brightness } , null , validBound ) ; } StorageUtils . setDevItem ( this . storageKey , { temperature , position } ) ; return position ; } coorToValue = ( { x , y } , bound ) => { const { brightness } = this . state ; const normalVector = this . getNormalVector ( bound ) ; const vector1 = { x : x - normalVector . originX , y : y - normalVector . originY } ; const total = Math . sqrt ( normalVector . x ** 2 + normalVector . y ** 2 ) ; const diff = ( vector1 . x * normalVector . x + vector1 . y * normalVector . y ) / total ; const temperature = Math . round ( ( diff / total ) * 1000 ) ; return { temperature , brightness } ; } ; handleTemperaturePosition ( temperature , bound ) { const normalVector = this . getNormalVector ( bound ) ; const total = Math . sqrt ( normalVector . x ** 2 + normalVector . y ** 2 ) ; const normal = { x : normalVector . x / total , y : normalVector . y / total } ; const length = total * ( temperature / 1000 ) ; const position = { x : normal . x * length + normalVector . originX , y : normal . y * length + normalVector . originY , } ; StorageUtils . setDevItem ( this . storageKey , { temperature , position } ) ; return position ; } valueToCoor = ( { temperature } , origin , validBound ) : Point => { if ( ! origin ) { let cacheEnabled = true ; if ( ! _ . isEqual ( validBound , this . pickerBound ) ) { cacheEnabled = false ; } if ( this . currentTemperature === temperature && cacheEnabled ) { if ( this . thumbPosition && typeof this . thumbPosition . x === 'number' && this . thumbPosition . x >= 0 ) { return this . thumbPosition ; } } return this . handleTemperaturePosition ( temperature , validBound ) ; } StorageUtils . setDevItem ( this . storageKey , { temperature , position : origin , } ) ; this . currentTemperature = temperature ; this . thumbPosition = origin ; return origin ; } ; valueToColor = ( ) : string => { return 'transparent' ; } ; firPropsEvent ( cb , ... args ) { typeof cb === 'function' && cb ( ... args ) ; } private thumbPosition : Point ; private currentTemperature : number ; private pickerRef : RectPicker ; private storageKey : string ; private pickerBound : ValidBound ; handlePickerGrant = ( ) => { const { temperature , brightness } = this . state ; this . firPropsEvent ( this . props . onGrant , { temperature , brightness } ) ; } ; handlePickerMove = ( white ) => { this . firPropsEvent ( this . props . onMove , white ) ; } ; handlePickerRelease = ( white ) => { this . setState ( { ... white } ) ; this . firPropsEvent ( this . props . onRelease , white ) ; } ; handlePickerPress = ( white ) => { this . setState ( { ... white } ) ; this . firPropsEvent ( this . props . onPress , white ) ; } ; render ( ) { const { style , rectStyle , brightOption , lossShow , lossSliderColor , clickEnabled , hideBright , ... pickerProps } = this . props ; const { temperature , brightness } = this . state ; const sliderProps = { } ; if ( lossShow ) { sliderProps . activeColor = lossSliderColor ; } return ( < View style = { [ { flex : 1 } , style ] } > < RectPicker ref = { ( ref ) => { this . pickerRef = ref ; } } coorToValue = { this . coorToValue } valueToColor = { this . valueToColor } valueToCoor = { this . valueToCoor } value = { { temperature , brightness } } lossShow = { lossShow } clickEnabled = { clickEnabled } { ... pickerProps } bgs = { this . getBgs ( ) } style = { rectStyle } onGrant = { this . handlePickerGrant } onMove = { this . handlePickerMove } onRelease = { this . handlePickerRelease } onPress = { this . handlePickerPress } initData = { this . initData } / > { ! hideBright && ( < Slider { ... brightOption } { ... sliderProps } clickEnabled = { clickEnabled } value = { brightness } onGrant = { this . onBrightGrant } onMove = { this . onBrightMove } onRelease = { this . onBrightRelease } onPress = { this . onBrightPress } / > ) } < /View>); } }