增加GanttChart甘特图

This commit is contained in:
monitor1394
2021-03-25 12:55:52 +08:00
parent e8fdea764c
commit da383c80ae
47 changed files with 968 additions and 72 deletions

View File

@@ -284,6 +284,7 @@ namespace XCharts
foreach (var component in m_Radars) component.SetAllDirty();
m_ReinitLabel = true;
m_ReinitTitle = true;
m_RefreshChart = true;
}
protected override void OnDestroy()

View File

@@ -178,6 +178,9 @@ namespace XCharts
case SerieType.Candlestick:
DrawCandlestickSerie(vh, colorIndex, serie);
break;
case SerieType.Gantt:
DrawGanttSerie(vh, colorIndex, serie);
break;
}
}
@@ -240,7 +243,7 @@ namespace XCharts
}
}
protected void UpdateTooltipValue(Vector2 local)
protected virtual void UpdateTooltipValue(Vector2 local)
{
var isCartesian = IsValue();
var dataCount = m_Series.list.Count > 0 ? m_Series.list[0].GetDataList(dataZoom).Count : 0;
@@ -495,6 +498,7 @@ namespace XCharts
yAxis.painter = m_Painter;
yAxis.refreshComponent = delegate ()
{
InitAxisRuntimeData(yAxis);
string objName = ChartCached.GetYAxisName(yAxisIndex);
var axisObj = ChartHelper.AddObject(objName, transform, graphAnchorMin,
graphAnchorMax, chartPivot, new Vector2(chartWidth, chartHeight));
@@ -593,6 +597,26 @@ namespace XCharts
yAxis.refreshComponent();
}
private void InitAxisRuntimeData(Axis axis)
{
if (axis.type != Axis.AxisType.Category) return;
if (axis.data.Count > 0) return;
var isYAxis = axis is YAxis;
if (this is GanttChart)
{
axis.runtimeData.Clear();
for (int i = 0; i < m_Series.Count; i++)
{
var serie = m_Series.GetSerie(i);
if(serie.yAxisIndex != axis.index) continue;
for (int j = serie.data.Count - 1; j >= 0; j--)
{
axis.runtimeData.Add(serie.data[j].name);
}
}
}
}
private void InitAxisX()
{
for (int i = 0; i < m_XAxes.Count; i++)
@@ -782,7 +806,7 @@ namespace XCharts
return new Vector3(grid.runtimeX + scaleWid, posY);
}
private void CheckMinMaxValue()
protected virtual void CheckMinMaxValue()
{
if (m_XAxes == null || m_YAxes == null) return;
for (int i = 0; i < m_XAxes.Count; i++)
@@ -806,23 +830,7 @@ namespace XCharts
}
float tempMinValue = 0;
float tempMaxValue = 0;
if (IsValue())
{
if (axis is XAxis)
{
SeriesHelper.GetXMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, false, axis.inverse, out tempMinValue, out tempMaxValue);
}
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
GetSeriesMinMaxValue(axis, axisIndex, out tempMinValue, out tempMaxValue);
if (tempMinValue != axis.runtimeMinValue || tempMaxValue != axis.runtimeMaxValue)
{
m_IsPlayingAnimation = true;
@@ -866,6 +874,26 @@ namespace XCharts
}
}
protected virtual void GetSeriesMinMaxValue(Axis axis, int axisIndex, out float tempMinValue, out float tempMaxValue)
{
if (IsValue())
{
if (axis is XAxis)
{
SeriesHelper.GetXMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue);
}
}
else
{
SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, false, axis.inverse, out tempMinValue, out tempMaxValue);
}
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
}
protected void UpdateAxisLabelText(Axis axis)
{
var grid = GetAxisGridOrDefault(axis);
@@ -1571,6 +1599,7 @@ namespace XCharts
{
base.OnRefreshLabel();
var anyPercentStack = SeriesHelper.IsPercentStack(m_Series, SerieType.Bar);
for (int i = 0; i < m_Series.Count; i++)
{
var serie = m_Series.GetSerie(i);
@@ -1578,6 +1607,7 @@ namespace XCharts
if (!serie.IsCoordinateSerie()) continue;
var total = serie.yTotal;
var isPercentStack = SeriesHelper.IsPercentStack(m_Series, serie.stack, SerieType.Bar);
for (int j = 0; j < serie.data.Count; j++)
{
var serieData = serie.data[j];
@@ -1602,7 +1632,7 @@ namespace XCharts
dimension = VisualMapHelper.GetDimension(visualMap, serieData.data.Count);
}
SerieLabelHelper.ResetLabel(serieData, serieLabel, theme, i);
SerieLabelHelper.ResetLabel(serieData.labelObject.label, serieLabel, theme, i);
value = serieData.data[dimension];
var content = "";

View File

@@ -0,0 +1,178 @@
/************************************************/
/* */
/* Copyright (c) 2018 - 2021 monitor1394 */
/* https://github.com/monitor1394 */
/* */
/************************************************/
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
public partial class CoordinateChart
{
protected void DrawGanttSerie(VertexHelper vh, int colorIndex, Serie serie)
{
if (!IsActive(serie.index)) return;
if (serie.animation.HasFadeOut()) return;
var showData = serie.GetDataList(null);
var yAxis = m_YAxes[serie.yAxisIndex];
var xAxis = m_XAxes[serie.xAxisIndex];
var grid = GetSerieGridOrDefault(serie);
var xCategoryWidth = AxisHelper.GetDataWidth(xAxis, grid.runtimeWidth, showData.Count, dataZoom);
var yCategoryWidth = AxisHelper.GetDataWidth(yAxis, grid.runtimeHeight, showData.Count, dataZoom);
var barGap = GetBarGap();
var barWidth = serie.GetBarWidth(yCategoryWidth);
var space = (yCategoryWidth - barWidth) / 2;
var dataChanging = false;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var minValue = xAxis.GetCurrMinValue(dataChangeDuration);
var maxValue = xAxis.GetCurrMaxValue(dataChangeDuration);
var pX = grid.runtimeX + (xAxis.boundaryGap ? xCategoryWidth / 2 : 0);
var pY = 0f;
var startY = grid.runtimeY - (yAxis.boundaryGap ? 0 : yCategoryWidth / 2);
var isTime = xAxis.type == Axis.AxisType.Time;
var categoryIndex = GetGanttSerieCategoryIndex(serie, grid.index);
var dataCount = serie.data.Count;
for (int i = 0; i < dataCount; i++)
{
var serieData = serie.data[i];
pY = startY + (categoryIndex - 1 - i) * yCategoryWidth;
DrawSerieData(vh, grid, serie, serieData, colorIndex, pX, pY, space, barWidth, isTime, minValue,
maxValue, xCategoryWidth);
}
if (dataChanging)
{
RefreshPainter(serie);
}
}
private void DrawSerieData(VertexHelper vh, Grid grid, Serie serie, SerieData serieData, int colorIndex,
float pX, float pY, float space, float barWidth, bool isTime, float minValue, float maxValue,
float xCategoryWidth)
{
var xStart = 0f;
var xEnd = 0f;
var xActualStart = 0f;
var xActualEnd = 0f;
var start = (int)serieData.GetData(0);
var end = (int)serieData.GetData(1);
var actualStart = (int)serieData.GetData(2);
var actualEnd = (int)serieData.GetData(3);
var enableActual = actualStart > 0 && actualEnd > 0;
if (isTime)
{
var valueTotal = maxValue - minValue;
xStart = pX + (start - minValue) / valueTotal * grid.runtimeWidth;
xEnd = pX + (end - minValue) / valueTotal * grid.runtimeWidth;
if (enableActual)
{
xActualStart = pX + (actualStart - minValue) / valueTotal * grid.runtimeWidth;
xActualEnd = pX + (actualEnd - minValue) / valueTotal * grid.runtimeWidth;
}
}
else
{
xStart = pX + start * xCategoryWidth;
xEnd = pX + end * xCategoryWidth;
if (enableActual)
{
xActualStart = pX + actualStart * xCategoryWidth;
xActualEnd = pX + actualEnd * xCategoryWidth;
}
}
var highlight = (serieData != null && serieData.highlighted)
|| serie.highlighted;
var itemStyle = SerieHelper.GetItemStyle(serie, serieData, highlight);
var color = SerieHelper.GetItemColor(serie, serieData, m_Theme, colorIndex, highlight);
var borderWidth = itemStyle.borderWidth;
var rect = DrawGanttBar(vh, grid, serie, serieData, itemStyle, color, pY, pY, space, barWidth, xStart,
xEnd);
if (enableActual)
{
var defaultActualColor = SerieHelper.GetItemColor(serie, serieData, m_Theme, colorIndex, true);
var actualColor = SerieHelper.GetItemColor0(serie, serieData, m_Theme, highlight, defaultActualColor);
var rect2 = DrawGanttBar(vh, grid, serie, serieData, itemStyle, actualColor, pY, pY, space, barWidth,
xActualStart, xActualEnd);
var rect3X = Mathf.Min(rect.x, rect2.x);
var rect3Width = Mathf.Max(rect.x + rect.width, rect2.x + rect2.width) - rect3X;
var rect3 = new Rect(rect3X, rect.y, rect3Width, rect.height);
serie.dataPoints.Add(rect3.center);
serieData.runtimePosition = rect3.center;
serieData.labelPosition = rect3.center;
serieData.runtimeRect = rect3;
}
else
{
serie.dataPoints.Add(rect.center);
serieData.runtimePosition = rect.center;
serieData.labelPosition = rect.center;
serieData.runtimeRect = rect;
}
}
private Rect DrawGanttBar(VertexHelper vh, Grid grid, Serie serie, SerieData serieData, ItemStyle itemStyle,
Color32 color, float pX, float pY, float space, float barWidth, float xStart, float xEnd)
{
var borderWidth = itemStyle.borderWidth;
var plb = new Vector3(xStart + borderWidth, pY + space + borderWidth);
var plt = new Vector3(xStart + borderWidth, pY + space + barWidth - borderWidth);
var prt = new Vector3(xEnd - borderWidth, pY + space + barWidth - borderWidth);
var prb = new Vector3(xEnd - borderWidth, pY + space + borderWidth);
var center = new Vector3((plb.x + prt.x) / 2, (plt.y + prb.y) / 2);
var itemWidth = Mathf.Abs(prt.x - plb.x);
var itemHeight = Mathf.Abs(plt.y - prb.y);
if (serie.clip)
{
plb = ClampInGrid(grid, plb);
plt = ClampInGrid(grid, plt);
prt = ClampInGrid(grid, prt);
prb = ClampInGrid(grid, prb);
center = ClampInGrid(grid, center);
}
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, color, color, 0,
itemStyle.cornerRadius, true, 0.5f);
}
else
{
CheckClipAndDrawPolygon(vh, ref prb, ref plb, ref plt, ref prt, color, color,
serie.clip, grid);
}
if (borderWidth != 0)
{
UGL.DrawBorder(vh, center, itemWidth, itemHeight, borderWidth, itemStyle.borderColor, 0,
itemStyle.cornerRadius, true, 0.5f);
}
return new Rect(plb.x, plb.y, xEnd - xStart, barWidth);
}
private int GetGanttSerieCategoryIndex(Serie currSerie, int gridIndex)
{
var count = m_Series.Count;
var index = 0;
for (int i = 0; i < count; i++)
{
var serie = m_Series.GetSerie(i);
if (serie.type != SerieType.Gantt) continue;
var grid = GetSerieGridOrDefault(serie);
if (grid.index != gridIndex) continue;
foreach (var serieData in serie.data)
{
index++;
}
if (serie.index == currSerie.index)
{
return index;
}
}
return index;
}
}
}

