增加PolarChart极坐标图表

This commit is contained in:
monitor1394
2020-07-01 09:38:00 +08:00
parent 9e48c23225
commit b6139514f5
31 changed files with 59285 additions and 111 deletions

View File

@@ -1,6 +1,7 @@
# 更新日志 # 更新日志
* (2020.07.01) 增加`PolarChart`极坐标图表
* (2020.06.25) 发布`v1.5.2`版本 * (2020.06.25) 发布`v1.5.2`版本
* (2020.06.25) 修复`BarChart`在数值为`0`时还会绘制一小部分柱条的问题 * (2020.06.25) 修复`BarChart`在数值为`0`时还会绘制一小部分柱条的问题
* (2020.06.24) 修复`PieChart`在设置`clockwise`后绘制异常的问题#65 * (2020.06.24) 修复`PieChart`在设置`clockwise`后绘制异常的问题#65

View File

@@ -0,0 +1,40 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEditor;
namespace XCharts
{
/// <summary>
/// Editor class used to edit UI PolarChart.
/// </summary>
[CustomEditor(typeof(PolarChart), false)]
public class PolarChartEditor : BaseChartEditor
{
protected SerializedProperty m_Polar;
protected SerializedProperty m_RadiusAxis;
protected SerializedProperty m_AngleAxis;
protected override void OnEnable()
{
base.OnEnable();
m_Target = (PolarChart)target;
m_Polar = serializedObject.FindProperty("m_Polar");
m_RadiusAxis = serializedObject.FindProperty("m_RadiusAxis");
m_AngleAxis = serializedObject.FindProperty("m_AngleAxis");
}
protected override void OnStartInspectorGUI()
{
base.OnStartInspectorGUI();
EditorGUILayout.PropertyField(m_Polar, true);
EditorGUILayout.PropertyField(m_RadiusAxis, true);
EditorGUILayout.PropertyField(m_AngleAxis, true);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 157ef5f1d75e04aa1814e0b188591912
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEditor;
using UnityEngine;
namespace XCharts
{
[CustomPropertyDrawer(typeof(AngleAxis), true)]
public class AngleAxisDrawer : AxisDrawer
{
protected override void DrawExtended(ref Rect drawRect, SerializedProperty prop)
{
SerializedProperty m_StartAngle = prop.FindPropertyRelative("m_StartAngle");
//SerializedProperty m_Clockwise = prop.FindPropertyRelative("m_Clockwise");
EditorGUI.PropertyField(drawRect, m_StartAngle);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
//EditorGUI.PropertyField(drawRect, m_Clockwise);
//drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
}
protected override string GetDisplayName(string displayName)
{
if (displayName.StartsWith("Element"))
{
displayName = displayName.Replace("Element", "Angle Axis");
}
return displayName;
}
protected override float GetExtendedHeight()
{
return 1 * EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 521ea44136ea74a2f82a4c0c46edfd32
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -100,6 +100,7 @@ namespace XCharts
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_BoundaryGap); EditorGUI.PropertyField(drawRect, m_BoundaryGap);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
DrawExtended(ref drawRect, prop);
EditorGUI.PropertyField(drawRect, m_AxisLine); EditorGUI.PropertyField(drawRect, m_AxisLine);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
drawRect.y += EditorGUI.GetPropertyHeight(m_AxisLine); drawRect.y += EditorGUI.GetPropertyHeight(m_AxisLine);
@@ -133,6 +134,11 @@ namespace XCharts
} }
} }
protected virtual void DrawExtended(ref Rect drawRect, SerializedProperty prop)
{
}
public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) public override float GetPropertyHeight(SerializedProperty prop, GUIContent label)
{ {
int index = InitToggle(prop); int index = InitToggle(prop);
@@ -195,10 +201,16 @@ namespace XCharts
height += EditorGUI.GetPropertyHeight(m_AxisLabel); height += EditorGUI.GetPropertyHeight(m_AxisLabel);
height += EditorGUI.GetPropertyHeight(m_SplitArea); height += EditorGUI.GetPropertyHeight(m_SplitArea);
height += EditorGUI.GetPropertyHeight(m_SplitLine); height += EditorGUI.GetPropertyHeight(m_SplitLine);
height += GetExtendedHeight();
return height; return height;
} }
} }
protected virtual float GetExtendedHeight()
{
return 0;
}
private int InitToggle(SerializedProperty prop) private int InitToggle(SerializedProperty prop)
{ {
int index = 0; int index = 0;

View File

@@ -0,0 +1,49 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEditor;
using UnityEngine;
namespace XCharts
{
[CustomPropertyDrawer(typeof(Polar), true)]
public class PolarDrawer : PropertyDrawer
{
private bool m_PolarModuleToggle = false;
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
{
Rect drawRect = pos;
drawRect.height = EditorGUIUtility.singleLineHeight;
SerializedProperty show = prop.FindPropertyRelative("m_Show");
SerializedProperty m_Center = prop.FindPropertyRelative("m_Center");
SerializedProperty m_Radius = prop.FindPropertyRelative("m_Radius");
SerializedProperty m_BackgroundColor = prop.FindPropertyRelative("m_BackgroundColor");
ChartEditorHelper.MakeFoldout(ref drawRect, ref m_PolarModuleToggle, "Polar", show);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
if (m_PolarModuleToggle)
{
EditorGUI.indentLevel++;
ChartEditorHelper.MakeTwoField(ref drawRect, pos.width, m_Center, "Center");
EditorGUI.PropertyField(drawRect, m_Radius);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(drawRect, m_BackgroundColor);
drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.indentLevel--;
}
}
public override float GetPropertyHeight(SerializedProperty prop, GUIContent label)
{
if (m_PolarModuleToggle)
return 4 * EditorGUIUtility.singleLineHeight + 3 * EditorGUIUtility.standardVerticalSpacing;
else
return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 48ff9465776e54e749f9ff8c424bafe2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEditor;
namespace XCharts
{
[CustomPropertyDrawer(typeof(RadiusAxis), true)]
public class RadiusAxisDrawer : AxisDrawer
{
protected override string GetDisplayName(string displayName)
{
if (displayName.StartsWith("Element"))
{
displayName = displayName.Replace("Element", "Radius Axis");
}
return displayName;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 433e6c679c39c4bf988a0447fd2e3775
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -127,5 +127,12 @@ namespace XCharts
{ {
AddChart<RingChart>("RingChart"); AddChart<RingChart>("RingChart");
} }
[MenuItem("XCharts/PolarChart", priority = 52)]
[MenuItem("GameObject/XCharts/PolarChart", priority = 52)]
public static void AddPolarChart()
{
AddChart<PolarChart>("PolarChart");
}
} }
} }

View File

@@ -0,0 +1,57 @@
using System.Runtime.InteropServices;
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEngine;
namespace XCharts.Examples
{
[DisallowMultipleComponent]
[ExecuteInEditMode]
public class Example80_Polar : MonoBehaviour
{
private PolarChart chart;
private float updateTime;
void Awake()
{
chart = gameObject.GetComponent<PolarChart>();
if (chart == null)
{
chart = gameObject.AddComponent<PolarChart>();
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
AddData();
}
}
void AddData()
{
chart.RemoveData();
chart.angleAxis.type = Axis.AxisType.Value;
chart.angleAxis.minMaxType = Axis.AxisMinMaxType.Custom;
chart.angleAxis.min = 0;
chart.angleAxis.max = 360;
chart.angleAxis.startAngle = Random.Range(0,90);
chart.AddSerie(SerieType.Line, "line1");
var rate = Random.Range(1, 4);
for (int i = 0; i <= 360; i++)
{
var t = i / 180f * Mathf.PI;
var r = Mathf.Sin(2 * t) * Mathf.Cos(2 * t) * rate;
chart.AddData(0, Mathf.Abs(r), i);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca29783da761a4e0e9c5204d5b24b610
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
public partial class PolarChart
{
/// <summary>
/// 极坐标。
/// </summary>
public Polar polar { get { return m_Polar; } }
/// <summary>
/// Angle axis of Polar Coordinate.
/// 极坐标系的角度轴。
/// </summary>
public AngleAxis angleAxis { get { return m_AngleAxis; } }
/// <summary>
/// Radial axis of polar coordinate.
/// 极坐标系的径向轴。
/// </summary>
public RadiusAxis radiusAxis { get { return m_RadiusAxis; } }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 42960f04fcc2442baa061d32386aaaa8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -805,4 +805,86 @@ namespace XCharts
} }
} }
} }
/// <summary>
/// Radial axis of polar coordinate.
/// 极坐标系的径向轴。
/// </summary>
[System.Serializable]
public class RadiusAxis : Axis
{
public static RadiusAxis defaultRadiusAxis
{
get
{
var axis = new RadiusAxis
{
m_Show = true,
m_Type = AxisType.Value,
m_Min = 0,
m_Max = 0,
m_SplitNumber = 5,
m_BoundaryGap = false,
m_Data = new List<string>(5),
};
axis.splitLine.show = true;
axis.splitLine.lineStyle.type = LineStyle.Type.Solid;
axis.axisLabel.textLimit.enable = false;
return axis;
}
}
}
/// <summary>
/// Angle axis of Polar Coordinate.
/// 极坐标系的角度轴。
/// </summary>
[System.Serializable]
public class AngleAxis : Axis
{
[SerializeField] private float m_StartAngle = 90;
[SerializeField] private bool m_Clockwise = true;
/// <summary>
/// Starting angle of axis. 90 degrees by default, standing for top position of center. 0 degree stands for right position of center.
/// 起始刻度的角度,默认为 90 度即圆心的正上方。0 度为圆心的正右方。
/// </summary>
public float startAngle
{
get { return m_StartAngle; }
set { if (PropertyUtility.SetStruct(ref m_StartAngle, value)) SetAllDirty(); }
}
/// <summary>
/// Whether the positive position of axis is in clockwise. True for clockwise by default.
/// 刻度增长是否按顺时针,默认顺时针。
/// </summary>
public bool clockWise
{
get { return m_Clockwise; }
set { if (PropertyUtility.SetStruct(ref m_Clockwise, value)) SetAllDirty(); }
}
public float runtimeStartAngle { get; set; }
public static AngleAxis defaultAngleAxis
{
get
{
var axis = new AngleAxis
{
m_Show = true,
m_Type = AxisType.Value,
m_SplitNumber = 13,
m_BoundaryGap = false,
m_Data = new List<string>(13),
};
axis.splitLine.show = true;
axis.splitLine.lineStyle.type = LineStyle.Type.Solid;
axis.axisLabel.textLimit.enable = false;
axis.minMaxType = AxisMinMaxType.Custom;
axis.min = 0;
axis.max = 360;
return axis;
}
}
}
} }

View File

@@ -0,0 +1,92 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using System;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// Polar coordinate can be used in scatter and line chart. Every polar coordinate has an angleAxis and a radiusAxis.
/// <para>
/// 极坐标系组件。
/// 极坐标系,可以用于散点图和折线图。每个极坐标系拥有一个角度轴和一个半径轴。
/// </para>
/// </summary>
[Serializable]
public class Polar : MainComponent
{
[SerializeField] private bool m_Show = true;
[SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.5f };
[SerializeField] private float m_Radius = 100;
[SerializeField] private Color m_BackgroundColor;
/// <summary>
/// Whether to show the grid in rectangular coordinate.
/// 是否显示直角坐标系网格。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtility.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// the center of ploar.
/// 极坐标的中心点。数组的第一项是横坐标,第二项是纵坐标。
/// 当值为0-1之间时表示百分比设置成百分比时第一项是相对于容器宽度第二项是相对于容器高度。
/// </summary>
public float[] center
{
get { return m_Center; }
set { if (value != null) { m_Center = value; SetAllDirty(); } }
}
/// <summary>
/// the radius of polar.
/// 极坐标的半径。
/// </summary>
public float radius
{
get { return m_Radius; }
set { if (PropertyUtility.SetStruct(ref m_Radius, value)) SetAllDirty(); }
}
/// <summary>
/// Background color of polar, which is transparent by default.
/// 极坐标的背景色,默认透明。
/// </summary>
public Color backgroundColor
{
get { return m_BackgroundColor; }
set { if (PropertyUtility.SetColor(ref m_BackgroundColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// the center position of polar in container.
/// 极坐标在容器中的具体中心点。
/// </summary>
public Vector3 runtimeCenterPos { get; internal set; }
/// <summary>
/// the true radius of polar.
/// 极坐标的运行时实际半径。
/// </summary>
public float runtimeRadius { get; internal set; }
public static Polar defaultPolar
{
get
{
var polar = new Polar
{
m_Show = true,
m_Radius = 0.35f,
};
polar.center[0] = 0.5f;
polar.center[1] = 0.45f;
return polar;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9eb9ba0a1d154f11ba169fc07ad7a91
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -249,6 +249,10 @@ namespace XCharts
/// 提示框的gameObject。 /// 提示框的gameObject。
/// </summary> /// </summary>
public GameObject runtimeGameObject { get { return m_GameObject; } } public GameObject runtimeGameObject { get { return m_GameObject; } }
/// <summary>
/// 当前指示的角度。
/// </summary>
public float runtimeAngle { get; internal set; }
public static Tooltip defaultTooltip public static Tooltip defaultTooltip
{ {
@@ -389,7 +393,7 @@ namespace XCharts
/// <param name="flag"></param> /// <param name="flag"></param>
public void SetActive(bool flag) public void SetActive(bool flag)
{ {
if(!flag && m_AlwayShow) return; if (!flag && m_AlwayShow) return;
lastDataIndex[0] = lastDataIndex[1] = -1; lastDataIndex[0] = lastDataIndex[1] = -1;
if (m_GameObject && m_GameObject.activeInHierarchy != flag) if (m_GameObject && m_GameObject.activeInHierarchy != flag)
m_GameObject.SetActive(flag); m_GameObject.SetActive(flag);

View File

@@ -167,6 +167,7 @@ namespace XCharts
/// </summary> /// </summary>
public float runtimePieOffsetRadius { get; internal set; } public float runtimePieOffsetRadius { get; internal set; }
public Vector3 runtimePosition { get; internal set; } public Vector3 runtimePosition { get; internal set; }
public float runtimeAngle { get; internal set; }
public Vector3 runtiemPieOffsetCenter { get; internal set; } public Vector3 runtiemPieOffsetCenter { get; internal set; }
private List<float> m_PreviousData = new List<float>(); private List<float> m_PreviousData = new List<float>();
private List<float> m_DataUpdateTime = new List<float>(); private List<float> m_DataUpdateTime = new List<float>();

View File

@@ -6,6 +6,7 @@
/******************************************/ /******************************************/
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
namespace XCharts namespace XCharts
{ {
@@ -165,7 +166,7 @@ namespace XCharts
/// </summary> /// </summary>
/// <param name="dataZoom"></param> /// <param name="dataZoom"></param>
/// <returns></returns> /// <returns></returns>
internal static int GetScaleNumber(Axis axis, float coordinateWidth, DataZoom dataZoom) internal static int GetScaleNumber(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
{ {
if (axis.type == Axis.AxisType.Value || axis.type == Axis.AxisType.Log) if (axis.type == Axis.AxisType.Value || axis.type == Axis.AxisType.Log)
{ {
@@ -190,7 +191,7 @@ namespace XCharts
/// <param name="coordinateWidth"></param> /// <param name="coordinateWidth"></param>
/// <param name="dataZoom"></param> /// <param name="dataZoom"></param>
/// <returns></returns> /// <returns></returns>
internal static float GetScaleWidth(Axis axis, float coordinateWidth, int index, DataZoom dataZoom) internal static float GetScaleWidth(Axis axis, float coordinateWidth, int index, DataZoom dataZoom = null)
{ {
int num = GetScaleNumber(axis, coordinateWidth, dataZoom) - 1; int num = GetScaleNumber(axis, coordinateWidth, dataZoom) - 1;
if (num <= 0) num = 1; if (num <= 0) num = 1;
@@ -285,5 +286,49 @@ namespace XCharts
else if (axis.IsValue() && axis.runtimeMinValue == 0 && axis.runtimeMaxValue == 0) return false; else if (axis.IsValue() && axis.runtimeMinValue == 0 && axis.runtimeMaxValue == 0) return false;
else return true; else return true;
} }
internal static void AdjustCircleLabelPos(Text txt, Vector3 pos, Vector3 cenPos, float txtHig, Vector3 offset)
{
var txtWidth = txt.preferredWidth;
var sizeDelta = new Vector2(txtWidth, txt.preferredHeight);
txt.GetComponent<RectTransform>().sizeDelta = sizeDelta;
var diff = pos.x - cenPos.x;
if (diff < -1f) //left
{
pos = new Vector3(pos.x - txtWidth / 2, pos.y);
}
else if (diff > 1f) //right
{
pos = new Vector3(pos.x + txtWidth / 2, pos.y);
}
else
{
float y = pos.y > cenPos.y ? pos.y + txtHig / 2 : pos.y - txtHig / 2;
pos = new Vector3(pos.x, y);
}
txt.transform.localPosition = pos + offset;
}
internal static void AdjustRadiusAxisLabelPos(Text txt, Vector3 pos, Vector3 cenPos, float txtHig, Vector3 offset)
{
var txtWidth = txt.preferredWidth;
var sizeDelta = new Vector2(txtWidth, txt.preferredHeight);
txt.GetComponent<RectTransform>().sizeDelta = sizeDelta;
var diff = pos.y - cenPos.y;
if (diff > 20f) //left
{
pos = new Vector3(pos.x - txtWidth / 2, pos.y);
}
else if (diff < -20f) //right
{
pos = new Vector3(pos.x + txtWidth / 2, pos.y);
}
else
{
float y = pos.y > cenPos.y ? pos.y + txtHig / 2 : pos.y - txtHig / 2;
pos = new Vector3(pos.x, y);
}
txt.transform.localPosition = pos;
}
} }
} }

View File

@@ -0,0 +1,34 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEngine;
namespace XCharts
{
internal static class PolarHelper
{
internal static void UpdatePolarCenter(Polar polar, Vector3 chartPosition, float chartWidth, float chartHeight)
{
if (polar.center.Length < 2) return;
var centerX = polar.center[0] <= 1 ? chartWidth * polar.center[0] : polar.center[0];
var centerY = polar.center[1] <= 1 ? chartHeight * polar.center[1] : polar.center[1];
polar.runtimeCenterPos = chartPosition + new Vector3(centerX, centerY);
if (polar.radius <= 0)
{
polar.runtimeRadius = 0;
}
else if (polar.radius <= 1)
{
polar.runtimeRadius = Mathf.Min(chartWidth, chartHeight) * polar.radius;
}
else
{
polar.runtimeRadius = polar.radius;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 64e494d13836f430ea7f4fe3e2a716b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -286,8 +286,16 @@ namespace XCharts
if (value < min) min = value; if (value < min) min = value;
} }
} }
serie.runtimeDataMin = ChartHelper.GetMinDivisibleValue(min, ceilRate); if (ceilRate < 0)
serie.runtimeDataMax = ChartHelper.GetMaxDivisibleValue(max, ceilRate); {
serie.runtimeDataMin = min;
serie.runtimeDataMax = max;
}
else
{
serie.runtimeDataMin = ChartHelper.GetMinDivisibleValue(min, ceilRate);
serie.runtimeDataMax = ChartHelper.GetMaxDivisibleValue(max, ceilRate);
}
} }
public static void GetAllMinMaxData(Serie serie, int ceilRate = 0, DataZoom dataZoom = null) public static void GetAllMinMaxData(Serie serie, int ceilRate = 0, DataZoom dataZoom = null)

View File

@@ -181,6 +181,48 @@ namespace XCharts
tooltip.UpdateContentPos(pos); tooltip.UpdateContentPos(pos);
} }
public static string GetPolarFormatterContent(Tooltip tooltip, Series series, ThemeInfo themeInfo)
{
if (string.IsNullOrEmpty(tooltip.formatter))
{
var sb = ChartHelper.sb;
sb.Length = 0;
sb.Append(tooltip.runtimeAngle).Append("\n");
foreach (var serie in series.list)
{
if (serie.show && IsSelectedSerie(tooltip, serie.index))
{
var dataIndexList = tooltip.runtimeSerieIndex[serie.index];
for (int i = 0; i < dataIndexList.Count; i++)
{
var dataIndex = dataIndexList[i];
var serieData = serie.GetSerieData(dataIndex);
var numericFormatter = GetItemNumericFormatter(tooltip, serie, serieData);
float xValue, yValue;
serie.GetXYData(dataIndex, null, out xValue, out yValue);
sb.Append("<color=#").Append(themeInfo.GetColorStr(serie.index)).Append(">● </color>");
if (!string.IsNullOrEmpty(serie.name))
sb.Append(serie.name).Append(": ");
sb.AppendFormat("{0}", ChartCached.FloatToStr(xValue, numericFormatter));
if (i != dataIndexList.Count - 1)
{
sb.Append("\n");
}
}
sb.Append("\n");
}
}
return sb.ToString().Trim();
}
else
{
string content = tooltip.formatter;
FormatterHelper.ReplaceContent(ref content, 0, tooltip.numericFormatter, null, series, themeInfo, null, null);
return content;
}
}
public static string GetFormatterContent(Tooltip tooltip, int dataIndex, Series series, ThemeInfo themeInfo, public static string GetFormatterContent(Tooltip tooltip, int dataIndex, Series series, ThemeInfo themeInfo,
string category = null, DataZoom dataZoom = null, bool isCartesian = false) string category = null, DataZoom dataZoom = null, bool isCartesian = false)
{ {

View File

@@ -0,0 +1,592 @@
/******************************************/
/* */
/* Copyright (c) 2018 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/******************************************/
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
[AddComponentMenu("XCharts/PolarChart", 21)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[DisallowMultipleComponent]
public partial class PolarChart : BaseChart
{
[SerializeField] Polar m_Polar = Polar.defaultPolar;
[SerializeField] private RadiusAxis m_RadiusAxis = RadiusAxis.defaultRadiusAxis;
[SerializeField] private AngleAxis m_AngleAxis = AngleAxis.defaultAngleAxis;
private bool m_CheckMinMaxValue = false;
protected override void Awake()
{
base.Awake();
m_CheckMinMaxValue = false;
CheckMinMaxValue();
UpdateRuntimeValue();
InitRadiusAxis(m_RadiusAxis);
InitAngleAxis(m_AngleAxis);
m_Tooltip.UpdateToTop();
}
#if UNITY_EDITOR
protected override void Reset()
{
base.Reset();
m_Title.text = "PolarChart";
m_Tooltip.type = Tooltip.Type.Line;
RemoveData();
ResetValuePolar();
Awake();
}
private void ResetValuePolar()
{
m_AngleAxis.type = Axis.AxisType.Value;
m_AngleAxis.minMaxType = Axis.AxisMinMaxType.Custom;
m_AngleAxis.min = 0;
m_AngleAxis.max = 360;
AddSerie(SerieType.Line, "line1");
for (int i = 0; i <= 360; i++)
{
var t = i / 180f * Mathf.PI;
var r = Mathf.Sin(2 * t) * Mathf.Cos(2 * t) * 2;
AddData(0, Mathf.Abs(r), i);
}
}
private void ResetCategoryPolar()
{
m_AngleAxis.type = Axis.AxisType.Category;
AddSerie(SerieType.Bar, "line1");
for (int i = 0; i <= 13; i++)
{
m_AngleAxis.AddData("bar" + i);
AddData(0, Random.Range(0, 10));
}
}
protected override void OnValidate()
{
base.OnValidate();
m_RadiusAxis.SetAllDirty();
m_AngleAxis.SetAllDirty();
CheckMinMaxValue();
}
#endif
protected override void CheckComponent()
{
if (m_Polar.anyDirty)
{
if (m_Polar.componentDirty)
{
m_AngleAxis.SetComponentDirty();
m_RadiusAxis.SetComponentDirty();
}
if (m_Polar.vertsDirty) RefreshChart();
m_Polar.ClearDirty();
}
if (m_AngleAxis.anyDirty || m_RadiusAxis.anyDirty)
{
if (m_AngleAxis.componentDirty || m_RadiusAxis.componentDirty)
{
UpdateRuntimeValue();
InitAngleAxis(m_AngleAxis);
InitRadiusAxis(m_RadiusAxis);
}
if (m_AngleAxis.vertsDirty || m_RadiusAxis.vertsDirty) RefreshChart();
m_AngleAxis.ClearDirty();
m_RadiusAxis.ClearDirty();
}
base.CheckComponent();
}
protected override void OnSizeChanged()
{
base.OnSizeChanged();
m_RadiusAxis.SetAllDirty();
m_AngleAxis.SetAllDirty();
UpdateRuntimeValue();
}
private void InitRadiusAxis(RadiusAxis axis)
{
PolarHelper.UpdatePolarCenter(m_Polar, m_ChartPosition, m_ChartWidth, m_ChartHeight);
var radius = m_Polar.runtimeRadius;
axis.axisLabelTextList.Clear();
string objName = "axis_radius";
var axisObj = ChartHelper.AddObject(objName, transform, chartAnchorMin,
chartAnchorMax, chartPivot, new Vector2(chartWidth, chartHeight));
axisObj.transform.localPosition = Vector3.zero;
axisObj.SetActive(axis.show && axis.axisLabel.show);
axisObj.hideFlags = chartHideFlags;
ChartHelper.HideAllObject(axisObj);
var labelColor = ChartHelper.IsClearColor(axis.axisLabel.color) ?
(Color)m_ThemeInfo.axisTextColor :
axis.axisLabel.color;
int splitNumber = AxisHelper.GetSplitNumber(axis, radius, null);
float totalWidth = 0;
var startAngle = m_AngleAxis.runtimeStartAngle;
var cenPos = m_Polar.runtimeCenterPos;
var txtHig = axis.axisLabel.fontSize + 2;
var dire = ChartHelper.GetDire(startAngle, true).normalized;
var tickVetor = ChartHelper.GetVertialDire(dire) * (m_RadiusAxis.axisTick.length + m_RadiusAxis.axisLabel.margin);
for (int i = 0; i < splitNumber; i++)
{
float labelWidth = AxisHelper.GetScaleWidth(axis, radius, i, null);
bool inside = axis.axisLabel.inside;
Text txt = ChartHelper.AddTextObject(objName + i, axisObj.transform,
m_ThemeInfo.font, labelColor, TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(labelWidth, txtHig),
axis.axisLabel.fontSize, axis.axisLabel.rotate, axis.axisLabel.fontStyle);
if (i == 0) axis.axisLabel.SetRelatedText(txt, labelWidth);
var isPercentStack = SeriesHelper.IsPercentStack(m_Series, SerieType.Bar);
txt.text = AxisHelper.GetLabelName(axis, radius, i, axis.runtimeMinValue, axis.runtimeMaxValue, null,
isPercentStack);
txt.gameObject.SetActive(axis.show &&
(axis.axisLabel.interval == 0 || i % (axis.axisLabel.interval + 1) == 0));
var pos = ChartHelper.GetPos(cenPos, totalWidth, startAngle, true) + tickVetor;
txt.transform.localPosition = pos;
AxisHelper.AdjustRadiusAxisLabelPos(txt, pos, cenPos, txtHig, Vector3.zero);
axis.axisLabelTextList.Add(txt);
totalWidth += labelWidth;
}
if (m_Tooltip.runtimeGameObject)
{
Vector2 privot = new Vector2(0.5f, 1);
var labelParent = m_Tooltip.runtimeGameObject.transform;
GameObject labelObj = ChartHelper.AddTooltipLabel(ChartCached.GetAxisTooltipLabel(objName), labelParent, m_ThemeInfo.font, privot);
axis.SetTooltipLabel(labelObj);
axis.SetTooltipLabelColor(m_ThemeInfo.tooltipBackgroundColor, m_ThemeInfo.tooltipTextColor);
axis.SetTooltipLabelActive(axis.show && m_Tooltip.show && m_Tooltip.type == Tooltip.Type.Corss);
}
}
private void InitAngleAxis(AngleAxis axis)
{
PolarHelper.UpdatePolarCenter(m_Polar, m_ChartPosition, m_ChartWidth, m_ChartHeight);
var radius = m_Polar.runtimeRadius;
axis.axisLabelTextList.Clear();
string objName = "axis_angle";
var axisObj = ChartHelper.AddObject(objName, transform, chartAnchorMin,
chartAnchorMax, chartPivot, new Vector2(chartWidth, chartHeight));
axisObj.transform.localPosition = Vector3.zero;
axisObj.SetActive(axis.show && axis.axisLabel.show);
axisObj.hideFlags = chartHideFlags;
ChartHelper.HideAllObject(axisObj);
var labelColor = ChartHelper.IsClearColor(axis.axisLabel.color) ?
(Color)m_ThemeInfo.axisTextColor :
axis.axisLabel.color;
int splitNumber = AxisHelper.GetSplitNumber(axis, radius, null);
float totalAngle = m_AngleAxis.runtimeStartAngle;
var total = 360;
var cenPos = m_Polar.runtimeCenterPos;
var txtHig = m_AngleAxis.axisLabel.fontSize + 2;
var margin = m_AngleAxis.axisLabel.margin;
var isCategory = m_AngleAxis.IsCategory();
for (int i = 0; i < splitNumber - 1; i++)
{
float scaleAngle = AxisHelper.GetScaleWidth(axis, total, i, null);
bool inside = axis.axisLabel.inside;
Text txt = ChartHelper.AddTextObject(objName + i, axisObj.transform,
m_ThemeInfo.font, labelColor, TextAnchor.MiddleCenter, new Vector2(0.5f, 0.5f),
new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(scaleAngle, txtHig),
axis.axisLabel.fontSize, axis.axisLabel.rotate, axis.axisLabel.fontStyle);
if (i == 0) axis.axisLabel.SetRelatedText(txt, scaleAngle);
var isPercentStack = SeriesHelper.IsPercentStack(m_Series, SerieType.Bar);
txt.text = AxisHelper.GetLabelName(axis, total, i, axis.runtimeMinValue, axis.runtimeMaxValue, null,
isPercentStack);
txt.gameObject.SetActive(axis.show &&
(axis.axisLabel.interval == 0 || i % (axis.axisLabel.interval + 1) == 0));
var pos = ChartHelper.GetPos(cenPos, radius + margin, isCategory ? (totalAngle + scaleAngle / 2) : totalAngle, true);
AxisHelper.AdjustCircleLabelPos(txt, pos, cenPos, txtHig, Vector3.zero);
axis.axisLabelTextList.Add(txt);
totalAngle += scaleAngle;
}
if (m_Tooltip.runtimeGameObject)
{
Vector2 privot = new Vector2(0.5f, 1);
var labelParent = m_Tooltip.runtimeGameObject.transform;
GameObject labelObj = ChartHelper.AddTooltipLabel(ChartCached.GetAxisTooltipLabel(objName), labelParent, m_ThemeInfo.font, privot);
axis.SetTooltipLabel(labelObj);
axis.SetTooltipLabelColor(m_ThemeInfo.tooltipBackgroundColor, m_ThemeInfo.tooltipTextColor);
axis.SetTooltipLabelActive(axis.show && m_Tooltip.show && m_Tooltip.type == Tooltip.Type.Corss);
}
}
protected override void Update()
{
base.Update();
CheckMinMaxValue();
}
private void CheckMinMaxValue()
{
if (m_RadiusAxis.IsCategory() && m_AngleAxis.IsCategory())
{
m_CheckMinMaxValue = true;
return;
}
UpdateAxisMinMaxValue(0, m_RadiusAxis);
UpdateAxisMinMaxValue(0, m_AngleAxis);
}
private void UpdateAxisMinMaxValue(int axisIndex, Axis axis, bool updateChart = true)
{
if (axis.IsCategory() || !axis.show) return;
float tempMinValue = 0;
float tempMaxValue = 0;
if (axis is RadiusAxis)
{
SeriesHelper.GetXMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
if (tempMinValue != axis.runtimeMinValue || tempMaxValue != axis.runtimeMaxValue)
{
m_CheckMinMaxValue = true;
m_IsPlayingAnimation = true;
var needCheck = !m_IsPlayingAnimation && axis.runtimeLastCheckInverse == axis.inverse;
axis.UpdateMinValue(tempMinValue, needCheck);
axis.UpdateMaxValue(tempMaxValue, needCheck);
axis.runtimeZeroXOffset = 0;
axis.runtimeZeroYOffset = 0;
axis.runtimeLastCheckInverse = axis.inverse;
if (updateChart)
{
UpdateAxisLabelText(axis);
RefreshChart();
}
}
if (axis.IsValueChanging(500) && !m_IsPlayingAnimation)
{
UpdateAxisLabelText(axis);
RefreshChart();
}
}
protected void UpdateAxisLabelText(Axis axis)
{
float m_CoordinateWidth = axis is RadiusAxis ? m_Polar.runtimeRadius : 360;
var isPercentStack = SeriesHelper.IsPercentStack(m_Series, SerieType.Bar);
axis.UpdateLabelText(m_CoordinateWidth, null, isPercentStack, 500);
}
protected override void DrawChart(VertexHelper vh)
{
base.DrawChart(vh);
DrawPolar(vh);
DrawAngleAxis(vh);
DrawRadiusAxis(vh);
DrawSerie(vh);
}
private void UpdateRuntimeValue()
{
PolarHelper.UpdatePolarCenter(m_Polar, m_ChartPosition, m_ChartWidth, m_ChartHeight);
m_AngleAxis.runtimeStartAngle = 90 - m_AngleAxis.startAngle;
}
private void DrawPolar(VertexHelper vh)
{
UpdateRuntimeValue();
if (!ChartHelper.IsClearColor(m_Polar.backgroundColor))
{
ChartDrawer.DrawCricle(vh, m_Polar.runtimeCenterPos, m_Polar.runtimeRadius, m_Polar.backgroundColor);
}
}
private void DrawRadiusAxis(VertexHelper vh)
{
var startAngle = m_AngleAxis.runtimeStartAngle;
var radius = m_Polar.runtimeRadius;
var cenPos = m_Polar.runtimeCenterPos;
var size = AxisHelper.GetScaleNumber(m_RadiusAxis, radius, null);
var totalWidth = 0f;
var dire = ChartHelper.GetDire(startAngle, true).normalized;
var tickVetor = ChartHelper.GetVertialDire(dire) * m_RadiusAxis.axisTick.length;
var tickWidth = AxisHelper.GetTickWidth(m_RadiusAxis);
for (int i = 0; i < size; i++)
{
var scaleWidth = AxisHelper.GetScaleWidth(m_RadiusAxis, radius, i);
var pos = ChartHelper.GetPos(cenPos, totalWidth, startAngle, true);
if (m_RadiusAxis.show && m_RadiusAxis.splitLine.show)
{
var outsideRaidus = totalWidth + m_RadiusAxis.splitLine.lineStyle.width * 2;
var splitLineColor = m_RadiusAxis.splitLine.GetColor(m_ThemeInfo);
ChartDrawer.DrawDoughnut(vh, cenPos, totalWidth, outsideRaidus, splitLineColor, Color.clear);
}
if (m_RadiusAxis.show && m_RadiusAxis.axisTick.show)
{
ChartDrawer.DrawLine(vh, pos, pos + tickVetor, tickWidth, m_ThemeInfo.axisLineColor);
}
totalWidth += scaleWidth;
}
if (m_RadiusAxis.show && m_RadiusAxis.axisLine.show)
{
var lineStartPos = m_Polar.runtimeCenterPos - dire * m_RadiusAxis.axisTick.width;
var lineEndPos = m_Polar.runtimeCenterPos + dire * (radius + m_RadiusAxis.axisTick.width);
ChartDrawer.DrawLine(vh, lineStartPos, lineEndPos, m_RadiusAxis.axisLine.width, m_ThemeInfo.axisLineColor);
}
}
private void DrawAngleAxis(VertexHelper vh)
{
var radius = m_Polar.runtimeRadius;
var cenPos = m_Polar.runtimeCenterPos;
var total = 360;
var size = AxisHelper.GetScaleNumber(m_AngleAxis, total, null);
var currAngle = m_AngleAxis.runtimeStartAngle;
var tickWidth = AxisHelper.GetTickWidth(m_AngleAxis);
for (int i = 0; i < size; i++)
{
var scaleWidth = AxisHelper.GetScaleWidth(m_AngleAxis, total, i);
var pos = ChartHelper.GetPos(cenPos, radius, currAngle, true);
if (m_AngleAxis.show && m_AngleAxis.splitLine.show)
{
var splitLineColor = m_AngleAxis.splitLine.GetColor(m_ThemeInfo);
ChartDrawer.DrawLine(vh, cenPos, pos, m_AngleAxis.splitLine.lineStyle.width, splitLineColor);
}
if (m_AngleAxis.show && m_AngleAxis.axisTick.show)
{
var tickPos = ChartHelper.GetPos(cenPos, radius + m_AngleAxis.axisTick.length, currAngle, true);
ChartDrawer.DrawLine(vh, pos, tickPos, tickWidth, m_ThemeInfo.axisLineColor);
}
currAngle += scaleWidth;
}
if (m_AngleAxis.show && m_AngleAxis.axisLine.show)
{
var outsideRaidus = radius + m_AngleAxis.axisLine.width * 2;
ChartDrawer.DrawDoughnut(vh, cenPos, radius, outsideRaidus, m_ThemeInfo.axisLineColor, Color.clear);
}
}
private void DrawSerie(VertexHelper vh)
{
for (int i = 0; i < m_Series.Count; i++)
{
var serie = m_Series.GetSerie(i);
serie.index = i;
if (!serie.show) continue;
switch (serie.type)
{
case SerieType.Line:
DrawPolarLine(vh, serie);
break;
case SerieType.Bar:
break;
case SerieType.Scatter:
case SerieType.EffectScatter:
break;
}
}
DrawPolarLineSymbol(vh);
}
private void DrawPolarLine(VertexHelper vh, Serie serie)
{
var startAngle = m_AngleAxis.runtimeStartAngle;
var radius = m_Polar.runtimeRadius;
var datas = serie.data;
if (datas.Count <= 0) return;
float dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
float min = m_RadiusAxis.GetCurrMinValue(dataChangeDuration);
float max = m_RadiusAxis.GetCurrMaxValue(dataChangeDuration);
var firstSerieData = datas[0];
var startPos = GetPolarPos(firstSerieData, min, max, radius);
var nextPos = Vector3.zero;
var lineColor = SerieHelper.GetLineColor(serie, m_ThemeInfo, serie.index, serie.highlighted);
var lineWidth = serie.lineStyle.width;
float currDetailProgress = 0;
float totalDetailProgress = datas.Count;
serie.animation.InitProgress(serie.dataPoints.Count, currDetailProgress, totalDetailProgress);
serie.animation.SetDataFinish(0);
for (int i = 1; i < datas.Count; i++)
{
if (serie.animation.CheckDetailBreak(i)) break;
var serieData = datas[i];
nextPos = GetPolarPos(datas[i], min, max, radius);
ChartDrawer.DrawLine(vh, startPos, nextPos, lineWidth, lineColor);
startPos = nextPos;
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(totalDetailProgress);
serie.animation.CheckSymbol(serie.symbol.size);
m_IsPlayingAnimation = true;
RefreshChart();
}
}
private void DrawPolarBar(VertexHelper vh, Serie serie)
{
}
private void DrawPolarLineSymbol(VertexHelper vh)
{
for (int n = 0; n < m_Series.Count; n++)
{
var serie = m_Series.GetSerie(n);
if (!serie.show) continue;
if (serie.type != SerieType.Line) continue;
var count = serie.dataCount;
for (int i = 0; i < count; i++)
{
var serieData = serie.GetSerieData(i);
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
if (ChartHelper.IsIngore(serieData.runtimePosition)) continue;
bool highlight = serieData.highlighted || serie.highlighted;
if ((!symbol.show || !symbol.ShowSymbol(i, count) || serie.IsPerformanceMode()) && !serieData.highlighted) continue;
float symbolSize = highlight ? symbol.selectedSize : symbol.size;
var symbolColor = SerieHelper.GetItemColor(serie, serieData, m_ThemeInfo, n, highlight);
var symbolToColor = SerieHelper.GetItemToColor(serie, serieData, m_ThemeInfo, n, highlight);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, highlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, highlight);
symbolSize = serie.animation.GetSysmbolSize(symbolSize);
DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, serieData.runtimePosition, symbolColor,
symbolToColor, symbol.gap, cornerRadius);
}
}
}
protected override void DrawTooltip(VertexHelper vh)
{
if (m_Tooltip.runtimeAngle < 0) return;
var lineColor = TooltipHelper.GetLineColor(tooltip, m_ThemeInfo);
var cenPos = m_Polar.runtimeCenterPos;
var sp = m_Polar.runtimeCenterPos;
var tooltipAngle = m_Tooltip.runtimeAngle + m_AngleAxis.runtimeStartAngle;
var ep = ChartHelper.GetPos(sp, m_Polar.runtimeRadius, tooltipAngle, true);
ChartDrawer.DrawLineStyle(vh, m_Tooltip.lineStyle, sp, ep, lineColor);
if (m_Tooltip.type == Tooltip.Type.Corss)
{
var dist = Vector2.Distance(pointerPos, cenPos);
if (dist > m_Polar.runtimeRadius) dist = m_Polar.runtimeRadius;
var outsideRaidus = dist + m_Tooltip.lineStyle.width * 2;
ChartDrawer.DrawDoughnut(vh, cenPos, dist, outsideRaidus, lineColor, Color.clear);
}
}
private Vector3 GetPolarPos(SerieData serieData, float min, float max, float polarRadius)
{
var angle = m_AngleAxis.runtimeStartAngle + serieData.GetData(1);
var value = serieData.GetData(0);
var radius = (value - min) / (max - min) * polarRadius;
serieData.runtimeAngle = (angle + 360) % 360;
serieData.runtimePosition = ChartHelper.GetPos(m_Polar.runtimeCenterPos, radius, angle, true);
return serieData.runtimePosition;
}
protected override void CheckTootipArea(Vector2 local)
{
var dist = Vector2.Distance(local, m_Polar.runtimeCenterPos);
if (dist > m_Polar.runtimeRadius)
{
m_Tooltip.runtimeAngle = -1;
if (m_Tooltip.IsActive())
{
foreach (var kv in m_Tooltip.runtimeSerieIndex)
{
var serie = m_Series.GetSerie(kv.Key);
foreach (var dataIndex in kv.Value)
{
serie.GetSerieData(dataIndex).highlighted = false;
}
}
m_Tooltip.ClearSerieDataIndex();
m_Tooltip.SetActive(false);
RefreshChart();
}
return;
}
m_Tooltip.ClearSerieDataIndex();
Vector2 dir = local - new Vector2(m_Polar.runtimeCenterPos.x, m_Polar.runtimeCenterPos.y);
float angle = ChartHelper.GetAngle360(Vector2.up, dir);
foreach (var serie in m_Series.list)
{
switch (serie.type)
{
case SerieType.Line:
bool refresh = false;
var count = serie.data.Count;
SerieHelper.GetDimensionMinMaxData(serie, 1, -1);
var diff = (serie.runtimeDataMax - serie.runtimeDataMin) / (count - 1);
for (int j = 0; j < count; j++)
{
var serieData = serie.data[j];
var flag = Mathf.Abs(serieData.runtimeAngle - angle) < Mathf.Abs(diff / 2);
if (serieData.highlighted != flag)
{
refresh = true;
}
serieData.highlighted = flag;
if (flag)
{
m_Tooltip.runtimeAngle = (serieData.runtimeAngle - m_AngleAxis.runtimeStartAngle + 360) % 360;
m_Tooltip.AddSerieDataIndex(serie.index, j);
}
}
if (refresh) RefreshChart();
break;
case SerieType.Bar:
break;
case SerieType.Scatter:
case SerieType.EffectScatter:
break;
}
}
m_Tooltip.UpdateContentPos(new Vector2(local.x + 18, local.y - 25));
UpdateTooltip();
if (m_Tooltip.type == Tooltip.Type.Corss)
{
RefreshChart();
}
}
private float GetAngleDiff(SerieData nextData, SerieData serieData, float angle)
{
var nextAngle = nextData.runtimeAngle;
var lastAngle = serieData.runtimeAngle;
var diff = 0f;
if (nextAngle > 270 && lastAngle < 90)
{
diff = 360 - nextAngle + lastAngle;
}
else
{
diff = nextAngle - lastAngle;
}
return Mathf.Abs(diff);
}
protected override void UpdateTooltip()
{
base.UpdateTooltip();
var showTooltip = m_Tooltip.isAnySerieDataIndex();
if (showTooltip)
{
var content = TooltipHelper.GetPolarFormatterContent(m_Tooltip, m_Series, m_ThemeInfo);
TooltipHelper.SetContentAndPosition(tooltip, content, chartRect);
}
m_Tooltip.SetActive(showTooltip);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 52fd81110b7774a4096479f4cd777579
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -133,24 +133,8 @@ namespace XCharts
txt.gameObject.hideFlags = chartHideFlags; txt.gameObject.hideFlags = chartHideFlags;
txt.text = radar.indicatorList[i].name; txt.text = radar.indicatorList[i].name;
txt.gameObject.SetActive(radar.indicator); txt.gameObject.SetActive(radar.indicator);
var txtWidth = txt.preferredWidth; var offset = new Vector3(textStyle.offset.x, textStyle.offset.y);
var sizeDelta = new Vector2(txt.preferredWidth, txt.preferredHeight); AxisHelper.AdjustCircleLabelPos(txt, pos, radar.runtimeCenterPos, txtHig, offset);
txt.GetComponent<RectTransform>().sizeDelta = sizeDelta;
var diff = pos.x - radar.runtimeCenterPos.x;
if (diff < -1f) //left
{
pos = new Vector3(pos.x - txtWidth / 2, pos.y);
}
else if (diff > 1f) //right
{
pos = new Vector3(pos.x + txtWidth / 2, pos.y);
}
else
{
float y = pos.y > radar.runtimeCenterPos.y ? pos.y + txtHig / 2 : pos.y - txtHig / 2;
pos = new Vector3(pos.x, y);
}
txt.transform.localPosition = pos + new Vector3(textStyle.offset.x, textStyle.offset.y);
} }
} }
} }

View File

@@ -824,7 +824,7 @@ namespace XCharts
float borderAngle = 0; float borderAngle = 0;
float spaceAngle = 0; float spaceAngle = 0;
var p2 = p + radius * GetDire(startAngle); var p2 = p + radius * ChartHelper.GetDire(startAngle);
var p3 = Vector3.zero; var p3 = Vector3.zero;
var p4 = Vector3.zero; var p4 = Vector3.zero;
var spaceCenter = p; var spaceCenter = p;
@@ -834,7 +834,7 @@ namespace XCharts
var needBorder = borderWidth != 0; var needBorder = borderWidth != 0;
var needSpace = space != 0; var needSpace = space != 0;
var lastPos = Vector3.zero; var lastPos = Vector3.zero;
var middleDire = GetDire(startAngle + halfAngle); var middleDire = ChartHelper.GetDire(startAngle + halfAngle);
if (needBorder || needSpace) if (needBorder || needSpace)
{ {
float spaceDiff = 0f; float spaceDiff = 0f;
@@ -848,7 +848,7 @@ namespace XCharts
realStartAngle = startAngle + spaceAngle; realStartAngle = startAngle + spaceAngle;
realToAngle = toAngle - spaceAngle; realToAngle = toAngle - spaceAngle;
if (realToAngle < realStartAngle) realToAngle = realStartAngle; if (realToAngle < realStartAngle) realToAngle = realStartAngle;
p2 = GetPos(p, radius, realStartAngle); p2 = ChartHelper.GetPos(p, radius, realStartAngle);
} }
if (needBorder) if (needBorder)
{ {
@@ -860,16 +860,16 @@ namespace XCharts
if (realToAngle < realStartAngle) if (realToAngle < realStartAngle)
{ {
realToAngle = realStartAngle; realToAngle = realStartAngle;
p2 = GetPos(p, radius, realStartAngle); p2 = ChartHelper.GetPos(p, radius, realStartAngle);
} }
else else
{ {
var borderX1 = GetPos(p, radius, realStartAngle); var borderX1 = ChartHelper.GetPos(p, radius, realStartAngle);
DrawPolygon(vh, realCenter, spaceCenter, p2, borderX1, borderColor); DrawPolygon(vh, realCenter, spaceCenter, p2, borderX1, borderColor);
p2 = borderX1; p2 = borderX1;
var borderX2 = GetPos(p, radius, realToAngle); var borderX2 = ChartHelper.GetPos(p, radius, realToAngle);
var pEnd = GetPos(p, radius, toAngle - spaceAngle); var pEnd = ChartHelper.GetPos(p, radius, toAngle - spaceAngle);
DrawPolygon(vh, realCenter, borderX2, pEnd, spaceCenter, borderColor); DrawPolygon(vh, realCenter, borderX2, pEnd, spaceCenter, borderColor);
} }
} }
@@ -879,7 +879,7 @@ namespace XCharts
for (int i = 0; i <= segments; i++) for (int i = 0; i <= segments; i++)
{ {
float currAngle = realStartAngle + i * segmentAngle; float currAngle = realStartAngle + i * segmentAngle;
p3 = p + radius * GetDire(currAngle); p3 = p + radius * ChartHelper.GetDire(currAngle);
if (gradientType == 1) if (gradientType == 1)
{ {
if (isYAxis) if (isYAxis)
@@ -918,7 +918,7 @@ namespace XCharts
{ {
if (realToAngle > realStartAngle) if (realToAngle > realStartAngle)
{ {
var borderX2 = p + radius * GetDire(realToAngle); var borderX2 = p + radius * ChartHelper.GetDire(realToAngle);
DrawTriangle(vh, realCenter, p2, borderX2, toColor, color, color); DrawTriangle(vh, realCenter, p2, borderX2, toColor, color, color);
if (needBorder) if (needBorder)
{ {
@@ -931,17 +931,7 @@ namespace XCharts
} }
} }
private static Vector3 GetPos(Vector3 center, float radius, float angle, bool isDegree = false)
{
angle = isDegree ? angle * Mathf.Deg2Rad : angle;
return new Vector3(center.x + radius * Mathf.Sin(angle), center.y + radius * Mathf.Cos(angle));
}
private static Vector3 GetDire(float angle, bool isDegree = false)
{
angle = isDegree ? angle * Mathf.Deg2Rad : angle;
return new Vector3(Mathf.Sin(angle), Mathf.Cos(angle));
}
public static void DrawRoundCap(VertexHelper vh, Vector3 center, float width, float radius, float angle, public static void DrawRoundCap(VertexHelper vh, Vector3 center, float width, float radius, float angle,
bool clockwise, Color color, bool end) bool clockwise, Color color, bool end)
@@ -1059,8 +1049,8 @@ namespace XCharts
spaceHalfAngle = 2 * Mathf.Asin(space / (2 * (insideRadius + (outsideRadius - insideRadius) / 2))); spaceHalfAngle = 2 * Mathf.Asin(space / (2 * (insideRadius + (outsideRadius - insideRadius) / 2)));
if (clockwise) if (clockwise)
{ {
p1 = GetPos(p, insideRadius, startAngle + spaceInAngle, false); p1 = ChartHelper.GetPos(p, insideRadius, startAngle + spaceInAngle, false);
e1 = GetPos(p, insideRadius, toAngle - spaceInAngle, false); e1 = ChartHelper.GetPos(p, insideRadius, toAngle - spaceInAngle, false);
realStartOutAngle = startAngle + spaceAngle; realStartOutAngle = startAngle + spaceAngle;
realToOutAngle = toAngle - spaceAngle; realToOutAngle = toAngle - spaceAngle;
realStartInAngle = startAngle + spaceInAngle; realStartInAngle = startAngle + spaceInAngle;
@@ -1068,15 +1058,15 @@ namespace XCharts
} }
else else
{ {
p1 = GetPos(p, insideRadius, startAngle - spaceInAngle, false); p1 = ChartHelper.GetPos(p, insideRadius, startAngle - spaceInAngle, false);
e1 = GetPos(p, insideRadius, toAngle + spaceInAngle, false); e1 = ChartHelper.GetPos(p, insideRadius, toAngle + spaceInAngle, false);
realStartOutAngle = startAngle - spaceAngle; realStartOutAngle = startAngle - spaceAngle;
realToOutAngle = toAngle + spaceAngle; realToOutAngle = toAngle + spaceAngle;
realStartInAngle = startAngle - spaceInAngle; realStartInAngle = startAngle - spaceInAngle;
realToOutAngle = toAngle + spaceInAngle; realToOutAngle = toAngle + spaceInAngle;
} }
p2 = GetPos(p, outsideRadius, realStartOutAngle, false); p2 = ChartHelper.GetPos(p, outsideRadius, realStartOutAngle, false);
e2 = GetPos(p, outsideRadius, realToOutAngle, false); e2 = ChartHelper.GetPos(p, outsideRadius, realToOutAngle, false);
} }
if (needBorder) if (needBorder)
{ {
@@ -1091,15 +1081,15 @@ namespace XCharts
realToOutAngle = realToOutAngle - borderAngle; realToOutAngle = realToOutAngle - borderAngle;
realStartInAngle = startAngle + spaceInAngle + borderInAngle; realStartInAngle = startAngle + spaceInAngle + borderInAngle;
realToInAngle = toAngle - spaceInAngle - borderInAngle; realToInAngle = toAngle - spaceInAngle - borderInAngle;
var newp1 = GetPos(p, insideRadius, startAngle + spaceInAngle + borderInAngle, false); var newp1 = ChartHelper.GetPos(p, insideRadius, startAngle + spaceInAngle + borderInAngle, false);
var newp2 = GetPos(p, outsideRadius, realStartOutAngle, false); var newp2 = ChartHelper.GetPos(p, outsideRadius, realStartOutAngle, false);
if (!roundCap) DrawPolygon(vh, newp2, newp1, p1, p2, borderColor); if (!roundCap) DrawPolygon(vh, newp2, newp1, p1, p2, borderColor);
p1 = newp1; p1 = newp1;
p2 = newp2; p2 = newp2;
if (toAngle - spaceInAngle - 2 * borderInAngle > realStartOutAngle) if (toAngle - spaceInAngle - 2 * borderInAngle > realStartOutAngle)
{ {
var newe1 = GetPos(p, insideRadius, toAngle - spaceInAngle - borderInAngle, false); var newe1 = ChartHelper.GetPos(p, insideRadius, toAngle - spaceInAngle - borderInAngle, false);
var newe2 = GetPos(p, outsideRadius, realToOutAngle, false); var newe2 = ChartHelper.GetPos(p, outsideRadius, realToOutAngle, false);
if (!roundCap) DrawPolygon(vh, newe2, e2, e1, newe1, borderColor); if (!roundCap) DrawPolygon(vh, newe2, e2, e1, newe1, borderColor);
e1 = newe1; e1 = newe1;
e2 = newe2; e2 = newe2;
@@ -1111,15 +1101,15 @@ namespace XCharts
realToOutAngle = realToOutAngle + borderAngle; realToOutAngle = realToOutAngle + borderAngle;
realStartInAngle = startAngle - spaceInAngle - borderInAngle; realStartInAngle = startAngle - spaceInAngle - borderInAngle;
realToInAngle = toAngle + spaceInAngle + borderInAngle; realToInAngle = toAngle + spaceInAngle + borderInAngle;
var newp1 = GetPos(p, insideRadius, startAngle - spaceInAngle - borderInAngle, false); var newp1 = ChartHelper.GetPos(p, insideRadius, startAngle - spaceInAngle - borderInAngle, false);
var newp2 = GetPos(p, outsideRadius, realStartOutAngle, false); var newp2 = ChartHelper.GetPos(p, outsideRadius, realStartOutAngle, false);
if (!roundCap) DrawPolygon(vh, newp2, newp1, p1, p2, borderColor); if (!roundCap) DrawPolygon(vh, newp2, newp1, p1, p2, borderColor);
p1 = newp1; p1 = newp1;
p2 = newp2; p2 = newp2;
if (toAngle + spaceInAngle + 2 * borderInAngle < realStartOutAngle) if (toAngle + spaceInAngle + 2 * borderInAngle < realStartOutAngle)
{ {
var newe1 = GetPos(p, insideRadius, toAngle + spaceInAngle + borderInAngle, false); var newe1 = ChartHelper.GetPos(p, insideRadius, toAngle + spaceInAngle + borderInAngle, false);
var newe2 = GetPos(p, outsideRadius, realToOutAngle, false); var newe2 = ChartHelper.GetPos(p, outsideRadius, realToOutAngle, false);
if (!roundCap) DrawPolygon(vh, newe2, e2, e1, newe1, borderColor); if (!roundCap) DrawPolygon(vh, newe2, e2, e1, newe1, borderColor);
e1 = newe1; e1 = newe1;
e2 = newe2; e2 = newe2;
@@ -1143,7 +1133,7 @@ namespace XCharts
realStartInAngle = startAngle - 2 * spaceHalfAngle - borderHalfAngle - roundAngle; realStartInAngle = startAngle - 2 * spaceHalfAngle - borderHalfAngle - roundAngle;
} }
var roundTotalDegree = realStartOutAngle * Mathf.Rad2Deg; var roundTotalDegree = realStartOutAngle * Mathf.Rad2Deg;
var roundCenter = p + roundAngleRadius * GetDire(realStartOutAngle); var roundCenter = p + roundAngleRadius * ChartHelper.GetDire(realStartOutAngle);
var sectorStartDegree = clockwise ? roundTotalDegree + 180 : roundTotalDegree; var sectorStartDegree = clockwise ? roundTotalDegree + 180 : roundTotalDegree;
var sectorToDegree = clockwise ? roundTotalDegree + 360 : roundTotalDegree + 180; var sectorToDegree = clockwise ? roundTotalDegree + 360 : roundTotalDegree + 180;
DrawSector(vh, roundCenter, roundRadius, color, sectorStartDegree, sectorToDegree, smoothness / 2); DrawSector(vh, roundCenter, roundRadius, color, sectorStartDegree, sectorToDegree, smoothness / 2);
@@ -1152,8 +1142,8 @@ namespace XCharts
DrawDoughnut(vh, roundCenter, roundRadius, roundRadius + borderWidth, borderColor, Color.clear, DrawDoughnut(vh, roundCenter, roundRadius, roundRadius + borderWidth, borderColor, Color.clear,
sectorStartDegree, sectorToDegree, smoothness / 2); sectorStartDegree, sectorToDegree, smoothness / 2);
} }
p1 = GetPos(p, insideRadius, realStartOutAngle); p1 = ChartHelper.GetPos(p, insideRadius, realStartOutAngle);
p2 = GetPos(p, outsideRadius, realStartOutAngle); p2 = ChartHelper.GetPos(p, outsideRadius, realStartOutAngle);
if (clockwise) if (clockwise)
{ {
@@ -1168,7 +1158,7 @@ namespace XCharts
if (realToOutAngle > realStartOutAngle) realToOutAngle = realStartOutAngle; if (realToOutAngle > realStartOutAngle) realToOutAngle = realStartOutAngle;
} }
roundTotalDegree = realToOutAngle * Mathf.Rad2Deg; roundTotalDegree = realToOutAngle * Mathf.Rad2Deg;
roundCenter = p + roundAngleRadius * GetDire(realToOutAngle); roundCenter = p + roundAngleRadius * ChartHelper.GetDire(realToOutAngle);
sectorStartDegree = clockwise ? roundTotalDegree : roundTotalDegree + 180; sectorStartDegree = clockwise ? roundTotalDegree : roundTotalDegree + 180;
sectorToDegree = clockwise ? roundTotalDegree + 180 : roundTotalDegree + 360; sectorToDegree = clockwise ? roundTotalDegree + 180 : roundTotalDegree + 360;
DrawSector(vh, roundCenter, roundRadius, color, sectorStartDegree, sectorToDegree, smoothness / 2); DrawSector(vh, roundCenter, roundRadius, color, sectorStartDegree, sectorToDegree, smoothness / 2);
@@ -1177,8 +1167,8 @@ namespace XCharts
DrawDoughnut(vh, roundCenter, roundRadius, roundRadius + borderWidth, borderColor, Color.clear, DrawDoughnut(vh, roundCenter, roundRadius, roundRadius + borderWidth, borderColor, Color.clear,
sectorStartDegree, sectorToDegree, smoothness / 2); sectorStartDegree, sectorToDegree, smoothness / 2);
} }
e1 = GetPos(p, insideRadius, realToOutAngle); e1 = ChartHelper.GetPos(p, insideRadius, realToOutAngle);
e2 = GetPos(p, outsideRadius, realToOutAngle); e2 = ChartHelper.GetPos(p, outsideRadius, realToOutAngle);
} }
float segmentAngle = (realToInAngle - realStartInAngle) / segments; float segmentAngle = (realToInAngle - realStartInAngle) / segments;
for (int i = 0; i <= segments; i++) for (int i = 0; i <= segments; i++)

View File

@@ -759,5 +759,33 @@ namespace XCharts
angle = (angle + 360) % 360; angle = (angle + 360) % 360;
return angle; return angle;
} }
public static Vector3 GetPos(Vector3 center, float radius, float angle, bool isDegree = false)
{
angle = isDegree ? angle * Mathf.Deg2Rad : angle;
return new Vector3(center.x + radius * Mathf.Sin(angle), center.y + radius * Mathf.Cos(angle));
}
public static Vector3 GetDire(float angle, bool isDegree = false)
{
angle = isDegree ? angle * Mathf.Deg2Rad : angle;
return new Vector3(Mathf.Sin(angle), Mathf.Cos(angle));
}
public static Vector3 GetVertialDire(Vector3 dire)
{
if (dire.x == 0)
{
return new Vector3(-1, 0, 0);
}
if (dire.y == 0)
{
return new Vector3(0, -1, 0);
}
else
{
return new Vector3(-dire.y / dire.x, 1, 0).normalized;
}
}
} }
} }

File diff suppressed because it is too large Load Diff