// 平滑过度选项@objcpublicenumChartEasingOption:Int{caseLinearcaseEaseInQuadcaseEaseOutQuadcaseEaseInOutQuadcaseEaseInCubiccaseEaseOutCubiccaseEaseInOutCubiccaseEaseInQuartcaseEaseOutQuartcaseEaseInOutQuartcaseEaseInQuintcaseEaseOutQuintcaseEaseInOutQuintcaseEaseInSinecaseEaseOutSinecaseEaseInOutSinecaseEaseInExpocaseEaseOutExpocaseEaseInOutExpocaseEaseInCirccaseEaseOutCirccaseEaseInOutCirccaseEaseInElasticcaseEaseOutElasticcaseEaseInOutElasticcaseEaseInBackcaseEaseOutBackcaseEaseInOutBackcaseEaseInBouncecaseEaseOutBouncecaseEaseInOutBounce}// elapsed: v. 时间过去;消逝(elapse的过去分词)// duration: n. 持续,持续的时间,期间publictypealiasChartEasingFunctionBlock=((elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloat)// 根据动画过渡类型,获取动画函数internalfunceasingFunctionFromOption(easing:ChartEasingOption)->ChartEasingFunctionBlock{switcheasing{case.Linear:returnEasingFunctions.Linearcase.EaseInQuad:returnEasingFunctions.EaseInQuadcase.EaseOutQuad:returnEasingFunctions.EaseOutQuadcase.EaseInOutQuad:returnEasingFunctions.EaseInOutQuadcase.EaseInCubic:returnEasingFunctions.EaseInCubiccase.EaseOutCubic:returnEasingFunctions.EaseOutCubiccase.EaseInOutCubic:returnEasingFunctions.EaseInOutCubiccase.EaseInQuart:returnEasingFunctions.EaseInQuartcase.EaseOutQuart:returnEasingFunctions.EaseOutQuartcase.EaseInOutQuart:returnEasingFunctions.EaseInOutQuartcase.EaseInQuint:returnEasingFunctions.EaseInQuintcase.EaseOutQuint:returnEasingFunctions.EaseOutQuintcase.EaseInOutQuint:returnEasingFunctions.EaseInOutQuintcase.EaseInSine:returnEasingFunctions.EaseInSinecase.EaseOutSine:returnEasingFunctions.EaseOutSinecase.EaseInOutSine:returnEasingFunctions.EaseInOutSinecase.EaseInExpo:returnEasingFunctions.EaseInExpocase.EaseOutExpo:returnEasingFunctions.EaseOutExpocase.EaseInOutExpo:returnEasingFunctions.EaseInOutExpocase.EaseInCirc:returnEasingFunctions.EaseInCirccase.EaseOutCirc:returnEasingFunctions.EaseOutCirccase.EaseInOutCirc:returnEasingFunctions.EaseInOutCirccase.EaseInElastic:returnEasingFunctions.EaseInElasticcase.EaseOutElastic:returnEasingFunctions.EaseOutElasticcase.EaseInOutElastic:returnEasingFunctions.EaseInOutElasticcase.EaseInBack:returnEasingFunctions.EaseInBackcase.EaseOutBack:returnEasingFunctions.EaseOutBackcase.EaseInOutBack:returnEasingFunctions.EaseInOutBackcase.EaseInBounce:returnEasingFunctions.EaseInBouncecase.EaseOutBounce:returnEasingFunctions.EaseOutBouncecase.EaseInOutBounce:returnEasingFunctions.EaseInOutBounce}}// 平滑过度函数internalstructEasingFunctions{internalstaticletLinear={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinreturnCGFloat(elapsed/duration);}internalstaticletEaseInQuad={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)returnposition*position}internalstaticletEaseOutQuad={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)return-position*(position-2.0)}internalstaticletEaseInOutQuad={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/(duration/2.0))if(position<1.0){return0.5*position*position}return-0.5*((--position)*(position-2.0)-1.0)}internalstaticletEaseInCubic={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)returnposition*position*position}internalstaticletEaseOutCubic={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)position--return(position*position*position+1.0)}internalstaticletEaseInOutCubic={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/(duration/2.0))if(position<1.0){return0.5*position*position*position}position-=2.0return0.5*(position*position*position+2.0)}internalstaticletEaseInQuart={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)returnposition*position*position*position}internalstaticletEaseOutQuart={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)position--return-(position*position*position*position-1.0)}internalstaticletEaseInOutQuart={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/(duration/2.0))if(position<1.0){return0.5*position*position*position*position}position-=2.0return-0.5*(position*position*position*position-2.0)}internalstaticletEaseInQuint={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)returnposition*position*position*position*position}internalstaticletEaseOutQuint={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)position--return(position*position*position*position*position+1.0)}internalstaticletEaseInOutQuint={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/(duration/2.0))if(position<1.0){return0.5*position*position*position*position*position}else{position-=2.0return0.5*(position*position*position*position*position+2.0)}}internalstaticletEaseInSine={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition:NSTimeInterval=elapsed/durationreturnCGFloat(-cos(position*M_PI_2)+1.0)}internalstaticletEaseOutSine={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition:NSTimeInterval=elapsed/durationreturnCGFloat(sin(position*M_PI_2))}internalstaticletEaseInOutSine={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition:NSTimeInterval=elapsed/durationreturnCGFloat(-0.5*(cos(M_PI*position)-1.0))}internalstaticletEaseInExpo={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinreturn(elapsed==0)?0.0:CGFloat(pow(2.0,10.0*(elapsed/duration-1.0)))}internalstaticletEaseOutExpo={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinreturn(elapsed==duration)?1.0:(-CGFloat(pow(2.0,-10.0*elapsed/duration))+1.0)}internalstaticletEaseInOutExpo={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinif(elapsed==0){return0.0}if(elapsed==duration){return1.0}varposition:NSTimeInterval=elapsed/(duration/2.0)if(position<1.0){returnCGFloat(0.5*pow(2.0,10.0*(position-1.0)))}returnCGFloat(0.5*(-pow(2.0,-10.0*--position)+2.0))}internalstaticletEaseInCirc={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)return-(CGFloat(sqrt(1.0-position*position))-1.0)}internalstaticletEaseOutCirc={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition=CGFloat(elapsed/duration)position--returnCGFloat(sqrt(1-position*position))}internalstaticletEaseInOutCirc={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition:NSTimeInterval=elapsed/(duration/2.0)if(position<1.0){returnCGFloat(-0.5*(sqrt(1.0-position*position)-1.0))}position-=2.0returnCGFloat(0.5*(sqrt(1.0-position*position)+1.0))}internalstaticletEaseInElastic={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinif(elapsed==0.0){return0.0}varposition:NSTimeInterval=elapsed/durationif(position==1.0){return1.0}varp=duration*0.3vars=p/(2.0*M_PI)*asin(1.0)position-=1.0returnCGFloat(-(pow(2.0,10.0*position)*sin((position*duration-s)*(2.0*M_PI)/p)))}internalstaticletEaseOutElastic={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinif(elapsed==0.0){return0.0}varposition:NSTimeInterval=elapsed/durationif(position==1.0){return1.0}varp=duration*0.3vars=p/(2.0*M_PI)*asin(1.0)returnCGFloat(pow(2.0,-10.0*position)*sin((position*duration-s)*(2.0*M_PI)/p)+1.0)}internalstaticletEaseInOutElastic={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinif(elapsed==0.0){return0.0}varposition:NSTimeInterval=elapsed/(duration/2.0)if(position==2.0){return1.0}varp=duration*(0.3*1.5)vars=p/(2.0*M_PI)*asin(1.0)if(position<1.0){position-=1.0returnCGFloat(-0.5*(pow(2.0,10.0*position)*sin((position*duration-s)*(2.0*M_PI)/p)))}position-=1.0returnCGFloat(pow(2.0,-10.0*position)*sin((position*duration-s)*(2.0*M_PI)/p)*0.5+1.0)}internalstaticletEaseInBack={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinlets:NSTimeInterval=1.70158varposition:NSTimeInterval=elapsed/durationreturnCGFloat(position*position*((s+1.0)*position-s))}internalstaticletEaseOutBack={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinlets:NSTimeInterval=1.70158varposition:NSTimeInterval=elapsed/durationposition--returnCGFloat((position*position*((s+1.0)*position+s)+1.0))}internalstaticletEaseInOutBack={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvars:NSTimeInterval=1.70158varposition:NSTimeInterval=elapsed/(duration/2.0)if(position<1.0){s*=1.525returnCGFloat(0.5*(position*position*((s+1.0)*position-s)))}s*=1.525position-=2.0returnCGFloat(0.5*(position*position*((s+1.0)*position+s)+2.0))}internalstaticletEaseInBounce={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinreturn1.0-EaseOutBounce(duration-elapsed,duration)}internalstaticletEaseOutBounce={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinvarposition:NSTimeInterval=elapsed/durationif(position<(1.0/2.75)){returnCGFloat(7.5625*position*position)}elseif(position<(2.0/2.75)){position-=(1.5/2.75)returnCGFloat(7.5625*position*position+0.75)}elseif(position<(2.5/2.75)){position-=(2.25/2.75)returnCGFloat(7.5625*position*position+0.9375)}else{position-=(2.625/2.75)returnCGFloat(7.5625*position*position+0.984375)}}internalstaticletEaseInOutBounce={(elapsed:NSTimeInterval,duration:NSTimeInterval)->CGFloatinif(elapsed<(duration/2.0)){returnEaseInBounce(elapsed*2.0,duration)*0.5}returnEaseOutBounce(elapsed*2.0-duration,duration)*0.5+0.5}}
ChartAnimator
@objcpublicprotocolChartAnimatorDelegate{/// Called when the Animator has stepped./// 动画执行时调用funcchartAnimatorUpdated(chartAnimator:ChartAnimator)/// Called when the Animator has stopped./// 动画结束时调用funcchartAnimatorStopped(chartAnimator:ChartAnimator)}publicclassChartAnimator:NSObject{publicweakvardelegate:ChartAnimatorDelegate?publicvarupdateBlock:(()->Void)?publicvarstopBlock:(()->Void)?/// the phase that is animated and influences the drawn values on the y-axis/// x相位 影响y轴绘值publicvarphaseX:CGFloat=1.0/// the phase that is animated and influences the drawn values on the y-axis/// y相位 影响y轴绘值publicvarphaseY:CGFloat=1.0privatevar_startTime:NSTimeInterval=0.0privatevar_displayLink:CADisplayLink!privatevar_xDuration:NSTimeInterval=0.0privatevar_yDuration:NSTimeInterval=0.0privatevar_endTimeX:NSTimeInterval=0.0privatevar_endTimeY:NSTimeInterval=0.0privatevar_endTime:NSTimeInterval=0.0privatevar_enabledX:Bool=falseprivatevar_enabledY:Bool=falseprivatevar_easingX:ChartEasingFunctionBlock?privatevar_easingY:ChartEasingFunctionBlock?publicoverrideinit(){super.init()}deinit{stop()}publicfuncstop(){if(_displayLink!=nil){_displayLink.removeFromRunLoop(NSRunLoop.mainRunLoop(),forMode:NSRunLoopCommonModes)_displayLink=nil_enabledX=false_enabledY=falseif(delegate!=nil){delegate!.chartAnimatorStopped(self)}if(stopBlock!=nil){stopBlock?()}}}privatefuncupdateAnimationPhases(currentTime:NSTimeInterval){varelapsedTime:NSTimeInterval=currentTime-_startTimeif(_enabledX){varduration:NSTimeInterval=_xDurationvarelapsed:NSTimeInterval=elapsedTimeif(elapsed>duration){elapsed=duration}if(_easingX!=nil){phaseX=_easingX!(elapsed:elapsed,duration:duration)}else{phaseX=CGFloat(elapsed/duration)}}if(_enabledY){varduration:NSTimeInterval=_yDurationvarelapsed:NSTimeInterval=elapsedTimeif(elapsed>duration){elapsed=duration}if(_easingY!=nil){phaseY=_easingY!(elapsed:elapsed,duration:duration)}else{phaseY=CGFloat(elapsed/duration)}}}@objcprivatefuncanimationLoop(){varcurrentTime:NSTimeInterval=CACurrentMediaTime()updateAnimationPhases(currentTime)if(delegate!=nil){delegate!.chartAnimatorUpdated(self)}if(updateBlock!=nil){updateBlock!()}if(currentTime>=_endTime){stop()}}/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axis/// :param: yAxisDuration duration for animating the y axis/// :param: easingX an easing function for the animation on the x axis/// :param: easingY an easing function for the animation on the y axispublicfuncanimate(#xAxisDuration:NSTimeInterval,yAxisDuration:NSTimeInterval,easingX:ChartEasingFunctionBlock?,easingY:ChartEasingFunctionBlock?){stop()_displayLink=CADisplayLink(target:self,selector:Selector("animationLoop"))_startTime=CACurrentMediaTime()_xDuration=xAxisDuration_yDuration=yAxisDuration_endTimeX=_startTime+xAxisDuration_endTimeY=_startTime+yAxisDuration_endTime=_endTimeX>_endTimeY?_endTimeX:_endTimeY_enabledX=xAxisDuration>0.0_enabledY=yAxisDuration>0.0_easingX=easingX_easingY=easingY// Take care of the first frame if rendering is already scheduled...updateAnimationPhases(_startTime)if(_enabledX||_enabledY){_displayLink.addToRunLoop(NSRunLoop.mainRunLoop(),forMode:NSRunLoopCommonModes)}}/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axis/// :param: yAxisDuration duration for animating the y axis/// :param: easingOptionX the easing function for the animation on the x axis/// :param: easingOptionY the easing function for the animation on the y axispublicfuncanimate(#xAxisDuration:NSTimeInterval,yAxisDuration:NSTimeInterval,easingOptionX:ChartEasingOption,easingOptionY:ChartEasingOption){animate(xAxisDuration:xAxisDuration,yAxisDuration:yAxisDuration,easingX:easingFunctionFromOption(easingOptionX),easingY:easingFunctionFromOption(easingOptionY))}/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axis/// :param: yAxisDuration duration for animating the y axis/// :param: easing an easing function for the animationpublicfuncanimate(#xAxisDuration:NSTimeInterval,yAxisDuration:NSTimeInterval,easing:ChartEasingFunctionBlock?){animate(xAxisDuration:xAxisDuration,yAxisDuration:yAxisDuration,easingX:easing,easingY:easing)}/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axis/// :param: yAxisDuration duration for animating the y axis/// :param: easingOption the easing function for the animationpublicfuncanimate(#xAxisDuration:NSTimeInterval,yAxisDuration:NSTimeInterval,easingOption:ChartEasingOption){animate(xAxisDuration:xAxisDuration,yAxisDuration:yAxisDuration,easing:easingFunctionFromOption(easingOption))}/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axis/// :param: yAxisDuration duration for animating the y axispublicfuncanimate(#xAxisDuration:NSTimeInterval,yAxisDuration:NSTimeInterval){animate(xAxisDuration:xAxisDuration,yAxisDuration:yAxisDuration,easingOption:.EaseInOutSine)}/// Animates the drawing / rendering of the chart the x-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axis/// :param: easing an easing function for the animationpublicfuncanimate(#xAxisDuration:NSTimeInterval,easing:ChartEasingFunctionBlock?){animate(xAxisDuration:xAxisDuration,yAxisDuration:0.0,easing:easing)}/// Animates the drawing / rendering of the chart the x-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axis/// :param: easingOption the easing function for the animationpublicfuncanimate(#xAxisDuration:NSTimeInterval,easingOption:ChartEasingOption){animate(xAxisDuration:xAxisDuration,yAxisDuration:0.0,easing:easingFunctionFromOption(easingOption))}/// Animates the drawing / rendering of the chart the x-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: xAxisDuration duration for animating the x axispublicfuncanimate(#xAxisDuration:NSTimeInterval){animate(xAxisDuration:xAxisDuration,yAxisDuration:0.0,easingOption:.EaseInOutSine)}/// Animates the drawing / rendering of the chart the y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: yAxisDuration duration for animating the y axis/// :param: easing an easing function for the animationpublicfuncanimate(#yAxisDuration:NSTimeInterval,easing:ChartEasingFunctionBlock?){animate(xAxisDuration:0.0,yAxisDuration:yAxisDuration,easing:easing)}/// Animates the drawing / rendering of the chart the y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: yAxisDuration duration for animating the y axis/// :param: easingOption the easing function for the animationpublicfuncanimate(#yAxisDuration:NSTimeInterval,easingOption:ChartEasingOption){animate(xAxisDuration:0.0,yAxisDuration:yAxisDuration,easing:easingFunctionFromOption(easingOption))}/// Animates the drawing / rendering of the chart the y-axis with the specified animation time./// If animate(...) is called, no further calling of invalidate() is necessary to refresh the chart./// :param: yAxisDuration duration for animating the y axispublicfuncanimate(#yAxisDuration:NSTimeInterval){animate(xAxisDuration:0.0,yAxisDuration:yAxisDuration,easingOption:.EaseInOutSine)}}