增加SerieLabel的LineType给饼图配置不同类型的视觉引导线

This commit is contained in:
monitor1394
2019-10-05 18:23:06 +08:00
parent 0a39463bac
commit 4a2a395922
12 changed files with 23391 additions and 27755 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -27,6 +27,8 @@ namespace XCharts
SerializedProperty m_FontSize = prop.FindPropertyRelative("m_FontSize"); SerializedProperty m_FontSize = prop.FindPropertyRelative("m_FontSize");
SerializedProperty m_FontStyle = prop.FindPropertyRelative("m_FontStyle"); SerializedProperty m_FontStyle = prop.FindPropertyRelative("m_FontStyle");
SerializedProperty m_Line = prop.FindPropertyRelative("m_Line"); SerializedProperty m_Line = prop.FindPropertyRelative("m_Line");
SerializedProperty m_LineType = prop.FindPropertyRelative("m_LineType");
SerializedProperty m_LineColor = prop.FindPropertyRelative("m_LineColor");
SerializedProperty m_LineWidth = prop.FindPropertyRelative("m_LineWidth"); SerializedProperty m_LineWidth = prop.FindPropertyRelative("m_LineWidth");
SerializedProperty m_LineLength1 = prop.FindPropertyRelative("m_LineLength1"); SerializedProperty m_LineLength1 = prop.FindPropertyRelative("m_LineLength1");
SerializedProperty m_LineLength2 = prop.FindPropertyRelative("m_LineLength2"); SerializedProperty m_LineLength2 = prop.FindPropertyRelative("m_LineLength2");
@@ -81,6 +83,10 @@ namespace XCharts
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_Line); EditorGUI.PropertyField(drawRect, m_Line);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_LineType);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_LineColor);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_LineWidth); EditorGUI.PropertyField(drawRect, m_LineWidth);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_LineLength1); EditorGUI.PropertyField(drawRect, m_LineLength1);
@@ -96,7 +102,7 @@ namespace XCharts
float height = 0; float height = 0;
if (ChartEditorHelper.IsToggle(m_SerieLabelToggle, prop)) if (ChartEditorHelper.IsToggle(m_SerieLabelToggle, prop))
{ {
height += 20 * EditorGUIUtility.singleLineHeight + 19 * EditorGUIUtility.standardVerticalSpacing; height += 22 * EditorGUIUtility.singleLineHeight + 21 * EditorGUIUtility.standardVerticalSpacing;
} }
else else
{ {

View File

@@ -389,8 +389,30 @@ namespace XCharts
/// 数据项个数。 /// 数据项个数。
/// </summary> /// </summary>
public int dataCount { get { return m_Data.Count; } } public int dataCount { get { return m_Data.Count; } }
/// <summary>
/// 数据项位置坐标。
/// </summary>
public List<Vector3> dataPoints { get { return m_DataPoints; } } public List<Vector3> dataPoints { get { return m_DataPoints; } }
/// <summary>
/// 饼图的中心点位置。
/// </summary>
public Vector3 pieCenterPos { get; set; }
/// <summary>
/// 饼图的内径
/// </summary>
public float pieInsideRadius { get; set; }
/// <summary>
/// 饼图的外径
/// </summary>
public float pieOutsideRadius { get; set; }
/// <summary>
/// 饼图的数据项最大值
/// </summary>
public float pieDataMax { get; set; }
/// <summary>
/// 饼图的数据项之和
/// </summary>
public float pieDataTotal { get; set; }
public List<Vector3> GetUpSmoothList(int dataIndex, int size = 100) public List<Vector3> GetUpSmoothList(int dataIndex, int size = 100)
{ {

View File

@@ -126,6 +126,11 @@ namespace XCharts
return true; return true;
} }
public bool IsCategory()
{
return !IsValue();
}
} }
} }

View File

@@ -296,7 +296,7 @@ namespace XCharts
} }
break; break;
case LineType.Smooth: case LineType.Smooth:
ChartHelper.GetBezierList(ref bezierPoints, null, lp, np, llp, nnp, fine, lineSmoothStyle); ChartHelper.GetBezierList(ref bezierPoints, lp, np, llp, nnp, fine, lineSmoothStyle);
if (bezierPoints.Count > 0) progress = bezierPoints.Count - 1; if (bezierPoints.Count > 0) progress = bezierPoints.Count - 1;
break; break;
case LineType.StepStart: case LineType.StepStart:
@@ -858,7 +858,7 @@ namespace XCharts
var smoothDownPoints = serie.GetDownSmoothList(dataIndex); var smoothDownPoints = serie.GetDownSmoothList(dataIndex);
var fine = isStack && m_Series.IsAnyGradientSerie(serie.stack); var fine = isStack && m_Series.IsAnyGradientSerie(serie.stack);
if (isYAxis) ChartHelper.GetBezierListVertical(ref bezierPoints, lp, np, fine, lineSmoothStyle); if (isYAxis) ChartHelper.GetBezierListVertical(ref bezierPoints, lp, np, fine, lineSmoothStyle);
else ChartHelper.GetBezierList(ref bezierPoints, vh, lp, np, llp, nnp, fine, lineSmoothStyle); else ChartHelper.GetBezierList(ref bezierPoints, lp, np, llp, nnp, fine, lineSmoothStyle);
Vector3 start, to; Vector3 start, to;
if (serie.lineType == LineType.SmoothDash) if (serie.lineType == LineType.SmoothDash)

View File

