UI update 02
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
public class UIRadarGraphic : MaskableGraphic
|
||||
{
|
||||
private const float MainStrokeWidth = 2.5f;
|
||||
private const float ReferenceStrokeWidth = 2f;
|
||||
private const float MainPointSize = 8f;
|
||||
private const float ReferencePointSize = 7f;
|
||||
|
||||
private readonly List<URadarAxisEntry> axisEntries = new List<URadarAxisEntry>();
|
||||
|
||||
private float minValue;
|
||||
private float maxValue = 100f;
|
||||
private int splitCount = 5;
|
||||
private bool showReferenceSeries;
|
||||
private Color gridLineColor = new Color32(255, 255, 255, 180);
|
||||
private Color outerGridLineColor = Color.white;
|
||||
private float gridLineWidth = 2f;
|
||||
private Color mainStrokeColor = new Color32(82, 126, 255, 255);
|
||||
private Color mainFillColor = new Color(82f / 255f, 126f / 255f, 255f / 255f, 0.28f);
|
||||
private Color mainPointColor = Color.white;
|
||||
private Color referenceStrokeColor = new Color32(72, 229, 229, 255);
|
||||
private Color referenceFillColor = new Color(72f / 255f, 229f / 255f, 229f / 255f, 0.22f);
|
||||
private Color referencePointColor = Color.white;
|
||||
private float radarPlotPadding = 8f;
|
||||
private float radarInnerRadius;
|
||||
private float radarLabelRadialOffset;
|
||||
|
||||
public void SetData(
|
||||
List<URadarAxisEntry> sourceAxes,
|
||||
float sourceMinValue,
|
||||
float sourceMaxValue,
|
||||
int sourceSplitCount,
|
||||
bool sourceShowReferenceSeries,
|
||||
Color sourceGridLineColor,
|
||||
Color sourceOuterGridLineColor,
|
||||
float sourceGridLineWidth,
|
||||
Color sourceMainStrokeColor,
|
||||
Color sourceMainFillColor,
|
||||
Color sourceMainPointColor,
|
||||
Color sourceReferenceStrokeColor,
|
||||
Color sourceReferenceFillColor,
|
||||
Color sourceReferencePointColor,
|
||||
float sourceRadarPlotPadding,
|
||||
float sourceRadarInnerRadius,
|
||||
float sourceRadarLabelRadialOffset)
|
||||
{
|
||||
axisEntries.Clear();
|
||||
if (sourceAxes != null)
|
||||
{
|
||||
for (int i = 0; i < sourceAxes.Count; i++)
|
||||
{
|
||||
URadarAxisEntry source = sourceAxes[i];
|
||||
if (source == null)
|
||||
{
|
||||
axisEntries.Add(new URadarAxisEntry());
|
||||
continue;
|
||||
}
|
||||
|
||||
axisEntries.Add(new URadarAxisEntry
|
||||
{
|
||||
label = source.label,
|
||||
value = source.value,
|
||||
referenceValue = source.referenceValue
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
minValue = sourceMinValue;
|
||||
maxValue = Mathf.Max(sourceMinValue + 0.0001f, sourceMaxValue);
|
||||
splitCount = Mathf.Max(2, sourceSplitCount);
|
||||
showReferenceSeries = sourceShowReferenceSeries;
|
||||
gridLineColor = sourceGridLineColor;
|
||||
outerGridLineColor = sourceOuterGridLineColor;
|
||||
gridLineWidth = Mathf.Max(0.1f, sourceGridLineWidth);
|
||||
mainStrokeColor = sourceMainStrokeColor;
|
||||
mainFillColor = sourceMainFillColor;
|
||||
mainPointColor = sourceMainPointColor;
|
||||
referenceStrokeColor = sourceReferenceStrokeColor;
|
||||
referenceFillColor = sourceReferenceFillColor;
|
||||
referencePointColor = sourceReferencePointColor;
|
||||
radarPlotPadding = Mathf.Max(0f, sourceRadarPlotPadding);
|
||||
radarInnerRadius = Mathf.Max(0f, sourceRadarInnerRadius);
|
||||
radarLabelRadialOffset = sourceRadarLabelRadialOffset;
|
||||
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
vh.Clear();
|
||||
|
||||
if (axisEntries.Count < 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rect rect = GetPixelAdjustedRect();
|
||||
Vector2 center = rect.center;
|
||||
float maxRadius = Mathf.Max(0f, Mathf.Min(rect.width, rect.height) * 0.5f - radarPlotPadding - Mathf.Max(MainPointSize, ReferencePointSize));
|
||||
float innerRadius = Mathf.Clamp(radarInnerRadius, 0f, maxRadius * 0.8f);
|
||||
|
||||
DrawGrid(vh, center, innerRadius, maxRadius);
|
||||
|
||||
List<Vector2> mainPoints = BuildSeriesPoints(center, innerRadius, maxRadius, false);
|
||||
if (showReferenceSeries)
|
||||
{
|
||||
List<Vector2> referencePoints = BuildSeriesPoints(center, innerRadius, maxRadius, true);
|
||||
DrawFilledPolygon(vh, center, referencePoints, referenceFillColor);
|
||||
DrawPolyline(vh, referencePoints, true, ReferenceStrokeWidth, referenceStrokeColor);
|
||||
DrawPointMarkers(vh, referencePoints, ReferencePointSize, referencePointColor);
|
||||
}
|
||||
|
||||
DrawFilledPolygon(vh, center, mainPoints, mainFillColor);
|
||||
DrawPolyline(vh, mainPoints, true, MainStrokeWidth, mainStrokeColor);
|
||||
DrawPointMarkers(vh, mainPoints, MainPointSize, mainPointColor);
|
||||
}
|
||||
|
||||
private void DrawGrid(VertexHelper vh, Vector2 center, float innerRadius, float maxRadius)
|
||||
{
|
||||
int axisCount = axisEntries.Count;
|
||||
for (int ring = 1; ring <= splitCount; ring++)
|
||||
{
|
||||
float t = ring / (float)splitCount;
|
||||
float radius = Mathf.Lerp(innerRadius, maxRadius, t);
|
||||
List<Vector2> ringPoints = new List<Vector2>(axisCount);
|
||||
for (int i = 0; i < axisCount; i++)
|
||||
{
|
||||
ringPoints.Add(GetAxisPoint(center, radius, i, axisCount));
|
||||
}
|
||||
|
||||
DrawPolyline(vh, ringPoints, true, gridLineWidth, ring == splitCount ? outerGridLineColor : gridLineColor);
|
||||
}
|
||||
|
||||
for (int i = 0; i < axisCount; i++)
|
||||
{
|
||||
Vector2 start = GetAxisPoint(center, innerRadius, i, axisCount);
|
||||
Vector2 end = GetAxisPoint(center, maxRadius, i, axisCount);
|
||||
DrawLine(vh, start, end, gridLineWidth, gridLineColor);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Vector2> BuildSeriesPoints(Vector2 center, float innerRadius, float maxRadius, bool useReferenceValue)
|
||||
{
|
||||
int axisCount = axisEntries.Count;
|
||||
List<Vector2> points = new List<Vector2>(axisCount);
|
||||
|
||||
for (int i = 0; i < axisCount; i++)
|
||||
{
|
||||
URadarAxisEntry entry = axisEntries[i];
|
||||
float value = useReferenceValue ? entry.referenceValue : entry.value;
|
||||
float normalized = Mathf.InverseLerp(minValue, maxValue, Mathf.Clamp(value, minValue, maxValue));
|
||||
float radius = Mathf.Lerp(innerRadius, maxRadius, normalized);
|
||||
points.Add(GetAxisPoint(center, radius, i, axisCount));
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static Vector2 GetAxisPoint(Vector2 center, float radius, int axisIndex, int axisCount)
|
||||
{
|
||||
float angle = Mathf.PI * 0.5f - (Mathf.PI * 2f / axisCount) * axisIndex;
|
||||
return center + new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
|
||||
}
|
||||
|
||||
private static void DrawFilledPolygon(VertexHelper vh, Vector2 center, List<Vector2> points, Color color)
|
||||
{
|
||||
if (points == null || points.Count < 3 || color.a <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int startIndex = vh.currentVertCount;
|
||||
UIVertex centerVertex = UIVertex.simpleVert;
|
||||
centerVertex.color = color;
|
||||
centerVertex.position = center;
|
||||
vh.AddVert(centerVertex);
|
||||
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
UIVertex vertex = UIVertex.simpleVert;
|
||||
vertex.color = color;
|
||||
vertex.position = points[i];
|
||||
vh.AddVert(vertex);
|
||||
}
|
||||
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
int current = startIndex + 1 + i;
|
||||
int next = startIndex + 1 + ((i + 1) % points.Count);
|
||||
vh.AddTriangle(startIndex, current, next);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawPolyline(VertexHelper vh, List<Vector2> points, bool closed, float thickness, Color color)
|
||||
{
|
||||
if (points == null || points.Count < 2 || color.a <= 0f || thickness <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
DrawLine(vh, points[i], points[i + 1], thickness, color);
|
||||
}
|
||||
|
||||
if (closed)
|
||||
{
|
||||
DrawLine(vh, points[points.Count - 1], points[0], thickness, color);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawLine(VertexHelper vh, Vector2 start, Vector2 end, float thickness, Color color)
|
||||
{
|
||||
Vector2 delta = end - start;
|
||||
if (delta.sqrMagnitude <= 0.0001f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 normal = new Vector2(-delta.y, delta.x).normalized * (thickness * 0.5f);
|
||||
int index = vh.currentVertCount;
|
||||
|
||||
UIVertex vertex = UIVertex.simpleVert;
|
||||
vertex.color = color;
|
||||
|
||||
vertex.position = start - normal;
|
||||
vh.AddVert(vertex);
|
||||
vertex.position = start + normal;
|
||||
vh.AddVert(vertex);
|
||||
vertex.position = end + normal;
|
||||
vh.AddVert(vertex);
|
||||
vertex.position = end - normal;
|
||||
vh.AddVert(vertex);
|
||||
|
||||
vh.AddTriangle(index, index + 1, index + 2);
|
||||
vh.AddTriangle(index, index + 2, index + 3);
|
||||
}
|
||||
|
||||
private static void DrawPointMarkers(VertexHelper vh, List<Vector2> points, float size, Color color)
|
||||
{
|
||||
if (points == null || color.a <= 0f || size <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float half = size * 0.5f;
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
DrawQuad(vh, points[i], new Vector2(half, half), color);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawQuad(VertexHelper vh, Vector2 center, Vector2 halfSize, Color color)
|
||||
{
|
||||
int index = vh.currentVertCount;
|
||||
UIVertex vertex = UIVertex.simpleVert;
|
||||
vertex.color = color;
|
||||
|
||||
vertex.position = new Vector2(center.x - halfSize.x, center.y - halfSize.y);
|
||||
vh.AddVert(vertex);
|
||||
vertex.position = new Vector2(center.x - halfSize.x, center.y + halfSize.y);
|
||||
vh.AddVert(vertex);
|
||||
vertex.position = new Vector2(center.x + halfSize.x, center.y + halfSize.y);
|
||||
vh.AddVert(vertex);
|
||||
vertex.position = new Vector2(center.x + halfSize.x, center.y - halfSize.y);
|
||||
vh.AddVert(vertex);
|
||||
|
||||
vh.AddTriangle(index, index + 1, index + 2);
|
||||
vh.AddTriangle(index, index + 2, index + 3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3ca4e8566bf67d45a1c44b84dbb88dd
|
||||
@@ -1,12 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using EasyChart;
|
||||
using EasyChart.UGUI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.UIElements;
|
||||
using XCharts.Runtime;
|
||||
|
||||
public class URadarChartController : MonoBehaviour
|
||||
{
|
||||
[Header("Chart")]
|
||||
[Header("Legacy Compatibility")]
|
||||
public UGUIChartBridge chartBridge;
|
||||
|
||||
[Header("Chart")]
|
||||
public bool rebuildOnEnable = true;
|
||||
public bool showReferenceSeries = false;
|
||||
public int enforcedSortOrder = 0;
|
||||
@@ -62,6 +66,11 @@ public class URadarChartController : MonoBehaviour
|
||||
|
||||
[Header("Style")]
|
||||
public bool overrideSeriesStyle = true;
|
||||
public bool overrideSymbolStyle = true;
|
||||
public float mainSymbolSize = 8f;
|
||||
public float referenceSymbolSize = 7f;
|
||||
public SymbolType mainSymbolType = SymbolType.Circle;
|
||||
public SymbolType referenceSymbolType = SymbolType.Circle;
|
||||
public Color mainStrokeColor = new Color32(82, 126, 255, 255);
|
||||
public Color mainFillColor = new Color(82f / 255f, 126f / 255f, 255f / 255f, 0.28f);
|
||||
public Color mainPointColor = Color.white;
|
||||
@@ -72,15 +81,34 @@ public class URadarChartController : MonoBehaviour
|
||||
[Min(0f)] public float radarInnerRadius = 0f;
|
||||
[Min(0f)] public float radarLabelRadialOffset = 0f;
|
||||
|
||||
private ChartProfile sourceProfile;
|
||||
private ChartProfile runtimeProfile;
|
||||
private ChartTheme runtimeTheme;
|
||||
[Header("Legacy Serialized Fields")]
|
||||
[SerializeField] private UIRadarGraphic radarGraphic;
|
||||
[SerializeField] private RectTransform labelRoot;
|
||||
[SerializeField] private bool autoCreateLabelRoot = true;
|
||||
[SerializeField] private string labelRootName = "RadarLabels";
|
||||
|
||||
[Header("XCharts Runtime")]
|
||||
[SerializeField] private RectTransform radarChartHost;
|
||||
[SerializeField] private string radarChartHostName = "RadarChartHost";
|
||||
[SerializeField] private RadarChart radarChart;
|
||||
|
||||
private bool rebuildQueued;
|
||||
private bool chartInitialized;
|
||||
|
||||
public bool IsRendererReady
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureRenderer();
|
||||
return radarChart != null;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
showReferenceSeries = false;
|
||||
NormalizeAxes();
|
||||
EnsureRenderer();
|
||||
QueueRebuild();
|
||||
}
|
||||
|
||||
@@ -88,6 +116,7 @@ public class URadarChartController : MonoBehaviour
|
||||
{
|
||||
showReferenceSeries = false;
|
||||
NormalizeAxes();
|
||||
EnsureRenderer();
|
||||
if (rebuildOnEnable)
|
||||
{
|
||||
QueueRebuild();
|
||||
@@ -111,27 +140,15 @@ public class URadarChartController : MonoBehaviour
|
||||
gridLineWidth = Mathf.Max(0.1f, gridLineWidth);
|
||||
radarInnerRadius = Mathf.Max(0f, radarInnerRadius);
|
||||
radarLabelRadialOffset = Mathf.Max(0f, radarLabelRadialOffset);
|
||||
mainSymbolSize = Mathf.Max(0f, mainSymbolSize);
|
||||
referenceSymbolSize = Mathf.Max(0f, referenceSymbolSize);
|
||||
tooltipBorderWidth = Mathf.Max(0f, tooltipBorderWidth);
|
||||
tooltipCornerRadius = Mathf.Max(0f, tooltipCornerRadius);
|
||||
axisCount = Mathf.Max(3, axisCount);
|
||||
EnsureRenderer(false);
|
||||
QueueRebuild();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (runtimeProfile != null)
|
||||
{
|
||||
DestroyImmediate(runtimeProfile);
|
||||
runtimeProfile = null;
|
||||
}
|
||||
|
||||
if (runtimeTheme != null)
|
||||
{
|
||||
DestroyImmediate(runtimeTheme);
|
||||
runtimeTheme = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void QueueRebuild()
|
||||
{
|
||||
rebuildQueued = true;
|
||||
@@ -203,6 +220,35 @@ public class URadarChartController : MonoBehaviour
|
||||
NormalizeAxes();
|
||||
}
|
||||
|
||||
public void EnsureRenderer(bool initializeChart = true)
|
||||
{
|
||||
DisableLegacyRenderer();
|
||||
|
||||
EnsureChartHost();
|
||||
|
||||
if (radarChart == null)
|
||||
{
|
||||
radarChart = radarChartHost != null ? radarChartHost.GetComponent<RadarChart>() : null;
|
||||
}
|
||||
|
||||
if (radarChart == null && radarChartHost != null)
|
||||
{
|
||||
radarChart = radarChartHost.gameObject.AddComponent<RadarChart>();
|
||||
}
|
||||
|
||||
if (radarChart != null)
|
||||
{
|
||||
radarChart.enabled = true;
|
||||
radarChart.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
if (initializeChart)
|
||||
{
|
||||
EnsureChartInitialized();
|
||||
}
|
||||
EnsureRuntimeChartStyle();
|
||||
}
|
||||
|
||||
private bool TryGetAxis(int index, out URadarAxisEntry axis)
|
||||
{
|
||||
NormalizeAxes();
|
||||
@@ -218,243 +264,368 @@ public class URadarChartController : MonoBehaviour
|
||||
|
||||
private void TryRebuild()
|
||||
{
|
||||
if (chartBridge == null || chartBridge.Profile == null)
|
||||
EnsureRenderer();
|
||||
if (radarChart == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceProfile == null)
|
||||
{
|
||||
sourceProfile = chartBridge.Profile;
|
||||
}
|
||||
|
||||
if (sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureRuntimeProfile();
|
||||
EnsureBridgePriority();
|
||||
ConfigureRuntimeProfile();
|
||||
chartBridge.Refresh();
|
||||
ApplyRuntimeTheme();
|
||||
ApplyRendererState();
|
||||
rebuildQueued = false;
|
||||
}
|
||||
|
||||
private void EnsureRuntimeProfile()
|
||||
{
|
||||
if (runtimeProfile != null)
|
||||
{
|
||||
if (!ReferenceEquals(chartBridge.Profile, runtimeProfile))
|
||||
{
|
||||
chartBridge.Profile = runtimeProfile;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeProfile = Instantiate(sourceProfile);
|
||||
runtimeProfile.name = sourceProfile.name + "_URadar_Runtime";
|
||||
runtimeProfile.hideFlags = HideFlags.DontSave;
|
||||
chartBridge.Profile = runtimeProfile;
|
||||
}
|
||||
|
||||
private void EnsureBridgePriority()
|
||||
{
|
||||
if (chartBridge != null && chartBridge.SortOrder < enforcedSortOrder)
|
||||
{
|
||||
chartBridge.SortOrder = enforcedSortOrder;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureRuntimeProfile()
|
||||
private void ApplyRendererState()
|
||||
{
|
||||
NormalizeAxes();
|
||||
EnsureChartInitialized();
|
||||
|
||||
runtimeProfile.coordinateSystem = CoordinateSystemType.Polar2D;
|
||||
runtimeProfile.EnsureRuntimeData();
|
||||
radarChart.RemoveChartComponents<RadarCoord>();
|
||||
radarChart.RemoveData();
|
||||
|
||||
runtimeProfile.polarAxes.angleAxis.labels = BuildLabels();
|
||||
runtimeProfile.polarAxes.angleAxis.visible = true;
|
||||
runtimeProfile.polarAxes.angleAxis.showLabels = true;
|
||||
if (runtimeProfile.polarAxes.angleAxis.labelStyle == null)
|
||||
RadarCoord radarCoord = radarChart.AddChartComponent<RadarCoord>();
|
||||
if (radarCoord == null)
|
||||
{
|
||||
runtimeProfile.polarAxes.angleAxis.labelStyle = new LabelStyleSettings();
|
||||
}
|
||||
runtimeProfile.polarAxes.angleAxis.labelStyle.enabled = true;
|
||||
|
||||
runtimeProfile.polarAxes.radiusAxis.visible = true;
|
||||
runtimeProfile.polarAxes.radiusAxis.autoRangeMin = false;
|
||||
runtimeProfile.polarAxes.radiusAxis.autoRangeMax = false;
|
||||
runtimeProfile.polarAxes.radiusAxis.minValue = minValue;
|
||||
runtimeProfile.polarAxes.radiusAxis.maxValue = Mathf.Max(minValue + 1f, maxValue);
|
||||
runtimeProfile.polarAxes.radiusAxis.splitCount = Mathf.Max(2, splitCount);
|
||||
if (runtimeProfile.polarAxes.radiusAxis.labelStyle == null)
|
||||
{
|
||||
runtimeProfile.polarAxes.radiusAxis.labelStyle = new LabelStyleSettings();
|
||||
}
|
||||
runtimeProfile.polarAxes.radiusAxis.labelStyle.enabled = runtimeProfile.polarAxes.radiusAxis.showLabels;
|
||||
|
||||
if (overrideGridStyle)
|
||||
{
|
||||
runtimeProfile.polarAxes.angleAxis.color = gridLineColor;
|
||||
runtimeProfile.polarAxes.angleAxis.width = gridLineWidth;
|
||||
runtimeProfile.polarAxes.radiusAxis.color = gridLineColor;
|
||||
runtimeProfile.polarAxes.radiusAxis.edgeColor = outerGridLineColor;
|
||||
runtimeProfile.polarAxes.radiusAxis.width = gridLineWidth;
|
||||
return;
|
||||
}
|
||||
|
||||
if (overrideLabelStyle)
|
||||
{
|
||||
runtimeProfile.polarAxes.angleAxis.labelColor = axisLabelColor;
|
||||
runtimeProfile.polarAxes.angleAxis.fontSize = axisLabelFontSize;
|
||||
runtimeProfile.polarAxes.angleAxis.labelOffset = axisLabelOffset;
|
||||
runtimeProfile.polarAxes.angleAxis.labelStyle.fontSize = axisLabelFontSize;
|
||||
runtimeProfile.polarAxes.angleAxis.labelStyle.color = axisLabelColor;
|
||||
runtimeProfile.polarAxes.angleAxis.labelStyle.offset = axisLabelOffset;
|
||||
radarCoord.indicatorList.Clear();
|
||||
|
||||
runtimeProfile.polarAxes.radiusAxis.labelColor = axisLabelColor;
|
||||
runtimeProfile.polarAxes.radiusAxis.fontSize = axisLabelFontSize;
|
||||
runtimeProfile.polarAxes.radiusAxis.labelStyle.fontSize = axisLabelFontSize;
|
||||
runtimeProfile.polarAxes.radiusAxis.labelStyle.color = axisLabelColor;
|
||||
float clampedMin = Mathf.Min(minValue, maxValue - 0.0001f);
|
||||
float clampedMax = Mathf.Max(minValue + 0.0001f, maxValue);
|
||||
|
||||
for (int i = 0; i < axes.Count; i++)
|
||||
{
|
||||
string label = string.IsNullOrWhiteSpace(axes[i].label) ? $"Axis {i + 1}" : axes[i].label.Trim();
|
||||
radarCoord.AddIndicator(label, clampedMin, clampedMax);
|
||||
}
|
||||
|
||||
if (runtimeProfile.series == null)
|
||||
ConfigureRadarCoord(radarCoord);
|
||||
|
||||
Radar mainSerie = radarChart.AddSerie<Radar>(mainSeriesName);
|
||||
if (mainSerie != null)
|
||||
{
|
||||
runtimeProfile.series = new List<Serie>();
|
||||
mainSerie.radarIndex = radarCoord.index;
|
||||
}
|
||||
ConfigureSerie(mainSerie, true);
|
||||
if (mainSerie != null)
|
||||
{
|
||||
radarChart.AddData(mainSerie.index, BuildDataValues(false), mainSeriesName);
|
||||
}
|
||||
|
||||
int targetSeriesCount = 1;
|
||||
while (runtimeProfile.series.Count < targetSeriesCount)
|
||||
if (showReferenceSeries)
|
||||
{
|
||||
runtimeProfile.series.Add(new Serie());
|
||||
Radar referenceSerie = radarChart.AddSerie<Radar>(referenceSeriesName);
|
||||
if (referenceSerie != null)
|
||||
{
|
||||
referenceSerie.radarIndex = radarCoord.index;
|
||||
}
|
||||
ConfigureSerie(referenceSerie, false);
|
||||
if (referenceSerie != null)
|
||||
{
|
||||
radarChart.AddData(referenceSerie.index, BuildDataValues(true), referenceSeriesName);
|
||||
}
|
||||
}
|
||||
|
||||
while (runtimeProfile.series.Count > targetSeriesCount)
|
||||
{
|
||||
runtimeProfile.series.RemoveAt(runtimeProfile.series.Count - 1);
|
||||
}
|
||||
|
||||
ConfigureSeries(runtimeProfile.series[0], mainSeriesName, true);
|
||||
|
||||
runtimeProfile.EnsureRuntimeData();
|
||||
RefreshLegendAndTooltip();
|
||||
radarChart.RefreshChart();
|
||||
}
|
||||
|
||||
private void ApplyRuntimeTheme()
|
||||
private void ConfigureRadarCoord(RadarCoord radarCoord)
|
||||
{
|
||||
if (chartBridge == null || chartBridge.ChartElement == null)
|
||||
RectTransform rectTransform = transform as RectTransform;
|
||||
float minRectSize = rectTransform == null ? 0f : Mathf.Min(rectTransform.rect.width, rectTransform.rect.height);
|
||||
float reservedRadius = Mathf.Max(0f, radarPlotPadding);
|
||||
float computedRadius = minRectSize > 0f
|
||||
? Mathf.Max(0f, (minRectSize * 0.5f) - reservedRadius - Mathf.Max(0f, radarLabelRadialOffset))
|
||||
: 0f;
|
||||
float xchartsRadius = minRectSize > 0f ? Mathf.Clamp01(computedRadius / minRectSize) : 0.35f;
|
||||
if (xchartsRadius <= 0f)
|
||||
{
|
||||
return;
|
||||
xchartsRadius = 0.35f;
|
||||
}
|
||||
|
||||
bool useTooltipStyle = overrideTooltipStyle;
|
||||
bool useTooltipFont = overrideTooltipFont && tooltipFont != null;
|
||||
bool useLabelFont = overrideLabelFont && axisLabelFont != null;
|
||||
radarCoord.show = true;
|
||||
radarCoord.shape = RadarCoord.Shape.Polygon;
|
||||
radarCoord.splitNumber = Mathf.Max(2, splitCount);
|
||||
radarCoord.center[0] = 0.5f;
|
||||
radarCoord.center[1] = 0.5f;
|
||||
radarCoord.radius = xchartsRadius;
|
||||
radarCoord.indicator = true;
|
||||
radarCoord.indicatorGap = radarLabelRadialOffset;
|
||||
radarCoord.positionType = RadarCoord.PositionType.Vertice;
|
||||
radarCoord.isAxisTooltip = false;
|
||||
radarCoord.startAngle = 0f;
|
||||
|
||||
if (!useLabelFont && !useTooltipFont && !useTooltipStyle)
|
||||
{
|
||||
chartBridge.ChartElement.Theme = null;
|
||||
return;
|
||||
}
|
||||
Color innerGrid = overrideGridStyle ? gridLineColor : new Color32(255, 255, 255, 180);
|
||||
Color outerGrid = overrideGridStyle ? outerGridLineColor : Color.white;
|
||||
Color effectiveLabelColor = overrideLabelStyle ? axisLabelColor : Color.white;
|
||||
Vector2 effectiveLabelOffset = overrideLabelStyle ? axisLabelOffset : Vector2.zero;
|
||||
Font effectiveLabelFont = overrideLabelFont && axisLabelFont != null ? axisLabelFont : axisLabelFont;
|
||||
|
||||
if (runtimeTheme == null)
|
||||
{
|
||||
runtimeTheme = ScriptableObject.CreateInstance<ChartTheme>();
|
||||
runtimeTheme.name = "URadar_RuntimeTheme";
|
||||
runtimeTheme.hideFlags = HideFlags.DontSave;
|
||||
}
|
||||
radarCoord.axisLine.show = true;
|
||||
radarCoord.axisLine.lineStyle.show = true;
|
||||
radarCoord.axisLine.lineStyle.type = LineStyle.Type.Solid;
|
||||
radarCoord.axisLine.lineStyle.width = gridLineWidth;
|
||||
radarCoord.axisLine.lineStyle.color = innerGrid;
|
||||
|
||||
runtimeTheme.primaryFont = useLabelFont ? axisLabelFont : null;
|
||||
runtimeTheme.axisFontSize = useLabelFont ? axisLabelFontSize : -1f;
|
||||
runtimeTheme.tooltipFont = useTooltipFont ? tooltipFont : null;
|
||||
runtimeTheme.tooltipFontSize = (useTooltipFont || useTooltipStyle) ? tooltipFontSize : -1f;
|
||||
runtimeTheme.tooltipTextColor = useTooltipStyle ? tooltipTextColor : Color.white;
|
||||
runtimeTheme.tooltipBackgroundColor = useTooltipStyle ? tooltipBackgroundColor : new Color(0f, 0f, 0f, 0.8f);
|
||||
runtimeTheme.tooltipBorderColor = useTooltipStyle ? tooltipBorderColor : new Color(0f, 0f, 0f, 0f);
|
||||
runtimeTheme.tooltipBorderWidth = useTooltipStyle ? tooltipBorderWidth : 0f;
|
||||
runtimeTheme.tooltipCornerRadius = useTooltipStyle ? tooltipCornerRadius : 4f;
|
||||
runtimeTheme.tooltipPadding = useTooltipStyle ? tooltipPadding : new Vector4(8f, 8f, 4f, 4f);
|
||||
radarCoord.splitLine.show = true;
|
||||
radarCoord.splitLine.lineStyle.show = true;
|
||||
radarCoord.splitLine.lineStyle.type = LineStyle.Type.Solid;
|
||||
radarCoord.splitLine.lineStyle.width = gridLineWidth;
|
||||
radarCoord.splitLine.lineStyle.color = outerGrid;
|
||||
|
||||
// Force ChartElement.Theme setter to re-apply tooltip visuals even when reusing the same runtime theme instance.
|
||||
chartBridge.ChartElement.Theme = null;
|
||||
chartBridge.ChartElement.Theme = runtimeTheme;
|
||||
radarCoord.splitArea.show = false;
|
||||
|
||||
radarCoord.axisName.show = true;
|
||||
radarCoord.axisName.name = null;
|
||||
radarCoord.axisName.labelStyle.show = true;
|
||||
radarCoord.axisName.labelStyle.textStyle.autoColor = false;
|
||||
radarCoord.axisName.labelStyle.textStyle.color = effectiveLabelColor;
|
||||
radarCoord.axisName.labelStyle.textStyle.fontSize = axisLabelFontSize;
|
||||
radarCoord.axisName.labelStyle.textStyle.font = effectiveLabelFont;
|
||||
radarCoord.axisName.labelStyle.textStyle.autoAlign = false;
|
||||
radarCoord.axisName.labelStyle.textStyle.alignment = TextAnchor.MiddleCenter;
|
||||
radarCoord.axisName.labelStyle.offset = new Vector3(effectiveLabelOffset.x, effectiveLabelOffset.y, 0f);
|
||||
radarCoord.axisName.labelStyle.width = 140f;
|
||||
radarCoord.axisName.labelStyle.height = Mathf.Max(24f, axisLabelFontSize + 10f);
|
||||
radarCoord.SetVerticesDirty();
|
||||
}
|
||||
|
||||
private void ConfigureSeries(Serie serie, string serieName, bool isMainSeries)
|
||||
private void ConfigureSerie(Radar serie, bool isMainSerie)
|
||||
{
|
||||
if (serie == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
serie.name = string.IsNullOrWhiteSpace(serieName) ? (isMainSeries ? "Player" : "Reference") : serieName.Trim();
|
||||
serie.visible = true;
|
||||
if (serie.type != SerieType.Radar)
|
||||
serie.radarType = RadarType.Multiple;
|
||||
serie.showDataName = false;
|
||||
serie.symbol.show = true;
|
||||
if (overrideSymbolStyle)
|
||||
{
|
||||
serie.SetType(SerieType.Radar);
|
||||
}
|
||||
|
||||
if (!(serie.settings is RadarSettings radarSettings))
|
||||
{
|
||||
radarSettings = new RadarSettings();
|
||||
serie.settings = radarSettings;
|
||||
}
|
||||
|
||||
radarSettings.radar.innerRadius = radarInnerRadius;
|
||||
radarSettings.radar.outerRadius = 0f;
|
||||
radarSettings.radar.plot.padding = radarPlotPadding;
|
||||
radarSettings.radar.plot.labelRadialOffset = radarLabelRadialOffset;
|
||||
|
||||
radarSettings.area.show = true;
|
||||
radarSettings.point.show = true;
|
||||
|
||||
if (overrideSeriesStyle)
|
||||
{
|
||||
radarSettings.stroke.color = isMainSeries ? mainStrokeColor : referenceStrokeColor;
|
||||
radarSettings.stroke.width = isMainSeries ? 2.5f : 2f;
|
||||
radarSettings.area.textureFill.color = isMainSeries ? mainFillColor : referenceFillColor;
|
||||
radarSettings.point.textureFill.color = isMainSeries ? mainPointColor : referencePointColor;
|
||||
radarSettings.point.size = isMainSeries ? 8f : 7f;
|
||||
}
|
||||
|
||||
if (serie.labelSettings != null)
|
||||
{
|
||||
serie.labelSettings.enabled = false;
|
||||
}
|
||||
|
||||
if (serie.seriesData == null)
|
||||
{
|
||||
serie.seriesData = new List<SeriesData>();
|
||||
serie.symbol.type = isMainSerie ? mainSymbolType : referenceSymbolType;
|
||||
serie.symbol.size = isMainSerie ? mainSymbolSize : referenceSymbolSize;
|
||||
serie.symbol.color = isMainSerie ? mainPointColor : referencePointColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
serie.seriesData.Clear();
|
||||
serie.symbol.type = SymbolType.Circle;
|
||||
serie.symbol.size = isMainSerie ? 8f : 7f;
|
||||
serie.symbol.color = Color.white;
|
||||
}
|
||||
|
||||
for (int i = 0; i < axisCount; i++)
|
||||
serie.lineStyle.show = true;
|
||||
serie.lineStyle.type = LineStyle.Type.Solid;
|
||||
serie.lineStyle.width = isMainSerie ? 2.5f : 2f;
|
||||
serie.lineStyle.color = isMainSerie
|
||||
? (overrideSeriesStyle ? mainStrokeColor : new Color32(82, 126, 255, 255))
|
||||
: (overrideSeriesStyle ? referenceStrokeColor : new Color32(72, 229, 229, 255));
|
||||
|
||||
AreaStyle areaStyle = serie.EnsureComponent<AreaStyle>();
|
||||
areaStyle.show = true;
|
||||
areaStyle.color = isMainSerie
|
||||
? (overrideSeriesStyle ? mainFillColor : new Color(82f / 255f, 126f / 255f, 1f, 0.28f))
|
||||
: (overrideSeriesStyle ? referenceFillColor : new Color(72f / 255f, 229f / 255f, 229f / 255f, 0.22f));
|
||||
areaStyle.toColor = Color.clear;
|
||||
areaStyle.opacity = 1f;
|
||||
|
||||
LabelStyle labelStyle = serie.EnsureComponent<LabelStyle>();
|
||||
labelStyle.show = false;
|
||||
}
|
||||
|
||||
private List<double> BuildDataValues(bool useReferenceValue)
|
||||
{
|
||||
List<double> values = new List<double>(axes.Count);
|
||||
for (int i = 0; i < axes.Count; i++)
|
||||
{
|
||||
URadarAxisEntry axis = axes[i];
|
||||
float value = isMainSeries ? axis.value : axis.referenceValue;
|
||||
serie.seriesData.Add(new SeriesData
|
||||
float raw = useReferenceValue ? axes[i].referenceValue : axes[i].value;
|
||||
values.Add(Mathf.Clamp(raw, minValue, maxValue));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private void RefreshLegendAndTooltip()
|
||||
{
|
||||
Legend legend = radarChart.GetChartComponent<Legend>();
|
||||
if (legend != null)
|
||||
{
|
||||
legend.show = false;
|
||||
legend.data.Clear();
|
||||
}
|
||||
|
||||
Title title = radarChart.GetChartComponent<Title>();
|
||||
if (title != null)
|
||||
{
|
||||
title.show = false;
|
||||
title.text = string.Empty;
|
||||
title.subText = string.Empty;
|
||||
}
|
||||
|
||||
XCharts.Runtime.Background background = radarChart.GetChartComponent<XCharts.Runtime.Background>();
|
||||
if (background != null)
|
||||
{
|
||||
background.show = false;
|
||||
}
|
||||
|
||||
Tooltip tooltip = radarChart.GetChartComponent<Tooltip>();
|
||||
if (tooltip == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tooltip.show = false;
|
||||
tooltip.showContent = false;
|
||||
tooltip.type = Tooltip.Type.None;
|
||||
tooltip.trigger = Tooltip.Trigger.None;
|
||||
|
||||
if (overrideTooltipStyle)
|
||||
{
|
||||
tooltip.backgroundColor = tooltipBackgroundColor;
|
||||
tooltip.borderColor = tooltipBorderColor;
|
||||
tooltip.borderWidth = tooltipBorderWidth;
|
||||
tooltip.paddingLeftRight = Mathf.RoundToInt(Mathf.Max(0f, tooltipPadding.x));
|
||||
tooltip.paddingTopBottom = Mathf.RoundToInt(Mathf.Max(0f, tooltipPadding.z));
|
||||
}
|
||||
|
||||
if (overrideTooltipFont)
|
||||
{
|
||||
tooltip.titleLabelStyle.textStyle.font = tooltipFont;
|
||||
tooltip.titleLabelStyle.textStyle.fontSize = tooltipFontSize;
|
||||
tooltip.titleLabelStyle.textStyle.color = tooltipTextColor;
|
||||
for (int i = 0; i < tooltip.contentLabelStyles.Count; i++)
|
||||
{
|
||||
id = (isMainSeries ? "main_" : "ref_") + i,
|
||||
name = axis.label,
|
||||
x = i,
|
||||
value = Mathf.Clamp(value, minValue, maxValue)
|
||||
});
|
||||
tooltip.contentLabelStyles[i].textStyle.font = tooltipFont;
|
||||
tooltip.contentLabelStyles[i].textStyle.fontSize = tooltipFontSize;
|
||||
tooltip.contentLabelStyles[i].textStyle.color = tooltipTextColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> BuildLabels()
|
||||
private void EnsureChartInitialized()
|
||||
{
|
||||
List<string> labels = new List<string>(axisCount);
|
||||
for (int i = 0; i < axisCount; i++)
|
||||
if (radarChart == null)
|
||||
{
|
||||
string label = axes[i] != null ? axes[i].label : null;
|
||||
labels.Add(string.IsNullOrWhiteSpace(label) ? $"Axis {i + 1}" : label.Trim());
|
||||
return;
|
||||
}
|
||||
|
||||
return labels;
|
||||
if (!chartInitialized)
|
||||
{
|
||||
radarChart.Init();
|
||||
chartInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
radarChart.EnsureChartComponent<Title>();
|
||||
radarChart.EnsureChartComponent<Tooltip>();
|
||||
radarChart.EnsureChartComponent<XCharts.Runtime.Background>();
|
||||
radarChart.EnsureChartComponent<RadarCoord>();
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureRuntimeChartStyle()
|
||||
{
|
||||
if (radarChart == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
radarChart.raycastTarget = false;
|
||||
CanvasRenderer canvasRenderer = radarChart.GetComponent<CanvasRenderer>();
|
||||
if (canvasRenderer != null)
|
||||
{
|
||||
canvasRenderer.SetAlpha(1f);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureChartHost()
|
||||
{
|
||||
if (radarChartHost == null)
|
||||
{
|
||||
Transform existing = transform.Find(radarChartHostName);
|
||||
if (existing != null)
|
||||
{
|
||||
radarChartHost = existing as RectTransform;
|
||||
}
|
||||
}
|
||||
|
||||
if (radarChartHost == null)
|
||||
{
|
||||
GameObject host = new GameObject(radarChartHostName, typeof(RectTransform));
|
||||
radarChartHost = host.GetComponent<RectTransform>();
|
||||
radarChartHost.SetParent(transform, false);
|
||||
}
|
||||
|
||||
radarChartHost.anchorMin = Vector2.zero;
|
||||
radarChartHost.anchorMax = Vector2.one;
|
||||
radarChartHost.pivot = new Vector2(0.5f, 0.5f);
|
||||
radarChartHost.anchoredPosition = Vector2.zero;
|
||||
radarChartHost.sizeDelta = Vector2.zero;
|
||||
radarChartHost.offsetMin = Vector2.zero;
|
||||
radarChartHost.offsetMax = Vector2.zero;
|
||||
radarChartHost.localScale = Vector3.one;
|
||||
radarChartHost.localRotation = Quaternion.identity;
|
||||
radarChartHost.SetAsLastSibling();
|
||||
radarChartHost.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
private void DisableLegacyRenderer()
|
||||
{
|
||||
if (chartBridge == null)
|
||||
{
|
||||
chartBridge = GetComponent<UGUIChartBridge>();
|
||||
}
|
||||
|
||||
if (chartBridge != null)
|
||||
{
|
||||
chartBridge.enabled = false;
|
||||
}
|
||||
|
||||
UIDocument uiDocument = GetComponent<UIDocument>();
|
||||
if (uiDocument != null)
|
||||
{
|
||||
uiDocument.enabled = false;
|
||||
}
|
||||
|
||||
RawImage rawImage = GetComponent<RawImage>();
|
||||
if (rawImage != null)
|
||||
{
|
||||
rawImage.enabled = false;
|
||||
rawImage.texture = null;
|
||||
rawImage.raycastTarget = false;
|
||||
Color color = rawImage.color;
|
||||
color.a = 0f;
|
||||
rawImage.color = color;
|
||||
}
|
||||
|
||||
if (radarGraphic == null)
|
||||
{
|
||||
radarGraphic = GetComponent<UIRadarGraphic>();
|
||||
}
|
||||
|
||||
if (radarGraphic != null)
|
||||
{
|
||||
radarGraphic.enabled = false;
|
||||
radarGraphic.raycastTarget = false;
|
||||
Color color = radarGraphic.color;
|
||||
color.a = 0f;
|
||||
radarGraphic.color = color;
|
||||
radarGraphic.SetVerticesDirty();
|
||||
}
|
||||
|
||||
if (labelRoot == null && autoCreateLabelRoot)
|
||||
{
|
||||
Transform existing = transform.Find(labelRootName);
|
||||
if (existing != null)
|
||||
{
|
||||
labelRoot = existing as RectTransform;
|
||||
}
|
||||
}
|
||||
|
||||
if (labelRoot != null)
|
||||
{
|
||||
labelRoot.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void NormalizeAxes()
|
||||
|
||||
@@ -99,8 +99,7 @@ public class uBehaviourRaderController : MonoBehaviour
|
||||
ResolveDependencies();
|
||||
|
||||
if (radarChartController != null &&
|
||||
chartBridge != null &&
|
||||
chartBridge.Profile != null)
|
||||
radarChartController.IsRendererReady)
|
||||
{
|
||||
ApplyOverlayVisibility(btmandtopController.CurrentOverlayPanelsVisible);
|
||||
ApplySummary(BuildSummary(RecentPlayHistoryStore.GetRecords()));
|
||||
@@ -145,6 +144,11 @@ public class uBehaviourRaderController : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
if (chartBridge != null)
|
||||
{
|
||||
chartBridge.DisablePointerInteraction = true;
|
||||
}
|
||||
|
||||
if (rankConfig == null)
|
||||
{
|
||||
RankConfig[] configs = Resources.LoadAll<RankConfig>(string.Empty);
|
||||
@@ -232,6 +236,12 @@ public class uBehaviourRaderController : MonoBehaviour
|
||||
|
||||
bool shouldShow = !hideWhenOverlayVisible || !overlayVisible;
|
||||
bool wasActive = uRaderObj.activeSelf;
|
||||
|
||||
if (!shouldShow && chartBridge != null)
|
||||
{
|
||||
chartBridge.ReleaseRuntimeResources();
|
||||
}
|
||||
|
||||
uRaderObj.SetActive(shouldShow);
|
||||
|
||||
if (shouldShow && !wasActive)
|
||||
@@ -242,14 +252,18 @@ public class uBehaviourRaderController : MonoBehaviour
|
||||
|
||||
private void ForceRefreshChartBridge()
|
||||
{
|
||||
if (chartBridge == null)
|
||||
if (radarChartController == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
chartBridge.enabled = false;
|
||||
chartBridge.enabled = true;
|
||||
chartBridge.Refresh();
|
||||
if (chartBridge != null)
|
||||
{
|
||||
chartBridge.DisablePointerInteraction = true;
|
||||
chartBridge.ReleaseRuntimeResources();
|
||||
}
|
||||
|
||||
radarChartController.RebuildNow();
|
||||
}
|
||||
|
||||
private void ApplySummary(BehaviourRadarSummary summary)
|
||||
|
||||
Reference in New Issue
Block a user