using System; using System.Collections.Generic; using UnityEngine; namespace XCharts.Runtime { public static class SeriesHelper { public static bool IsLegalLegendName(string name) { int numName = -1; if (int.TryParse(name, out numName)) { if (numName >= 0 && numName < 100) return false; } return true; } public static List GetLegalSerieNameList(List series) { var list = new List(); for (int n = 0; n < series.Count; n++) { var serie = series[n]; if (serie.placeHolder) continue; if (serie.useDataNameForColor) { for (int i = 0; i < serie.data.Count; i++) { var dataName = serie.data[i].name; if (!string.IsNullOrEmpty(dataName) && IsLegalLegendName(dataName) && !list.Contains(dataName)) list.Add(dataName); } } else { if (!string.IsNullOrEmpty(serie.serieName) && !list.Contains(serie.serieName) && IsLegalLegendName(serie.serieName)) list.Add(serie.serieName); } } return list; } /// /// 获得所有系列名,不包含空名字。 /// /// public static void UpdateSerieNameList(BaseChart chart, ref List serieNameList) { serieNameList.Clear(); for (int n = 0; n < chart.series.Count; n++) { var serie = chart.series[n]; if (serie.placeHolder) continue; if (serie.useDataNameForColor) { for (int i = 0; i < serie.data.Count; i++) { var serieData = serie.data[i]; if (serie is Pie && serie.IsIgnoreValue(serieData)) continue; if (string.IsNullOrEmpty(serieData.name)) serieNameList.Add(ChartCached.IntToStr(i)); else if (!serieNameList.Contains(serieData.name)) serieNameList.Add(serieData.name); } } else { if (string.IsNullOrEmpty(serie.serieName)) serieNameList.Add(ChartCached.IntToStr(n)); else if (!serieNameList.Contains(serie.serieName)) serieNameList.Add(serie.serieName); } } } public static Color GetNameColor(BaseChart chart, int index, string name) { Serie destSerie = null; SerieData destSerieData = null; var series = chart.series; for (int n = 0; n < series.Count; n++) { var serie = series[n]; if (serie.placeHolder) continue; if (serie.useDataNameForColor) { bool found = false; for (int i = 0; i < serie.data.Count; i++) { if (name.Equals(serie.data[i].name)) { destSerie = serie; destSerieData = serie.data[i]; found = true; break; } } if (found) break; } if (name.Equals(serie.serieName)) { destSerie = serie; destSerieData = null; break; } } return SerieHelper.GetItemColor(destSerie, destSerieData, chart.theme, index, false); } /// /// 是否有需裁剪的serie。 /// /// public static bool IsAnyClipSerie(List series) { foreach (var serie in series) { if (serie.clip) return true; } return false; } /// /// 获得上一个同堆叠且显示的serie。 /// /// /// public static Serie GetLastStackSerie(List series, Serie serie) { if (serie == null || string.IsNullOrEmpty(serie.stack)) return null; for (int i = serie.index - 1; i >= 0; i--) { var temp = series[i]; if (temp.show && serie.stack.Equals(temp.stack)) return temp; } return null; } public static Serie GetSerieByVesselIndex(List series, int vesselIndex) { foreach (var serie in series) { if (serie.vesselIndex == vesselIndex) return serie; } return null; } private static HashSet _setForStack = new HashSet(); /// /// 是否由数据堆叠 /// /// public static bool IsStack(List series) { _setForStack.Clear(); foreach (var serie in series) { if (string.IsNullOrEmpty(serie.stack)) continue; if (_setForStack.Contains(serie.stack)) return true; _setForStack.Add(serie.stack); } return false; } /// /// 是否堆叠 /// /// /// /// public static bool IsStack(List series, string stackName) where T : Serie { if (string.IsNullOrEmpty(stackName)) return false; int count = 0; foreach (var serie in series) { if (serie.show && serie is T) { if (stackName.Equals(serie.stack)) count++; if (count >= 2) return true; } } return false; } /// /// 是否时百分比堆叠 /// /// /// public static bool IsPercentStack(List series) where T : Serie { int count = 0; bool isPercentStack = false; foreach (var serie in series) { if (serie.show && serie is T) { if (!string.IsNullOrEmpty(serie.stack)) { count++; if (serie.barPercentStack) isPercentStack = true; } if (count >= 2 && isPercentStack) return true; } } return false; } /// /// 是否时百分比堆叠 /// /// /// /// public static bool IsPercentStack(List series, string stackName) where T : Serie { if (string.IsNullOrEmpty(stackName)) return false; int count = 0; bool isPercentStack = false; foreach (var serie in series) { if (serie.show && serie is T) { if (stackName.Equals(serie.stack)) { count++; if (serie.barPercentStack) isPercentStack = true; } if (count >= 2 && isPercentStack) return true; } } return false; } private static Dictionary sets = new Dictionary(); /// /// 获得堆叠系列列表 /// /// /// public static void GetStackSeries(List series, ref Dictionary> stackSeries) { int count = 0; var serieCount = series.Count; sets.Clear(); if (stackSeries == null) { stackSeries = new Dictionary>(serieCount); } else { foreach (var kv in stackSeries) { kv.Value.Clear(); } } for (int i = 0; i < serieCount; i++) { var serie = series[i]; serie.index = i; if (string.IsNullOrEmpty(serie.stack)) { if (!stackSeries.ContainsKey(count)) stackSeries[count] = new List(serieCount); stackSeries[count].Add(serie); count++; } else { if (!sets.ContainsKey(serie.stack)) { sets.Add(serie.stack, count); if (!stackSeries.ContainsKey(count)) stackSeries[count] = new List(serieCount); stackSeries[count].Add(serie); count++; } else { int stackIndex = sets[serie.stack]; stackSeries[stackIndex].Add(serie); } } } } public static void UpdateStackDataList(List series, Serie currSerie, DataZoom dataZoom, List> dataList) { dataList.Clear(); for (int i = 0; i <= currSerie.index; i++) { var serie = series[i]; if (serie.GetType() == currSerie.GetType() && ChartHelper.IsValueEqualsString(serie.stack, currSerie.stack)) { dataList.Add(serie.GetDataList(dataZoom)); } } } /// /// 获得维度X的最大最小值 /// /// /// /// /// public static void GetXMinMaxValue(List series, DataZoom dataZoom, int axisIndex, bool isValueAxis, bool inverse, out double minVaule, out double maxValue, bool isPolar = false) { GetMinMaxValue(series, dataZoom, axisIndex, isValueAxis, inverse, false, out minVaule, out maxValue, isPolar); } /// /// 获得维度Y的最大最小值 /// /// /// /// /// public static void GetYMinMaxValue(List series, DataZoom dataZoom, int axisIndex, bool isValueAxis, bool inverse, out double minVaule, out double maxValue, bool isPolar = false) { GetMinMaxValue(series, dataZoom, axisIndex, isValueAxis, inverse, true, out minVaule, out maxValue, isPolar); } private static Dictionary> _stackSeriesForMinMax = new Dictionary>(); private static Dictionary _serieTotalValueForMinMax = new Dictionary(); public static void GetMinMaxValue(List series, DataZoom dataZoom, int axisIndex, bool isValueAxis, bool inverse, bool yValue, out double minVaule, out double maxValue, bool isPolar = false) { double min = double.MaxValue; double max = double.MinValue; var isPercentStack = SeriesHelper.IsPercentStack(series); if (!SeriesHelper.IsStack(series) || (isValueAxis && !yValue)) { for (int i = 0; i < series.Count; i++) { var serie = series[i]; if ((isPolar && serie.polarIndex != axisIndex) || (!isPolar && serie.yAxisIndex != axisIndex) || !serie.show) continue; var updateDuration = serie.animation.enable?serie.animation.dataChangeDuration : 0; if (isPercentStack && SeriesHelper.IsPercentStack(series, serie.serieName)) { if (100 > max) max = 100; if (0 < min) min = 0; } else { var showData = serie.GetDataList(dataZoom); foreach (var data in showData) { if (serie is Candlestick) { var dataMin = data.GetMinData(inverse); var dataMax = data.GetMaxData(inverse); if (dataMax > max) max = dataMax; if (dataMin < min) min = dataMin; } else { //var currData = data.GetData(yValue ? 1 : 0, inverse); var currData = data.GetCurrData(yValue ? 1 : 0, updateDuration, inverse); if (!serie.IsIgnoreValue(currData)) { if (currData > max) max = currData; if (currData < min) min = currData; } } } } } } else { SeriesHelper.GetStackSeries(series, ref _stackSeriesForMinMax); foreach (var ss in _stackSeriesForMinMax) { _serieTotalValueForMinMax.Clear(); for (int i = 0; i < ss.Value.Count; i++) { var serie = ss.Value[i]; if ((isPolar && serie.polarIndex != axisIndex) || (!isPolar && serie.yAxisIndex != axisIndex) || !serie.show) continue; var showData = serie.GetDataList(dataZoom); if (SeriesHelper.IsPercentStack(series, serie.stack)) { for (int j = 0; j < showData.Count; j++) { _serieTotalValueForMinMax[j] = 100; } } else { for (int j = 0; j < showData.Count; j++) { if (!_serieTotalValueForMinMax.ContainsKey(j)) _serieTotalValueForMinMax[j] = 0; double currData = 0; if (serie is Candlestick) { currData = showData[j].GetMaxData(false); } else { currData = yValue ? showData[j].GetData(1) : showData[j].GetData(0); } if (inverse) currData = -currData; if (!serie.IsIgnoreValue(currData)) _serieTotalValueForMinMax[j] = _serieTotalValueForMinMax[j] + currData; } } } double tmax = double.MinValue; double tmin = double.MaxValue; foreach (var tt in _serieTotalValueForMinMax) { if (tt.Value > tmax) tmax = tt.Value; if (tt.Value < tmin) tmin = tt.Value; } if (tmax > max) max = tmax; if (tmin < min) min = tmin; } } if (max == double.MinValue && min == double.MaxValue) { minVaule = 0; maxValue = 0; } else { minVaule = min > 1 ? Math.Floor(min) : min; maxValue = max > 1 ? Math.Ceiling(max) : max; } } public static int GetMaxSerieDataCount(List series) { int max = 0; foreach (var serie in series) { if (serie.dataCount > max) max = serie.dataCount; } return max; } } }