增加HeatmapChart热力图

This commit is contained in:
monitor1394
2019-10-14 07:45:56 +08:00
parent c54c8e60d2
commit d7933eb06e
41 changed files with 182730 additions and 60532 deletions

View File

@@ -167,7 +167,7 @@ namespace XCharts
/// Category data, available in type: 'Category' axis.
/// 类目数据在类目轴type: 'category')中有效。
/// </summary>
public List<string> data { get { return m_Data; } }
public List<string> data { get { return m_Data; } set { if (value != null) m_Data = value; } }
/// <summary>
/// axis Line.
/// 坐标轴轴线。

View File

@@ -197,11 +197,6 @@ namespace XCharts
/// </summary>
public FontStyle fontStyle { get { return m_FontStyle; } set { m_FontStyle = value; } }
/// <summary>
/// DataZoom is in draging.
/// 正在拖拽组件。
/// </summary>
public bool isDraging { get; set; }
/// <summary>
/// The start label.
/// 组件的开始信息文本。

View File

@@ -61,7 +61,7 @@ namespace XCharts
{
var coordinate = new Grid
{
m_Show = false,
m_Show = true,
m_Left = 50,
m_Right = 30,
m_Top = 50,

View File

@@ -36,7 +36,11 @@ namespace XCharts
/// <summary>
/// 带有涟漪特效动画的散点图。利用动画特效可以将某些想要突出的数据进行视觉突出。
/// </summary>
EffectScatter
EffectScatter,
/// <summary>
/// 热力图。主要通过颜色去表现数值的大小,必须要配合 visualMap 组件使用。
/// </summary>
Heatmap,
}
/// <summary>
@@ -177,9 +181,10 @@ namespace XCharts
[SerializeField] private float[] m_Radius = new float[2] { 0, 80 };
#endregion
[SerializeField] private SerieLabel m_Label = new SerieLabel();
[SerializeField] private SerieLabel m_HighlightLabel = new SerieLabel();
[SerializeField] private Animation m_Animation = new Animation();
[SerializeField] private LineArrow m_LineArrow = new LineArrow();
[SerializeField] private ItemStyle m_ItemStyle = new ItemStyle();
[SerializeField] private Emphasis m_Emphasis = new Emphasis();
[SerializeField] [Range(1, 10)] private int m_ShowDataDimension;
[SerializeField] private bool m_ShowDataName;
[SerializeField] private bool m_ShowDataIcon;
@@ -355,11 +360,6 @@ namespace XCharts
/// </summary>
public SerieLabel label { get { return m_Label; } set { m_Label = value; } }
/// <summary>
/// Text label of highlight graphic element.
/// 高亮时的文本标签配置。
/// </summary>
public SerieLabel highlightLabel { get { return m_HighlightLabel; } set { m_HighlightLabel = value; } }
/// <summary>
/// The start animation.
/// 起始动画。
/// </summary>
@@ -367,9 +367,19 @@ namespace XCharts
public Animation animation { get { return m_Animation; } set { m_Animation = value; } }
/// <summary>
/// The arrow of line.
/// 折线图的箭头
/// 折线图的箭头
/// </summary>
public LineArrow lineArrow { get { return m_LineArrow; } set { m_LineArrow = value; } }
/// <summary>
/// The style of data item.
/// 图形样式。
/// </summary>
public ItemStyle itemStyle { get { return m_ItemStyle; } set { m_ItemStyle = value; } }
/// <summary>
/// 高亮的图形样式和文本标签样式。
/// </summary>
public Emphasis emphasis { get { return m_Emphasis; } set { m_Emphasis = value; } }
/// <summary>
/// 系列中的数据内容数组。SerieData可以设置1到n维数据。
/// </summary>
@@ -738,7 +748,7 @@ namespace XCharts
/// </summary>
/// <param name="dataZoom"></param>
/// <returns></returns>
public List<SerieData> GetDataList(DataZoom dataZoom)
public List<SerieData> GetDataList(DataZoom dataZoom = null)
{
if (dataZoom != null && dataZoom.enable)
{

View File

@@ -14,6 +14,7 @@ namespace XCharts
[SerializeField] [Range(1f, 20)] protected float m_LineSmoothness = 2f;
[SerializeField] [Range(1f, 20)] protected float m_LineSegmentDistance = 3f;
[SerializeField] [Range(1, 10)] protected float m_CicleSmoothness = 2f;
[SerializeField] [Range(10, 50)] protected float m_VisualMapTriangeLen = 20f;
/// <summary>
/// Curve smoothing factor. By adjusting the smoothing coefficient, the curvature of the curve can be changed,
@@ -41,6 +42,11 @@ namespace XCharts
/// 圆形的平滑度。数越小圆越平滑,但顶点数也会随之增加。
/// </summary>
public float cicleSmoothness { get { return m_CicleSmoothness; } set { m_CicleSmoothness = value <= 0 ? 1f : value; } }
/// <summary>
/// 可视化组件的调节三角形变长。
/// </summary>
/// <value></value>
public float visualMapTriangeLen { get { return m_VisualMapTriangeLen; } set { m_VisualMapTriangeLen = value <= 0 ? 1f : value; } }
}
}

View File

@@ -50,6 +50,8 @@ namespace XCharts
[SerializeField] private Color32 m_DataZoomTextColor;
[SerializeField] private Color32 m_DataZoomLineColor;
[SerializeField] private Color32 m_DataZoomSelectedColor;
[SerializeField] private Color32 m_VisualMapBackgroundColor;
[SerializeField] private Color32 m_VisualMapBorderColor;
[SerializeField] private Color32[] m_ColorPalette;
[SerializeField] private Font m_CustomFont;
@@ -70,6 +72,8 @@ namespace XCharts
[SerializeField] private Color32 m_CustomDataZoomTextColor;
[SerializeField] private Color32 m_CustomDataZoomLineColor;
[SerializeField] private Color32 m_CustomDataZoomSelectedColor;
[SerializeField] private Color32 m_CustomVisualMapBackgroundColor;
[SerializeField] private Color32 m_CustomVisualMapBorderColor;
[SerializeField] private List<Color32> m_CustomColorPalette = new List<Color32>(13);
/// <summary>
/// the theme of chart.
@@ -229,6 +233,25 @@ namespace XCharts
get { return m_CustomDataZoomSelectedColor != Color.clear ? m_CustomDataZoomSelectedColor : m_DataZoomSelectedColor; }
set { m_CustomDataZoomSelectedColor = value; }
}
/// <summary>
/// 视觉映射组件的背景色。
/// </summary>
public Color32 visualMapBackgroundColor
{
get { return m_CustomVisualMapBackgroundColor != Color.clear ? m_CustomVisualMapBackgroundColor : m_VisualMapBackgroundColor; }
set { m_CustomVisualMapBackgroundColor = value; }
}
/// <summary>
/// 视觉映射的边框色。
/// </summary>
public Color32 visualMapBorderColor
{
get { return m_CustomVisualMapBorderColor != Color.clear ? m_CustomVisualMapBorderColor : m_VisualMapBorderColor; }
set { m_CustomVisualMapBorderColor = value; }
}
/// <summary>
/// The color list of palette. If no color is set in series, the colors would be adopted sequentially and circularly from this list as the colors of series.
/// 调色盘颜色列表。如果系列没有设置颜色,则会依次循环从该列表中取颜色作为系列颜色。
@@ -304,6 +327,8 @@ namespace XCharts
m_DataZoomLineColor = theme.m_DataZoomLineColor;
m_DataZoomSelectedColor = theme.m_DataZoomSelectedColor;
m_DataZoomTextColor = theme.m_DataZoomTextColor;
m_VisualMapBackgroundColor = theme.m_VisualMapBackgroundColor;
m_VisualMapBorderColor = theme.m_VisualMapBorderColor;
m_ColorPalette = new Color32[theme.m_ColorPalette.Length];
for (int i = 0; i < theme.m_ColorPalette.Length; i++)
{
@@ -334,6 +359,8 @@ namespace XCharts
m_DataZoomLineColor = Color.clear;
m_DataZoomSelectedColor = Color.clear;
m_DataZoomTextColor = Color.clear;
m_VisualMapBackgroundColor = Color.clear;
m_VisualMapBorderColor = Color.clear;
for (int i = 0; i < m_CustomColorPalette.Count; i++)
{
m_CustomColorPalette[i] = Color.clear;
@@ -369,6 +396,8 @@ namespace XCharts
m_DataZoomLineColor = GetColor("#51515120"),
m_DataZoomSelectedColor = GetColor("#51515120"),
m_DataZoomTextColor = GetColor("#514D4D"),
m_VisualMapBackgroundColor = GetColor("#51515120"),
m_VisualMapBorderColor = GetColor("#cccccc"),
m_ColorPalette = new Color32[]
{
new Color32(194, 53, 49, 255),
@@ -429,6 +458,8 @@ namespace XCharts
m_DataZoomLineColor = GetColor("#51515120"),
m_DataZoomSelectedColor = GetColor("#51515120"),
m_DataZoomTextColor = GetColor("#514D4D"),
m_VisualMapBackgroundColor = GetColor("#51515120"),
m_VisualMapBorderColor = GetColor("#cccccc"),
m_ColorPalette = new Color32[]
{
new Color32(55, 162, 218, 255),
@@ -493,6 +524,8 @@ namespace XCharts
m_DataZoomLineColor = GetColor("#FFFFFF45"),
m_DataZoomSelectedColor = GetColor("#D0D0D03D"),
m_DataZoomTextColor = GetColor("#FFFFFFFF"),
m_VisualMapBackgroundColor = GetColor("#aaa"),
m_VisualMapBorderColor = GetColor("#cccccc"),
m_ColorPalette = new Color32[]
{
new Color32(221, 107, 102, 255),

View File

@@ -157,8 +157,8 @@ namespace XCharts
var tooltip = new Tooltip
{
m_Show = true,
xValues = new float[2],
yValues = new float[2],
xValues = new float[2]{-1,-1},
yValues = new float[2]{-1,-1},
dataIndex = new List<int>() { -1, -1 },
lastDataIndex = new List<int>() { -1, -1 }
};

View File

@@ -0,0 +1,389 @@
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
/// <summary>
/// VisualMap component.
/// 视觉映射组件。用于进行『视觉编码』,也就是将数据映射到视觉元素(视觉通道)。
/// </summary>
[System.Serializable]
public class VisualMap
{
/// <summary>
/// 类型。分为连续型和分段型。
/// </summary>
public enum Type
{
/// <summary>
/// 连续型。
/// </summary>
Continuous,
/// <summary>
/// 分段型。
/// </summary>
Piecewise
}
/// <summary>
/// 选择模式
/// </summary>
public enum SelectedMode
{
/// <summary>
/// 多选。
/// </summary>
Multiple,
/// <summary>
/// 单选。
/// </summary>
Single
}
[SerializeField] private bool m_Enable = false;
[SerializeField] private bool m_Show = true;
[SerializeField] private Type m_Type = Type.Continuous;
[SerializeField] private SelectedMode m_SelectedMode = SelectedMode.Multiple;
[SerializeField] private float m_Min = 0;
[SerializeField] private float m_Max = 100f;
[SerializeField] private float[] m_Range = new float[2] { 0, 100f };
[SerializeField] private string[] m_Text = new string[2] { "", "" };
[SerializeField] private float[] m_TextGap = new float[2] { 10f, 10f };
[SerializeField] private int m_SplitNumber = 5;
[SerializeField] private bool m_Calculable = false;
[SerializeField] private bool m_Realtime = true;
[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 bool m_HoverLink = true;
[SerializeField] private Orient m_Orient = Orient.Horizonal;
[SerializeField] private Location m_Location = Location.defaultLeft;
[SerializeField] private List<Color> m_InRange = new List<Color>();
[SerializeField] private List<Color> m_OutOfRange = new List<Color>();
/// <summary>
/// 是否开启组件功能。
/// </summary>
public bool enable { get { return m_Enable; } set { m_Enable = value; } }
/// <summary>
/// 是否显示组件。如果设置为 false不会显示但是数据映射的功能还存在。
/// </summary>
public bool show { get { return m_Show; } set { m_Show = value; } }
/// <summary>
/// 组件类型。
/// </summary>
public Type type { get { return m_Type; } set { m_Type = value; } }
/// <summary>
/// 选择模式。
/// </summary>
public SelectedMode selectedMode { get { return m_SelectedMode; } set { m_SelectedMode = value; } }
/// <summary>
/// 允许的最小值。'min' 必须用户指定。[visualMap.min, visualMap.max] 形成了视觉映射的『定义域』。
/// </summary>
public float min { get { return m_Min; } set { m_Min = value; } }
/// <summary>
/// 允许的最大值。'max' 必须用户指定。[visualMap.min, visualMax.max] 形成了视觉映射的『定义域』。
/// </summary>
public float max { get { return m_Max; } set { m_Max = value < min ? min + 1 : value; } }
/// <summary>
/// 指定手柄对应数值的位置。range 应在 min max 范围内。
/// </summary>
public float[] range { get { return m_Range; } }
/// <summary>
/// 两端的文本,如 ['High', 'Low']。
/// </summary>
public string[] text { get { return m_Text; } }
/// <summary>
/// 两端文字主体之间的距离单位为px。
/// </summary>
public float[] textGap { get { return m_TextGap; } }
/// <summary>
/// 对于连续型数据自动平均切分成几段默认为0时自动匹配inRange颜色列表大小。
/// </summary>
/// <value></value>
public int splitNumber { get { return m_SplitNumber; } set { m_SplitNumber = value; } }
/// <summary>
/// 是否显示拖拽用的手柄(手柄能拖拽调整选中范围)。
/// </summary>
public bool calculable { get { return m_Calculable; } set { m_Calculable = value; } }
/// <summary>
/// 拖拽时,是否实时更新。
/// </summary>
public bool realtime { get { return m_Realtime; } set { m_Realtime = value; } }
/// <summary>
/// 图形的宽度,即颜色条的宽度。
/// </summary>
public float itemWidth { get { return m_ItemWidth; } set { m_ItemWidth = value; } }
/// <summary>
/// 图形的高度,即颜色条的高度。
/// </summary>
public float itemHeight { get { return m_ItemHeight; } set { m_ItemHeight = value; } }
/// <summary>
/// 边框线宽单位px。
/// </summary>
public float borderWidth { get { return m_BorderWidth; } set { m_BorderWidth = value; } }
/// <summary>
/// 指定用数据的『哪个维度』,映射到视觉元素上。『数据』即 series.data。从1开始默认为0取 data 中最后一个维度。
/// </summary>
public int dimension { get { return m_Dimension; } set { m_Dimension = value; } }
/// <summary>
/// 打开 hoverLink 功能时,鼠标悬浮到 visualMap 组件上时,鼠标位置对应的数值 在 图表中对应的图形元素,会高亮。
/// 反之,鼠标悬浮到图表中的图形元素上时,在 visualMap 组件的相应位置会有三角提示其所对应的数值。
/// </summary>
/// <value></value>
public bool hoverLink { get { return m_HoverLink; } set { m_HoverLink = value; } }
/// <summary>
/// Specify whether the layout of component is horizontal or vertical.
/// 布局方式是横还是竖。
/// </summary>
public Orient orient { get { return m_Orient; } set { m_Orient = value; } }
/// <summary>
/// The location of component.
/// 组件显示的位置。
/// </summary>
public Location location { get { return m_Location; } set { m_Location = value; } }
/// <summary>
/// 定义 在选中范围中 的视觉颜色。
/// </summary>
public List<Color> inRange { get { return m_InRange; } set { if (value != null) m_InRange = value; } }
/// <summary>
/// 定义 在选中范围外 的视觉颜色。
/// </summary>
public List<Color> outOfRange { get { return m_OutOfRange; } set { if (value != null) m_OutOfRange = value; } }
/// <summary>
/// 鼠标悬停选中的index
/// </summary>
/// <value></value>
public int rtSelectedIndex { get; set; }
public float rtSelectedValue { get; set; }
/// <summary>
/// the current pointer position.
/// 当前鼠标位置。
/// </summary>
public Vector2 pointerPos { get; set; }
public bool isVertical { get { return orient == Orient.Vertical; } }
public float rangeMin
{
get
{
if (m_Range[0] < min || m_Range[0] > max) return min;
else return m_Range[0];
}
set
{
if (value >= min && value <= m_Range[1]) m_Range[0] = value;
}
}
public float rangeMax
{
get
{
if (m_Range[1] >= m_Range[0] && m_Range[1] < max) return m_Range[1];
else return max;
}
set
{
if (value >= m_Range[0] && value <= max) m_Range[1] = value;
}
}
public int rtSplitNumber
{
get
{
if (splitNumber > 0 && splitNumber <= m_InRange.Count) return splitNumber;
else return inRange.Count;
}
}
public float rangeMinHeight { get { return (rangeMin - min) / (max - min) * itemHeight; } }
public float rangeMaxHeight { get { return (rangeMax - min) / (max - min) * itemHeight; } }
private List<Color> m_RtInRange = new List<Color>();
public List<Color> rtInRange
{
get
{
if (splitNumber == 0 || m_InRange.Count >= splitNumber || m_InRange.Count < 1) return m_InRange;
else
{
if (m_RtInRange.Count != rtSplitNumber)
{
m_RtInRange.Clear();
var total = max - min;
var diff1 = total / (m_InRange.Count - 1);
var diff2 = total / splitNumber;
var inCount = 0;
var inValue = min;
var rtValue = min;
for (int i = 0; i < splitNumber; i++)
{
rtValue += diff2;
if (rtValue > inValue + diff1)
{
inValue += diff1;
inCount++;
}
if (i == splitNumber - 1)
{
m_RtInRange.Add(m_InRange[m_InRange.Count - 1]);
}
else
{
var rate = (rtValue - inValue) / diff1;
m_RtInRange.Add(Color.Lerp(m_InRange[inCount], m_InRange[inCount + 1], rate));
}
}
}
return m_RtInRange;
}
}
}
public Color GetColor(float value)
{
int splitNumber = rtInRange.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 rtInRange[index];
else return Color.Lerp(rtInRange[index], rtInRange[index + 1], rate);
}
public int GetIndex(float value)
{
int splitNumber = rtInRange.Count;
if (splitNumber <= 0) return -1;
value = Mathf.Clamp(value, min, max);
var diff = (max - min) / (splitNumber - 1);
var index = -1;
for (int i = 0; i < splitNumber; i++)
{
if (value <= min + (i + 1) * diff)
{
index = i;
break;
}
}
return index;
}
public bool IsInSelectedValue(float value)
{
if (rtSelectedIndex < 0) return true;
else
{
return rtSelectedIndex == GetIndex(value);
}
}
public float GetValue(Vector3 pos, float chartWidth, float chartHeight)
{
var centerPos = location.GetPosition(chartWidth, chartHeight);
var pos1 = centerPos + (isVertical ? Vector3.down : Vector3.left) * itemHeight / 2;
var pos2 = centerPos + (isVertical ? Vector3.up : Vector3.right) * itemHeight / 2;
if (isVertical)
{
if (pos.y < pos1.y) return min;
else if (pos.y > pos2.y) return max;
else return min + (pos.y - pos1.y) / (pos2.y - pos1.y) * (max - min);
}
else
{
if (pos.x < pos1.x) return min;
else if (pos.x > pos2.x) return max;
else return min + (pos.x - pos1.x) / (pos2.x - pos1.x) * (max - min);
}
}
public bool IsInRect(Vector3 local, float chartWidth, float chartHeight, float triangleLen = 20)
{
var centerPos = location.GetPosition(chartWidth, chartHeight);
var diff = calculable ? triangleLen : 0;
if (local.x >= centerPos.x - itemWidth / 2 - diff && local.x <= centerPos.x + itemWidth / 2 + diff &&
local.y >= centerPos.y - itemHeight / 2 - diff && local.y <= centerPos.y + itemHeight / 2 + diff)
{
return true;
}
else
{
return false;
}
}
public bool IsInRangeRect(Vector3 local, float chartWidth, float chartHeight)
{
var centerPos = location.GetPosition(chartWidth, chartHeight);
if (orient == Orient.Vertical)
{
var pos1 = centerPos + Vector3.down * itemHeight / 2;
return local.x >= centerPos.x - itemWidth / 2 && local.x <= centerPos.x + itemWidth / 2 &&
local.y >= pos1.y + rangeMinHeight && local.y <= pos1.y + rangeMaxHeight;
}
else
{
var pos1 = centerPos + Vector3.left * itemHeight / 2;
return local.x >= pos1.x + rangeMinHeight && local.x <= pos1.x + rangeMaxHeight &&
local.y >= centerPos.y - itemWidth / 2 && local.y <= centerPos.y + itemWidth / 2;
}
}
public bool IsInRangeMinRect(Vector3 local, float chartWidth, float chartHeight, float triangleLen)
{
var centerPos = location.GetPosition(chartWidth, chartHeight);
if (orient == Orient.Vertical)
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.down * itemHeight / 2;
var cpos = new Vector3(pos1.x + itemWidth / 2 + radius, pos1.y + rangeMinHeight - radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
else
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.left * itemHeight / 2;
var cpos = new Vector3(pos1.x + rangeMinHeight - radius, pos1.y + itemWidth / 2 + radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
}
public bool IsInRangeMaxRect(Vector3 local, float chartWidth, float chartHeight, float triangleLen)
{
var centerPos = location.GetPosition(chartWidth, chartHeight);
if (orient == Orient.Vertical)
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.down * itemHeight / 2;
var cpos = new Vector3(pos1.x + itemWidth / 2 + radius, pos1.y + rangeMaxHeight + radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
else
{
var radius = triangleLen / 2;
var pos1 = centerPos + Vector3.left * itemHeight / 2;
var cpos = new Vector3(pos1.x + rangeMaxHeight + radius, pos1.y + itemWidth / 2 + radius);
return local.x >= cpos.x - radius && local.x <= cpos.x + radius &&
local.y >= cpos.y - radius && local.y <= cpos.y + radius;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 066b3522287d94c9388681683567fad6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: