630 lines
20 KiB
C#
630 lines
20 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace XCharts.Runtime
|
||
{
|
||
public enum AnimationType
|
||
{
|
||
/// <summary>
|
||
/// he default. An animation playback mode will be selected according to the actual situation.
|
||
/// |默认。内部会根据实际情况选择一种动画播放方式。
|
||
/// </summary>
|
||
Default,
|
||
/// <summary>
|
||
/// Play the animation from left to right.
|
||
/// |从左往右播放动画。
|
||
/// </summary>
|
||
LeftToRight,
|
||
/// <summary>
|
||
/// Play the animation from bottom to top.
|
||
/// |从下往上播放动画。
|
||
/// </summary>
|
||
BottomToTop,
|
||
/// <summary>
|
||
/// Play animations from the inside out.
|
||
/// |由内到外播放动画。
|
||
/// </summary>
|
||
InsideOut,
|
||
/// <summary>
|
||
/// Play the animation along the path.
|
||
/// |沿着路径播放动画。
|
||
/// </summary>
|
||
AlongPath,
|
||
/// <summary>
|
||
/// Play the animation clockwise.
|
||
/// |顺时针播放动画。
|
||
/// </summary>
|
||
Clockwise,
|
||
}
|
||
|
||
public enum AnimationEasing
|
||
{
|
||
Linear,
|
||
}
|
||
|
||
/// <summary>
|
||
/// the animation of serie.
|
||
/// |动画表现。
|
||
/// </summary>
|
||
[System.Serializable]
|
||
public class AnimationStyle : ChildComponent
|
||
{
|
||
[SerializeField] private bool m_Enable = true;
|
||
[SerializeField] private AnimationType m_Type;
|
||
[SerializeField] private AnimationEasing m_Easting;
|
||
[SerializeField] private int m_Threshold = 2000;
|
||
[SerializeField] private float m_FadeInDuration = 1000;
|
||
[SerializeField] private float m_FadeInDelay = 0;
|
||
[SerializeField] private float m_FadeOutDuration = 1000f;
|
||
[SerializeField] private float m_FadeOutDelay = 0;
|
||
[SerializeField] private bool m_DataChangeEnable = true;
|
||
[SerializeField] private float m_DataChangeDuration = 500;
|
||
[SerializeField] private float m_ActualDuration;
|
||
/// <summary>
|
||
/// 自定义渐入动画延时函数。返回ms值。
|
||
/// </summary>
|
||
public AnimationDelayFunction fadeInDelayFunction;
|
||
/// <summary>
|
||
/// 自定义渐入动画时长函数。返回ms值。
|
||
/// </summary>
|
||
public AnimationDurationFunction fadeInDurationFunction;
|
||
/// <summary>
|
||
/// 自定义渐出动画延时函数。返回ms值。
|
||
/// </summary>
|
||
public AnimationDelayFunction fadeOutDelayFunction;
|
||
/// <summary>
|
||
/// 自定义渐出动画时长函数。返回ms值。
|
||
/// </summary>
|
||
public AnimationDurationFunction fadeOutDurationFunction;
|
||
public AnimationStyleContext context = new AnimationStyleContext();
|
||
|
||
/// <summary>
|
||
/// Whether to enable animation.
|
||
/// |是否开启动画效果。
|
||
/// </summary>
|
||
public bool enable { get { return m_Enable; } set { m_Enable = value; } }
|
||
/// <summary>
|
||
/// The type of animation.
|
||
/// |动画类型。
|
||
/// </summary>
|
||
public AnimationType type { get { return m_Type; } set { m_Type = value; } }
|
||
/// <summary>
|
||
/// Easing method used for the first animation.
|
||
/// |动画的缓动效果。
|
||
/// </summary>
|
||
//public Easing easting { get { return m_Easting; } set { m_Easting = value; } }
|
||
/// <summary>
|
||
/// The milliseconds duration of the fadeIn animation.
|
||
/// |设定的渐入动画时长(毫秒)。如果要设置单个数据项的渐入时长,可以用代码定制:customFadeInDuration。
|
||
/// </summary>
|
||
public float fadeInDuration { get { return m_FadeInDuration; } set { m_FadeInDuration = value < 0 ? 0 : value; } }
|
||
/// <summary>
|
||
/// The milliseconds duration of the fadeOut animation.
|
||
/// |设定的渐出动画时长(毫秒)。如果要设置单个数据项的渐出时长,可以用代码定制:customFadeOutDuration。
|
||
/// </summary>
|
||
public float fadeOutDuration { get { return m_FadeOutDuration; } set { m_FadeOutDuration = value < 0 ? 0 : value; } }
|
||
/// <summary>
|
||
/// The milliseconds actual duration of the first animation.
|
||
/// |实际的动画时长(毫秒)。
|
||
/// </summary>
|
||
public float actualDuration { get { return m_ActualDuration; } }
|
||
/// <summary>
|
||
/// Whether to set graphic number threshold to animation. Animation will be disabled when graphic number is larger than threshold.
|
||
/// |是否开启动画的阈值,当单个系列显示的图形数量大于这个阈值时会关闭动画。
|
||
/// </summary>
|
||
public int threshold { get { return m_Threshold; } set { m_Threshold = value; } }
|
||
/// <summary>
|
||
/// The milliseconds delay before updating the first animation.
|
||
/// |渐入动画延时(毫秒)。如果要设置单个数据项的延时,可以用代码定制:customFadeInDelay。
|
||
/// </summary>
|
||
public float fadeInDelay { get { return m_FadeInDelay; } set { m_FadeInDelay = value < 0 ? 0 : value; } }
|
||
/// <summary>
|
||
/// 渐出动画延时(毫秒)。如果要设置单个数据项的延时,可以用代码定制:customFadeOutDelay。
|
||
/// </summary>
|
||
public float fadeOutDelay { get { return m_FadeOutDelay; } set { m_FadeInDelay = value < 0 ? 0 : value; } }
|
||
/// <summary>
|
||
/// 是否开启数据变更动画。
|
||
/// </summary>
|
||
public bool dataChangeEnable { get { return m_DataChangeEnable; } set { m_DataChangeEnable = value; } }
|
||
/// <summary>
|
||
/// The milliseconds duration of the data change animation.
|
||
/// |数据变更的动画时长(毫秒)。
|
||
/// </summary>
|
||
public float dataChangeDuration { get { return m_DataChangeDuration; } set { m_DataChangeDuration = value < 0 ? 0 : value; } }
|
||
/// <summary>
|
||
/// 渐入动画完成回调
|
||
/// </summary>
|
||
public Action fadeInFinishCallback { get; set; }
|
||
/// <summary>
|
||
/// 渐出动画完成回调
|
||
/// </summary>
|
||
public Action fadeOutFinishCallback { get; set; }
|
||
private Dictionary<int, float> m_ItemCurrProgress = new Dictionary<int, float>();
|
||
private Dictionary<int, float> m_ItemDestProgress = new Dictionary<int, float>();
|
||
private bool m_FadeIn = false;
|
||
private bool m_IsEnd = true;
|
||
private bool m_IsPause = false;
|
||
private bool m_FadeOut = false;
|
||
private bool m_FadeOuted = false;
|
||
private bool m_IsInit = false;
|
||
|
||
private float startTime { get; set; }
|
||
private float m_CurrDetailProgress;
|
||
private float m_DestDetailProgress;
|
||
private float m_TotalDetailProgress;
|
||
private float m_CurrSymbolProgress;
|
||
private Vector3 m_LinePathLastPos;
|
||
|
||
public void FadeIn()
|
||
{
|
||
if (m_FadeOut)
|
||
return;
|
||
|
||
if (m_IsPause)
|
||
{
|
||
m_IsPause = false;
|
||
return;
|
||
}
|
||
|
||
if (m_FadeIn)
|
||
return;
|
||
|
||
startTime = Time.time;
|
||
m_FadeIn = true;
|
||
m_IsEnd = false;
|
||
m_IsInit = false;
|
||
m_IsPause = false;
|
||
m_FadeOuted = false;
|
||
m_CurrDetailProgress = 0;
|
||
m_DestDetailProgress = 1;
|
||
m_CurrSymbolProgress = 0;
|
||
m_ItemCurrProgress.Clear();
|
||
m_ItemDestProgress.Clear();
|
||
}
|
||
|
||
public void Restart()
|
||
{
|
||
Reset();
|
||
FadeIn();
|
||
}
|
||
|
||
public void FadeOut()
|
||
{
|
||
if (m_IsPause)
|
||
{
|
||
m_IsPause = false;
|
||
return;
|
||
}
|
||
|
||
m_FadeOut = true;
|
||
startTime = Time.time;
|
||
m_FadeIn = true;
|
||
m_IsEnd = false;
|
||
m_IsInit = false;
|
||
m_IsPause = false;
|
||
m_CurrDetailProgress = 0;
|
||
m_DestDetailProgress = 1;
|
||
m_CurrSymbolProgress = 0;
|
||
m_ItemCurrProgress.Clear();
|
||
m_ItemDestProgress.Clear();
|
||
}
|
||
|
||
public void Pause()
|
||
{
|
||
if (!m_IsPause)
|
||
{
|
||
m_IsPause = true;
|
||
}
|
||
}
|
||
|
||
public void Resume()
|
||
{
|
||
if (m_IsPause)
|
||
{
|
||
m_IsPause = false;
|
||
}
|
||
}
|
||
|
||
private void End()
|
||
{
|
||
if (m_IsEnd)
|
||
return;
|
||
|
||
m_ActualDuration = (int) ((Time.time - startTime) * 1000) - (m_FadeOut ? fadeOutDelay : fadeInDelay);
|
||
m_IsEnd = true;
|
||
m_IsInit = false;
|
||
|
||
if (m_FadeIn)
|
||
{
|
||
m_FadeIn = false;
|
||
if (fadeInFinishCallback != null)
|
||
{
|
||
fadeInFinishCallback();
|
||
}
|
||
}
|
||
if (m_FadeOut)
|
||
{
|
||
m_FadeOut = false;
|
||
m_FadeOuted = true;
|
||
if (fadeOutFinishCallback != null)
|
||
{
|
||
fadeOutFinishCallback();
|
||
}
|
||
}
|
||
}
|
||
|
||
public void Reset()
|
||
{
|
||
m_FadeIn = false;
|
||
m_IsEnd = true;
|
||
m_IsInit = false;
|
||
m_IsPause = false;
|
||
m_FadeOut = false;
|
||
m_FadeOuted = false;
|
||
m_ItemCurrProgress.Clear();
|
||
}
|
||
|
||
public void InitProgress(float curr, float dest)
|
||
{
|
||
if (m_IsInit || m_IsEnd)
|
||
return;
|
||
if (curr > dest)
|
||
return;
|
||
|
||
m_IsInit = true;
|
||
m_TotalDetailProgress = dest - curr;
|
||
|
||
if (m_FadeOut)
|
||
{
|
||
m_CurrDetailProgress = dest;
|
||
m_DestDetailProgress = curr;
|
||
}
|
||
else
|
||
{
|
||
m_CurrDetailProgress = curr;
|
||
m_DestDetailProgress = dest;
|
||
}
|
||
}
|
||
|
||
public void InitProgress(List<Vector3> paths, bool isY)
|
||
{
|
||
if (paths.Count < 1) return;
|
||
var sp = paths[0];
|
||
var ep = paths[paths.Count - 1];
|
||
var currDetailProgress = isY ? sp.y : sp.x;
|
||
var totalDetailProgress = isY ? ep.y : ep.x;
|
||
if (context.type == AnimationType.AlongPath)
|
||
{
|
||
currDetailProgress = 0;
|
||
totalDetailProgress = 0;
|
||
var lp = sp;
|
||
for (int i = 1; i < paths.Count; i++)
|
||
{
|
||
var np = paths[i];
|
||
totalDetailProgress += Vector3.Distance(np, lp);
|
||
lp = np;
|
||
}
|
||
m_LinePathLastPos = sp;
|
||
context.currentPathDistance = 0;
|
||
}
|
||
InitProgress(currDetailProgress, totalDetailProgress);
|
||
}
|
||
|
||
private void SetDataCurrProgress(int index, float state)
|
||
{
|
||
m_ItemCurrProgress[index] = state;
|
||
}
|
||
|
||
private float GetDataCurrProgress(int index, float initValue, float destValue, ref bool isBarEnd)
|
||
{
|
||
if (IsInDelay())
|
||
{
|
||
isBarEnd = false;
|
||
return initValue;
|
||
}
|
||
var c1 = !m_ItemCurrProgress.ContainsKey(index);
|
||
var c2 = !m_ItemDestProgress.ContainsKey(index);
|
||
if (c1 || c2)
|
||
{
|
||
if (c1)
|
||
m_ItemCurrProgress.Add(index, initValue);
|
||
|
||
if (c2)
|
||
m_ItemDestProgress.Add(index, destValue);
|
||
|
||
isBarEnd = false;
|
||
}
|
||
else
|
||
{
|
||
isBarEnd = m_ItemCurrProgress[index] == m_ItemDestProgress[index];
|
||
}
|
||
return m_ItemCurrProgress[index];
|
||
}
|
||
|
||
public bool IsFinish()
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (!Application.isPlaying)
|
||
return true;
|
||
#endif
|
||
if (!m_Enable || m_IsEnd)
|
||
return true;
|
||
|
||
if (IsIndexAnimation())
|
||
return m_CurrDetailProgress > m_DestDetailProgress;
|
||
if (IsItemAnimation())
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
public bool IsInFadeOut()
|
||
{
|
||
return m_FadeOut;
|
||
}
|
||
|
||
public bool IsInDelay()
|
||
{
|
||
if (m_FadeOut)
|
||
return (fadeOutDelay > 0 && Time.time - startTime < fadeOutDelay / 1000);
|
||
else
|
||
return (fadeInDelay > 0 && Time.time - startTime < fadeInDelay / 1000);
|
||
}
|
||
|
||
public bool IsItemAnimation()
|
||
{
|
||
return context.type == AnimationType.BottomToTop || context.type == AnimationType.InsideOut;
|
||
}
|
||
|
||
public bool IsIndexAnimation()
|
||
{
|
||
return context.type == AnimationType.LeftToRight ||
|
||
context.type == AnimationType.Clockwise ||
|
||
context.type == AnimationType.AlongPath;
|
||
}
|
||
|
||
public float GetIndexDelay(int dataIndex)
|
||
{
|
||
if (m_FadeOut && fadeOutDelayFunction != null)
|
||
return fadeOutDelayFunction(dataIndex);
|
||
else if (m_FadeIn && fadeInDelayFunction != null)
|
||
return fadeInDelayFunction(dataIndex);
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
public bool IsInIndexDelay(int dataIndex)
|
||
{
|
||
return Time.time - startTime < GetIndexDelay(dataIndex) / 1000f;
|
||
}
|
||
|
||
public bool IsAllOutDelay(int dataCount)
|
||
{
|
||
var nowTime = Time.time - startTime;
|
||
for (int i = 0; i < dataCount; i++)
|
||
{
|
||
if (nowTime < GetIndexDelay(i) / 1000)
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public bool CheckDetailBreak(float detail)
|
||
{
|
||
if (!IsIndexAnimation())
|
||
return false;
|
||
return !IsFinish() && detail > m_CurrDetailProgress;
|
||
}
|
||
|
||
public bool CheckDetailBreak(Vector3 pos, bool isYAxis)
|
||
{
|
||
if (!IsIndexAnimation())
|
||
return false;
|
||
|
||
if (IsFinish())
|
||
return false;
|
||
|
||
if (context.type == AnimationType.AlongPath)
|
||
{
|
||
context.currentPathDistance += Vector3.Distance(pos, m_LinePathLastPos);
|
||
m_LinePathLastPos = pos;
|
||
return CheckDetailBreak(context.currentPathDistance);
|
||
}
|
||
else
|
||
{
|
||
if (isYAxis)
|
||
return pos.y > m_CurrDetailProgress;
|
||
else
|
||
return pos.x > m_CurrDetailProgress;
|
||
}
|
||
}
|
||
|
||
public void CheckProgress()
|
||
{
|
||
if (IsItemAnimation() && context.isAllItemAnimationEnd)
|
||
{
|
||
End();
|
||
return;
|
||
}
|
||
CheckProgress(m_TotalDetailProgress);
|
||
}
|
||
|
||
public void CheckProgress(double total)
|
||
{
|
||
if (IsFinish())
|
||
return;
|
||
|
||
if (!m_IsInit || m_IsPause || m_IsEnd)
|
||
return;
|
||
|
||
if (IsInDelay())
|
||
return;
|
||
|
||
m_ActualDuration = (int) ((Time.time - startTime) * 1000) - fadeInDelay;
|
||
var duration = GetCurrAnimationDuration();
|
||
var delta = (float) (total / duration * Time.deltaTime);
|
||
if (m_FadeOut)
|
||
{
|
||
m_CurrDetailProgress -= delta;
|
||
if (m_CurrDetailProgress <= m_DestDetailProgress)
|
||
{
|
||
m_CurrDetailProgress = m_DestDetailProgress;
|
||
End();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_CurrDetailProgress += delta;
|
||
if (m_CurrDetailProgress >= m_DestDetailProgress)
|
||
{
|
||
m_CurrDetailProgress = m_DestDetailProgress;
|
||
End();
|
||
}
|
||
}
|
||
}
|
||
|
||
internal float GetCurrAnimationDuration(int dataIndex = -1)
|
||
{
|
||
if (dataIndex >= 0)
|
||
{
|
||
if (m_FadeOut && fadeOutDurationFunction != null)
|
||
return fadeOutDurationFunction(dataIndex) / 1000f;
|
||
if (m_FadeIn && fadeInDurationFunction != null)
|
||
return fadeInDurationFunction(dataIndex) / 1000f;
|
||
}
|
||
|
||
if (m_FadeOut)
|
||
return m_FadeOutDuration > 0 ? m_FadeOutDuration / 1000 : 1f;
|
||
else
|
||
return m_FadeInDuration > 0 ? m_FadeInDuration / 1000 : 1f;
|
||
}
|
||
|
||
internal float CheckItemProgress(int dataIndex, float destProgress, ref bool isEnd, float startProgress = 0)
|
||
{
|
||
isEnd = false;
|
||
var initHig = m_FadeOut ? destProgress : startProgress;
|
||
var destHig = m_FadeOut ? startProgress : destProgress;
|
||
var currHig = GetDataCurrProgress(dataIndex, initHig, destHig, ref isEnd);
|
||
if (isEnd || IsFinish())
|
||
{
|
||
return m_FadeOuted ? startProgress : destProgress;
|
||
}
|
||
else if (IsInDelay() || IsInIndexDelay(dataIndex))
|
||
{
|
||
return m_FadeOut ? destProgress : startProgress;
|
||
}
|
||
else if (m_IsPause)
|
||
{
|
||
return currHig;
|
||
}
|
||
else
|
||
{
|
||
var duration = GetCurrAnimationDuration(dataIndex);
|
||
var delta = (destProgress - startProgress) / duration * Time.deltaTime;
|
||
currHig = currHig + (m_FadeOut ? -delta : delta);
|
||
if (m_FadeOut)
|
||
{
|
||
if ((initHig > 0 && currHig <= 0) || (initHig < 0 && currHig >= 0))
|
||
{
|
||
currHig = 0;
|
||
isEnd = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ((destProgress - startProgress > 0 && currHig > destProgress) ||
|
||
(destProgress - startProgress < 0 && currHig < destProgress))
|
||
{
|
||
currHig = destProgress;
|
||
isEnd = true;
|
||
}
|
||
}
|
||
SetDataCurrProgress(dataIndex, currHig);
|
||
return currHig;
|
||
}
|
||
}
|
||
|
||
public void CheckSymbol(float dest)
|
||
{
|
||
if (!enable || m_IsEnd || m_IsPause || !m_IsInit)
|
||
return;
|
||
|
||
if (IsInDelay())
|
||
return;
|
||
|
||
var duration = GetCurrAnimationDuration();
|
||
var delta = dest / duration * Time.deltaTime;
|
||
if (m_FadeOut)
|
||
{
|
||
m_CurrSymbolProgress -= delta;
|
||
if (m_CurrSymbolProgress < 0)
|
||
m_CurrSymbolProgress = 0;
|
||
}
|
||
else
|
||
{
|
||
m_CurrSymbolProgress += delta;
|
||
if (m_CurrSymbolProgress > dest)
|
||
m_CurrSymbolProgress = dest;
|
||
}
|
||
}
|
||
|
||
public float GetSysmbolSize(float dest)
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (!Application.isPlaying)
|
||
return dest;
|
||
#endif
|
||
if (!enable)
|
||
return dest;
|
||
|
||
if (m_IsEnd)
|
||
return m_FadeOut ? 0 : dest;
|
||
|
||
return m_CurrSymbolProgress;
|
||
}
|
||
|
||
public float GetCurrDetail()
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (!Application.isPlaying)
|
||
return m_DestDetailProgress;
|
||
#endif
|
||
return m_CurrDetailProgress;
|
||
}
|
||
|
||
public float GetCurrRate()
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (!Application.isPlaying)
|
||
return 1;
|
||
#endif
|
||
if (!enable || m_IsEnd)
|
||
return 1;
|
||
return m_CurrDetailProgress;
|
||
}
|
||
|
||
public int GetCurrIndex()
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (!Application.isPlaying)
|
||
return -1;
|
||
#endif
|
||
if (!enable || m_IsEnd)
|
||
return -1;
|
||
return (int) m_CurrDetailProgress;
|
||
}
|
||
|
||
public float GetUpdateAnimationDuration()
|
||
{
|
||
if (m_Enable && m_DataChangeEnable && IsFinish())
|
||
return m_DataChangeDuration;
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
public bool HasFadeOut()
|
||
{
|
||
return enable && m_FadeOuted && m_IsEnd;
|
||
}
|
||
}
|
||
} |