297 lines
7.5 KiB
C#
297 lines
7.5 KiB
C#
|
|
using System.Collections.Generic;
|
|||
|
|
using TMPro;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// UI兼容的图表组件
|
|||
|
|
/// 使用UI Image和RectTransform在Canvas中绘制折线图,替代LineRenderer
|
|||
|
|
/// </summary>
|
|||
|
|
public class UIChartComponent : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
[Header("图表设置")]
|
|||
|
|
public RectTransform chartArea;
|
|||
|
|
public TextMeshProUGUI valueLabel;
|
|||
|
|
public TextMeshProUGUI titleLabel;
|
|||
|
|
public Color lineColor = Color.green;
|
|||
|
|
public float lineWidth = 2f;
|
|||
|
|
|
|||
|
|
[Header("数据设置")]
|
|||
|
|
public int maxDataPoints = 50;
|
|||
|
|
public float minValue = 0f;
|
|||
|
|
public float maxValue = 100f;
|
|||
|
|
public string unit = "";
|
|||
|
|
|
|||
|
|
[Header("UI设置")]
|
|||
|
|
public GameObject linePrefab; // 预制件:包含Image组件的GameObject
|
|||
|
|
public Transform lineParent; // 折线段的父物体
|
|||
|
|
|
|||
|
|
private List<float> dataPoints = new List<float>();
|
|||
|
|
private List<GameObject> lineSegments = new List<GameObject>();
|
|||
|
|
|
|||
|
|
void Awake()
|
|||
|
|
{
|
|||
|
|
InitializeChart();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化图表
|
|||
|
|
/// </summary>
|
|||
|
|
private void InitializeChart()
|
|||
|
|
{
|
|||
|
|
// 如果没有设置lineParent,使用chartArea
|
|||
|
|
if (lineParent == null && chartArea != null)
|
|||
|
|
{
|
|||
|
|
lineParent = chartArea;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果没有linePrefab,创建一个默认的
|
|||
|
|
if (linePrefab == null)
|
|||
|
|
{
|
|||
|
|
CreateDefaultLinePrefab();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 创建默认的线段预制件
|
|||
|
|
/// </summary>
|
|||
|
|
private void CreateDefaultLinePrefab()
|
|||
|
|
{
|
|||
|
|
linePrefab = new GameObject("LineSegment");
|
|||
|
|
|
|||
|
|
// 添加RectTransform
|
|||
|
|
var rectTransform = linePrefab.AddComponent<RectTransform>();
|
|||
|
|
rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
|
|||
|
|
rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
|
|||
|
|
rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
|||
|
|
|
|||
|
|
// 添加Image组件
|
|||
|
|
var image = linePrefab.AddComponent<Image>();
|
|||
|
|
image.color = lineColor;
|
|||
|
|
|
|||
|
|
// 设置为预制件状态
|
|||
|
|
linePrefab.SetActive(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 添加数据点
|
|||
|
|
/// </summary>
|
|||
|
|
public void AddDataPoint(float value)
|
|||
|
|
{
|
|||
|
|
dataPoints.Add(value);
|
|||
|
|
|
|||
|
|
// 保持最大数据点数量
|
|||
|
|
if (dataPoints.Count > maxDataPoints)
|
|||
|
|
{
|
|||
|
|
dataPoints.RemoveAt(0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateChart();
|
|||
|
|
UpdateValueLabel(value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 更新图表显示
|
|||
|
|
/// </summary>
|
|||
|
|
private void UpdateChart()
|
|||
|
|
{
|
|||
|
|
if (chartArea == null || lineParent == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int requiredSegmentCount = Mathf.Max(0, dataPoints.Count - 1);
|
|||
|
|
EnsureLineSegmentCount(requiredSegmentCount);
|
|||
|
|
|
|||
|
|
var rect = chartArea.rect;
|
|||
|
|
var width = rect.width;
|
|||
|
|
var height = rect.height;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < lineSegments.Count; i++)
|
|||
|
|
{
|
|||
|
|
var segment = lineSegments[i];
|
|||
|
|
if (segment == null)
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool active = i < requiredSegmentCount;
|
|||
|
|
if (segment.activeSelf != active)
|
|||
|
|
{
|
|||
|
|
segment.SetActive(active);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!active)
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Vector2 point1 = CalculatePointPosition(i, dataPoints[i], width, height);
|
|||
|
|
Vector2 point2 = CalculatePointPosition(i + 1, dataPoints[i + 1], width, height);
|
|||
|
|
UpdateLineSegment(segment, point1, point2);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 计算数据点在图表中的位置
|
|||
|
|
/// </summary>
|
|||
|
|
private Vector2 CalculatePointPosition(int index, float value, float width, float height)
|
|||
|
|
{
|
|||
|
|
float x = (float)index / (maxDataPoints - 1) * width - width / 2;
|
|||
|
|
float y = Mathf.Lerp(-height / 2, height / 2,
|
|||
|
|
Mathf.InverseLerp(minValue, maxValue, value));
|
|||
|
|
|
|||
|
|
return new Vector2(x, y);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 创建线段
|
|||
|
|
/// </summary>
|
|||
|
|
private void EnsureLineSegmentCount(int requiredCount)
|
|||
|
|
{
|
|||
|
|
if (linePrefab == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
while (lineSegments.Count < requiredCount)
|
|||
|
|
{
|
|||
|
|
GameObject segment = Instantiate(linePrefab, lineParent);
|
|||
|
|
segment.SetActive(false);
|
|||
|
|
lineSegments.Add(segment);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateLineSegment(GameObject segment, Vector2 point1, Vector2 point2)
|
|||
|
|
{
|
|||
|
|
if (segment == null) return;
|
|||
|
|
|
|||
|
|
RectTransform segmentRect = segment.GetComponent<RectTransform>();
|
|||
|
|
Image segmentImage = segment.GetComponent<Image>();
|
|||
|
|
if (segmentRect == null) return;
|
|||
|
|
|
|||
|
|
// 计算线段的位置、长度和角度
|
|||
|
|
Vector2 direction = point2 - point1;
|
|||
|
|
float length = direction.magnitude;
|
|||
|
|
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
|
|||
|
|
|
|||
|
|
// 设置线段位置(中心点)
|
|||
|
|
segmentRect.anchoredPosition = (point1 + point2) / 2;
|
|||
|
|
|
|||
|
|
// 设置线段大小(宽度为lineWidth,高度为长度)
|
|||
|
|
segmentRect.sizeDelta = new Vector2(length, lineWidth);
|
|||
|
|
|
|||
|
|
// 设置线段旋转
|
|||
|
|
segmentRect.rotation = Quaternion.Euler(0, 0, angle);
|
|||
|
|
|
|||
|
|
// 设置颜色
|
|||
|
|
if (segmentImage != null)
|
|||
|
|
{
|
|||
|
|
segmentImage.color = lineColor;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 清除所有线段
|
|||
|
|
/// </summary>
|
|||
|
|
private void ClearLineSegments()
|
|||
|
|
{
|
|||
|
|
foreach (var segment in lineSegments)
|
|||
|
|
{
|
|||
|
|
if (segment != null)
|
|||
|
|
{
|
|||
|
|
Destroy(segment);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
lineSegments.Clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 更新数值标签
|
|||
|
|
/// </summary>
|
|||
|
|
private void UpdateValueLabel(float value)
|
|||
|
|
{
|
|||
|
|
if (valueLabel != null)
|
|||
|
|
{
|
|||
|
|
valueLabel.text = value.ToString("F1") + unit;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置图表标题
|
|||
|
|
/// </summary>
|
|||
|
|
public void SetTitle(string title)
|
|||
|
|
{
|
|||
|
|
if (titleLabel != null)
|
|||
|
|
{
|
|||
|
|
titleLabel.text = title;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置线条颜色
|
|||
|
|
/// </summary>
|
|||
|
|
public void SetLineColor(Color color)
|
|||
|
|
{
|
|||
|
|
lineColor = color;
|
|||
|
|
|
|||
|
|
// 更新现有线段的颜色
|
|||
|
|
foreach (var segment in lineSegments)
|
|||
|
|
{
|
|||
|
|
if (segment != null)
|
|||
|
|
{
|
|||
|
|
var image = segment.GetComponent<Image>();
|
|||
|
|
if (image != null)
|
|||
|
|
{
|
|||
|
|
image.color = lineColor;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置值范围
|
|||
|
|
/// </summary>
|
|||
|
|
public void SetValueRange(float min, float max)
|
|||
|
|
{
|
|||
|
|
minValue = min;
|
|||
|
|
maxValue = max;
|
|||
|
|
UpdateChart(); // 重新绘制图表以应用新范围
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 清空数据
|
|||
|
|
/// </summary>
|
|||
|
|
public void ClearData()
|
|||
|
|
{
|
|||
|
|
dataPoints.Clear();
|
|||
|
|
ClearLineSegments();
|
|||
|
|
|
|||
|
|
if (valueLabel != null)
|
|||
|
|
{
|
|||
|
|
valueLabel.text = "0.0" + unit;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取当前数据点数量
|
|||
|
|
/// </summary>
|
|||
|
|
public int GetDataPointCount()
|
|||
|
|
{
|
|||
|
|
return dataPoints.Count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取最新的数据值
|
|||
|
|
/// </summary>
|
|||
|
|
public float GetLatestValue()
|
|||
|
|
{
|
|||
|
|
return dataPoints.Count > 0 ? dataPoints[dataPoints.Count - 1] : 0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnDestroy()
|
|||
|
|
{
|
|||
|
|
ClearLineSegments();
|
|||
|
|
}
|
|||
|
|
}
|