增加LineChart可通过VisualMapItemStyle配置渐变#78

This commit is contained in:
monitor1394
2020-07-30 09:31:44 +08:00
parent 6ea04ed671
commit 4c9f60e6c6
16 changed files with 332 additions and 58 deletions

View File

@@ -303,6 +303,7 @@ namespace XCharts
splitLine.ClearVerticesDirty();
splitArea.ClearVerticesDirty();
}
public int index { get; internal set; }
/// <summary>
/// the axis label text list.
/// 坐标轴刻度标签的Text列表。

View File

@@ -32,6 +32,25 @@ namespace XCharts
Piecewise
}
/// <summary>
/// 方向。X轴还是Y轴。
/// </summary>
public enum Direction
{
/// <summary>
/// 默认方向。
/// </summary>
Default,
/// <summary>
/// X轴方向。
/// </summary>
X,
/// <summary>
/// Y轴方向。
/// </summary>
Y
}
/// <summary>
/// 选择模式
/// </summary>
@@ -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<Color> m_InRange = new List<Color>();
@@ -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(); }
}
/// <summary>
/// the type of visualmap component.
@@ -104,6 +125,14 @@ namespace XCharts
set { if (PropertyUtility.SetStruct(ref m_Type, value)) SetVerticesDirty(); }
}
/// <summary>
/// 映射方向。
/// </summary>
public Direction direction
{
get { return m_Direction; }
set { if (PropertyUtility.SetStruct(ref m_Direction, value)) SetVerticesDirty(); }
}
/// <summary>
/// the selected mode for Piecewise visualMap.
/// 选择模式。
/// </summary>
@@ -115,7 +144,7 @@ namespace XCharts
/// <summary>
/// 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] 形成了视觉映射的『定义域』。
/// </summary>
public float min
{
@@ -125,12 +154,12 @@ namespace XCharts
/// <summary>
/// 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] 形成了视觉映射的『定义域』。
/// </summary>
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(); }
}
/// <summary>
/// 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(); }
}
/// <summary>
/// Automatically set min, Max value
/// 自动设置minmax的值
/// </summary>
public bool autoMinMax
{
get { return m_AutoMinMax; }
set { if (PropertyUtility.SetStruct(ref m_AutoMinMax, value)) SetVerticesDirty(); }
}
/// <summary>
/// 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;

View File

@@ -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(); }
}
/// <summary>
/// Gradient color, start color to toColor.
/// 渐变色的终点颜色。
/// Gradient color1.
/// 渐变色的颜色1
/// </summary>
public Color toColor
{
@@ -102,6 +104,15 @@ namespace XCharts
set { if (PropertyUtility.SetColor(ref m_ToColor, value)) SetVerticesDirty(); }
}
/// <summary>
/// Gradient color2.Only valid in line diagrams.
/// 渐变色的颜色2。只在折线图中有效。
/// </summary>
public Color toColor2
{
get { return m_ToColor2; }
set { if (PropertyUtility.SetColor(ref m_ToColor2, value)) SetVerticesDirty(); }
}
/// <summary>
/// 数据项背景颜色。
/// </summary>
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);
}
}
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<Vector3> smoothPoints,
List<Vector3> lastSmoothPoints, Color lineColor, Color areaColor, Color areaToColor)
List<Vector3> lastSmoothPoints, Color areaColor, Color areaToColor)
{
if (!serie.areaStyle.show || lastSmoothPoints.Count <= 0) return;
Vector3 start, to;

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;