217 lines
6.9 KiB
C#
217 lines
6.9 KiB
C#
|
|
#define Graph_And_Chart_PRO
|
||
|
|
using ChartAndGraph;
|
||
|
|
using System;
|
||
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
public class StackedGraphManager : MonoBehaviour
|
||
|
|
{
|
||
|
|
public int RealtimeDownSampleCount = 10;
|
||
|
|
public int DownSampleToPoints = 100;
|
||
|
|
|
||
|
|
public GraphChart Chart;
|
||
|
|
|
||
|
|
class CategoryEntry
|
||
|
|
{
|
||
|
|
public List<double> mYValues = new List<double>();
|
||
|
|
public List<DoubleVector2> mVectors = new List<DoubleVector2>();
|
||
|
|
public LargeDataFeed mFeed = null;
|
||
|
|
public bool mEnabled = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
Dictionary<string, CategoryEntry> mData = new Dictionary<string, CategoryEntry>();
|
||
|
|
List<double> mXValues = new List<double>();
|
||
|
|
List<double> mAccumilated = new List<double>();
|
||
|
|
void Start()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
public DoubleVector2 GetPointValue(string category,int inGraphIndex)
|
||
|
|
{
|
||
|
|
if (mData.ContainsKey(category) == false)
|
||
|
|
throw new ArgumentException("Category does not exist");
|
||
|
|
|
||
|
|
var entry = mData[category];
|
||
|
|
int index = entry.mFeed.GetIndex(inGraphIndex);
|
||
|
|
double y = entry.mYValues[index];
|
||
|
|
double x = mXValues[index];
|
||
|
|
return new DoubleVector2(x,y);
|
||
|
|
}
|
||
|
|
public void ToggleCategoryEnabled(string category)
|
||
|
|
{
|
||
|
|
VerifyCategories();
|
||
|
|
if (mData.ContainsKey(category) == false)
|
||
|
|
throw new ArgumentException("no such category");
|
||
|
|
var entry = mData[category];
|
||
|
|
entry.mEnabled = !entry.mEnabled;
|
||
|
|
Chart.DataSource.SetCategoryEnabled(category, entry.mEnabled);
|
||
|
|
ApplyData();
|
||
|
|
}
|
||
|
|
public void SetCategoryEnabled(string category,bool isEnabled)
|
||
|
|
{
|
||
|
|
VerifyCategories();
|
||
|
|
if (mData.ContainsKey(category) == false)
|
||
|
|
throw new ArgumentException("no such category");
|
||
|
|
var entry = mData[category];
|
||
|
|
entry.mEnabled = isEnabled;
|
||
|
|
Chart.DataSource.SetCategoryEnabled(category, isEnabled);
|
||
|
|
ApplyData();
|
||
|
|
}
|
||
|
|
void VerifyNewCategory(string name)
|
||
|
|
{
|
||
|
|
CategoryEntry data = null;
|
||
|
|
if (mData.ContainsKey(name))
|
||
|
|
data = mData[name];
|
||
|
|
if(data == null)
|
||
|
|
{
|
||
|
|
data = new CategoryEntry();
|
||
|
|
data.mYValues = new List<double>(mXValues.Count);
|
||
|
|
data.mVectors = new List<DoubleVector2>(mXValues.Count);
|
||
|
|
data.mFeed = gameObject.AddComponent<LargeDataFeed>();
|
||
|
|
data.mFeed.LoadExample = false;
|
||
|
|
data.mFeed.AlternativeGraph = Chart;
|
||
|
|
data.mFeed.Category = name;
|
||
|
|
mData[name] = data;
|
||
|
|
}
|
||
|
|
data.mVectors.Clear();
|
||
|
|
data.mYValues.Clear();
|
||
|
|
for (int i = 0; i < mXValues.Count; i++)
|
||
|
|
{
|
||
|
|
data.mVectors.Add(new DoubleVector2(mXValues[i], 0.0));
|
||
|
|
data.mYValues.Add(0.0);
|
||
|
|
}
|
||
|
|
data.mFeed.DownSampleToPoints = DownSampleToPoints;
|
||
|
|
data.mFeed.RealtimeDownSampleCount = RealtimeDownSampleCount;
|
||
|
|
}
|
||
|
|
private void OnValidate()
|
||
|
|
{
|
||
|
|
foreach(var feed in gameObject.GetComponents<LargeDataFeed>())
|
||
|
|
{
|
||
|
|
feed.DownSampleToPoints = DownSampleToPoints;
|
||
|
|
feed.RealtimeDownSampleCount = RealtimeDownSampleCount;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void VerifyRemoveCategory(string name)
|
||
|
|
{
|
||
|
|
if (mData.ContainsKey(name) == false)
|
||
|
|
return;
|
||
|
|
var data = mData[name];
|
||
|
|
if(data != null)
|
||
|
|
{
|
||
|
|
data.mVectors = null;
|
||
|
|
UnityEngine.Object.Destroy(data.mFeed);
|
||
|
|
}
|
||
|
|
mData.Remove(name);
|
||
|
|
}
|
||
|
|
|
||
|
|
void VerifyCategories()
|
||
|
|
{
|
||
|
|
var names = Chart.DataSource.CategoryNames;
|
||
|
|
foreach(string name in names)
|
||
|
|
{
|
||
|
|
if(mData.ContainsKey(name) == false)
|
||
|
|
{
|
||
|
|
VerifyNewCategory(name);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
foreach(string name in mData.Keys)
|
||
|
|
{
|
||
|
|
if (names.Contains(name) == false)
|
||
|
|
VerifyRemoveCategory(name);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void ClearEntries()
|
||
|
|
{
|
||
|
|
mXValues.Clear();
|
||
|
|
foreach (string name in Chart.DataSource.CategoryNames)
|
||
|
|
{
|
||
|
|
var entry = mData[name];
|
||
|
|
entry.mVectors.Clear();
|
||
|
|
entry.mFeed.SetData(new List<DoubleVector2>());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
public void InitialData(double[] x,double[,] y)
|
||
|
|
{
|
||
|
|
VerifyCategories();
|
||
|
|
ClearEntries();
|
||
|
|
if (x.Length != y.GetLength(0))
|
||
|
|
throw new ArgumentException("x and y size should match");
|
||
|
|
mXValues.Clear();
|
||
|
|
mXValues.AddRange(x);
|
||
|
|
mAccumilated.Clear();
|
||
|
|
mAccumilated.AddRange(Enumerable.Repeat(0.0, mXValues.Count));
|
||
|
|
int categoryIndex = Chart.DataSource.CategoryNames.Count()-1;
|
||
|
|
|
||
|
|
foreach (string name in Chart.DataSource.CategoryNames.Reverse())
|
||
|
|
{
|
||
|
|
var entry = mData[name];
|
||
|
|
|
||
|
|
|
||
|
|
if (entry.mEnabled)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < x.Length; i++)
|
||
|
|
mAccumilated[i] += y[i, categoryIndex];
|
||
|
|
}
|
||
|
|
entry.mYValues.Clear();
|
||
|
|
entry.mVectors.Clear();
|
||
|
|
for (int i = 0; i < mXValues.Count; i++)
|
||
|
|
{
|
||
|
|
entry.mYValues.Add(y[i, categoryIndex]);
|
||
|
|
entry.mVectors.Add(new DoubleVector2(mXValues[i], mAccumilated[i]));
|
||
|
|
}
|
||
|
|
|
||
|
|
entry.mFeed.SetData(entry.mVectors);
|
||
|
|
categoryIndex--;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void ApplyData()
|
||
|
|
{
|
||
|
|
mAccumilated.Clear();
|
||
|
|
mAccumilated.AddRange(Enumerable.Repeat(0.0, mXValues.Count));
|
||
|
|
int categoryIndex = Chart.DataSource.CategoryNames.Count() - 1;
|
||
|
|
|
||
|
|
foreach (string name in Chart.DataSource.CategoryNames.Reverse())
|
||
|
|
{
|
||
|
|
var entry = mData[name];
|
||
|
|
entry.mVectors.Clear();
|
||
|
|
if (entry.mEnabled)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < mXValues.Count; i++)
|
||
|
|
mAccumilated[i] += entry.mYValues[i];
|
||
|
|
}
|
||
|
|
entry.mVectors.Clear();
|
||
|
|
for (int i = 0; i < mXValues.Count; i++)
|
||
|
|
entry.mVectors.Add(new DoubleVector2(mXValues[i], mAccumilated[i]));
|
||
|
|
entry.mFeed.SetData(entry.mVectors);
|
||
|
|
categoryIndex--;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
public void AddPointRealtime(double x,double[] y,double slideTime = 0.0)
|
||
|
|
{
|
||
|
|
VerifyCategories();
|
||
|
|
mXValues.Add(x);
|
||
|
|
int categoryIndex = Chart.DataSource.CategoryNames.Count()-1;
|
||
|
|
double accumilated = 0.0;
|
||
|
|
foreach (string name in Chart.DataSource.CategoryNames.Reverse())
|
||
|
|
{
|
||
|
|
var entry = mData[name];
|
||
|
|
double yValue = 0.0;
|
||
|
|
if (categoryIndex < y.Length)
|
||
|
|
yValue = y[categoryIndex];
|
||
|
|
if (entry.mEnabled)
|
||
|
|
accumilated += yValue;
|
||
|
|
//entry.mVectors.Add(new DoubleVector2(x,yValue)); // this happens in AppendRealtimeWithDownSampling
|
||
|
|
entry.mYValues.Add(yValue);
|
||
|
|
entry.mFeed.AppendPointRealtime(x, accumilated, slideTime);
|
||
|
|
categoryIndex--;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
// Update is called once per frame
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|