612 lines
29 KiB
C#
612 lines
29 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace EasyChart
|
|
{
|
|
public class AxisLayer : VisualElement
|
|
{
|
|
private const float LabelClipMarginPx = 2000f;
|
|
private const float LabelEdgeClipMarginPx = 20f;
|
|
|
|
private VisualElement _xAxisViewport;
|
|
private VisualElement _yAxisViewport;
|
|
private VisualElement _xAxisContainer;
|
|
private VisualElement _yAxisContainer;
|
|
|
|
// These are now mostly redundant if Settings are used, but kept for fallback
|
|
public Color AxisColor { get; set; } = Color.white;
|
|
public float AxisLineWidth { get; set; } = 2.0f;
|
|
|
|
// Data for labels
|
|
public List<string> XLabels { get; set; } = new List<string>();
|
|
public List<string> YLabels { get; set; } = new List<string>();
|
|
|
|
public float XMin { get; set; } = 0;
|
|
public float XMax { get; set; } = 100;
|
|
public int XSplitCount { get; set; } = 6;
|
|
public float YMin { get; set; } = 0;
|
|
public float YMax { get; set; } = 100;
|
|
public int YSplitCount { get; set; } = 6;
|
|
|
|
public bool XIsCategory { get; set; } = true;
|
|
public bool YIsCategory { get; set; } = false;
|
|
|
|
public AxisId XAxisId { get; set; } = AxisId.XBottom;
|
|
public AxisId YAxisId { get; set; } = AxisId.YLeft;
|
|
|
|
public AxisConfig XAxisConfig { get; set; }
|
|
public AxisConfig YAxisConfig { get; set; }
|
|
|
|
public AxisLayer()
|
|
{
|
|
this.StretchToParentSize();
|
|
pickingMode = PickingMode.Ignore;
|
|
|
|
_xAxisViewport = new VisualElement { name = "xAxisViewport", pickingMode = PickingMode.Ignore };
|
|
_yAxisViewport = new VisualElement { name = "yAxisViewport", pickingMode = PickingMode.Ignore };
|
|
|
|
_xAxisContainer = new VisualElement { name = "xAxis", pickingMode = PickingMode.Ignore };
|
|
_yAxisContainer = new VisualElement { name = "yAxis", pickingMode = PickingMode.Ignore };
|
|
|
|
// X axis labels should be clipped horizontally to plot width, but may extend above/below.
|
|
// We achieve this with a tall viewport (extra margin on Y) and an inner container aligned to plot coords.
|
|
_xAxisViewport.style.position = Position.Absolute;
|
|
_xAxisViewport.style.left = -LabelEdgeClipMarginPx;
|
|
_xAxisViewport.style.right = -LabelEdgeClipMarginPx;
|
|
_xAxisViewport.style.top = -LabelClipMarginPx;
|
|
_xAxisViewport.style.bottom = -LabelClipMarginPx;
|
|
_xAxisViewport.style.overflow = Overflow.Hidden;
|
|
|
|
// Y axis labels should be clipped vertically to plot height, but may extend left/right.
|
|
// We achieve this with a wide viewport (extra margin on X) and an inner container aligned to plot coords.
|
|
_yAxisViewport.style.position = Position.Absolute;
|
|
_yAxisViewport.style.left = -LabelClipMarginPx;
|
|
_yAxisViewport.style.right = -LabelClipMarginPx;
|
|
_yAxisViewport.style.top = -LabelEdgeClipMarginPx;
|
|
_yAxisViewport.style.bottom = -LabelEdgeClipMarginPx;
|
|
_yAxisViewport.style.overflow = Overflow.Hidden;
|
|
|
|
// Containers stretch to parent, labels positioned with pixel values
|
|
_xAxisContainer.style.position = Position.Absolute;
|
|
_xAxisContainer.style.left = LabelEdgeClipMarginPx;
|
|
_xAxisContainer.style.right = LabelEdgeClipMarginPx;
|
|
_xAxisContainer.style.top = LabelClipMarginPx;
|
|
_xAxisContainer.style.bottom = LabelClipMarginPx;
|
|
_xAxisContainer.style.overflow = Overflow.Visible;
|
|
|
|
_yAxisContainer.style.position = Position.Absolute;
|
|
_yAxisContainer.style.left = LabelClipMarginPx;
|
|
_yAxisContainer.style.right = LabelClipMarginPx;
|
|
_yAxisContainer.style.top = LabelEdgeClipMarginPx;
|
|
_yAxisContainer.style.bottom = LabelEdgeClipMarginPx;
|
|
_yAxisContainer.style.overflow = Overflow.Visible;
|
|
|
|
_xAxisViewport.Add(_xAxisContainer);
|
|
_yAxisViewport.Add(_yAxisContainer);
|
|
|
|
Add(_xAxisViewport);
|
|
Add(_yAxisViewport);
|
|
|
|
generateVisualContent += OnGenerateVisualContent;
|
|
}
|
|
|
|
public void SetCategoryScrollOffset(float xPx, float yPx)
|
|
{
|
|
if (_xAxisContainer != null)
|
|
{
|
|
_xAxisContainer.style.translate = new Translate(xPx, 0, 0);
|
|
}
|
|
if (_yAxisContainer != null)
|
|
{
|
|
_yAxisContainer.style.translate = new Translate(0, yPx, 0);
|
|
}
|
|
}
|
|
|
|
private static int ClampCategoryVisibleCount(AxisConfig axis, int labelsCount)
|
|
{
|
|
if (labelsCount <= 0) return 0;
|
|
// When autoTicks is true, use all labels
|
|
if (axis != null && axis.autoTicks) return labelsCount;
|
|
int v = axis != null ? axis.splitCount : 0;
|
|
if (v < 2) v = 2;
|
|
if (v > labelsCount) v = labelsCount;
|
|
return v;
|
|
}
|
|
|
|
private void OnGenerateVisualContent(MeshGenerationContext context)
|
|
{
|
|
var w = contentRect.width;
|
|
var h = contentRect.height;
|
|
|
|
if (w <= 0 || h <= 0) return;
|
|
|
|
var painter = context.painter2D;
|
|
|
|
// Use config if available, else fallback
|
|
var xColor = XAxisConfig != null ? XAxisConfig.color : AxisColor;
|
|
var xWidth = XAxisConfig != null ? XAxisConfig.width : AxisLineWidth;
|
|
var yColor = YAxisConfig != null ? YAxisConfig.color : AxisColor;
|
|
var yWidth = YAxisConfig != null ? YAxisConfig.width : AxisLineWidth;
|
|
|
|
bool showX = XAxisConfig != null ? XAxisConfig.visible : true;
|
|
bool showY = YAxisConfig != null ? YAxisConfig.visible : true;
|
|
|
|
painter.BeginPath();
|
|
|
|
float xAxisY = XAxisId == AxisId.XTop ? 0 : h;
|
|
float yAxisX = YAxisId == AxisId.YRight ? w : 0;
|
|
|
|
// X Axis Line
|
|
if (showX)
|
|
{
|
|
painter.strokeColor = xColor;
|
|
painter.lineWidth = xWidth;
|
|
painter.MoveTo(new Vector2(0, xAxisY));
|
|
painter.LineTo(new Vector2(w, xAxisY));
|
|
painter.Stroke(); // Stroke separately to support different colors
|
|
painter.BeginPath();
|
|
}
|
|
|
|
// Y Axis Line
|
|
if (showY)
|
|
{
|
|
painter.strokeColor = yColor;
|
|
painter.lineWidth = yWidth;
|
|
painter.MoveTo(new Vector2(yAxisX, 0));
|
|
painter.LineTo(new Vector2(yAxisX, h));
|
|
painter.Stroke();
|
|
}
|
|
}
|
|
|
|
private static void ApplyAxisLabelBaseStyle(Label label)
|
|
{
|
|
label.style.marginLeft = 0;
|
|
label.style.marginRight = 0;
|
|
label.style.marginTop = 0;
|
|
label.style.marginBottom = 0;
|
|
|
|
label.style.paddingLeft = 0;
|
|
label.style.paddingRight = 0;
|
|
label.style.paddingTop = 0;
|
|
label.style.paddingBottom = 0;
|
|
|
|
label.style.borderLeftWidth = 0;
|
|
label.style.borderRightWidth = 0;
|
|
label.style.borderTopWidth = 0;
|
|
label.style.borderBottomWidth = 0;
|
|
|
|
label.style.flexGrow = 0;
|
|
label.style.flexShrink = 0;
|
|
label.style.whiteSpace = WhiteSpace.NoWrap;
|
|
}
|
|
|
|
private static string FormatNumericTick(float val, string labelFormat)
|
|
{
|
|
if (!string.IsNullOrEmpty(labelFormat)) return val.ToString(labelFormat);
|
|
|
|
float v = Mathf.Round(val * 1000f) / 1000f;
|
|
float r = Mathf.Round(v);
|
|
if (Mathf.Abs(v - r) < 0.0001f)
|
|
{
|
|
return ((int)r).ToString();
|
|
}
|
|
|
|
return v.ToString("0.###");
|
|
}
|
|
|
|
public void RefreshLabels()
|
|
{
|
|
_xAxisContainer.Clear();
|
|
_yAxisContainer.Clear();
|
|
|
|
float w = contentRect.width;
|
|
float h = contentRect.height;
|
|
|
|
var plotViewport = parent != null ? parent.Q<VisualElement>("plot-viewport") : null;
|
|
float plotX0 = 0f;
|
|
float plotW = w;
|
|
if (plotViewport != null)
|
|
{
|
|
var rs = plotViewport.resolvedStyle;
|
|
plotX0 = plotViewport.layout.x + rs.borderLeftWidth + rs.paddingLeft;
|
|
plotW = plotViewport.contentRect.width;
|
|
}
|
|
|
|
bool xOnTop = XAxisId == AxisId.XTop;
|
|
bool yOnRight = YAxisId == AxisId.YRight;
|
|
float xAxisY = xOnTop ? 0 : h;
|
|
float yAxisX = yOnRight ? w : 0;
|
|
|
|
// --- X Axis Labels ---
|
|
if (XAxisConfig != null && (XAxisConfig.labelStyle != null ? XAxisConfig.labelStyle.enabled : XAxisConfig.showLabels))
|
|
{
|
|
var xLabelStyle = XAxisConfig.labelStyle;
|
|
var xLabels = XLabels;
|
|
if ((xLabels == null || xLabels.Count == 0) && XAxisConfig != null && XAxisConfig.labels != null && XAxisConfig.labels.Count > 0)
|
|
{
|
|
xLabels = XAxisConfig.labels;
|
|
}
|
|
|
|
if (xLabels != null && xLabels.Count > 0)
|
|
{
|
|
var sourceLabels = xLabels;
|
|
if (XAxisConfig != null && XAxisConfig.axisType == AxisType.Category && XAxisConfig.labels != null && XAxisConfig.labels.Count > 0)
|
|
{
|
|
sourceLabels = XAxisConfig.labels;
|
|
}
|
|
|
|
int totalCount = sourceLabels != null ? sourceLabels.Count : 0;
|
|
if (totalCount <= 0) return;
|
|
|
|
int visibleCount = ClampCategoryVisibleCount(XAxisConfig, totalCount);
|
|
int startIndex = 0;
|
|
if (totalCount > visibleCount)
|
|
{
|
|
startIndex = Mathf.RoundToInt(XMin);
|
|
startIndex = Mathf.Clamp(startIndex, 0, totalCount - 1);
|
|
}
|
|
|
|
for (int i = 0; i < visibleCount; i++)
|
|
{
|
|
int labelIndex = (totalCount > visibleCount) ? ((startIndex + i) % totalCount) : i;
|
|
var label = new Label(sourceLabels[labelIndex]);
|
|
ApplyAxisLabelBaseStyle(label);
|
|
int fs = xLabelStyle != null ? xLabelStyle.fontSize : XAxisConfig.fontSize;
|
|
if (fs > 0) label.style.fontSize = fs;
|
|
else label.style.fontSize = StyleKeyword.Null;
|
|
label.style.color = xLabelStyle != null ? xLabelStyle.color : XAxisConfig.labelColor;
|
|
label.style.position = Position.Absolute;
|
|
label.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
|
|
ChartTextStyleApplier.ApplyLabel(label, this, ChartTextRole.AxisLabel);
|
|
|
|
float xPos;
|
|
if (XAxisConfig != null && XAxisConfig.labelPlacement == CategoryLabelPlacement.CellCenter)
|
|
{
|
|
float step = visibleCount > 0 ? (plotW / visibleCount) : 0f;
|
|
xPos = plotX0 + (i + 0.5f) * step;
|
|
}
|
|
else
|
|
{
|
|
float denom = Mathf.Max(1, visibleCount - 1);
|
|
float step = denom > 0 ? (plotW / denom) : 0f;
|
|
xPos = plotX0 + i * step;
|
|
}
|
|
label.style.left = xPos;
|
|
|
|
// Position Vertical (relative to X axis line)
|
|
var xPosMode = xLabelStyle != null ? xLabelStyle.position : XAxisConfig.labelPosition;
|
|
if (xPosMode == LabelPosition.Inside)
|
|
{
|
|
label.style.top = xOnTop ? xAxisY + 5 : xAxisY - 5;
|
|
label.style.translate = xOnTop
|
|
? new Translate(new Length(-50, LengthUnit.Percent), 0, 0)
|
|
: new Translate(new Length(-50, LengthUnit.Percent), new Length(-100, LengthUnit.Percent), 0);
|
|
}
|
|
else if (xPosMode == LabelPosition.Center)
|
|
{
|
|
label.style.top = xAxisY;
|
|
label.style.translate = new Translate(new Length(-50, LengthUnit.Percent), new Length(-50, LengthUnit.Percent), 0);
|
|
}
|
|
else // Outside
|
|
{
|
|
label.style.top = xOnTop ? xAxisY - 5 : xAxisY + 5;
|
|
label.style.translate = xOnTop
|
|
? new Translate(new Length(-50, LengthUnit.Percent), new Length(-100, LengthUnit.Percent), 0)
|
|
: new Translate(new Length(-50, LengthUnit.Percent), 0, 0);
|
|
}
|
|
|
|
// Apply Offset
|
|
var xOffset = xLabelStyle != null ? xLabelStyle.offset : XAxisConfig.labelOffset;
|
|
if (xOffset != Vector2.zero)
|
|
{
|
|
label.style.marginLeft = xOffset.x;
|
|
label.style.marginTop = xOffset.y;
|
|
}
|
|
|
|
_xAxisContainer.Add(label);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Numeric X axis labels (used by HorizontalBar)
|
|
int split = Mathf.Max(1, XSplitCount);
|
|
|
|
bool cellCenter = XAxisConfig != null && XAxisConfig.labelPlacement == CategoryLabelPlacement.CellCenter;
|
|
int labelCount = cellCenter ? split : (split + 1);
|
|
for (int i = 0; i < labelCount; i++)
|
|
{
|
|
float t = cellCenter ? ((i + 0.5f) / split) : ((float)i / split);
|
|
float val = Mathf.Lerp(XMin, XMax, t);
|
|
string text = FormatNumericTick(val, XAxisConfig.labelFormat);
|
|
|
|
var label = new Label(text);
|
|
ApplyAxisLabelBaseStyle(label);
|
|
int fs = xLabelStyle != null ? xLabelStyle.fontSize : XAxisConfig.fontSize;
|
|
if (fs > 0) label.style.fontSize = fs;
|
|
else label.style.fontSize = StyleKeyword.Null;
|
|
label.style.color = xLabelStyle != null ? xLabelStyle.color : XAxisConfig.labelColor;
|
|
label.style.position = Position.Absolute;
|
|
label.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
|
|
ChartTextStyleApplier.ApplyLabel(label, this, ChartTextRole.AxisLabel);
|
|
|
|
float xPos = plotX0 + t * plotW;
|
|
label.style.left = xPos;
|
|
|
|
var xPosMode = xLabelStyle != null ? xLabelStyle.position : XAxisConfig.labelPosition;
|
|
if (xPosMode == LabelPosition.Inside)
|
|
{
|
|
label.style.top = xOnTop ? xAxisY + 5 : xAxisY - 5;
|
|
label.style.translate = xOnTop
|
|
? new Translate(new Length(-50, LengthUnit.Percent), 0, 0)
|
|
: new Translate(new Length(-50, LengthUnit.Percent), new Length(-100, LengthUnit.Percent), 0);
|
|
}
|
|
else if (xPosMode == LabelPosition.Center)
|
|
{
|
|
label.style.top = xAxisY;
|
|
label.style.translate = new Translate(new Length(-50, LengthUnit.Percent), new Length(-50, LengthUnit.Percent), 0);
|
|
}
|
|
else
|
|
{
|
|
label.style.top = xOnTop ? xAxisY - 5 : xAxisY + 5;
|
|
label.style.translate = xOnTop
|
|
? new Translate(new Length(-50, LengthUnit.Percent), new Length(-100, LengthUnit.Percent), 0)
|
|
: new Translate(new Length(-50, LengthUnit.Percent), 0, 0);
|
|
}
|
|
|
|
var xOffset = xLabelStyle != null ? xLabelStyle.offset : XAxisConfig.labelOffset;
|
|
if (xOffset != Vector2.zero)
|
|
{
|
|
label.style.marginLeft = xOffset.x;
|
|
label.style.marginTop = xOffset.y;
|
|
}
|
|
|
|
_xAxisContainer.Add(label);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (XAxisConfig != null && XAxisConfig.axisType == AxisType.Value && XAxisConfig.showUnit && !string.IsNullOrEmpty(XAxisConfig.unitText))
|
|
{
|
|
var unitStyle = XAxisConfig.unitLabelStyle;
|
|
var unitLabel = new Label(XAxisConfig.unitText);
|
|
ApplyAxisLabelBaseStyle(unitLabel);
|
|
int fs = unitStyle != null ? unitStyle.fontSize : XAxisConfig.fontSize;
|
|
if (fs > 0) unitLabel.style.fontSize = fs;
|
|
else unitLabel.style.fontSize = StyleKeyword.Null;
|
|
unitLabel.style.color = unitStyle != null ? unitStyle.color : XAxisConfig.labelColor;
|
|
unitLabel.style.position = Position.Absolute;
|
|
unitLabel.style.left = w;
|
|
unitLabel.style.unityTextAlign = TextAnchor.MiddleLeft;
|
|
|
|
ChartTextStyleApplier.ApplyLabel(unitLabel, this, ChartTextRole.AxisLabel);
|
|
|
|
var xPosMode = unitStyle != null ? unitStyle.position : LabelPosition.Outside;
|
|
if (xPosMode == LabelPosition.Inside)
|
|
{
|
|
unitLabel.style.top = xOnTop ? xAxisY + 5 : xAxisY - 5;
|
|
unitLabel.style.translate = xOnTop
|
|
? new Translate(0, 0, 0)
|
|
: new Translate(0, new Length(-100, LengthUnit.Percent), 0);
|
|
}
|
|
else if (xPosMode == LabelPosition.Center)
|
|
{
|
|
unitLabel.style.top = xAxisY;
|
|
unitLabel.style.translate = new Translate(0, new Length(-50, LengthUnit.Percent), 0);
|
|
}
|
|
else
|
|
{
|
|
unitLabel.style.top = xOnTop ? xAxisY - 5 : xAxisY + 5;
|
|
unitLabel.style.translate = xOnTop
|
|
? new Translate(0, new Length(-100, LengthUnit.Percent), 0)
|
|
: new Translate(0, 0, 0);
|
|
}
|
|
|
|
var offset = unitStyle != null ? unitStyle.offset : Vector2.zero;
|
|
if (offset != Vector2.zero)
|
|
{
|
|
unitLabel.style.marginLeft = offset.x;
|
|
unitLabel.style.marginTop = offset.y;
|
|
}
|
|
|
|
_xAxisContainer.Add(unitLabel);
|
|
}
|
|
|
|
// --- Y Axis Labels ---
|
|
if (YAxisConfig != null && (YAxisConfig.labelStyle != null ? YAxisConfig.labelStyle.enabled : YAxisConfig.showLabels))
|
|
{
|
|
var yLabelStyle = YAxisConfig.labelStyle;
|
|
var yLabels = YLabels;
|
|
if ((yLabels == null || yLabels.Count == 0) && YAxisConfig != null && YAxisConfig.labels != null && YAxisConfig.labels.Count > 0)
|
|
{
|
|
yLabels = YAxisConfig.labels;
|
|
}
|
|
|
|
if (yLabels != null && yLabels.Count > 0)
|
|
{
|
|
var sourceLabels = yLabels;
|
|
if (YAxisConfig != null && YAxisConfig.axisType == AxisType.Category && YAxisConfig.labels != null && YAxisConfig.labels.Count > 0)
|
|
{
|
|
sourceLabels = YAxisConfig.labels;
|
|
}
|
|
|
|
int totalCount = sourceLabels != null ? sourceLabels.Count : 0;
|
|
if (totalCount <= 0) return;
|
|
|
|
int visibleCount = ClampCategoryVisibleCount(YAxisConfig, totalCount);
|
|
int startIndex = 0;
|
|
if (totalCount > visibleCount)
|
|
{
|
|
startIndex = Mathf.RoundToInt(YMin);
|
|
startIndex = Mathf.Clamp(startIndex, 0, totalCount - 1);
|
|
}
|
|
|
|
for (int i = 0; i < visibleCount; i++)
|
|
{
|
|
int labelIndex = (totalCount > visibleCount) ? ((startIndex + i) % totalCount) : i;
|
|
var label = new Label(sourceLabels[labelIndex]);
|
|
ApplyAxisLabelBaseStyle(label);
|
|
int fs = yLabelStyle != null ? yLabelStyle.fontSize : YAxisConfig.fontSize;
|
|
if (fs > 0) label.style.fontSize = fs;
|
|
else label.style.fontSize = StyleKeyword.Null;
|
|
label.style.color = yLabelStyle != null ? yLabelStyle.color : YAxisConfig.labelColor;
|
|
label.style.position = Position.Absolute;
|
|
|
|
ChartTextStyleApplier.ApplyLabel(label, this, ChartTextRole.AxisLabel);
|
|
|
|
float t;
|
|
if (YAxisConfig != null && YAxisConfig.labelPlacement == CategoryLabelPlacement.CellCenter)
|
|
{
|
|
t = (i + 0.5f) / Mathf.Max(1, visibleCount);
|
|
}
|
|
else
|
|
{
|
|
t = visibleCount > 1 ? (float)i / (visibleCount - 1) : 0;
|
|
}
|
|
|
|
float yPos;
|
|
if (YIsCategory)
|
|
{
|
|
yPos = h > 0 ? (xOnTop ? (t * h) : ((1.0f - t) * h)) : 0;
|
|
}
|
|
else
|
|
{
|
|
yPos = h > 0 ? (1.0f - t) * h : 0;
|
|
}
|
|
label.style.top = yPos;
|
|
|
|
label.style.left = yOnRight ? yAxisX + 5 : yAxisX - 5;
|
|
label.style.unityTextAlign = yOnRight ? TextAnchor.MiddleLeft : TextAnchor.MiddleRight;
|
|
label.style.translate = yOnRight
|
|
? new Translate(0, new Length(-50, LengthUnit.Percent), 0)
|
|
: new Translate(new Length(-100, LengthUnit.Percent), new Length(-50, LengthUnit.Percent), 0);
|
|
|
|
var yOffset = yLabelStyle != null ? yLabelStyle.offset : YAxisConfig.labelOffset;
|
|
if (yOffset != Vector2.zero)
|
|
{
|
|
label.style.marginLeft = yOffset.x;
|
|
label.style.marginTop = yOffset.y;
|
|
}
|
|
|
|
_yAxisContainer.Add(label);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
bool cellCenter = YAxisConfig != null && YAxisConfig.labelPlacement == CategoryLabelPlacement.CellCenter;
|
|
int labelCount = cellCenter ? Mathf.Max(1, YSplitCount) : (Mathf.Max(1, YSplitCount) + 1);
|
|
for (int i = 0; i < labelCount; i++)
|
|
{
|
|
float split = Mathf.Max(1, YSplitCount);
|
|
float t = cellCenter ? ((i + 0.5f) / split) : ((float)i / split);
|
|
float val = Mathf.Lerp(YMin, YMax, t);
|
|
string text = FormatNumericTick(val, YAxisConfig.labelFormat);
|
|
|
|
var label = new Label(text);
|
|
ApplyAxisLabelBaseStyle(label);
|
|
int fs = yLabelStyle != null ? yLabelStyle.fontSize : YAxisConfig.fontSize;
|
|
if (fs > 0) label.style.fontSize = fs;
|
|
else label.style.fontSize = StyleKeyword.Null;
|
|
label.style.color = yLabelStyle != null ? yLabelStyle.color : YAxisConfig.labelColor;
|
|
label.style.position = Position.Absolute;
|
|
|
|
ChartTextStyleApplier.ApplyLabel(label, this, ChartTextRole.AxisLabel);
|
|
|
|
// Use pixel position based on actual height
|
|
float yPos = h > 0 ? (1.0f - t) * h : 0;
|
|
label.style.top = yPos;
|
|
|
|
// Position Horizontal (relative to Y axis line)
|
|
var yPosMode = yLabelStyle != null ? yLabelStyle.position : YAxisConfig.labelPosition;
|
|
if (yPosMode == LabelPosition.Inside)
|
|
{
|
|
label.style.left = yOnRight ? yAxisX - 5 : yAxisX + 5;
|
|
label.style.unityTextAlign = yOnRight ? TextAnchor.MiddleRight : TextAnchor.MiddleLeft;
|
|
label.style.translate = yOnRight
|
|
? new Translate(new Length(-100, LengthUnit.Percent), new Length(-50, LengthUnit.Percent), 0)
|
|
: new Translate(0, new Length(-50, LengthUnit.Percent), 0);
|
|
}
|
|
else if (yPosMode == LabelPosition.Center)
|
|
{
|
|
label.style.left = yAxisX;
|
|
label.style.translate = new Translate(new Length(-50, LengthUnit.Percent), new Length(-50, LengthUnit.Percent), 0);
|
|
}
|
|
else // Outside (Default) - left of axis
|
|
{
|
|
label.style.left = yOnRight ? yAxisX + 5 : yAxisX - 5;
|
|
label.style.unityTextAlign = yOnRight ? TextAnchor.MiddleLeft : TextAnchor.MiddleRight;
|
|
label.style.translate = yOnRight
|
|
? new Translate(0, new Length(-50, LengthUnit.Percent), 0)
|
|
: new Translate(new Length(-100, LengthUnit.Percent), new Length(-50, LengthUnit.Percent), 0);
|
|
}
|
|
|
|
// Apply Offset
|
|
var yOffset = yLabelStyle != null ? yLabelStyle.offset : YAxisConfig.labelOffset;
|
|
if (yOffset != Vector2.zero)
|
|
{
|
|
label.style.marginLeft = yOffset.x;
|
|
label.style.marginTop = yOffset.y;
|
|
}
|
|
|
|
_yAxisContainer.Add(label);
|
|
}
|
|
}
|
|
|
|
if (YAxisConfig != null && YAxisConfig.axisType == AxisType.Value && YAxisConfig.showUnit && !string.IsNullOrEmpty(YAxisConfig.unitText))
|
|
{
|
|
var unitStyle = YAxisConfig.unitLabelStyle;
|
|
var unitLabel = new Label(YAxisConfig.unitText);
|
|
ApplyAxisLabelBaseStyle(unitLabel);
|
|
int fs = unitStyle != null ? unitStyle.fontSize : YAxisConfig.fontSize;
|
|
if (fs > 0) unitLabel.style.fontSize = fs;
|
|
else unitLabel.style.fontSize = StyleKeyword.Null;
|
|
unitLabel.style.color = unitStyle != null ? unitStyle.color : YAxisConfig.labelColor;
|
|
unitLabel.style.position = Position.Absolute;
|
|
|
|
ChartTextStyleApplier.ApplyLabel(unitLabel, this, ChartTextRole.AxisLabel);
|
|
|
|
unitLabel.style.top = 0;
|
|
|
|
var yPosMode = unitStyle != null ? unitStyle.position : LabelPosition.Outside;
|
|
if (yPosMode == LabelPosition.Inside)
|
|
{
|
|
unitLabel.style.left = yOnRight ? yAxisX - 5 : yAxisX + 5;
|
|
unitLabel.style.unityTextAlign = yOnRight ? TextAnchor.MiddleRight : TextAnchor.MiddleLeft;
|
|
unitLabel.style.translate = yOnRight
|
|
? new Translate(new Length(-100, LengthUnit.Percent), new Length(-100, LengthUnit.Percent), 0)
|
|
: new Translate(0, new Length(-100, LengthUnit.Percent), 0);
|
|
}
|
|
else if (yPosMode == LabelPosition.Center)
|
|
{
|
|
unitLabel.style.left = yAxisX;
|
|
unitLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
unitLabel.style.translate = new Translate(new Length(-50, LengthUnit.Percent), new Length(-100, LengthUnit.Percent), 0);
|
|
}
|
|
else
|
|
{
|
|
unitLabel.style.left = yOnRight ? yAxisX + 5 : yAxisX - 5;
|
|
unitLabel.style.unityTextAlign = yOnRight ? TextAnchor.MiddleLeft : TextAnchor.MiddleRight;
|
|
unitLabel.style.translate = yOnRight
|
|
? new Translate(0, new Length(-100, LengthUnit.Percent), 0)
|
|
: new Translate(new Length(-100, LengthUnit.Percent), new Length(-100, LengthUnit.Percent), 0);
|
|
}
|
|
|
|
var offset = unitStyle != null ? unitStyle.offset : Vector2.zero;
|
|
if (offset != Vector2.zero)
|
|
{
|
|
unitLabel.style.marginLeft = offset.x;
|
|
unitLabel.style.marginTop = offset.y;
|
|
}
|
|
|
|
_yAxisContainer.Add(unitLabel);
|
|
}
|
|
|
|
MarkDirtyRepaint();
|
|
}
|
|
}
|
|
}
|