优化RadarChart雷达图,增加多雷达图支持

This commit is contained in:
monitor1394
2019-08-04 15:24:31 +08:00
parent 757e45d05e
commit bc7be8ce89
32 changed files with 156122 additions and 84445 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
@@ -12,7 +13,28 @@ namespace XCharts
[System.Serializable]
public class Legend : JsonDataSupport, IPropertyChanged, IEquatable<Legend>
{
/// <summary>
/// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends.
/// It is enabled by default, and you may set it to be false to disabled it.
/// 图例选择的模式,控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。
/// </summary>
public enum SelectedMode
{
/// <summary>
/// 多选。
/// </summary>
Multiple,
/// <summary>
/// 单选。
/// </summary>
Single,
/// <summary>
/// 无法选择。
/// </summary>
None
}
[SerializeField] private bool m_Show = true;
[SerializeField] private SelectedMode m_SelectedMode;
[SerializeField] private Orient m_Orient = Orient.Horizonal;
[SerializeField] private Location m_Location = Location.defaultRight;
[SerializeField] private float m_ItemWidth = 50.0f;
@@ -29,6 +51,12 @@ namespace XCharts
/// </summary>
public bool show { get { return m_Show; } set { m_Show = value; } }
/// <summary>
/// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends.
/// 选择模式。控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。
/// </summary>
/// <value></value>
public SelectedMode selectedMode { get { return m_SelectedMode; } set { m_SelectedMode = value; } }
/// <summary>
/// Specify whether the layout of legend component is horizontal or vertical.
/// 布局方式是横还是竖。
/// </summary>
@@ -66,6 +94,12 @@ namespace XCharts
/// 如果 data 没有被指定会自动从当前系列中获取。指定data时里面的数据项和serie匹配时才会生效。
/// </summary>
public List<string> data { get { return m_Data; } }
/// <summary>
/// the button list of legend.
/// 图例按钮列表。
/// </summary>
/// <value></value>
public Dictionary<string, Button> buttonList { get { return m_DataBtnList; } }
/// <summary>
/// 一个在顶部居中显示的默认图例。
@@ -77,6 +111,7 @@ namespace XCharts
var legend = new Legend
{
m_Show = false,
m_SelectedMode = SelectedMode.Multiple,
m_Orient = Orient.Horizonal,
m_Location = Location.defaultTop,
m_ItemWidth = 60.0f,
@@ -91,6 +126,7 @@ namespace XCharts
public void Copy(Legend legend)
{
m_Show = legend.show;
m_SelectedMode = legend.selectedMode;
m_Orient = legend.orient;
m_Location.Copy(legend.location);
m_ItemWidth = legend.itemWidth;
@@ -124,6 +160,7 @@ namespace XCharts
return false;
}
return show == other.show &&
selectedMode == other.selectedMode &&
orient == other.orient &&
location == other.location &&
itemWidth == other.itemWidth &&

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System;
using System.Text.RegularExpressions;
using UnityEngine.UI;
namespace XCharts
{
@@ -12,6 +13,15 @@ namespace XCharts
[System.Serializable]
public class Radar : JsonDataSupport, IEquatable<Radar>
{
/// <summary>
/// Radar render type, in which 'Polygon' and 'Circle' are supported.
/// 雷达图绘制类型,支持 'Polygon' 和 'Circle'。
/// </summary>
public enum Shape
{
Polygon,
Circle
}
/// <summary>
/// Indicator of radar chart, which is used to assign multiple variables(dimensions) in radar chart.
/// 雷达图的指示器,用来指定雷达图中的多个变量(维度)。
@@ -39,9 +49,14 @@ namespace XCharts
public float min { get { return m_Min; } set { m_Min = value; } }
/// <summary>
/// Specfy a color the the indicator.
/// 标签特定的颜色。
/// 标签特定的颜色。默认取自主题的axisTextColor。
/// </summary>
public Color color { get { return m_Color; } set { m_Color = value; } }
/// <summary>
/// the text conponent of indicator.
/// 指示器的文本组件。
/// </summary>
public Text text { get; set; }
public Indicator Clone()
{
@@ -54,43 +69,51 @@ namespace XCharts
};
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
else if (obj is Indicator)
{
return Equals((Indicator)obj);
}
else
{
return false;
}
}
public bool Equals(Indicator other)
{
return name.Equals(other.name);
if (ReferenceEquals(null, other))
{
return false;
}
return m_Name.Equals(other.name) &&
ChartHelper.IsValueEqualsColor(m_Color, other.color);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
[SerializeField] private bool m_Cricle;
[SerializeField] private bool m_Area;
[SerializeField] private Shape m_Shape;
[SerializeField] private float m_Radius = 100;
[SerializeField] private int m_SplitNumber = 5;
[SerializeField] private float m_Left;
[SerializeField] private float m_Right;
[SerializeField] private float m_Top;
[SerializeField] private float m_Bottom;
[SerializeField] private float m_LineTickness = 1f;
[SerializeField] private float m_LinePointSize = 5f;
[SerializeField] private Color m_LineColor = Color.grey;
[Range(0, 255)]
[SerializeField] private int m_AreaAlpha;
[SerializeField] private List<Color> m_BackgroundColorList = new List<Color>();
[SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.5f };
[SerializeField] private LineStyle m_LineStyle = new LineStyle();
[SerializeField] private AxisSplitArea m_SplitArea = AxisSplitArea.defaultSplitArea;
[SerializeField] private bool m_Indicator = true;
[SerializeField] private List<Indicator> m_IndicatorList = new List<Indicator>();
/// <summary>
/// True is render radar as cricle,otherwise render as polygon.
///雷达图是否绘制成圆形true为圆形false为多边形
/// Radar render type, in which 'Polygon' and 'Circle' are supported.
/// 雷达图绘制类型,支持 'Polygon' 和 'Circle'
/// </summary>
public bool cricle { get { return m_Cricle; } set { m_Cricle = value; } }
/// <summary>
/// Whether to fill color in area.
/// 是否区域填充颜色
/// </summary>
public bool area { get { return m_Area; } set { m_Area = value; } }
/// <value></value>
public Shape shape { get { return m_Shape; } set { m_Shape = value; } }
/// <summary>
/// the radius of radar.
/// 雷达图的半径。
@@ -102,50 +125,21 @@ namespace XCharts
/// </summary>
public int splitNumber { get { return m_SplitNumber; } set { m_SplitNumber = value; } }
/// <summary>
/// Distance between radar component and the left side of the container.
/// 雷达图离容器左侧的距离
/// the center of radar chart.
/// 雷达图的中心点。数组的第一项是横坐标,第二项是纵坐标
/// 当值为0-1之间时表示百分比设置成百分比时第一项是相对于容器宽度第二项是相对于容器高度。
/// </summary>
public float left { get { return m_Left; } set { m_Left = value; } }
public float[] center { get { return m_Center; } set { m_Center = value; } }
/// <summary>
/// Distance between radar component and the right side of the container.
/// 雷达图离容器右侧的距离
/// the line style of radar.
/// 线条样式
/// </summary>
public float right { get { return m_Right; } set { m_Right = value; } }
public LineStyle lineStyle { get { return m_LineStyle; } set { m_LineStyle = value; } }
/// <summary>
/// Distance between radar component and the top side of the container.
/// 雷达图离容器上侧的距离
/// Split area of axis in grid area.
/// 分割区域
/// </summary>
public float top { get { return m_Top; } set { m_Top = value; } }
/// <summary>
/// Distance between radar component and the bottom side of the container.
/// 雷达图离容器下侧的距离。
/// </summary>
public float bottom { get { return m_Bottom; } set { m_Bottom = value; } }
/// <summary>
/// the tickness of line.
/// 线的粗细。
/// </summary>
public float lineTickness { get { return m_LineTickness; } set { m_LineTickness = value; } }
/// <summary>
/// the size of point.
/// 圆点大小。
/// </summary>
public float linePointSize { get { return m_LinePointSize; } set { m_LinePointSize = value; } }
/// <summary>
/// the color of line.
/// 线的颜色。
/// </summary>
public Color lineColor { get { return m_LineColor; } set { m_LineColor = value; } }
/// <summary>
/// the alpha of area color.
/// 区域填充时的颜色alpha值
/// </summary>
public int areaAlpha { get { return m_AreaAlpha; } set { m_AreaAlpha = value; } }
/// <summary>
/// the color list of split area.
/// 分割区域颜色列表。
/// </summary>
public List<Color> backgroundColorList { get { return m_BackgroundColorList; } }
public AxisSplitArea splitArea { get { return m_SplitArea; } set { m_SplitArea = value; } }
/// <summary>
/// Whether to show indicator.
/// 是否显示指示器。
@@ -157,55 +151,77 @@ namespace XCharts
/// </summary>
public List<Indicator> indicatorList { get { return m_IndicatorList; } }
/// <summary>
/// the center position of radar in container.
/// 雷达图在容器中的具体中心点。
/// </summary>
/// <value></value>
public Vector2 centerPos { get; set; }
/// <summary>
/// the true radius of radar.
/// 雷达图的运行时实际半径。
/// </summary>
/// <value></value>
public float actualRadius { get; set; }
/// <summary>
/// the data position list of radar.
/// 雷达图的所有数据坐标点列表。
/// </summary>
/// <returns></returns>
public Dictionary<int,List<Vector3>> dataPosList = new Dictionary<int,List<Vector3>>();
public static Radar defaultRadar
{
get
{
var radar = new Radar
{
m_Cricle = false,
m_Area = false,
m_Radius = 100,
m_Shape = Shape.Polygon,
m_Radius = 0.4f,
m_SplitNumber = 5,
m_Left = 0,
m_Right = 0,
m_Top = 0,
m_Bottom = 0,
m_LineTickness = 1f,
m_LinePointSize = 5f,
m_AreaAlpha = 150,
m_LineColor = Color.grey,
m_Indicator = true,
m_BackgroundColorList = new List<Color> {
new Color32(246, 246, 246, 255),
new Color32(231, 231, 231, 255)
},
m_IndicatorList = new List<Indicator>(5){
new Indicator(){name="radar1",max = 100},
new Indicator(){name="radar2",max = 100},
new Indicator(){name="radar3",max = 100},
new Indicator(){name="radar4",max = 100},
new Indicator(){name="radar5",max = 100},
new Indicator(){name="indicator1",max = 100},
new Indicator(){name="indicator2",max = 100},
new Indicator(){name="indicator3",max = 100},
new Indicator(){name="indicator4",max = 100},
new Indicator(){name="indicator5",max = 100},
}
};
radar.center[0] = 0.5f;
radar.center[1] = 0.45f;
radar.splitArea.show = true;
radar.lineStyle.width = 0.3f;
return radar;
}
}
public void Copy(Radar other)
{
m_Shape = other.shape;
m_Radius = other.radius;
m_SplitNumber = other.splitNumber;
m_Left = other.left;
m_Right = other.right;
m_Top = other.top;
m_Bottom = other.bottom;
m_Center[0] = other.center[0];
m_Center[1] = other.center[1];
m_Indicator = other.indicator;
m_AreaAlpha = other.areaAlpha;
indicatorList.Clear();
foreach (var d in other.indicatorList) indicatorList.Add(d.Clone());
}
public Radar Clone()
{
var radar = new Radar();
radar.shape = shape;
radar.radius = radius;
radar.splitNumber = splitNumber;
radar.center[0] = center[0];
radar.center[1] = center[1];
radar.indicatorList.Clear();
radar.indicator = indicator;
foreach (var d in indicatorList) radar.indicatorList.Add(d.Clone());
return radar;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
@@ -229,11 +245,10 @@ namespace XCharts
return false;
}
return radius == other.radius &&
shape == other.shape &&
splitNumber == other.splitNumber &&
left == other.left &&
right == other.right &&
top == other.top &&
bottom == other.bottom &&
center[0] == other.center[0] &&
center[1] == other.center[1] &&
indicator == other.indicator &&
IsEqualsIndicatorList(indicatorList, other.indicatorList);
}
@@ -305,6 +320,14 @@ namespace XCharts
}
}
public float GetIndicatorMin(int index)
{
if (index >= 0 && index < m_IndicatorList.Count)
{
return m_IndicatorList[index].min;
}
return 0;
}
public float GetIndicatorMax(int index)
{
if (index >= 0 && index < m_IndicatorList.Count)
@@ -313,5 +336,34 @@ namespace XCharts
}
return 0;
}
public void UpdateRadarCenter(float chartWidth, float chartHeight)
{
if (center.Length < 2) return;
var centerX = center[0] <= 1 ? chartWidth * center[0] : center[0];
var centerY = center[1] <= 1 ? chartHeight * center[1] : center[1];
centerPos = new Vector2(centerX, centerY);
if (radius <= 0)
{
actualRadius = 0;
}
else if (radius <= 1)
{
actualRadius = Mathf.Min(chartWidth, chartHeight) * radius;
}
else
{
actualRadius = radius;
}
}
public Vector3 GetIndicatorPosition(int index)
{
int indicatorNum = indicatorList.Count;
var angle = 2 * Mathf.PI / indicatorNum * index;
var x = centerPos.x + actualRadius * Mathf.Sin(angle);
var y = centerPos.y + actualRadius * Mathf.Cos(angle);
return new Vector3(x, y);
}
}
}

