/************************************************/ /* */ /* Copyright (c) 2018 - 2021 monitor1394 */ /* https://github.com/monitor1394 */ /* */ /************************************************/ using System.Linq; using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; using System; using UnityEngine.EventSystems; using XUGL; namespace XCharts { /// /// the layout is horizontal or vertical. /// 垂直还是水平布局方式。 /// public enum Orient { /// /// 水平 /// Horizonal, /// /// 垂直 /// Vertical } public partial class BaseChart : BaseGraph { protected static readonly string s_TitleObjectName = "title"; protected static readonly string s_SubTitleObjectName = "title_sub"; protected static readonly string s_LegendObjectName = "legend"; protected static readonly string s_SerieLabelObjectName = "label"; protected static readonly string s_SerieTitleObjectName = "serie"; [SerializeField] protected string m_ChartName; [SerializeField] protected ChartTheme m_Theme; [SerializeField] protected Settings m_Settings; [SerializeField] protected List m_Titles = new List<Title>() { Title.defaultTitle }; [SerializeField] protected List<Legend> m_Legends = new List<Legend>() { Legend.defaultLegend }; [SerializeField] protected List<Tooltip> m_Tooltips = new List<Tooltip>() { Tooltip.defaultTooltip }; [SerializeField] protected List<Grid> m_Grids = new List<Grid>(); [SerializeField] protected List<XAxis> m_XAxes = new List<XAxis>(); [SerializeField] protected List<YAxis> m_YAxes = new List<YAxis>(); [SerializeField] protected List<DataZoom> m_DataZooms = new List<DataZoom>(); [SerializeField] protected List<VisualMap> m_VisualMaps = new List<VisualMap>(); [SerializeField] protected List<Vessel> m_Vessels = new List<Vessel>(); [SerializeField] protected List<Polar> m_Polars = new List<Polar>(); [SerializeField] protected List<RadiusAxis> m_RadiusAxes = new List<RadiusAxis>(); [SerializeField] protected List<AngleAxis> m_AngleAxes = new List<AngleAxis>(); [SerializeField] protected List<Radar> m_Radars = new List<Radar>(); [SerializeField] protected Series m_Series = Series.defaultSeries; protected float m_ChartWidth; protected float m_ChartHeight; protected float m_ChartX; protected float m_ChartY; protected Vector3 m_ChartPosition = Vector3.zero; protected Vector2 m_ChartMinAnchor; protected Vector2 m_ChartMaxAnchor; protected Vector2 m_ChartPivot; protected Vector2 m_ChartSizeDelta; protected Rect m_ChartRect = new Rect(0, 0, 0, 0); protected Action<VertexHelper> m_OnCustomDrawBaseCallback; protected Action<VertexHelper> m_OnCustomDrawTopCallback; protected Action<VertexHelper, Serie> m_OnCustomDrawSerieBeforeCallback; protected Action<VertexHelper, Serie> m_OnCustomDrawSerieAfterCallback; protected Action<PointerEventData, int, int> m_OnPointerClickPie; protected bool m_RefreshLabel = false; internal bool m_ReinitLabel = false; internal bool m_ReinitTitle = false; internal bool m_CheckAnimation = false; internal bool m_IsPlayingAnimation = false; internal protected List<string> m_LegendRealShowName = new List<string>(); protected List<Painter> m_PainterList = new List<Painter>(); internal Painter m_PainterTop; protected GameObject m_SerieLabelRoot; private Theme m_CheckTheme = 0; protected List<IDrawSerie> m_DrawSeries = new List<IDrawSerie>(); protected List<IComponentHandler> m_ComponentHandlers = new List<IComponentHandler>(); protected override void InitComponent() { base.InitComponent(); InitTitles(); InitLegends(); InitSerieLabel(); InitSerieTitle(); InitTooltip(); m_DrawSeries.Clear(); m_DrawSeries.Add(new DrawSeriePie(this)); m_DrawSeries.Add(new DrawSerieRing(this)); m_DrawSeries.Add(new DrawSerieGauge(this)); m_DrawSeries.Add(new DrawSerieLiquid(this)); m_DrawSeries.Add(new DrawSerieRadar(this)); foreach (var draw in m_DrawSeries) draw.InitComponent(); m_ComponentHandlers.Clear(); m_ComponentHandlers.Add(new VisualMapHandler(this)); m_ComponentHandlers.Add(new DataZoomHandler(this)); foreach (var draw in m_ComponentHandlers) draw.Init(); } protected override void Awake() { if (m_Settings == null) m_Settings = Settings.DefaultSettings; if (m_Series == null) m_Series = Series.defaultSeries; ; if (m_Titles.Count == 0) m_Titles = new List<Title>() { Title.defaultTitle }; if (m_Legends.Count == 0) m_Legends = new List<Legend>() { Legend.defaultLegend }; if (m_Tooltips.Count == 0) m_Tooltips = new List<Tooltip>() { Tooltip.defaultTooltip }; CheckTheme(); base.Awake(); AnimationReset(); AnimationFadeIn(); XChartsMgr.Instance.AddChart(this); } #if UNITY_EDITOR protected override void Reset() { base.Reset(); m_Theme = null; m_Settings = null; m_Series = null; m_Titles.Clear(); m_Legends.Clear(); m_Tooltips.Clear(); var sizeDelta = rectTransform.sizeDelta; if (sizeDelta.x < 580 && sizeDelta.y < 300) { rectTransform.sizeDelta = new Vector2(580, 300); } ChartHelper.HideAllObject(transform); Awake(); } #endif protected override void Start() { RefreshChart(); } protected override void Update() { CheckTheme(); base.Update(); CheckPainter(); CheckTooltip(); CheckRefreshChart(); CheckRefreshLabel(); Internal_CheckAnimation(); foreach (var draw in m_DrawSeries) draw.Update(); foreach (var draw in m_ComponentHandlers) draw.Update(); } public Painter GetPainter(int index) { if (index >= 0 && index < m_PainterList.Count) { return m_PainterList[index]; } return null; } public void RefreshBasePainter() { m_Painter.Refresh(); } public void RefreshTopPainter() { m_PainterTop.Refresh(); } public void RefreshPainter(int index) { var painter = GetPainter(index); RefreshPainter(painter); } public void RefreshPainter(Serie serie) { RefreshPainter(GetPainterIndexBySerie(serie)); } internal override void RefreshPainter(Painter painter) { base.RefreshPainter(painter); if (painter != null && painter.type == Painter.Type.Serie) { m_PainterTop.Refresh(); } } public void SetPainterActive(int index, bool flag) { var painter = GetPainter(index); if (painter == null) return; painter.SetActive(flag, m_DebugMode); } protected virtual void CheckTheme() { if (m_Theme == null) { m_Theme = ChartTheme.Default; } else { if (m_Theme.colorPalette.Count == 0) { m_Theme.ResetTheme(); } if (m_CheckTheme != m_Theme.theme) { m_CheckTheme = m_Theme.theme; m_Theme.CopyTheme(m_CheckTheme); #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(this); #endif SetAllComponentDirty(); OnThemeChanged(); } } } protected override void CheckComponent() { base.CheckComponent(); if (m_Series.anyDirty) { if (SeriesHelper.IsLabelDirty(m_Series)) m_ReinitLabel = true; if (SeriesHelper.IsNeedLabelUpdate(m_Series) && !m_RefreshChart) m_RefreshLabel = true; foreach (var serie in m_Series.list) { if (serie.titleStyle.componentDirty) m_ReinitTitle = true; if (serie.nameDirty) { foreach (var legend in m_Legends) legend.SetAllDirty(); RefreshChart(); serie.ClearNameDirty(); } if (serie.vertsDirty) { RefreshPainter(serie); } } m_Series.ClearDirty(); } if (m_Theme.anyDirty) { if (m_Theme.componentDirty) { foreach (var title in m_Titles) title.SetAllDirty(); foreach (var legend in m_Legends) legend.SetAllDirty(); tooltip.SetAllDirty(); } if (m_Theme.vertsDirty) RefreshChart(); m_Theme.ClearDirty(); } CheckComponentDirty(tooltip); foreach (var component in m_Titles) CheckComponentDirty(component); foreach (var component in m_Legends) CheckComponentDirty(component); foreach (var component in m_Tooltips) CheckComponentDirty(component); foreach (var component in m_DataZooms) CheckComponentDirty(component); foreach (var component in m_VisualMaps) CheckComponentDirty(component); foreach (var component in m_Grids) CheckComponentDirty(component); foreach (var component in m_XAxes) CheckComponentDirty(component); foreach (var component in m_YAxes) CheckComponentDirty(component); foreach (var component in m_Vessels) CheckComponentDirty(component); foreach (var component in m_Polars) CheckComponentDirty(component); foreach (var component in m_AngleAxes) CheckComponentDirty(component); foreach (var component in m_RadiusAxes) CheckComponentDirty(component); foreach (var component in m_Radars) CheckComponentDirty(component); foreach (var drawSerie in m_DrawSeries) drawSerie.CheckComponent(); } protected override void SetAllComponentDirty() { base.SetAllComponentDirty(); m_Theme.SetAllDirty(); foreach (var component in m_Titles) component.SetAllDirty(); foreach (var component in m_Legends) component.SetAllDirty(); foreach (var component in m_Tooltips) component.SetAllDirty(); foreach (var component in m_Grids) component.SetAllDirty(); foreach (var component in m_XAxes) component.SetAllDirty(); foreach (var component in m_YAxes) component.SetAllDirty(); foreach (var component in m_DataZooms) component.SetAllDirty(); foreach (var component in m_VisualMaps) component.SetAllDirty(); foreach (var component in m_Vessels) component.SetAllDirty(); foreach (var component in m_Polars) component.SetAllDirty(); foreach (var component in m_RadiusAxes) component.SetAllDirty(); foreach (var component in m_AngleAxes) component.SetAllDirty(); foreach (var component in m_Radars) component.SetAllDirty(); m_ReinitLabel = true; m_ReinitTitle = true; m_RefreshChart = true; } protected override void OnDestroy() { for (int i = transform.childCount - 1; i >= 0; i--) { DestroyImmediate(transform.GetChild(i).gameObject); } } protected virtual void CheckPainter() { for (int i = 0; i < m_Series.Count; i++) { var serie = m_Series.GetSerie(i); serie.index = i; SetPainterActive(i, true); } } protected override void InitPainter() { base.InitPainter(); m_Painter.material = settings.basePainterMaterial; m_PainterList.Clear(); if (settings == null) return; var sizeDelta = new Vector2(m_GraphWidth, m_GraphHeight); for (int i = 0; i < settings.maxPainter; i++) { var index = settings.reversePainter ? settings.maxPainter - 1 - i : i; var painter = ChartHelper.AddPainterObject("painter_" + index, transform, m_GraphMinAnchor, m_GraphMaxAnchor, m_GraphPivot, sizeDelta, chartHideFlags, 2 + index); painter.index = m_PainterList.Count; painter.type = Painter.Type.Serie; painter.onPopulateMesh = OnDrawPainterSerie; painter.SetActive(false, m_DebugMode); painter.material = settings.seriePainterMaterial; m_PainterList.Add(painter); } m_PainterTop = ChartHelper.AddPainterObject("painter_t", transform, m_GraphMinAnchor, m_GraphMaxAnchor, m_GraphPivot, sizeDelta, chartHideFlags, 2 + settings.maxPainter); m_PainterTop.type = Painter.Type.Top; m_PainterTop.onPopulateMesh = OnDrawPainterTop; m_PainterTop.SetActive(true, m_DebugMode); m_PainterTop.material = settings.topPainterMaterial; } private void InitTitles() { for (int i = 0; i < m_Titles.Count; i++) { var title = m_Titles[i]; title.index = i; InitTitle(title); } } private void InitTitle(Title title) { title.painter = null; title.refreshComponent = delegate () { title.OnChanged(); var anchorMin = title.location.runtimeAnchorMin; var anchorMax = title.location.runtimeAnchorMax; var pivot = title.location.runtimePivot; var titleObject = ChartHelper.AddObject(s_TitleObjectName + title.index, transform, anchorMin, anchorMax, pivot, m_ChartSizeDelta); title.gameObject = titleObject; anchorMin = title.location.runtimeAnchorMin; anchorMax = title.location.runtimeAnchorMax; pivot = title.location.runtimePivot; title.textStyle.UpdateAlignmentByLocation(title.location); title.subTextStyle.UpdateAlignmentByLocation(title.location); var fontSize = title.textStyle.GetFontSize(theme.title); ChartHelper.UpdateRectTransform(titleObject, anchorMin, anchorMax, pivot, new Vector2(chartWidth, chartHeight)); var titlePosition = GetTitlePosition(title); var subTitlePosition = -new Vector3(0, fontSize + title.itemGap, 0); var titleWid = chartWidth; titleObject.transform.localPosition = titlePosition; titleObject.hideFlags = chartHideFlags; ChartHelper.HideAllObject(titleObject); var titleText = ChartHelper.AddTextObject(s_TitleObjectName, titleObject.transform, anchorMin, anchorMax, pivot, new Vector2(titleWid, fontSize), title.textStyle, theme.title); titleText.SetActive(title.show); titleText.SetLocalPosition(Vector3.zero + title.textStyle.offsetv3); titleText.SetText(title.text); var subText = ChartHelper.AddTextObject(s_SubTitleObjectName, titleObject.transform, anchorMin, anchorMax, pivot, new Vector2(titleWid, title.subTextStyle.GetFontSize(theme.subTitle)), title.subTextStyle, theme.subTitle); subText.SetActive(title.show && !string.IsNullOrEmpty(title.subText)); subText.SetLocalPosition(subTitlePosition + title.subTextStyle.offsetv3); subText.SetText(title.subText); }; title.refreshComponent(); } private void InitLegends() { for (int i = 0; i < m_Legends.Count; i++) { var legend = m_Legends[i]; legend.index = i; InitLegend(legend); } } private void InitLegend(Legend legend) { legend.painter = null; // legend component does not need to paint legend.refreshComponent = delegate () { legend.OnChanged(); var legendObject = ChartHelper.AddObject(s_LegendObjectName + legend.index, transform, m_ChartMinAnchor, m_ChartMaxAnchor, m_ChartPivot, m_ChartSizeDelta); legend.gameObject = legendObject; legendObject.hideFlags = chartHideFlags; SeriesHelper.UpdateSerieNameList(this, ref m_LegendRealShowName); List<string> datas; if (legend.show && legend.data.Count > 0) { datas = new List<string>(); for (int i = 0; i < m_LegendRealShowName.Count; i++) { if (legend.data.Contains(m_LegendRealShowName[i])) datas.Add(m_LegendRealShowName[i]); } } else { datas = m_LegendRealShowName; } int totalLegend = 0; for (int i = 0; i < datas.Count; i++) { if (!SeriesHelper.IsLegalLegendName(datas[i])) continue; totalLegend++; } legend.RemoveButton(); ChartHelper.HideAllObject(legendObject); if (!legend.show) return; for (int i = 0; i < datas.Count; i++) { if (!SeriesHelper.IsLegalLegendName(datas[i])) continue; string legendName = legend.GetFormatterContent(datas[i]); var readIndex = m_LegendRealShowName.IndexOf(datas[i]); var active = IsActiveByLegend(datas[i]); var bgColor = LegendHelper.GetIconColor(this, readIndex, datas[i], active); var item = LegendHelper.AddLegendItem(legend, i, datas[i], legendObject.transform, m_Theme, legendName, bgColor, active, readIndex); legend.SetButton(legendName, item, totalLegend); ChartHelper.ClearEventListener(item.button.gameObject); ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerDown, (data) => { if (data.selectedObject == null || legend.selectedMode == Legend.SelectedMode.None) return; var temp = data.selectedObject.name.Split('_'); string selectedName = temp[1]; int clickedIndex = int.Parse(temp[0]); if (legend.selectedMode == Legend.SelectedMode.Multiple) { OnLegendButtonClick(clickedIndex, selectedName, !IsActiveByLegend(selectedName)); } else { var btnList = legend.buttonList.Values.ToArray(); if (btnList.Length == 1) { OnLegendButtonClick(0, selectedName, !IsActiveByLegend(selectedName)); } else { for (int n = 0; n < btnList.Length; n++) { temp = btnList[n].name.Split('_'); selectedName = btnList[n].legendName; var index = btnList[n].index; OnLegendButtonClick(n, selectedName, index == clickedIndex ? true : false); } } } }); ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerEnter, (data) => { if (item.button == null) return; var temp = item.button.name.Split('_'); string selectedName = temp[1]; int index = int.Parse(temp[0]); OnLegendButtonEnter(index, selectedName); }); ChartHelper.AddEventListener(item.button.gameObject, EventTriggerType.PointerExit, (data) => { if (item.button == null) return; var temp = item.button.name.Split('_'); string selectedName = temp[1]; int index = int.Parse(temp[0]); OnLegendButtonExit(index, selectedName); }); } if (legend.selectedMode == Legend.SelectedMode.Single) { for (int n = 0; n < m_LegendRealShowName.Count; n++) { OnLegendButtonClick(n, m_LegendRealShowName[n], n == 0 ? true : false); } } LegendHelper.ResetItemPosition(legend, m_ChartPosition, m_ChartWidth, m_ChartHeight); }; legend.refreshComponent(); } private void InitSerieLabel() { m_SerieLabelRoot = ChartHelper.AddObject(s_SerieLabelObjectName, transform, m_ChartMinAnchor, m_ChartMaxAnchor, m_ChartPivot, m_ChartSizeDelta); m_SerieLabelRoot.hideFlags = chartHideFlags; SerieLabelPool.ReleaseAll(m_SerieLabelRoot.transform); int count = 0; for (int i = 0; i < m_Series.Count; i++) { var serie = m_Series.list[i]; serie.index = i; SerieHelper.UpdateCenter(serie, chartPosition, chartWidth, chartHeight); for (int j = 0; j < serie.data.Count; j++) { var serieData = serie.data[j]; serieData.index = count; serieData.labelObject = null; AddSerieLabel(serie, serieData, ref count); count++; } } SerieLabelHelper.UpdateLabelText(m_Series, m_Theme, m_LegendRealShowName); } protected void AddSerieLabel(Serie serie, SerieData serieData, ref int count) { if (m_SerieLabelRoot == null) return; if (count == -1) count = serie.dataCount; var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); var iconStyle = SerieHelper.GetIconStyle(serie, serieData); if (serie.IsPerformanceMode()) return; if (!serieLabel.show && !iconStyle.show) return; if (serie.animation.enable && serie.animation.HasFadeOut()) return; var textName = ChartCached.GetSerieLabelName(s_SerieLabelObjectName, serie.index, serieData.index); var color = Color.grey; if (serie.type == SerieType.Pie) { color = (serieLabel.position == SerieLabel.Position.Inside) ? Color.white : (Color)m_Theme.GetColor(count); } else { color = !ChartHelper.IsClearColor(serieLabel.textStyle.color) ? serieLabel.textStyle.color : (Color)m_Theme.GetColor(serie.index); } var labelObj = SerieLabelPool.Get(textName, m_SerieLabelRoot.transform, serieLabel, color, iconStyle.width, iconStyle.height, theme); var iconImage = labelObj.transform.Find("Icon").GetComponent<Image>(); var isAutoSize = serieLabel.backgroundWidth == 0 || serieLabel.backgroundHeight == 0; var item = new ChartLabel(); item.SetLabel(labelObj, isAutoSize, serieLabel.paddingLeftRight, serieLabel.paddingTopBottom); item.SetIcon(iconImage); item.SetIconActive(iconStyle.show); serieData.labelObject = item; foreach (var dataIndex in serieData.children) { AddSerieLabel(serie, serie.GetSerieData(dataIndex), ref count); count++; } } private void InitSerieTitle() { var titleObject = ChartHelper.AddObject(s_SerieTitleObjectName, transform, m_ChartMinAnchor, m_ChartMaxAnchor, m_ChartPivot, new Vector2(chartWidth, chartHeight)); titleObject.hideFlags = chartHideFlags; ChartHelper.HideAllObject(titleObject); for (int i = 0; i < m_Series.Count; i++) { var serie = m_Series.list[i]; var textStyle = serie.titleStyle.textStyle; var titleColor = ChartHelper.IsClearColor(textStyle.color) ? m_Theme.GetColor(i) : (Color32)textStyle.color; var anchorMin = new Vector2(0.5f, 0.5f); var anchorMax = new Vector2(0.5f, 0.5f); var pivot = new Vector2(0.5f, 0.5f); var fontSize = 10; var sizeDelta = new Vector2(50, fontSize + 2); var txt = ChartHelper.AddTextObject("title_" + i, titleObject.transform, anchorMin, anchorMax, pivot, sizeDelta, textStyle, theme.common); txt.SetText(""); txt.SetColor(titleColor); txt.SetLocalPosition(Vector2.zero); txt.SetLocalEulerAngles(Vector2.zero); txt.SetActive(serie.titleStyle.show); serie.titleStyle.runtimeText = txt; serie.titleStyle.UpdatePosition(serie.runtimeCenterPos); var serieData = serie.GetSerieData(0); if (serieData != null) { txt.SetText(serieData.name); } } } private void InitTooltip() { tooltip.painter = m_PainterTop; tooltip.refreshComponent = delegate () { tooltip.gameObject = ChartHelper.AddObject("tooltip", transform, m_ChartMinAnchor, m_ChartMaxAnchor, m_ChartPivot, m_ChartSizeDelta); var tooltipObject = tooltip.gameObject; tooltipObject.transform.localPosition = Vector3.zero; tooltipObject.hideFlags = chartHideFlags; DestroyImmediate(tooltipObject.GetComponent<Image>()); var parent = tooltipObject.transform; var textStyle = tooltip.textStyle; ChartHelper.HideAllObject(tooltipObject.transform); GameObject content = ChartHelper.AddTooltipContent("content", parent, textStyle, m_Theme); tooltip.SetObj(tooltipObject); tooltip.SetContentObj(content); tooltip.SetContentBackgroundColor(TooltipHelper.GetTexBackgroundColor(tooltip, m_Theme.tooltip)); tooltip.SetContentTextColor(TooltipHelper.GetTexColor(tooltip, m_Theme.tooltip)); tooltip.SetActive(false); }; tooltip.refreshComponent(); } private Vector3 GetLegendPosition(Legend legend, int i) { return legend.location.GetPosition(chartWidth, chartHeight); } protected override bool IsNeedCheckPointerPos() { return (tooltip.show && tooltip.runtimeInited) || raycastTarget; } private void CheckTooltip() { if (!isPointerInChart || !tooltip.show || !tooltip.runtimeInited) { if (tooltip.IsActive()) { tooltip.ClearValue(); tooltip.SetActive(false); m_PainterTop.Refresh(); } return; } for (int i = 0; i < tooltip.runtimeDataIndex.Count; i++) { tooltip.runtimeDataIndex[i] = -1; } Vector2 local = pointerPos; if (canvas == null) return; if (local == Vector2.zero) { if (tooltip.IsActive()) { tooltip.SetActive(false); m_PainterTop.Refresh(); } return; } if (!IsInChart(local)) { if (tooltip.IsActive()) { tooltip.SetActive(false); m_PainterTop.Refresh(); } return; } tooltip.runtimePointerPos = local; CheckAllTooptip(local); } private void CheckAllTooptip(Vector2 localPostion) { tooltip.runtimeGridIndex = -1; var actived = false; foreach (var draw in m_DrawSeries) actived = actived || draw.CheckTootipArea(localPostion); CheckTootipArea(localPostion, actived); } protected virtual void CheckTootipArea(Vector2 localPostion, bool isActivedOther) { } protected override void CheckRefreshChart() { if (m_Painter == null) return; if (m_RefreshChart) { m_Painter.Refresh(); foreach (var painter in m_PainterList) painter.Refresh(); if (m_PainterTop != null) m_PainterTop.Refresh(); m_RefreshChart = false; } } protected override void CheckRefreshPainter() { if (m_Painter == null) return; m_Painter.CheckRefresh(); foreach (var painter in m_PainterList) painter.CheckRefresh(); if (m_PainterTop != null) m_PainterTop.CheckRefresh(); } protected void CheckRefreshLabel() { if (m_ReinitLabel) { m_ReinitLabel = false; SeriesHelper.UpdateSerieNameList(this, ref m_LegendRealShowName); InitSerieLabel(); } if (m_ReinitTitle) { m_ReinitTitle = false; InitSerieTitle(); } if (m_RefreshLabel) { m_RefreshLabel = false; OnRefreshLabel(); } } public void Internal_CheckAnimation() { if (!m_CheckAnimation) { m_CheckAnimation = true; AnimationFadeIn(); } } protected virtual void OnRefreshLabel() { foreach (var drawSerie in m_DrawSeries) drawSerie.RefreshLabel(); } protected override void OnSizeChanged() { base.OnSizeChanged(); m_ChartWidth = m_GraphWidth; m_ChartHeight = m_GraphHeight; m_ChartX = m_GraphX; m_ChartY = m_GraphY; m_ChartPosition = m_GraphPosition; m_ChartMinAnchor = m_GraphMinAnchor; m_ChartMaxAnchor = m_GraphMaxAnchor; m_ChartPivot = m_GraphPivot; m_ChartSizeDelta = m_GraphSizeDelta; m_ChartRect = m_GraphRect; SetAllComponentDirty(); m_Series.SetLabelDirty(); m_ReinitLabel = true; RefreshChart(); } protected override void OnLocalPositionChanged() { m_Background.SetAllDirty(); } protected virtual void OnThemeChanged() { } protected virtual void OnYMaxValueChanged() { } public virtual void OnDataZoomRangeChanged(DataZoom dataZoom) { } public override void OnPointerDown(PointerEventData eventData) { base.OnPointerDown(eventData); foreach (var drawSerie in m_DrawSeries) drawSerie.OnPointerDown(eventData); foreach (var handler in m_ComponentHandlers) handler.OnPointerDown(eventData); } public override void OnBeginDrag(PointerEventData eventData) { base.OnBeginDrag(eventData); foreach (var handler in m_ComponentHandlers) handler.OnBeginDrag(eventData); } public override void OnDrag(PointerEventData eventData) { base.OnDrag(eventData); foreach (var handler in m_ComponentHandlers) handler.OnDrag(eventData); } public override void OnEndDrag(PointerEventData eventData) { base.OnEndDrag(eventData); foreach (var handler in m_ComponentHandlers) handler.OnEndDrag(eventData); } public override void OnScroll(PointerEventData eventData) { base.OnScroll(eventData); foreach (var handler in m_ComponentHandlers) handler.OnScroll(eventData); } protected virtual void OnLegendButtonClick(int index, string legendName, bool show) { var clicked = false; foreach (var drawSerie in m_DrawSeries) clicked = clicked || drawSerie.OnLegendButtonClick(index, legendName, show); if (!clicked) { foreach (var serie in m_Series.GetSeries(legendName)) { SetActive(serie.index, show); RefreshPainter(serie); } OnYMaxValueChanged(); } } protected virtual void OnLegendButtonEnter(int index, string legendName) { var enter = false; foreach (var drawSerie in m_DrawSeries) enter = enter || drawSerie.OnLegendButtonEnter(index, legendName); if (!enter) { foreach (var serie in m_Series.GetSeries(legendName)) { serie.highlighted = true; RefreshPainter(serie); } } } protected virtual void OnLegendButtonExit(int index, string legendName) { var exit = false; foreach (var drawSerie in m_DrawSeries) exit = exit || drawSerie.OnLegendButtonExit(index, legendName); if (!exit) { foreach (var serie in m_Series.GetSeries(legendName)) { serie.highlighted = false; RefreshPainter(serie); } } } protected virtual void UpdateTooltip() { } protected override void OnDrawPainterBase(VertexHelper vh, Painter painter) { vh.Clear(); DrawBackground(vh); DrawPainterBase(vh); foreach (var draw in m_ComponentHandlers) draw.DrawBase(vh); foreach (var draw in m_DrawSeries) draw.DrawBase(vh); if (m_OnCustomDrawBaseCallback != null) { m_OnCustomDrawBaseCallback(vh); } } protected virtual void OnDrawPainterSerie(VertexHelper vh, Painter painter) { vh.Clear(); var maxPainter = settings.maxPainter; var maxSeries = m_Series.Count; var rate = Mathf.CeilToInt(maxSeries * 1.0f / maxPainter); m_PainterTop.Refresh(); for (int i = painter.index * rate; i < (painter.index + 1) * rate && i < maxSeries; i++) { var serie = m_Series.GetSerie(i); if (m_OnCustomDrawSerieBeforeCallback != null) { m_OnCustomDrawSerieBeforeCallback.Invoke(vh, serie); } DrawPainterSerie(vh, serie); if (m_OnCustomDrawSerieAfterCallback != null) { m_OnCustomDrawSerieAfterCallback(vh, serie); } } m_RefreshLabel = true; } protected virtual void OnDrawPainterTop(VertexHelper vh, Painter painter) { vh.Clear(); DrawLegend(vh); DrawPainterTop(vh); foreach (var draw in m_ComponentHandlers) draw.DrawTop(vh); if (m_OnCustomDrawTopCallback != null) { m_OnCustomDrawTopCallback(vh); } DrawTooltip(vh); } protected virtual void DrawPainterSerie(VertexHelper vh, Serie serie) { foreach (var drawSerie in m_DrawSeries) { drawSerie.DrawSerie(vh, serie); } } protected virtual void DrawPainterTop(VertexHelper vh) { } protected virtual void DrawTooltip(VertexHelper vh) { } protected override void DrawBackground(VertexHelper vh) { Vector3 p1 = new Vector3(chartX, chartY + chartHeight); Vector3 p2 = new Vector3(chartX + chartWidth, chartY + chartHeight); Vector3 p3 = new Vector3(chartX + chartWidth, chartY); Vector3 p4 = new Vector3(chartX, chartY); var backgroundColor = ThemeHelper.GetBackgroundColor(m_Theme, m_Background); UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, backgroundColor); } protected virtual void DrawLegend(VertexHelper vh) { if (m_Series.Count == 0) return; foreach (var legend in m_Legends) { if (!legend.show) continue; if (legend.iconType == Legend.Type.Custom) continue; foreach (var kv in legend.buttonList) { var item = kv.Value; var rect = item.GetIconRect(); var radius = Mathf.Min(rect.width, rect.height) / 2; var color = item.GetIconColor(); var iconType = legend.iconType; if (legend.iconType == Legend.Type.Auto) { var serie = m_Series.GetSerie(item.legendName); if (serie != null && serie.type == SerieType.Line) { var sp = new Vector3(rect.center.x - rect.width / 2, rect.center.y); var ep = new Vector3(rect.center.x + rect.width / 2, rect.center.y); UGL.DrawLine(vh, sp, ep, m_Settings.legendIconLineWidth, color); if (!serie.symbol.show) continue; switch (serie.symbol.type) { case SerieSymbolType.None: continue; case SerieSymbolType.Circle: iconType = Legend.Type.Circle; break; case SerieSymbolType.Diamond: iconType = Legend.Type.Diamond; break; case SerieSymbolType.EmptyCircle: iconType = Legend.Type.EmptyCircle; break; case SerieSymbolType.Rect: iconType = Legend.Type.Rect; break; case SerieSymbolType.Triangle: iconType = Legend.Type.Triangle; break; } } else { iconType = Legend.Type.Rect; } } switch (iconType) { case Legend.Type.Rect: var cornerRadius = m_Settings.legendIconCornerRadius; UGL.DrawRoundRectangle(vh, rect.center, rect.width, rect.height, color, color, 0, cornerRadius, false, 0.5f); break; case Legend.Type.Circle: UGL.DrawCricle(vh, rect.center, radius, color); break; case Legend.Type.Diamond: UGL.DrawDiamond(vh, rect.center, radius, color); break; case Legend.Type.EmptyCircle: var backgroundColor = ThemeHelper.GetBackgroundColor(m_Theme, m_Background); UGL.DrawEmptyCricle(vh, rect.center, radius, 2 * m_Settings.legendIconLineWidth, color, color, backgroundColor, 1f); break; case Legend.Type.Triangle: UGL.DrawTriangle(vh, rect.center, 1.2f * radius, color); break; } } } } public void DrawSymbol(VertexHelper vh, SerieSymbolType type, float symbolSize, float tickness, Vector3 pos, Color32 color, Color32 toColor, Color32 fillColor, float gap, float[] cornerRadius) { DrawSymbol(vh, type, symbolSize, tickness, pos, color, toColor, fillColor, gap, cornerRadius, Vector3.zero); } public void DrawSymbol(VertexHelper vh, SerieSymbolType type, float symbolSize, float tickness, Vector3 pos, Color32 color, Color32 toColor, Color32 fillColor, float gap, float[] cornerRadius, Vector3 startPos) { var backgroundColor = ThemeHelper.GetBackgroundColor(m_Theme, m_Background); if (ChartHelper.IsClearColor(fillColor)) fillColor = backgroundColor; var smoothness = settings.cicleSmoothness; ChartDrawer.DrawSymbol(vh, type, symbolSize, tickness, pos, color, toColor, gap, cornerRadius, fillColor, backgroundColor, smoothness, startPos); } public void DrawLabelBackground(VertexHelper vh, Serie serie, SerieData serieData) { if (serieData == null || serieData.labelObject == null) return; var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); if (!serieLabel.show) return; var invert = serieLabel.autoOffset && serie.type == SerieType.Line && SerieHelper.IsDownPoint(serie, serieData.index) && !serie.areaStyle.show; var centerPos = Vector3.zero; if (serie.type == SerieType.Pie) centerPos = SerieLabelHelper.GetRealLabelPosition(serieData, serieLabel); else centerPos = serieData.labelPosition + serieLabel.offset * (invert ? -1 : 1); var labelHalfWid = serieData.labelObject.GetLabelWidth() / 2; var labelHalfHig = serieData.GetLabelHeight() / 2; var p1 = new Vector3(centerPos.x - labelHalfWid, centerPos.y + labelHalfHig); var p2 = new Vector3(centerPos.x + labelHalfWid, centerPos.y + labelHalfHig); var p3 = new Vector3(centerPos.x + labelHalfWid, centerPos.y - labelHalfHig); var p4 = new Vector3(centerPos.x - labelHalfWid, centerPos.y - labelHalfHig); if (serieLabel.textStyle.rotate > 0) { p1 = ChartHelper.RotateRound(p1, centerPos, Vector3.forward, serieLabel.textStyle.rotate); p2 = ChartHelper.RotateRound(p2, centerPos, Vector3.forward, serieLabel.textStyle.rotate); p3 = ChartHelper.RotateRound(p3, centerPos, Vector3.forward, serieLabel.textStyle.rotate); p4 = ChartHelper.RotateRound(p4, centerPos, Vector3.forward, serieLabel.textStyle.rotate); } UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, serieLabel.textStyle.backgroundColor); if (serieLabel.border) { UGL.DrawBorder(vh, centerPos, serieData.GetLabelWidth(), serieData.GetLabelHeight(), serieLabel.borderWidth, serieLabel.borderColor, serieLabel.textStyle.rotate); } } protected int GetPainterIndexBySerie(Serie serie) { var maxPainter = settings.maxPainter; var maxSeries = m_Series.Count; if (maxPainter >= maxSeries) return serie.index; else { var rate = Mathf.CeilToInt(maxSeries * 1.0f / maxPainter); return serie.index / rate; } } } }