Files
XCharts/Scripts/PieChart.cs

219 lines
6.8 KiB
C#
Raw Normal View History

2018-09-23 08:18:26 +08:00
using System.Collections.Generic;
2019-03-20 07:35:32 +08:00
using System.Text;
2018-09-23 08:18:26 +08:00
using UnityEngine;
using UnityEngine.UI;
namespace xcharts
{
[System.Serializable]
public class PieInfo
{
public string name;
2018-09-23 09:09:17 +08:00
public float insideRadius = 0f;
public float outsideRadius = 80f;
2019-03-20 07:35:32 +08:00
public float tooltipExtraRadius = 10f;
2018-09-23 13:32:46 +08:00
public bool outsideRadiusDynamic = false;
2018-09-23 08:18:26 +08:00
public float space;
public float left;
public float right;
public float top;
public float bottom;
}
public class PieChart : BaseChart
{
[SerializeField]
2018-10-01 17:00:15 +08:00
private PieInfo pieInfo = new PieInfo();
2018-09-23 08:18:26 +08:00
private float pieCenterX = 0f;
private float pieCenterY = 0f;
private float pieRadius = 0;
2019-03-20 07:35:32 +08:00
private Vector2 pieCenter;
private List<float> angleList = new List<float>();
2018-09-23 08:18:26 +08:00
protected override void Awake()
{
base.Awake();
}
protected override void Update()
{
base.Update();
}
2019-03-12 08:10:25 +08:00
protected override void DrawChart(VertexHelper vh)
2018-09-23 08:18:26 +08:00
{
2019-03-12 08:10:25 +08:00
base.DrawChart(vh);
2018-09-23 08:18:26 +08:00
UpdatePieCenter();
float totalDegree = 360;
float startDegree = 0;
float dataTotal = GetDataTotal();
2018-09-23 13:32:46 +08:00
float dataMax = GetDataMax();
2019-03-20 07:35:32 +08:00
angleList.Clear();
for (int i = 0; i < seriesList.Count; i++)
2018-09-23 08:18:26 +08:00
{
2019-03-20 07:35:32 +08:00
if (!legend.IsShowSeries(i))
{
angleList.Add(0);
continue;
}
float value = seriesList[i].dataList[0];
2018-09-23 08:18:26 +08:00
float degree = totalDegree * value / dataTotal;
float toDegree = startDegree + degree;
2018-09-23 13:32:46 +08:00
2019-03-16 07:49:36 +08:00
float outSideRadius = pieInfo.outsideRadiusDynamic ?
pieInfo.insideRadius + (pieRadius - pieInfo.insideRadius) * value / dataMax :
2018-09-23 13:32:46 +08:00
pieRadius;
2019-03-20 07:35:32 +08:00
if (tooltip.show && tooltip.DataIndex == i + 1)
{
outSideRadius += pieInfo.tooltipExtraRadius;
}
ChartUtils.DrawDoughnut(vh, pieCenter, pieInfo.insideRadius,
2019-03-16 07:49:36 +08:00
outSideRadius, startDegree, toDegree, themeInfo.GetColor(i));
2019-03-20 07:35:32 +08:00
angleList.Add(toDegree);
2018-09-23 08:18:26 +08:00
startDegree = toDegree;
}
}
protected override void OnLegendButtonClicked()
{
base.OnLegendButtonClicked();
}
private float GetDataTotal()
{
float total = 0;
2019-03-16 07:49:36 +08:00
for (int i = 0; i < seriesList.Count; i++)
2018-09-23 08:18:26 +08:00
{
if (legend.IsShowSeries(i))
{
total += seriesList[i].GetData(0);
2018-09-23 08:18:26 +08:00
}
}
return total;
}
2018-09-23 13:32:46 +08:00
private float GetDataMax()
{
float max = 0;
2019-03-16 07:49:36 +08:00
for (int i = 0; i < seriesList.Count; i++)
2018-09-23 13:32:46 +08:00
{
2019-03-16 07:49:36 +08:00
if (legend.IsShowSeries(i) && seriesList[i].GetData(0) > max)
2018-09-23 13:32:46 +08:00
{
max = seriesList[i].GetData(0);
2018-09-23 13:32:46 +08:00
}
}
return max;
}
2018-09-23 08:18:26 +08:00
private void UpdatePieCenter()
{
float diffX = chartWid - pieInfo.left - pieInfo.right;
float diffY = chartHig - pieInfo.top - pieInfo.bottom;
float diff = Mathf.Min(diffX, diffY);
2019-03-16 07:49:36 +08:00
if (pieInfo.outsideRadius <= 0)
2018-09-23 08:18:26 +08:00
{
pieRadius = diff / 3 * 2;
pieCenterX = pieInfo.left + pieRadius;
pieCenterY = pieInfo.bottom + pieRadius;
}
else
{
2018-09-23 09:09:17 +08:00
pieRadius = pieInfo.outsideRadius;
2018-09-23 08:18:26 +08:00
pieCenterX = chartWid / 2;
pieCenterY = chartHig / 2;
if (pieInfo.left > 0) pieCenterX = pieInfo.left + pieRadius;
if (pieInfo.right > 0) pieCenterX = chartWid - pieInfo.right - pieRadius;
if (pieInfo.top > 0) pieCenterY = chartHig - pieInfo.top - pieRadius;
if (pieInfo.bottom > 0) pieCenterY = pieInfo.bottom + pieRadius;
}
2019-03-20 07:35:32 +08:00
pieCenter = new Vector2(pieCenterX, pieCenterY);
}
protected override void CheckTootipArea(Vector2 local)
{
float dist = Vector2.Distance(local, pieCenter);
if (dist > pieRadius)
{
tooltip.DataIndex = 0;
2019-03-21 07:51:20 +08:00
tooltip.SetActive(false);
2019-03-20 07:35:32 +08:00
}
else
{
Vector2 dir = local - pieCenter;
float angle = VectorAngle(Vector2.up, dir);
tooltip.DataIndex = 0;
for (int i = angleList.Count - 1; i >= 0; i--)
{
if (i == 0 && angle < angleList[i])
{
tooltip.DataIndex = 1;
break;
}
else if (angle < angleList[i] && angle > angleList[i - 1])
{
tooltip.DataIndex = i + 1;
break;
}
}
}
if (tooltip.DataIndex > 0)
{
tooltip.UpdatePos(new Vector2(local.x + 18, local.y - 25));
RefreshTooltip();
if (tooltip.LastDataIndex != tooltip.DataIndex)
{
RefreshChart();
}
tooltip.LastDataIndex = tooltip.DataIndex;
}
}
float VectorAngle(Vector2 from, Vector2 to)
{
float angle;
Vector3 cross = Vector3.Cross(from, to);
angle = Vector2.Angle(from, to);
angle = cross.z > 0 ? -angle : angle;
angle = (angle + 360) % 360;
return angle;
}
protected override void RefreshTooltip()
{
base.RefreshTooltip();
int index = tooltip.DataIndex - 1;
if (index < 0)
{
tooltip.SetActive(false);
return;
}
tooltip.SetActive(true);
string strColor = ColorUtility.ToHtmlStringRGBA(themeInfo.GetColor(index));
string key = legend.dataList[index];
float value = seriesList[index].dataList[0];
string txt = "";
if (!string.IsNullOrEmpty(pieInfo.name))
{
txt += pieInfo.name + "\n";
}
txt += string.Format("<color=#{0}>● </color>{1}: {2}", strColor, key, value);
tooltip.UpdateTooltipText(txt);
var pos = tooltip.GetPos();
if (pos.x + tooltip.Width > chartWid)
{
pos.x = chartWid - tooltip.Width;
}
if (pos.y - tooltip.Height < 0)
{
pos.y = tooltip.Height;
}
tooltip.UpdatePos(pos);
2018-09-23 08:18:26 +08:00
}
}
}