diff --git a/Demo.cs b/Demo.cs index a18462ea..20694dbd 100644 --- a/Demo.cs +++ b/Demo.cs @@ -13,7 +13,7 @@ public class Demo : MonoBehaviour void Awake() { - lineChart = transform.Find("xchart/line_chart").GetComponent(); + //lineChart = transform.Find("xchart/line_chart").GetComponent(); var xchart = transform.Find("xchart"); GridLayoutGroup grid = xchart.GetComponent(); diff --git a/Scripts/BarChart.cs b/Scripts/BarChart.cs index 113f6066..a4138549 100644 --- a/Scripts/BarChart.cs +++ b/Scripts/BarChart.cs @@ -25,10 +25,9 @@ namespace xcharts base.Update(); } - protected override void OnPopulateMesh(VertexHelper vh) + protected override void DrawChart(VertexHelper vh) { - base.OnPopulateMesh(vh); - + base.DrawChart(vh); if(yAxis.type == AxisType.category) { int seriesCount = seriesList.Count; @@ -36,6 +35,16 @@ namespace xcharts float barWid = barInfo.barWid > 1 ? barInfo.barWid : scaleWid * barInfo.barWid; float offset = (scaleWid - barWid * seriesCount - barInfo.space * (seriesCount - 1)) / 2; float max = GetMaxValue(); + if (tooltip.show && tooltip.DataIndex > 0) + { + float pX = zeroX + coordinateWid; + float pY = zeroY + scaleWid * (tooltip.DataIndex - 1); + Vector3 p1 = new Vector3(zeroX, pY); + Vector3 p2 = new Vector3(zeroX, pY + scaleWid); + Vector3 p3 = new Vector3(pX, pY + scaleWid); + Vector3 p4 = new Vector3(pX, pY); + ChartUtils.DrawPolygon(vh, p1, p2, p3, p4, themeInfo.tooltipFlagAreaColor); + } for (int j = 0; j < seriesCount; j++) { if (!legend.IsShowSeries(j)) continue; @@ -69,6 +78,16 @@ namespace xcharts float barWid = barInfo.barWid > 1 ? barInfo.barWid : scaleWid * barInfo.barWid; float offset = (scaleWid - barWid * seriesCount - barInfo.space * (seriesCount - 1)) / 2; float max = GetMaxValue(); + if (tooltip.show && tooltip.DataIndex > 0) + { + float pX = zeroX + scaleWid * (tooltip.DataIndex - 1); + float pY = zeroY + coordinateHig; + Vector3 p1 = new Vector3(pX, zeroY); + Vector3 p2 = new Vector3(pX, pY); + Vector3 p3 = new Vector3(pX + scaleWid, pY); + Vector3 p4 = new Vector3(pX + scaleWid, zeroY); + ChartUtils.DrawPolygon(vh, p1, p2, p3, p4, themeInfo.tooltipFlagAreaColor); + } for (int j = 0; j < seriesCount; j++) { if (!legend.IsShowSeries(j)) continue; diff --git a/Scripts/BaseAxesChart.cs b/Scripts/BaseAxesChart.cs index 61866e78..779700e9 100644 --- a/Scripts/BaseAxesChart.cs +++ b/Scripts/BaseAxesChart.cs @@ -2,6 +2,7 @@ using System.Collections; using UnityEngine.UI; using System.Collections.Generic; +using System.Text; namespace xcharts { @@ -114,12 +115,153 @@ namespace xcharts CheckCoordinate(); } - protected override void OnPopulateMesh(VertexHelper vh) + protected override void DrawChart(VertexHelper vh) { - base.OnPopulateMesh(vh); + base.DrawChart(vh); DrawCoordinate(vh); } + protected override void CheckTootipArea(Vector2 local) + { + if (local.x < zeroX || local.x > zeroX + coordinateWid || + local.y < zeroY || local.y > zeroY + coordinateHig) + { + tooltip.DataIndex = 0; + RefreshTooltip(); + } + else + { + if (xAxis.type == AxisType.value) + { + float splitWid = coordinateHig / (yAxis.splitNumber - 1); + for (int i = 0; i < yAxis.splitNumber; i++) + { + float pY = zeroY + i * splitWid; + if (yAxis.boundaryGap) + { + if (local.y > pY && local.y <= pY + splitWid) + { + tooltip.DataIndex = i + 1; + break; + } + } + else + { + if (local.y > pY - splitWid / 2 && local.y <= pY + splitWid / 2) + { + tooltip.DataIndex = i + 1; + break; + } + } + } + } + else + { + float splitWid = coordinateWid / (xAxis.splitNumber - 1); + for (int i = 0; i < xAxis.splitNumber; i++) + { + float pX = zeroX + i * splitWid; + if (xAxis.boundaryGap) + { + if (local.x > pX && local.x <= pX + splitWid) + { + tooltip.DataIndex = i + 1; + break; + } + } + else + { + if (local.x > pX - splitWid / 2 && local.x <= pX + splitWid / 2) + { + tooltip.DataIndex = i + 1; + break; + } + } + } + } + } + if (tooltip.DataIndex > 0) + { + tooltip.UpdatePos(new Vector2(local.x + 18, local.y - 25)); + RefreshTooltip(); + if (tooltip.LastDataIndex != tooltip.DataIndex) + { + RefreshChart(); + } + tooltip.LastDataIndex = tooltip.DataIndex; + } + } + + protected override void RefreshTooltip() + { + base.RefreshTooltip(); + int index = tooltip.DataIndex - 1; + if (index < 0) + { + tooltip.SetActive(false); + return; + } + Axis tempAxis = xAxis.type == AxisType.value ? (Axis)yAxis : (Axis)xAxis; + if (index > tempAxis.data.Count - 1) + { + index = tempAxis.data.Count - 1; + } + tooltip.SetActive(true); + if (seriesList.Count == 1) + { + string txt = tempAxis.data[index] + ": " + seriesList[0].dataList[index].value; + tooltip.UpdateTooltipText(txt); + } + else + { + StringBuilder sb = new StringBuilder(tempAxis.data[index]); + for(int i=0; i● ", strColor); + sb.AppendFormat("{0}: {1}", key, value); + } + tooltip.UpdateTooltipText(sb.ToString()); + } + var pos = tooltip.GetPos(); + if (pos.x + tooltip.Width > chartWid) + { + pos.x = chartWid - tooltip.Width; + } + if (pos.y - tooltip.Height < 0) + { + pos.y = tooltip.Height; + } + tooltip.UpdatePos(pos); + } + + TextGenerationSettings GetTextSetting() + { + var setting = new TextGenerationSettings(); + var fontdata = FontData.defaultFontData; + + //setting.generationExtents = rectTransform.rect.size; + setting.generationExtents = new Vector2(200.0F, 50.0F); + setting.fontSize = 14; + setting.textAnchor = TextAnchor.MiddleCenter; + setting.scaleFactor = 1f; + setting.color = Color.red; + setting.font = themeInfo.font; + setting.pivot = new Vector2(0.5f, 0.5f); + setting.richText = false; + setting.lineSpacing = 0; + setting.fontStyle = FontStyle.Normal; + setting.resizeTextForBestFit = false; + setting.horizontalOverflow = HorizontalWrapMode.Overflow; + setting.verticalOverflow = VerticalWrapMode.Overflow; + + return setting; + + } + protected override void OnThemeChanged() { base.OnThemeChanged(); diff --git a/Scripts/BaseChart.cs b/Scripts/BaseChart.cs index 24bb60d4..54f388fc 100644 --- a/Scripts/BaseChart.cs +++ b/Scripts/BaseChart.cs @@ -15,7 +15,7 @@ namespace xcharts public class Title { public bool show = true; - public string text ="Chart Title"; + public string text = "Chart Title"; public Align align = Align.center; public float left; public float right; @@ -81,6 +81,53 @@ namespace xcharts { public bool show; + public int DataIndex { get; set; } + public int LastDataIndex { get; set; } + public float Width { get { return bgRect.sizeDelta.x; } } + public float Height { get { return bgRect.sizeDelta.y; } } + + + private GameObject gameObject; + private Text text; + private RectTransform bgRect; + + public void SetObj(GameObject obj) + { + gameObject = obj; + bgRect = gameObject.GetComponent(); + text = gameObject.GetComponentInChildren(); + } + + public void SetBackgroundColor(Color color) + { + gameObject.GetComponent().color = color; + } + + public void SetTextColor(Color color) + { + text.color = color; + } + + public void UpdateTooltipText(string txt) + { + text.text = txt; + bgRect.sizeDelta = new Vector2(text.preferredWidth + 8, text.preferredHeight + 8); + } + + public void SetActive(bool flag) + { + gameObject.SetActive(flag); + } + + public void UpdatePos(Vector2 pos) + { + gameObject.transform.localPosition = pos; + } + + public Vector3 GetPos() + { + return gameObject.transform.localPosition; + } } [System.Serializable] @@ -155,6 +202,8 @@ namespace xcharts [SerializeField] protected Legend legend = new Legend(); [SerializeField] + protected Tooltip tooltip = new Tooltip(); + [SerializeField] protected List seriesList = new List(); private Theme checkTheme = 0; @@ -165,7 +214,7 @@ namespace xcharts protected List legendTextList = new List(); protected float chartWid { get { return rectTransform.sizeDelta.x; } } protected float chartHig { get { return rectTransform.sizeDelta.y; } } - + protected override void Awake() { themeInfo = ThemeInfo.Dark; @@ -174,6 +223,7 @@ namespace xcharts rectTransform.pivot = Vector2.zero; InitTitle(); InitLegend(); + InitTooltip(); } protected virtual void Update() @@ -181,11 +231,12 @@ namespace xcharts CheckTheme(); CheckTile(); CheckLegend(); + CheckTooltip(); } protected override void OnDestroy() { - for(int i = transform.childCount - 1; i >= 0; i--) + for (int i = transform.childCount - 1; i >= 0; i--) { DestroyImmediate(transform.GetChild(i).gameObject); } @@ -244,7 +295,7 @@ namespace xcharts break; case Align.right: anchor = TextAnchor.MiddleRight; - titlePosition = new Vector3(chartWid - title.right - titleWid, + titlePosition = new Vector3(chartWid - title.right - titleWid, chartHig - title.top, 0); break; case Align.center: @@ -271,7 +322,7 @@ namespace xcharts { LegendData data = legend.dataList[i]; Button btn = ChartUtils.AddButtonObject(LEGEND_TEXT + i, transform, themeInfo.font, - themeInfo.textColor, Vector2.zero,Vector2.zero, Vector2.zero, + themeInfo.textColor, Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(legend.itemWidth, legend.itemHeight)); legend.dataList[i].button = btn; Color bcolor = data.show ? themeInfo.GetColor(i) : themeInfo.unableColor; @@ -282,7 +333,8 @@ namespace xcharts btn.onClick.AddListener(delegate () { data.show = !data.show; - btn.GetComponent().color = data.show ? themeInfo.GetColor(i) : themeInfo.unableColor; + btn.GetComponent().color = data.show ? + themeInfo.GetColor(i) : themeInfo.unableColor; OnYMaxValueChanged(); OnLegendButtonClicked(); RefreshChart(); @@ -290,6 +342,15 @@ namespace xcharts } } + private void InitTooltip() + { + GameObject obj = ChartUtils.AddTooltipObject("tooltip", transform,themeInfo.font); + tooltip.SetObj(obj); + tooltip.SetBackgroundColor(themeInfo.tooltipBackgroundColor); + tooltip.SetTextColor(themeInfo.tooltipTextColor); + tooltip.SetActive(false); + } + private Vector3 GetLegendPosition(int i) { int legendCount = legend.dataList.Count; @@ -319,8 +380,8 @@ namespace xcharts float offset = (chartHig - legendHig) / 2; startY = chartHig - offset - legend.itemHeight; } - float posX = legend.location == Location.left ? - legend.left : + float posX = legend.location == Location.left ? + legend.left : chartWid - legend.right - legend.itemWidth; return new Vector3(posX, startY - i * (legend.itemHeight + legend.itemGap), 0); default: break; @@ -341,7 +402,7 @@ namespace xcharts private void CheckTheme() { - if(checkTheme != theme) + if (checkTheme != theme) { checkTheme = theme; OnThemeChanged(); @@ -350,6 +411,7 @@ namespace xcharts private void CheckTile() { + if (checkTitle == null || title == null) return; if (checkTitle.align != title.align || checkTitle.left != title.left || checkTitle.right != title.right || @@ -394,6 +456,27 @@ namespace xcharts } } + private void CheckTooltip() + { + if (!tooltip.show) return; + tooltip.DataIndex = 0; + Vector2 local; + + if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, + Input.mousePosition, null, out local)) + return; + + if (local.x < 0 || local.x > chartWid || + local.y < 0 || local.y > chartHig) + return; + + CheckTootipArea(local); + } + + protected virtual void CheckTootipArea(Vector2 localPostion) + { + } + protected virtual void OnThemeChanged() { switch (theme) @@ -422,10 +505,10 @@ namespace xcharts for (int i = 0; i < legend.dataList.Count; i++) { Button btn = legend.dataList[i].button; - btn.GetComponent().sizeDelta = + btn.GetComponent().sizeDelta = new Vector2(legend.itemWidth, legend.itemHeight); Text txt = btn.GetComponentInChildren(); - txt.transform.GetComponent().sizeDelta = + txt.transform.GetComponent().sizeDelta = new Vector2(legend.itemWidth, legend.itemHeight); txt.transform.localPosition = Vector3.zero; btn.transform.localPosition = GetLegendPosition(i); @@ -453,10 +536,24 @@ namespace xcharts rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, tempWid); } + protected virtual void RefreshTooltip() + { + } + protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); DrawBackground(vh); + DrawChart(vh); + DrawTooltip(vh); + } + + protected virtual void DrawChart(VertexHelper vh) + { + } + + protected virtual void DrawTooltip(VertexHelper vh) + { } private void DrawBackground(VertexHelper vh) @@ -469,4 +566,5 @@ namespace xcharts ChartUtils.DrawPolygon(vh, p1, p2, p3, p4, themeInfo.backgroundColor); } } -} \ No newline at end of file +} + \ No newline at end of file diff --git a/Scripts/ChartTheme.cs b/Scripts/ChartTheme.cs index 8c790c87..a266528c 100644 --- a/Scripts/ChartTheme.cs +++ b/Scripts/ChartTheme.cs @@ -24,6 +24,10 @@ namespace xcharts public Color axisLineColor; public Color axisSplitLineColor; + public Color tooltipBackgroundColor; + public Color tooltipFlagAreaColor; + public Color tooltipTextColor; + public Color[] colorPalette; public Color GetColor(int index) @@ -46,6 +50,8 @@ namespace xcharts subTextColor = theme.subTextColor; axisLineColor = theme.axisLineColor; axisSplitLineColor = theme.axisSplitLineColor; + tooltipBackgroundColor = theme.tooltipBackgroundColor; + tooltipTextColor = theme.tooltipTextColor; colorPalette = new Color[theme.colorPalette.Length]; for(int i = 0; i < theme.colorPalette.Length; i++) { @@ -67,6 +73,9 @@ namespace xcharts subTextColor = GetColor("#514D4D"), axisLineColor = GetColor("#514D4D"), axisSplitLineColor = GetColor("#AB9999"), + tooltipBackgroundColor = GetColor("#515151B5"), + tooltipTextColor = GetColor("#FFFFFFFF"), + tooltipFlagAreaColor = GetColor("#51515120"), colorPalette = new Color[] { new Color32(194, 53, 49, 255), @@ -99,6 +108,9 @@ namespace xcharts subTextColor = GetColor("#514D4D"), axisLineColor = GetColor("#514D4D"), axisSplitLineColor = GetColor("#AB9999"), + tooltipBackgroundColor = GetColor("#515151B5"), + tooltipTextColor = GetColor("#FFFFFFFF"), + tooltipFlagAreaColor = GetColor("#51515120"), colorPalette = new Color[] { new Color32(55, 162, 218, 255), @@ -133,6 +145,9 @@ namespace xcharts subTextColor = GetColor("#eee"), axisLineColor = GetColor("#eee"), axisSplitLineColor = GetColor("#aaa"), + tooltipBackgroundColor = GetColor("#515151B5"), + tooltipTextColor = GetColor("#FFFFFFFF"), + tooltipFlagAreaColor = GetColor("#51515120"), colorPalette = new Color[] { new Color32(221, 107, 102, 255), diff --git a/Scripts/ChartUtils.cs b/Scripts/ChartUtils.cs index 7eefbb4d..31de325c 100644 --- a/Scripts/ChartUtils.cs +++ b/Scripts/ChartUtils.cs @@ -38,11 +38,11 @@ namespace xcharts txtObj.GetComponent().alignment = anchor; RectTransform rect = txtObj.GetComponent(); + rect.localPosition = Vector3.zero; rect.sizeDelta = sizeDelta; rect.anchorMin = anchorMin; rect.anchorMax = anchorMax; rect.pivot = pivot; - rect.localPosition = Vector3.zero; return txtObj.GetComponent(); } @@ -82,6 +82,40 @@ namespace xcharts return btnObj.GetComponent