using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using XUGL; namespace XCharts.Runtime { [UnityEngine.Scripting.Preserve] internal sealed class LegendHandler : MainComponentHandler { private static readonly string s_LegendObjectName = "legend"; public override void InitComponent() { InitLegend(component); } public override void CheckComponent(System.Text.StringBuilder sb) { var legend = component; if (ChartHelper.IsColorAlphaZero(legend.labelStyle.textStyle.color)) sb.AppendFormat("warning:legend{0}->textStyle->color alpha is 0\n", legend.index); var serieNameList = SeriesHelper.GetLegalSerieNameList(chart.series); if (serieNameList.Count == 0) sb.AppendFormat("warning:legend{0} need serie.serieName or serieData.name not empty\n", legend.index); foreach (var category in legend.data) { if (!serieNameList.Contains(category)) { sb.AppendFormat("warning:legend{0} [{1}] is invalid, must be one of serie.serieName or serieData.name\n", legend.index, category); } } } public override void DrawTop(VertexHelper vh) { DrawLegend(vh); } public override void OnSerieDataUpdate(int serieIndex) { if (FormatterHelper.NeedFormat(component.formatter)) component.refreshComponent(); } private void InitLegend(Legend legend) { legend.painter = null; legend.refreshComponent = delegate() { legend.OnChanged(); var legendObject = ChartHelper.AddObject(s_LegendObjectName + legend.index, chart.transform, chart.chartMinAnchor, chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta); legend.gameObject = legendObject; legendObject.hideFlags = chart.chartHideFlags; SeriesHelper.UpdateSerieNameList(chart, ref chart.m_LegendRealShowName); List datas; if (legend.show && legend.data.Count > 0) { datas = new List(); foreach (var data in legend.data) { if (chart.m_LegendRealShowName.Contains(data) || chart.IsSerieName(data)) datas.Add(data); } } else { datas = chart.m_LegendRealShowName; } int totalLegend = 0; for (int i = 0; i < datas.Count; i++) { if (!SeriesHelper.IsLegalLegendName(datas[i])) continue; totalLegend++; } legend.RemoveButton(); ChartHelper.HideAllObject(legendObject); if (!legend.show) return; for (int i = 0; i < datas.Count; i++) { if (!SeriesHelper.IsLegalLegendName(datas[i])) continue; string legendName = GetFormatterContent(legend, i, datas[i]); var readIndex = chart.m_LegendRealShowName.IndexOf(datas[i]); var active = chart.IsActiveByLegend(datas[i]); var bgColor = LegendHelper.GetIconColor(chart, legend, readIndex, datas[i], active); bgColor.a = legend.itemOpacity; var item = LegendHelper.AddLegendItem(chart, legend, i, datas[i], legendObject.transform, chart.theme, legendName, bgColor, active, readIndex); legend.SetButton(legendName, item, totalLegend); ChartHelper.ClearEventListener(item.button.gameObject); ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerDown, (data) => { if (data.selectedObject == null || legend.selectedMode == Legend.SelectedMode.None) return; var temp = data.selectedObject.name.Split('_'); string selectedName = temp[1]; int clickedIndex = int.Parse(temp[0]); if (legend.selectedMode == Legend.SelectedMode.Multiple) { OnLegendButtonClick(legend, clickedIndex, selectedName, !chart.IsActiveByLegend(selectedName)); } else { var btnList = legend.context.buttonList.Values.ToArray(); if (btnList.Length == 1) { OnLegendButtonClick(legend, 0, selectedName, !chart.IsActiveByLegend(selectedName)); } else { for (int n = 0; n < btnList.Length; n++) { temp = btnList[n].name.Split('_'); selectedName = btnList[n].legendName; var index = btnList[n].index; OnLegendButtonClick(legend, n, selectedName, index == clickedIndex ? true : false); } } } }); ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerEnter, (data) => { if (item.button == null) return; var temp = item.button.name.Split('_'); string selectedName = temp[1]; int index = int.Parse(temp[0]); OnLegendButtonEnter(legend, index, selectedName); }); ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerExit, (data) => { if (item.button == null) return; var temp = item.button.name.Split('_'); string selectedName = temp[1]; int index = int.Parse(temp[0]); OnLegendButtonExit(legend, index, selectedName); }); } LegendHelper.ResetItemPosition(legend, chart.chartPosition, chart.chartWidth, chart.chartHeight); }; legend.refreshComponent(); } private string GetFormatterContent(Legend legend, int dataIndex, string category) { if (string.IsNullOrEmpty(legend.formatter)) return category; else { var content = legend.formatter.Replace("{name}", category); content = content.Replace("{value}", category); var serie = chart.GetSerie(0); FormatterHelper.ReplaceContent(ref content, dataIndex, legend.numericFormatter, serie, chart); return content; } } private void OnLegendButtonClick(Legend legend, int index, string legendName, bool show) { chart.OnLegendButtonClick(index, legendName, show); if (chart.onLegendClick != null) chart.onLegendClick(legend, index, legendName, show); } private void OnLegendButtonEnter(Legend legend, int index, string legendName) { chart.OnLegendButtonEnter(index, legendName); if (chart.onLegendEnter != null) chart.onLegendEnter(legend, index, legendName); } private void OnLegendButtonExit(Legend legend, int index, string legendName) { chart.OnLegendButtonExit(index, legendName); if (chart.onLegendExit != null) chart.onLegendExit(legend, index, legendName); } private void DrawLegend(VertexHelper vh) { if (chart.series.Count == 0) return; var legend = component; if (!legend.show) return; if (legend.iconType == Legend.Type.Custom) return; foreach (var kv in legend.context.buttonList) { var item = kv.Value; var rect = item.GetIconRect(); var radius = Mathf.Min(rect.width, rect.height) / 2; var color = item.GetIconColor(); var iconType = legend.iconType; if (legend.iconType == Legend.Type.Auto) { var serie = chart.GetSerie(item.legendName); if (serie != null && serie is Line) { var sp = new Vector3(rect.center.x - rect.width / 2, rect.center.y); var ep = new Vector3(rect.center.x + rect.width / 2, rect.center.y); UGL.DrawLine(vh, sp, ep, chart.settings.legendIconLineWidth, color); if (!serie.symbol.show) continue; switch (serie.symbol.type) { case SymbolType.None: continue; case SymbolType.Circle: iconType = Legend.Type.Circle; break; case SymbolType.Diamond: iconType = Legend.Type.Diamond; break; case SymbolType.EmptyCircle: iconType = Legend.Type.EmptyCircle; break; case SymbolType.Rect: iconType = Legend.Type.Rect; break; case SymbolType.Triangle: iconType = Legend.Type.Triangle; break; } } else { iconType = Legend.Type.Rect; } } switch (iconType) { case Legend.Type.Rect: var cornerRadius = chart.settings.legendIconCornerRadius; UGL.DrawRoundRectangle(vh, rect.center, rect.width, rect.height, color, color, 0, cornerRadius, false, 0.5f); break; case Legend.Type.Circle: UGL.DrawCricle(vh, rect.center, radius, color); break; case Legend.Type.Diamond: UGL.DrawDiamond(vh, rect.center, radius, color); break; case Legend.Type.EmptyCircle: var backgroundColor = chart.GetChartBackgroundColor(); UGL.DrawEmptyCricle(vh, rect.center, radius, 2 * chart.settings.legendIconLineWidth, color, color, backgroundColor, 1f); break; case Legend.Type.Triangle: UGL.DrawTriangle(vh, rect.center, 1.2f * radius, color); break; } } } } }