View File

@@ -72,7 +72,10 @@ namespace XCharts
[SerializeField] private SerieType m_Type;
[SerializeField] private string m_Name;
[SerializeField] private string m_Stack;
[SerializeField] [Range(0, 1)] private int m_AxisIndex;
[SerializeField] [Range(0, 1)] private int m_AxisIndex = 0;
[SerializeField] private int m_RadarIndex = 0;
[SerializeField] private LineStyle m_LineStyle = new LineStyle();
[SerializeField] private AreaStyle m_AreaStyle = AreaStyle.defaultAreaStyle;
[SerializeField] private SerieSymbol m_Symbol = new SerieSymbol();
#region PieChart field
[SerializeField] private bool m_ClickOffset = true;
@@ -83,7 +86,7 @@ namespace XCharts
#endregion
[SerializeField] private SerieLabel m_Label = new SerieLabel();
[SerializeField] private SerieLabel m_HighlightLabel = new SerieLabel();
[SerializeField] [Range(1, 6)] private int m_ShowDataDimension;
[SerializeField] [Range(1, 10)] private int m_ShowDataDimension;
[SerializeField] private bool m_ShowDataName;
[FormerlySerializedAs("m_Data")]
[SerializeField] private List<float> m_YData = new List<float>();
@@ -116,6 +119,23 @@ namespace XCharts
/// </summary>
public int axisIndex { get { return m_AxisIndex; } set { m_AxisIndex = value; } }
/// <summary>
/// Index of radar component that radar chart uses.
/// 雷达图所使用的 radar 组件的 index。
/// </summary>
public int radarIndex { get { return m_RadarIndex; } set { m_RadarIndex = value; } }
/// <summary>
/// The style of line.
/// 线条样式。
/// </summary>
/// <value></value>
public LineStyle lineStyle { get { return m_LineStyle; } set { m_LineStyle = value; } }
/// <summary>
/// The style of area.
/// 区域填充样式。
/// </summary>
/// <value></value>
public AreaStyle areaStyle { get { return m_AreaStyle; } set { m_AreaStyle = value; } }
/// <summary>
/// the symbol of serie data item.
/// 标记的图形。
/// </summary>
@@ -360,7 +380,7 @@ namespace XCharts
m_YData.Add(yValue);
m_Data.Add(new SerieData() { data = new List<float>() { xValue, yValue }, name = dataName });
}
/// <summary>
/// 将一组数据添加到系列中。
/// 如果数据只有一个默认添加到维度Y中。
@@ -393,7 +413,7 @@ namespace XCharts
{
if (i == 0) m_XData.Add(valueList[i]);
else if (i == 1) m_YData.Add(valueList[i]);
serieData.data.Add(valueList[0]);
serieData.data.Add(valueList[i]);
}
m_Data.Add(serieData);
}
@@ -545,6 +565,31 @@ namespace XCharts
}
}
/// <summary>
/// 获得指定维数的最大最小值
/// </summary>
/// <param name="dimension"></param>
/// <param name="dataZoom"></param>
/// <returns></returns>
public void GetMinMaxData(int dimension, out float minValue, out float maxValue, DataZoom dataZoom = null)
{
var dataList = GetDataList(dataZoom);
float max = float.MinValue;
float min = float.MaxValue;
for (int i = 0; i < dataList.Count; i++)
{
var serieData = dataList[i];
if (serieData.data.Count > dimension)
{
var value = serieData.data[dimension];
if (value > max) max = value;
if (value < min) min = value;
}
}
maxValue = max;
minValue = min;
}
/// <summary>
/// 根据dataZoom更新数据列表缓存
/// </summary>
@@ -664,6 +709,42 @@ namespace XCharts
}
}
public Color GetAreaColor(ThemeInfo theme, int index, bool highlight)
{
if (areaStyle.color != Color.clear)
{
var color = areaStyle.color;
if (highlight) color *= color;
color.a *= areaStyle.opactiy;
return color;
}
else
{
var color = (Color)theme.GetColor(index);
if (highlight) color *= color;
color.a *= areaStyle.opactiy;
return color;
}
}
public Color GetLineColor(ThemeInfo theme, int index, bool highlight)
{
if (lineStyle.color != Color.clear)
{
var color = lineStyle.color;
if (highlight) color *= color;
color.a *= lineStyle.opactiy;
return color;
}
else
{
var color = (Color)theme.GetColor(index);
if (highlight) color *= color;
color.a *= lineStyle.opactiy;
return color;
}
}
/// <summary>
/// 从json中导入数据
/// </summary>

