mirror of
https://github.com/XCharts-Team/XCharts.git
synced 2026-05-28 12:08:46 +00:00
980 lines
43 KiB
C#
980 lines
43 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
using UnityEngine.UI;
|
||
|
||
namespace XCharts.Runtime
|
||
{
|
||
public abstract class SerieHandler
|
||
{
|
||
public BaseChart chart { get; internal set; }
|
||
public SerieHandlerAttribute attribute { get; internal set; }
|
||
public bool inited { get; internal set; }
|
||
public virtual int defaultDimension { get; internal set; }
|
||
|
||
public virtual void InitComponent() { }
|
||
public virtual void RemoveComponent() { }
|
||
public virtual void CheckComponent(StringBuilder sb) { }
|
||
public virtual void BeforeUpdate() { }
|
||
public virtual void Update() { }
|
||
public virtual void AfterUpdate() { }
|
||
public virtual void DrawBase(VertexHelper vh) { }
|
||
public virtual void DrawSerie(VertexHelper vh) { }
|
||
public virtual void DrawUpper(VertexHelper vh) { }
|
||
public virtual void DrawTop(VertexHelper vh) { }
|
||
public virtual void OnPointerClick(PointerEventData eventData) { }
|
||
public virtual void OnPointerDown(PointerEventData eventData) { }
|
||
public virtual void OnPointerUp(PointerEventData eventData) { }
|
||
public virtual void OnPointerEnter(PointerEventData eventData) { }
|
||
public virtual void OnPointerExit(PointerEventData eventData) { }
|
||
public virtual void OnDrag(PointerEventData eventData) { }
|
||
public virtual void OnBeginDrag(PointerEventData eventData) { }
|
||
public virtual void OnEndDrag(PointerEventData eventData) { }
|
||
public virtual void OnScroll(PointerEventData eventData) { }
|
||
public virtual void OnDataUpdate() { }
|
||
public virtual void RefreshLabelNextFrame() { }
|
||
public virtual void RefreshLabelInternal() { }
|
||
public virtual void ForceUpdateSerieContext() { }
|
||
public virtual void UpdateSerieContext() { }
|
||
public virtual void UpdateTooltipSerieParams(int dataIndex, bool showCategory,
|
||
string category, string marker,
|
||
string itemFormatter, string numericFormatter, string ignoreDataDefaultContent,
|
||
ref List<SerieParams> paramList, ref string title)
|
||
{ }
|
||
public virtual void OnLegendButtonClick(int index, string legendName, bool show) { }
|
||
public virtual void OnLegendButtonEnter(int index, string legendName) { }
|
||
public virtual void OnLegendButtonExit(int index, string legendName) { }
|
||
internal abstract void SetSerie(Serie serie);
|
||
public virtual int GetPointerItemDataIndex() { return -1; }
|
||
public virtual int GetPointerItemDataDimension() { return 1; }
|
||
}
|
||
|
||
public abstract class SerieHandler<T> : SerieHandler where T : Serie
|
||
{
|
||
private static readonly string s_SerieLabelObjectName = "label";
|
||
private static readonly string s_SerieTitleObjectName = "title";
|
||
private static readonly string s_SerieRootObjectName = "serie";
|
||
private static readonly string s_SerieEndLabelObjectName = "end_label";
|
||
protected GameObject m_SerieRoot;
|
||
protected GameObject m_SerieLabelRoot;
|
||
protected bool m_InitedLabel;
|
||
protected bool m_InitTitleLabel;
|
||
protected bool m_NeedInitComponent;
|
||
protected bool m_RefreshLabel;
|
||
protected bool m_LastCheckContextFlag = false;
|
||
protected bool m_LegendEnter = false;
|
||
protected bool m_LegendExiting = false;
|
||
protected bool m_ForceUpdateSerieContext = false;
|
||
protected int m_LegendEnterIndex;
|
||
protected ChartLabel m_EndLabel;
|
||
|
||
private float[] m_LastRadius = new float[2] { 0, 0 };
|
||
private float[] m_LastCenter = new float[2] { 0, 0 };
|
||
private bool m_LastPointerEnter;
|
||
private int m_LastPointerDataIndex;
|
||
private int m_LastPointerDataDimension;
|
||
|
||
public T serie { get; internal set; }
|
||
public GameObject labelObject { get { return m_SerieLabelRoot; } }
|
||
|
||
internal override void SetSerie(Serie serie)
|
||
{
|
||
this.serie = (T)serie;
|
||
this.serie.context.param.serieType = typeof(T);
|
||
m_NeedInitComponent = true;
|
||
AnimationStyleHelper.UpdateSerieAnimation(serie);
|
||
}
|
||
|
||
public override void BeforeUpdate()
|
||
{
|
||
m_LastPointerEnter = serie.context.pointerEnter;
|
||
m_LastPointerDataIndex = serie.context.pointerItemDataIndex;
|
||
m_LastPointerDataDimension = GetPointerItemDataDimension();
|
||
serie.context.pointerEnter = false;
|
||
serie.context.pointerItemDataIndex = -1;
|
||
}
|
||
|
||
public override void Update()
|
||
{
|
||
CheckConfigurationChanged();
|
||
if (m_NeedInitComponent)
|
||
{
|
||
m_NeedInitComponent = false;
|
||
InitComponent();
|
||
}
|
||
if (m_RefreshLabel)
|
||
{
|
||
m_RefreshLabel = false;
|
||
RefreshLabelInternal();
|
||
RefreshEndLabelInternal();
|
||
RefreshTitleLabelInternal();
|
||
}
|
||
if (serie.dataDirty)
|
||
{
|
||
OnDataUpdate();
|
||
SeriesHelper.UpdateSerieNameList(chart, ref chart.m_LegendRealShowName);
|
||
chart.OnSerieDataUpdate(serie.index);
|
||
serie.OnDataUpdate();
|
||
serie.dataDirty = false;
|
||
}
|
||
if (serie.label != null && (serie.labelDirty || serie.label.componentDirty))
|
||
{
|
||
serie.labelDirty = false;
|
||
serie.label.ClearComponentDirty();
|
||
InitSerieLabel();
|
||
InitSerieEndLabel();
|
||
}
|
||
if (serie.endLabel != null && serie.endLabel.componentDirty)
|
||
{
|
||
serie.endLabel.ClearComponentDirty();
|
||
InitSerieEndLabel();
|
||
}
|
||
if (serie.titleStyle != null && (serie.titleDirty || serie.titleStyle.componentDirty))
|
||
{
|
||
serie.titleDirty = false;
|
||
serie.titleStyle.ClearComponentDirty();
|
||
InitSerieTitle();
|
||
}
|
||
if (serie.nameDirty)
|
||
{
|
||
foreach (var component in chart.components)
|
||
{
|
||
if (component is Legend)
|
||
component.SetAllDirty();
|
||
}
|
||
chart.RefreshChart();
|
||
serie.ClearSerieNameDirty();
|
||
}
|
||
if (serie.vertsDirty)
|
||
{
|
||
chart.RefreshPainter(serie);
|
||
serie.ClearVerticesDirty();
|
||
}
|
||
if (serie.interactDirty)
|
||
{
|
||
if (serie.animation.enable && serie.animation.interaction.enable)
|
||
{
|
||
Color32 color1, toColor1;
|
||
bool needInteract = false;
|
||
serie.context.colorIndex = chart.GetLegendRealShowNameIndex(serie.legendName);
|
||
foreach (var serieData in serie.data)
|
||
{
|
||
var state = SerieHelper.GetSerieState(serie, serieData, true);
|
||
SerieHelper.GetItemColor(out color1, out toColor1, serie, serieData, chart.theme, state);
|
||
serieData.interact.SetColor(ref needInteract, color1, toColor1);
|
||
}
|
||
}
|
||
chart.RefreshChart();
|
||
serie.interactDirty = false;
|
||
m_ForceUpdateSerieContext = true;
|
||
}
|
||
UpdateSerieContextInternal();
|
||
}
|
||
|
||
public override void AfterUpdate()
|
||
{
|
||
if (m_LastPointerEnter != serie.context.pointerEnter || m_LastPointerDataIndex != serie.context.pointerItemDataIndex)
|
||
{
|
||
if (chart.onSerieEnter != null || chart.onSerieExit != null || serie.onEnter != null || serie.onExit != null)
|
||
{
|
||
if (serie.context.pointerEnter)
|
||
{
|
||
if ((serie.onExit != null || chart.onSerieExit != null) && m_LastPointerDataIndex >= 0)
|
||
{
|
||
var dataValue = serie.GetData(m_LastPointerDataIndex, m_LastPointerDataDimension);
|
||
var exitEventData = SerieEventDataPool.Get(chart.pointerPos, serie.index, m_LastPointerDataIndex, m_LastPointerDataDimension, dataValue);
|
||
if (serie.onExit != null) serie.onExit(exitEventData);
|
||
if (chart.onSerieExit != null) chart.onSerieExit(exitEventData);
|
||
SerieEventDataPool.Release(exitEventData);
|
||
}
|
||
var dataIndex = GetPointerItemDataIndex();
|
||
var dimension = GetPointerItemDataDimension();
|
||
var value = serie.GetData(dataIndex, dimension);
|
||
var enterEventData = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value);
|
||
if (serie.onEnter != null) serie.onEnter(enterEventData);
|
||
if (chart.onSerieEnter != null) chart.onSerieEnter(enterEventData);
|
||
SerieEventDataPool.Release(enterEventData);
|
||
}
|
||
else if (m_LastPointerDataIndex >= 0)
|
||
{
|
||
var dataValue = serie.GetData(m_LastPointerDataIndex, m_LastPointerDataDimension);
|
||
var exitEventData = SerieEventDataPool.Get(chart.pointerPos, serie.index, m_LastPointerDataIndex, m_LastPointerDataDimension, dataValue);
|
||
if (serie.onExit != null) serie.onExit(exitEventData);
|
||
if (chart.onSerieExit != null) chart.onSerieExit(exitEventData);
|
||
SerieEventDataPool.Release(exitEventData);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public override void ForceUpdateSerieContext()
|
||
{
|
||
m_ForceUpdateSerieContext = true;
|
||
}
|
||
|
||
private void CheckConfigurationChanged()
|
||
{
|
||
if (m_LastRadius[0] != serie.radius[0] || m_LastRadius[1] != serie.radius[1])
|
||
{
|
||
m_LastRadius[0] = serie.radius[0];
|
||
m_LastRadius[1] = serie.radius[1];
|
||
serie.SetVerticesDirty();
|
||
}
|
||
if (m_LastCenter[0] != serie.center[0] || m_LastCenter[1] != serie.center[1])
|
||
{
|
||
m_LastCenter[0] = serie.center[0];
|
||
m_LastCenter[1] = serie.center[1];
|
||
serie.SetVerticesDirty();
|
||
}
|
||
}
|
||
|
||
private void UpdateSerieContextInternal()
|
||
{
|
||
UpdateSerieContext();
|
||
m_ForceUpdateSerieContext = false;
|
||
}
|
||
|
||
public override void RefreshLabelNextFrame()
|
||
{
|
||
m_RefreshLabel = true;
|
||
}
|
||
|
||
public override void InitComponent()
|
||
{
|
||
m_InitedLabel = false;
|
||
m_InitTitleLabel = false;
|
||
|
||
serie.context.totalDataIndex = serie.dataCount - 1;
|
||
InitRoot();
|
||
InitSerieLabel();
|
||
InitSerieTitle();
|
||
InitSerieEndLabel();
|
||
}
|
||
|
||
public override void RemoveComponent()
|
||
{
|
||
ChartHelper.SetActive(m_SerieRoot, false);
|
||
}
|
||
|
||
public override void OnLegendButtonClick(int index, string legendName, bool show)
|
||
{
|
||
if (serie.colorByData && serie.IsSerieDataLegendName(legendName))
|
||
{
|
||
LegendHelper.CheckDataShow(serie, legendName, show);
|
||
chart.UpdateLegendColor(legendName, show);
|
||
chart.RefreshPainter(serie);
|
||
}
|
||
else if (serie.IsLegendName(legendName))
|
||
{
|
||
chart.SetSerieActive(serie, show);
|
||
chart.RefreshPainter(serie);
|
||
}
|
||
}
|
||
|
||
public override void OnLegendButtonEnter(int index, string legendName)
|
||
{
|
||
if (serie.colorByData && serie.IsSerieDataLegendName(legendName))
|
||
{
|
||
m_LegendEnterIndex = LegendHelper.CheckDataHighlighted(serie, legendName, true);
|
||
m_LegendEnter = true;
|
||
chart.RefreshPainter(serie);
|
||
}
|
||
else if (serie.IsLegendName(legendName))
|
||
{
|
||
m_LegendEnter = true;
|
||
chart.RefreshPainter(serie);
|
||
}
|
||
}
|
||
|
||
public override void OnLegendButtonExit(int index, string legendName)
|
||
{
|
||
if (serie.colorByData && serie.IsSerieDataLegendName(legendName))
|
||
{
|
||
LegendHelper.CheckDataHighlighted(serie, legendName, false);
|
||
m_LegendEnter = false;
|
||
m_LegendExiting = true;
|
||
chart.RefreshPainter(serie);
|
||
}
|
||
else if (serie.IsLegendName(legendName))
|
||
{
|
||
m_LegendEnter = false;
|
||
m_LegendExiting = true;
|
||
chart.RefreshPainter(serie);
|
||
}
|
||
}
|
||
|
||
private void InitRoot()
|
||
{
|
||
if (m_SerieRoot != null)
|
||
{
|
||
var rect = ChartHelper.EnsureComponent<RectTransform>(m_SerieRoot);
|
||
rect.localPosition = Vector3.zero;
|
||
rect.sizeDelta = chart.chartSizeDelta;
|
||
rect.anchorMin = chart.chartMinAnchor;
|
||
rect.anchorMax = chart.chartMaxAnchor;
|
||
rect.pivot = chart.chartPivot;
|
||
return;
|
||
}
|
||
var objName = s_SerieRootObjectName + "_" + serie.index;
|
||
m_SerieRoot = ChartHelper.AddObject(objName, chart.transform, chart.chartMinAnchor,
|
||
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta, -1, chart.childrenNodeNames);
|
||
m_SerieRoot.hideFlags = chart.chartHideFlags;
|
||
ChartHelper.SetActive(m_SerieRoot, true);
|
||
ChartHelper.HideAllObject(m_SerieRoot);
|
||
}
|
||
|
||
private void InitSerieLabel()
|
||
{
|
||
InitRoot();
|
||
m_SerieLabelRoot = ChartHelper.AddObject(s_SerieLabelObjectName, m_SerieRoot.transform,
|
||
chart.chartMinAnchor, chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
|
||
m_SerieLabelRoot.hideFlags = chart.chartHideFlags;
|
||
SerieLabelPool.ReleaseAll(m_SerieLabelRoot.transform);
|
||
int count = 0;
|
||
SerieHelper.UpdateCenter(serie, chart);
|
||
for (int j = 0; j < serie.data.Count; j++)
|
||
{
|
||
var serieData = serie.data[j];
|
||
serieData.index = j;
|
||
serieData.labelObject = null;
|
||
if (AddSerieLabel(m_SerieLabelRoot, serieData, ref count))
|
||
{
|
||
m_InitedLabel = true;
|
||
count++;
|
||
}
|
||
}
|
||
RefreshLabelInternal();
|
||
}
|
||
|
||
protected bool AddSerieLabel(GameObject serieLabelRoot, SerieData serieData, ref int count)
|
||
{
|
||
if (serieData == null)
|
||
return false;
|
||
if (serieLabelRoot == null)
|
||
return false;
|
||
if (serie.IsPerformanceMode())
|
||
return false;
|
||
|
||
if (count == -1) count = serie.dataCount;
|
||
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
|
||
if (serieLabel == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
var dataAutoColor = GetSerieDataAutoColor(serieData);
|
||
serieData.context.dataLabels.Clear();
|
||
if (serie.multiDimensionLabel)
|
||
{
|
||
for (int i = 0; i < serieData.data.Count; i++)
|
||
{
|
||
var textName = string.Format("{0}_{1}_{2}_{3}", s_SerieLabelObjectName, serie.index, serieData.index, i);
|
||
var label = ChartHelper.AddChartLabel(textName, serieLabelRoot.transform, serieLabel, chart.theme.common,
|
||
"", dataAutoColor, TextAnchor.MiddleCenter);
|
||
label.SetActive(false, true);
|
||
serieData.context.dataLabels.Add(label);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var textName = ChartCached.GetSerieLabelName(s_SerieLabelObjectName, serie.index, serieData.index);
|
||
var label = ChartHelper.AddChartLabel(textName, serieLabelRoot.transform, serieLabel, chart.theme.common,
|
||
"", dataAutoColor, TextAnchor.MiddleCenter);
|
||
label.SetActive(false, true);
|
||
serieData.labelObject = label;
|
||
}
|
||
|
||
if (serieData.context.children.Count > 0)
|
||
{
|
||
foreach (var childSerieData in serieData.context.children)
|
||
{
|
||
AddSerieLabel(serieLabelRoot, childSerieData, ref count);
|
||
count++;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
private void InitSerieEndLabel()
|
||
{
|
||
if (serie.endLabel == null)
|
||
{
|
||
if (m_EndLabel != null)
|
||
{
|
||
m_EndLabel.SetActive(false);
|
||
m_EndLabel = null;
|
||
}
|
||
return;
|
||
}
|
||
InitRoot();
|
||
var dataAutoColor = (Color)chart.GetLegendRealShowNameColor(serie.legendName);
|
||
m_EndLabel = ChartHelper.AddChartLabel(s_SerieEndLabelObjectName, m_SerieRoot.transform, serie.endLabel,
|
||
chart.theme.common, "", dataAutoColor, TextAnchor.MiddleLeft);
|
||
m_EndLabel.SetActive(serie.endLabel.show);
|
||
RefreshEndLabelInternal();
|
||
}
|
||
|
||
private void InitSerieTitle()
|
||
{
|
||
InitRoot();
|
||
var serieTitleRoot = ChartHelper.AddObject(s_SerieTitleObjectName, m_SerieRoot.transform,
|
||
chart.chartMinAnchor, chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
|
||
serieTitleRoot.hideFlags = chart.chartHideFlags;
|
||
SerieLabelPool.ReleaseAll(serieTitleRoot.transform);
|
||
ChartHelper.RemoveComponent<Text>(serieTitleRoot);
|
||
|
||
SerieHelper.UpdateCenter(serie, chart);
|
||
|
||
if (serie.titleJustForSerie)
|
||
{
|
||
var titleStyle = SerieHelper.GetTitleStyle(serie, null);
|
||
if (titleStyle != null)
|
||
{
|
||
var color = chart.GetItemColor(serie, null);
|
||
var content = SerieLabelHelper.GetTitleFormatterContent(serie, null, -1, titleStyle, chart);
|
||
var label = ChartHelper.AddChartLabel("title_0", serieTitleRoot.transform, titleStyle, chart.theme.common,
|
||
content, color, TextAnchor.MiddleCenter);
|
||
serie.context.titleObject = label;
|
||
label.SetActive(titleStyle.show, true);
|
||
var labelPosition = GetSerieDataTitlePosition(null, titleStyle);
|
||
var offset = titleStyle.GetOffset(serie.context.insideRadius);
|
||
label.SetPosition(labelPosition + offset);
|
||
m_InitTitleLabel = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int i = 0; i < serie.dataCount; i++)
|
||
{
|
||
var serieData = serie.data[i];
|
||
var titleStyle = SerieHelper.GetTitleStyle(serie, serieData);
|
||
if (titleStyle == null) continue;
|
||
m_InitTitleLabel = true;
|
||
var color = chart.GetItemColor(serie, serieData);
|
||
var content = SerieLabelHelper.GetTitleFormatterContent(serie, serieData, i, titleStyle, chart);
|
||
var label = ChartHelper.AddChartLabel("title_" + i, serieTitleRoot.transform, titleStyle, chart.theme.common,
|
||
content, color, TextAnchor.MiddleCenter);
|
||
serieData.titleObject = label;
|
||
label.SetActive(titleStyle.show, true);
|
||
var labelPosition = GetSerieDataTitlePosition(serieData, titleStyle);
|
||
var offset = titleStyle.GetOffset(serie.context.insideRadius);
|
||
label.SetPosition(labelPosition + offset);
|
||
}
|
||
}
|
||
}
|
||
|
||
public void RefreshTitleLabelInternal()
|
||
{
|
||
if (!m_InitTitleLabel) return;
|
||
if (serie.titleJustForSerie)
|
||
{
|
||
if (serie.context.titleObject != null)
|
||
{
|
||
var titleStyle = SerieHelper.GetTitleStyle(serie, null);
|
||
var labelPosition = GetSerieDataTitlePosition(null, titleStyle);
|
||
var offset = titleStyle.GetOffset(serie.context.insideRadius);
|
||
serie.context.titleObject.SetPosition(labelPosition + offset);
|
||
var content = SerieLabelHelper.GetTitleFormatterContent(serie, null, -1, titleStyle, chart);
|
||
serie.context.titleObject.SetText(content);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int i = 0; i < serie.dataCount; i++)
|
||
{
|
||
var serieData = serie.data[i];
|
||
if (serieData.titleObject == null) continue;
|
||
var titleStyle = SerieHelper.GetTitleStyle(serie, serieData);
|
||
if (titleStyle == null) continue;
|
||
var labelPosition = GetSerieDataTitlePosition(serieData, titleStyle);
|
||
var offset = titleStyle.GetOffset(serie.context.insideRadius);
|
||
serieData.titleObject.SetPosition(labelPosition + offset);
|
||
var content = SerieLabelHelper.GetTitleFormatterContent(serie, serieData, i, titleStyle, chart);
|
||
serieData.titleObject.SetText(content);
|
||
}
|
||
}
|
||
}
|
||
|
||
public override void RefreshLabelInternal()
|
||
{
|
||
if (!m_InitedLabel)
|
||
return;
|
||
|
||
var dataChangeDuration = serie.animation.GetChangeDuration();
|
||
var dataAddDuration = serie.animation.GetAdditionDuration();
|
||
var unscaledTime = serie.animation.unscaledTime;
|
||
var needCheck = serie.context.dataIndexs.Count > 0;
|
||
var allLabelZeroPosition = true;
|
||
var anyLabelActive = false;
|
||
SerieData lastActiveLabelSerieData = null;
|
||
var lastActiveLabelPos = Vector3.zero;
|
||
double lastActiveLabelValue = 0;
|
||
foreach (var serieData in serie.data)
|
||
{
|
||
if (serieData.labelObject == null && serieData.context.dataLabels.Count <= 0)
|
||
{
|
||
continue;
|
||
}
|
||
if (needCheck && !serie.context.dataIndexs.Contains(serieData.index))
|
||
{
|
||
serieData.SetLabelActive(false);
|
||
continue;
|
||
}
|
||
var currLabel = SerieHelper.GetSerieLabel(serie, serieData);
|
||
var isIgnore = serie.IsIgnoreIndex(serieData.index, defaultDimension);
|
||
if (serie.show &&
|
||
currLabel != null &&
|
||
currLabel.show &&
|
||
serieData.context.canShowLabel &&
|
||
!serieData.context.isClip &&
|
||
!isIgnore)
|
||
{
|
||
if (serie.multiDimensionLabel)
|
||
{
|
||
var total = serieData.GetTotalData();
|
||
var color = chart.GetItemColor(serie, serieData);
|
||
for (int i = 0; i < serieData.context.dataLabels.Count; i++)
|
||
{
|
||
if (i >= serieData.context.dataPoints.Count) continue;
|
||
var labelObject = serieData.context.dataLabels[i];
|
||
var value = serieData.GetCurrData(i, dataAddDuration, dataChangeDuration, unscaledTime);
|
||
var content = string.IsNullOrEmpty(currLabel.formatter) ?
|
||
ChartCached.NumberToStr(value, currLabel.numericFormatter) :
|
||
SerieLabelHelper.GetFormatterContent(serie, serieData, value, total,
|
||
currLabel, color, chart);
|
||
var offset = GetSerieDataLabelOffset(serieData, currLabel);
|
||
var active = currLabel.show && !isIgnore && !serie.IsMinShowLabelValue(value);
|
||
if (active) active = CheckLabelVisible(currLabel, serieData.index, value, i);
|
||
if (active)
|
||
{
|
||
anyLabelActive = true;
|
||
if (!ChartHelper.IsZeroVector(serieData.context.dataPoints[i]))
|
||
{
|
||
allLabelZeroPosition = false;
|
||
}
|
||
}
|
||
labelObject.SetActive(active);
|
||
labelObject.SetText(content);
|
||
labelObject.SetPosition(serieData.context.dataPoints[i] + offset);
|
||
labelObject.UpdateIcon(currLabel.icon);
|
||
if (currLabel.textStyle.autoColor)
|
||
{
|
||
var dataAutoColor = GetSerieDataAutoColor(serieData);
|
||
if (!ChartHelper.IsClearColor(dataAutoColor))
|
||
labelObject.SetTextColor(dataAutoColor);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var value = serieData.GetCurrData(defaultDimension, dataAddDuration, dataChangeDuration, unscaledTime);
|
||
var total = serie.GetDataTotal(defaultDimension, serieData);
|
||
var color = chart.GetItemColor(serie, serieData);
|
||
var content = string.IsNullOrEmpty(currLabel.formatter) ?
|
||
ChartCached.NumberToStr(value, currLabel.numericFormatter) :
|
||
SerieLabelHelper.GetFormatterContent(serie, serieData, value, total,
|
||
currLabel, color, chart);
|
||
var labelPos = UpdateLabelPosition(serieData, currLabel);
|
||
var active = currLabel.show && !isIgnore && !serie.IsMinShowLabelValue(value);
|
||
if (active) active = CheckLabelVisible(currLabel, serieData.index, value, defaultDimension);
|
||
if (active && currLabel.showMinGap > 0 && lastActiveLabelSerieData != null)
|
||
{
|
||
var dist = Mathf.Abs(labelPos.x - lastActiveLabelPos.x);
|
||
if (dist < currLabel.showMinGap)
|
||
{
|
||
var currValue = serieData.GetData(1);
|
||
if (Math.Abs(currValue) >= Math.Abs(lastActiveLabelValue))
|
||
{
|
||
lastActiveLabelSerieData.SetLabelActive(false);
|
||
lastActiveLabelSerieData = serieData;
|
||
lastActiveLabelPos = labelPos;
|
||
lastActiveLabelValue = currValue;
|
||
}
|
||
else
|
||
{
|
||
active = false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
lastActiveLabelSerieData = serieData;
|
||
lastActiveLabelPos = labelPos;
|
||
lastActiveLabelValue = serieData.GetData(1);
|
||
}
|
||
}
|
||
else if (active)
|
||
{
|
||
lastActiveLabelSerieData = serieData;
|
||
lastActiveLabelPos = labelPos;
|
||
lastActiveLabelValue = serieData.GetData(1);
|
||
}
|
||
if (active)
|
||
{
|
||
anyLabelActive = true;
|
||
if (!ChartHelper.IsZeroVector(labelPos))
|
||
{
|
||
allLabelZeroPosition = false;
|
||
}
|
||
}
|
||
serieData.SetLabelActive(active);
|
||
serieData.labelObject.UpdateIcon(currLabel.icon);
|
||
serieData.labelObject.SetText(content);
|
||
if (currLabel.textStyle.autoColor)
|
||
{
|
||
var dataAutoColor = GetSerieDataAutoColor(serieData);
|
||
if (!ChartHelper.IsClearColor(dataAutoColor))
|
||
serieData.labelObject.SetTextColor(dataAutoColor);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
serieData.SetLabelActive(false);
|
||
}
|
||
}
|
||
if (anyLabelActive && allLabelZeroPosition)
|
||
{
|
||
foreach (var serieData in serie.data)
|
||
{
|
||
serieData.SetLabelActive(false);
|
||
}
|
||
}
|
||
}
|
||
|
||
private bool CheckLabelVisible(LabelStyle label, int dataIndex, double value, int dimension)
|
||
{
|
||
// showCondition: 基于阈值的条件检查(AND showFilter)
|
||
bool conditionResult;
|
||
switch (label.showCondition)
|
||
{
|
||
case LabelStyle.ShowCondition.GreaterThan:
|
||
conditionResult = value > label.showThreshold;
|
||
break;
|
||
case LabelStyle.ShowCondition.LessThan:
|
||
conditionResult = value < label.showThreshold;
|
||
break;
|
||
default: // Always
|
||
conditionResult = true;
|
||
break;
|
||
}
|
||
|
||
if (!conditionResult)
|
||
return false;
|
||
|
||
// showFilter: 基于数据形态的过滤检查
|
||
switch (label.showFilter)
|
||
{
|
||
case LabelStyle.ShowFilter.Peak:
|
||
{
|
||
bool isPeak = true;
|
||
bool hasNeighbor = false;
|
||
if (dataIndex > 0)
|
||
{
|
||
hasNeighbor = true;
|
||
isPeak &= value > serie.data[dataIndex - 1].GetData(dimension);
|
||
}
|
||
if (dataIndex < serie.dataCount - 1)
|
||
{
|
||
hasNeighbor = true;
|
||
isPeak &= value > serie.data[dataIndex + 1].GetData(dimension);
|
||
}
|
||
return isPeak && hasNeighbor;
|
||
}
|
||
case LabelStyle.ShowFilter.Valley:
|
||
{
|
||
bool isValley = true;
|
||
bool hasNeighbor = false;
|
||
if (dataIndex > 0)
|
||
{
|
||
hasNeighbor = true;
|
||
isValley &= value < serie.data[dataIndex - 1].GetData(dimension);
|
||
}
|
||
if (dataIndex < serie.dataCount - 1)
|
||
{
|
||
hasNeighbor = true;
|
||
isValley &= value < serie.data[dataIndex + 1].GetData(dimension);
|
||
}
|
||
return isValley && hasNeighbor;
|
||
}
|
||
default: // All
|
||
return true;
|
||
}
|
||
}
|
||
|
||
public virtual void RefreshEndLabelInternal()
|
||
{
|
||
if (m_EndLabel == null)
|
||
return;
|
||
var endLabelStyle = serie.endLabel;
|
||
if (endLabelStyle == null)
|
||
return;
|
||
var dataCount = serie.context.dataPoints.Count;
|
||
var active = endLabelStyle.show && dataCount > 0 && !ChartHelper.IsZeroVector(serie.context.lineEndPostion);
|
||
m_EndLabel.SetActive(active);
|
||
if (active)
|
||
{
|
||
var value = serie.context.lineEndValueY;
|
||
var content = SerieLabelHelper.GetFormatterContent(serie, null, value, 0,
|
||
endLabelStyle, Color.clear);
|
||
m_EndLabel.SetText(content);
|
||
m_EndLabel.SetPosition(serie.context.lineEndPostion + endLabelStyle.offset);
|
||
}
|
||
m_EndLabel.isAnimationEnd = serie.animation.IsFinish();
|
||
}
|
||
|
||
protected Vector3 UpdateLabelPosition(SerieData serieData, LabelStyle currLabel)
|
||
{
|
||
var labelPosition = GetSerieDataLabelPosition(serieData, currLabel);
|
||
if (currLabel.fixedX != 0) labelPosition.x = currLabel.fixedX;
|
||
if (currLabel.fixedY != 0) labelPosition.y = currLabel.fixedY;
|
||
var offset = GetSerieDataLabelOffset(serieData, currLabel);
|
||
serieData.labelObject.SetPosition(labelPosition + offset);
|
||
if (currLabel.autoRotate && serieData.context.angle != 0)
|
||
{
|
||
if (serieData.context.angle > 90 && serieData.context.angle < 270)
|
||
serieData.labelObject.SetRotate(180 - serieData.context.angle + currLabel.rotate);
|
||
else
|
||
serieData.labelObject.SetRotate(-serieData.context.angle + currLabel.rotate);
|
||
}
|
||
return labelPosition;
|
||
}
|
||
|
||
public virtual Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label)
|
||
{
|
||
return ChartHelper.IsZeroVector(serieData.context.labelPosition) ?
|
||
serieData.context.position :
|
||
serieData.context.labelPosition;
|
||
}
|
||
|
||
public virtual Vector3 GetSerieDataLabelOffset(SerieData serieData, LabelStyle label)
|
||
{
|
||
return label.GetOffset(serie.context.insideRadius);
|
||
}
|
||
|
||
public virtual Vector3 GetSerieDataTitlePosition(SerieData serieData, TitleStyle titleStyle)
|
||
{
|
||
return serieData.context.position;
|
||
}
|
||
|
||
public virtual Color GetSerieDataAutoColor(SerieData serieData)
|
||
{
|
||
var colorIndex = serie.colorByData ? serieData.index : serie.index;
|
||
Color32 color, toColor;
|
||
SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal, false);
|
||
return (Color)color;
|
||
}
|
||
|
||
protected void UpdateCoordSerieParams(ref List<SerieParams> paramList, ref string title,
|
||
int dataIndex, bool showCategory, string category, string marker,
|
||
string itemFormatter, string numericFormatter, string ignoreDataDefaultContent)
|
||
{
|
||
var dimension = 1;
|
||
if (dataIndex < 0)
|
||
dataIndex = serie.context.pointerItemDataIndex;
|
||
|
||
if (dataIndex < 0)
|
||
return;
|
||
|
||
var serieData = serie.GetSerieData(dataIndex);
|
||
if (serieData == null)
|
||
return;
|
||
|
||
var ignore = serie.IsIgnoreValue(serieData, dimension);
|
||
if (ignore && string.IsNullOrEmpty(ignoreDataDefaultContent))
|
||
return;
|
||
|
||
itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
|
||
if (serie.placeHolder || TooltipHelper.IsIgnoreFormatter(itemFormatter))
|
||
return;
|
||
if (itemFormatter == null) itemFormatter = "";
|
||
var newItemFormatter = itemFormatter.Replace("\\n", "\n");
|
||
var newNumericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
|
||
var needTotal = newItemFormatter.IndexOf("{d", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||
newItemFormatter.IndexOf("{f", System.StringComparison.OrdinalIgnoreCase) >= 0;
|
||
var total = needTotal ? serie.yTotal : 0;
|
||
int newLinePos = newItemFormatter.IndexOf('\n');
|
||
if (newLinePos < 0)
|
||
{
|
||
var formatter = newItemFormatter;
|
||
var param = serie.context.param;
|
||
param.serieName = serie.serieName;
|
||
param.serieIndex = serie.index;
|
||
param.category = category;
|
||
param.dimension = dimension;
|
||
param.serieData = serieData;
|
||
param.dataCount = serie.dataCount;
|
||
param.value = serieData.GetData(dimension);
|
||
param.ignore = ignore;
|
||
param.total = total;
|
||
param.color = chart.GetMarkColor(serie, serieData);
|
||
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
|
||
param.itemFormatter = formatter;
|
||
param.numericFormatter = newNumericFormatter;
|
||
param.columns.Clear();
|
||
|
||
param.columns.Add(param.marker);
|
||
param.columns.Add(showCategory ? category : serie.serieName);
|
||
param.columns.Add(ignore ? ignoreDataDefaultContent : ChartCached.NumberToStr(param.value, param.numericFormatter));
|
||
|
||
paramList.Add(param);
|
||
}
|
||
else
|
||
{
|
||
var temp = newItemFormatter.Split('\n');
|
||
for (int i = 0; i < temp.Length; i++)
|
||
{
|
||
var formatter = temp[i];
|
||
var param = i == 0 ? serie.context.param : new SerieParams();
|
||
param.serieName = serie.serieName;
|
||
param.serieIndex = serie.index;
|
||
param.category = category;
|
||
param.dimension = dimension;
|
||
param.serieData = serieData;
|
||
param.dataCount = serie.dataCount;
|
||
param.value = serieData.GetData(dimension);
|
||
param.ignore = ignore;
|
||
param.total = total;
|
||
param.color = chart.GetMarkColor(serie, serieData);
|
||
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
|
||
param.itemFormatter = formatter;
|
||
param.numericFormatter = newNumericFormatter;
|
||
param.columns.Clear();
|
||
|
||
param.columns.Add(param.marker);
|
||
param.columns.Add(showCategory ? category : serie.serieName);
|
||
param.columns.Add(ignore ? ignoreDataDefaultContent : ChartCached.NumberToStr(param.value, param.numericFormatter));
|
||
|
||
paramList.Add(param);
|
||
}
|
||
}
|
||
}
|
||
|
||
protected void UpdateItemSerieParams(ref List<SerieParams> paramList, ref string title,
|
||
int dataIndex, string category, string marker,
|
||
string itemFormatter, string numericFormatter, string ignoreDataDefaultContent,
|
||
int dimension = 1, int colorIndex = -1)
|
||
{
|
||
if (dataIndex < 0)
|
||
dataIndex = serie.context.pointerItemDataIndex;
|
||
|
||
if (dataIndex < 0)
|
||
return;
|
||
|
||
var serieData = serie.GetSerieData(dataIndex);
|
||
if (serieData == null)
|
||
return;
|
||
|
||
var ignore = serie.IsIgnoreValue(serieData, dimension);
|
||
if (ignore && string.IsNullOrEmpty(ignoreDataDefaultContent))
|
||
return;
|
||
|
||
itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
|
||
if (serie.placeHolder || TooltipHelper.IsIgnoreFormatter(itemFormatter))
|
||
return;
|
||
|
||
if (colorIndex < 0)
|
||
colorIndex = serie.colorByData ? dataIndex : chart.GetLegendRealShowNameIndex(serieData.name);
|
||
|
||
Color32 color, toColor;
|
||
SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal);
|
||
|
||
if (itemFormatter == null) itemFormatter = "";
|
||
var newItemFormatter = itemFormatter.Replace("\\n", "\n");
|
||
var newNumericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
|
||
var temp = newItemFormatter.Split('\n');
|
||
var mark = SerieHelper.GetItemMarker(serie, serieData, marker);
|
||
var total = serie.multiDimensionLabel ? serieData.GetTotalData() : serie.GetDataTotal(defaultDimension);
|
||
for (int i = 0; i < temp.Length; i++)
|
||
{
|
||
var formatter = temp[i];
|
||
var param = i == 0 ? serie.context.param : new SerieParams();
|
||
param.serieName = serie.serieName;
|
||
param.serieIndex = serie.index;
|
||
|
||
param.category = category;
|
||
param.dimension = dimension;
|
||
param.serieData = serieData;
|
||
param.dataCount = serie.dataCount;
|
||
param.value = serieData.GetData(param.dimension);
|
||
param.ignore = ignore;
|
||
param.total = total;
|
||
param.color = color;
|
||
param.marker = mark;
|
||
param.itemFormatter = formatter;
|
||
param.numericFormatter = newNumericFormatter;
|
||
param.columns.Clear();
|
||
|
||
param.columns.Add(param.marker);
|
||
param.columns.Add(serieData.name);
|
||
|
||
param.columns.Add(ignore ? ignoreDataDefaultContent : ChartCached.NumberToStr(param.value, param.numericFormatter));
|
||
|
||
paramList.Add(param);
|
||
}
|
||
}
|
||
|
||
public void DrawLabelLineSymbol(VertexHelper vh, LabelLine labelLine, Vector3 startPos, Vector3 endPos, Color32 defaultColor)
|
||
{
|
||
if (labelLine.startSymbol != null && labelLine.startSymbol.show)
|
||
{
|
||
DrawSymbol(vh, labelLine.startSymbol, startPos, defaultColor);
|
||
}
|
||
if (labelLine.endSymbol != null && labelLine.endSymbol.show)
|
||
{
|
||
DrawSymbol(vh, labelLine.endSymbol, endPos, defaultColor);
|
||
}
|
||
}
|
||
|
||
private void DrawSymbol(VertexHelper vh, SymbolStyle symbol, Vector3 pos, Color32 defaultColor)
|
||
{
|
||
var color = symbol.GetColor(defaultColor);
|
||
chart.DrawSymbol(vh, symbol.type, symbol.size, 1, pos,
|
||
color, color, ColorUtil.clearColor32, color, symbol.gap, null, symbol.size2);
|
||
}
|
||
|
||
public override void OnPointerDown(PointerEventData eventData)
|
||
{
|
||
if (serie.onDown == null && chart.onSerieDown == null) return;
|
||
if (!serie.context.pointerEnter) return;
|
||
var dataIndex = GetPointerItemDataIndex();
|
||
if (dataIndex < 0) return;
|
||
var dimension = GetPointerItemDataDimension();
|
||
var value = serie.GetData(dataIndex, dimension);
|
||
var data = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value);
|
||
if (chart.onSerieDown != null)
|
||
chart.onSerieDown(data);
|
||
if (serie.onDown != null)
|
||
serie.onDown(data);
|
||
SerieEventDataPool.Release(data);
|
||
}
|
||
|
||
public override void OnPointerClick(PointerEventData eventData)
|
||
{
|
||
serie.context.clickTotalDataIndex = serie.context.totalDataIndex;
|
||
if (serie.onClick == null && chart.onSerieClick == null) return;
|
||
if (!serie.context.pointerEnter) return;
|
||
var dataIndex = GetPointerItemDataIndex();
|
||
if (dataIndex < 0) return;
|
||
var dimension = GetPointerItemDataDimension();
|
||
var value = serie.GetData(dataIndex, dimension);
|
||
var data = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value);
|
||
if (chart.onSerieClick != null)
|
||
chart.onSerieClick(data);
|
||
if (serie.onClick != null)
|
||
serie.onClick(data);
|
||
SerieEventDataPool.Release(data);
|
||
}
|
||
|
||
public override int GetPointerItemDataIndex()
|
||
{
|
||
return serie.context.pointerItemDataIndex;
|
||
}
|
||
|
||
public override int GetPointerItemDataDimension()
|
||
{
|
||
return serie.context.pointerItemDataDimension;
|
||
}
|
||
}
|
||
} |