DCS/ruiyiweiUX/Assets/Scripts/UI/UIChartComponent.cs

297 lines
7.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
}
}