@@ -28,12 +28,18 @@ namespace XCharts
private float m_LabelPaddingLeftRight; private float m_LabelPaddingLeftRight;
private float m_LabelPaddingTopBottom; private float m_LabelPaddingTopBottom;
public int index { get; set; }
/// <summary> /// <summary>
/// the name of data item. /// the name of data item.
/// 数据项名称。 /// 数据项名称。
/// </summary> /// </summary>
public string name { get { return m_Name; } set { m_Name = value; } } public string name { get { return m_Name; } set { m_Name = value; } }
/// <summary> /// <summary>
/// 数据项图例名称。当数据项名称不为空时图例名称即为系列名称反之则为索引index。
/// </summary>
/// <value></value>
public string legendName { get { return string.IsNullOrEmpty(name) ? ChartCached.IntToStr(index) : name; } }
/// <summary>
/// Whether the data item is selected. /// Whether the data item is selected.
/// 该数据项是否被选中。 /// 该数据项是否被选中。
/// </summary> /// </summary>
@@ -110,6 +116,35 @@ namespace XCharts
/// 关联的gameObject /// 关联的gameObject
/// </summary> /// </summary>
public GameObject gameObject { get; private set; } public GameObject gameObject { get; private set; }
/// <summary>
/// 饼图数据项的开始角度(运行时自动计算)
/// </summary>
public float pieStartAngle { get; set; }
/// <summary>
/// 饼图数据项的结束角度(运行时自动计算)
/// </summary>
public float pieToAngle { get; set; }
/// <summary>
/// 饼图数据项的一半时的角度(运行时自动计算)
/// </summary>
public float pieHalfAngle { get; set; }
/// <summary>
/// 饼图数据项的当前角度(运行时自动计算)
/// </summary>
public float pieCurrAngle { get; set; }
/// <summary>
/// 饼图数据项的内半径
/// </summary>
public float pieInsideRadius{get;set;}
/// <summary>
/// 饼图数据项的外半径
/// </summary>
public float pieOutsideRadius { get; set; }
/// <summary>
/// 饼图数据项的偏移半径
/// </summary>
public float pieOffsetRadius { get; set; }
public Vector3 pieOffsetCenter { get; set; }
public float GetData(int index) public float GetData(int index)
{ {

View File

@@ -51,6 +51,25 @@ namespace XCharts
/// </summary> /// </summary>
Bottom, Bottom,
} }
/// <summary>
/// 标签视觉引导线类型
/// </summary>
public enum LineType
{
/// <summary>
/// 折线
/// </summary>
BrokenLine,
/// <summary>
/// 曲线
/// </summary>
Curves,
/// <summary>
/// 水平线
/// </summary>
HorizontalLine
}
[SerializeField] private bool m_Show = false; [SerializeField] private bool m_Show = false;
[SerializeField] Position m_Position; [SerializeField] Position m_Position;
[SerializeField] private Vector3 m_Offset; [SerializeField] private Vector3 m_Offset;
@@ -65,6 +84,8 @@ namespace XCharts
[SerializeField] private int m_FontSize = 18; [SerializeField] private int m_FontSize = 18;
[SerializeField] private FontStyle m_FontStyle = FontStyle.Normal; [SerializeField] private FontStyle m_FontStyle = FontStyle.Normal;
[SerializeField] private bool m_Line = true; [SerializeField] private bool m_Line = true;
[SerializeField] private LineType m_LineType = LineType.BrokenLine;
[SerializeField] private Color m_LineColor = Color.clear;
[SerializeField] private float m_LineWidth = 1.0f; [SerializeField] private float m_LineWidth = 1.0f;
[SerializeField] private float m_LineLength1 = 25f; [SerializeField] private float m_LineLength1 = 25f;
[SerializeField] private float m_LineLength2 = 15f; [SerializeField] private float m_LineLength2 = 15f;
@@ -153,6 +174,16 @@ namespace XCharts
/// </summary> /// </summary>
public bool line { get { return m_Line; } set { m_Line = value; } } public bool line { get { return m_Line; } set { m_Line = value; } }
/// <summary> /// <summary>
/// the type of visual guide line.
/// 视觉引导线类型。
/// </summary>
public LineType lineType { get { return m_LineType; } set { m_LineType = value; } }
/// <summary>
/// the color of visual guild line.
/// 视觉引导线颜色。默认和serie一致取自调色板。
/// </summary>
public Color lineColor { get { return m_LineColor; } set { m_LineColor = value; } }
/// <summary>
/// the width of visual guild line. /// the width of visual guild line.
/// 视觉引导线的宽度。 /// 视觉引导线的宽度。
/// </summary> /// </summary>

View File

