using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SkiaSharp; using UnityEngine; using UnityEngine.UIElements; namespace BITKit.UX { public class SkiaChart : VisualElement { public new class UxmlTraits : VisualElement.UxmlTraits { private readonly UxmlStringAttributeDescription m_JsonAttribute = new() { name = "Json" }; private readonly UxmlBoolAttributeDescription m_allowWarningsAttribute = new() { name = "allowWarnings", defaultValue = false }; public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) { base.Init(ve, bag, cc); var x = (SkiaChart)ve; x.Json = m_JsonAttribute.GetValueFromBag(bag, cc); x.AllowWarning = m_allowWarningsAttribute.GetValueFromBag(bag, cc); } } public new class UxmlFactory : UxmlFactory { } public SkiaChart() { RegisterCallback(x => { if (visible) { Rebuild(); } }); RegisterCallback(OnCustomStyleResolved); style.flexDirection = FlexDirection.Row; _dataContainer = this.Create(); _chartContainer = this.Create(); _chartContainer.style.flexGrow = 1; _dataContainer.style.justifyContent = Justify.SpaceBetween; _dataContainer.name = "Data"; _chartContainer.name = "Chart"; } private void OnCustomStyleResolved(CustomStyleResolvedEvent evt) { if (evt.customStyle.TryGetValue(new CustomStyleProperty("--chart-secondary-color"), out var helpLineColor)) { _secondaryColor = helpLineColor; } Rebuild(); } public string Json { get => _json; set { _json = value; Rebuild(); } } private string _json; public bool AllowWarning { get; set; } public Color SecondaryColor { get => _secondaryColor; set { _secondaryColor = value; Rebuild(); } } private Color _secondaryColor; private readonly VisualElement _dataContainer; private readonly VisualElement _chartContainer; private void Rebuild() { if (float.IsNaN(layout.width) || float.IsNaN(layout.height)) { if (AllowWarning) BIT4Log.Log("Width or height is NaN"); return; } JArray[] array; float[] data; try { array = JsonConvert.DeserializeObject(Json); data = array.SelectMany(x => x.ToObject()).ToArray(); } catch (Exception e) { if (AllowWarning) Debug.LogException(e); return; } if (data is null or { Length: 0 }) { if (AllowWarning) BIT4Log.Log("Data is null or empty"); return; } _dataContainer.Clear(); _chartContainer.Clear(); // _chartContainer.style.marginBottom = 8; // _chartContainer.style.marginLeft = 8; // _chartContainer.style.marginRight = 8; // _chartContainer.style.marginTop = 8; _dataContainer.style.flexDirection = FlexDirection.ColumnReverse; //假如min是x,max是y,将中间的差用data.Length划分 var max = data.Max(); var min = data.Min(); var difference = max - min; var maxLength = array.Select(x => x.Count).Max(); max = max + difference / maxLength; min = min - difference / maxLength; difference = max - min; //Debug.Log($"min:{min} max:{max} difference:{difference} max:{max}"); for (var i = 0; i <= maxLength; i++) { var label = _dataContainer.Create