View File

@@ -558,58 +558,6 @@ namespace XCharts
}
}
/// <summary>
/// 获得指定系列的最大值
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public float GetMaxValue(int index)
{
float max = int.MinValue;
float min = int.MaxValue;
for (int i = 0; i < m_Series.Count; i++)
{
var showData = m_Series[i].yData;
if (showData[index] > max)
{
max = Mathf.Ceil(showData[index]);
}
if (showData[index] < min)
{
min = Mathf.Ceil(showData[index]);
}
}
if (max < 1 && max > -1) return max;
if (max < 0 && min < 0) max = min;
return ChartHelper.GetMaxDivisibleValue(max);
}
/// <summary>
/// 获得指定系列的最小值
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public float GetMinValue(int index)
{
float max = int.MinValue;
float min = int.MaxValue;
for (int i = 0; i < m_Series.Count; i++)
{
var showData = m_Series[i].yData;
if (showData[index] > max)
{
max = Mathf.Ceil(showData[index]);
}
if (showData[index] < min)
{
min = Mathf.Ceil(showData[index]);
}
}
if (min < 1 && min > -1) return min;
if (min < 0 && max < 0) min = max;
return ChartHelper.GetMinDivisibleValue(min);
}
private HashSet<string> _setForStack = new HashSet<string>();
/// <summary>
/// 是否由数据堆叠
@@ -729,21 +677,15 @@ namespace XCharts
serieNameList.Clear();
foreach (var serie in m_Series)
{
if (serie.type == SerieType.Pie)
if (!string.IsNullOrEmpty(serie.name) && !serieNameList.Contains(serie.name))
{
foreach (var data in serie.data)
{
if (!string.IsNullOrEmpty(data.name) && !serieNameList.Contains(data.name))
{
serieNameList.Add(data.name);
}
}
serieNameList.Add(serie.name);
}
else
foreach (var data in serie.data)
{
if (!string.IsNullOrEmpty(serie.name) && !serieNameList.Contains(serie.name))
if (!string.IsNullOrEmpty(data.name) && !serieNameList.Contains(data.name))
{
serieNameList.Add(serie.name);
serieNameList.Add(data.name);
}
}
}