diff --git a/Runtime/Component/Animation/AnimationInfo.cs b/Runtime/Component/Animation/AnimationInfo.cs index a0a41622..b0ca43c7 100644 --- a/Runtime/Component/Animation/AnimationInfo.cs +++ b/Runtime/Component/Animation/AnimationInfo.cs @@ -412,9 +412,9 @@ namespace XCharts.Runtime [System.Serializable] public class AnimationInteraction : AnimationInfo { - [SerializeField][Since("v3.8.0")] private float m_WidthRate = 1.3f; + [SerializeField][Since("v3.8.0")] private float m_WidthRate = 1.1f; [SerializeField][Since("v3.8.0")] private float m_RadiusRate = 1.1f; - [SerializeField][Since("v3.8.0")] private float m_Offset = 8f; + [SerializeField][Since("v3.8.0")] private float m_Offset = 5f; /// /// the size rate of the width. diff --git a/Runtime/Component/Animation/AnimationStyle.cs b/Runtime/Component/Animation/AnimationStyle.cs index b0c908e2..c6ebb68b 100644 --- a/Runtime/Component/Animation/AnimationStyle.cs +++ b/Runtime/Component/Animation/AnimationStyle.cs @@ -540,7 +540,6 @@ namespace XCharts.Runtime public float GetInteractionRadius(float radius) { - if (m_Enable && m_Interaction.enable) return m_Interaction.GetRadius(radius); else diff --git a/Runtime/Component/Interaction/InteractData.cs b/Runtime/Component/Interaction/InteractData.cs index 4fa47d1f..f1d25197 100644 --- a/Runtime/Component/Interaction/InteractData.cs +++ b/Runtime/Component/Interaction/InteractData.cs @@ -5,7 +5,10 @@ namespace XCharts.Runtime public class InteractData { private float m_PreviousValue = 0; + private float m_CurrentValue = 0; private float m_TargetValue = 0; + private Vector3 m_PreviousPosition; + private Vector3 m_TargetPosition; private Color32 m_PreviousColor; private Color32 m_TargetColor; private Color32 m_PreviousToColor; @@ -21,30 +24,27 @@ namespace XCharts.Runtime public override string ToString() { - return string.Format("m_PreviousValue:{0},m_TargetValue:{1},m_UpdateTime:{2},m_UpdateFlag:{3},m_ValueEnable:{4}", - m_PreviousValue, m_TargetValue, m_UpdateTime, m_UpdateFlag, m_ValueEnable); + return string.Format("m_PreviousValue:{0},m_TargetValue:{1},m_UpdateTime:{2},m_UpdateFlag:{3},m_ValueEnable:{4},m_PreviousPosition:{5},m_TargetPosition:{6}", + m_PreviousValue, m_TargetValue, m_UpdateTime, m_UpdateFlag, m_ValueEnable, m_PreviousPosition, m_TargetPosition); } - public void SetValue(ref bool needInteract, float size, bool highlight, float rate = 1.3f) + public void SetValue(ref bool needInteract, float value, bool highlight, float rate = 1.3f) { - size = highlight && rate != 0 ? size * rate : size; - SetValue(ref needInteract, size); + value = highlight && rate != 0 ? value * rate : value; + SetValue(ref needInteract, value); } - public void SetValue(ref bool needInteract, float size) + public void SetValue(ref bool needInteract, float value) { - if (m_PreviousValue == float.NaN) - { - m_PreviousValue = size; - } - else if (m_TargetValue != size) + if (m_TargetValue != value) { needInteract = true; - m_UpdateFlag = true; - m_ValueEnable = true; - m_UpdateTime = Time.time; - m_PreviousValue = m_TargetValue; - m_TargetValue = size; + if (!m_ValueEnable) + m_PreviousValue = value; + else + m_PreviousValue = m_CurrentValue; + UpdateStart(); + m_TargetValue = value; } else if (m_UpdateFlag) { @@ -52,18 +52,24 @@ namespace XCharts.Runtime } } + public void SetPosition(ref bool needInteract, Vector3 pos) + { + if (m_TargetPosition != pos) + { + needInteract = true; + UpdateStart(); + m_PreviousPosition = m_TargetPosition == Vector3.one ? pos : m_TargetPosition; + m_TargetPosition = pos; + } + } + public void SetColor(ref bool needInteract, Color32 color) { if (!ChartHelper.IsValueEqualsColor(color, m_TargetColor)) { - if (!ChartHelper.IsClearColor(m_TargetColor)) - { - needInteract = true; - m_UpdateFlag = true; - m_ValueEnable = true; - m_UpdateTime = Time.time; - m_PreviousColor = m_TargetColor; - } + needInteract = true; + UpdateStart(); + m_PreviousColor = ChartHelper.IsClearColor(m_TargetColor) ? color : m_TargetColor; m_TargetColor = color; } else if (m_UpdateFlag) @@ -76,14 +82,9 @@ namespace XCharts.Runtime SetColor(ref needInteract, color); if (!ChartHelper.IsValueEqualsColor(toColor, m_TargetToColor)) { - if (!ChartHelper.IsClearColor(m_TargetToColor)) - { - needInteract = true; - m_UpdateFlag = true; - m_ValueEnable = true; - m_UpdateTime = Time.time; - m_PreviousToColor = m_TargetToColor; - } + needInteract = true; + UpdateStart(); + m_PreviousToColor = ChartHelper.IsClearColor(m_TargetToColor) ? color : m_TargetToColor; m_TargetToColor = toColor; } } @@ -102,41 +103,62 @@ namespace XCharts.Runtime public bool TryGetValue(ref float value, ref bool interacting, float animationDuration = 250) { - if (!IsValueEnable() || m_PreviousValue == 0 || animationDuration == 0) + if (!IsValueEnable() || animationDuration == 0) return false; if (float.IsNaN(m_TargetValue)) return false; if (m_UpdateFlag && !float.IsNaN(m_PreviousValue)) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; value = Mathf.Lerp(m_PreviousValue, m_TargetValue, rate); + m_CurrentValue = value; return true; } else { - m_UpdateFlag = false; + UpdateEnd(); } } value = m_TargetValue; return true; } + public bool TryGetPosition(ref Vector3 pos, ref bool interacting, float animationDuration = 250) + { + if (!IsValueEnable() || animationDuration == 0) + return false; + if (m_TargetPosition == Vector3.one) + { + return false; + } + if (m_UpdateFlag && m_PreviousPosition != Vector3.one) + { + var rate = GetRate(animationDuration); + if (rate < 1) + { + interacting = true; + pos = Vector3.Lerp(m_PreviousPosition, m_TargetPosition, rate); + return true; + } + else + { + UpdateEnd(); + } + } + pos = m_TargetPosition; + return true; + } + public bool TryGetColor(ref Color32 color, ref bool interacting, float animationDuration = 250) { if (!IsValueEnable() || animationDuration == 0) return false; if (m_UpdateFlag) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; @@ -145,7 +167,7 @@ namespace XCharts.Runtime } else { - m_UpdateFlag = false; + UpdateEnd(); } } color = m_TargetColor; @@ -158,10 +180,7 @@ namespace XCharts.Runtime return false; if (m_UpdateFlag) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; @@ -171,7 +190,7 @@ namespace XCharts.Runtime } else { - m_UpdateFlag = false; + UpdateEnd(); } } color = m_TargetColor; @@ -186,21 +205,19 @@ namespace XCharts.Runtime return false; if (m_UpdateFlag && !float.IsNaN(m_PreviousValue)) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; value = Mathf.Lerp(m_PreviousValue, m_TargetValue, rate); color = Color32.Lerp(m_PreviousColor, m_TargetColor, rate); toColor = Color32.Lerp(m_PreviousToColor, m_TargetToColor, rate); + m_CurrentValue = value; return true; } else { - m_UpdateFlag = false; + UpdateEnd(); } } value = m_TargetValue; @@ -209,12 +226,56 @@ namespace XCharts.Runtime return true; } + private float GetRate(float animationDuration) + { + var time = Time.time - m_UpdateTime; + var total = animationDuration / 1000; + var rate = time / total; + if (rate > 1) rate = 1; + return rate; + } + + private void UpdateStart() + { + m_ValueEnable = true; + m_UpdateFlag = true; + m_UpdateTime = Time.time; + } + + private void UpdateEnd() + { + if (!m_UpdateFlag) return; + m_UpdateFlag = false; + m_PreviousColor = m_TargetColor; + m_PreviousToColor = m_TargetToColor; + m_PreviousValue = m_TargetValue; + m_CurrentValue = m_TargetValue; + m_PreviousPosition = m_TargetPosition; + } + + public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250) + { + var flag = TryGetValueAndColor(ref value, ref color, ref toColor, ref interacting, animationDuration); + flag |= TryGetPosition(ref pos, ref interacting, animationDuration); + return flag; + } + + public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref bool interacting, float animationDuration = 250) + { + var flag = TryGetValue(ref value, ref interacting, animationDuration); + flag |= TryGetPosition(ref pos, ref interacting, animationDuration); + return flag; + } + public void Reset() { m_UpdateFlag = false; m_ValueEnable = false; m_TargetValue = float.NaN; m_PreviousValue = float.NaN; + m_CurrentValue = float.NaN; + m_PreviousPosition = Vector3.one; + m_TargetPosition = Vector3.one; m_TargetColor = ColorUtil.clearColor32; m_TargetToColor = ColorUtil.clearColor32; m_PreviousColor = ColorUtil.clearColor32; diff --git a/Runtime/Component/Label/SerieLabelHelper.cs b/Runtime/Component/Label/SerieLabelHelper.cs index 6baf1026..0f3a65b5 100644 --- a/Runtime/Component/Label/SerieLabelHelper.cs +++ b/Runtime/Component/Label/SerieLabelHelper.cs @@ -82,6 +82,9 @@ namespace XCharts.Runtime var outsideRadius = serieData.context.outsideRadius; var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); + var center = serieData.context.offsetCenter; + var interact = false; + serieData.interact.TryGetValueAndColor(ref outsideRadius, ref center, ref interact, serie.animation.GetInteractionDuration()); switch (serieLabel.position) { case LabelStyle.Position.Center: @@ -89,8 +92,8 @@ namespace XCharts.Runtime break; case LabelStyle.Position.Inside: var labelRadius = offsetRadius + insideRadius + (outsideRadius - insideRadius) / 2 + serieLabel.distance; - var labelCenter = new Vector2(serie.context.center.x + labelRadius * Mathf.Sin(currRad), - serie.context.center.y + labelRadius * Mathf.Cos(currRad)); + var labelCenter = new Vector2(center.x + labelRadius * Mathf.Sin(currRad), + center.y + labelRadius * Mathf.Cos(currRad)); serieData.context.labelPosition = labelCenter; break; default: @@ -101,7 +104,7 @@ namespace XCharts.Runtime var radius3 = insideRadius + (outsideRadius - insideRadius) / 2; var currSin = Mathf.Sin(currRad); var currCos = Mathf.Cos(currRad); - var pos0 = new Vector3(serie.context.center.x + radius3 * currSin, serie.context.center.y + radius3 * currCos); + var pos0 = new Vector3(center.x + radius3 * currSin, center.y + radius3 * currCos); if ((currAngle - startAngle) % 360 > 180) { currSin = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad); @@ -115,8 +118,8 @@ namespace XCharts.Runtime else { labelRadius = serie.context.outsideRadius + (labelLine == null ? 0 : labelLine.lineLength1); - labelCenter = new Vector2(serie.context.center.x + labelRadius * Mathf.Sin(currRad), - serie.context.center.y + labelRadius * Mathf.Cos(currRad)); + labelCenter = new Vector2(center.x + labelRadius * Mathf.Sin(currRad), + center.y + labelRadius * Mathf.Cos(currRad)); serieData.context.labelPosition = labelCenter; } break; diff --git a/Runtime/Serie/Pie/PieHandler.cs b/Runtime/Serie/Pie/PieHandler.cs index 27ba1b52..d7114719 100644 --- a/Runtime/Serie/Pie/PieHandler.cs +++ b/Runtime/Serie/Pie/PieHandler.cs @@ -51,31 +51,6 @@ namespace XCharts.Runtime return serie.context.center; } - // public override void OnLegendButtonClick(int index, string legendName, bool show) - // { - // if (!serie.IsLegendName(legendName)) - // return; - // LegendHelper.CheckDataShow(serie, legendName, show); - // chart.UpdateLegendColor(legendName, show); - // chart.RefreshPainter(serie); - // } - - // public override void OnLegendButtonEnter(int index, string legendName) - // { - // if (!serie.IsLegendName(legendName)) - // return; - // LegendHelper.CheckDataHighlighted(serie, legendName, true); - // chart.RefreshPainter(serie); - // } - - // public override void OnLegendButtonExit(int index, string legendName) - // { - // if (!serie.IsLegendName(legendName)) - // return; - // LegendHelper.CheckDataHighlighted(serie, legendName, false); - // chart.RefreshPainter(serie); - // } - public override void OnPointerDown(PointerEventData eventData) { if (chart.pointerPos == Vector2.zero) return; @@ -123,6 +98,7 @@ namespace XCharts.Runtime SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal); UpdateSerieDataRadius(serieData, value); serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); + serieData.interact.SetPosition(ref needInteract, serieData.context.offsetCenter); } } if (needInteract) @@ -133,7 +109,6 @@ namespace XCharts.Runtime { m_LastCheckContextFlag = needCheck; m_LegendExiting = false; - serie.ResetInteract(); chart.RefreshPainter(serie); } } @@ -169,6 +144,7 @@ namespace XCharts.Runtime var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, state); serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); + serieData.interact.SetPosition(ref needInteract, serieData.context.offsetCenter); } } if (lastPointerItemDataIndex != serie.context.pointerItemDataIndex) @@ -229,48 +205,16 @@ namespace XCharts.Runtime (float)(totalDegree * value / dataTotalFilterMinAngle); if (serie.minAngle > 0 && degree < serie.minAngle) degree = serie.minAngle; serieData.context.toAngle = startDegree + degree; - UpdateSerieDataRadius(serieData, value); - var offset = 0f; - if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) - { - offset += serie.animation.interaction.offset; - } - if (serie.animation.CheckDetailBreak(serieData.context.toAngle)) - { - serieData.context.currentAngle = serie.animation.GetCurrDetail(); - } - else - { - serieData.context.currentAngle = serieData.context.toAngle; - } var halfDegree = (serieData.context.toAngle - startDegree) / 2; - var halfRadius = serie.context.insideRadius + (serieData.context.outsideRadius - serie.context.insideRadius) / 2; serieData.context.halfAngle = startDegree + halfDegree; serieData.context.angle = startDegree + halfDegree; - serieData.context.offsetCenter = serie.context.center; + serieData.context.currentAngle = serie.animation.CheckDetailBreak(serieData.context.toAngle) + ? serie.animation.GetCurrDetail() : serieData.context.toAngle; serieData.context.insideRadius = serie.context.insideRadius; - serieData.context.position = ChartHelper.GetPosition(serie.context.center, serieData.context.halfAngle, halfRadius); - if (offset > 0) - { - var currRad = serieData.context.halfAngle * Mathf.Deg2Rad; - var currSin = Mathf.Sin(currRad); - var currCos = Mathf.Cos(currRad); - serieData.context.offsetRadius = 0; - if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) - { - serieData.context.offsetRadius += serie.animation.interaction.offset; - if (serieData.context.insideRadius > 0) - { - serieData.context.insideRadius += serie.animation.interaction.offset; - } - } - serieData.context.offsetCenter = new Vector3( - serie.context.center.x + serieData.context.offsetRadius * currSin, - serie.context.center.y + serieData.context.offsetRadius * currCos); - } serieData.context.canShowLabel = serieData.context.currentAngle >= serieData.context.halfAngle; - startDegree = serieData.context.toAngle; + UpdateSerieDataRadius(serieData, value); SerieLabelHelper.UpdatePieLabelPosition(serie, serieData); + startDegree = serieData.context.toAngle; } SerieLabelHelper.AvoidLabelOverlap(serie, chart.theme.common); } @@ -292,11 +236,32 @@ namespace XCharts.Runtime if (offset > 0) { serieData.context.outsideRadius += serie.animation.interaction.offset; + var currRad = serieData.context.halfAngle * Mathf.Deg2Rad; + var currSin = Mathf.Sin(currRad); + var currCos = Mathf.Cos(currRad); + serieData.context.offsetRadius = 0; + if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) + { + serieData.context.offsetRadius += serie.animation.interaction.offset; + if (serieData.context.insideRadius > 0) + { + serieData.context.insideRadius += serie.animation.interaction.offset; + } + } + serieData.context.offsetCenter = new Vector3( + serie.context.center.x + serieData.context.offsetRadius * currSin, + serie.context.center.y + serieData.context.offsetRadius * currCos); + } + else + { + serieData.context.offsetCenter = serie.context.center; } if (serieData.context.highlight) { serieData.context.outsideRadius = serie.animation.GetInteractionRadius(serieData.context.outsideRadius); } + var halfRadius = serie.context.insideRadius + (serieData.context.outsideRadius - serie.context.insideRadius) / 2; + serieData.context.position = ChartHelper.GetPosition(serie.context.center, serieData.context.halfAngle, halfRadius); } private double GetTotalAngle(Serie serie, double dataTotal, ref float totalAngle) @@ -361,40 +326,33 @@ namespace XCharts.Runtime var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); var outsideRadius = 0f; + var needOffset = (serie.pieClickOffset && (serieData.selected || serieData.context.selected)); + var offsetCenter = needOffset ? serieData.context.offsetCenter : serie.context.center; + var borderWidth = itemStyle.borderWidth; var borderColor = itemStyle.borderColor; var progress = AnimationStyleHelper.CheckDataAnimation(chart, serie, n, 1); var insideRadius = serieData.context.insideRadius * progress; - if (!interactEnable || !serieData.interact.TryGetValueAndColor(ref outsideRadius, ref color, ref toColor, ref interacting, interactDuration)) + if (!interactEnable || !serieData.interact.TryGetValueAndColor( + ref outsideRadius, ref offsetCenter, ref color, ref toColor, ref interacting, interactDuration)) { SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex); outsideRadius = serieData.context.outsideRadius * progress; if (interactEnable) { serieData.interact.SetValueAndColor(ref interacting, outsideRadius, color, toColor); + serieData.interact.SetPosition(ref interacting, offsetCenter); } } - if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) - { - var drawEndDegree = serieData.context.currentAngle; - var needRoundCap = serie.roundCap && insideRadius > 0; - UGL.DrawDoughnut(vh, serieData.context.offsetCenter, insideRadius, - outsideRadius, color, toColor, Color.clear, serieData.context.startAngle, - drawEndDegree, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, - needRoundCap, true); - } - else - { - var drawEndDegree = serieData.context.currentAngle; - var needRoundCap = serie.roundCap && insideRadius > 0; - UGL.DrawDoughnut(vh, serie.context.center, insideRadius, - outsideRadius, color, toColor, Color.clear, serieData.context.startAngle, - drawEndDegree, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, - needRoundCap, true); - DrawPieCenter(vh, serie, itemStyle, insideRadius); - } + var drawEndDegree = serieData.context.currentAngle; + var needRoundCap = serie.roundCap && insideRadius > 0; + UGL.DrawDoughnut(vh, offsetCenter, insideRadius, + outsideRadius, color, toColor, Color.clear, serieData.context.startAngle, + drawEndDegree, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, + needRoundCap, true); + DrawPieCenter(vh, serie, itemStyle, insideRadius); if (serie.animation.CheckDetailBreak(serieData.context.toAngle)) break; @@ -463,9 +421,10 @@ namespace XCharts.Runtime { var insideRadius = serieData.context.insideRadius; var outSideRadius = serieData.context.outsideRadius; - var center = serie.context.center; + var center = serieData.context.offsetCenter; + var interact = false; + serieData.interact.TryGetValueAndColor(ref outSideRadius,ref center,ref interact, serie.animation.GetInteractionDuration()); var currAngle = serieData.context.halfAngle; - if (!ChartHelper.IsClearColor(labelLine.lineColor)) color = labelLine.lineColor; else if (labelLine.lineType == LabelLine.LineType.HorizontalLine)