#define Graph_And_Chart_PRO using System; using ChartAndGraph.DataSource; using UnityEngine; using System.Collections.Generic; using ChartAndGraph.Exceptions; using System.Linq; namespace ChartAndGraph { /// /// data source for bar charts /// [Serializable] public class BarData : AbstractChartData,IInternalBarData, IChartData { [Serializable] class CategoryData { public string Name; public ChartDynamicMaterial Materials; } [Serializable] class DataEntry { public string GroupName; public string ColumnName; public double Amount; } private ChartSparseDataSource mDataSource = new ChartSparseDataSource(); ChartSparseDataSource IInternalBarData.InternalDataSource { get { return mDataSource; } } [SerializeField] private CategoryData[] mCategories = new CategoryData[0]; [SerializeField] private string[] mGroups = new string[0]; [SerializeField] private DataEntry[] mData = new DataEntry[0]; public event Action ProperyUpdated; protected void RaisePropertyUpdated() { if (ProperyUpdated != null) ProperyUpdated(); } /// /// the number of categories in the data source /// public int TotalCategories { get { return mDataSource.Columns.Count; } } /// /// the number of groups in the data source /// public int TotalGroups { get { return mDataSource.Rows.Count; } } /// /// set this to true to automatically detect the highest bar value int the chart. This value will be used to scale all other bars /// [SerializeField] private bool automaticMaxValue = true; public void Update() { } /// /// renames a category. throw an exception on error /// /// /// public void RenameCategory(string prevName,string newName) { mDataSource.Columns[prevName].Name = newName; RaisePropertyUpdated(); } /// /// renames a group. throw an exception on error /// /// /// public void RenameGroup(string prevName,string newName) { mDataSource.Rows[prevName].Name = newName; RaisePropertyUpdated(); } /// /// set this to true to automatically detect the highest bar value int the chart. This value will be used to scale all other bars /// public bool AutomaticMaxValue { get { return automaticMaxValue; } set { automaticMaxValue = value; RaisePropertyUpdated(); } } /// /// Mannualy set the maximum value , all bars will be scaled based on this value. If a bar value is larger than this value it will be clamped /// Note: set AutomaticMaxValue to false in order to use this field /// [SerializeField] private double maxValue = 10; /// /// Mannualy set the maximum value , all bars will be scaled based on this value. If a bar value is larger than this value it will be clamped /// Note: set AutomaticMaxValue to false in order to use this field /// public double MaxValue { get { return maxValue; } set { maxValue = value; RaisePropertyUpdated(); } } public bool HasGroup(string groupName) { try { var row = mDataSource.Rows[groupName]; if (row != null) return true; } catch { } return false; } public bool HasCategory(string category) { try { var col = mDataSource.Columns[category]; if (col != null) return true; } catch { } return false; } /// /// set this to true to automatically detect the lowest bar value int the chart. This value will be used to scale all other bars /// [SerializeField] private bool automaticMinValue = false; /// /// set this to true to automatically detect the lowest bar value int the chart. This value will be used to scale all other bars /// public bool AutomaticMinValue { get { return automaticMinValue; } set { automaticMinValue = value; RaisePropertyUpdated(); } } /// /// Mannualy set the minimum value , all bars will be scaled based on this value. If a bar value is larger than this value it will be clamped /// Note: set AutomaticMinValue to false in order to use this field /// [SerializeField] private double minValue = 0; /// /// Mannualy set the minimum value , all bars will be scaled based on this value. If a bar value is larger than this value it will be clamped /// Note: set AutomaticMinValue to false in order to use this field /// public double MinValue { get { return minValue; } set { minValue = value; RaisePropertyUpdated(); } } void IInternalBarData.Update() { UpdateSliders(); } /// /// call this to suspend chart redrawing while updating the data of the chart /// public void StartBatch() { mDataSource.SuspendEvents = true; } /// /// call this after StartBatch , this will apply all the changed made between the StartBatch call to this call /// public void EndBatch() { mDataSource.SuspendEvents = false; } public double GetMinValue() { double min = MinValue; double? rawMin = mDataSource.getRawMinValue(); if (AutomaticMinValue && rawMin.HasValue) min = rawMin.Value; return min; } public double GetMaxValue() { double max = MaxValue; double? rawMax = mDataSource.getRawMaxValue(); if (AutomaticMaxValue && rawMax.HasValue) max = rawMax.Value; return max; } public string GetCategoryName(int index) { return mDataSource.Columns[index].Name; } public string GetGroupName(int index) { return mDataSource.Rows[index].Name; } /// /// used intenally , do not call /// /// public object[] StoreAllCategoriesinOrder() { return mCategories.ToArray(); } public void OnBeforeSerialize() { int totalColumns = mDataSource.Columns.Count; mCategories = new CategoryData[totalColumns]; for (int i = 0; i < totalColumns; i++) { CategoryData data = new CategoryData(); data.Name = mDataSource.Columns[i].Name; data.Materials = mDataSource.Columns[i].Material; mCategories[i] = data; } int totalRows = mDataSource.Rows.Count; mGroups = new string[totalRows]; for(int i=0; i< totalRows; i++) mGroups[i] = mDataSource.Rows[i].Name; double[,] raw = mDataSource.getRawData(); int current = 0; mData = new DataEntry[raw.GetLength(0) * raw.GetLength(1)]; for (int i = 0; i < raw.GetLength(0); ++i) { for (int j = 0; j < raw.GetLength(1); ++j) { DataEntry entry = new DataEntry(); entry.ColumnName = mDataSource.Columns[j].Name; entry.GroupName = mDataSource.Rows[i].Name; entry.Amount = raw[i, j]; mData[current++] = entry; } } } public void OnAfterDeserialize() { mDataSource = new ChartSparseDataSource(); mDataSource.SuspendEvents = true; mDataSource.Clear(); if (mCategories == null) mCategories = new CategoryData[0]; if (mGroups == null) mGroups = new string[0]; if (mData == null) mData = new DataEntry[0]; for (int i = 0; i < mCategories.Length; i++) { AddCategory(mCategories[i].Name, mCategories[i].Materials); } for (int i = 0; i < mGroups.Length; i++) AddGroup(mGroups[i]); for(int i=0; i< mData.Length; i++) { try { DataEntry entry = mData[i]; mDataSource.SetValue(entry.ColumnName, entry.GroupName, entry.Amount); } catch(Exception) { } } mDataSource.SuspendEvents = false; } /// /// Adds a new category to the bar chart. Each category has it's own material and name. /// Note: you must also have at least one group on the bar chart /// Example: you can set the categories to "Player 1","Player 2","Player 3" and the groups to "Gold","Wood","Oil","Total" /// in order to compare the resources the players have gather during a level /// /// the name of the category /// the material of the category public void AddCategory(string name, Material material) { AddCategory(name, new ChartDynamicMaterial(material)); } /// /// clears all groups in the bar chart /// public void ClearGroups() { string[] groups = mDataSource.Rows.Select(x => x.Name).ToArray(); foreach(string s in groups) { RemoveGroup(s); } } /// /// sets all values to the value parameted /// public void ClearValues(double value = 0.0) { string[] catgories = mDataSource.Columns.Select(x => x.Name).ToArray(); string[] groups = mDataSource.Rows.Select(x => x.Name).ToArray(); foreach (string g in groups) { foreach (string c in catgories) { SetValue(c, g, value); } } } /// /// clears alll categories in the bar chart /// public void ClearCategories() { string[] catgories = mDataSource.Columns.Select(x => x.Name).ToArray(); foreach (string s in catgories) { RemoveCategory(s); } } /// /// Adds a new category to the bar chart. Each category has it's own material and name. /// Note: you must also add groups to the bar data. /// Example: you can set the chart categories to be "Player 1","Player 2","Player 3" in order to compare player achivments /// /// the name of the category /// the dynamic material of the category. dynamic materials allows setting the material for different events public void AddCategory(string name, ChartDynamicMaterial material,int position) { ChartDataColumn column = new ChartDataColumn(name); column.Material = material; mDataSource.mColumns.Insert(position,column); } /// /// moves the category to a new position /// /// /// public void MoveCategory(string name,int newPosition) { mDataSource.mColumns.Move(name, newPosition); } public void SwitchCategoryPositions(string firstCategory,string secondCategory) { mDataSource.mColumns.SwitchPositions(firstCategory, secondCategory); } /// /// Adds a new category to the bar chart. Each category has it's own material and name. /// Note: you must also add groups to the bar data. /// Example: you can set the chart categories to be "Player 1","Player 2","Player 3" in order to compare player achivments /// /// the name of the category /// the dynamic material of the category. dynamic materials allows setting the material for different events public void AddCategory(string name, ChartDynamicMaterial material) { ChartDataColumn column = new ChartDataColumn(name); column.Material = material; mDataSource.mColumns.Add(column); } public void SetCategoryIndex(string name,int index) { ChartDataColumn col = mDataSource.mColumns[name]; double[] values = new double[TotalGroups]; for(int i=0; i /// sets the material for the specified category /// /// the name of the category /// the material of the category public void SetMaterial(string category,Material material) { SetMaterial(category, new ChartDynamicMaterial(material)); } public ChartDynamicMaterial GetMaterial(string category) { return mDataSource.Columns[category].Material; } /// /// sets the material for the specified category /// /// the name of the category /// the dynamic material of the category. dynamic materials allows setting the material for different events public void SetMaterial(string category,ChartDynamicMaterial material) { mDataSource.Columns[category].Material = material; RaisePropertyUpdated(); } /// /// removes a category from the bar chart /// /// the name of the category to remove public void RemoveCategory(string name) { ChartDataColumn column = mDataSource.Columns[name]; RemoveSliderForCategory(name); mDataSource.Columns.Remove(column); } /// /// removes a group from the bar chart /// /// the name of the group to remove public void RemoveGroup(string name) { ChartDataRow row = mDataSource.Rows[name]; RemoveSliderForGroup(name); mDataSource.Rows.Remove(row); } /// /// Adds a group to the bar chart. Each group holds a double value for each category. /// Note: you must also add at least one category to the bar chart /// Example: you can set the categories to "Player 1","Player 2","Player 3" and the groups to "Gold","Wood","Oil","Total" /// in order to compare the resources the players have gather during a level /// /// public void AddGroup(string name) { mDataSource.Rows.Add(new ChartDataRow(name)); } /// /// gets the value for the specified group and category /// /// the category name /// the group name /// public double GetValue(string category,string group) { return mDataSource.GetValue(category, group); } public bool CheckAnimationEnded(float time, AnimationCurve curve) { if (curve.length == 0) return true; return time > curve.keys[curve.length - 1].time; } private void FixEaseFunction(AnimationCurve curve) { curve.postWrapMode = WrapMode.Once; curve.preWrapMode = WrapMode.Once; } public void RestoreCategory(string name,object obj) { var cat = (CategoryData)obj; SetMaterial(name, cat.Materials); } public void SlideValue(string category, string group, double slideTo,float totalTime, AnimationCurve curve) { try { RemoveSlider(category, group); curve.postWrapMode = WrapMode.Once; curve.preWrapMode = WrapMode.Once; float time = 0f; if (curve.length > 0) time = curve.keys[curve.length - 1].time; Slider s = new Slider(); s.category = category; s.group = group; s.from = GetValue(category, group); s.to = slideTo; s.startTime = Time.time; s.timeScale = time / totalTime; s.totalTime = time; s.curve = curve; mSliders.Add(s); } catch (ChartException e) { Debug.LogWarning(e.Message); } } public void SlideValue(string category,string group,double slideTo,float time) { try { RemoveSlider(category, group); Slider s = new Slider(); s.category = category; s.group = group; s.from = GetValue(category, group); s.to = slideTo; s.startTime = Time.time; s.totalTime = time; mSliders.Add(s); } catch (ChartException e) { Debug.LogWarning(e.Message); } } /// /// sets the value for the specified group and category /// /// the category name /// the group name /// the value fo the bar public void SetValue(string category,string group,double amount) { RemoveSlider(category, group); SetValueInternal(category, group, amount); } protected override void SetValueInternal(string category, string group, double amount) { try { mDataSource.SetValue(category, group, amount); } catch (ChartException e) { Debug.LogWarning(e.Message); } } } }