UI update 02

This commit is contained in:
2026-06-30 21:21:30 +08:00
parent b2a1e307a4
commit f62f643cfc
1666 changed files with 211081 additions and 22799 deletions
@@ -0,0 +1,270 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using XUGL;
namespace XCharts.Runtime
{
/// <summary>
/// View control component in 3D coordinate system.
/// ||3D视角控制组件。
/// </summary>
[Since("v3.11.0")]
[Serializable]
public class ViewControl : ChildComponent
{
[SerializeField][Range(-90, 180)] private float m_Alpha = 90f;
[SerializeField][Range(-90, 90)] private float m_Beta = 55f;
/// <summary>
/// The angle of the view in the x-z plane.
/// ||视角在x-z平面的角度。
/// </summary>
public float alpha
{
get { return m_Alpha; }
set { if (PropertyUtil.SetStruct(ref m_Alpha, value)) SetVerticesDirty(); }
}
/// <summary>
/// The angle of the view in the y-z plane.
/// ||视角在y-z平面的角度。
/// </summary>
public float beta
{
get { return m_Beta; }
set { if (PropertyUtil.SetStruct(ref m_Beta, value)) SetVerticesDirty(); }
}
}
/// <summary>
/// Grid component.
/// ||Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart can be drawn in grid.
/// ||3D网格组件。
/// 3D直角坐标系内绘图网格。可以在网格上绘制3D折线图,3D柱状图,3D散点图。
/// </summary>
[Serializable]
[ComponentHandler(typeof(GridCoord3DHandler), true)]
public class GridCoord3D : CoordSystem, IUpdateRuntimeData, ISerieContainer
{
[SerializeField] private bool m_Show = true;
[SerializeField] private float m_Left = 0.15f;
[SerializeField] private float m_Right = 0.2f;
[SerializeField] private float m_Top = 0.3f;
[SerializeField] private float m_Bottom = 0.15f;
[SerializeField] private bool m_ShowBorder = false;
[SerializeField] private float m_BoxWidth = 0.55f;
[SerializeField] private float m_BoxHeight = 0.4f;
[SerializeField] private float m_BoxDepth = 0.2f;
[SerializeField] private bool m_XYExchanged = false;
[SerializeField] private ViewControl m_ViewControl = new ViewControl();
public GridCoord3DContext context = new GridCoord3DContext();
/// <summary>
/// Whether to show the grid in rectangular coordinate.
/// ||是否显示直角坐标系网格。
/// </summary>
public bool show
{
get { return m_Show; }
set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); }
}
/// <summary>
/// Distance between grid component and the left side of the container.
/// ||grid 组件离容器左侧的距离。
/// </summary>
public float left
{
get { return m_Left; }
set { if (PropertyUtil.SetStruct(ref m_Left, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between grid component and the right side of the container.
/// ||grid 组件离容器右侧的距离。
/// </summary>
public float right
{
get { return m_Right; }
set { if (PropertyUtil.SetStruct(ref m_Right, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between grid component and the top side of the container.
/// ||grid 组件离容器上侧的距离。
/// </summary>
public float top
{
get { return m_Top; }
set { if (PropertyUtil.SetStruct(ref m_Top, value)) SetAllDirty(); }
}
/// <summary>
/// Distance between grid component and the bottom side of the container.
/// ||grid 组件离容器下侧的距离。
/// </summary>
public float bottom
{
get { return m_Bottom; }
set { if (PropertyUtil.SetStruct(ref m_Bottom, value)) SetAllDirty(); }
}
/// <summary>
/// Whether to show the grid border.
/// ||是否显示网格边框。
/// </summary>
public bool showBorder
{
get { return m_ShowBorder; }
set { if (PropertyUtil.SetStruct(ref m_ShowBorder, value)) SetVerticesDirty(); }
}
/// <summary>
/// The width of the box in the coordinate system.
/// ||坐标系的宽度。
/// </summary>
public float boxWidth
{
get { return m_BoxWidth; }
set { if (PropertyUtil.SetStruct(ref m_BoxWidth, value)) SetVerticesDirty(); }
}
/// <summary>
/// The height of the box in the coordinate system.
/// ||坐标系的高度。
/// </summary>
public float boxHeight
{
get { return m_BoxHeight; }
set { if (PropertyUtil.SetStruct(ref m_BoxHeight, value)) SetVerticesDirty(); }
}
/// <summary>
/// The depth of the box in the coordinate system.
/// ||坐标系的深度。
/// </summary>
public float boxDepth
{
get { return m_BoxDepth; }
set { if (PropertyUtil.SetStruct(ref m_BoxDepth, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to exchange the x and y axes.
/// ||是否交换x和y轴。
/// </summary>
public bool xyExchanged
{
get { return m_XYExchanged; }
set { if (PropertyUtil.SetStruct(ref m_XYExchanged, value)) SetVerticesDirty(); }
}
/// <summary>
/// View control component in 3D coordinate system.
/// ||3D视角控制组件。
/// </summary>
public ViewControl viewControl
{
get { return m_ViewControl; }
//set { if (PropertyUtil.SetClass(ref m_ViewControl, value)) SetVerticesDirty(); }
}
public void UpdateRuntimeData(BaseChart chart)
{
var chartX = chart.chartX;
var chartY = chart.chartY;
var chartWidth = chart.chartWidth;
var chartHeight = chart.chartHeight;
var actualLeft = left <= 1 ? left * chartWidth : left;
var actualBottom = bottom <= 1 ? bottom * chartHeight : bottom;
var actualBoxWidth = m_BoxWidth <= 1 ? m_BoxWidth * chartWidth : m_BoxWidth;
var actualBoxHeight = m_BoxHeight <= 1 ? m_BoxHeight * chartHeight : m_BoxHeight;
var actualBoxDepth = m_BoxDepth <= 1 ? m_BoxDepth * chartWidth : m_BoxDepth;
context.x = chartX + actualLeft;
context.y = chartY + actualBottom;
context.pointA.x = context.x;
context.pointA.y = context.y;
var angle = m_ViewControl.alpha * Mathf.Deg2Rad;
context.pointD.x = context.x + actualBoxWidth * Mathf.Sin(angle);
context.pointD.y = context.y - actualBoxWidth * Mathf.Cos(angle);
angle = (90 - m_ViewControl.beta) * Mathf.Deg2Rad;
context.pointB.x = context.x + actualBoxDepth * Mathf.Cos(angle);
context.pointB.y = context.y + actualBoxDepth * Mathf.Sin(angle);
context.pointC = context.pointB + (context.pointD - context.pointA);
context.pointE.x = context.pointA.x;
context.pointE.y = context.pointA.y + actualBoxHeight;
var diff = context.pointE - context.pointA;
context.pointF = context.pointB + diff;
context.pointG = context.pointC + diff;
context.pointH = context.pointD + diff;
var minX = Mathf.Min(context.pointA.x, context.pointB.x, context.pointC.x, context.pointD.x, context.pointE.x, context.pointF.x, context.pointG.x, context.pointH.x);
var minY = Mathf.Min(context.pointA.y, context.pointB.y, context.pointC.y, context.pointD.y, context.pointE.y, context.pointF.y, context.pointG.y, context.pointH.y);
var maxX = Mathf.Max(context.pointA.x, context.pointB.x, context.pointC.x, context.pointD.x, context.pointE.x, context.pointF.x, context.pointG.x, context.pointH.x);
var maxY = Mathf.Max(context.pointA.y, context.pointB.y, context.pointC.y, context.pointD.y, context.pointE.y, context.pointF.y, context.pointG.y, context.pointH.y);
context.maxRect.x = minX;
context.maxRect.y = minY;
context.maxRect.width = maxX - minX;
context.maxRect.height = maxY - minY;
}
/// <summary>
/// The opening of the coordinate system faces to the left.
/// 坐标系开口朝向左边。
/// </summary>
/// <returns></returns>
public bool IsLeft()
{
return context.pointB.x < context.pointA.x;
}
/// <summary>
/// Whether the pointer is in the grid.
/// ||指针是否在网格内。
/// </summary>
/// <returns></returns>
public bool IsPointerEnter()
{
return context.isPointerEnter;
}
/// <summary>
/// Whether the given position is in the grid.
/// ||给定的位置是否在网格内。
/// </summary>
/// <param name="pos"></param>
/// <returns></returns>
public bool Contains(Vector3 pos)
{
if (!context.maxRect.Contains(pos)) return false;
if (UGLHelper.IsPointInPolygon(pos, context.pointA, context.pointB, context.pointC, context.pointD)) return true;
if (UGLHelper.IsPointInPolygon(pos, context.pointB, context.pointF, context.pointG, context.pointC)) return true;
if (IsLeft())
if (UGLHelper.IsPointInPolygon(pos, context.pointC, context.pointG, context.pointH, context.pointD)) return true;
else
if (UGLHelper.IsPointInPolygon(pos, context.pointA, context.pointE, context.pointF, context.pointB)) return true;
return false;
}
/// <summary>
/// Clamp the position of pos to the grid.
/// ||将位置限制在网格内。
/// </summary>
/// <param name="pos"></param>
public void Clamp(ref Vector3 pos)
{
//TODO:
}
/// <summary>
/// Determines whether a given line segment will not intersect the Grid boundary at all.
/// ||判断给定的线段是否与Grid边界是否完全不会相交。
/// </summary>
/// <param name="sp"></param>
/// <param name="ep"></param>
/// <returns></returns>
public bool NotAnyIntersect(Vector3 sp, Vector3 ep)
{
//TODO:
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 95f8c8c3492e54987af59175d94f8761
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts.Runtime
{
public class GridCoord3DContext : MainComponentContext
{
public float x;
public float y;
public Rect maxRect = new Rect(0, 0, 0, 0);
public bool isPointerEnter;
public List<ChartLabel> endLabelList = new List<ChartLabel>();
//public Vector3 position = Vector3.zero;
public Vector3 pointA = Vector3.zero;
public Vector3 pointB = Vector3.zero;
public Vector3 pointC = Vector3.zero;
public Vector3 pointD = Vector3.zero;
public Vector3 pointE = Vector3.zero;
public Vector3 pointF = Vector3.zero;
public Vector3 pointG = Vector3.zero;
public Vector3 pointH = Vector3.zero;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a4a0f1dda078b4877bfabe3c16815498
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,79 @@
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts.Runtime
{
[UnityEngine.Scripting.Preserve]
internal sealed class GridCoord3DHandler : MainComponentHandler<GridCoord3D>
{
public override void InitComponent()
{
var grid = component;
grid.painter = chart.painter;
grid.refreshComponent = delegate ()
{
grid.UpdateRuntimeData(chart);
chart.OnCoordinateChanged();
};
grid.refreshComponent();
}
public override void CheckComponent(StringBuilder sb)
{
var grid = component;
if (grid.left >= chart.chartWidth)
sb.Append("warning:grid->left > chartWidth\n");
if (grid.right >= chart.chartWidth)
sb.Append("warning:grid->right > chartWidth\n");
if (grid.top >= chart.chartHeight)
sb.Append("warning:grid->top > chartHeight\n");
if (grid.bottom >= chart.chartHeight)
sb.Append("warning:grid->bottom > chartHeight\n");
if (grid.left + grid.right >= chart.chartWidth)
sb.Append("warning:grid.left + grid.right > chartWidth\n");
if (grid.top + grid.bottom >= chart.chartHeight)
sb.Append("warning:grid.top + grid.bottom > chartHeight\n");
}
public override void Update()
{
if (chart.isPointerInChart)
{
component.context.isPointerEnter = component.Contains(chart.pointerPos);
}
else
{
component.context.isPointerEnter = false;
}
}
public override void DrawUpper(VertexHelper vh)
{
DrawCoord(vh, component);
}
private void DrawCoord(VertexHelper vh, GridCoord3D grid)
{
if (!grid.show) return;
if (grid.showBorder)
{
var borderWidth = chart.theme.axis.lineWidth;
var borderColor = chart.theme.axis.lineColor;
if (grid.IsLeft())
{
UGL.DrawLine(vh, grid.context.pointA, grid.context.pointE, borderWidth, borderColor);
UGL.DrawLine(vh, grid.context.pointE, grid.context.pointF, borderWidth, borderColor);
UGL.DrawLine(vh, grid.context.pointE, grid.context.pointH, borderWidth, borderColor);
}
else
{
UGL.DrawLine(vh, grid.context.pointD, grid.context.pointH, borderWidth, borderColor);
UGL.DrawLine(vh, grid.context.pointE, grid.context.pointH, borderWidth, borderColor);
UGL.DrawLine(vh, grid.context.pointG, grid.context.pointH, borderWidth, borderColor);
}
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 92481e92b90724f46b3a7e8c585e12e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: