From 4c9f60e6c650561d8668396edea346b4559d718c Mon Sep 17 00:00:00 2001 From: monitor1394 Date: Thu, 30 Jul 2020 09:31:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0`LineChart`=E5=8F=AF=E9=80=9A?= =?UTF-8?q?=E8=BF=87`VisualMap`=E6=88=96`ItemStyle`=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=B8=90=E5=8F=98#78?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG-EN.md | 1 + CHANGELOG.md | 1 + Documentation/XCharts配置项手册.md | 7 +- Documentation/xcharts-configuration-EN.md | 6 +- Editor/CoordinateChartEditor.cs | 2 +- Editor/PropertyDrawers/ItemStyleDrawer.cs | 5 +- Editor/PropertyDrawers/VisualMapDrawer.cs | 43 +++--- Runtime/Component/Main/Axis.cs | 1 + Runtime/Component/Main/VisualMap.cs | 92 ++++++++++--- Runtime/Component/Sub/ItemStyle.cs | 36 ++++- Runtime/Internal/CoordinateChart.cs | 19 +-- .../Internal/CoordinateChart_DrawHeatmap.cs | 3 +- Runtime/Internal/CoordinateChart_DrawLine.cs | 25 +++- Runtime/Internal/Helper/SeriesHelper.cs | 10 ++ Runtime/Internal/Helper/VisualMapHelper.cs | 130 ++++++++++++++++++ Runtime/LineChart.cs | 9 ++ 16 files changed, 332 insertions(+), 58 deletions(-) create mode 100644 Runtime/Internal/Helper/VisualMapHelper.cs diff --git a/CHANGELOG-EN.md b/CHANGELOG-EN.md index a5312e5b..e66f4377 100644 --- a/CHANGELOG-EN.md +++ b/CHANGELOG-EN.md @@ -1,6 +1,7 @@ # 更新日志 +* (2020.07.30) Added `LineChart` to configure gradient through `VisualMap` or `ItemStyle`#78 * (2020.07.25) Fixed a problem with `LineChart` emerging abnormal in animation drawing#79 * (2020.07.25) Fixed a problem with gradual discoloration on `LiquidChart` at `100%`#80 * (2020.07.25) Added `RadarChart` support for `formatter` of `Tooltip`#77 diff --git a/CHANGELOG.md b/CHANGELOG.md index 881161af..5f02bf80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 更新日志 +* (2020.07.30) 增加`LineChart`可通过`VisualMap`或`ItemStyle`配置渐变#78 * (2020.07.25) 修复`LineChart`渐出动画绘制异常的问题#79 * (2020.07.25) 修复`LiquidChart`在`100%`时渐变色会失效的问题#80 * (2020.07.25) 增加`RadarChart`对`Tooltip`的`formatter`支持#77 diff --git a/Documentation/XCharts配置项手册.md b/Documentation/XCharts配置项手册.md index add2f617..4f400d26 100644 --- a/Documentation/XCharts配置项手册.md +++ b/Documentation/XCharts配置项手册.md @@ -300,8 +300,9 @@ * ~~`selectedMode`:分段型的选择模式,支持以下模式:~~ * ~~`Multiple`:多选。~~ * ~~`Single`:单选。~~ -* `min`:允许的最小值。'min' 必须用户指定。[visualMap.min, visualMap.max] 形成了视觉映射的『定义域』。 -* `max`:允许的最大值。'max' 必须用户指定。[visualMap.min, visualMax.max] 形成了视觉映射的『定义域』。 +* `autoMinMax`:自动设置`min`,`max`的值。 +* `min`:允许的最小值。`autoMinMax`为`false`时必须指定。`[min, max]` 形成了视觉映射的『定义域』。 +* `max`:允许的最大值。`autoMinMax`为`false`时必须指定。`[min, max]` 形成了视觉映射的『定义域』。 * `range`:指定手柄对应数值的位置。range 应在 min max 范围内。 * ~~`text`:两端的文本,如 ['High', 'Low']。~~ * ~~`textGap`:两端文字主体之间的距离,单位为px。~~ @@ -831,6 +832,8 @@ * `show`:是否启用。 * `color`:颜色。 +* `toColor`:渐变颜色1。 +* `toColor2`:渐变颜色2。只在折线图中有效。 * `backgroundColor`:背景颜色。 * `backgroundWidth`:背景的宽。 * `centerColor`:中心区域的颜色。如环形图的中心区域。 diff --git a/Documentation/xcharts-configuration-EN.md b/Documentation/xcharts-configuration-EN.md index 41093710..1396b502 100644 --- a/Documentation/xcharts-configuration-EN.md +++ b/Documentation/xcharts-configuration-EN.md @@ -299,6 +299,8 @@ VisualMap component. mapping data to visual elements such as colors. * ~~`selectedMode`: the selected mode for Piecewise visualMap.~~ * ~~`Multiple`: Multiple.~~ * ~~`Single`: Single.~~ + +* `autoMinMax`: Automatically set min, Max value. * `min`: The minimum allowed. `min` must be user specified. `[min, max]` forms the domain of the visualMap. * `max`: The maximum allowed. `max` must be user specified. `[min, max]` forms the domain of the visualMap. * `range`: Specifies the position of the numeric value corresponding to the handle. Range should be within the range of [min,max]. @@ -406,7 +408,7 @@ Check each serie for parameters. Line chart serie. * `show`: Whether to show serie in chart. -* `type`: `Line`。 +* `type`: `Line`. * `name`: Series name used for displaying in tooltip and filtering with legend. * `stack`: If stack the value. On the same category axis, the series with the same stack name would be put on top of each other. * `axisIndex`: Index of axis to combine with, which is useful for multiple x axes in one chart. @@ -723,6 +725,8 @@ Line chart serie. * `show`: 是否启用。 * `color`: 颜色。 +* `toColor`:gradient color1. +* `toColor2`:gradient color2. * `backgroundColor`: 背景颜色。 * `backgroundWidth`: 背景的宽。 * `centerColor`: 中心区域的颜色。如环形图的中心区域。 diff --git a/Editor/CoordinateChartEditor.cs b/Editor/CoordinateChartEditor.cs index f25acc4f..257d9d2b 100644 --- a/Editor/CoordinateChartEditor.cs +++ b/Editor/CoordinateChartEditor.cs @@ -43,7 +43,7 @@ namespace XCharts { EditorGUILayout.PropertyField(m_DataZoom); } - if (m_Target is HeatmapChart) + if (m_Target is HeatmapChart || m_Target is LineChart) { EditorGUILayout.PropertyField(m_VisualMap); } diff --git a/Editor/PropertyDrawers/ItemStyleDrawer.cs b/Editor/PropertyDrawers/ItemStyleDrawer.cs index d2c4c9d9..27ae3452 100644 --- a/Editor/PropertyDrawers/ItemStyleDrawer.cs +++ b/Editor/PropertyDrawers/ItemStyleDrawer.cs @@ -25,6 +25,7 @@ namespace XCharts SerializedProperty show = prop.FindPropertyRelative("m_Show"); SerializedProperty m_Color = prop.FindPropertyRelative("m_Color"); SerializedProperty m_ToColor = prop.FindPropertyRelative("m_ToColor"); + SerializedProperty m_ToColor2 = prop.FindPropertyRelative("m_ToColor2"); SerializedProperty m_BackgroundColor = prop.FindPropertyRelative("m_BackgroundColor"); SerializedProperty m_BackgroundWidth = prop.FindPropertyRelative("m_BackgroundWidth"); SerializedProperty m_CenterColor = prop.FindPropertyRelative("m_CenterColor"); @@ -45,6 +46,8 @@ namespace XCharts drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_ToColor); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, m_ToColor2); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_BackgroundColor); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_BackgroundWidth); @@ -80,7 +83,7 @@ namespace XCharts float height = 0; if (ChartEditorHelper.IsToggle(m_ItemStyleToggle, prop)) { - height += 14 * EditorGUIUtility.singleLineHeight + 13 * EditorGUIUtility.standardVerticalSpacing; + height += 15 * EditorGUIUtility.singleLineHeight + 14 * EditorGUIUtility.standardVerticalSpacing; var m_CornerRadius = prop.FindPropertyRelative("m_CornerRadius"); if (ChartEditorHelper.IsToggle(m_CornerRadiusToggle, m_CornerRadius)) { diff --git a/Editor/PropertyDrawers/VisualMapDrawer.cs b/Editor/PropertyDrawers/VisualMapDrawer.cs index c813b539..aee7ca82 100644 --- a/Editor/PropertyDrawers/VisualMapDrawer.cs +++ b/Editor/PropertyDrawers/VisualMapDrawer.cs @@ -42,7 +42,9 @@ namespace XCharts SerializedProperty m_Orient = prop.FindPropertyRelative("m_Orient"); SerializedProperty m_Location = prop.FindPropertyRelative("m_Location"); SerializedProperty m_InRange = prop.FindPropertyRelative("m_InRange"); - // SerializedProperty m_OutOfRange = prop.FindPropertyRelative("m_OutOfRange"); + SerializedProperty m_AutoMinMax = prop.FindPropertyRelative("m_AutoMinMax"); + SerializedProperty m_Direction = prop.FindPropertyRelative("m_Direction"); + SerializedProperty m_OutOfRange = prop.FindPropertyRelative("m_OutOfRange"); ChartEditorHelper.MakeFoldout(ref drawRect, ref m_VisualMapModuleToggle, "Visual Map", m_Enable); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; @@ -51,7 +53,10 @@ namespace XCharts ++EditorGUI.indentLevel; EditorGUI.PropertyField(drawRect, m_Type); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - + EditorGUI.PropertyField(drawRect, m_Direction); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + EditorGUI.PropertyField(drawRect, m_AutoMinMax); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_Min); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_Max); @@ -60,8 +65,6 @@ namespace XCharts drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_Dimension); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - EditorGUI.PropertyField(drawRect, m_HoverLink); - drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; m_InRangeFoldout = EditorGUI.Foldout(drawRect, m_InRangeFoldout, "InRange"); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; @@ -71,12 +74,12 @@ namespace XCharts } // drawRect.width = pos.width; - // m_OutOfRangeFoldout = EditorGUI.Foldout(drawRect, m_OutOfRangeFoldout, "OutOfRange"); - // drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; - // if (m_OutOfRangeFoldout) - // { - // ChartEditorHelper.MakeList(ref drawRect, ref m_OutOfRangeSize, m_OutOfRange); - // } + m_OutOfRangeFoldout = EditorGUI.Foldout(drawRect, m_OutOfRangeFoldout, "OutOfRange"); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + if (m_OutOfRangeFoldout) + { + ChartEditorHelper.MakeList(ref drawRect, ref m_OutOfRangeSize, m_OutOfRange); + } // drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_Show); @@ -88,6 +91,8 @@ namespace XCharts ChartEditorHelper.MakeTwoField(ref drawRect, pos.width, m_Range, "Range"); ChartEditorHelper.MakeTwoField(ref drawRect, pos.width, m_Text, "Text"); ChartEditorHelper.MakeTwoField(ref drawRect, pos.width, m_Text, "TextGap"); + EditorGUI.PropertyField(drawRect, m_HoverLink); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_Calculable); drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; EditorGUI.PropertyField(drawRect, m_ItemWidth); @@ -111,7 +116,7 @@ namespace XCharts int num = 1; if (m_VisualMapModuleToggle) { - num += 8; + num += 10; height += num * EditorGUIUtility.singleLineHeight + (num - 1) * EditorGUIUtility.standardVerticalSpacing; if (m_InRangeFoldout) @@ -121,16 +126,16 @@ namespace XCharts height += size * EditorGUIUtility.singleLineHeight + (size - 1) * EditorGUIUtility.standardVerticalSpacing; height += EditorGUIUtility.standardVerticalSpacing; } - // if (m_OutOfRangeFoldout) - // { - // SerializedProperty m_OutOfRange = prop.FindPropertyRelative("m_OutOfRange"); - // int size = m_OutOfRange.arraySize + 1; - // height += size * EditorGUIUtility.singleLineHeight + (size - 1) * EditorGUIUtility.standardVerticalSpacing; - // height += EditorGUIUtility.standardVerticalSpacing; - // } + if (m_OutOfRangeFoldout) + { + SerializedProperty m_OutOfRange = prop.FindPropertyRelative("m_OutOfRange"); + int size = m_OutOfRange.arraySize + 1; + height += size * EditorGUIUtility.singleLineHeight + (size - 1) * EditorGUIUtility.standardVerticalSpacing; + height += EditorGUIUtility.standardVerticalSpacing; + } if (prop.FindPropertyRelative("m_Show").boolValue) { - height += 9 * EditorGUIUtility.singleLineHeight + 8 * EditorGUIUtility.standardVerticalSpacing; + height += 10 * EditorGUIUtility.singleLineHeight + 9 * EditorGUIUtility.standardVerticalSpacing; height += EditorGUI.GetPropertyHeight(prop.FindPropertyRelative("m_Location")); } } diff --git a/Runtime/Component/Main/Axis.cs b/Runtime/Component/Main/Axis.cs index d3befebe..92890f3b 100644 --- a/Runtime/Component/Main/Axis.cs +++ b/Runtime/Component/Main/Axis.cs @@ -303,6 +303,7 @@ namespace XCharts splitLine.ClearVerticesDirty(); splitArea.ClearVerticesDirty(); } + public int index { get; internal set; } /// /// the axis label text list. /// 坐标轴刻度标签的Text列表。 diff --git a/Runtime/Component/Main/VisualMap.cs b/Runtime/Component/Main/VisualMap.cs index 6a964941..8ef0ab16 100644 --- a/Runtime/Component/Main/VisualMap.cs +++ b/Runtime/Component/Main/VisualMap.cs @@ -32,6 +32,25 @@ namespace XCharts Piecewise } + /// + /// 方向。X轴还是Y轴。 + /// + public enum Direction + { + /// + /// 默认方向。 + /// + Default, + /// + /// X轴方向。 + /// + X, + /// + /// Y轴方向。 + /// + Y + } + /// /// 选择模式 /// @@ -50,6 +69,7 @@ namespace XCharts [SerializeField] private bool m_Enable = false; [SerializeField] private bool m_Show = true; [SerializeField] private Type m_Type = Type.Continuous; + [SerializeField] private Direction m_Direction = Direction.Default; [SerializeField] private SelectedMode m_SelectedMode = SelectedMode.Multiple; [SerializeField] private float m_Min = 0; [SerializeField] private float m_Max = 100f; @@ -63,8 +83,9 @@ namespace XCharts [SerializeField] private float m_ItemWidth = 20f; [SerializeField] private float m_ItemHeight = 140f; [SerializeField] private float m_BorderWidth = 0; - [SerializeField] private int m_Dimension = 0; + [SerializeField] private int m_Dimension = -1; [SerializeField] private bool m_HoverLink = true; + [SerializeField] private bool m_AutoMinMax = true; [SerializeField] private Orient m_Orient = Orient.Horizonal; [SerializeField] private Location m_Location = Location.defaultLeft; [SerializeField] private List m_InRange = new List(); @@ -92,7 +113,7 @@ namespace XCharts public bool show { get { return m_Show; } - set { if (PropertyUtility.SetStruct(ref m_Enable, value)) SetVerticesDirty(); } + set { if (PropertyUtility.SetStruct(ref m_Show, value)) SetVerticesDirty(); } } /// /// the type of visualmap component. @@ -104,6 +125,14 @@ namespace XCharts set { if (PropertyUtility.SetStruct(ref m_Type, value)) SetVerticesDirty(); } } /// + /// 映射方向。 + /// + public Direction direction + { + get { return m_Direction; } + set { if (PropertyUtility.SetStruct(ref m_Direction, value)) SetVerticesDirty(); } + } + /// /// the selected mode for Piecewise visualMap. /// 选择模式。 /// @@ -115,7 +144,7 @@ namespace XCharts /// /// The minimum allowed. 'min' must be user specified. [visualmap.min, visualmap.max] forms the "domain" of the visualMap. /// - /// 允许的最小值。'min' 必须用户指定。[visualMap.min, visualMap.max] 形成了视觉映射的『定义域』。 + /// 允许的最小值。`autoMinMax`为`false`时必须指定。[visualMap.min, visualMap.max] 形成了视觉映射的『定义域』。 /// public float min { @@ -125,12 +154,12 @@ namespace XCharts /// /// The maximum allowed. 'max' must be user specified. [visualmap.min, visualmap.max] forms the "domain" of the visualMap. /// - /// 允许的最大值。'max' 必须用户指定。[visualMap.min, visualMax.max] 形成了视觉映射的『定义域』。 + /// 允许的最大值。`autoMinMax`为`false`时必须指定。[visualMap.min, visualMax.max] 形成了视觉映射的『定义域』。 /// public float max { get { return m_Max; } - set { m_Max = value < min ? min + 1 : value; SetVerticesDirty(); } + set { m_Max = (value < min ? min + 1 : value); SetVerticesDirty(); } } /// /// Specifies the position of the numeric value corresponding to the handle. Range should be within the range of [min,max]. @@ -237,6 +266,15 @@ namespace XCharts set { if (PropertyUtility.SetStruct(ref m_HoverLink, value)) SetVerticesDirty(); } } /// + /// Automatically set min, Max value + /// 自动设置min,max的值 + /// + public bool autoMinMax + { + get { return m_AutoMinMax; } + set { if (PropertyUtility.SetStruct(ref m_AutoMinMax, value)) SetVerticesDirty(); } + } + /// /// Specify whether the layout of component is horizontal or vertical. /// /// 布局方式是横还是竖。 @@ -330,7 +368,7 @@ namespace XCharts get { if (splitNumber > 0 && splitNumber <= m_InRange.Count) return splitNumber; - else return inRange.Count; + else return m_InRange.Count; } } @@ -342,7 +380,10 @@ namespace XCharts { get { - if (splitNumber == 0 || m_InRange.Count >= splitNumber || m_InRange.Count < 1) return m_InRange; + if (splitNumber == 0 || m_InRange.Count >= splitNumber || m_InRange.Count < 1 || IsPiecewise()) + { + return m_InRange; + } else { if (m_RtInRange.Count != runtimeSplitNumber) @@ -383,29 +424,41 @@ namespace XCharts public Color GetColor(float value) { + if (value < m_Min || value > m_Max) + { + if (m_OutOfRange.Count > 0) return m_OutOfRange[0]; + else return Color.clear; + } int splitNumber = runtimeInRange.Count; if (splitNumber <= 0) return Color.clear; - value = Mathf.Clamp(value, min, max); - - var diff = (max - min) / (splitNumber - 1); var index = GetIndex(value); - var nowMin = min + index * diff; - var rate = (value - nowMin) / diff; - if (index == splitNumber - 1) return runtimeInRange[index]; - else return Color.Lerp(runtimeInRange[index], runtimeInRange[index + 1], rate); + if (m_Type == VisualMap.Type.Piecewise) + { + if (index >= 0 && index < runtimeInRange.Count) + return runtimeInRange[index]; + else return Color.clear; + } + else + { + var diff = (m_Max - m_Min) / (splitNumber - 1); + var nowMin = m_Min + index * diff; + var rate = (value - nowMin) / diff; + if (index == splitNumber - 1) return runtimeInRange[index]; + else return Color.Lerp(runtimeInRange[index], runtimeInRange[index + 1], rate); + } } public int GetIndex(float value) { int splitNumber = runtimeInRange.Count; if (splitNumber <= 0) return -1; - value = Mathf.Clamp(value, min, max); + value = Mathf.Clamp(value, m_Min, m_Max); - var diff = (max - min) / (splitNumber - 1); + var diff = (m_Max - m_Min) / (splitNumber - (IsPiecewise() ? 0 : 1)); var index = -1; for (int i = 0; i < splitNumber; i++) { - if (value <= min + (i + 1) * diff) + if (value <= m_Min + (i + 1) * diff) { index = i; break; @@ -414,6 +467,11 @@ namespace XCharts return index; } + public bool IsPiecewise() + { + return m_Type == VisualMap.Type.Piecewise; + } + public bool IsInSelectedValue(float value) { if (runtimeSelectedIndex < 0) return true; diff --git a/Runtime/Component/Sub/ItemStyle.cs b/Runtime/Component/Sub/ItemStyle.cs index 8c2cad56..c1315726 100644 --- a/Runtime/Component/Sub/ItemStyle.cs +++ b/Runtime/Component/Sub/ItemStyle.cs @@ -38,6 +38,7 @@ namespace XCharts [SerializeField] private bool m_Show = false; [SerializeField] private Color m_Color; [SerializeField] private Color m_ToColor; + [SerializeField] private Color m_ToColor2; [SerializeField] private Color m_BackgroundColor; [SerializeField] private float m_BackgroundWidth; [SerializeField] private Color m_CenterColor; @@ -55,6 +56,7 @@ namespace XCharts m_Show = false; m_Color = Color.clear; m_ToColor = Color.clear; + m_ToColor2 = Color.clear; m_BackgroundColor = Color.clear; m_BackgroundWidth = 0; m_CenterColor = Color.clear; @@ -93,8 +95,8 @@ namespace XCharts set { if (PropertyUtility.SetColor(ref m_Color, value)) SetVerticesDirty(); } } /// - /// Gradient color, start color to toColor. - /// 渐变色的终点颜色。 + /// Gradient color1. + /// 渐变色的颜色1。 /// public Color toColor { @@ -102,6 +104,15 @@ namespace XCharts set { if (PropertyUtility.SetColor(ref m_ToColor, value)) SetVerticesDirty(); } } /// + /// Gradient color2.Only valid in line diagrams. + /// 渐变色的颜色2。只在折线图中有效。 + /// + public Color toColor2 + { + get { return m_ToColor2; } + set { if (PropertyUtility.SetColor(ref m_ToColor2, value)) SetVerticesDirty(); } + } + /// /// 数据项背景颜色。 /// public Color backgroundColor @@ -214,5 +225,26 @@ namespace XCharts color.a *= m_Opacity; return color; } + + public bool IsNeedGradient() + { + return !ChartHelper.IsClearColor(m_ToColor) || !ChartHelper.IsClearColor(m_ToColor2); + } + + public Color GetGradientColor(float value, Color defaultColor) + { + if (!IsNeedGradient()) return Color.clear; + value = Mathf.Clamp01(value); + var startColor = m_Color == Color.clear ? defaultColor : m_Color; + if (m_ToColor2 != Color.clear) + { + if (value <= 0.5f) return Color.Lerp(startColor, m_ToColor, 2 * value); + else return Color.Lerp(m_ToColor, m_ToColor2, 2 * (value - 0.5f)); + } + else + { + return Color.Lerp(startColor, m_ToColor, value); + } + } } } \ No newline at end of file diff --git a/Runtime/Internal/CoordinateChart.cs b/Runtime/Internal/CoordinateChart.cs index e382de32..f3db108f 100644 --- a/Runtime/Internal/CoordinateChart.cs +++ b/Runtime/Internal/CoordinateChart.cs @@ -764,11 +764,6 @@ namespace XCharts private void CheckMinMaxValue() { if (m_XAxises == null || m_YAxises == null) return; - if (IsCategory()) - { - m_CheckMinMaxValue = true; - return; - } for (int i = 0; i < m_XAxises.Count; i++) { UpdateAxisMinMaxValue(i, m_XAxises[i]); @@ -781,7 +776,14 @@ namespace XCharts private void UpdateAxisMinMaxValue(int axisIndex, Axis axis, bool updateChart = true) { - if (axis.IsCategory() || !axis.show) return; + if (!axis.show) return; + if (axis.IsCategory()) + { + m_CheckMinMaxValue = true; + axis.runtimeMinValue = 0; + axis.runtimeMaxValue = SeriesHelper.GetMaxSerieDataCount(m_Series); + return; + } float tempMinValue = 0; float tempMaxValue = 0; @@ -864,10 +866,12 @@ namespace XCharts DrawGrid(vh); for (int i = 0; i < m_XAxises.Count; i++) { + m_XAxises[i].index = i; DrawXAxisSplit(vh, i, m_XAxises[i]); } for (int i = 0; i < m_YAxises.Count; i++) { + m_YAxises[i].index = i; DrawYAxisSplit(vh, i, m_YAxises[i]); } for (int i = 0; i < m_XAxises.Count; i++) @@ -1494,8 +1498,7 @@ namespace XCharts if (serie.type == SerieType.Heatmap) { - dimension = m_VisualMap.enable && m_VisualMap.dimension > 0 ? m_VisualMap.dimension - 1 : - serieData.data.Count - 1; + dimension = VisualMapHelper.GetDimension(m_VisualMap, serieData.data.Count); } SerieLabelHelper.ResetLabel(serieData, serieLabel, themeInfo, i); diff --git a/Runtime/Internal/CoordinateChart_DrawHeatmap.cs b/Runtime/Internal/CoordinateChart_DrawHeatmap.cs index 08df943f..ea5fe96c 100644 --- a/Runtime/Internal/CoordinateChart_DrawHeatmap.cs +++ b/Runtime/Internal/CoordinateChart_DrawHeatmap.cs @@ -145,8 +145,7 @@ namespace XCharts var dataIndex = i * yCount + j; if (dataIndex >= dataList.Count) continue; var serieData = dataList[dataIndex]; - var dimension = m_VisualMap.enable && m_VisualMap.dimension > 0 ? m_VisualMap.dimension - 1 : - serieData.data.Count - 1; + var dimension = VisualMapHelper.GetDimension(m_VisualMap, serieData.data.Count); if (serie.IsIgnoreIndex(dataIndex, dimension)) { serie.dataPoints.Add(Vector3.zero); diff --git a/Runtime/Internal/CoordinateChart_DrawLine.cs b/Runtime/Internal/CoordinateChart_DrawLine.cs index 9d4b8bfe..bc74a612 100644 --- a/Runtime/Internal/CoordinateChart_DrawLine.cs +++ b/Runtime/Internal/CoordinateChart_DrawLine.cs @@ -220,6 +220,7 @@ namespace XCharts { lastNextPos = endPos; } + VisualMapHelper.AutoSetLineMinMax(visualMap, serie, xAxis, yAxis); for (i = startIndex + 1; i < serie.dataPoints.Count; i++) { np = serie.dataPoints[i]; @@ -641,10 +642,11 @@ namespace XCharts private Vector3 stPos1, stPos2, lastDir, lastDnPos; private bool lastIsDown; - private bool DrawNormalLine(VertexHelper vh, Serie serie, Axis axis, Vector3 lp, - Vector3 np, Vector3 nnp, int dataIndex, Color lineColor, Color areaColor, Color areaToColor, + private bool DrawNormalLine(VertexHelper vh, Serie serie, Axis axis, Vector3 lp, Vector3 np, Vector3 nnp, + int dataIndex, Color lineColor, Color areaColor, Color areaToColor, Vector3 zeroPos, int startIndex = 0) { + var defaultLineColor = lineColor; var isSecond = dataIndex == startIndex + 1; var isTheLastPos = np == nnp; bool isYAxis = axis is YAxis; @@ -715,6 +717,7 @@ namespace XCharts if (serie.animation.CheckDetailBreak(cp, isYAxis)) isBreak = true; var tp1 = cp - dir1v * serie.lineStyle.width; var tp2 = cp + dir1v * serie.lineStyle.width; + CheckLineGradientColor(cp, serie.itemStyle, axis, defaultLineColor, ref lineColor); if (isDown) { if (!isBreak) @@ -849,7 +852,7 @@ namespace XCharts if (lastSerie != null) { var lastSmoothPoints = lastSerie.GetUpSmoothList(dataIndex); - DrawStackArea(vh, serie, axis, smoothDownPoints, lastSmoothPoints, lineColor, areaColor, areaToColor); + DrawStackArea(vh, serie, axis, smoothDownPoints, lastSmoothPoints, areaColor, areaToColor); } else { @@ -985,6 +988,14 @@ namespace XCharts return !isBreak; } + private void CheckLineGradientColor(Vector3 cp, ItemStyle itemStyle, Axis axis, Color defaultLineColor, ref Color lineColor) + { + if (VisualMapHelper.IsNeedGradient(m_VisualMap)) + lineColor = VisualMapHelper.GetLineGradientColor(m_VisualMap, cp, this, axis, defaultLineColor); + else if (itemStyle.IsNeedGradient()) + lineColor = VisualMapHelper.GetItemStyleGradientColor(itemStyle, cp, this, axis, defaultLineColor); + } + private bool IsInRightOrUp(bool isYAxis, bool isLastDown, Vector3 dnPos, Vector3 checkPos) { if ((isLastDown && ((isYAxis && checkPos.y <= dnPos.y) || (!isYAxis && checkPos.x <= dnPos.x))) || @@ -1082,6 +1093,7 @@ namespace XCharts Vector3 np, Vector3 llp, Vector3 nnp, int dataIndex, Color lineColor, Color areaColor, Color areaToColor, bool isStack, Vector3 zeroPos, int startIndex = 0) { + var defaultLineColor = lineColor; bool isYAxis = xAxis is YAxis; var lineWidth = serie.lineStyle.width; var smoothPoints = serie.GetUpSmoothList(dataIndex); @@ -1096,6 +1108,7 @@ namespace XCharts { start = bezierPoints[i]; to = bezierPoints[i + 1]; + CheckLineGradientColor(start, serie.itemStyle, xAxis, defaultLineColor, ref lineColor); CheckClipAndDrawLine(vh, start, to, lineWidth, lineColor, serie.clip); } return true; @@ -1118,6 +1131,7 @@ namespace XCharts { if (!serie.animation.IsInFadeOut()) { + CheckLineGradientColor(lp, serie.itemStyle, xAxis, defaultLineColor, ref lineColor); CheckClipAndDrawTriangle(vh, smoothStartPosUp, startUp, lp, lineColor, serie.clip); CheckClipAndDrawTriangle(vh, smoothStartPosDn, startDn, lp, lineColor, serie.clip); } @@ -1146,6 +1160,7 @@ namespace XCharts diff = dir1v * lineWidth; toUp = to - diff; toDn = to + diff; + CheckLineGradientColor(to, serie.itemStyle, xAxis, defaultLineColor, ref lineColor); if (isYAxis) CheckClipAndDrawPolygon(vh, startDn, toDn, toUp, startUp, lineColor, serie.clip); else CheckClipAndDrawPolygon(vh, startUp, toUp, toDn, startDn, lineColor, serie.clip); smoothPoints.Add(toUp); @@ -1209,7 +1224,7 @@ namespace XCharts if (lastSerie != null) { var lastSmoothPoints = lastSerie.GetUpSmoothList(dataIndex); - DrawStackArea(vh, serie, xAxis, smoothDownPoints, lastSmoothPoints, lineColor, areaColor, areaToColor); + DrawStackArea(vh, serie, xAxis, smoothDownPoints, lastSmoothPoints, areaColor, areaToColor); } } return isFinish; @@ -1241,7 +1256,7 @@ namespace XCharts } private void DrawStackArea(VertexHelper vh, Serie serie, Axis axis, List smoothPoints, - List lastSmoothPoints, Color lineColor, Color areaColor, Color areaToColor) + List lastSmoothPoints, Color areaColor, Color areaToColor) { if (!serie.areaStyle.show || lastSmoothPoints.Count <= 0) return; Vector3 start, to; diff --git a/Runtime/Internal/Helper/SeriesHelper.cs b/Runtime/Internal/Helper/SeriesHelper.cs index 2e57f4ef..d37bb155 100644 --- a/Runtime/Internal/Helper/SeriesHelper.cs +++ b/Runtime/Internal/Helper/SeriesHelper.cs @@ -470,5 +470,15 @@ namespace XCharts maxValue = max > 1 ? Mathf.CeilToInt(max) : max; } } + + public static int GetMaxSerieDataCount(Series series) + { + int max = 0; + foreach (var serie in series.list) + { + if (serie.dataCount > max) max = serie.dataCount; + } + return max; + } } } \ No newline at end of file diff --git a/Runtime/Internal/Helper/VisualMapHelper.cs b/Runtime/Internal/Helper/VisualMapHelper.cs new file mode 100644 index 00000000..340581bc --- /dev/null +++ b/Runtime/Internal/Helper/VisualMapHelper.cs @@ -0,0 +1,130 @@ +/******************************************/ +/* */ +/* Copyright (c) 2018 monitor1394 */ +/* https://github.com/monitor1394 */ +/* */ +/******************************************/ + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace XCharts +{ + public static class VisualMapHelper + { + public static void AutoSetLineMinMax(VisualMap visualMap, Serie serie, XAxis xAxis, YAxis yAxis) + { + if (!IsNeedGradient(visualMap) || !visualMap.autoMinMax) return; + float min = 0; + float max = 0; + switch (visualMap.direction) + { + case VisualMap.Direction.Default: + case VisualMap.Direction.X: + min = xAxis.IsCategory() ? 0 : xAxis.runtimeMinValue; + max = xAxis.IsCategory() ? serie.dataCount : xAxis.runtimeMaxValue; + SetMinMax(visualMap, min, max); + break; + case VisualMap.Direction.Y: + min = yAxis.IsCategory() ? 0 : yAxis.runtimeMinValue; + max = yAxis.IsCategory() ? serie.dataCount : yAxis.runtimeMaxValue; + SetMinMax(visualMap, min, max); + break; + } + } + + public static void SetMinMax(VisualMap visualMap, float min, float max) + { + if (visualMap.enable && (visualMap.min != min || visualMap.max != max)) + { + //Debug.LogError("minmax:"+min+","+max); + if (max >= min) + { + visualMap.min = min; + visualMap.max = max; + //Debug.LogError("minmax2222:"+visualMap.min+","+visualMap.max); + } + else + { + throw new Exception("SetMinMax:max < min:" + min + "," + max); + } + } + } + + public static void GetLineGradientColor(VisualMap visualMap, float xValue, float yValue, + out Color startColor, out Color toColor) + { + startColor = Color.clear; + toColor = Color.clear; + switch (visualMap.direction) + { + case VisualMap.Direction.Default: + case VisualMap.Direction.X: + startColor = visualMap.IsPiecewise() ? visualMap.GetColor(xValue) : visualMap.GetColor(xValue - 1); + toColor = visualMap.IsPiecewise() ? startColor : visualMap.GetColor(xValue); + break; + case VisualMap.Direction.Y: + startColor = visualMap.IsPiecewise() ? visualMap.GetColor(yValue) : visualMap.GetColor(yValue - 1); + toColor = visualMap.IsPiecewise() ? startColor : visualMap.GetColor(yValue); + break; + } + } + + internal static Color GetLineGradientColor(VisualMap visualMap, Vector3 pos, CoordinateChart chart, Axis axis, Color defaultColor) + { + float value = 0; + switch (visualMap.direction) + { + case VisualMap.Direction.Default: + case VisualMap.Direction.X: + var min = axis.runtimeMinValue; + var max = axis.runtimeMaxValue; + value = min + (pos.x - chart.coordinateX) / chart.coordinateWidth * (max - min); + break; + case VisualMap.Direction.Y: + if (axis is YAxis) + { + var yAxis = chart.xAxises[axis.index]; + min = yAxis.runtimeMinValue; + max = yAxis.runtimeMaxValue; + } + else + { + var yAxis = chart.yAxises[axis.index]; + min = yAxis.runtimeMinValue; + max = yAxis.runtimeMaxValue; + } + value = min + (pos.y - chart.coordinateY) / chart.coordinateHeight * (max - min); + break; + } + var color = visualMap.GetColor(value); + if (ChartHelper.IsClearColor(color)) return defaultColor; + else return color; + } + + internal static Color GetItemStyleGradientColor(ItemStyle itemStyle, Vector3 pos, CoordinateChart chart, Axis axis, Color defaultColor) + { + var min = axis.runtimeMinValue; + var max = axis.runtimeMaxValue; + var value = min + (pos.x - chart.coordinateX) / chart.coordinateWidth * (max - min); + var rate = (value - min) / (max - min); + var color = itemStyle.GetGradientColor(rate, defaultColor); + if (ChartHelper.IsClearColor(color)) return defaultColor; + else return color; + } + + public static bool IsNeedGradient(VisualMap visualMap) + { + if (!visualMap.enable || visualMap.inRange.Count <= 0) return false; + return true; + } + + public static int GetDimension(VisualMap visualMap, int serieDataCount) + { + var dimension = visualMap.enable && visualMap.dimension >= 0 ? visualMap.dimension : serieDataCount - 1; + if (dimension > serieDataCount - 1) dimension = serieDataCount - 1; + return dimension; + } + } +} \ No newline at end of file diff --git a/Runtime/LineChart.cs b/Runtime/LineChart.cs index 476e8f0c..ea090282 100644 --- a/Runtime/LineChart.cs +++ b/Runtime/LineChart.cs @@ -23,6 +23,15 @@ namespace XCharts base.Reset(); m_Title.text = "LineChart"; m_Tooltip.type = Tooltip.Type.Line; + + m_VisualMap.enable = false; + m_VisualMap.show = false; + m_VisualMap.autoMinMax = true; + m_VisualMap.direction = VisualMap.Direction.Y; + m_VisualMap.inRange.Clear(); + m_VisualMap.inRange.Add(Color.blue); + m_VisualMap.inRange.Add(Color.red); + RemoveData(); var serie = AddSerie(SerieType.Line, "serie1"); serie.symbol.show = true;