Files

860 lines
37 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using EasyChart.Layers;
namespace EasyChart
{
internal sealed class ChartLegendController
{
private VisualElement _legendContainer;
private ChartInteractionState _state;
private int _legendHash;
public IChartLegendTogglePolicy LegendTogglePolicy { get; set; }
public ChartLegendController()
{
LegendTogglePolicy = DefaultChartLegendTogglePolicy.Instance;
}
public void SetInteractionState(ChartInteractionState state)
{
_state = state;
}
public void EnsureContainer(VisualElement host)
{
if (_legendContainer != null) return;
if (host == null) return;
_legendContainer = new VisualElement();
_legendContainer.name = "legend";
_legendContainer.pickingMode = PickingMode.Position;
if (host is ChartElement chart) _legendContainer.userData = chart;
else if (host.userData is ChartElement chartFromUserData) _legendContainer.userData = chartFromUserData;
host.Add(_legendContainer);
}
public void ClearHiddenPieSliceIds()
{
_state?.ClearHiddenPieSliceIds();
}
public void RefreshLegend(
ChartData data,
bool trace,
System.Action<string> pushBreadcrumb,
System.Action<ChartDirtyReason> requestImmediate)
{
if (_legendContainer == null) return;
if (data == null)
{
if (_legendContainer.childCount > 0) _legendContainer.Clear();
_legendHash = 0;
return;
}
PieSettings pieSettings = null;
PieLegendSettings pieLegend = null;
bool hasPieType = false;
bool hasNonPieType = false;
if (data.Series != null)
{
for (int i = 0; i < data.Series.Count; i++)
{
var s = data.Series[i];
if (s == null) continue;
bool isPieType = s.type == SerieType.Pie || s.type == SerieType.RingChart || s.type == SerieType.Pie3D;
if (isPieType)
{
hasPieType = true;
if (pieSettings == null) pieSettings = s.settings as PieSettings;
if (pieLegend == null)
{
if (s.settings is PieSettings ps) pieLegend = ps.legend;
else if (s.settings is RingChartSettings rcs) pieLegend = rcs.legend;
}
}
else
{
hasNonPieType = true;
}
}
}
bool isPurePieChart = hasPieType && !hasNonPieType;
if (isPurePieChart && pieLegend == null)
{
pieLegend = pieSettings != null ? pieSettings.legend : null;
}
LegendSettings settings = null;
if (isPurePieChart)
{
settings = CreateLegendSettings(pieLegend);
}
else
{
settings = data.legend;
}
if (settings == null || !settings.enabled)
{
if (_legendContainer.childCount > 0) _legendContainer.Clear();
_legendHash = 0;
return;
}
int nextHash = ComputeLegendHash(data);
if (nextHash == _legendHash) return;
_legendHash = nextHash;
if (trace) pushBreadcrumb?.Invoke("RefreshLegend start");
_legendContainer.Clear();
if (trace) pushBreadcrumb?.Invoke("RefreshLegend cleared");
_legendContainer.style.backgroundColor = settings.backgroundColor;
_legendContainer.style.position = Position.Absolute;
_legendContainer.style.flexDirection = (settings.position == LegendPosition.Left || settings.position == LegendPosition.Right)
? FlexDirection.Column
: FlexDirection.Row;
_legendContainer.style.flexWrap = Wrap.Wrap;
if (settings.position == LegendPosition.Left || settings.position == LegendPosition.Right)
{
_legendContainer.style.alignItems = Align.FlexStart;
_legendContainer.style.alignContent = Align.FlexStart;
}
else
{
_legendContainer.style.alignItems = Align.Center;
_legendContainer.style.alignContent = Align.Center;
}
_legendContainer.style.left = StyleKeyword.Null;
_legendContainer.style.right = StyleKeyword.Null;
_legendContainer.style.top = StyleKeyword.Null;
_legendContainer.style.bottom = StyleKeyword.Null;
_legendContainer.style.translate = new Translate(new Length(0), new Length(0), 0);
_legendContainer.style.paddingBottom = 0;
_legendContainer.style.paddingTop = 0;
_legendContainer.style.paddingLeft = 0;
_legendContainer.style.paddingRight = 0;
_legendContainer.style.marginLeft = 0;
_legendContainer.style.marginRight = 0;
_legendContainer.style.marginTop = 0;
_legendContainer.style.marginBottom = 0;
_legendContainer.style.borderLeftWidth = 0;
_legendContainer.style.borderRightWidth = 0;
_legendContainer.style.borderTopWidth = 0;
_legendContainer.style.borderBottomWidth = 0;
switch (settings.position)
{
case LegendPosition.Bottom:
_legendContainer.style.bottom = 0;
_legendContainer.style.left = 0;
_legendContainer.style.right = 0;
_legendContainer.style.justifyContent = Justify.Center;
_legendContainer.style.paddingBottom = 5;
break;
case LegendPosition.Top:
_legendContainer.style.top = 0;
_legendContainer.style.left = 0;
_legendContainer.style.right = 0;
_legendContainer.style.justifyContent = Justify.Center;
_legendContainer.style.paddingTop = 5;
break;
case LegendPosition.Left:
_legendContainer.style.left = 0;
_legendContainer.style.top = 0;
_legendContainer.style.bottom = 0;
_legendContainer.style.justifyContent = Justify.Center;
_legendContainer.style.paddingLeft = 5;
break;
case LegendPosition.Right:
_legendContainer.style.right = 0;
_legendContainer.style.top = 0;
_legendContainer.style.bottom = 0;
_legendContainer.style.justifyContent = Justify.Center;
_legendContainer.style.paddingRight = 5;
break;
}
// Apply offset with position-based defaults to center legend between plot edge and canvas edge
Vector2 effectiveOffset = settings.offset;
if (effectiveOffset == Vector2.zero)
{
switch (settings.position)
{
case LegendPosition.Top:
effectiveOffset = new Vector2(0, 30);
break;
case LegendPosition.Bottom:
effectiveOffset = new Vector2(0, -30);
break;
case LegendPosition.Right:
effectiveOffset = new Vector2(-30, 0);
break;
case LegendPosition.Left:
effectiveOffset = new Vector2(30, 0);
break;
}
}
_legendContainer.style.translate = new Translate(new Length(effectiveOffset.x), new Length(-effectiveOffset.y), 0);
bool isPieChart = isPurePieChart && (pieLegend == null || pieLegend.source != PieLegendSource.Series);
if (isPieChart)
{
Serie pieSerie = null;
for (int si = 0; si < data.Series.Count; si++)
{
var s = data.Series[si];
if (s != null && (s.type == SerieType.Pie || s.type == SerieType.RingChart || s.type == SerieType.Pie3D) && s.seriesData != null)
{
pieSerie = s;
if (pieSettings == null)
{
pieSettings = s.settings as PieSettings;
if (pieSettings == null && s.settings is RingChartSettings rcs)
{
// RingChartSettings doesn't have aggregation, create a minimal PieSettings for legend
pieSettings = null;
}
}
break;
}
}
if (pieSerie != null && pieSerie.seriesData != null)
{
// For None coordinate system (Pie/etc), only use SeriesData.name (no axis labels fallback)
bool isNoneCoord = data != null && data.CoordinateSystem == CoordinateSystemType.None;
List<string> labels = null;
if (!isNoneCoord)
{
if (pieLegend != null && pieLegend.source == PieLegendSource.RingSlice)
{
if (data != null && data.PolarAxes != null && data.PolarAxes.angleAxis != null)
{
labels = data.PolarAxes.angleAxis.labels;
}
}
else
{
if (data != null && data.Axes != null)
{
AxisId preferredAxisId = data.Cartesian != null ? data.Cartesian.xAxisId : AxisId.XBottom;
for (int j = 0; j < data.Axes.Count; j++)
{
var a = data.Axes[j];
if (a != null && a.id == preferredAxisId && a.axisType == AxisType.Category)
{
labels = a.labels;
break;
}
}
if (labels == null)
{
for (int j = 0; j < data.Axes.Count; j++)
{
var a = data.Axes[j];
if (a != null && a.axisType == AxisType.Category)
{
labels = a.labels;
break;
}
}
}
}
}
}
var candidates = new List<(int SourceIndex, float Value, SeriesData Data)>();
for (int i = 0; i < pieSerie.seriesData.Count; i++)
{
var dp = pieSerie.seriesData[i];
if (dp == null) continue;
if (dp.value <= 0) continue;
candidates.Add((i, dp.value, dp));
}
bool doAgg = pieSettings != null && pieSettings.aggregation != null && pieSettings.aggregation.enabled;
int keepTopN = doAgg ? Mathf.Max(0, pieSettings.aggregation.keepTopN) : 0;
bool sortByValue = pieSettings != null && pieSettings.sortByValue;
if (sortByValue)
{
candidates.Sort((a, b) => b.Value.CompareTo(a.Value));
}
float othersValue = 0f;
int limit = (doAgg && keepTopN > 0) ? Mathf.Min(keepTopN, candidates.Count) : candidates.Count;
int sliceIndex = 0;
for (int i = 0; i < candidates.Count; i++)
{
if (i < limit)
{
var c = candidates[i];
string name = null;
if (c.Data != null && !string.IsNullOrEmpty(c.Data.name)) name = c.Data.name;
else if (labels != null && c.SourceIndex < labels.Count) name = labels[c.SourceIndex];
if (string.IsNullOrEmpty(name))
{
name = (pieLegend != null && pieLegend.source == PieLegendSource.RingSlice)
? $"Ring {c.SourceIndex}"
: $"Slice {c.SourceIndex}";
}
ValueDisplayStyle displayStyle = ValueDisplayStyle.None;
if (pieLegend != null)
{
displayStyle = pieLegend.valueDisplayStyle;
if (displayStyle == ValueDisplayStyle.None && pieLegend.showValue) displayStyle = ValueDisplayStyle.Parentheses;
}
string valueText = c.Value.ToString("0.##");
if (displayStyle == ValueDisplayStyle.Parentheses)
{
name = $"{name} ({valueText})";
}
Color color = (c.Data != null && c.Data.useColor)
? c.Data.color
: PieSeriesRenderer.Palette[sliceIndex % PieSeriesRenderer.Palette.Length];
string sliceId = (c.Data != null && !string.IsNullOrEmpty(c.Data.id))
? c.Data.id
: c.SourceIndex.ToString();
string capturedId = sliceId;
bool isVisible = _state == null || !_state.HiddenPieSliceIds.Contains(capturedId);
if (displayStyle == ValueDisplayStyle.AlignedColumns)
{
CreateLegendItemAlignedColumns(settings, name, valueText, color, isVisible, (visible) =>
{
if (_state != null)
{
if (visible) _state.HiddenPieSliceIds.Remove(capturedId);
else _state.HiddenPieSliceIds.Add(capturedId);
}
requestImmediate?.Invoke(ChartDirtyReason.LegendTogglePieSlice);
});
}
else
{
CreateLegendItem(settings, name, color, isVisible, (visible) =>
{
if (_state != null)
{
if (visible) _state.HiddenPieSliceIds.Remove(capturedId);
else _state.HiddenPieSliceIds.Add(capturedId);
}
requestImmediate?.Invoke(ChartDirtyReason.LegendTogglePieSlice);
});
}
sliceIndex++;
}
else
{
othersValue += candidates[i].Value;
}
}
if (doAgg && keepTopN > 0 && candidates.Count > keepTopN && othersValue > 0f)
{
string name = pieSettings != null && pieSettings.aggregation != null && !string.IsNullOrEmpty(pieSettings.aggregation.othersName)
? pieSettings.aggregation.othersName
: "Others";
ValueDisplayStyle displayStyle = ValueDisplayStyle.None;
if (pieLegend != null)
{
displayStyle = pieLegend.valueDisplayStyle;
if (displayStyle == ValueDisplayStyle.None && pieLegend.showValue) displayStyle = ValueDisplayStyle.Parentheses;
}
string valueText = othersValue.ToString("0.##");
if (displayStyle == ValueDisplayStyle.Parentheses)
{
name = $"{name} ({valueText})";
}
Color color = PieSeriesRenderer.Palette[sliceIndex % PieSeriesRenderer.Palette.Length];
if (pieSettings != null && pieSettings.aggregation != null && pieSettings.aggregation.useOthersColor) color = pieSettings.aggregation.othersColor;
string capturedId = PieSeriesRenderer.OthersSliceId;
bool isVisible = _state == null || !_state.HiddenPieSliceIds.Contains(capturedId);
if (displayStyle == ValueDisplayStyle.AlignedColumns)
{
CreateLegendItemAlignedColumns(settings, name, valueText, color, isVisible, (visible) =>
{
if (_state != null)
{
if (visible) _state.HiddenPieSliceIds.Remove(capturedId);
else _state.HiddenPieSliceIds.Add(capturedId);
}
requestImmediate?.Invoke(ChartDirtyReason.LegendTogglePieSlice);
});
}
else
{
CreateLegendItem(settings, name, color, isVisible, (visible) =>
{
if (_state != null)
{
if (visible) _state.HiddenPieSliceIds.Remove(capturedId);
else _state.HiddenPieSliceIds.Add(capturedId);
}
requestImmediate?.Invoke(ChartDirtyReason.LegendTogglePieSlice);
});
}
}
}
}
else
{
foreach (var serie in data.Series)
{
Color color = Color.white;
if (serie.type == SerieType.Line && serie.settings is LineSettings ls)
{
if (ls.stroke == null) ls.stroke = new LineStrokeSettings();
color = ls.stroke.color;
}
else if ((serie.type == SerieType.Bar || serie.type == SerieType.HorizontalBar) && serie.settings is BarSettings bs) color = (bs.textureFill != null ? bs.textureFill.color : Color.white);
else if (serie.type == SerieType.Scatter && serie.settings is ScatterSettings ss) color = (ss.point != null && ss.point.textureFill != null ? ss.point.textureFill.color : Color.white);
else if (serie.type == SerieType.Radar && serie.settings is RadarSettings rs)
{
// Prefer area fill color if area is shown, otherwise use stroke color
if (rs.area != null && rs.area.show && rs.area.textureFill != null)
{
color = rs.area.textureFill.color;
}
else
{
if (rs.stroke == null) rs.stroke = new LineStrokeSettings();
color = rs.stroke.color;
}
}
else if ((serie.type == SerieType.Pie || serie.type == SerieType.RingChart || serie.type == SerieType.Pie3D) && serie.seriesData != null)
{
// Series-level legend for pie: pick a representative color.
Color picked = Color.white;
int pickedIndex = 0;
for (int i = 0; i < serie.seriesData.Count; i++)
{
var dp = serie.seriesData[i];
if (dp == null) continue;
if (dp.value <= 0f) continue;
pickedIndex = i;
picked = dp.useColor ? dp.color : PieSeriesRenderer.Palette[0];
break;
}
if (picked == Color.white)
{
picked = PieSeriesRenderer.Palette[pickedIndex % PieSeriesRenderer.Palette.Length];
}
color = picked;
}
CreateLegendItem(settings, serie.name, color, serie.visible, (visible) =>
{
serie.visible = visible;
requestImmediate?.Invoke(ChartDirtyReason.LegendToggleSeriesVisibility);
});
}
}
}
private static LegendSettings CreateLegendSettings(PieLegendSettings src)
{
if (src == null) return null;
return new LegendSettings
{
enabled = src.enabled,
position = src.position,
fontSize = src.fontSize,
color = src.color,
backgroundColor = src.backgroundColor,
itemSpacing = src.itemSpacing,
offset = src.offset,
};
}
private int ComputeLegendHash(ChartData data)
{
unchecked
{
int h = 17;
if (data == null) return 0;
h = h * 31 + (data.CoordinateSystem.GetHashCode());
PieLegendSettings pieLegend = null;
bool hasPieType = false;
bool hasNonPieType = false;
if (data.Series != null)
{
for (int i = 0; i < data.Series.Count; i++)
{
var s = data.Series[i];
if (s == null) continue;
bool isPieType = s.type == SerieType.Pie || s.type == SerieType.RingChart || s.type == SerieType.Pie3D;
if (isPieType)
{
hasPieType = true;
if (pieLegend == null)
{
if (s.settings is PieSettings ps) pieLegend = ps.legend;
else if (s.settings is RingChartSettings rcs) pieLegend = rcs.legend;
}
}
else
{
hasNonPieType = true;
}
}
}
bool isPurePieChart = hasPieType && !hasNonPieType;
LegendSettings settings = null;
if (isPurePieChart)
{
settings = CreateLegendSettings(pieLegend);
}
else
{
settings = data.legend;
}
if (settings == null) return h;
h = h * 31 + (settings.enabled ? 1 : 0);
h = h * 31 + settings.position.GetHashCode();
h = h * 31 + settings.offset.GetHashCode();
h = h * 31 + settings.backgroundColor.GetHashCode();
h = h * 31 + settings.itemSpacing.GetHashCode();
bool isPieChart = isPurePieChart && (pieLegend == null || pieLegend.source != PieLegendSource.Series);
h = h * 31 + (isPieChart ? 1 : 0);
if (pieLegend != null)
{
h = h * 31 + pieLegend.source.GetHashCode();
h = h * 31 + (pieLegend.enabled ? 1 : 0);
h = h * 31 + (pieLegend.showValue ? 1 : 0);
h = h * 31 + pieLegend.valueDisplayStyle.GetHashCode();
h = h * 31 + pieLegend.position.GetHashCode();
h = h * 31 + pieLegend.offset.GetHashCode();
h = h * 31 + pieLegend.backgroundColor.GetHashCode();
h = h * 31 + pieLegend.itemSpacing.GetHashCode();
}
int hiddenHash = 0;
if (_state != null)
{
foreach (var id in _state.HiddenPieSliceIds)
{
if (id == null) continue;
hiddenHash ^= id.GetHashCode();
}
}
h = h * 31 + hiddenHash;
if (data.Series == null) return h;
if (isPieChart)
{
Serie pieSerie = null;
PieSettings pieSettings = null;
for (int si = 0; si < data.Series.Count; si++)
{
var s = data.Series[si];
if (s != null && s.visible && (s.type == SerieType.Pie || s.type == SerieType.RingChart || s.type == SerieType.Pie3D) && s.seriesData != null)
{
pieSerie = s;
pieSettings = s.settings as PieSettings;
break;
}
}
if (pieSerie != null)
{
h = h * 31 + pieSerie.seriesData.Count;
for (int i = 0; i < pieSerie.seriesData.Count; i++)
{
var dp = pieSerie.seriesData[i];
if (dp == null) continue;
h = h * 31 + (dp.id != null ? dp.id.GetHashCode() : i);
h = h * 31 + (dp.name != null ? dp.name.GetHashCode() : 0);
h = h * 31 + (dp.useColor ? dp.color.GetHashCode() : 0);
h = h * 31 + dp.value.GetHashCode();
}
}
if (pieSettings != null)
{
h = h * 31 + (pieSettings.sortByValue ? 1 : 0);
if (pieSettings.aggregation != null)
{
h = h * 31 + (pieSettings.aggregation.enabled ? 1 : 0);
h = h * 31 + pieSettings.aggregation.keepTopN;
h = h * 31 + (pieSettings.aggregation.othersName != null ? pieSettings.aggregation.othersName.GetHashCode() : 0);
h = h * 31 + (pieSettings.aggregation.useOthersColor ? 1 : 0);
h = h * 31 + pieSettings.aggregation.othersColor.GetHashCode();
}
}
}
else
{
for (int i = 0; i < data.Series.Count; i++)
{
var serie = data.Series[i];
if (serie == null) continue;
h = h * 31 + serie.type.GetHashCode();
h = h * 31 + (serie.name != null ? serie.name.GetHashCode() : 0);
h = h * 31 + (serie.visible ? 1 : 0);
Color color = Color.white;
if (serie.type == SerieType.Line && serie.settings is LineSettings ls)
{
if (ls.stroke == null) ls.stroke = new LineStrokeSettings();
color = ls.stroke.color;
}
else if (serie.type == SerieType.Bar && serie.settings is BarSettings bs)
{
color = (bs.textureFill != null ? bs.textureFill.color : Color.white);
}
else if (serie.type == SerieType.Scatter && serie.settings is ScatterSettings ss)
{
color = (ss.point != null && ss.point.textureFill != null ? ss.point.textureFill.color : Color.white);
}
else if (serie.type == SerieType.Radar && serie.settings is RadarSettings rs)
{
if (rs.stroke == null) rs.stroke = new LineStrokeSettings();
color = rs.stroke.color;
}
else if ((serie.type == SerieType.Pie || serie.type == SerieType.RingChart) && serie.seriesData != null)
{
// Keep series-level legend hash stable for pie.
int pickedIndex = 0;
Color picked = Color.white;
for (int j = 0; j < serie.seriesData.Count; j++)
{
var dp = serie.seriesData[j];
if (dp == null) continue;
if (dp.value <= 0f) continue;
pickedIndex = j;
picked = dp.useColor ? dp.color : PieSeriesRenderer.Palette[0];
break;
}
if (picked == Color.white)
{
picked = PieSeriesRenderer.Palette[pickedIndex % PieSeriesRenderer.Palette.Length];
}
color = picked;
}
h = h * 31 + color.GetHashCode();
}
}
return h;
}
}
private static void ApplyLegendElementBaseStyle(VisualElement ve)
{
ve.style.marginLeft = 0;
ve.style.marginRight = 0;
ve.style.marginTop = 0;
ve.style.marginBottom = 0;
ve.style.paddingLeft = 0;
ve.style.paddingRight = 0;
ve.style.paddingTop = 0;
ve.style.paddingBottom = 0;
ve.style.borderLeftWidth = 0;
ve.style.borderRightWidth = 0;
ve.style.borderTopWidth = 0;
ve.style.borderBottomWidth = 0;
ve.style.flexGrow = 0;
ve.style.flexShrink = 0;
}
private static void ApplyLegendLabelBaseStyle(Label label)
{
ApplyLegendElementBaseStyle(label);
label.style.whiteSpace = WhiteSpace.NoWrap;
}
private void CreateLegendItem(string name, Color color, bool isVisible, System.Action<bool> onToggle)
{
CreateLegendItem(null, name, color, isVisible, onToggle);
}
private void CreateLegendItem(LegendSettings settings, string name, Color color, bool isVisible, System.Action<bool> onToggle)
{
if (_legendContainer == null) return;
var item = new VisualElement();
ApplyLegendElementBaseStyle(item);
item.style.flexDirection = FlexDirection.Row;
item.style.alignItems = Align.Center;
if (settings != null)
{
bool vertical = settings.position == LegendPosition.Left || settings.position == LegendPosition.Right;
item.style.marginRight = vertical ? 0 : settings.itemSpacing;
item.style.marginBottom = settings.itemSpacing;
item.style.paddingLeft = 2;
item.style.paddingRight = 2;
item.style.paddingTop = 1;
item.style.paddingBottom = 1;
}
// Icon
var icon = new VisualElement();
ApplyLegendElementBaseStyle(icon);
icon.style.width = 10;
icon.style.height = 10;
icon.style.backgroundColor = color;
item.Add(icon);
// Label
var label = new Label(name);
ApplyLegendLabelBaseStyle(label);
if (settings != null)
{
if (settings.fontSize > 0) label.style.fontSize = settings.fontSize;
else label.style.fontSize = StyleKeyword.Null;
label.style.color = settings.color;
}
label.style.marginLeft = 5;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
ChartTextStyleApplier.ApplyLabel(label, _legendContainer, ChartTextRole.Legend);
item.Add(label);
item.RegisterCallback<PointerDownEvent>(evt =>
{
var policy = LegendTogglePolicy ?? DefaultChartLegendTogglePolicy.Instance;
bool newState = policy.GetNextVisibleState(isVisible, evt);
onToggle?.Invoke(newState);
});
if (!isVisible)
{
item.style.opacity = 0.5f;
}
_legendContainer.Add(item);
}
private void CreateLegendItemAlignedColumns(LegendSettings settings, string name, string value, Color color, bool isVisible, System.Action<bool> onToggle)
{
if (_legendContainer == null) return;
var item = new VisualElement();
ApplyLegendElementBaseStyle(item);
item.style.flexDirection = FlexDirection.Row;
item.style.alignItems = Align.Center;
if (settings != null)
{
bool vertical = settings.position == LegendPosition.Left || settings.position == LegendPosition.Right;
item.style.marginRight = vertical ? 0 : settings.itemSpacing;
item.style.marginBottom = settings.itemSpacing;
item.style.paddingLeft = 2;
item.style.paddingRight = 2;
item.style.paddingTop = 1;
item.style.paddingBottom = 1;
}
// Icon
var icon = new VisualElement();
ApplyLegendElementBaseStyle(icon);
icon.style.width = 10;
icon.style.height = 10;
icon.style.backgroundColor = color;
item.Add(icon);
// Labels container
var labels = new VisualElement();
ApplyLegendElementBaseStyle(labels);
labels.style.flexDirection = FlexDirection.Row;
labels.style.alignItems = Align.Center;
labels.style.flexGrow = 1f;
labels.style.flexShrink = 1f;
labels.style.minWidth = 0;
labels.style.marginLeft = 5;
item.Add(labels);
var nameLabel = new Label(name);
ApplyLegendLabelBaseStyle(nameLabel);
nameLabel.style.flexGrow = 1f;
nameLabel.style.flexShrink = 1f;
nameLabel.style.minWidth = 0;
nameLabel.style.unityTextAlign = TextAnchor.MiddleLeft;
var valueLabel = new Label(value);
ApplyLegendLabelBaseStyle(valueLabel);
valueLabel.style.flexGrow = 0f;
valueLabel.style.flexShrink = 0f;
valueLabel.style.unityTextAlign = TextAnchor.MiddleRight;
valueLabel.style.marginLeft = 10;
if (settings != null)
{
if (settings.fontSize > 0)
{
nameLabel.style.fontSize = settings.fontSize;
valueLabel.style.fontSize = settings.fontSize;
}
else
{
nameLabel.style.fontSize = StyleKeyword.Null;
valueLabel.style.fontSize = StyleKeyword.Null;
}
nameLabel.style.color = settings.color;
valueLabel.style.color = settings.color;
}
ChartTextStyleApplier.ApplyLabel(nameLabel, _legendContainer, ChartTextRole.Legend);
ChartTextStyleApplier.ApplyLabel(valueLabel, _legendContainer, ChartTextRole.Legend);
labels.Add(nameLabel);
labels.Add(valueLabel);
item.RegisterCallback<PointerDownEvent>(evt =>
{
var policy = LegendTogglePolicy ?? DefaultChartLegendTogglePolicy.Instance;
bool newState = policy.GetNextVisibleState(isVisible, evt);
onToggle?.Invoke(newState);
});
if (!isVisible)
{
item.style.opacity = 0.5f;
}
_legendContainer.Add(item);
}
}
}