@@ -12,22 +12,11 @@ namespace XCharts
[DisallowMultipleComponent] [DisallowMultipleComponent]
public class PieChart : BaseChart public class PieChart : BaseChart
{ {
private class PieTempData
{
public List<float> angleList = new List<float>();
public Vector2 center;
public float insideRadius;
public float outsideRadius;
public float dataMax;
public float dataTotal;
}
[SerializeField] private Pie m_Pie = Pie.defaultPie; [SerializeField] private Pie m_Pie = Pie.defaultPie;
private bool isDrawPie; private bool isDrawPie;
private bool m_IsEnterLegendButtom; private bool m_IsEnterLegendButtom;
private bool m_RefreshLabel; private bool m_RefreshLabel;
private List<PieTempData> m_PieTempDataList = new List<PieTempData>();
public Pie pie { get { return m_Pie; } } public Pie pie { get { return m_Pie; } }
@@ -44,7 +33,7 @@ namespace XCharts
m_Pie = Pie.defaultPie; m_Pie = Pie.defaultPie;
m_Title.text = "PieChart"; m_Title.text = "PieChart";
RemoveData(); RemoveData();
AddSerie(SerieType.Pie,"serie1"); AddSerie(SerieType.Pie, "serie1");
AddData(0, 70, "pie1"); AddData(0, 70, "pie1");
AddData(0, 20, "pie2"); AddData(0, 20, "pie2");
AddData(0, 10, "pie3"); AddData(0, 10, "pie3");
@@ -57,11 +46,9 @@ namespace XCharts
if (!isDrawPie) RefreshChart(); if (!isDrawPie) RefreshChart();
} }
Dictionary<string, int> serieNameSet = new Dictionary<string, int>();
protected override void DrawChart(VertexHelper vh) protected override void DrawChart(VertexHelper vh)
{ {
base.DrawChart(vh); base.DrawChart(vh);
serieNameSet.Clear();
int serieNameCount = -1; int serieNameCount = -1;
bool isClickOffset = false; bool isClickOffset = false;
bool isDataHighlight = false; bool isDataHighlight = false;
@@ -78,124 +65,93 @@ namespace XCharts
if (!serie.animation.NeedAnimation(i)) break; if (!serie.animation.NeedAnimation(i)) break;
bool isFinish = true; bool isFinish = true;
if (serie.pieClickOffset) isClickOffset = true; if (serie.pieClickOffset) isClickOffset = true;
PieTempData tempData; serie.pieDataMax = serie.yMax;
if (i < m_PieTempDataList.Count) serie.pieDataTotal = serie.yTotal;
{
tempData = m_PieTempDataList[i];
tempData.angleList.Clear();
}
else
{
tempData = new PieTempData();
m_PieTempDataList.Add(tempData);
}
tempData.angleList.Clear();
tempData.dataMax = serie.yMax;
tempData.dataTotal = serie.yTotal;
UpdatePieCenter(serie); UpdatePieCenter(serie);
float totalDegree = 360; float totalDegree = 360;
float startDegree = 0; float startDegree = 0;
int showdataCount = 0; int showdataCount = 0;
foreach (var sd in serie.data) foreach (var sd in serie.data)
{ {
if (sd.show && serie.pieRoseType == RoseType.Area) showdataCount++; if (sd.show && serie.pieRoseType == RoseType.Area) showdataCount++;
sd.canShowLabel = false; sd.canShowLabel = false;
} }
for (int n = 0; n < data.Count; n++) for (int n = 0; n < data.Count; n++)
{ {
var serieData = data[n]; var serieData = data[n];
float value = serieData.data[1]; float value = serieData.data[1];
string dataName = serieData.name; serieNameCount = m_LegendRealShowName.IndexOf(serieData.name);
Color color; Color color = m_ThemeInfo.GetColor(serieNameCount);
if (string.IsNullOrEmpty(dataName)) serieData.pieStartAngle = startDegree;
{ serieData.pieToAngle = startDegree;
serieNameCount++; serieData.pieHalfAngle = startDegree;
color = m_ThemeInfo.GetColor(serieNameCount); serieData.pieCurrAngle = startDegree;
}
else if (!serieNameSet.ContainsKey(dataName))
{
serieNameSet.Add(dataName, serieNameCount);
serieNameCount++;
color = m_ThemeInfo.GetColor(serieNameCount);
}
else
{
color = m_ThemeInfo.GetColor(serieNameSet[dataName]);
}
if (!serieData.show) if (!serieData.show)
{ {
tempData.angleList.Add(0);
continue; continue;
} }
float degree = serie.pieRoseType == RoseType.Area ? (totalDegree / showdataCount) : (totalDegree * value / tempData.dataTotal); float degree = serie.pieRoseType == RoseType.Area ?
float toDegree = startDegree + degree; (totalDegree / showdataCount) : (totalDegree * value / serie.pieDataTotal);
serieData.pieToAngle = startDegree + degree;
float outSideRadius = serie.pieRoseType > 0 ? serieData.pieOutsideRadius = serie.pieRoseType > 0 ?
tempData.insideRadius + (tempData.outsideRadius - tempData.insideRadius) * value / tempData.dataMax : serie.pieInsideRadius + (serie.pieOutsideRadius - serie.pieInsideRadius) * value / serie.pieDataMax :
tempData.outsideRadius; serie.pieOutsideRadius;
if (serieData.highlighted) if (serieData.highlighted)
{ {
isDataHighlight = true; isDataHighlight = true;
color *= 1.2f; color *= 1.2f;
outSideRadius += m_Pie.tooltipExtraRadius; serieData.pieOutsideRadius += m_Pie.tooltipExtraRadius;
} }
var offset = serie.pieSpace; var offset = serie.pieSpace;
if (serie.pieClickOffset && serieData.selected) if (serie.pieClickOffset && serieData.selected)
{ {
offset += m_Pie.selectedOffset; offset += m_Pie.selectedOffset;
} }
var halfDegree = (toDegree - startDegree) / 2; var halfDegree = (serieData.pieToAngle - startDegree) / 2;
float currAngle = startDegree + halfDegree; serieData.pieHalfAngle = startDegree + halfDegree;
float currRad = currAngle * Mathf.Deg2Rad; float currRad = serieData.pieHalfAngle * Mathf.Deg2Rad;
float currSin = Mathf.Sin(currRad); float currSin = Mathf.Sin(currRad);
float currCos = Mathf.Cos(currRad); float currCos = Mathf.Cos(currRad);
var center = tempData.center; var center = serie.pieCenterPos;
var currDegree = toDegree; serieData.pieCurrAngle = serieData.pieToAngle;
if (serie.animation.CheckDetailBreak(n, toDegree)) serieData.pieOffsetCenter = center;
serieData.pieInsideRadius = serie.pieInsideRadius;
if (serie.animation.CheckDetailBreak(n, serieData.pieToAngle))
{ {
isFinish = false; isFinish = false;
currDegree = serie.animation.GetCurrDetail(); serieData.pieCurrAngle = serie.animation.GetCurrDetail();
} }
if (offset > 0) if (offset > 0)
{ {
float offsetRadius = serie.pieSpace / Mathf.Sin(halfDegree * Mathf.Deg2Rad); serieData.pieOffsetRadius = serie.pieSpace / Mathf.Sin(halfDegree * Mathf.Deg2Rad);
var insideRadius = tempData.insideRadius - offsetRadius; serieData.pieInsideRadius -= serieData.pieOffsetRadius;
var outsideRadius = outSideRadius - offsetRadius; serieData.pieOutsideRadius -= serieData.pieOffsetRadius;
if (serie.pieClickOffset && serieData.selected) if (serie.pieClickOffset && serieData.selected)
{ {
offsetRadius += m_Pie.selectedOffset; serieData.pieOffsetRadius += m_Pie.selectedOffset;
if (insideRadius > 0) insideRadius += m_Pie.selectedOffset; if (serieData.pieInsideRadius > 0) serieData.pieInsideRadius += m_Pie.selectedOffset;
outsideRadius += m_Pie.selectedOffset; serieData.pieOutsideRadius += m_Pie.selectedOffset;
} }
var offestCenter = new Vector3(center.x + offsetRadius * currSin, serieData.pieOffsetCenter = new Vector3(center.x + serieData.pieOffsetRadius * currSin,
center.y + offsetRadius * currCos); center.y + serieData.pieOffsetRadius * currCos);
ChartDrawer.DrawDoughnut(vh, offestCenter, insideRadius, outsideRadius, ChartDrawer.DrawDoughnut(vh, serieData.pieOffsetCenter, serieData.pieInsideRadius, serieData.pieOutsideRadius,
startDegree, currDegree, color); startDegree, serieData.pieCurrAngle, color);
} }
else else
{ {
ChartDrawer.DrawDoughnut(vh, center, tempData.insideRadius, outSideRadius, ChartDrawer.DrawDoughnut(vh, center, serieData.pieInsideRadius, serieData.pieOutsideRadius,
startDegree, currDegree, color); startDegree, serieData.pieCurrAngle, color);
}
serieData.canShowLabel = currDegree >= currAngle;
if (currDegree >= currAngle)
{
DrawLabelLine(vh, serie, tempData, outSideRadius, center, currAngle, color);
} }
serieData.canShowLabel = serieData.pieCurrAngle >= serieData.pieHalfAngle;
isDrawPie = true; isDrawPie = true;
tempData.angleList.Add(toDegree); startDegree = serieData.pieToAngle;
startDegree = toDegree;
if (isFinish) serie.animation.SetDataFinish(n); if (isFinish) serie.animation.SetDataFinish(n);
else else break;
{
break;
}
} }
if (!serie.animation.IsFinish()) if (!serie.animation.IsFinish())
{ {
@@ -207,10 +163,30 @@ namespace XCharts
RefreshChart(); RefreshChart();
} }
} }
DrawLabelLine(vh);
DrawLabelBackground(vh); DrawLabelBackground(vh);
raycastTarget = isClickOffset && isDataHighlight; raycastTarget = isClickOffset && isDataHighlight;
} }
private void DrawLabelLine(VertexHelper vh)
{
foreach (var serie in m_Series.list)
{
if (serie.type == SerieType.Pie && serie.label.show)
{
foreach (var serieData in serie.data)
{
if (serieData.canShowLabel)
{
int colorIndex = m_LegendRealShowName.IndexOf(serieData.name);
Color color = m_ThemeInfo.GetColor(colorIndex);
DrawLabelLine(vh, serie, serieData, color);
}
}
}
}
}
private void DrawLabelBackground(VertexHelper vh) private void DrawLabelBackground(VertexHelper vh)
{ {
foreach (var serie in m_Series.list) foreach (var serie in m_Series.list)
@@ -221,6 +197,7 @@ namespace XCharts
{ {
if (serieData.canShowLabel) if (serieData.canShowLabel)
{ {
UpdateLabelPostion(serie, serieData);
DrawLabelBackground(vh, serie, serieData); DrawLabelBackground(vh, serie, serieData);
} }
} }
@@ -228,84 +205,103 @@ namespace XCharts
} }
} }
private void DrawLabelLine(VertexHelper vh, Serie serie, PieTempData tempData, float outSideRadius, Vector2 center, float currAngle, Color color) private void DrawLabelLine(VertexHelper vh, Serie serie, SerieData serieData, Color color)
{ {
if (serie.label.show if (serie.label.show
&& serie.label.position == SerieLabel.Position.Outside && serie.label.position == SerieLabel.Position.Outside
&& serie.label.line) && serie.label.line)
{ {
if (serie.label.color != Color.clear) color = serie.label.color; var insideRadius = serieData.pieInsideRadius;
var outSideRadius = serieData.pieOutsideRadius;
var center = serie.pieCenterPos;
var currAngle = serieData.pieHalfAngle;
if (serie.label.lineColor != Color.clear) color = serie.label.lineColor;
else if (serie.label.lineType == SerieLabel.LineType.HorizontalLine) color *= color;
float currSin = Mathf.Sin(currAngle * Mathf.Deg2Rad); float currSin = Mathf.Sin(currAngle * Mathf.Deg2Rad);
float currCos = Mathf.Cos(currAngle * Mathf.Deg2Rad); float currCos = Mathf.Cos(currAngle * Mathf.Deg2Rad);
var radius1 = outSideRadius; var radius1 = serie.label.lineType == SerieLabel.LineType.HorizontalLine ?
var radius2 = tempData.outsideRadius + serie.label.lineLength1; serie.pieOutsideRadius : outSideRadius;
var pos1 = new Vector2(center.x + radius1 * currSin, center.y + radius1 * currCos); var radius2 = serie.pieOutsideRadius + serie.label.lineLength1;
var pos2 = new Vector2(center.x + radius2 * currSin, center.y + radius2 * currCos); var radius3 = insideRadius + (outSideRadius - insideRadius) / 2;
var pos0 = new Vector3(center.x + radius3 * currSin, center.y + radius3 * currCos);
var pos1 = new Vector3(center.x + radius1 * currSin, center.y + radius1 * currCos);
var pos2 = new Vector3(center.x + radius2 * currSin, center.y + radius2 * currCos);
float tx, ty; float tx, ty;
Vector2 pos3; Vector3 pos3, pos4, pos6;
var horizontalLineCircleRadius = serie.label.lineWidth * 4f;
var lineCircleDiff = horizontalLineCircleRadius - 0.3f;
if (currAngle < 90) if (currAngle < 90)
{ {
ty = serie.label.lineWidth * Mathf.Cos((90 - currAngle) * Mathf.Deg2Rad); ty = serie.label.lineWidth * Mathf.Cos((90 - currAngle) * Mathf.Deg2Rad);
tx = serie.label.lineWidth * Mathf.Sin((90 - currAngle) * Mathf.Deg2Rad); tx = serie.label.lineWidth * Mathf.Sin((90 - currAngle) * Mathf.Deg2Rad);
pos3 = new Vector2(pos2.x - tx, pos2.y + ty - serie.label.lineWidth); pos3 = new Vector3(pos2.x - tx, pos2.y + ty - serie.label.lineWidth);
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3;
r4 += serie.label.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.right * lineCircleDiff;
pos4 = pos6 + Vector3.right * r4;
} }
else if (currAngle < 180) else if (currAngle < 180)
{ {
ty = serie.label.lineWidth * Mathf.Sin((180 - currAngle) * Mathf.Deg2Rad); ty = serie.label.lineWidth * Mathf.Sin((180 - currAngle) * Mathf.Deg2Rad);
tx = serie.label.lineWidth * Mathf.Cos((180 - currAngle) * Mathf.Deg2Rad); tx = serie.label.lineWidth * Mathf.Cos((180 - currAngle) * Mathf.Deg2Rad);
pos3 = new Vector2(pos2.x - tx, pos2.y - ty + serie.label.lineWidth); pos3 = new Vector3(pos2.x - tx, pos2.y - ty + serie.label.lineWidth);
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3;
r4 += serie.label.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.right * lineCircleDiff;
pos4 = pos6 + Vector3.right * r4;
} }
else if (currAngle < 270) else if (currAngle < 270)
{ {
ty = serie.label.lineWidth * Mathf.Sin((180 + currAngle) * Mathf.Deg2Rad); ty = serie.label.lineWidth * Mathf.Sin((180 + currAngle) * Mathf.Deg2Rad);
tx = serie.label.lineWidth * Mathf.Cos((180 + currAngle) * Mathf.Deg2Rad); tx = serie.label.lineWidth * Mathf.Cos((180 + currAngle) * Mathf.Deg2Rad);
pos3 = new Vector2(pos2.x + tx, pos2.y - ty + serie.label.lineWidth); var currSin1 = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad);
var currCos1 = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad);
pos3 = new Vector3(pos2.x + tx, pos2.y - ty + serie.label.lineWidth);
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos1 * radius3, 2)) - currSin1 * radius3;
r4 += serie.label.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.left * lineCircleDiff;
pos4 = pos6 + Vector3.left * r4;
} }
else else
{ {
ty = serie.label.lineWidth * Mathf.Cos((90 + currAngle) * Mathf.Deg2Rad); ty = serie.label.lineWidth * Mathf.Cos((90 + currAngle) * Mathf.Deg2Rad);
tx = serie.label.lineWidth * Mathf.Sin((90 + currAngle) * Mathf.Deg2Rad); tx = serie.label.lineWidth * Mathf.Sin((90 + currAngle) * Mathf.Deg2Rad);
pos3 = new Vector2(pos2.x + tx, pos2.y + ty - serie.label.lineWidth); pos3 = new Vector3(pos2.x + tx, pos2.y + ty - serie.label.lineWidth);
var currSin1 = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad);
var currCos1 = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad);
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos1 * radius3, 2)) - currSin1 * radius3;
r4 += serie.label.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.left * lineCircleDiff;
pos4 = pos6 + Vector3.left * r4;
}
var pos5 = new Vector3(currAngle > 180 ? pos3.x - serie.label.lineLength2 : pos3.x + serie.label.lineLength2, pos3.y);
switch (serie.label.lineType)
{
case SerieLabel.LineType.BrokenLine:
ChartDrawer.DrawLine(vh, pos1, pos2, serie.label.lineWidth, color);
ChartDrawer.DrawLine(vh, pos3, pos5, serie.label.lineWidth, color);
break;
case SerieLabel.LineType.Curves:
ChartDrawer.DrawCurves(vh, pos1, pos5, pos1, pos2, serie.label.lineWidth, color);
break;
case SerieLabel.LineType.HorizontalLine:
ChartDrawer.DrawCricle(vh, pos0, horizontalLineCircleRadius, color, 20);
ChartDrawer.DrawLine(vh, pos6, pos4, serie.label.lineWidth, color);
break;
} }
var pos4 = new Vector2(currAngle > 180 ? pos3.x - serie.label.lineLength2 : pos3.x + serie.label.lineLength2, pos3.y);
ChartDrawer.DrawLine(vh, pos1, pos2, serie.label.lineWidth, color);
ChartDrawer.DrawLine(vh, pos3, pos4, serie.label.lineWidth, color);
} }
} }
protected override void OnRefreshLabel() protected override void OnRefreshLabel()
{ {
serieNameSet.Clear();
int serieNameCount = -1; int serieNameCount = -1;
for (int i = 0; i < m_Series.Count; i++) for (int i = 0; i < m_Series.Count; i++)
{ {
var serie = m_Series.list[i]; var serie = m_Series.list[i];
serie.index = i; serie.index = i;
if (!serie.show) continue;
if (!serie.show)
{
continue;
}
PieTempData tempData;
if (i < m_PieTempDataList.Count)
{
tempData = m_PieTempDataList[i];
tempData.angleList.Clear();
}
else
{
tempData = new PieTempData();
m_PieTempDataList.Add(tempData);
}
tempData.angleList.Clear();
tempData.dataMax = serie.yMax;
tempData.dataTotal = serie.yTotal;
UpdatePieCenter(serie);
var data = serie.data; var data = serie.data;
float totalDegree = 360;
float startDegree = 0;
int showdataCount = 0; int showdataCount = 0;
if (serie.pieRoseType == RoseType.Area) if (serie.pieRoseType == RoseType.Area)
{ {
@@ -322,73 +318,19 @@ namespace XCharts
serieData.SetLabelActive(false); serieData.SetLabelActive(false);
continue; continue;
} }
float value = serieData.data[1]; if (!serieData.show) continue;
string dataName = serieData.name; serieNameCount = m_LegendRealShowName.IndexOf(serieData.name);
Color color; Color color = m_ThemeInfo.GetColor(serieNameCount);
if (string.IsNullOrEmpty(dataName))
{
serieNameCount++;
color = m_ThemeInfo.GetColor(serieNameCount);
}
else if (!serieNameSet.ContainsKey(dataName))
{
serieNameSet.Add(dataName, serieNameCount);
serieNameCount++;
color = m_ThemeInfo.GetColor(serieNameCount);
}
else
{
color = m_ThemeInfo.GetColor(serieNameSet[dataName]);
}
if (!serieData.show)
{
tempData.angleList.Add(0);
continue;
}
float degree = serie.pieRoseType == RoseType.Area ? (totalDegree / showdataCount) : (totalDegree * value / tempData.dataTotal);
float toDegree = startDegree + degree;
float outSideRadius = serie.pieRoseType > 0 ? DrawLabel(serie, n, serieData, color);
tempData.insideRadius + (tempData.outsideRadius - tempData.insideRadius) * value / tempData.dataMax :
tempData.outsideRadius;
if (serieData.highlighted)
{
outSideRadius += m_Pie.tooltipExtraRadius;
}
var offset = serie.pieSpace;
if (serie.pieClickOffset && serieData.selected)
{
offset += m_Pie.selectedOffset;
}
var halfDegree = (toDegree - startDegree) / 2;
float currAngle = startDegree + halfDegree;
if (offset > 0)
{
float offsetRadius = serie.pieSpace / Mathf.Sin(halfDegree * Mathf.Deg2Rad);
var insideRadius = tempData.insideRadius - offsetRadius;
var outsideRadius = outSideRadius - offsetRadius;
if (serie.pieClickOffset && serieData.selected)
{
offsetRadius += m_Pie.selectedOffset;
if (insideRadius > 0) insideRadius += m_Pie.selectedOffset;
outsideRadius += m_Pie.selectedOffset;
}
DrawLabel(serie, n, serieData, tempData, color, currAngle, offsetRadius, insideRadius, outsideRadius);
}
else
{
DrawLabel(serie, n, serieData, tempData, color, currAngle, 0, tempData.insideRadius, outSideRadius);
}
tempData.angleList.Add(toDegree);
startDegree = toDegree;
} }
} }
} }
private void DrawLabel(Serie serie, int dataIndex, SerieData serieData, PieTempData tempData, Color serieColor, private void DrawLabel(Serie serie, int dataIndex, SerieData serieData, Color serieColor)
float currAngle, float offsetRadius, float insideRadius, float outsideRadius)
{ {
if (serieData.labelText == null) return; if (serieData.labelText == null) return;
var currAngle = serieData.pieHalfAngle;
var isHighlight = (serieData.highlighted && serie.highlightLabel.show); var isHighlight = (serieData.highlighted && serie.highlightLabel.show);
var showLabel = ((serie.label.show || isHighlight) && serieData.canShowLabel); var showLabel = ((serie.label.show || isHighlight) && serieData.canShowLabel);
if (showLabel || serieData.showIcon) if (showLabel || serieData.showIcon)
@@ -416,7 +358,6 @@ namespace XCharts
} }
var fontSize = isHighlight ? serie.highlightLabel.fontSize : serie.label.fontSize; var fontSize = isHighlight ? serie.highlightLabel.fontSize : serie.label.fontSize;
var fontStyle = isHighlight ? serie.highlightLabel.fontStyle : serie.label.fontStyle; var fontStyle = isHighlight ? serie.highlightLabel.fontStyle : serie.label.fontStyle;
float currRad = currAngle * Mathf.Deg2Rad;
serieData.labelText.color = color; serieData.labelText.color = color;
serieData.labelText.fontSize = fontSize; serieData.labelText.fontSize = fontSize;
@@ -424,21 +365,65 @@ namespace XCharts
serieData.labelRect.transform.localEulerAngles = new Vector3(0, 0, rotate); serieData.labelRect.transform.localEulerAngles = new Vector3(0, 0, rotate);
switch (serie.label.position) UpdateLabelPostion(serie, serieData);
if (!string.IsNullOrEmpty(serie.label.formatter))
{ {
case SerieLabel.Position.Center: var value = serieData.data[1];
serieData.labelPosition = tempData.center; var total = serie.yTotal;
break; var content = serie.label.GetFormatterContent(serie.name, serieData.name, value, total);
case SerieLabel.Position.Inside: if (serieData.SetLabelText(content)) RefreshChart();
var labelRadius = offsetRadius + insideRadius + (outsideRadius - insideRadius) / 2; }
var labelCenter = new Vector2(tempData.center.x + labelRadius * Mathf.Sin(currRad), serieData.SetGameObjectPosition(serieData.labelPosition);
tempData.center.y + labelRadius * Mathf.Cos(currRad)); if (showLabel) serieData.SetLabelPosition(serie.label.offset);
serieData.labelPosition = labelCenter; }
break; else
case SerieLabel.Position.Outside: {
labelRadius = tempData.outsideRadius + serie.label.lineLength1; serieData.SetLabelActive(false);
labelCenter = new Vector2(tempData.center.x + labelRadius * Mathf.Sin(currRad), }
tempData.center.y + labelRadius * Mathf.Cos(currRad)); serieData.UpdateIcon();
}
protected void UpdateLabelPostion(Serie serie, SerieData serieData)
{
var currAngle = serieData.pieHalfAngle;
var currRad = currAngle * Mathf.Deg2Rad;
var offsetRadius = serieData.pieOffsetRadius;
var insideRadius = serieData.pieInsideRadius;
var outsideRadius = serieData.pieOutsideRadius;
switch (serie.label.position)
{
case SerieLabel.Position.Center:
serieData.labelPosition = serie.pieCenterPos;
break;
case SerieLabel.Position.Inside:
var labelRadius = offsetRadius + insideRadius + (outsideRadius - insideRadius) / 2;
var labelCenter = new Vector2(serie.pieCenterPos.x + labelRadius * Mathf.Sin(currRad),
serie.pieCenterPos.y + labelRadius * Mathf.Cos(currRad));
serieData.labelPosition = labelCenter;
break;
case SerieLabel.Position.Outside:
if (serie.label.lineType == SerieLabel.LineType.HorizontalLine)
{
var radius1 = serie.pieOutsideRadius;
var radius3 = insideRadius + (outsideRadius - insideRadius) / 2;
var currSin = Mathf.Sin(currRad);
var currCos = Mathf.Cos(currRad);
var pos0 = new Vector3(serie.pieCenterPos.x + radius3 * currSin, serie.pieCenterPos.y + radius3 * currCos);
if (currAngle > 180)
{
currSin = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad);
currCos = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad);
}
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3;
r4 += serie.label.lineLength1 + serie.label.lineWidth * 4;
r4 += serieData.labelText.preferredWidth / 2;
serieData.labelPosition = pos0 + (currAngle > 180 ? Vector3.left : Vector3.right) * r4;
}
else
{
labelRadius = serie.pieOutsideRadius + serie.label.lineLength1;
labelCenter = new Vector2(serie.pieCenterPos.x + labelRadius * Mathf.Sin(currRad),
serie.pieCenterPos.y + labelRadius * Mathf.Cos(currRad));
float labelWidth = serieData.labelText.preferredWidth; float labelWidth = serieData.labelText.preferredWidth;
if (currAngle > 180) if (currAngle > 180)
{ {
@@ -448,23 +433,9 @@ namespace XCharts
{ {
serieData.labelPosition = new Vector2(labelCenter.x + serie.label.lineLength2 + 5 + labelWidth / 2, labelCenter.y); serieData.labelPosition = new Vector2(labelCenter.x + serie.label.lineLength2 + 5 + labelWidth / 2, labelCenter.y);
} }
break; }
} break;
if (!string.IsNullOrEmpty(serie.label.formatter))
{
var value = serieData.data[1];
var total = serie.yTotal;
var content = serie.label.GetFormatterContent(serie.name, serieData.name, value, total);
if (serieData.SetLabelText(content)) RefreshChart();
}
serieData.SetGameObjectPosition(serieData.labelPosition);
if(showLabel) serieData.SetLabelPosition(serie.label.offset);
} }
else
{
serieData.SetLabelActive(false);
}
serieData.UpdateIcon();
} }
protected override void OnLegendButtonClick(int index, string legendName, bool show) protected override void OnLegendButtonClick(int index, string legendName, bool show)
@@ -492,13 +463,12 @@ namespace XCharts
private void UpdatePieCenter(Serie serie) private void UpdatePieCenter(Serie serie)
{ {
if (serie.pieCenter.Length < 2) return; if (serie.pieCenter.Length < 2) return;
var tempData = m_PieTempDataList[serie.index];
var centerX = serie.pieCenter[0] <= 1 ? chartWidth * serie.pieCenter[0] : serie.pieCenter[0]; var centerX = serie.pieCenter[0] <= 1 ? chartWidth * serie.pieCenter[0] : serie.pieCenter[0];
var centerY = serie.pieCenter[1] <= 1 ? chartHeight * serie.pieCenter[1] : serie.pieCenter[1]; var centerY = serie.pieCenter[1] <= 1 ? chartHeight * serie.pieCenter[1] : serie.pieCenter[1];
tempData.center = new Vector2(centerX, centerY); serie.pieCenterPos = new Vector2(centerX, centerY);
var minWidth = Mathf.Min(chartWidth, chartHeight); var minWidth = Mathf.Min(chartWidth, chartHeight);
tempData.insideRadius = serie.pieRadius[0] <= 1 ? minWidth * serie.pieRadius[0] : serie.pieRadius[0]; serie.pieInsideRadius = serie.pieRadius[0] <= 1 ? minWidth * serie.pieRadius[0] : serie.pieRadius[0];
tempData.outsideRadius = serie.pieRadius[1] <= 1 ? minWidth * serie.pieRadius[1] : serie.pieRadius[1]; serie.pieOutsideRadius = serie.pieRadius[1] <= 1 ? minWidth * serie.pieRadius[1] : serie.pieRadius[1];
} }
protected override void CheckTootipArea(Vector2 local) protected override void CheckTootipArea(Vector2 local)
@@ -506,13 +476,11 @@ namespace XCharts
if (m_IsEnterLegendButtom) return; if (m_IsEnterLegendButtom) return;
m_Tooltip.dataIndex.Clear(); m_Tooltip.dataIndex.Clear();
bool selected = false; bool selected = false;
for (int i = 0; i < m_PieTempDataList.Count; i++) foreach (var serie in m_Series.list)
{ {
var serie = m_Series.GetSerie(i); int index = GetPosPieIndex(serie, local);
var tempData = m_PieTempDataList[i];
int index = GetPosPieIndex(tempData, local);
m_Tooltip.dataIndex.Add(index); m_Tooltip.dataIndex.Add(index);
if (serie.type != SerieType.Pie) continue;
bool refresh = false; bool refresh = false;
for (int j = 0; j < serie.data.Count; j++) for (int j = 0; j < serie.data.Count; j++)
{ {
@@ -520,7 +488,6 @@ namespace XCharts
if (serieData.highlighted != (j == index)) refresh = true; if (serieData.highlighted != (j == index)) refresh = true;
serieData.highlighted = j == index; serieData.highlighted = j == index;
} }
if (index >= 0) selected = true; if (index >= 0) selected = true;
if (refresh) RefreshChart(); if (refresh) RefreshChart();
} }
@@ -536,20 +503,17 @@ namespace XCharts
} }
} }
private int GetPosPieIndex(PieTempData tempData, Vector2 local) private int GetPosPieIndex(Serie serie, Vector2 local)
{ {
var dist = Vector2.Distance(local, tempData.center); if (serie.type != SerieType.Pie) return -1;
if (dist < tempData.insideRadius || dist > tempData.outsideRadius) return -1; var dist = Vector2.Distance(local, serie.pieCenterPos);
Vector2 dir = local - tempData.center; if (dist < serie.pieInsideRadius || dist > serie.pieOutsideRadius) return -1;
Vector2 dir = local - new Vector2(serie.pieCenterPos.x, serie.pieCenterPos.y);
float angle = VectorAngle(Vector2.up, dir); float angle = VectorAngle(Vector2.up, dir);
var angleList = tempData.angleList; for (int i = 0; i < serie.data.Count; i++)
for (int i = angleList.Count - 1; i >= 0; i--)
{ {
if (i == 0) var serieData = serie.data[i];
{ if (angle >= serieData.pieStartAngle && angle <= serieData.pieToAngle)
if (angle <= angleList[i]) return 0;
}
else if (angle <= angleList[i] && angle > angleList[i - 1])
{ {
return i; return i;
} }
@@ -573,14 +537,13 @@ namespace XCharts
{ {
base.RefreshTooltip(); base.RefreshTooltip();
bool showTooltip = false; bool showTooltip = false;
for (int i = 0; i < m_PieTempDataList.Count; i++) foreach (var serie in m_Series.list)
{ {
int index = m_Tooltip.dataIndex[i]; int index = m_Tooltip.dataIndex[serie.index];
if (index < 0) continue; if (index < 0) continue;
showTooltip = true; showTooltip = true;
if (string.IsNullOrEmpty(tooltip.formatter)) if (string.IsNullOrEmpty(tooltip.formatter))
{ {
var serie = m_Series.GetSerie(i);
string key = serie.data[index].name; string key = serie.data[index].name;
if (string.IsNullOrEmpty(key)) key = m_Legend.GetData(index); if (string.IsNullOrEmpty(key)) key = m_Legend.GetData(index);
@@ -621,17 +584,19 @@ namespace XCharts
{ {
return; return;
} }
for (int i = 0; i < m_PieTempDataList.Count; i++) for (int i = 0; i < m_Series.Count; i++)
{ {
var tempData = m_PieTempDataList[i]; var serie = m_Series.GetSerie(i);
int index = GetPosPieIndex(tempData, local); if (serie.type == SerieType.Pie)
if (index >= 0)
{ {
var serie = m_Series.GetSerie(i); var index = GetPosPieIndex(serie, local);
for (int j = 0; j < serie.data.Count; j++) if (index >= 0)
{ {
if (j == index) serie.data[j].selected = !serie.data[j].selected; for (int j = 0; j < serie.data.Count; j++)
else serie.data[j].selected = false; {
if (j == index) serie.data[j].selected = !serie.data[j].selected;
else serie.data[j].selected = false;
}
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
@@ -8,6 +9,7 @@ namespace XCharts
{ {
public static float CRICLE_SMOOTHNESS = 2f; public static float CRICLE_SMOOTHNESS = 2f;
private static UIVertex[] vertex = new UIVertex[4]; private static UIVertex[] vertex = new UIVertex[4];
private static List<Vector3> s_CurvesPosList = new List<Vector3>();
public static void DrawArrow(VertexHelper vh, Vector3 startPos, Vector3 arrowPos, float width, public static void DrawArrow(VertexHelper vh, Vector3 startPos, Vector3 arrowPos, float width,
float height, float offset, float dent, Color32 color) float height, float offset, float dent, Color32 color)
@@ -264,5 +266,42 @@ namespace XCharts
} }
} }
/// <summary>
/// 画贝塞尔曲线
/// </summary>
/// <param name="vh"></param>
/// <param name="sp">起始点</param>
/// <param name="ep">结束点</param>
/// <param name="cp1">控制点1</param>
/// <param name="cp2">控制点2</param>
/// <param name="lineWidth">曲线宽</param>
/// <param name="lineColor">曲线颜色</param>
public static void DrawCurves(VertexHelper vh, Vector3 sp, Vector3 ep, Vector3 cp1, Vector3 cp2,
float lineWidth, Color lineColor)
{
var dist = Vector3.Distance(sp, ep);
var segment = (int)(dist / 1f);
ChartHelper.GetBezierList2(ref s_CurvesPosList, sp, ep, segment, cp1, cp2);
if (s_CurvesPosList.Count > 1)
{
var start = s_CurvesPosList[0];
var to = Vector3.zero;
var dir = s_CurvesPosList[1] - start;
var diff = Vector3.Cross(dir, Vector3.forward).normalized * lineWidth;
var startUp = start - diff;
var startDn = start + diff;
for (int i = 1; i < s_CurvesPosList.Count; i++)
{
to = s_CurvesPosList[i];
diff = Vector3.Cross(to - start, Vector3.forward).normalized * lineWidth;
var toUp = to - diff;
var toDn = to + diff;
DrawPolygon(vh, startUp, toUp, toDn, startDn, lineColor);
startUp = toUp;
startDn = toDn;
start = to;
}
}
}
} }
} }

View File

@@ -251,7 +251,7 @@ namespace XCharts
posList.Add(ep); posList.Add(ep);
} }
public static void GetBezierList(ref List<Vector3> posList, VertexHelper vh, Vector3 sp, Vector3 ep, public static void GetBezierList(ref List<Vector3> posList, Vector3 sp, Vector3 ep,
Vector3 lsp, Vector3 nep, bool fine, float k = 2.0f) Vector3 lsp, Vector3 nep, bool fine, float k = 2.0f)
{ {
float dist = Mathf.Abs(sp.x - ep.x); float dist = Mathf.Abs(sp.x - ep.x);

View File

@@ -386,6 +386,11 @@
* `fontSize`:标签文字的字体大小。 * `fontSize`:标签文字的字体大小。
* `fontStyle`:标签文字的字体风格。 * `fontStyle`:标签文字的字体风格。
* `line`:是否显示视觉引导线。在 `label` 位置 设置为 `'Outside'` 的时候会显示视觉引导线。 * `line`:是否显示视觉引导线。在 `label` 位置 设置为 `'Outside'` 的时候会显示视觉引导线。
* `lineType`:视觉引导线类型。支持以下几种类型:
* `BrokenLine`:折线。
* `Curves`:曲线。
* `HorizontalLine`:水平线。
* `lineColor`:视觉引导线自定义颜色。
* `lineWidth`:视觉引导线的宽度。 * `lineWidth`:视觉引导线的宽度。
* `lineLength1`:视觉引导线第一段的长度。 * `lineLength1`:视觉引导线第一段的长度。
* `lineLength2`:视觉引导线第二段的长度。 * `lineLength2`:视觉引导线第二段的长度。

View File

@@ -7,7 +7,7 @@ An ECharts style UGUI Charting Library for Unity
QQ交流群XCharts交流群202030963 QQ交流群XCharts交流群202030963
[XCharts问答](Doc/XCharts问答.md) [XCharts问答](Doc/XCharts问答.md)
[XChartsAPI接口](Doc/XChartsAPI.md) [XChartsAPI手册](Doc/XChartsAPI.md)
[XCharts配置项手册](Doc/XCharts配置项手册.md) [XCharts配置项手册](Doc/XCharts配置项手册.md)
[教程5分钟上手XCharts](Doc/教程5分钟上手XCharts.md) [教程5分钟上手XCharts](Doc/教程5分钟上手XCharts.md)
@@ -28,6 +28,7 @@ QQ交流群XCharts交流群202030963
## 更新日志 ## 更新日志
* 2019.10.05)增加`SerieLabel``LineType`给饼图配置不同类型的视觉引导线
* 2019.10.02)增加`ScatterChart`同时对`Scatter``Line`的支持,实现折线图和散点图的组合图 * 2019.10.02)增加`ScatterChart`同时对`Scatter``Line`的支持,实现折线图和散点图的组合图
* 2019.10.01)重构代码,废弃`Series.series`接口,用`Series.list`代替 * 2019.10.01)重构代码,废弃`Series.series`接口,用`Series.list`代替
* 2019.10.01)增加`customDrawCallback`自定义绘制回调 * 2019.10.01)增加`customDrawCallback`自定义绘制回调