1709 lines
58 KiB
C#
1709 lines
58 KiB
C#
![]() |
using UnityEngine;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System;
|
||
|
|
||
|
public class WMG_Series : MonoBehaviour {
|
||
|
|
||
|
public enum comboTypes {line, bar};
|
||
|
public enum areaShadingTypes {None, Solid, Gradient};
|
||
|
|
||
|
[SerializeField] private List<Vector2> _pointValues;
|
||
|
public WMG_List<Vector2> pointValues = new WMG_List<Vector2>();
|
||
|
[SerializeField] private List<Color> _pointColors;
|
||
|
public WMG_List<Color> pointColors = new WMG_List<Color>();
|
||
|
|
||
|
// public properties
|
||
|
public comboTypes comboType { get {return _comboType;}
|
||
|
set {
|
||
|
if (_comboType != value) {
|
||
|
_comboType = value;
|
||
|
prefabC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool useSecondYaxis { get {return _useSecondYaxis;}
|
||
|
set {
|
||
|
if (_useSecondYaxis != value) {
|
||
|
if (theGraph.axesType != WMG_Axis_Graph.axesTypes.DUAL_Y && value == true) {
|
||
|
Debug.LogWarning("Cannot set useSecondYaxis to true before setting graph axesType to dual-y");
|
||
|
return;
|
||
|
}
|
||
|
_useSecondYaxis = value;
|
||
|
pointValuesC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public string seriesName { get {return _seriesName;}
|
||
|
set {
|
||
|
if (_seriesName != value) {
|
||
|
_seriesName = value;
|
||
|
seriesNameC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public float pointWidthHeight { get {return _pointWidthHeight;}
|
||
|
set {
|
||
|
if (_pointWidthHeight != value) {
|
||
|
_pointWidthHeight = value;
|
||
|
pointWidthHeightC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public float lineScale { get {return _lineScale;}
|
||
|
set {
|
||
|
if (_lineScale != value) {
|
||
|
_lineScale = value;
|
||
|
lineScaleC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public Color pointColor { get {return _pointColor;}
|
||
|
set {
|
||
|
if (_pointColor != value) {
|
||
|
_pointColor = value;
|
||
|
pointColorC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool usePointColors { get {return _usePointColors;}
|
||
|
set {
|
||
|
if (_usePointColors != value) {
|
||
|
_usePointColors = value;
|
||
|
pointColorC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public Color lineColor { get {return _lineColor;}
|
||
|
set {
|
||
|
if (_lineColor != value) {
|
||
|
_lineColor = value;
|
||
|
lineColorC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool UseXDistBetweenToSpace { get {return _UseXDistBetweenToSpace;}
|
||
|
set {
|
||
|
if (_UseXDistBetweenToSpace != value) {
|
||
|
_UseXDistBetweenToSpace = value;
|
||
|
pointValuesC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool ManuallySetXDistBetween { get {return _ManuallySetXDistBetween;}
|
||
|
set {
|
||
|
if (_ManuallySetXDistBetween != value) {
|
||
|
_ManuallySetXDistBetween = value;
|
||
|
pointValuesC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public float xDistBetweenPoints { get {return _xDistBetweenPoints;}
|
||
|
set {
|
||
|
if (_xDistBetweenPoints != value) {
|
||
|
_xDistBetweenPoints = value;
|
||
|
pointValuesC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool ManuallySetExtraXSpace { get {return _ManuallySetExtraXSpace;}
|
||
|
set {
|
||
|
if (_ManuallySetExtraXSpace != value) {
|
||
|
_ManuallySetExtraXSpace = value;
|
||
|
pointValuesC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public float extraXSpace { get {return _extraXSpace;}
|
||
|
set {
|
||
|
if (_extraXSpace != value) {
|
||
|
_extraXSpace = value;
|
||
|
pointValuesC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool hidePoints { get {return _hidePoints;}
|
||
|
set {
|
||
|
if (_hidePoints != value) {
|
||
|
_hidePoints = value;
|
||
|
hidePointC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool hideLines { get {return _hideLines;}
|
||
|
set {
|
||
|
if (_hideLines != value) {
|
||
|
_hideLines = value;
|
||
|
hideLineC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool connectFirstToLast { get {return _connectFirstToLast;}
|
||
|
set {
|
||
|
if (_connectFirstToLast != value) {
|
||
|
_connectFirstToLast = value;
|
||
|
connectFirstToLastC.Changed();
|
||
|
lineScaleC.Changed();
|
||
|
linePaddingC.Changed();
|
||
|
hideLineC.Changed();
|
||
|
lineColorC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public float linePadding { get {return _linePadding;}
|
||
|
set {
|
||
|
if (_linePadding != value) {
|
||
|
_linePadding = value;
|
||
|
linePaddingC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool dataLabelsEnabled { get {return _dataLabelsEnabled;}
|
||
|
set {
|
||
|
if (_dataLabelsEnabled != value) {
|
||
|
_dataLabelsEnabled = value;
|
||
|
dataLabelsC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public int dataLabelsNumDecimals { get {return _dataLabelsNumDecimals;}
|
||
|
set {
|
||
|
if (_dataLabelsNumDecimals != value) {
|
||
|
_dataLabelsNumDecimals = value;
|
||
|
dataLabelsC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public int dataLabelsFontSize { get {return _dataLabelsFontSize;}
|
||
|
set {
|
||
|
if (_dataLabelsFontSize != value) {
|
||
|
_dataLabelsFontSize = value;
|
||
|
dataLabelsC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public Color dataLabelsColor { get {return _dataLabelsColor;}
|
||
|
set {
|
||
|
if (_dataLabelsColor != value) {
|
||
|
_dataLabelsColor = value;
|
||
|
dataLabelsC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public FontStyle dataLabelsFontStyle { get {return _dataLabelsFontStyle;}
|
||
|
set {
|
||
|
if (_dataLabelsFontStyle != value) {
|
||
|
_dataLabelsFontStyle = value;
|
||
|
dataLabelsC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public Font dataLabelsFont { get {return _dataLabelsFont;}
|
||
|
set {
|
||
|
if (_dataLabelsFont != value) {
|
||
|
_dataLabelsFont = value;
|
||
|
dataLabelsC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public Vector2 dataLabelsOffset { get {return _dataLabelsOffset;}
|
||
|
set {
|
||
|
if (_dataLabelsOffset != value) {
|
||
|
_dataLabelsOffset = value;
|
||
|
dataLabelsC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public areaShadingTypes areaShadingType { get {return _areaShadingType;}
|
||
|
set {
|
||
|
if (_areaShadingType != value) {
|
||
|
_areaShadingType = value;
|
||
|
areaShadingTypeC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public bool areaShadingUsesComputeShader { get {return _areaShadingUsesComputeShader;}
|
||
|
set {
|
||
|
if (_areaShadingUsesComputeShader != value) {
|
||
|
_areaShadingUsesComputeShader = value;
|
||
|
areaShadingTypeC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public Color areaShadingColor { get {return _areaShadingColor;}
|
||
|
set {
|
||
|
if (_areaShadingColor != value) {
|
||
|
_areaShadingColor = value;
|
||
|
areaShadingC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public float areaShadingAxisValue { get {return _areaShadingAxisValue;}
|
||
|
set {
|
||
|
if (_areaShadingAxisValue != value) {
|
||
|
_areaShadingAxisValue = value;
|
||
|
areaShadingC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public int pointPrefab { get {return _pointPrefab;}
|
||
|
set {
|
||
|
if (_pointPrefab != value) {
|
||
|
_pointPrefab = value;
|
||
|
prefabC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public int linkPrefab { get {return _linkPrefab;}
|
||
|
set {
|
||
|
if (_linkPrefab != value) {
|
||
|
_linkPrefab = value;
|
||
|
prefabC.Changed();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[System.Obsolete("This parameter is no longer used. Use ManuallySetXDistBetween if needed.")]
|
||
|
public bool AutoUpdateXDistBetween;
|
||
|
|
||
|
// Public variables without change tracking
|
||
|
public UnityEngine.Object dataLabelPrefab;
|
||
|
public GameObject dataLabelsParent;
|
||
|
|
||
|
public Material areaShadingMatSolid;
|
||
|
public Material areaShadingMatGradient;
|
||
|
public GameObject areaShadingParent;
|
||
|
public UnityEngine.Object areaShadingPrefab;
|
||
|
public UnityEngine.Object areaShadingCSPrefab;
|
||
|
|
||
|
public WMG_Axis_Graph theGraph;
|
||
|
public WMG_Data_Source realTimeDataSource;
|
||
|
public WMG_Data_Source pointValuesDataSource;
|
||
|
public UnityEngine.Object legendEntryPrefab;
|
||
|
public GameObject linkParent;
|
||
|
public GameObject nodeParent;
|
||
|
|
||
|
public WMG_Legend_Entry legendEntry;
|
||
|
|
||
|
// Private backing variables
|
||
|
[SerializeField] private comboTypes _comboType;
|
||
|
[SerializeField] private bool _useSecondYaxis;
|
||
|
[SerializeField] private string _seriesName;
|
||
|
[SerializeField] private float _pointWidthHeight;
|
||
|
[SerializeField] private float _lineScale;
|
||
|
[SerializeField] private Color _pointColor;
|
||
|
[SerializeField] private bool _usePointColors;
|
||
|
[SerializeField] private Color _lineColor;
|
||
|
[SerializeField] private bool _UseXDistBetweenToSpace;
|
||
|
[SerializeField] private bool _ManuallySetXDistBetween;
|
||
|
[SerializeField] private float _xDistBetweenPoints;
|
||
|
[SerializeField] private bool _ManuallySetExtraXSpace;
|
||
|
[SerializeField] private float _extraXSpace;
|
||
|
[SerializeField] private bool _hidePoints;
|
||
|
[SerializeField] private bool _hideLines;
|
||
|
[SerializeField] private bool _connectFirstToLast;
|
||
|
[SerializeField] private float _linePadding;
|
||
|
[SerializeField] private bool _dataLabelsEnabled;
|
||
|
[SerializeField] private int _dataLabelsNumDecimals;
|
||
|
[SerializeField] private int _dataLabelsFontSize;
|
||
|
[SerializeField] private Color _dataLabelsColor = Color.white;
|
||
|
[SerializeField] private FontStyle _dataLabelsFontStyle = FontStyle.Normal;
|
||
|
[SerializeField] private Font _dataLabelsFont;
|
||
|
[SerializeField] private Vector2 _dataLabelsOffset;
|
||
|
[SerializeField] private areaShadingTypes _areaShadingType;
|
||
|
[SerializeField] private bool _areaShadingUsesComputeShader;
|
||
|
[SerializeField] private Color _areaShadingColor;
|
||
|
[SerializeField] private float _areaShadingAxisValue;
|
||
|
[SerializeField] private int _pointPrefab;
|
||
|
[SerializeField] private int _linkPrefab;
|
||
|
|
||
|
// Useful property getters
|
||
|
public bool seriesIsLine {
|
||
|
get {
|
||
|
return (theGraph.graphType == WMG_Axis_Graph.graphTypes.line ||
|
||
|
theGraph.graphType == WMG_Axis_Graph.graphTypes.line_stacked ||
|
||
|
(theGraph.graphType == WMG_Axis_Graph.graphTypes.combo && comboType == comboTypes.line));
|
||
|
}
|
||
|
}
|
||
|
public bool IsLast {
|
||
|
get {
|
||
|
return theGraph.lineSeries[theGraph.lineSeries.Count-1].GetComponent<WMG_Series>() == this;
|
||
|
}
|
||
|
}
|
||
|
public WMG_Axis yAxis {
|
||
|
get {
|
||
|
if (theGraph.axesType == WMG_Axis_Graph.axesTypes.DUAL_Y && useSecondYaxis && theGraph.yAxis2 != null) {
|
||
|
return theGraph.yAxis2;
|
||
|
}
|
||
|
else {
|
||
|
return theGraph.yAxis;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Private vars
|
||
|
private UnityEngine.Object nodePrefab;
|
||
|
private List<GameObject> points = new List<GameObject>();
|
||
|
private List<GameObject> lines = new List<GameObject>();
|
||
|
private List<GameObject> areaShadingRects = new List<GameObject>();
|
||
|
private List<GameObject> dataLabels = new List<GameObject>();
|
||
|
private List<bool> barIsNegative = new List<bool>();
|
||
|
private List<int> changedValIndices = new List<int>();
|
||
|
|
||
|
// Original property values for use with dynamic resizing
|
||
|
public float origPointWidthHeight { get; private set; }
|
||
|
public float origLineScale { get; private set; }
|
||
|
public int origDataLabelsFontSize { get; private set; }
|
||
|
public Vector2 origDataLabelOffset { get; set; }
|
||
|
|
||
|
// Cache
|
||
|
private WMG_Axis_Graph.graphTypes cachedSeriesType;
|
||
|
|
||
|
// Real time update
|
||
|
private bool realTimeRunning;
|
||
|
private float realTimeLoopVar;
|
||
|
private float realTimeOrigMax;
|
||
|
|
||
|
// Automatic Animation variables and functions
|
||
|
private bool animatingFromPreviousData;
|
||
|
public bool currentlyAnimating { get; set; }
|
||
|
private List<Vector2> afterPositions = new List<Vector2>();
|
||
|
private List<int> afterWidths = new List<int>();
|
||
|
private List<int> afterHeights = new List<int>();
|
||
|
//private List<Vector2> previousPointValues = new List<Vector2>();
|
||
|
|
||
|
private List<WMG_Change_Obj> changeObjs = new List<WMG_Change_Obj>();
|
||
|
public WMG_Change_Obj pointValuesC = new WMG_Change_Obj();
|
||
|
public WMG_Change_Obj pointValuesCountC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj pointValuesValC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj lineScaleC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj pointWidthHeightC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj dataLabelsC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj lineColorC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj pointColorC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj hideLineC = new WMG_Change_Obj ();
|
||
|
private WMG_Change_Obj hidePointC = new WMG_Change_Obj ();
|
||
|
private WMG_Change_Obj seriesNameC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj linePaddingC = new WMG_Change_Obj();
|
||
|
private WMG_Change_Obj areaShadingTypeC = new WMG_Change_Obj ();
|
||
|
private WMG_Change_Obj areaShadingC = new WMG_Change_Obj ();
|
||
|
public WMG_Change_Obj prefabC = new WMG_Change_Obj ();
|
||
|
private WMG_Change_Obj connectFirstToLastC = new WMG_Change_Obj ();
|
||
|
|
||
|
private bool hasInit;
|
||
|
|
||
|
public delegate string SeriesDataLabeler(WMG_Series series, float val);
|
||
|
public SeriesDataLabeler seriesDataLabeler;
|
||
|
|
||
|
public string formatSeriesDataLabel(WMG_Series series, float val) {
|
||
|
float numberToMult = Mathf.Pow(10f, series.dataLabelsNumDecimals);
|
||
|
return (Mathf.Round(val * numberToMult) / numberToMult).ToString();
|
||
|
}
|
||
|
|
||
|
public delegate void SeriesDataChangedHandler(WMG_Series aSeries);
|
||
|
public event SeriesDataChangedHandler SeriesDataChanged;
|
||
|
|
||
|
protected virtual void OnSeriesDataChanged() {
|
||
|
SeriesDataChangedHandler handler = SeriesDataChanged;
|
||
|
if (handler != null) {
|
||
|
handler(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Init(int index) {
|
||
|
if (hasInit) return;
|
||
|
hasInit = true;
|
||
|
|
||
|
changeObjs.Add (pointValuesCountC);
|
||
|
changeObjs.Add (pointValuesC);
|
||
|
changeObjs.Add (pointValuesValC);
|
||
|
changeObjs.Add (connectFirstToLastC);
|
||
|
changeObjs.Add (lineScaleC);
|
||
|
changeObjs.Add (pointWidthHeightC);
|
||
|
changeObjs.Add (dataLabelsC);
|
||
|
changeObjs.Add (lineColorC);
|
||
|
changeObjs.Add (pointColorC);
|
||
|
changeObjs.Add (hideLineC);
|
||
|
changeObjs.Add (hidePointC);
|
||
|
changeObjs.Add (seriesNameC);
|
||
|
changeObjs.Add (linePaddingC);
|
||
|
changeObjs.Add (areaShadingTypeC);
|
||
|
changeObjs.Add (areaShadingC);
|
||
|
changeObjs.Add (prefabC);
|
||
|
|
||
|
if (seriesIsLine) {
|
||
|
nodePrefab = theGraph.pointPrefabs[pointPrefab];
|
||
|
}
|
||
|
else {
|
||
|
nodePrefab = theGraph.barPrefab;
|
||
|
}
|
||
|
|
||
|
legendEntry = theGraph.legend.createLegendEntry(legendEntryPrefab, this, index);
|
||
|
createLegendSwatch();
|
||
|
theGraph.legend.updateLegend();
|
||
|
|
||
|
pointValues.SetList (_pointValues);
|
||
|
pointValues.Changed += pointValuesListChanged;
|
||
|
|
||
|
pointColors.SetList (_pointColors);
|
||
|
pointColors.Changed += pointColorsListChanged;
|
||
|
|
||
|
pointValuesCountC.OnChange += PointValuesCountChanged;
|
||
|
pointValuesC.OnChange += PointValuesChanged;
|
||
|
pointValuesValC.OnChange += PointValuesValChanged;
|
||
|
lineScaleC.OnChange += LineScaleChanged;
|
||
|
pointWidthHeightC.OnChange += PointWidthHeightChanged;
|
||
|
dataLabelsC.OnChange += DataLabelsChanged;
|
||
|
lineColorC.OnChange += LineColorChanged;
|
||
|
pointColorC.OnChange += PointColorChanged;
|
||
|
hideLineC.OnChange += HideLinesChanged;
|
||
|
hidePointC.OnChange += HidePointsChanged;
|
||
|
seriesNameC.OnChange += SeriesNameChanged;
|
||
|
linePaddingC.OnChange += LinePaddingChanged;
|
||
|
areaShadingTypeC.OnChange += AreaShadingTypeChanged;
|
||
|
areaShadingC.OnChange += AreaShadingChanged;
|
||
|
prefabC.OnChange += PrefabChanged;
|
||
|
connectFirstToLastC.OnChange += ConnectFirstToLastChanged;
|
||
|
|
||
|
seriesDataLabeler = formatSeriesDataLabel;
|
||
|
|
||
|
setOriginalPropertyValues();
|
||
|
}
|
||
|
|
||
|
public void PauseCallbacks() {
|
||
|
for (int i = 0; i < changeObjs.Count; i++) {
|
||
|
changeObjs[i].changesPaused = true;
|
||
|
changeObjs[i].changePaused = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void ResumeCallbacks() {
|
||
|
for (int i = 0; i < changeObjs.Count; i++) {
|
||
|
changeObjs[i].changesPaused = false;
|
||
|
if (changeObjs[i].changePaused) changeObjs[i].Changed();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void pointColorsListChanged(bool editorChange, bool countChanged, bool oneValChanged, int index) {
|
||
|
WMG_Util.listChanged (editorChange, ref pointColors, ref _pointColors, oneValChanged, index);
|
||
|
pointColorC.Changed();
|
||
|
}
|
||
|
|
||
|
public void pointValuesListChanged(bool editorChange, bool countChanged, bool oneValChanged, int index) {
|
||
|
WMG_Util.listChanged (editorChange, ref pointValues, ref _pointValues, oneValChanged, index);
|
||
|
if (countChanged) {
|
||
|
pointValuesCountC.Changed();
|
||
|
}
|
||
|
else {
|
||
|
setAnimatingFromPreviousData();
|
||
|
if (oneValChanged) {
|
||
|
changedValIndices.Add(index);
|
||
|
pointValuesValC.Changed();
|
||
|
}
|
||
|
else {
|
||
|
pointValuesC.Changed ();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void PrefabChanged() {
|
||
|
UpdatePrefabType();
|
||
|
pointValuesCountC.Changed ();
|
||
|
}
|
||
|
|
||
|
public void pointValuesChanged() {
|
||
|
theGraph.aSeriesPointsChanged ();
|
||
|
UpdateNullVisibility();
|
||
|
UpdateSprites();
|
||
|
}
|
||
|
|
||
|
public void pointValuesCountChanged() {
|
||
|
theGraph.aSeriesPointsChanged ();
|
||
|
CreateOrDeleteSpritesBasedOnPointValues();
|
||
|
UpdateLineColor();
|
||
|
UpdatePointColor();
|
||
|
UpdateLineScale();
|
||
|
UpdatePointWidthHeight();
|
||
|
UpdateHideLines();
|
||
|
UpdateHidePoints();
|
||
|
UpdateNullVisibility();
|
||
|
UpdateLinePadding();
|
||
|
UpdateSprites();
|
||
|
}
|
||
|
|
||
|
public void pointValuesValChanged(int index) {
|
||
|
theGraph.aSeriesPointsChanged ();
|
||
|
UpdateNullVisibility();
|
||
|
UpdateSprites();
|
||
|
}
|
||
|
|
||
|
public void PointValuesChanged() {
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.bar_stacked_percent || (theGraph.IsStacked && !IsLast)) {
|
||
|
theGraph.aSeriesPointsChanged ();
|
||
|
theGraph.SeriesChanged(false, true);
|
||
|
}
|
||
|
else {
|
||
|
pointValuesChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void PointValuesCountChanged() {
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.bar_stacked_percent || (theGraph.IsStacked && !IsLast)) {
|
||
|
theGraph.aSeriesPointsChanged ();
|
||
|
theGraph.SeriesChanged(true, true);
|
||
|
}
|
||
|
else {
|
||
|
pointValuesCountChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void PointValuesValChanged() {
|
||
|
if (changedValIndices.Count != 1) { // multiple single vals changed in a single frame
|
||
|
PointValuesChanged();
|
||
|
}
|
||
|
else {
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.bar_stacked_percent || (theGraph.IsStacked && !IsLast)) {
|
||
|
theGraph.aSeriesPointsChanged ();
|
||
|
theGraph.SeriesChanged(false, true);
|
||
|
}
|
||
|
else {
|
||
|
pointValuesValChanged(changedValIndices[0]);
|
||
|
}
|
||
|
changedValIndices.Clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void LineColorChanged() {
|
||
|
UpdateLineColor();
|
||
|
}
|
||
|
|
||
|
public void ConnectFirstToLastChanged() {
|
||
|
createOrDeletePoints(pointValues.Count);
|
||
|
}
|
||
|
|
||
|
public void PointColorChanged() {
|
||
|
UpdatePointColor();
|
||
|
}
|
||
|
|
||
|
public void LineScaleChanged() {
|
||
|
UpdateLineScale();
|
||
|
}
|
||
|
|
||
|
public void PointWidthHeightChanged() {
|
||
|
UpdatePointWidthHeight();
|
||
|
}
|
||
|
|
||
|
public void HideLinesChanged() {
|
||
|
UpdateHideLines();
|
||
|
UpdateNullVisibility();
|
||
|
}
|
||
|
|
||
|
public void HidePointsChanged() {
|
||
|
UpdateHidePoints();
|
||
|
UpdateNullVisibility();
|
||
|
}
|
||
|
|
||
|
public void SeriesNameChanged() {
|
||
|
UpdateSeriesName();
|
||
|
}
|
||
|
|
||
|
public void LinePaddingChanged() {
|
||
|
UpdateLinePadding();
|
||
|
}
|
||
|
|
||
|
public void AreaShadingTypeChanged() {
|
||
|
createOrDeleteAreaShading(pointValues.Count);
|
||
|
}
|
||
|
|
||
|
public void AreaShadingChanged() {
|
||
|
if (areaShadingUsesComputeShader) {
|
||
|
UpdateSprites();
|
||
|
}
|
||
|
else {
|
||
|
updateAreaShading(null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void DataLabelsChanged() {
|
||
|
createOrDeleteLabels(pointValues.Count);
|
||
|
updateDataLabels();
|
||
|
}
|
||
|
|
||
|
public void UpdateFromDataSource() {
|
||
|
if (pointValuesDataSource != null) {
|
||
|
List<Vector2> dataSourceData = pointValuesDataSource.getData<Vector2>();
|
||
|
if (theGraph.useGroups) {
|
||
|
dataSourceData = sanitizeGroupData(dataSourceData);
|
||
|
}
|
||
|
pointValues.SetList(dataSourceData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void RealTimeUpdate() {
|
||
|
if (realTimeRunning) {
|
||
|
DoRealTimeUpdate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public List<Vector2> AfterPositions() {
|
||
|
return afterPositions;
|
||
|
}
|
||
|
|
||
|
public List<int> AfterHeights() {
|
||
|
return afterHeights;
|
||
|
}
|
||
|
|
||
|
public List<int> AfterWidths() {
|
||
|
return afterWidths;
|
||
|
}
|
||
|
|
||
|
public bool AnimatingFromPreviousData() {
|
||
|
return animatingFromPreviousData;
|
||
|
}
|
||
|
|
||
|
public void setAnimatingFromPreviousData() {
|
||
|
// Automatic animations doesn't work for real time updating or stacked graphs
|
||
|
if (realTimeRunning) return;
|
||
|
if (theGraph.IsStacked) return;
|
||
|
if (theGraph.autoAnimationsEnabled) {
|
||
|
animatingFromPreviousData = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set initial property values for use with percentage based dynamic resizing
|
||
|
public void setOriginalPropertyValues() {
|
||
|
origPointWidthHeight = pointWidthHeight;
|
||
|
origLineScale = lineScale;
|
||
|
origDataLabelsFontSize = dataLabelsFontSize;
|
||
|
origDataLabelOffset = dataLabelsOffset;
|
||
|
}
|
||
|
|
||
|
public List<GameObject> getPoints() {
|
||
|
return points;
|
||
|
}
|
||
|
|
||
|
public GameObject getLastPoint() {
|
||
|
return points[points.Count-1];
|
||
|
}
|
||
|
|
||
|
public GameObject getFirstPoint() {
|
||
|
return points[0];
|
||
|
}
|
||
|
|
||
|
public List<GameObject> getLines() {
|
||
|
return lines;
|
||
|
}
|
||
|
|
||
|
public List<GameObject> getDataLabels() {
|
||
|
return dataLabels;
|
||
|
}
|
||
|
|
||
|
public bool getBarIsNegative(int i) {
|
||
|
return barIsNegative[i];
|
||
|
}
|
||
|
|
||
|
// Get Vector2 associated with a node in this series
|
||
|
public Vector2 getNodeValue(WMG_Node aNode) {
|
||
|
for (int i = 0; i < pointValues.Count; i++) {
|
||
|
if (points[i].GetComponent<WMG_Node>() == aNode) return pointValues[i];
|
||
|
}
|
||
|
return Vector2.zero;
|
||
|
}
|
||
|
|
||
|
public void UpdateHidePoints() {
|
||
|
// Series points
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
theGraph.SetActive(points[i],!hidePoints);
|
||
|
}
|
||
|
// Legend point
|
||
|
theGraph.SetActive(legendEntry.swatchNode, !hidePoints);
|
||
|
if (!areaShadingUsesComputeShader) StartCoroutine(SetDelayedAreaShadingChanged ());
|
||
|
}
|
||
|
|
||
|
public void UpdateNullVisibility() {
|
||
|
// For null groups hide the appropriate points
|
||
|
if (theGraph.useGroups) {
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
theGraph.SetActive(points[i], pointValues[i].x > 0);
|
||
|
}
|
||
|
// For null groups hide the appropriate lines
|
||
|
if (seriesIsLine) {
|
||
|
for (int i = 0; i < lines.Count; i++) {
|
||
|
theGraph.SetActive(lines[i],true);
|
||
|
}
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
if (pointValues[i].x < 0) {
|
||
|
WMG_Node thePoint = points[i].GetComponent<WMG_Node>();
|
||
|
for (int j = 0; j < thePoint.links.Count; j++) {
|
||
|
theGraph.SetActive(thePoint.links[j], false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!areaShadingUsesComputeShader) StartCoroutine(SetDelayedAreaShadingChanged ());
|
||
|
}
|
||
|
if (hidePoints) {
|
||
|
// Series points
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
theGraph.SetActive(points[i],false);
|
||
|
}
|
||
|
}
|
||
|
if (hideLines || !seriesIsLine) {
|
||
|
// Series lines
|
||
|
for (int i = 0; i < lines.Count; i++) {
|
||
|
theGraph.SetActive (lines [i], false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void UpdateHideLines() {
|
||
|
// Series lines
|
||
|
for (int i = 0; i < lines.Count; i++) {
|
||
|
if (hideLines || !seriesIsLine) theGraph.SetActive(lines[i],false);
|
||
|
else theGraph.SetActive(lines[i],true);
|
||
|
}
|
||
|
// Legend lines
|
||
|
if (hideLines || !seriesIsLine) {
|
||
|
theGraph.SetActive(legendEntry.line, false);
|
||
|
}
|
||
|
else {
|
||
|
theGraph.SetActive(legendEntry.line, true);
|
||
|
}
|
||
|
if (!areaShadingUsesComputeShader) StartCoroutine(SetDelayedAreaShadingChanged ());
|
||
|
}
|
||
|
|
||
|
public void UpdateLineColor() {
|
||
|
// Series line colors
|
||
|
for (int i = 0; i < lines.Count; i++) {
|
||
|
WMG_Link theLine = lines[i].GetComponent<WMG_Link>();
|
||
|
theGraph.changeSpriteColor(theLine.objectToColor, lineColor);
|
||
|
}
|
||
|
// Legend line colors
|
||
|
WMG_Link legendLine = legendEntry.line.GetComponent<WMG_Link>();
|
||
|
theGraph.changeSpriteColor(legendLine.objectToColor, lineColor);
|
||
|
}
|
||
|
|
||
|
public void UpdatePointColor() {
|
||
|
// Series point colors
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
WMG_Node thePoint = points[i].GetComponent<WMG_Node>();
|
||
|
if (usePointColors) {
|
||
|
if (i < pointColors.Count) {
|
||
|
theGraph.changeSpriteColor(thePoint.objectToColor, pointColors[i]);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
theGraph.changeSpriteColor(thePoint.objectToColor, pointColor);
|
||
|
}
|
||
|
}
|
||
|
// Legend point color
|
||
|
WMG_Node legendPoint = legendEntry.swatchNode.GetComponent<WMG_Node>();
|
||
|
theGraph.changeSpriteColor(legendPoint.objectToColor, pointColor);
|
||
|
}
|
||
|
|
||
|
public void UpdateLineScale() {
|
||
|
// Series line widths
|
||
|
for (int i = 0; i < lines.Count; i++) {
|
||
|
WMG_Link theLine = lines[i].GetComponent<WMG_Link>();
|
||
|
theLine.objectToScale.transform.localScale = new Vector3(lineScale, theLine.objectToScale.transform.localScale.y, theLine.objectToScale.transform.localScale.z);
|
||
|
}
|
||
|
// Legend line widths
|
||
|
WMG_Link legendLine = legendEntry.line.GetComponent<WMG_Link>();
|
||
|
legendLine.objectToScale.transform.localScale = new Vector3(lineScale, legendLine.objectToScale.transform.localScale.y, legendLine.objectToScale.transform.localScale.z);
|
||
|
}
|
||
|
|
||
|
public void UpdatePointWidthHeight() {
|
||
|
// Series line point dimensions
|
||
|
if (seriesIsLine) {
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
WMG_Node thePoint = points[i].GetComponent<WMG_Node>();
|
||
|
theGraph.changeSpriteHeight(thePoint.objectToColor, Mathf.RoundToInt(pointWidthHeight));
|
||
|
theGraph.changeSpriteWidth(thePoint.objectToColor, Mathf.RoundToInt(pointWidthHeight));
|
||
|
}
|
||
|
}
|
||
|
// Legend point / bar dimensions
|
||
|
WMG_Node legendPoint = legendEntry.swatchNode.GetComponent<WMG_Node>();
|
||
|
theGraph.changeSpriteHeight(legendPoint.objectToColor, Mathf.RoundToInt(pointWidthHeight));
|
||
|
theGraph.changeSpriteWidth(legendPoint.objectToColor, Mathf.RoundToInt(pointWidthHeight));
|
||
|
}
|
||
|
|
||
|
public void UpdatePrefabType() {
|
||
|
// Update prefab variable used later in the creating sprites function
|
||
|
if (seriesIsLine) {
|
||
|
nodePrefab = theGraph.pointPrefabs[pointPrefab];
|
||
|
}
|
||
|
else {
|
||
|
nodePrefab = theGraph.barPrefab;
|
||
|
}
|
||
|
|
||
|
// Delete points and lines
|
||
|
for (int i = points.Count - 1; i >= 0; i--) {
|
||
|
if (points[i] != null) {
|
||
|
WMG_Node thePoint = points[i].GetComponent<WMG_Node>();
|
||
|
foreach (GameObject child in thePoint.links) {
|
||
|
lines.Remove(child);
|
||
|
}
|
||
|
theGraph.DeleteNode(thePoint);
|
||
|
points.RemoveAt(i);
|
||
|
}
|
||
|
}
|
||
|
// Delete legend
|
||
|
if (legendEntry.swatchNode != null) {
|
||
|
theGraph.DeleteNode(legendEntry.swatchNode.GetComponent<WMG_Node>());
|
||
|
theGraph.DeleteLink(legendEntry.line.GetComponent<WMG_Link>());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void UpdateSeriesName() {
|
||
|
theGraph.legend.LegendChanged();
|
||
|
}
|
||
|
|
||
|
public void UpdateLinePadding() {
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
points[i].GetComponent<WMG_Node>().radius = -1 * linePadding;
|
||
|
}
|
||
|
RepositionLines();
|
||
|
}
|
||
|
|
||
|
public void RepositionLines() {
|
||
|
for (int i = 0; i < lines.Count; i++) {
|
||
|
lines[i].GetComponent<WMG_Link>().Reposition();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void CreateOrDeleteSpritesBasedOnPointValues() {
|
||
|
if (theGraph.useGroups) {
|
||
|
pointValues.SetListNoCb(sanitizeGroupData(pointValues.list), ref _pointValues);
|
||
|
}
|
||
|
|
||
|
int pointValuesCount = pointValues.Count;
|
||
|
|
||
|
createOrDeletePoints(pointValuesCount);
|
||
|
createOrDeleteLabels(pointValuesCount);
|
||
|
createOrDeleteAreaShading(pointValuesCount);
|
||
|
}
|
||
|
|
||
|
List<Vector2> sanitizeGroupData(List<Vector2> groupData) {
|
||
|
// Groups are defined at the graph level in the groups variable.
|
||
|
// If, for example, there are 5 groups defined, then the data in the series must comprise of 5 Vector2's
|
||
|
// The x value in each Vector2 represents the group, and a negative x value represents a null group.
|
||
|
// Null groups will not be graphed at all (for example line graph with broken line segments)
|
||
|
// This function will automatically group together data and insert nulls as needed.
|
||
|
// For example, for 3 groups, if you supply input of (2,3) (2,5), this will convert it to (-1,0) (2,8) (-3,0)
|
||
|
|
||
|
// remove values that can't possibly represent groups
|
||
|
for (int i = groupData.Count - 1; i >= 0; i--) {
|
||
|
int intVal = Mathf.RoundToInt(groupData[i].x);
|
||
|
if (intVal - groupData[i].x != 0) {
|
||
|
groupData.RemoveAt(i); // Not an integer
|
||
|
continue;
|
||
|
}
|
||
|
if (Mathf.Abs(intVal) > theGraph.groups.Count) {
|
||
|
groupData.RemoveAt(i); // Out of bounds
|
||
|
continue;
|
||
|
}
|
||
|
if (intVal == 0) {
|
||
|
groupData.RemoveAt(i); // 0, because nulls are represented by negatives and there is no negative 0
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
// sort values, combine duplicates
|
||
|
groupData.Sort( (vec1,vec2)=>vec1.x.CompareTo(vec2.x));
|
||
|
List<Vector2> newPoints = new List<Vector2>();
|
||
|
bool newPoint = true;
|
||
|
for (int i = 0; i < groupData.Count; i++) {
|
||
|
if (newPoint) {
|
||
|
newPoints.Add(groupData[i]);
|
||
|
newPoint = false;
|
||
|
}
|
||
|
else {
|
||
|
Vector2 prev = newPoints[newPoints.Count-1];
|
||
|
newPoints[newPoints.Count-1] = new Vector2(prev.x, prev.y + groupData[i].y);
|
||
|
}
|
||
|
|
||
|
if (i < groupData.Count-1) {
|
||
|
if (groupData[i].x != groupData[i+1].x) {
|
||
|
newPoint = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// insert nulls
|
||
|
if (newPoints.Count < theGraph.groups.Count) {
|
||
|
int numNullsToAdd = theGraph.groups.Count - newPoints.Count;
|
||
|
for (int i = 0; i < numNullsToAdd; i++) {
|
||
|
newPoints.Insert(0, new Vector2(-1, 0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// this is rare, but there could be extras nulls (negatives), remove them until the counts are equal
|
||
|
if (newPoints.Count > theGraph.groups.Count) {
|
||
|
int numNullsToRemove = newPoints.Count - theGraph.groups.Count;
|
||
|
for (int i = 0; i < numNullsToRemove; i++) {
|
||
|
newPoints.RemoveAt(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// at this point, we should have for example, if 5 groups, -1, -1, 1, 2, 5
|
||
|
// now to easily determine which groups are null, need something like 1, 2, -3, -4, 5
|
||
|
List<int> nullGroups = new List<int>();
|
||
|
for (int i = 0; i < theGraph.groups.Count; i++) {
|
||
|
nullGroups.Add(i+1);
|
||
|
}
|
||
|
for (int i = newPoints.Count - 1; i >= 0; i--) {
|
||
|
if (newPoints[i].x > 0) nullGroups.Remove(Mathf.RoundToInt(newPoints[i].x));
|
||
|
}
|
||
|
for (int i = 0; i < nullGroups.Count; i++) {
|
||
|
newPoints[i] = new Vector2(-1*nullGroups[i], 0);
|
||
|
}
|
||
|
|
||
|
// sort values, so that negatives treated same as positives
|
||
|
newPoints.Sort( (vec1,vec2)=>Mathf.Abs(vec1.x).CompareTo(Mathf.Abs(vec2.x)));
|
||
|
|
||
|
return newPoints;
|
||
|
}
|
||
|
|
||
|
void createOrDeletePoints(int pointValuesCount) {
|
||
|
// Create points based on pointValues data
|
||
|
for (int i = 0; i < pointValuesCount; i++) {
|
||
|
if (points.Count <= i) {
|
||
|
GameObject curObj = theGraph.CreateNode(nodePrefab, nodeParent);
|
||
|
|
||
|
theGraph.addNodeClickEvent(curObj);
|
||
|
theGraph.addNodeMouseEnterEvent(curObj);
|
||
|
theGraph.addNodeMouseLeaveEvent(curObj);
|
||
|
|
||
|
curObj.GetComponent<WMG_Node>().radius = -1 * linePadding;
|
||
|
theGraph.SetActive(curObj,false);
|
||
|
points.Add(curObj);
|
||
|
barIsNegative.Add(false);
|
||
|
if (i > 0) {
|
||
|
WMG_Node fromNode = points[i-1].GetComponent<WMG_Node>();
|
||
|
curObj = theGraph.CreateLink(fromNode, curObj, theGraph.linkPrefabs[linkPrefab], linkParent);
|
||
|
|
||
|
theGraph.addLinkClickEvent(curObj);
|
||
|
theGraph.addLinkMouseEnterEvent(curObj);
|
||
|
theGraph.addLinkMouseLeaveEvent(curObj);
|
||
|
|
||
|
theGraph.SetActive(curObj,false);
|
||
|
lines.Add(curObj);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// If there are more points than pointValues data, delete the extras
|
||
|
for (int i = points.Count - 1; i >= 0; i--) {
|
||
|
if (points[i] != null && i >= pointValuesCount) {
|
||
|
WMG_Node thePoint = points[i].GetComponent<WMG_Node>();
|
||
|
foreach (GameObject child in thePoint.links) {
|
||
|
lines.Remove(child);
|
||
|
}
|
||
|
theGraph.DeleteNode(thePoint);
|
||
|
points.RemoveAt(i);
|
||
|
barIsNegative.RemoveAt(i);
|
||
|
}
|
||
|
// Delete existing connect first to last
|
||
|
if (i > 1 && i < pointValuesCount-1) {
|
||
|
WMG_Node firstNode = points[0].GetComponent<WMG_Node>();
|
||
|
WMG_Node toNode = points[i].GetComponent<WMG_Node>();
|
||
|
WMG_Link delLink = theGraph.GetLink(firstNode,toNode);
|
||
|
if (delLink != null) {
|
||
|
lines.Remove(delLink.gameObject);
|
||
|
theGraph.DeleteLink(delLink);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Connect first to last
|
||
|
if (points.Count > 2) {
|
||
|
WMG_Node firstNode = points[0].GetComponent<WMG_Node>();
|
||
|
WMG_Node toNode = points[points.Count-1].GetComponent<WMG_Node>();
|
||
|
WMG_Link delLink = theGraph.GetLink(firstNode,toNode);
|
||
|
if (connectFirstToLast && delLink == null) {
|
||
|
GameObject curObj = theGraph.CreateLink(firstNode, toNode.gameObject, theGraph.linkPrefabs[linkPrefab], linkParent);
|
||
|
|
||
|
theGraph.addLinkClickEvent(curObj);
|
||
|
theGraph.addLinkMouseEnterEvent(curObj);
|
||
|
theGraph.addLinkMouseLeaveEvent(curObj);
|
||
|
|
||
|
theGraph.SetActive(curObj,false);
|
||
|
lines.Add(curObj);
|
||
|
}
|
||
|
if (!connectFirstToLast && delLink != null) {
|
||
|
lines.Remove(delLink.gameObject);
|
||
|
theGraph.DeleteLink(delLink);
|
||
|
}
|
||
|
}
|
||
|
// Create the legend if it doesn't exist (changing prefab type deletes the legend swatch and lines)
|
||
|
if (legendEntry.swatchNode == null) {
|
||
|
createLegendSwatch();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void createLegendSwatch() {
|
||
|
legendEntry.swatchNode = theGraph.CreateNode(nodePrefab, legendEntry.gameObject);
|
||
|
|
||
|
theGraph.addNodeClickEvent_Leg(legendEntry.swatchNode);
|
||
|
theGraph.addNodeMouseEnterEvent_Leg(legendEntry.swatchNode);
|
||
|
theGraph.addNodeMouseLeaveEvent_Leg(legendEntry.swatchNode);
|
||
|
|
||
|
WMG_Node cNode = legendEntry.swatchNode.GetComponent<WMG_Node>();
|
||
|
theGraph.changeSpritePivot(cNode.objectToColor, WMG_Graph_Manager.WMGpivotTypes.Center);
|
||
|
cNode.Reposition(0,0);
|
||
|
|
||
|
legendEntry.line = theGraph.CreateLink(legendEntry.nodeRight.GetComponent<WMG_Node>(), legendEntry.nodeLeft, theGraph.linkPrefabs[linkPrefab], legendEntry.gameObject);
|
||
|
|
||
|
theGraph.addLinkClickEvent_Leg(legendEntry.line);
|
||
|
theGraph.addLinkMouseEnterEvent_Leg(legendEntry.line);
|
||
|
theGraph.addLinkMouseLeaveEvent_Leg(legendEntry.line);
|
||
|
|
||
|
theGraph.bringSpriteToFront(legendEntry.swatchNode);
|
||
|
}
|
||
|
|
||
|
void createOrDeleteLabels(int pointValuesCount) {
|
||
|
// Create / delete data labels
|
||
|
if (dataLabelPrefab != null && dataLabelsParent != null) {
|
||
|
if (dataLabelsEnabled) {
|
||
|
for (int i = 0; i < pointValuesCount; i++) {
|
||
|
if (dataLabels.Count <= i) {
|
||
|
GameObject curObj = Instantiate(dataLabelPrefab) as GameObject;
|
||
|
theGraph.changeSpriteParent(curObj, dataLabelsParent);
|
||
|
curObj.transform.localScale = Vector3.one;
|
||
|
dataLabels.Add(curObj);
|
||
|
curObj.name = "Data_Label_" + dataLabels.Count;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int numLabels = pointValuesCount;
|
||
|
if (!dataLabelsEnabled) {
|
||
|
numLabels = 0;
|
||
|
}
|
||
|
else {
|
||
|
// Data labels doesn't work for stacked bar or stacked percentage bar
|
||
|
if (theGraph.IsStacked && theGraph.graphType != WMG_Axis_Graph.graphTypes.line_stacked) {
|
||
|
numLabels = 0;
|
||
|
dataLabelsEnabled = false;
|
||
|
}
|
||
|
}
|
||
|
// If there are more data labels than pointValues data, delete the extras
|
||
|
for (int i = dataLabels.Count - 1; i >= 0; i--) {
|
||
|
if (dataLabels[i] != null && i >= numLabels) {
|
||
|
DestroyImmediate(dataLabels[i]);
|
||
|
dataLabels.RemoveAt(i);
|
||
|
}
|
||
|
}
|
||
|
if (!areaShadingUsesComputeShader) StartCoroutine(SetDelayedAreaShadingChanged ()); // For some reason creating / deleting objects hides area shading
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void createOrDeleteAreaShading(int pointValuesCount) {
|
||
|
if (areaShadingUsesComputeShader) {
|
||
|
if (areaShadingCSPrefab == null || areaShadingParent == null) return;
|
||
|
|
||
|
if (areaShadingType != areaShadingTypes.None && areaShadingRects.Count == 1 && areaShadingRects[0].name == "Area_Shading_CS") {
|
||
|
UpdateSprites(); // changed from gradient to fill or vice versa
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (int i = areaShadingRects.Count - 1; i >= 0; i--) {
|
||
|
if (areaShadingRects[i] != null && i >= 0) {
|
||
|
DestroyImmediate(areaShadingRects[i]);
|
||
|
areaShadingRects.RemoveAt(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (areaShadingType != areaShadingTypes.None) {
|
||
|
if (areaShadingRects.Count != 1) {
|
||
|
GameObject curObj = Instantiate(areaShadingCSPrefab) as GameObject;
|
||
|
theGraph.changeSpriteParent(curObj, areaShadingParent);
|
||
|
theGraph.changeSpriteSizeFloat(curObj, theGraph.xAxisLength, theGraph.yAxisLength);
|
||
|
theGraph.changeSpritePivot(curObj, WMG_GUI_Functions.WMGpivotTypes.BottomLeft);
|
||
|
theGraph.changeSpritePositionTo(curObj, new Vector3(0, 0, 0));
|
||
|
curObj.transform.localScale = Vector3.one;
|
||
|
areaShadingRects.Add(curObj);
|
||
|
curObj.name = "Area_Shading_CS";
|
||
|
WMG_Compute_Shader areaShadingCS = curObj.GetComponent<WMG_Compute_Shader>();
|
||
|
areaShadingCS.Init();
|
||
|
UpdateSprites();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
if (areaShadingPrefab == null || areaShadingParent == null) return;
|
||
|
|
||
|
if (areaShadingRects.Count == 1 && areaShadingRects[0].name == "Area_Shading_CS") {
|
||
|
DestroyImmediate(areaShadingRects[0]);
|
||
|
areaShadingRects.RemoveAt(0);
|
||
|
}
|
||
|
|
||
|
// Create area shading rectangles based on pointValues data
|
||
|
if (areaShadingType != areaShadingTypes.None) {
|
||
|
for (int i = 0; i < pointValuesCount-1; i++) {
|
||
|
if (areaShadingRects.Count <= i) {
|
||
|
GameObject curObj = Instantiate(areaShadingPrefab) as GameObject;
|
||
|
theGraph.changeSpriteParent(curObj, areaShadingParent);
|
||
|
curObj.transform.localScale = Vector3.one;
|
||
|
areaShadingRects.Add(curObj);
|
||
|
curObj.name = "Area_Shading_" + areaShadingRects.Count;
|
||
|
StartCoroutine(SetDelayedAreaShadingChanged ());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
int numRects = pointValuesCount-1;
|
||
|
if (areaShadingType == areaShadingTypes.None) {
|
||
|
numRects = 0;
|
||
|
}
|
||
|
// If there are more shading rectangles than pointValues data, delete the extras
|
||
|
for (int i = areaShadingRects.Count - 1; i >= 0; i--) {
|
||
|
if (areaShadingRects[i] != null && i >= numRects) {
|
||
|
DestroyImmediate(areaShadingRects[i]);
|
||
|
areaShadingRects.RemoveAt(i);
|
||
|
StartCoroutine(SetDelayedAreaShadingChanged ());
|
||
|
}
|
||
|
}
|
||
|
Material matToUse = areaShadingMatSolid;
|
||
|
if (areaShadingType == areaShadingTypes.Gradient) {
|
||
|
matToUse = areaShadingMatGradient;
|
||
|
}
|
||
|
for (int i = 0; i < areaShadingRects.Count; i++) {
|
||
|
theGraph.setTextureMaterial(areaShadingRects[i], matToUse);
|
||
|
StartCoroutine(SetDelayedAreaShadingChanged ());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IEnumerator SetDelayedAreaShadingChanged() {
|
||
|
yield return new WaitForEndOfFrame();
|
||
|
AreaShadingChanged();
|
||
|
yield return new WaitForEndOfFrame();
|
||
|
AreaShadingChanged();
|
||
|
}
|
||
|
|
||
|
public void UpdateSprites() {
|
||
|
List<GameObject> prevPoints = null;
|
||
|
if (theGraph.IsStacked) {
|
||
|
for (int j = 1; j < theGraph.lineSeries.Count; j++) {
|
||
|
if (!theGraph.activeInHierarchy(theGraph.lineSeries[j])) continue;
|
||
|
WMG_Series theSeries = theGraph.lineSeries[j].GetComponent<WMG_Series>();
|
||
|
if (theSeries == this) {
|
||
|
if (!theGraph.activeInHierarchy(theGraph.lineSeries[j-1])) continue;
|
||
|
WMG_Series prevSeries = theGraph.lineSeries[j-1].GetComponent<WMG_Series>();
|
||
|
prevPoints = prevSeries.getPoints();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
List<Vector2> newPositions = new List<Vector2>();
|
||
|
List<int> newWidths = new List<int>();
|
||
|
List<int> newHeights = new List<int>();
|
||
|
bool callUpdateShading = true;
|
||
|
getNewPointPositionsAndSizes(prevPoints, ref newPositions, ref newWidths, ref newHeights);
|
||
|
updatePointSprites(newPositions, newWidths, newHeights, ref callUpdateShading);
|
||
|
updateDataLabels();
|
||
|
if (callUpdateShading) {
|
||
|
updateAreaShading(newPositions);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void updateXdistBetween() {
|
||
|
// Auto set xDistBetween based on the axis length and point count
|
||
|
if (!ManuallySetXDistBetween) {
|
||
|
_xDistBetweenPoints = theGraph.getDistBetween(points.Count, (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal ? theGraph.yAxisLength : theGraph.xAxisLength));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void updateExtraXSpace() {
|
||
|
// auto update space from axis
|
||
|
if (!ManuallySetExtraXSpace) {
|
||
|
if (theGraph.autoUpdateSeriesAxisSpacing) {
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.line || theGraph.graphType == WMG_Axis_Graph.graphTypes.line_stacked) {
|
||
|
_extraXSpace = 0;
|
||
|
}
|
||
|
else {
|
||
|
_extraXSpace = xDistBetweenPoints / 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void getNewPointPositionsAndSizes(List<GameObject> prevPoints, ref List<Vector2> newPositions, ref List<int> newWidths, ref List<int> newHeights) {
|
||
|
if (points.Count == 0) return;
|
||
|
float xAxisLength = theGraph.xAxisLength;
|
||
|
float yAxisLength = theGraph.yAxisLength;
|
||
|
float xAxisMax = theGraph.xAxis.AxisMaxValue;
|
||
|
float yAxisMax = yAxis.AxisMaxValue;
|
||
|
float xAxisMin = theGraph.xAxis.AxisMinValue;
|
||
|
float yAxisMin = yAxis.AxisMinValue;
|
||
|
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
theGraph.SwapVals(ref xAxisLength, ref yAxisLength);
|
||
|
theGraph.SwapVals(ref xAxisMax, ref yAxisMax);
|
||
|
theGraph.SwapVals(ref xAxisMin, ref yAxisMin);
|
||
|
}
|
||
|
|
||
|
updateXdistBetween();
|
||
|
|
||
|
updateExtraXSpace();
|
||
|
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
if (i >= pointValues.Count) break;
|
||
|
|
||
|
float newX = 0;
|
||
|
float newY = (pointValues[i].y - yAxisMin)/(yAxisMax - yAxisMin) * yAxisLength; // new y always based on the pointValues.y
|
||
|
|
||
|
// If using xDistBetween then point positioning based on previous point point position
|
||
|
if (!theGraph.useGroups && UseXDistBetweenToSpace) {
|
||
|
if (i > 0) { // For points greater than 0, use the previous point position plus xDistBetween
|
||
|
float prevPosX = newPositions[i-1].x;
|
||
|
float barOffsetX = 0;
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
prevPosX = newPositions[i-1].y;
|
||
|
barOffsetX = theGraph.barWidth;
|
||
|
}
|
||
|
newX = prevPosX + xDistBetweenPoints;
|
||
|
if (!seriesIsLine) {
|
||
|
newX += barOffsetX;
|
||
|
}
|
||
|
}
|
||
|
else { // For point 0, one of the positions is just 0
|
||
|
newX = extraXSpace;
|
||
|
}
|
||
|
}
|
||
|
else if (theGraph.useGroups) { // Using groups, x values represent integer index of group
|
||
|
newX = extraXSpace + xDistBetweenPoints * (Mathf.Abs(pointValues[i].x) - 1);
|
||
|
}
|
||
|
else { // Not using xDistBetween or groups, so use the actual x values in the Vector2 list
|
||
|
newX = (pointValues[i].x - xAxisMin)/(xAxisMax - xAxisMin) * xAxisLength;
|
||
|
}
|
||
|
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
theGraph.SwapVals(ref newX, ref newY);
|
||
|
}
|
||
|
|
||
|
int newWidth = 0;
|
||
|
int newHeight = 0;
|
||
|
|
||
|
if (seriesIsLine) {
|
||
|
// Width and height of points for line graphs - needed because autospace functionality requires height and width of previous point
|
||
|
// And previous point widths and heights are not set in this loop because of automatic animations
|
||
|
newWidth = Mathf.RoundToInt(pointWidthHeight);
|
||
|
newHeight = Mathf.RoundToInt(pointWidthHeight);
|
||
|
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.line_stacked) {
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.vertical) {
|
||
|
if (prevPoints != null && i < prevPoints.Count) {
|
||
|
newY += theGraph.getSpritePositionY(prevPoints[i]);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (prevPoints != null && i < prevPoints.Count) {
|
||
|
newX += theGraph.getSpritePositionX(prevPoints[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
// For bar graphs, need to update sprites width and height based on positions
|
||
|
// For stacked percentage, need to set a y position based on the percentage of all series values combined
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.bar_stacked_percent && theGraph.TotalPointValues.Count > i) {
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.vertical) {
|
||
|
newY = (pointValues[i].y - yAxisMin) / theGraph.TotalPointValues[i] * yAxisLength;
|
||
|
}
|
||
|
else {
|
||
|
newX = (pointValues[i].y - yAxisMin) / theGraph.TotalPointValues[i] * yAxisLength;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update sprite dimensions and increase position using previous point position
|
||
|
// Previous points is null for side by side bar, but should not be empty for stacked and stacked percentage for series after the first series
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.vertical) {
|
||
|
newWidth = Mathf.RoundToInt(theGraph.barWidth);
|
||
|
newHeight = Mathf.RoundToInt(newY);
|
||
|
// Adjust height based on barAxisValue
|
||
|
int heightAdjust = 0;
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.bar_side || (theGraph.graphType == WMG_Axis_Graph.graphTypes.combo && comboType == comboTypes.bar)) {
|
||
|
heightAdjust = Mathf.RoundToInt((theGraph.barAxisValue - yAxisMin) / (yAxisMax - yAxisMin) * yAxisLength);
|
||
|
}
|
||
|
newHeight -= heightAdjust;
|
||
|
newY -= newHeight;
|
||
|
barIsNegative[i] = false;
|
||
|
if (newHeight < 0) {
|
||
|
newHeight *= -1;
|
||
|
newY -= newHeight;
|
||
|
barIsNegative[i] = true;
|
||
|
}
|
||
|
if (prevPoints != null && i < prevPoints.Count) {
|
||
|
newY += theGraph.getSpritePositionY(prevPoints[i]) + theGraph.getSpriteHeight(prevPoints[i]);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
newWidth = Mathf.RoundToInt(newX);
|
||
|
newHeight = Mathf.RoundToInt(theGraph.barWidth);
|
||
|
// Adjust width based on barAxisValue
|
||
|
int widthAdjust = 0;
|
||
|
if (theGraph.graphType == WMG_Axis_Graph.graphTypes.bar_side || (theGraph.graphType == WMG_Axis_Graph.graphTypes.combo && comboType == comboTypes.bar)) {
|
||
|
widthAdjust = Mathf.RoundToInt((theGraph.barAxisValue - yAxisMin) / (yAxisMax - yAxisMin) * yAxisLength);
|
||
|
}
|
||
|
newWidth -= widthAdjust;
|
||
|
newX = widthAdjust;
|
||
|
newY -= theGraph.barWidth;
|
||
|
barIsNegative[i] = false;
|
||
|
if (newWidth < 0) {
|
||
|
newWidth *= -1;
|
||
|
newX -= newWidth;
|
||
|
barIsNegative[i] = true;
|
||
|
}
|
||
|
if (prevPoints != null && i < prevPoints.Count) {
|
||
|
newX += theGraph.getSpritePositionX(prevPoints[i]) + theGraph.getSpriteWidth(prevPoints[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
newWidths.Add(newWidth);
|
||
|
newHeights.Add(newHeight);
|
||
|
newPositions.Add(new Vector2(newX, newY));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void updatePointSprites(List<Vector2> newPositions, List<int> newWidths, List<int> newHeights, ref bool callUpdateShading) {
|
||
|
if (points.Count == 0) return;
|
||
|
if (animatingFromPreviousData) { // For animations, copy over the newly calculated values into lists to be used later in the animation code
|
||
|
if (seriesIsLine) {
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
if (i >= pointValues.Count) break;
|
||
|
newPositions[i] = theGraph.getChangeSpritePositionTo(points[i], newPositions[i]);
|
||
|
}
|
||
|
}
|
||
|
afterPositions = new List<Vector2>(newPositions);
|
||
|
afterWidths = new List<int>(newWidths);
|
||
|
afterHeights = new List<int>(newHeights);
|
||
|
OnSeriesDataChanged();
|
||
|
animatingFromPreviousData = false;
|
||
|
if (areaShadingUsesComputeShader) {
|
||
|
callUpdateShading = false;
|
||
|
}
|
||
|
}
|
||
|
else { // Otherwise update the visuals now
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
if (i >= pointValues.Count) break;
|
||
|
if (!seriesIsLine) {
|
||
|
WMG_Node thePoint = points[i].GetComponent<WMG_Node>();
|
||
|
theGraph.changeBarWidthHeight(thePoint.objectToColor, newWidths[i], newHeights[i]);
|
||
|
}
|
||
|
theGraph.changeSpritePositionTo(points[i], new Vector3(newPositions[i].x, newPositions[i].y, 0));
|
||
|
}
|
||
|
RepositionLines();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void updateDataLabels() {
|
||
|
if (!dataLabelsEnabled) return;
|
||
|
for (int i = 0; i < dataLabels.Count; i++) {
|
||
|
Vector2 currentPointPosition = new Vector2(theGraph.getSpritePositionX(points[i]), theGraph.getSpritePositionY(points[i]));
|
||
|
// Update font size
|
||
|
theGraph.changeLabelFontSize(dataLabels[i], dataLabelsFontSize);
|
||
|
// Font Color
|
||
|
theGraph.changeLabelColor(dataLabels[i], dataLabelsColor);
|
||
|
// Font Style
|
||
|
theGraph.changeLabelFontStyle(dataLabels[i], dataLabelsFontStyle);
|
||
|
// Font
|
||
|
if (dataLabelsFont != null) {
|
||
|
theGraph.changeLabelFont(dataLabels[i], dataLabelsFont);
|
||
|
}
|
||
|
// Update text based on y value and number decimals
|
||
|
theGraph.changeLabelText(dataLabels[i], seriesDataLabeler(this, pointValues[i].y));
|
||
|
|
||
|
// Update pivot
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
theGraph.changeSpritePivot(dataLabels[i], WMG_Graph_Manager.WMGpivotTypes.Left);
|
||
|
}
|
||
|
else {
|
||
|
theGraph.changeSpritePivot(dataLabels[i], WMG_Graph_Manager.WMGpivotTypes.Bottom);
|
||
|
}
|
||
|
|
||
|
// Update positions
|
||
|
if (seriesIsLine) {
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.vertical) {
|
||
|
theGraph.changeSpritePositionTo(dataLabels[i], new Vector3(
|
||
|
dataLabelsOffset.x + currentPointPosition.x,
|
||
|
dataLabelsOffset.y + currentPointPosition.y + pointWidthHeight / 2,
|
||
|
0));
|
||
|
}
|
||
|
else {
|
||
|
theGraph.changeSpritePositionTo(dataLabels[i], new Vector3(
|
||
|
dataLabelsOffset.x + currentPointPosition.x + pointWidthHeight / 2,
|
||
|
dataLabelsOffset.y + currentPointPosition.y,
|
||
|
0));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.vertical) {
|
||
|
float newY = dataLabelsOffset.y + currentPointPosition.y + theGraph.getSpriteHeight(points[i]);
|
||
|
if (barIsNegative[i]) {
|
||
|
newY = -dataLabelsOffset.y - theGraph.getSpriteHeight(points[i]) + Mathf.RoundToInt((theGraph.barAxisValue - yAxis.AxisMinValue) / (yAxis.AxisMaxValue - yAxis.AxisMinValue) * theGraph.yAxisLength);
|
||
|
}
|
||
|
theGraph.changeSpritePositionTo(dataLabels[i], new Vector3(
|
||
|
dataLabelsOffset.x + currentPointPosition.x + theGraph.barWidth / 2,
|
||
|
newY,
|
||
|
0));
|
||
|
}
|
||
|
else {
|
||
|
float newX = dataLabelsOffset.x + currentPointPosition.x + theGraph.getSpriteWidth(points[i]);
|
||
|
if (barIsNegative[i]) {
|
||
|
newX = -dataLabelsOffset.x - theGraph.getSpriteWidth(points[i]) + Mathf.RoundToInt((theGraph.barAxisValue - theGraph.xAxis.AxisMinValue) / (theGraph.xAxis.AxisMaxValue - theGraph.xAxis.AxisMinValue) * theGraph.xAxisLength);
|
||
|
}
|
||
|
theGraph.changeSpritePositionTo(dataLabels[i], new Vector3(
|
||
|
newX,
|
||
|
dataLabelsOffset.y + currentPointPosition.y + theGraph.barWidth / 2,
|
||
|
0));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Update the position, alpha clipping, and other properties of the area shading rectangles
|
||
|
public void updateAreaShading(List<Vector2> newPositions) {
|
||
|
if (areaShadingType == areaShadingTypes.None) return;
|
||
|
if (areaShadingUsesComputeShader && areaShadingRects.Count == 1) { // all values (min, max, and the points) represent a percentage of graph
|
||
|
WMG_Compute_Shader areaShadingCS = areaShadingRects[0].GetComponent<WMG_Compute_Shader>();
|
||
|
|
||
|
areaShadingCS.computeShader.SetFloats ("color", new float[]{ areaShadingColor.r, areaShadingColor.g, areaShadingColor.b, areaShadingColor.a });
|
||
|
areaShadingCS.computeShader.SetInt("numPoints", pointValues.Count);
|
||
|
areaShadingCS.computeShader.SetInt("isFill", areaShadingType == areaShadingTypes.Solid ? 1 : 0);
|
||
|
areaShadingCS.computeShader.SetInt("isHorizontal", theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal ? 1 : 0);
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
areaShadingCS.computeShader.SetFloat ("minVal", (areaShadingAxisValue - theGraph.xAxis.AxisMinValue) / (theGraph.xAxis.AxisMaxValue - theGraph.xAxis.AxisMinValue));
|
||
|
}
|
||
|
else {
|
||
|
areaShadingCS.computeShader.SetFloat ("minVal", (areaShadingAxisValue - yAxis.AxisMinValue) / (yAxis.AxisMaxValue - yAxis.AxisMinValue));
|
||
|
}
|
||
|
float maxVal = 0;
|
||
|
for (int i = 0; i < pointValues.Count; i++) {
|
||
|
Vector2 pointPos = newPositions == null ? theGraph.getSpritePositionXY(points[i]) : newPositions[i];
|
||
|
pointPos = new Vector2(pointPos.x / theGraph.xAxisLength, pointPos.y / theGraph.yAxisLength);
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
pointPos = new Vector2(pointPos.y, pointPos.x);
|
||
|
}
|
||
|
areaShadingCS.pointVals[4 * i] = pointPos.x;
|
||
|
areaShadingCS.pointVals[4 * i + 1] = pointPos.y;
|
||
|
if (pointPos.y > maxVal) {
|
||
|
maxVal = pointPos.y;
|
||
|
}
|
||
|
}
|
||
|
areaShadingCS.computeShader.SetFloat ("maxVal", maxVal);
|
||
|
areaShadingCS.computeShader.SetFloats("pointVals", areaShadingCS.pointVals);
|
||
|
|
||
|
areaShadingCS.dispatchAndUpdateImage();
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
// Find the maximum area shading height so that we can corectly adjust each sprites transparency based on their height in comparison to the max height
|
||
|
float maxVal = Mathf.NegativeInfinity;
|
||
|
for (int i = 0; i < points.Count; i++) {
|
||
|
if (i >= pointValues.Count) break;
|
||
|
if (pointValues[i].y > maxVal) {
|
||
|
maxVal = pointValues[i].y;
|
||
|
}
|
||
|
}
|
||
|
for (int i = 0; i < points.Count - 1; i++) {
|
||
|
if (i >= pointValues.Count) break;
|
||
|
|
||
|
int rotation = 180;
|
||
|
Vector2 currentPointPosition = theGraph.getSpritePositionXY(points[i]);
|
||
|
Vector2 nextPointPosition = theGraph.getSpritePositionXY(points[i+1]);
|
||
|
float axisMultiplier = theGraph.yAxisLength / (yAxis.AxisMaxValue - yAxis.AxisMinValue);
|
||
|
float yPosOfAxisVal = (areaShadingAxisValue - yAxis.AxisMinValue) * axisMultiplier;
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
rotation = 90;
|
||
|
currentPointPosition = new Vector2(theGraph.getSpritePositionY(points[i]), theGraph.getSpritePositionX(points[i]));
|
||
|
nextPointPosition = new Vector2(theGraph.getSpritePositionY(points[i+1]), theGraph.getSpritePositionX(points[i+1]));
|
||
|
axisMultiplier = theGraph.xAxisLength / (theGraph.xAxis.AxisMaxValue - theGraph.xAxis.AxisMinValue);
|
||
|
yPosOfAxisVal = (areaShadingAxisValue - theGraph.xAxis.AxisMinValue) * axisMultiplier;
|
||
|
}
|
||
|
|
||
|
areaShadingRects[i].transform.localEulerAngles = new Vector3(0, 0, rotation);
|
||
|
float maxY = Mathf.Max(nextPointPosition.y, currentPointPosition.y);
|
||
|
float minY = Mathf.Min(nextPointPosition.y, currentPointPosition.y);
|
||
|
int newX = Mathf.RoundToInt(currentPointPosition.x);
|
||
|
int newWidth = Mathf.RoundToInt(nextPointPosition.x - currentPointPosition.x);
|
||
|
float newHeight = maxY - minY + ((Mathf.Min(pointValues[i+1].y, pointValues[i].y) - areaShadingAxisValue) * axisMultiplier ) ;
|
||
|
|
||
|
// If areaShading value goes above a line segment, decrease the width appropriately
|
||
|
if (minY < yPosOfAxisVal) {
|
||
|
float slope = (nextPointPosition.y - currentPointPosition.y) / (nextPointPosition.x - currentPointPosition.x);
|
||
|
// Slope increasing
|
||
|
if (nextPointPosition.y > currentPointPosition.y) {
|
||
|
float deltaY = yPosOfAxisVal - minY;
|
||
|
int deltaX = Mathf.RoundToInt(deltaY / slope);
|
||
|
newWidth -= deltaX;
|
||
|
// Increase position by delta
|
||
|
newX += deltaX;
|
||
|
}
|
||
|
else {
|
||
|
float deltaY = yPosOfAxisVal - minY;
|
||
|
int deltaX = Mathf.RoundToInt(deltaY / slope * -1);
|
||
|
newWidth -= deltaX;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
theGraph.changeSpritePositionTo(areaShadingRects[i], new Vector3(maxY,
|
||
|
newX + newWidth, 0));
|
||
|
}
|
||
|
else {
|
||
|
theGraph.changeSpritePositionTo(areaShadingRects[i], new Vector3(newX,
|
||
|
maxY, 0));
|
||
|
}
|
||
|
theGraph.changeSpriteSizeFloat(areaShadingRects[i], newWidth, newHeight);
|
||
|
|
||
|
// Adjust previous sprite width based on previous width and position so that the sprites do not overlap due to position being a float and width being an integer
|
||
|
if (i > 0) { // Don't need to adjust the width for the first rectangle
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
int previousSpriteWidthPlusPosition = Mathf.RoundToInt(theGraph.getSpritePositionY(areaShadingRects[i]))
|
||
|
- Mathf.RoundToInt(theGraph.getSpriteWidth(areaShadingRects[i]));
|
||
|
int yPrevious = Mathf.RoundToInt(theGraph.getSpritePositionY(areaShadingRects[i-1]));
|
||
|
// if y previous < y current - width current then increase current width by 1y 1
|
||
|
if (previousSpriteWidthPlusPosition > yPrevious) {
|
||
|
theGraph.changeSpriteWidth(areaShadingRects[i], Mathf.RoundToInt(theGraph.getSpriteWidth(areaShadingRects[i]) + 1));
|
||
|
}
|
||
|
// if y previous > y current - width current then decrease current width by 1y 1
|
||
|
if (previousSpriteWidthPlusPosition < yPrevious) {
|
||
|
theGraph.changeSpriteWidth(areaShadingRects[i], Mathf.RoundToInt(theGraph.getSpriteWidth(areaShadingRects[i]) - 1));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
int previousSpriteWidthPlusPosition = Mathf.RoundToInt(theGraph.getSpriteWidth(areaShadingRects[i-1])) + Mathf.RoundToInt(theGraph.getSpritePositionX(areaShadingRects[i-1]));
|
||
|
// If greater then sprites would overlap, subtract width by 1
|
||
|
if (previousSpriteWidthPlusPosition > Mathf.RoundToInt(theGraph.getSpritePositionX(areaShadingRects[i]))) {
|
||
|
theGraph.changeSpriteWidth(areaShadingRects[i-1], Mathf.RoundToInt(theGraph.getSpriteWidth(areaShadingRects[i-1]) - 1));
|
||
|
}
|
||
|
// If lesser then sprites would have gap, increased width by 1
|
||
|
if (previousSpriteWidthPlusPosition < Mathf.RoundToInt(theGraph.getSpritePositionX(areaShadingRects[i]))) {
|
||
|
theGraph.changeSpriteWidth(areaShadingRects[i-1], Mathf.RoundToInt(theGraph.getSpriteWidth(areaShadingRects[i-1]) + 1));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set custom shader properties to do appropriate alpha clipping, gradient shading, color, etc.
|
||
|
Material curMat = theGraph.getTextureMaterial(areaShadingRects[i]);
|
||
|
if (curMat == null) continue;
|
||
|
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.horizontal) {
|
||
|
curMat.SetFloat("_Slope", -(nextPointPosition.y - currentPointPosition.y) / newHeight);
|
||
|
}
|
||
|
else {
|
||
|
curMat.SetFloat("_Slope", (nextPointPosition.y - currentPointPosition.y) / newHeight);
|
||
|
}
|
||
|
|
||
|
curMat.SetColor("_Color", areaShadingColor);
|
||
|
curMat.SetFloat("_Transparency", 1 - areaShadingColor.a );
|
||
|
// Set the gradient scale based on current sprite height in comparison to maximum sprite height
|
||
|
curMat.SetFloat("_GradientScale",
|
||
|
(Mathf.Max(pointValues[i+1].y, pointValues[i].y) - areaShadingAxisValue) / (maxVal - areaShadingAxisValue)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void StartRealTimeUpdate() {
|
||
|
if (realTimeRunning) return;
|
||
|
if (realTimeDataSource != null) {
|
||
|
realTimeRunning = true;
|
||
|
pointValues.SetListNoCb(new List<Vector2>(), ref _pointValues);
|
||
|
pointValues.AddNoCb(new Vector2(0, realTimeDataSource.getDatum<float>()), ref _pointValues);
|
||
|
realTimeLoopVar = 0;
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.vertical) {
|
||
|
realTimeOrigMax = theGraph.xAxis.AxisMaxValue;
|
||
|
}
|
||
|
else {
|
||
|
realTimeOrigMax = yAxis.AxisMaxValue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void StopRealTimeUpdate() {
|
||
|
realTimeRunning = false;
|
||
|
}
|
||
|
|
||
|
public void ResumeRealTimeUpdate() {
|
||
|
realTimeRunning = true;
|
||
|
}
|
||
|
|
||
|
private void DoRealTimeUpdate() {
|
||
|
/* This "Real Time" update is FPS dependent, so the time axis actually represents a number of frames.
|
||
|
* The waitForSeconds for coroutines does not actually wait for the specified number of seconds, and is also FPS dependent.
|
||
|
* An FPS independent solution only seems possible with fixedUpdate, which may be added later. */
|
||
|
|
||
|
float waitTime = 0.0166f; // Each x-axis unit is 60 frames. This is 1 second at 60 fps.
|
||
|
|
||
|
realTimeLoopVar += waitTime;
|
||
|
|
||
|
float yval = realTimeDataSource.getDatum<float>();
|
||
|
int sampleSize = 2;
|
||
|
|
||
|
// Add new point or move the last existing point
|
||
|
if (pointValues.Count >= 2) {
|
||
|
float maxStdDev = 0.3f; // a standard deviation above this means generate a new point
|
||
|
// use graph slope to normalize the calculated slopes.
|
||
|
float graphSlope = (yAxis.AxisMaxValue - yAxis.AxisMinValue) / (theGraph.xAxis.AxisMaxValue - theGraph.xAxis.AxisMinValue);
|
||
|
float[] slopes = new float[sampleSize];
|
||
|
Vector2 p1 = new Vector2(realTimeLoopVar, yval);
|
||
|
|
||
|
for (int i = 0; i < slopes.Length; i++) {
|
||
|
Vector2 p2 = pointValues[pointValues.Count-(i+1)];
|
||
|
slopes[i] = ((p1.y - p2.y) / (p1.x - p2.x)) / graphSlope;
|
||
|
}
|
||
|
|
||
|
// For 2 points this is equivalent to the standard deviation
|
||
|
if (Mathf.Abs(slopes[0]-slopes[1]) <= maxStdDev) { // if standard deviation less than threshold, then move point
|
||
|
// Slopes about the same, move the last point
|
||
|
pointValues[pointValues.Count-1] = new Vector2(realTimeLoopVar,yval);
|
||
|
}
|
||
|
else {
|
||
|
// Slopes significantly different, add a new point
|
||
|
pointValues.Add(new Vector2(realTimeLoopVar, yval));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// Just add the second point
|
||
|
pointValues.Add(new Vector2(realTimeLoopVar, yval));
|
||
|
}
|
||
|
|
||
|
// If needed, change graph axis boundary and remove or move the first point to keep the series within the graph boundaries
|
||
|
if (pointValues.Count > 1 && pointValues[pointValues.Count-1].x > realTimeOrigMax) {
|
||
|
|
||
|
// For the last real time update series update the axis boundaries by the difference
|
||
|
if (theGraph.orientationType == WMG_Axis_Graph.orientationTypes.vertical) {
|
||
|
theGraph.xAxis.AxisMinValue = realTimeLoopVar - realTimeOrigMax;
|
||
|
theGraph.xAxis.AxisMaxValue = realTimeLoopVar;
|
||
|
}
|
||
|
else {
|
||
|
yAxis.AxisMinValue = realTimeLoopVar - realTimeOrigMax;
|
||
|
yAxis.AxisMaxValue = realTimeLoopVar;
|
||
|
}
|
||
|
|
||
|
// First and second points used to see if the first point should be moved or deleted after incrementing the minimum axis value
|
||
|
float x1 = pointValues[0].x;
|
||
|
float x2 = pointValues[1].x;
|
||
|
float y1 = pointValues[0].y;
|
||
|
float y2 = pointValues[1].y;
|
||
|
|
||
|
// Delete or move the very first point to keep the series in the graph boundary when the maximum is increased
|
||
|
if (Mathf.Approximately(x1 + waitTime, x2)) pointValues.RemoveAt(0);
|
||
|
else pointValues[0] = new Vector2(x1 + waitTime, y1 + (y2 - y1) / (x2 - x1) * waitTime);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void deleteAllNodesFromGraphManager() {
|
||
|
// This should not be called manually, only an internal helper function for dynamically deleting series
|
||
|
for (int i = points.Count - 1; i >= 0; i--) {
|
||
|
theGraph.DeleteNode(points[i].GetComponent<WMG_Node>());
|
||
|
}
|
||
|
theGraph.DeleteNode(legendEntry.nodeLeft.GetComponent<WMG_Node>());
|
||
|
theGraph.DeleteNode(legendEntry.nodeRight.GetComponent<WMG_Node>());
|
||
|
theGraph.DeleteNode(legendEntry.swatchNode.GetComponent<WMG_Node>());
|
||
|
}
|
||
|
}
|