View File

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

View File

@@ -99,7 +99,7 @@ namespace XCharts
{
var value = serieData.GetCurrData(1);
var max = radar.GetIndicatorMax(n);
SerieLabelHelper.ResetLabel(serieData, serieLabel, chart.theme, i);
SerieLabelHelper.ResetLabel(serieData.labelObject.label, serieLabel, chart.theme, i);
serieData.SetLabelActive(serieData.labelPosition != Vector3.zero);
serieData.labelObject.SetLabelPosition(serieLabel.offset);
var content = SerieLabelHelper.GetFormatterContent(serie, serieData, value, max, serieLabel);

View File

@@ -53,6 +53,25 @@ namespace XCharts
return axis.splitNumber > 0 ? axis.splitNumber : 4;
}
}
else if (axis.type == Axis.AxisType.Time)
{
if (axis.interval > 0)
{
if (coordinateWid <= 0) return 0;
int num = Mathf.CeilToInt(axis.runtimeMinMaxRange / axis.interval);
int maxNum = Mathf.CeilToInt(coordinateWid / 15);
if (num > maxNum)
{
axis.interval *= 2;
num = Mathf.CeilToInt(axis.runtimeMinMaxRange / axis.interval);
}
return num;
}
else
{
return axis.splitNumber > 0 ? axis.splitNumber : 4;
}
}
else if (axis.type == Axis.AxisType.Log)
{
return axis.splitNumber > 0 ? axis.splitNumber : 4;
@@ -146,6 +165,23 @@ namespace XCharts
}
return axis.axisLabel.GetFormatterContent(value, minValue, maxValue, true);
}
else if (axis.type == Axis.AxisType.Time)
{
if (minValue == 0 && maxValue == 0) return string.Empty;
var value = 0f;
if (axis.interval > 0)
{
if (index == split) value = maxValue;
else value = minValue + index * axis.interval;
}
else
{
value = minValue + (maxValue - minValue) * index / split;
}
var timestamp = (int)value;
var dateTime = DateTimeUtil.GetDateTime(timestamp);
return axis.axisLabel.GetFormatterDateTime(dateTime);
}
var showData = axis.GetDataList(dataZoom);
int dataCount = showData.Count;
if (dataCount <= 0) return "";
@@ -177,11 +213,12 @@ namespace XCharts
int splitNum = GetSplitNumber(axis, coordinateWidth, dataZoom);
if (axis.IsCategory())
{
int tick = Mathf.RoundToInt(axis.data.Count * 1f / splitNum);
var data = axis.GetDataList();
int tick = Mathf.RoundToInt(data.Count * 1f / splitNum);
if (axis.boundaryGap)
return Mathf.CeilToInt(axis.data.Count * 1.0f / tick) + 1;
return Mathf.CeilToInt(data.Count * 1.0f / tick) + 1;
else
return Mathf.CeilToInt(axis.data.Count * 1.0f / tick);
return Mathf.CeilToInt(data.Count * 1.0f / tick);
}
else
{
@@ -209,10 +246,11 @@ namespace XCharts
}
else
{
if (axis.IsCategory() && axis.data.Count > 0)
var data = axis.GetDataList();
if (axis.IsCategory() && data.Count > 0)
{
int tick = Mathf.RoundToInt(axis.data.Count * 1f / splitNum);
var count = axis.boundaryGap ? axis.data.Count : axis.data.Count - 1;
int tick = Mathf.RoundToInt(data.Count * 1f / splitNum);
var count = axis.boundaryGap ? data.Count : data.Count - 1;
if (count <= 0) return 0;
var each = coordinateWidth / count;
if (index >= num - 1)
@@ -232,9 +270,10 @@ namespace XCharts
internal static float GetEachWidth(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
{
if (axis.data.Count > 0)
var data = axis.GetDataList();
if (data.Count > 0)
{
var count = axis.boundaryGap ? axis.data.Count : axis.data.Count - 1;
var count = axis.boundaryGap ? data.Count : data.Count - 1;
return count > 0 ? coordinateWidth / count : coordinateWidth;
}
else
@@ -249,7 +288,7 @@ namespace XCharts
/// </summary>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
internal static void AdjustMinMaxValue(Axis axis, ref float minValue, ref float maxValue, bool needFormat)
internal static void AdjustMinMaxValue(Axis axis, ref float minValue, ref float maxValue, bool needFormat, int ceilRate = 0)
{
if (axis.type == Axis.AxisType.Log)
{
@@ -278,6 +317,7 @@ namespace XCharts
}
else
{
if (ceilRate == 0) ceilRate = axis.ceilRate;
switch (axis.minMaxType)
{
case Axis.AxisMinMaxType.Default:
@@ -287,22 +327,22 @@ namespace XCharts
else if (minValue > 0 && maxValue > 0)
{
minValue = 0;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, axis.ceilRate) : maxValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
}
else if (minValue < 0 && maxValue < 0)
{
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, axis.ceilRate) : minValue;
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = 0;
}
else
{
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, axis.ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, axis.ceilRate) : maxValue;
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
}
break;
case Axis.AxisMinMaxType.MinMax:
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, axis.ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, axis.ceilRate) : maxValue;
minValue = needFormat ? ChartHelper.GetMinDivisibleValue(minValue, ceilRate) : minValue;
maxValue = needFormat ? ChartHelper.GetMaxDivisibleValue(maxValue, ceilRate) : maxValue;
break;
}
}
@@ -320,7 +360,7 @@ namespace XCharts
internal static bool NeedShowSplit(Axis axis)
{
if (!axis.show) return false;
if (axis.IsCategory() && axis.data.Count <= 0) return false;
if (axis.IsCategory() && axis.GetDataList().Count <= 0) return false;
else if (axis.IsValue() && axis.runtimeMinValue == 0 && axis.runtimeMaxValue == 0) return false;
else return true;
}

View File

@@ -70,6 +70,32 @@ namespace XCharts
return color;
}
}
internal static Color32 GetItemColor0(Serie serie, SerieData serieData, ChartTheme theme, bool highlight, Color32 defaultColor)
{
if (serie == null) return ChartConst.clearColor32;
if (highlight)
{
var itemStyleEmphasis = GetItemStyleEmphasis(serie, serieData);
if (itemStyleEmphasis != null && !ChartHelper.IsClearColor(itemStyleEmphasis.color))
{
var color = itemStyleEmphasis.color0;
ChartHelper.SetColorOpacity(ref color, itemStyleEmphasis.opacity);
return color;
}
}
var itemStyle = GetItemStyle(serie, serieData);
if (!ChartHelper.IsClearColor(itemStyle.color0))
{
return itemStyle.GetColor0();
}
else
{
var color = defaultColor;
if (highlight) color = ChartHelper.GetHighlightColor(color);
ChartHelper.SetColorOpacity(ref color, itemStyle.opacity);
return color;
}
}
internal static Color32 GetItemToColor(Serie serie, SerieData serieData, ChartTheme theme, int index, bool highlight)
{

View File

@@ -75,14 +75,13 @@ namespace XCharts
}
}
public static void ResetLabel(SerieData serieData, SerieLabel label, ChartTheme theme, int colorIndex)
public static void ResetLabel(ChartText labelObject, SerieLabel label, ChartTheme theme, int colorIndex)
{
if (serieData.labelObject == null) return;
if (serieData.labelObject.label == null) return;
serieData.labelObject.label.SetColor(!ChartHelper.IsClearColor(label.textStyle.color) ? label.textStyle.color :
if (labelObject == null) return;
labelObject.SetColor(!ChartHelper.IsClearColor(label.textStyle.color) ? label.textStyle.color :
(Color)theme.GetColor(colorIndex));
serieData.labelObject.label.SetFontSize(label.textStyle.GetFontSize(theme.common));
serieData.labelObject.label.SetFontStyle(label.textStyle.fontStyle);
labelObject.SetFontSize(label.textStyle.GetFontSize(theme.common));
labelObject.SetFontStyle(label.textStyle.fontStyle);
}
public static bool CanShowLabel(Serie serie, SerieData serieData, SerieLabel label, int dimesion)

View File

@@ -232,6 +232,14 @@ namespace XCharts
}
}
private static void InitGanttTooltip(ref StringBuilder sb, Tooltip tooltip, Serie serie, int index,
ChartTheme theme, string category)
{
//if (tooltip.runtimeGridIndex >= 0) return;
//if (serie.index != index || serie.type != SerieType.Gantt) return;
sb.Append(serie.name);
}
private static void InitDefaultContent(ref StringBuilder sb, Tooltip tooltip, Serie serie, int index,
string category, ChartTheme theme = null, DataZoom dataZoom = null, bool isCartesian = false,
Radar radar = null)
@@ -261,6 +269,9 @@ namespace XCharts
case SerieType.Gauge:
InitGaugeTooltip(ref sb, tooltip, serie, index, theme);
break;
case SerieType.Gantt:
InitGanttTooltip(ref sb, tooltip, serie, index, theme, category);
break;
}
}