import { Updater } from "./Updater" ; import { ParamUpdater } from "./ParamUpdater" ; import { HTMLUtil } from "../../utils/HTMLUtil" ; import { StyleColorUpdater } from "./StyleColorUpdater" ; import { ColorUtil } from "../../utils/ColorUtil" ; export class StyleUpdater implements Updater { static className : string = "StyleUpdater" ; static readonly PARAM_REG : RegExp = new RegExp ( /^[0-9.]*/ ) ; static readonly UNIT_REG : RegExp = new RegExp ( /[^0-9.].*/ ) ; private _target : HTMLElement ; private _query : string | null ; private _param : { [ key ] : ParamUpdater | StyleColorUpdater ; } ; private _key : string [ ] ; private _unit : { [ key ] : string ; } ; private _tweenKey : string [ ] | null ; private _onceParam : { [ key ] : string ; } | null ; private _isUpdatedOnce : boolean ; private _pseudo : string | null ; private _style : CSSStyleDeclaration | undefined ; private _useWillChange : boolean ; constructor ( target , query ) { this . _target = target ; this . _query = query ; this . _param ||= { } ; this . _key ||= [ ] ; this . _unit ||= { } ; this . _tweenKey = null ; this . _onceParam = null ; this . _isUpdatedOnce = false ; this . _pseudo = this . _query ? HTMLUtil . getPseudoQuery ( this . _query ) : null ; this . _useWillChange = false ; } addPropStr ( key , value ) { const val = String ( value ) . match ( StyleUpdater . PARAM_REG ) ; const unit = String ( value ) . match ( StyleUpdater . UNIT_REG ) ; if ( ColorUtil . isColorCode ( value ) ) { this . _param [ key ] = new StyleColorUpdater ( key , value ) ; this . _key . push ( key ) ; } else if ( val ) { const original = this . _target . style . getPropertyValue ( key ) ; this . _target . style . setProperty ( key , value ) ; const targetValue = HTMLUtil . getComputedStyle ( this . _target ) . getPropertyValue ( key ) ; this . _target . style . setProperty ( key , original ) ; const targetUnit = targetValue . match ( StyleUpdater . UNIT_REG ) ; this . _param [ key ] = new ParamUpdater ( key , parseInt ( targetValue ) ) ; this . _unit [ key ] = targetUnit ? targetUnit [ 0 ] : "" ; this . _key . push ( key ) ; } else { this . _onceParam ||= { } ; this . _onceParam [ key ] = value ; } } init ( useWillChange ) { this . _useWillChange = useWillChange ; if ( ! this . _style && this . _pseudo && this . _query ) { this . _style = HTMLUtil . getAddedStyleByElement ( this . _target , this . _pseudo ) ; } this . _isUpdatedOnce = false ; this . _tweenKey = this . _key . concat ( ) ; for ( const key of this . _tweenKey ) { const value = HTMLUtil . getComputedStyle ( this . _target , this . _pseudo ) . getPropertyValue ( key ) ; if ( ColorUtil . isColorCode ( value ) ) { ( this . _param [ key ] as StyleColorUpdater ) . init ( value ) ; this . _unit [ key ] ||= "" ; } else { const val = value . match ( StyleUpdater . PARAM_REG ) ; const unit = value . match ( StyleUpdater . UNIT_REG ) ; this . _unit [ key ] ||= unit && val && val [ 0 ] . length ? unit [ 0 ] : "" ; ( this . _param [ key ] as ParamUpdater ) . init ( Number ( val ? val : 0 ) ) ; } } if ( this . _useWillChange ) { HTMLUtil . addWillChange ( this . _style || this . _target . style , this . _key ) ; } } update ( progress ) { if ( ! this . _isUpdatedOnce ) { for ( const key in this . _onceParam ) { const value = this . _onceParam [ key ] ; if ( this . _style ) this . _style . setProperty ( key , value ) ; else HTMLUtil . setStyleProp ( this . _target , key , value ) ; } this . _isUpdatedOnce = true ; } if ( this . _tweenKey ) { for ( const key of this . _tweenKey ) { const value = this . _param [ key ] . update ( progress ) + this . _unit [ key ] ; if ( this . _style ) this . _style . setProperty ( key , value ) ; else HTMLUtil . setStyleProp ( this . _target , key , value ) ; } } if ( progress == 1 ) this . complete ( ) ; } overwrite ( updater ) { if ( this . _target == updater . _target ) { const targetKey = updater . _tweenKey ; if ( this . _tweenKey && targetKey ) { for ( const key of targetKey ) { const i = this . _tweenKey . indexOf ( key ) ; if ( i > - 1 ) this . _tweenKey . splice ( i , 1 ) ; } } } } getMaxAbsDelta ( ) { const deltas = [ ] ; if ( this . _param ) { for ( const key in this . _param ) deltas . push ( Math . abs ( this . _param [ key ] . getDelta ( ) ) ) ; } return Math . max ( ... deltas ) ; } clone ( target = this . _target , query = this . _query ) { const copy = new StyleUpdater ( target , query ) ; if ( this . _param ) { copy . _param = { } ; for ( const key in this . _param ) copy . _param [ key ] = this . _param [ key ] . clone ( ) ; } if ( this . _key ) copy . _key = [ ... this . _key ] ; if ( this . _unit ) copy . _unit = { ... this . _unit } ; if ( this . _onceParam ) copy . _onceParam = { ... this . _onceParam } ; return copy ; } toString ( ) { let str = "" ; if ( this . _param && this . _key ) for ( const key of this . _key ) str += this . _param [ key ] . toString ( ) + " " ; for ( const key in this . _onceParam ) str += key + ":" + this . _onceParam [ key ] . toString ( ) + " " ; return str . trim ( ) ; } addProp ( key , value ) { } complete ( ) { if ( this . _useWillChange ) { HTMLUtil . removeWillChange ( this . _style || this . _target . style , this . _key ) ; } } }