3.0 - unitypackage

This commit is contained in:
monitor1394
2022-01-05 21:40:48 +08:00
parent c160867765
commit 228a4b2840
846 changed files with 105 additions and 467693 deletions

8
Runtime/Serie/Bar.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: db4db63725f6848e785146f5cf4bb657
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

37
Runtime/Serie/Bar/Bar.cs Normal file
View File

@@ -0,0 +1,37 @@
using System;
using System.Reflection;
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(BarHandler), true)]
[SerieConvert(typeof(Line), typeof(Pie))]
[RequireChartComponent(typeof(GridCoord))]
[DefaultAnimation(AnimationType.BottomToTop)]
[SerieExtraComponent(
typeof(LabelStyle),
typeof(IconStyle),
typeof(Emphasis))]
public class Bar : Serie, INeedSerieContainer, ISimplifiedSerie
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Bar>(serieName);
for (int i = 0; i < 5; i++)
{
chart.AddData(serie.index, UnityEngine.Random.Range(10, 90));
}
}
public static Bar CovertSerie(Serie serie)
{
var newSerie = SerieHelper.CloneSerie<Bar>(serie);
return newSerie;
}
}
}

View File

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

View File

@@ -0,0 +1,640 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class BarHandler : SerieHandler<Bar>
{
List<List<SerieData>> m_StackSerieData = new List<List<SerieData>>();
private GridCoord m_SerieGrid;
public override void Update()
{
base.Update();
UpdateSerieContext();
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
UpdateCoordSerieParams(ref paramList, ref title, dataIndex, showCategory, category,
marker, itemFormatter, numericFormatter);
}
public override void DrawSerie(VertexHelper vh)
{
DrawBarSerie(vh, serie, serie.context.colorIndex);
}
private void UpdateSerieContext()
{
if (m_SerieGrid == null)
return;
var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter()) || m_LegendEnter;
var needInteract = false;
if (!needCheck)
{
if (m_LastCheckContextFlag != needCheck)
{
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
return;
}
m_LastCheckContextFlag = needCheck;
if (m_LegendEnter)
{
serie.context.pointerEnter = true;
foreach (var serieData in serie.data)
{
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
}
else
{
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
if (serieData.context.rect.Contains(chart.pointerPos))
{
serie.context.pointerItemDataIndex = serieData.index;
serie.context.pointerEnter = true;
serieData.context.highlight = true;
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
else
{
serieData.context.highlight = false;
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
}
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
private void DrawBarSerie(VertexHelper vh, Bar serie, int colorIndex)
{
if (!serie.show || serie.animation.HasFadeOut())
return;
var isY = ComponentHelper.IsAnyCategoryOfYAxis(chart.components);
Axis axis;
Axis relativedAxis;
if (isY)
{
axis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
relativedAxis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
}
else
{
axis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
relativedAxis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
}
m_SerieGrid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
if (axis == null)
return;
if (relativedAxis == null)
return;
if (m_SerieGrid == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(axis);
var showData = serie.GetDataList(dataZoom);
if (showData.Count <= 0)
return;
var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width;
var axisXY = isY ? m_SerieGrid.context.y : m_SerieGrid.context.x;
var isStack = SeriesHelper.IsStack<Bar>(chart.series, serie.stack);
if (isStack)
SeriesHelper.UpdateStackDataList(chart.series, serie, dataZoom, m_StackSerieData);
float categoryWidth = AxisHelper.GetDataWidth(axis, axisLength, showData.Count, dataZoom);
float barGap = chart.GetSerieBarGap<Bar>();
float totalBarWidth = chart.GetSerieTotalWidth<Bar>(categoryWidth, barGap);
float barWidth = serie.GetBarWidth(categoryWidth);
float offset = (categoryWidth - totalBarWidth) * 0.5f;
float barGapWidth = barWidth + barWidth * barGap;
float space = serie.barGap == -1 ? offset : offset + chart.GetSerieIndexIfStack<Bar>(serie) * barGapWidth;
int maxCount = serie.maxShow > 0
? (serie.maxShow > showData.Count ? showData.Count : serie.maxShow)
: showData.Count;
var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series, serie.stack);
bool dataChanging = false;
float dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
double yMinValue = relativedAxis.context.minValue;
double yMaxValue = relativedAxis.context.maxValue;
var areaColor = ColorUtil.clearColor32;
var areaToColor = ColorUtil.clearColor32;
var interacting = false;
serie.containerIndex = m_SerieGrid.index;
serie.containterInstanceId = m_SerieGrid.instanceId;
serie.animation.InitProgress(axisXY, axisXY + axisLength);
for (int i = serie.minShow; i < maxCount; i++)
{
var serieData = showData[i];
if (!serieData.show || serie.IsIgnoreValue(serieData))
{
serie.context.dataPoints.Add(Vector3.zero);
continue;
}
if (serieData.IsDataChanged())
dataChanging = true;
var highlight = serieData.context.highlight || serie.highlight;
var itemStyle = SerieHelper.GetItemStyle(serie, serieData, highlight);
var value = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse);
var relativedValue = serieData.GetCurrData(1, dataChangeDuration, relativedAxis.inverse, yMinValue, yMaxValue);
var borderWidth = relativedValue == 0 ? 0 : itemStyle.runtimeBorderWidth;
if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting))
{
areaColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, highlight);
areaToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, highlight);
serieData.interact.SetColor(ref interacting, areaColor, areaToColor);
}
var pX = 0f;
var pY = 0f;
UpdateXYPosition(m_SerieGrid, isY, axis, relativedAxis, i, categoryWidth, barWidth, isStack, value, ref pX, ref pY);
var barHig = 0f;
if (isPercentStack)
{
var valueTotal = chart.GetSerieSameStackTotalValue<Bar>(serie.stack, i);
barHig = valueTotal != 0 ? (float)(relativedValue / valueTotal * axisLength) : 0;
}
else
{
barHig = AxisHelper.GetAxisValueLength(m_SerieGrid, relativedAxis, categoryWidth, relativedValue);
}
float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig);
Vector3 plb, plt, prt, prb, top;
UpdateRectPosition(m_SerieGrid, isY, relativedValue, pX, pY, space, borderWidth, barWidth, currHig,
out plb, out plt, out prt, out prb, out top);
serieData.context.stackHeight = barHig;
serieData.context.position = top;
serieData.context.rect = Rect.MinMaxRect(plb.x, plb.y, prb.x, prt.y);
serie.context.dataPoints.Add(top);
if (serie.show && currHig != 0)
{
switch (serie.barType)
{
case BarType.Normal:
DrawNormalBar(vh, serie, serieData, itemStyle, colorIndex, highlight, space, barWidth,
pX, pY, plb, plt, prt, prb, false, m_SerieGrid, areaColor, areaToColor);
break;
case BarType.Zebra:
DrawZebraBar(vh, serie, serieData, itemStyle, colorIndex, highlight, space, barWidth,
pX, pY, plb, plt, prt, prb, false, m_SerieGrid, areaColor, areaToColor);
break;
case BarType.Capsule:
DrawCapsuleBar(vh, serie, serieData, itemStyle, colorIndex, highlight, space, barWidth,
pX, pY, plb, plt, prt, prb, false, m_SerieGrid, areaColor, areaToColor);
break;
}
}
if (serie.animation.CheckDetailBreak(top, isY))
{
break;
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress();
chart.RefreshPainter(serie);
}
if (dataChanging || interacting)
{
chart.RefreshPainter(serie);
}
}
private void UpdateXYPosition(GridCoord grid, bool isY, Axis axis, Axis relativedAxis, int i, float categoryWidth, float barWidth, bool isStack,
double value, ref float pX, ref float pY)
{
if (isY)
{
if (axis.IsCategory())
{
pY = grid.context.y + i * categoryWidth + (axis.boundaryGap ? 0 : -categoryWidth * 0.5f);
}
else
{
if (axis.context.minMaxRange <= 0) pY = grid.context.y;
else pY = grid.context.y + (float)((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.height - barWidth);
}
pX = AxisHelper.GetAxisPosition(grid, relativedAxis, categoryWidth, 0);
if (isStack)
{
for (int n = 0; n < m_StackSerieData.Count - 1; n++)
pX += m_StackSerieData[n][i].context.stackHeight;
}
}
else
{
if (axis.IsCategory())
{
pX = grid.context.x + i * categoryWidth + (axis.boundaryGap ? 0 : -categoryWidth * 0.5f);
}
else
{
if (axis.context.minMaxRange <= 0) pX = grid.context.x;
else pX = grid.context.x + (float)((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.width - barWidth);
}
pY = AxisHelper.GetAxisPosition(grid, relativedAxis, categoryWidth, 0);
if (isStack)
{
for (int n = 0; n < m_StackSerieData.Count - 1; n++)
pY += m_StackSerieData[n][i].context.stackHeight;
}
}
}
private void UpdateRectPosition(GridCoord grid, bool isY, double yValue, float pX, float pY, float space, float borderWidth,
float barWidth, float currHig,
out Vector3 plb, out Vector3 plt, out Vector3 prt, out Vector3 prb, out Vector3 top)
{
if (isY)
{
if (yValue < 0)
{
plt = new Vector3(pX - borderWidth, pY + space + barWidth - borderWidth);
prt = new Vector3(pX + currHig + borderWidth, pY + space + barWidth - borderWidth);
prb = new Vector3(pX + currHig + borderWidth, pY + space + borderWidth);
plb = new Vector3(pX - borderWidth, pY + space + borderWidth);
}
else
{
plt = new Vector3(pX + borderWidth, pY + space + barWidth - borderWidth);
prt = new Vector3(pX + currHig - borderWidth, pY + space + barWidth - borderWidth);
prb = new Vector3(pX + currHig - borderWidth, pY + space + borderWidth);
plb = new Vector3(pX + borderWidth, pY + space + borderWidth);
}
top = new Vector3(pX + currHig - borderWidth, pY + space + barWidth / 2);
}
else
{
if (yValue < 0)
{
plb = new Vector3(pX + space + borderWidth, pY - borderWidth);
plt = new Vector3(pX + space + borderWidth, pY + currHig + borderWidth);
prt = new Vector3(pX + space + barWidth - borderWidth, pY + currHig + borderWidth);
prb = new Vector3(pX + space + barWidth - borderWidth, pY - borderWidth);
}
else
{
plb = new Vector3(pX + space + borderWidth, pY + borderWidth);
plt = new Vector3(pX + space + borderWidth, pY + currHig - borderWidth);
prt = new Vector3(pX + space + barWidth - borderWidth, pY + currHig - borderWidth);
prb = new Vector3(pX + space + barWidth - borderWidth, pY + borderWidth);
}
top = new Vector3(pX + space + barWidth / 2, pY + currHig - borderWidth);
}
if (serie.clip)
{
plb = chart.ClampInGrid(grid, plb);
plt = chart.ClampInGrid(grid, plt);
prt = chart.ClampInGrid(grid, prt);
prb = chart.ClampInGrid(grid, prb);
top = chart.ClampInGrid(grid, top);
}
}
private void DrawNormalBar(VertexHelper vh, Serie serie, SerieData serieData, ItemStyle itemStyle, int colorIndex,
bool highlight, float space, float barWidth, float pX, float pY, Vector3 plb, Vector3 plt, Vector3 prt,
Vector3 prb, bool isYAxis, GridCoord grid, Color32 areaColor, Color32 areaToColor)
{
DrawBarBackground(vh, serie, serieData, itemStyle, colorIndex, highlight, pX, pY, space, barWidth, isYAxis, grid);
var borderWidth = itemStyle.runtimeBorderWidth;
if (isYAxis)
{
if (serie.clip)
{
prb = chart.ClampInGrid(grid, prb);
plb = chart.ClampInGrid(grid, plb);
plt = chart.ClampInGrid(grid, plt);
prt = chart.ClampInGrid(grid, prt);
}
var itemWidth = Mathf.Abs(prb.x - plt.x);
var itemHeight = Mathf.Abs(prt.y - plb.y);
var center = new Vector3((plt.x + prb.x) / 2, (prt.y + plb.y) / 2);
if (itemWidth > 0 && itemHeight > 0)
{
var invert = center.x < plb.x;
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaToColor, 0,
itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
else
{
chart.DrawClipPolygon(vh, plb, plt, prt, prb, areaColor, areaToColor, serie.clip, grid);
}
UGL.DrawBorder(vh, center, itemWidth, itemHeight, borderWidth, itemStyle.borderColor,
itemStyle.borderToColor, 0, itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
}
else
{
if (serie.clip)
{
prb = chart.ClampInGrid(grid, prb);
plb = chart.ClampInGrid(grid, plb);
plt = chart.ClampInGrid(grid, plt);
prt = chart.ClampInGrid(grid, prt);
}
var itemWidth = Mathf.Abs(prt.x - plb.x);
var itemHeight = Mathf.Abs(plt.y - prb.y);
var center = new Vector3((plb.x + prt.x) / 2, (plt.y + prb.y) / 2);
if (itemWidth > 0 && itemHeight > 0)
{
var invert = center.y < plb.y;
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaToColor, 0,
itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
else
{
chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaToColor,
serie.clip, grid);
}
UGL.DrawBorder(vh, center, itemWidth, itemHeight, borderWidth, itemStyle.borderColor,
itemStyle.borderToColor, 0, itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
}
}
private void DrawZebraBar(VertexHelper vh, Serie serie, SerieData serieData, ItemStyle itemStyle, int colorIndex,
bool highlight, float space, float barWidth, float pX, float pY, Vector3 plb, Vector3 plt, Vector3 prt,
Vector3 prb, bool isYAxis, GridCoord grid, Color32 barColor, Color32 barToColor)
{
DrawBarBackground(vh, serie, serieData, itemStyle, colorIndex, highlight, pX, pY, space, barWidth, isYAxis, grid);
if (isYAxis)
{
plt = (plb + plt) / 2;
prt = (prt + prb) / 2;
chart.DrawClipZebraLine(vh, plt, prt, barWidth / 2, serie.barZebraWidth, serie.barZebraGap,
barColor, barToColor, serie.clip, grid);
}
else
{
plb = (prb + plb) / 2;
plt = (plt + prt) / 2;
chart.DrawClipZebraLine(vh, plb, plt, barWidth / 2, serie.barZebraWidth, serie.barZebraGap,
barColor, barToColor, serie.clip, grid);
}
}
private void DrawCapsuleBar(VertexHelper vh, Serie serie, SerieData serieData, ItemStyle itemStyle, int colorIndex,
bool highlight, float space, float barWidth, float pX, float pY, Vector3 plb, Vector3 plt, Vector3 prt,
Vector3 prb, bool isYAxis, GridCoord grid, Color32 areaColor, Color32 areaToColor)
{
DrawBarBackground(vh, serie, serieData, itemStyle, colorIndex, highlight, pX, pY, space, barWidth, isYAxis, grid);
var borderWidth = itemStyle.runtimeBorderWidth;
var radius = barWidth / 2 - borderWidth;
var isGradient = !ChartHelper.IsValueEqualsColor(areaColor, areaToColor);
if (isYAxis)
{
var diff = Vector3.right * radius;
if (plt.x < prt.x)
{
var pcl = (plt + plb) / 2 + diff;
var pcr = (prt + prb) / 2 - diff;
if (pcr.x > pcl.x)
{
if (isGradient)
{
var barLen = prt.x - plt.x;
var rectStartColor = Color32.Lerp(areaColor, areaToColor, radius / barLen);
var rectEndColor = Color32.Lerp(areaColor, areaToColor, (barLen - radius) / barLen);
chart.DrawClipPolygon(vh, plb + diff, plt + diff, prt - diff, prb - diff, rectStartColor,
rectEndColor, serie.clip, grid);
UGL.DrawSector(vh, pcl, radius, areaColor, rectStartColor, 180, 360, 1, isYAxis);
UGL.DrawSector(vh, pcr, radius, rectEndColor, areaToColor, 0, 180, 1, isYAxis);
}
else
{
chart.DrawClipPolygon(vh, plb + diff, plt + diff, prt - diff, prb - diff, areaColor,
areaToColor, serie.clip, grid);
UGL.DrawSector(vh, pcl, radius, areaColor, 180, 360);
UGL.DrawSector(vh, pcr, radius, areaToColor, 0, 180);
}
}
}
else if (plt.x > prt.x)
{
var pcl = (plt + plb) / 2 - diff;
var pcr = (prt + prb) / 2 + diff;
if (pcr.x < pcl.x)
{
if (isGradient)
{
var barLen = plt.x - prt.x;
var rectStartColor = Color32.Lerp(areaColor, areaToColor, radius / barLen);
var rectEndColor = Color32.Lerp(areaColor, areaToColor, (barLen - radius) / barLen);
chart.DrawClipPolygon(vh, plb - diff, plt - diff, prt + diff, prb + diff, rectStartColor,
rectEndColor, serie.clip, grid);
UGL.DrawSector(vh, pcl, radius, rectStartColor, areaColor, 0, 180, 1, isYAxis);
UGL.DrawSector(vh, pcr, radius, areaToColor, rectEndColor, 180, 360, 1, isYAxis);
}
else
{
chart.DrawClipPolygon(vh, plb - diff, plt - diff, prt + diff, prb + diff, areaColor,
areaToColor, serie.clip, grid);
UGL.DrawSector(vh, pcl, radius, areaColor, 0, 180);
UGL.DrawSector(vh, pcr, radius, areaToColor, 180, 360);
}
}
}
}
else
{
var diff = Vector3.up * radius;
if (plt.y > plb.y)
{
var pct = (plt + prt) / 2 - diff;
var pcb = (plb + prb) / 2 + diff;
if (pct.y > pcb.y)
{
if (isGradient)
{
var barLen = plt.y - plb.y;
var rectStartColor = Color32.Lerp(areaColor, areaToColor, radius / barLen);
var rectEndColor = Color32.Lerp(areaColor, areaToColor, (barLen - radius) / barLen);
chart.DrawClipPolygon(vh, prb + diff, plb + diff, plt - diff, prt - diff, rectStartColor,
rectEndColor, serie.clip, grid);
UGL.DrawSector(vh, pct, radius, rectEndColor, areaToColor, 270, 450, 1, isYAxis);
UGL.DrawSector(vh, pcb, radius, rectStartColor, areaColor, 90, 270, 1, isYAxis);
}
else
{
chart.DrawClipPolygon(vh, prb + diff, plb + diff, plt - diff, prt - diff, areaColor,
areaToColor, serie.clip, grid);
UGL.DrawSector(vh, pct, radius, areaToColor, 270, 450);
UGL.DrawSector(vh, pcb, radius, areaColor, 90, 270);
}
}
}
else if (plt.y < plb.y)
{
var pct = (plt + prt) / 2 + diff;
var pcb = (plb + prb) / 2 - diff;
if (pct.y < pcb.y)
{
if (isGradient)
{
var barLen = plb.y - plt.y;
var rectStartColor = Color32.Lerp(areaColor, areaToColor, radius / barLen);
var rectEndColor = Color32.Lerp(areaColor, areaToColor, (barLen - radius) / barLen);
chart.DrawClipPolygon(vh, prb - diff, plb - diff, plt + diff, prt + diff, rectStartColor,
rectEndColor, serie.clip, grid);
UGL.DrawSector(vh, pct, radius, rectEndColor, areaToColor, 90, 270, 1, isYAxis);
UGL.DrawSector(vh, pcb, radius, rectStartColor, areaColor, 270, 450, 1, isYAxis);
}
else
{
chart.DrawClipPolygon(vh, prb - diff, plb - diff, plt + diff, prt + diff, areaColor,
areaToColor, serie.clip, grid);
UGL.DrawSector(vh, pct, radius, areaToColor, 90, 270);
UGL.DrawSector(vh, pcb, radius, areaColor, 270, 450);
}
}
}
}
}
private void DrawBarBackground(VertexHelper vh, Serie serie, SerieData serieData, ItemStyle itemStyle,
int colorIndex, bool highlight, float pX, float pY, float space, float barWidth, bool isYAxis, GridCoord grid)
{
var color = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, colorIndex, highlight, false);
if (ChartHelper.IsClearColor(color)) return;
if (isYAxis)
{
var axis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
var axisWidth = axis.axisLine.GetWidth(chart.theme.axis.lineWidth);
Vector3 plt = new Vector3(grid.context.x + axisWidth, pY + space + barWidth);
Vector3 prt = new Vector3(grid.context.x + axisWidth + grid.context.width, pY + space + barWidth);
Vector3 prb = new Vector3(grid.context.x + axisWidth + grid.context.width, pY + space);
Vector3 plb = new Vector3(grid.context.x + axisWidth, pY + space);
if (serie.barType == BarType.Capsule)
{
var radius = barWidth / 2;
var diff = Vector3.right * radius;
var pcl = (plt + plb) / 2 + diff;
var pcr = (prt + prb) / 2 - diff;
chart.DrawClipPolygon(vh, plb + diff, plt + diff, prt - diff, prb - diff, color, color, serie.clip, grid);
UGL.DrawSector(vh, pcl, radius, color, 180, 360);
UGL.DrawSector(vh, pcr, radius, color, 0, 180);
if (itemStyle.NeedShowBorder())
{
var borderWidth = itemStyle.borderWidth;
var borderColor = itemStyle.borderColor;
var smoothness = chart.settings.cicleSmoothness;
var inRadius = radius - borderWidth;
var outRadius = radius;
var p1 = plb + diff + Vector3.up * borderWidth / 2;
var p2 = prb - diff + Vector3.up * borderWidth / 2;
var p3 = plt + diff - Vector3.up * borderWidth / 2;
var p4 = prt - diff - Vector3.up * borderWidth / 2;
UGL.DrawLine(vh, p1, p2, borderWidth / 2, borderColor);
UGL.DrawLine(vh, p3, p4, borderWidth / 2, borderColor);
UGL.DrawDoughnut(vh, pcl, inRadius, outRadius, borderColor, ChartConst.clearColor32,
180, 360, smoothness);
UGL.DrawDoughnut(vh, pcr, inRadius, outRadius, borderColor, ChartConst.clearColor32,
0, 180, smoothness);
}
}
else
{
chart.DrawClipPolygon(vh, ref plb, ref plt, ref prt, ref prb, color, color, serie.clip, grid);
}
}
else
{
var axis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
var axisWidth = axis.axisLine.GetWidth(chart.theme.axis.lineWidth);
Vector3 plb = new Vector3(pX + space, grid.context.y + axisWidth);
Vector3 plt = new Vector3(pX + space, grid.context.y + grid.context.height + axisWidth);
Vector3 prt = new Vector3(pX + space + barWidth, grid.context.y + grid.context.height + axisWidth);
Vector3 prb = new Vector3(pX + space + barWidth, grid.context.y + axisWidth);
if (serie.barType == BarType.Capsule)
{
var radius = barWidth / 2;
var diff = Vector3.up * radius;
var pct = (plt + prt) / 2 - diff;
var pcb = (plb + prb) / 2 + diff;
chart.DrawClipPolygon(vh, prb + diff, plb + diff, plt - diff, prt - diff, color, color,
serie.clip, grid);
UGL.DrawSector(vh, pct, radius, color, 270, 450);
UGL.DrawSector(vh, pcb, radius, color, 90, 270);
if (itemStyle.NeedShowBorder())
{
var borderWidth = itemStyle.borderWidth;
var borderColor = itemStyle.borderColor;
var smoothness = chart.settings.cicleSmoothness;
var inRadius = radius - borderWidth;
var outRadius = radius;
var p1 = plb + diff + Vector3.right * borderWidth / 2;
var p2 = plt - diff + Vector3.right * borderWidth / 2;
var p3 = prb + diff - Vector3.right * borderWidth / 2;
var p4 = prt - diff - Vector3.right * borderWidth / 2;
UGL.DrawLine(vh, p1, p2, borderWidth / 2, borderColor);
UGL.DrawLine(vh, p3, p4, borderWidth / 2, borderColor);
UGL.DrawDoughnut(vh, pct, inRadius, outRadius, borderColor, ChartConst.clearColor32,
270, 450, smoothness);
UGL.DrawDoughnut(vh, pcb, inRadius, outRadius, borderColor, ChartConst.clearColor32,
90, 270, smoothness);
}
}
else
{
chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, color, color, serie.clip, grid);
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,39 @@
using System;
using UnityEngine;
namespace XCharts
{
[Serializable]
[SerieHandler(typeof(SimplifiedBarHandler), true)]
[SerieConvert(typeof(SimplifiedLine), typeof(Bar))]
[CoordOptions(typeof(GridCoord))]
[DefaultAnimation(AnimationType.LeftToRight)]
[SerieExtraComponent()]
public class SimplifiedBar : Serie, INeedSerieContainer, ISimplifiedSerie
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<SimplifiedBar>(serieName);
serie.symbol.show = false;
var lastValue = 0d;
for (int i = 0; i < 50; i++)
{
if (i < 20)
lastValue += UnityEngine.Random.Range(0, 5);
else
lastValue += UnityEngine.Random.Range(-3, 5);
chart.AddData(serie.index, lastValue);
}
}
public static SimplifiedBar CovertSerie(Serie serie)
{
var newSerie = serie.Clone<SimplifiedBar>();
return newSerie;
}
}
}

View File

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

View File

@@ -0,0 +1,368 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class SimplifiedBarHandler : SerieHandler<SimplifiedBar>
{
private GridCoord m_SerieGrid;
public override void Update()
{
base.Update();
UpdateSerieContext();
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
UpdateCoordSerieParams(ref paramList, ref title, dataIndex, showCategory, category,
marker, itemFormatter, numericFormatter);
}
public override void DrawSerie(VertexHelper vh)
{
DrawBarSerie(vh, serie, serie.context.colorIndex);
}
private void UpdateSerieContext()
{
if (m_SerieGrid == null)
return;
var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter()) || m_LegendEnter;
var needInteract = false;
if (!needCheck)
{
if (m_LastCheckContextFlag != needCheck)
{
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
return;
}
m_LastCheckContextFlag = needCheck;
if (m_LegendEnter)
{
serie.context.pointerEnter = true;
foreach (var serieData in serie.data)
{
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
}
else
{
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
if (serieData.context.rect.Contains(chart.pointerPos))
{
serie.context.pointerItemDataIndex = serieData.index;
serie.context.pointerEnter = true;
serieData.context.highlight = true;
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, true);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
else
{
serieData.context.highlight = false;
var barColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
var barToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serie.context.colorIndex, false);
serieData.interact.SetColor(ref needInteract, barColor, barToColor);
}
}
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
private void DrawBarSerie(VertexHelper vh, SimplifiedBar serie, int colorIndex)
{
if (!serie.show || serie.animation.HasFadeOut())
return;
var isY = ComponentHelper.IsAnyCategoryOfYAxis(chart.components);
Axis axis;
Axis relativedAxis;
if (isY)
{
axis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
relativedAxis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
}
else
{
axis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
relativedAxis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
}
m_SerieGrid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
if (axis == null)
return;
if (relativedAxis == null)
return;
if (m_SerieGrid == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(axis);
var showData = serie.GetDataList(dataZoom);
if (showData.Count <= 0)
return;
var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width;
var axisXY = isY ? m_SerieGrid.context.y : m_SerieGrid.context.x;
float categoryWidth = AxisHelper.GetDataWidth(axis, axisLength, showData.Count, dataZoom);
float barGap = chart.GetSerieBarGap<Bar>();
float totalBarWidth = chart.GetSerieTotalWidth<Bar>(categoryWidth, barGap);
float barWidth = serie.GetBarWidth(categoryWidth);
float offset = (categoryWidth - totalBarWidth) * 0.5f;
float barGapWidth = barWidth + barWidth * barGap;
float space = serie.barGap == -1 ? offset : offset + serie.index * barGapWidth;
int maxCount = serie.maxShow > 0
? (serie.maxShow > showData.Count ? showData.Count : serie.maxShow)
: showData.Count;
bool dataChanging = false;
float dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
double yMinValue = relativedAxis.context.minValue;
double yMaxValue = relativedAxis.context.maxValue;
var areaColor = ColorUtil.clearColor32;
var areaToColor = ColorUtil.clearColor32;
var interacting = false;
serie.containerIndex = m_SerieGrid.index;
serie.containterInstanceId = m_SerieGrid.instanceId;
serie.animation.InitProgress(axisXY, axisXY + axisLength);
for (int i = serie.minShow; i < maxCount; i++)
{
var serieData = showData[i];
if (!serieData.show || serie.IsIgnoreValue(serieData))
{
serie.context.dataPoints.Add(Vector3.zero);
continue;
}
if (serieData.IsDataChanged())
dataChanging = true;
var highlight = serieData.context.highlight || serie.highlight;
var itemStyle = SerieHelper.GetItemStyle(serie, serieData, highlight);
var value = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse);
var relativedValue = serieData.GetCurrData(1, dataChangeDuration, relativedAxis.inverse, yMinValue, yMaxValue);
var borderWidth = relativedValue == 0 ? 0 : itemStyle.runtimeBorderWidth;
if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting))
{
areaColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, highlight);
areaToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, highlight);
serieData.interact.SetColor(ref interacting, areaColor, areaToColor);
}
var pX = 0f;
var pY = 0f;
UpdateXYPosition(m_SerieGrid, isY, axis, relativedAxis, i, categoryWidth, barWidth, value, ref pX, ref pY);
var barHig = AxisHelper.GetAxisValueLength(m_SerieGrid, relativedAxis, categoryWidth, relativedValue);
var currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig);
Vector3 plb, plt, prt, prb, top;
UpdateRectPosition(m_SerieGrid, isY, relativedValue, pX, pY, space, borderWidth, barWidth, currHig,
out plb, out plt, out prt, out prb, out top);
serieData.context.stackHeight = barHig;
serieData.context.position = top;
serieData.context.rect = Rect.MinMaxRect(plb.x, plb.y, prb.x, prt.y);
serie.context.dataPoints.Add(top);
DrawNormalBar(vh, serie, serieData, itemStyle, colorIndex, highlight, space, barWidth,
pX, pY, plb, plt, prt, prb, false, m_SerieGrid, areaColor, areaToColor);
if (serie.animation.CheckDetailBreak(top, isY))
{
break;
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress();
chart.RefreshPainter(serie);
}
if (dataChanging || interacting)
{
chart.RefreshPainter(serie);
}
}
private void UpdateXYPosition(GridCoord grid, bool isY, Axis axis, Axis relativedAxis, int i, float categoryWidth, float barWidth,
double value, ref float pX, ref float pY)
{
if (isY)
{
if (axis.IsCategory())
{
pY = grid.context.y + i * categoryWidth + (axis.boundaryGap ? 0 : -categoryWidth * 0.5f);
}
else
{
if (axis.context.minMaxRange <= 0) pY = grid.context.y;
else pY = grid.context.y + (float)((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.height - barWidth);
}
pX = AxisHelper.GetAxisPosition(grid, relativedAxis, categoryWidth, 0);
}
else
{
if (axis.IsCategory())
{
pX = grid.context.x + i * categoryWidth + (axis.boundaryGap ? 0 : -categoryWidth * 0.5f);
}
else
{
if (axis.context.minMaxRange <= 0) pX = grid.context.x;
else pX = grid.context.x + (float)((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.width - barWidth);
}
pY = AxisHelper.GetAxisPosition(grid, relativedAxis, categoryWidth, 0);
}
}
private void UpdateRectPosition(GridCoord grid, bool isY, double yValue, float pX, float pY, float space, float borderWidth,
float barWidth, float currHig,
out Vector3 plb, out Vector3 plt, out Vector3 prt, out Vector3 prb, out Vector3 top)
{
if (isY)
{
if (yValue < 0)
{
plt = new Vector3(pX - borderWidth, pY + space + barWidth - borderWidth);
prt = new Vector3(pX + currHig + borderWidth, pY + space + barWidth - borderWidth);
prb = new Vector3(pX + currHig + borderWidth, pY + space + borderWidth);
plb = new Vector3(pX - borderWidth, pY + space + borderWidth);
}
else
{
plt = new Vector3(pX + borderWidth, pY + space + barWidth - borderWidth);
prt = new Vector3(pX + currHig - borderWidth, pY + space + barWidth - borderWidth);
prb = new Vector3(pX + currHig - borderWidth, pY + space + borderWidth);
plb = new Vector3(pX + borderWidth, pY + space + borderWidth);
}
top = new Vector3(pX + currHig - borderWidth, pY + space + barWidth / 2);
}
else
{
if (yValue < 0)
{
plb = new Vector3(pX + space + borderWidth, pY - borderWidth);
plt = new Vector3(pX + space + borderWidth, pY + currHig + borderWidth);
prt = new Vector3(pX + space + barWidth - borderWidth, pY + currHig + borderWidth);
prb = new Vector3(pX + space + barWidth - borderWidth, pY - borderWidth);
}
else
{
plb = new Vector3(pX + space + borderWidth, pY + borderWidth);
plt = new Vector3(pX + space + borderWidth, pY + currHig - borderWidth);
prt = new Vector3(pX + space + barWidth - borderWidth, pY + currHig - borderWidth);
prb = new Vector3(pX + space + barWidth - borderWidth, pY + borderWidth);
}
top = new Vector3(pX + space + barWidth / 2, pY + currHig - borderWidth);
}
if (serie.clip)
{
plb = chart.ClampInGrid(grid, plb);
plt = chart.ClampInGrid(grid, plt);
prt = chart.ClampInGrid(grid, prt);
prb = chart.ClampInGrid(grid, prb);
top = chart.ClampInGrid(grid, top);
}
}
private void DrawNormalBar(VertexHelper vh, Serie serie, SerieData serieData, ItemStyle itemStyle, int colorIndex,
bool highlight, float space, float barWidth, float pX, float pY, Vector3 plb, Vector3 plt, Vector3 prt,
Vector3 prb, bool isYAxis, GridCoord grid, Color32 areaColor, Color32 areaToColor)
{
var borderWidth = itemStyle.runtimeBorderWidth;
if (isYAxis)
{
if (serie.clip)
{
prb = chart.ClampInGrid(grid, prb);
plb = chart.ClampInGrid(grid, plb);
plt = chart.ClampInGrid(grid, plt);
prt = chart.ClampInGrid(grid, prt);
}
var itemWidth = Mathf.Abs(prb.x - plt.x);
var itemHeight = Mathf.Abs(prt.y - plb.y);
var center = new Vector3((plt.x + prb.x) / 2, (prt.y + plb.y) / 2);
if (itemWidth > 0 && itemHeight > 0)
{
var invert = center.x < plb.x;
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaToColor, 0,
itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
else
{
chart.DrawClipPolygon(vh, plb, plt, prt, prb, areaColor, areaToColor, serie.clip, grid);
}
UGL.DrawBorder(vh, center, itemWidth, itemHeight, borderWidth, itemStyle.borderColor,
itemStyle.borderToColor, 0, itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
}
else
{
if (serie.clip)
{
prb = chart.ClampInGrid(grid, prb);
plb = chart.ClampInGrid(grid, plb);
plt = chart.ClampInGrid(grid, plt);
prt = chart.ClampInGrid(grid, prt);
}
var itemWidth = Mathf.Abs(prt.x - plb.x);
var itemHeight = Mathf.Abs(plt.y - prb.y);
var center = new Vector3((plb.x + prt.x) / 2, (plt.y + prb.y) / 2);
if (itemWidth > 0 && itemHeight > 0)
{
var invert = center.y < plb.y;
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaToColor, 0,
itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
else
{
chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaToColor,
serie.clip, grid);
}
UGL.DrawBorder(vh, center, itemWidth, itemHeight, borderWidth, itemStyle.borderColor,
itemStyle.borderToColor, 0, itemStyle.cornerRadius, isYAxis, chart.settings.cicleSmoothness, invert);
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 641a5dafd45e6455ca9ef9558efe1083
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(CandlestickHandler), true)]
[DefaultAnimation(AnimationType.LeftToRight)]
[SerieExtraComponent()]
public class Candlestick : Serie, INeedSerieContainer
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Candlestick>(serieName);
var defaultDataCount = 5;
for (int i = 0; i < defaultDataCount; i++)
{
var open = Random.Range(20, 60);
var close = Random.Range(40, 90);
var lowest = Random.Range(0, 50);
var heighest = Random.Range(50, 100);
chart.AddData(serie.index, open, close, lowest, heighest);
}
}
}
}

View File

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

View File

@@ -0,0 +1,213 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class CandlestickHandler : SerieHandler<Candlestick>
{
public override void DrawSerie(VertexHelper vh)
{
var colorIndex = chart.GetLegendRealShowNameIndex(serie.legendName);
DrawCandlestickSerie(vh, colorIndex, serie);
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
if (dataIndex < 0)
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
title = category;
var color = chart.GetLegendRealShowNameColor(serie.serieName);
var newMarker = SerieHelper.GetItemMarker(serie, serieData, marker);
var newItemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
var newNumericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
var param = serie.context.param;
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.category = category;
param.dimension = 1;
param.serieData = serieData;
param.value = 0;
param.total = 0;
param.color = color;
param.marker = newMarker;
param.itemFormatter = newItemFormatter;
param.numericFormatter = newNumericFormatter;
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(serie.serieName);
param.columns.Add(string.Empty);
paramList.Add(param);
for (int i = 0; i < 4; i++)
{
param = new SerieParams();
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.dimension = i;
param.serieData = serieData;
param.value = serieData.GetData(i);
param.total = SerieHelper.GetMaxData(serie, i);
param.color = color;
param.marker = newMarker;
param.itemFormatter = newItemFormatter;
param.numericFormatter = newNumericFormatter;
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(XCSettings.lang.GetCandlestickDimensionName(i));
param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter));
paramList.Add(param);
}
}
private void DrawCandlestickSerie(VertexHelper vh, int colorIndex, Candlestick serie)
{
if (!serie.show) return;
if (serie.animation.HasFadeOut()) return;
XAxis xAxis;
YAxis yAxis;
GridCoord grid;
if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return;
if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return;
if (!chart.TryGetChartComponent<GridCoord>(out grid, xAxis.gridIndex)) return;
var theme = chart.theme;
var dataZoom = chart.GetDataZoomOfAxis(xAxis);
var showData = serie.GetDataList(dataZoom);
float categoryWidth = AxisHelper.GetDataWidth(xAxis, grid.context.width, showData.Count, dataZoom);
float barWidth = serie.GetBarWidth(categoryWidth);
float space = (categoryWidth - barWidth) / 2;
int maxCount = serie.maxShow > 0
? (serie.maxShow > showData.Count ? showData.Count : serie.maxShow)
: showData.Count;
bool dataChanging = false;
float dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
double yMinValue = yAxis.context.minValue;
double yMaxValue = yAxis.context.maxValue;
var isYAxis = false;
serie.containerIndex = grid.index;
serie.containterInstanceId = grid.instanceId;
for (int i = serie.minShow; i < maxCount; i++)
{
var serieData = showData[i];
if (serie.IsIgnoreValue(serieData))
{
serie.context.dataPoints.Add(Vector3.zero);
continue;
}
var highlight = serie.data[i].context.highlight || serie.highlight;
var itemStyle = SerieHelper.GetItemStyle(serie, serieData, highlight);
var open = serieData.GetCurrData(0, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var close = serieData.GetCurrData(1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var lowest = serieData.GetCurrData(2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var heighest = serieData.GetCurrData(3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var isRise = yAxis.inverse ? close < open : close > open;
var borderWidth = open == 0 ? 0f
: (itemStyle.runtimeBorderWidth == 0 ? theme.serie.candlestickBorderWidth
: itemStyle.runtimeBorderWidth);
if (serieData.IsDataChanged()) dataChanging = true;
float pX = grid.context.x + i * categoryWidth;
float zeroY = grid.context.y + yAxis.context.offset;
if (!xAxis.boundaryGap) pX -= categoryWidth / 2;
float pY = zeroY;
var barHig = 0f;
double valueTotal = yMaxValue - yMinValue;
var minCut = (yMinValue > 0 ? yMinValue : 0);
if (valueTotal != 0)
{
barHig = (float)((close - open) / valueTotal * grid.context.height);
pY += (float)((open - minCut) / valueTotal * grid.context.height);
}
serieData.context.stackHeight = barHig;
float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig);
Vector3 plb, plt, prt, prb, top;
plb = new Vector3(pX + space + borderWidth, pY + borderWidth);
plt = new Vector3(pX + space + borderWidth, pY + currHig - borderWidth);
prt = new Vector3(pX + space + barWidth - borderWidth, pY + currHig - borderWidth);
prb = new Vector3(pX + space + barWidth - borderWidth, pY + borderWidth);
top = new Vector3(pX + space + barWidth / 2, pY + currHig - borderWidth);
if (serie.clip)
{
plb = chart.ClampInGrid(grid, plb);
plt = chart.ClampInGrid(grid, plt);
prt = chart.ClampInGrid(grid, prt);
prb = chart.ClampInGrid(grid, prb);
top = chart.ClampInGrid(grid, top);
}
serie.context.dataPoints.Add(top);
var areaColor = isRise
? itemStyle.GetColor(theme.serie.candlestickColor)
: itemStyle.GetColor0(theme.serie.candlestickColor0);
var borderColor = isRise
? itemStyle.GetBorderColor(theme.serie.candlestickBorderColor)
: itemStyle.GetBorderColor0(theme.serie.candlestickBorderColor0);
var itemWidth = Mathf.Abs(prt.x - plb.x);
var itemHeight = Mathf.Abs(plt.y - prb.y);
var center = new Vector3((plb.x + prt.x) / 2, (plt.y + prb.y) / 2);
var lowPos = new Vector3(center.x, zeroY + (float)((lowest - minCut) / valueTotal * grid.context.height));
var heighPos = new Vector3(center.x, zeroY + (float)((heighest - minCut) / valueTotal * grid.context.height));
var openCenterPos = new Vector3(center.x, prb.y);
var closeCenterPos = new Vector3(center.x, prt.y);
if (barWidth > 2f * borderWidth)
{
if (itemWidth > 0 && itemHeight > 0)
{
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaColor, 0,
itemStyle.cornerRadius, isYAxis, 0.5f);
}
else
{
chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor,
serie.clip, grid);
}
UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0,
itemStyle.cornerRadius, isYAxis, 0.5f);
}
}
else
{
UGL.DrawLine(vh, openCenterPos, closeCenterPos, Mathf.Max(borderWidth, barWidth / 2), borderColor);
}
if (isRise)
{
UGL.DrawLine(vh, openCenterPos, lowPos, borderWidth, borderColor);
UGL.DrawLine(vh, closeCenterPos, heighPos, borderWidth, borderColor);
}
else
{
UGL.DrawLine(vh, closeCenterPos, lowPos, borderWidth, borderColor);
UGL.DrawLine(vh, openCenterPos, heighPos, borderWidth, borderColor);
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress();
}
if (dataChanging)
{
chart.RefreshPainter(serie);
}
}
}
}

View File

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

View File

@@ -0,0 +1,37 @@
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(SimplifiedCandlestickHandler), true)]
[DefaultAnimation(AnimationType.LeftToRight)]
[SerieExtraComponent()]
public class SimplifiedCandlestick : Serie, INeedSerieContainer, ISimplifiedSerie
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<SimplifiedCandlestick>(serieName);
var lastValue = 50d;
for (int i = 0; i < 50; i++)
{
lastValue += UnityEngine.Random.Range(-10, 20);
var open = lastValue + Random.Range(-10, 5);
var close = lastValue + Random.Range(-5, 10);
var lowest = lastValue + Random.Range(-15, -10);
var heighest = lastValue + Random.Range(10, 20);
chart.AddData(serie.index, open, close, lowest, heighest);
}
}
public static SimplifiedCandlestick CovertSerie(Serie serie)
{
var newSerie = serie.Clone<SimplifiedCandlestick>();
return newSerie;
}
}
}

View File

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

View File

@@ -0,0 +1,214 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class SimplifiedCandlestickHandler : SerieHandler<SimplifiedCandlestick>
{
public override void DrawSerie(VertexHelper vh)
{
var colorIndex = chart.GetLegendRealShowNameIndex(serie.legendName);
DrawCandlestickSerie(vh, colorIndex, serie);
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
if (dataIndex < 0)
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
title = category;
var color = chart.GetLegendRealShowNameColor(serie.serieName);
var newMarker = SerieHelper.GetItemMarker(serie, serieData, marker);
var newItemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
var newNumericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
var param = serie.context.param;
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.category = category;
param.dimension = 1;
param.serieData = serieData;
param.value = 0;
param.total = 0;
param.color = color;
param.marker = newMarker;
param.itemFormatter = newItemFormatter;
param.numericFormatter = newNumericFormatter;
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(serie.serieName);
param.columns.Add(string.Empty);
paramList.Add(param);
for (int i = 0; i < 4; i++)
{
param = new SerieParams();
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.dimension = i;
param.serieData = serieData;
param.value = serieData.GetData(i);
param.total = SerieHelper.GetMaxData(serie, i);
param.color = color;
param.marker = newMarker;
param.itemFormatter = newItemFormatter;
param.numericFormatter = newNumericFormatter;
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(XCSettings.lang.GetCandlestickDimensionName(i));
param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter));
paramList.Add(param);
}
}
private void DrawCandlestickSerie(VertexHelper vh, int colorIndex, SimplifiedCandlestick serie)
{
if (!serie.show) return;
if (serie.animation.HasFadeOut()) return;
XAxis xAxis;
YAxis yAxis;
GridCoord grid;
if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return;
if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return;
if (!chart.TryGetChartComponent<GridCoord>(out grid, xAxis.gridIndex)) return;
var theme = chart.theme;
var dataZoom = chart.GetDataZoomOfAxis(xAxis);
var showData = serie.GetDataList(dataZoom);
float categoryWidth = AxisHelper.GetDataWidth(xAxis, grid.context.width, showData.Count, dataZoom);
float barWidth = serie.GetBarWidth(categoryWidth);
float space = (categoryWidth - barWidth) / 2;
int maxCount = serie.maxShow > 0
? (serie.maxShow > showData.Count ? showData.Count : serie.maxShow)
: showData.Count;
bool dataChanging = false;
float dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
double yMinValue = yAxis.context.minValue;
double yMaxValue = yAxis.context.maxValue;
var isYAxis = false;
var itemStyle = serie.itemStyle;
serie.containerIndex = grid.index;
serie.containterInstanceId = grid.instanceId;
for (int i = serie.minShow; i < maxCount; i++)
{
var serieData = showData[i];
if (serie.IsIgnoreValue(serieData))
{
serie.context.dataPoints.Add(Vector3.zero);
continue;
}
var open = serieData.GetCurrData(0, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var close = serieData.GetCurrData(1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var lowest = serieData.GetCurrData(2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var heighest = serieData.GetCurrData(3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue);
var isRise = yAxis.inverse ? close < open : close > open;
var borderWidth = open == 0 ? 0f
: (itemStyle.runtimeBorderWidth == 0 ? theme.serie.candlestickBorderWidth
: itemStyle.runtimeBorderWidth);
if (serieData.IsDataChanged()) dataChanging = true;
float pX = grid.context.x + i * categoryWidth;
float zeroY = grid.context.y + yAxis.context.offset;
if (!xAxis.boundaryGap) pX -= categoryWidth / 2;
float pY = zeroY;
var barHig = 0f;
double valueTotal = yMaxValue - yMinValue;
var minCut = (yMinValue > 0 ? yMinValue : 0);
if (valueTotal != 0)
{
barHig = (float)((close - open) / valueTotal * grid.context.height);
pY += (float)((open - minCut) / valueTotal * grid.context.height);
}
serieData.context.stackHeight = barHig;
float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig);
Vector3 plb, plt, prt, prb, top;
plb = new Vector3(pX + space + borderWidth, pY + borderWidth);
plt = new Vector3(pX + space + borderWidth, pY + currHig - borderWidth);
prt = new Vector3(pX + space + barWidth - borderWidth, pY + currHig - borderWidth);
prb = new Vector3(pX + space + barWidth - borderWidth, pY + borderWidth);
top = new Vector3(pX + space + barWidth / 2, pY + currHig - borderWidth);
// if (serie.clip)
// {
// plb = chart.ClampInGrid(grid, plb);
// plt = chart.ClampInGrid(grid, plt);
// prt = chart.ClampInGrid(grid, prt);
// prb = chart.ClampInGrid(grid, prb);
// top = chart.ClampInGrid(grid, top);
// }
serie.context.dataPoints.Add(top);
var areaColor = isRise
? itemStyle.GetColor(theme.serie.candlestickColor)
: itemStyle.GetColor0(theme.serie.candlestickColor0);
var borderColor = isRise
? itemStyle.GetBorderColor(theme.serie.candlestickBorderColor)
: itemStyle.GetBorderColor0(theme.serie.candlestickBorderColor0);
var itemWidth = Mathf.Abs(prt.x - plb.x);
var itemHeight = Mathf.Abs(plt.y - prb.y);
var center = new Vector3((plb.x + prt.x) / 2, (plt.y + prb.y) / 2);
var lowPos = new Vector3(center.x, zeroY + (float)((lowest - minCut) / valueTotal * grid.context.height));
var heighPos = new Vector3(center.x, zeroY + (float)((heighest - minCut) / valueTotal * grid.context.height));
var openCenterPos = new Vector3(center.x, prb.y);
var closeCenterPos = new Vector3(center.x, prt.y);
if (barWidth > 2f * borderWidth)
{
if (itemWidth > 0 && itemHeight > 0)
{
if (ItemStyleHelper.IsNeedCorner(itemStyle))
{
UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaColor, 0,
itemStyle.cornerRadius, isYAxis, 0.5f);
}
else
{
chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor,
serie.clip, grid);
}
UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0,
itemStyle.cornerRadius, isYAxis, 0.5f);
}
if (isRise)
{
UGL.DrawLine(vh, openCenterPos, lowPos, borderWidth, borderColor);
UGL.DrawLine(vh, closeCenterPos, heighPos, borderWidth, borderColor);
}
else
{
UGL.DrawLine(vh, closeCenterPos, lowPos, borderWidth, borderColor);
UGL.DrawLine(vh, openCenterPos, heighPos, borderWidth, borderColor);
}
}
else
{
UGL.DrawLine(vh, openCenterPos, closeCenterPos, Mathf.Max(borderWidth, barWidth / 2), borderColor);
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress();
}
if (dataChanging)
{
chart.RefreshPainter(serie);
}
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 70535a50c140c47cc8cac1820dc03170
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(HeatmapHandler), true)]
[DefaultAnimation(AnimationType.LeftToRight)]
[SerieExtraComponent(typeof(LabelStyle), typeof(Emphasis))]
public class Heatmap : Serie, INeedSerieContainer
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Heatmap>(serieName);
serie.itemStyle.show = true;
serie.itemStyle.borderWidth = 1;
serie.itemStyle.borderColor = Color.clear;
var emphasis = serie.AddExtraComponent<Emphasis>();
emphasis.show = true;
emphasis.itemStyle.show = true;
emphasis.itemStyle.borderWidth = 1;
emphasis.itemStyle.borderColor = Color.black;
}
}
}

View File

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

View File

@@ -0,0 +1,189 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class HeatmapHandler : SerieHandler<Heatmap>
{
public override void Update()
{
base.Update();
UpdateSerieContext();
}
public override void DrawSerie(VertexHelper vh)
{
var colorIndex = chart.GetLegendRealShowNameIndex(serie.legendName);
DrawHeatmapSerie(vh, colorIndex, serie);
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
title = serie.serieName;
var param = serie.context.param;
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.dimension = 2;
param.serieData = serieData;
param.color = chart.theme.GetColor(serie.index);
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(category);
param.columns.Add(ChartCached.NumberToStr(serieData.GetData(2), param.numericFormatter));
paramList.Add(param);
}
private void UpdateSerieContext()
{
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
if (!chart.isPointerInChart)
return;
var grid = chart.GetChartComponent<GridCoord>(serie.containerIndex);
if (grid == null)
return;
if (!grid.IsPointerEnter())
return;
foreach (var serieData in serie.data)
{
if (serieData.context.rect.Contains(chart.pointerPos))
{
serie.context.pointerItemDataIndex = serieData.index;
serie.context.pointerEnter = true;
serieData.context.highlight = true;
chart.RefreshTopPainter();
}
else
{
serieData.context.highlight = false;
}
}
}
private void DrawHeatmapSerie(VertexHelper vh, int colorIndex, Heatmap serie)
{
if (serie.animation.HasFadeOut()) return;
XAxis xAxis;
YAxis yAxis;
GridCoord grid;
if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return;
if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return;
if (!chart.TryGetChartComponent<GridCoord>(out grid, xAxis.gridIndex)) return;
xAxis.boundaryGap = true;
yAxis.boundaryGap = true;
var visualMap = chart.GetVisualMapOfSerie(serie);
var emphasis = serie.emphasis;
var xCount = xAxis.data.Count;
var yCount = yAxis.data.Count;
var xWidth = grid.context.width / xCount;
var yWidth = grid.context.height / yCount;
var zeroX = grid.context.x;
var zeroY = grid.context.y;
var dataList = serie.GetDataList();
var rangeMin = visualMap.rangeMin;
var rangeMax = visualMap.rangeMax;
var color = chart.theme.GetColor(serie.index);
var borderWidth = serie.itemStyle.show ? serie.itemStyle.borderWidth : 0;
var rectWid = xWidth - 2 * borderWidth;
var rectHig = yWidth - 2 * borderWidth;
var borderColor = serie.itemStyle.opacity > 0 ? serie.itemStyle.borderColor : ChartConst.clearColor32;
borderColor.a = (byte)(borderColor.a * serie.itemStyle.opacity);
var borderToColor = serie.itemStyle.opacity > 0 ? serie.itemStyle.borderToColor : ChartConst.clearColor32;
borderToColor.a = (byte)(borderToColor.a * serie.itemStyle.opacity);
serie.context.dataPoints.Clear();
serie.animation.InitProgress(0, xCount);
var animationIndex = serie.animation.GetCurrIndex();
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var dataChanging = false;
serie.containerIndex = grid.index;
serie.containterInstanceId = grid.instanceId;
for (int i = 0; i < xCount; i++)
{
for (int j = 0; j < yCount; j++)
{
var dataIndex = i * yCount + j;
if (dataIndex >= dataList.Count) continue;
var serieData = dataList[dataIndex];
var dimension = VisualMapHelper.GetDimension(visualMap, serieData.data.Count);
serieData.index = dataIndex;
if (serie.IsIgnoreIndex(dataIndex, dimension))
{
serie.context.dataPoints.Add(Vector3.zero);
continue;
}
var value = serieData.GetCurrData(dimension, dataChangeDuration, yAxis.inverse,
yAxis.context.minValue, yAxis.context.maxValue);
if (serieData.IsDataChanged()) dataChanging = true;
var pos = new Vector3(zeroX + (i + (xAxis.boundaryGap ? 0.5f : 0)) * xWidth,
zeroY + (j + (yAxis.boundaryGap ? 0.5f : 0)) * yWidth);
serie.context.dataPoints.Add(pos);
serieData.context.canShowLabel = false;
serieData.context.rect = new Rect(pos.x - rectWid / 2, pos.y - rectHig / 2, rectWid, rectHig);
if (value == 0) continue;
if ((value < rangeMin && rangeMin != visualMap.min)
|| (value > rangeMax && rangeMax != visualMap.max))
{
continue;
}
if (!visualMap.IsInSelectedValue(value)) continue;
color = visualMap.GetColor(value);
if (animationIndex >= 0 && i > animationIndex) continue;
serieData.context.canShowLabel = true;
var highlight = (serieData.context.highlight)
|| visualMap.context.pointerIndex > 0;
UGL.DrawRectangle(vh, pos, rectWid / 2, rectHig / 2, color);
if (borderWidth > 0 && !ChartHelper.IsClearColor(borderColor))
{
UGL.DrawBorder(vh, pos, rectWid, rectHig, borderWidth, borderColor, borderToColor);
}
if (visualMap.hoverLink && highlight && emphasis != null && emphasis.show
&& emphasis.itemStyle.borderWidth > 0)
{
var emphasisBorderWidth = emphasis.itemStyle.borderWidth;
var emphasisBorderColor = emphasis.itemStyle.opacity > 0
? emphasis.itemStyle.borderColor : ChartConst.clearColor32;
var emphasisBorderToColor = emphasis.itemStyle.opacity > 0
? emphasis.itemStyle.borderToColor : ChartConst.clearColor32;
UGL.DrawBorder(vh, pos, rectWid, rectHig, emphasisBorderWidth, emphasisBorderColor,
emphasisBorderToColor);
}
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(xCount);
chart.RefreshPainter(serie);
}
if (dataChanging)
{
chart.RefreshPainter(serie);
}
}
}
}

View File

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

View File

@@ -0,0 +1,185 @@
using UnityEngine;
namespace XCharts
{
public class InteractData
{
private float m_PreviousValue = 0;
private float m_TargetValue = 0;
private Color32 m_PreviousColor;
private Color32 m_TargetColor;
private Color32 m_PreviousToColor;
private Color32 m_TargetToColor;
private float m_UpdateTime = 0;
private bool m_UpdateFlag = false;
private bool m_ValueEnable = false;
public void SetValue(ref bool needInteract, float size, bool highlight, float rate = 1.3f)
{
size = highlight ? size * rate : size;
SetValue(ref needInteract, size);
}
public void SetValue(ref bool needInteract, float size)
{
if (m_TargetValue != size)
{
needInteract = true;
m_UpdateFlag = true;
m_ValueEnable = true;
m_UpdateTime = Time.time;
m_PreviousValue = m_TargetValue;
m_TargetValue = size;
}
}
public void SetColor(ref bool needInteract, Color32 color)
{
if (!ChartHelper.IsValueEqualsColor(color, m_TargetColor))
{
needInteract = true;
m_UpdateFlag = true;
m_ValueEnable = true;
m_UpdateTime = Time.time;
m_PreviousColor = m_TargetColor;
m_TargetColor = color;
}
}
public void SetColor(ref bool needInteract, Color32 color, Color32 toColor)
{
SetColor(ref needInteract, color);
if (!ChartHelper.IsValueEqualsColor(toColor, m_TargetToColor))
{
needInteract = true;
m_UpdateFlag = true;
m_ValueEnable = true;
m_UpdateTime = Time.time;
m_PreviousToColor = m_TargetToColor;
m_TargetToColor = toColor;
}
}
public void SetValueAndColor(ref bool needInteract, float value, Color32 color)
{
SetValue(ref needInteract, value);
SetColor(ref needInteract, color);
}
public void SetValueAndColor(ref bool needInteract, float value, Color32 color, Color32 toColor)
{
SetValue(ref needInteract, value);
SetColor(ref needInteract, color, toColor);
}
public bool TryGetValue(ref float value, ref bool interacting, float animationDuration = 250)
{
if (!m_ValueEnable || m_PreviousValue == 0)
return false;
if (m_UpdateFlag)
{
var time = Time.time - m_UpdateTime;
var total = animationDuration / 1000;
var rate = time / total;
if (rate > 1) rate = 1;
if (rate < 1)
{
interacting = true;
value = Mathf.Lerp(m_PreviousValue, m_TargetValue, rate);
return true;
}
else
{
m_UpdateFlag = false;
}
}
value = m_TargetValue;
return true;
}
public bool TryGetColor(ref Color32 color, ref bool interacting, float animationDuration = 250)
{
if (!m_ValueEnable)
return false;
if (m_UpdateFlag)
{
var time = Time.time - m_UpdateTime;
var total = animationDuration / 1000;
var rate = time / total;
if (rate > 1) rate = 1;
if (rate < 1)
{
interacting = true;
color = Color32.Lerp(m_PreviousColor, m_TargetColor, rate);
return true;
}
else
{
m_UpdateFlag = false;
}
}
color = m_TargetColor;
return true;
}
public bool TryGetColor(ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)
{
if (!m_ValueEnable)
return false;
if (m_UpdateFlag)
{
var time = Time.time - m_UpdateTime;
var total = animationDuration / 1000;
var rate = time / total;
if (rate > 1) rate = 1;
if (rate < 1)
{
interacting = true;
color = Color32.Lerp(m_PreviousColor, m_TargetColor, rate);
toColor = Color32.Lerp(m_PreviousToColor, m_TargetToColor, rate);
return true;
}
else
{
m_UpdateFlag = false;
}
}
color = m_TargetColor;
toColor = m_TargetToColor;
return true;
}
public bool TryGetValueAndColor(ref float value, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)
{
if (!m_ValueEnable)
return false;
if (m_UpdateFlag)
{
var time = Time.time - m_UpdateTime;
var total = animationDuration / 1000;
var rate = time / total;
if (rate > 1) rate = 1;
if (rate < 1)
{
interacting = true;
value = Mathf.Lerp(m_PreviousValue, m_TargetValue, rate);
color = Color32.Lerp(m_PreviousColor, m_TargetColor, rate);
toColor = Color32.Lerp(m_PreviousToColor, m_TargetToColor, rate);
return true;
}
else
{
m_UpdateFlag = false;
}
}
value = m_TargetValue;
color = m_TargetColor;
toColor = m_TargetToColor;
return true;
}
public void Reset()
{
m_ValueEnable = false;
}
}
}

View File

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

8
Runtime/Serie/Line.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 61f1a04d9920849e7861bebdfd070384
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
using System;
using UnityEngine;
namespace XCharts
{
[Serializable]
[SerieHandler(typeof(LineHandler), true)]
[SerieConvert(typeof(Bar), typeof(Pie))]
[CoordOptions(typeof(GridCoord), typeof(PolarCoord))]
[DefaultAnimation(AnimationType.LeftToRight)]
[SerieExtraComponent(
typeof(LabelStyle),
typeof(EndLabelStyle),
typeof(LineArrow),
typeof(AreaStyle),
typeof(IconStyle),
typeof(Emphasis))]
public class Line : Serie, INeedSerieContainer
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Line>(serieName);
serie.symbol.show = true;
for (int i = 0; i < 5; i++)
{
chart.AddData(serie.index, UnityEngine.Random.Range(10, 90));
}
}
public static Line CovertSerie(Serie serie)
{
var newSerie = serie.Clone<Line>();
return newSerie;
}
}
}

View File

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

View File

@@ -0,0 +1,447 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
/// <summary>
/// For grid coord
/// </summary>
[UnityEngine.Scripting.Preserve]
internal sealed partial class LineHandler : SerieHandler<Line>
{
List<List<SerieData>> m_StackSerieData = new List<List<SerieData>>();
private GridCoord m_SerieGrid;
public override void Update()
{
base.Update();
UpdateSerieContext();
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
UpdateCoordSerieParams(ref paramList, ref title, dataIndex, showCategory, category,
marker, itemFormatter, numericFormatter);
}
public override void DrawSerie(VertexHelper vh)
{
if (serie.IsUseCoord<PolarCoord>())
{
DrawPolarLine(vh, serie);
DrawPolarLineSymbol(vh);
}
else if (serie.IsUseCoord<GridCoord>())
{
DrawLineSerie(vh, serie);
if (!SeriesHelper.IsStack(chart.series))
{
DrawLinePoint(vh, serie);
DrawLineArrow(vh, serie);
}
}
}
public override void DrawTop(VertexHelper vh)
{
if (serie.IsUseCoord<GridCoord>())
{
if (SeriesHelper.IsStack(chart.series))
{
DrawLinePoint(vh, serie);
DrawLineArrow(vh, serie);
}
}
}
private void UpdateSerieContext()
{
if (m_SerieGrid == null)
return;
var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter()) || m_LegendEnter;
var lineWidth = 0f;
if (!needCheck)
{
if (m_LastCheckContextFlag != needCheck)
{
var needAnimation1 = false;
lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
serie.interact.SetValue(ref needAnimation1, lineWidth, false);
foreach (var serieData in serie.data)
{
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize);
serieData.context.highlight = false;
serieData.interact.SetValue(ref needAnimation1, symbolSize);
}
if (needAnimation1)
{
if (SeriesHelper.IsStack(chart.series))
chart.RefreshTopPainter();
else
chart.RefreshPainter(serie);
}
}
return;
}
m_LastCheckContextFlag = needCheck;
var themeSymbolSize = chart.theme.serie.lineSymbolSize;
var themeSymbolSelectedSize = chart.theme.serie.lineSymbolSelectedSize;
lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
var needInteract = false;
if (m_LegendEnter)
{
serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate);
for (int i = 0; i < serie.dataCount; i++)
{
var serieData = serie.data[i];
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSelectedSize = symbol.GetSelectedSize(serieData.data, themeSymbolSelectedSize);
serieData.context.highlight = true;
serieData.interact.SetValue(ref needInteract, symbolSelectedSize);
}
}
else if (serie.context.isTriggerByAxis)
{
serie.context.pointerEnter = true;
serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate);
for (int i = 0; i < serie.dataCount; i++)
{
var serieData = serie.data[i];
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, themeSymbolSize);
var symbolSelectedSize = symbol.GetSelectedSize(serieData.data, themeSymbolSelectedSize);
if (i == serie.context.pointerItemDataIndex)
{
serieData.context.highlight = true;
serieData.interact.SetValue(ref needInteract, symbolSelectedSize);
}
else
{
serieData.context.highlight = false;
serieData.interact.SetValue(ref needInteract, symbolSize);
}
}
}
else
{
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
var dist = Vector3.Distance(chart.pointerPos, serieData.context.position);
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, themeSymbolSize);
var symbolSelectedSize = symbol.GetSelectedSize(serieData.data, themeSymbolSelectedSize);
if (dist <= symbolSelectedSize)
{
serie.context.pointerItemDataIndex = serieData.index;
serie.context.pointerEnter = true;
serie.interact.SetValue(ref needInteract, lineWidth, true);
serieData.context.highlight = true;
serieData.interact.SetValue(ref needInteract, symbolSelectedSize);
}
else
{
serieData.context.highlight = false;
serieData.interact.SetValue(ref needInteract, symbolSize);
}
}
}
if (needInteract)
{
if (SeriesHelper.IsStack(chart.series))
chart.RefreshTopPainter();
else
chart.RefreshPainter(serie);
}
}
private void DrawLinePoint(VertexHelper vh, Serie serie)
{
if (!serie.show || serie.IsPerformanceMode())
return;
if (m_SerieGrid == null)
return;
var count = serie.context.dataPoints.Count;
var clip = SeriesHelper.IsAnyClipSerie(chart.series);
var theme = chart.theme;
var interacting = false;
var lineArrow = serie.lineArrow;
//var isY = ComponentHelper.IsAnyCategoryOfYAxis(chart.components);
for (int i = 0; i < count; i++)
{
var serieData = serie.GetSerieData(i);
if (serieData == null)
continue;
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
if (!symbol.show || !symbol.ShowSymbol(i, count))
continue;
var pos = serie.context.dataPoints[i];
// if (serie.animation.CheckDetailBreak(pos, isY))
// {
// continue;
// }
if (lineArrow != null && lineArrow.show)
{
if (lineArrow.position == LineArrow.Position.Start && i == 0)
continue;
if (lineArrow.position == LineArrow.Position.End && i == count - 1)
continue;
}
if (ChartHelper.IsIngore(pos))
continue;
var highlight = serie.data[i].context.highlight || serie.highlight;
var symbolSize = highlight
? theme.serie.lineSymbolSelectedSize
: theme.serie.lineSymbolSize;
if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting))
{
symbolSize = highlight
? symbol.GetSelectedSize(serieData.data, symbolSize)
: symbol.GetSize(serieData.data, symbolSize);
serieData.interact.SetValue(ref interacting, symbolSize);
symbolSize = serie.animation.GetSysmbolSize(symbolSize);
}
var symbolColor = SerieHelper.GetItemColor(serie, serieData, theme, serie.index, highlight);
var symbolToColor = SerieHelper.GetItemToColor(serie, serieData, theme, serie.index, highlight);
var symbolEmptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, theme, serie.index, highlight, false);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, theme, highlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, highlight);
chart.DrawClipSymbol(vh, symbol.type, symbolSize, symbolBorder, pos,
symbolColor, symbolToColor, symbolEmptyColor, symbol.gap, clip, cornerRadius, m_SerieGrid,
i > 0 ? serie.context.dataPoints[i - 1] : m_SerieGrid.context.position);
}
if (interacting)
{
if (SeriesHelper.IsStack(chart.series))
chart.RefreshTopPainter();
else
chart.RefreshPainter(serie);
}
}
private void DrawLineArrow(VertexHelper vh, Serie serie)
{
if (!serie.show || serie.lineArrow == null || !serie.lineArrow.show)
return;
if (serie.context.dataPoints.Count < 2)
return;
var lineColor = SerieHelper.GetLineColor(serie, chart.theme, serie.index, false);
var startPos = Vector3.zero;
var arrowPos = Vector3.zero;
var lineArrow = serie.lineArrow.arrow;
var dataPoints = serie.context.drawPoints;
switch (serie.lineArrow.position)
{
case LineArrow.Position.End:
if (dataPoints.Count < 3)
{
startPos = dataPoints[dataPoints.Count - 2].position;
arrowPos = dataPoints[dataPoints.Count - 1].position;
}
else
{
startPos = dataPoints[dataPoints.Count - 3].position;
arrowPos = dataPoints[dataPoints.Count - 2].position;
}
UGL.DrawArrow(vh, startPos, arrowPos, lineArrow.width, lineArrow.height,
lineArrow.offset, lineArrow.dent, lineArrow.GetColor(lineColor));
break;
case LineArrow.Position.Start:
startPos = dataPoints[1].position;
arrowPos = dataPoints[0].position;
UGL.DrawArrow(vh, startPos, arrowPos, lineArrow.width, lineArrow.height,
lineArrow.offset, lineArrow.dent, lineArrow.GetColor(lineColor));
break;
}
}
private void DrawLineSerie(VertexHelper vh, Line serie)
{
if (!serie.show)
return;
if (serie.animation.HasFadeOut())
return;
var isY = ComponentHelper.IsAnyCategoryOfYAxis(chart.components);
Axis axis;
Axis relativedAxis;
if (isY)
{
axis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
relativedAxis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
}
else
{
axis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
relativedAxis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
}
m_SerieGrid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
if (axis == null)
return;
if (relativedAxis == null)
return;
if (m_SerieGrid == null)
return;
var visualMap = chart.GetVisualMapOfSerie(serie);
var dataZoom = chart.GetDataZoomOfAxis(axis);
var showData = serie.GetDataList(dataZoom);
if (showData.Count <= 0)
return;
var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width;
var scaleWid = AxisHelper.GetDataWidth(axis, axisLength, showData.Count, dataZoom);
int maxCount = serie.maxShow > 0
? (serie.maxShow > showData.Count ? showData.Count : serie.maxShow)
: showData.Count;
int rate = LineHelper.GetDataAverageRate(serie, m_SerieGrid, maxCount, false);
var totalAverage = serie.sampleAverage > 0
? serie.sampleAverage
: DataHelper.DataAverage(ref showData, serie.sampleType, serie.minShow, maxCount, rate);
var dataChanging = false;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var interacting = false;
var lineWidth = LineHelper.GetLineWidth(ref interacting, serie, chart.theme.serie.lineWidth);
axis.context.scaleWidth = scaleWid;
serie.containerIndex = m_SerieGrid.index;
serie.containterInstanceId = m_SerieGrid.instanceId;
Serie lastSerie = null;
var isStack = SeriesHelper.IsStack<Line>(chart.series, serie.stack);
if (isStack)
{
lastSerie = SeriesHelper.GetLastStackSerie(chart.series, serie);
SeriesHelper.UpdateStackDataList(chart.series, serie, dataZoom, m_StackSerieData);
}
for (int i = serie.minShow; i < maxCount; i += rate)
{
var serieData = showData[i];
var isIgnore = serie.IsIgnoreValue(serieData);
if (isIgnore)
{
serieData.context.stackHeight = 0;
serieData.context.position = Vector3.zero;
if (serie.ignoreLineBreak && serie.context.dataIgnores.Count > 0)
{
serie.context.dataIgnores[serie.context.dataIgnores.Count - 1] = true;
}
}
else
{
var np = Vector3.zero;
var xValue = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse);
var relativedValue = DataHelper.SampleValue(ref showData, serie.sampleType, rate, serie.minShow,
maxCount, totalAverage, i, dataChangeDuration, ref dataChanging, relativedAxis);
serieData.context.stackHeight = GetDataPoint(isY, axis, relativedAxis, m_SerieGrid, xValue, relativedValue,
i, scaleWid, isStack, ref np);
serieData.context.position = np;
serie.context.dataPoints.Add(np);
serie.context.dataIgnores.Add(false);
}
}
if (dataChanging || interacting)
chart.RefreshPainter(serie);
if (serie.context.dataPoints.Count <= 0)
return;
serie.animation.InitProgress(serie.context.dataPoints, isY);
VisualMapHelper.AutoSetLineMinMax(visualMap, serie, isY, axis, relativedAxis);
LineHelper.UpdateSerieDrawPoints(serie, chart.settings, chart.theme, lineWidth, isY);
LineHelper.DrawSerieLineArea(vh, serie, lastSerie, chart.theme, isY, axis, relativedAxis, m_SerieGrid);
LineHelper.DrawSerieLine(vh, chart.theme, serie, visualMap, m_SerieGrid, axis, relativedAxis, lineWidth);
serie.context.vertCount = vh.currentVertCount;
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress();
serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize));
chart.RefreshPainter(serie);
}
}
private float GetDataPoint(bool isY, Axis axis, Axis relativedAxis, GridCoord grid, double xValue,
double yValue, int i, float scaleWid, bool isStack, ref Vector3 np)
{
float xPos, yPos;
var gridXY = isY ? grid.context.x : grid.context.y;
if (isY)
{
var valueHig = AxisHelper.GetAxisValueLength(grid, relativedAxis, scaleWid, yValue);
valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig);
xPos = gridXY + valueHig;
yPos = AxisHelper.GetAxisPosition(grid, axis, scaleWid, xValue);
if (isStack)
{
for (int n = 0; n < m_StackSerieData.Count - 1; n++)
xPos += m_StackSerieData[n][i].context.stackHeight;
}
}
else
{
var valueHig = AxisHelper.GetAxisValueLength(grid, relativedAxis, scaleWid, yValue);
valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig);
yPos = gridXY + valueHig;
xPos = AxisHelper.GetAxisPosition(grid, axis, scaleWid, xValue);
if (isStack)
{
for (int n = 0; n < m_StackSerieData.Count - 1; n++)
yPos += m_StackSerieData[n][i].context.stackHeight;
}
}
np = new Vector3(xPos, yPos);
return yPos;
}
}
}

View File

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

View File

@@ -0,0 +1,127 @@
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
/// <summary>
/// For polar coord
/// </summary>
internal sealed partial class LineHandler
{
private void DrawPolarLine(VertexHelper vh, Serie serie)
{
var datas = serie.data;
if (datas.Count <= 0)
return;
var m_Polar = chart.GetChartComponent<PolarCoord>(serie.polarIndex);
if (m_Polar == null)
return;
var m_AngleAxis = ComponentHelper.GetAngleAxis(chart.components, m_Polar.index);
var m_RadiusAxis = ComponentHelper.GetRadiusAxis(chart.components, m_Polar.index);
if (m_AngleAxis == null || m_RadiusAxis == null)
return;
var startAngle = m_AngleAxis.startAngle;
var radius = m_Polar.context.radius;
var min = m_RadiusAxis.context.minValue;
var max = m_RadiusAxis.context.maxValue;
var firstSerieData = datas[0];
var startPos = GetPolarPos(m_Polar, m_AngleAxis, firstSerieData, min, max, radius);
var nextPos = Vector3.zero;
var lineColor = SerieHelper.GetLineColor(serie, chart.theme, serie.index, serie.highlight);
var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
var currDetailProgress = 0f;
var totalDetailProgress = datas.Count;
serie.animation.InitProgress(currDetailProgress, totalDetailProgress);
for (int i = 1; i < datas.Count; i++)
{
if (serie.animation.CheckDetailBreak(i))
break;
var serieData = datas[i];
nextPos = GetPolarPos(m_Polar, m_AngleAxis, datas[i], min, max, radius);
UGL.DrawLine(vh, startPos, nextPos, lineWidth, lineColor);
startPos = nextPos;
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(totalDetailProgress);
serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize));
chart.RefreshChart();
}
}
private void DrawPolarLineSymbol(VertexHelper vh)
{
for (int n = 0; n < chart.series.Count; n++)
{
var serie = chart.series[n];
if (!serie.show)
continue;
if (!(serie is Line))
continue;
var count = serie.dataCount;
for (int i = 0; i < count; i++)
{
var serieData = serie.GetSerieData(i);
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
if (ChartHelper.IsIngore(serieData.context.position))
continue;
bool highlight = serieData.context.highlight || serie.highlight;
if ((!symbol.show || !symbol.ShowSymbol(i, count) || serie.IsPerformanceMode())
&& !serieData.context.highlight)
continue;
var symbolSize = highlight
? symbol.GetSelectedSize(serieData.data, chart.theme.serie.lineSymbolSize)
: symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize);
var symbolColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, n, highlight);
var symbolToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, n, highlight);
var symbolEmptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, n, highlight, false);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, chart.theme, highlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, highlight);
symbolSize = serie.animation.GetSysmbolSize(symbolSize);
chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, serieData.context.position,
symbolColor, symbolToColor, symbolEmptyColor, symbol.gap, cornerRadius);
}
}
}
private Vector3 GetPolarPos(PolarCoord m_Polar, AngleAxis m_AngleAxis, SerieData serieData, double min,
double max, float polarRadius)
{
var angle = 0f;
if (!m_AngleAxis.clockwise)
{
angle = m_AngleAxis.startAngle - (float)serieData.GetData(1);
}
else
{
angle = m_AngleAxis.startAngle + (float)serieData.GetData(1);
}
var value = serieData.GetData(0);
var radius = (float)((value - min) / (max - min) * polarRadius);
angle = (angle + 360) % 360;
serieData.context.angle = angle;
serieData.context.position = ChartHelper.GetPos(m_Polar.context.center, radius, angle, true);
return serieData.context.position;
}
}
}

View File

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

View File

@@ -0,0 +1,451 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
internal static class LineHelper
{
private static List<Vector3> s_CurvesPosList = new List<Vector3>();
public static int GetDataAverageRate(Serie serie, GridCoord grid, int maxCount, bool isYAxis)
{
var sampleDist = serie.sampleDist;
var rate = 0;
var width = isYAxis ? grid.context.height : grid.context.width;
if (sampleDist > 0)
rate = (int)((maxCount - serie.minShow) / (width / sampleDist));
if (rate < 1)
rate = 1;
return rate;
}
public static void DrawSerieLineArea(VertexHelper vh, Serie serie, Serie lastStackSerie,
ThemeStyle theme, bool isY, Axis axis, Axis relativedAxis, GridCoord grid)
{
if (serie.areaStyle == null || !serie.areaStyle.show)
return;
var srcAreaColor = SerieHelper.GetAreaColor(serie, theme, serie.context.colorIndex, false);
var srcAreaToColor = SerieHelper.GetAreaToColor(serie, theme, serie.context.colorIndex, false);
var gridXY = (isY ? grid.context.x : grid.context.y);
if (lastStackSerie == null)
{
LineHelper.DrawSerieLineNormalArea(vh, serie, isY,
gridXY + relativedAxis.context.offset,
gridXY,
gridXY + (isY ? grid.context.width : grid.context.height),
srcAreaColor,
srcAreaToColor);
}
else
{
LineHelper.DrawSerieLineStackArea(vh, serie, lastStackSerie, isY,
gridXY + relativedAxis.context.offset,
gridXY,
gridXY + (isY ? grid.context.width : grid.context.height),
srcAreaColor,
srcAreaToColor);
}
}
private static void DrawSerieLineNormalArea(VertexHelper vh, Serie serie, bool isY,
float zero, float min, float max, Color32 color, Color32 toColor)
{
var points = serie.context.drawPoints;
var count = points.Count;
if (count < 2)
return;
var isBreak = false;
var lp = Vector3.zero;
var lerp = !ChartHelper.IsValueEqualsColor(color, toColor);
var zsp = isY
? new Vector3(zero, points[0].position.y)
: new Vector3(points[0].position.x, zero);
var zep = isY
? new Vector3(zero, points[count - 1].position.y)
: new Vector3(points[count - 1].position.x, zero);
var lastDataIsIgnore = false;
for (int i = 0; i < points.Count; i++)
{
var tp = points[i].position;
var isIgnore = points[i].isIgnoreBreak;
if (serie.animation.CheckDetailBreak(tp, isY))
{
isBreak = true;
var progress = serie.animation.GetCurrDetail();
var ip = Vector3.zero;
var axisStartPos = isY ? new Vector3(-10000, progress) : new Vector3(progress, -10000);
var axisEndPos = isY ? new Vector3(10000, progress) : new Vector3(progress, 10000);
if (UGLHelper.GetIntersection(lp, tp, axisStartPos, axisEndPos, ref ip))
tp = ip;
}
var zp = isY ? new Vector3(zero, tp.y) : new Vector3(tp.x, zero);
if (i > 0)
{
if ((lp.y - zero > 0 && tp.y - zero < 0) || (lp.y - zero < 0 && tp.y - zero > 0))
{
var ip = Vector3.zero;
if (UGLHelper.GetIntersection(lp, tp, zsp, zep, ref ip))
{
if (lerp)
AddVertToVertexHelperWithLerpColor(vh, ip, ip, color, toColor, isY, min, max, i > 0);
else
{
if (lastDataIsIgnore)
UGL.AddVertToVertexHelper(vh, ip, ip, ColorUtil.clearColor32, true);
UGL.AddVertToVertexHelper(vh, ip, ip, toColor, color, i > 0);
if (isIgnore)
UGL.AddVertToVertexHelper(vh, ip, ip, ColorUtil.clearColor32, true);
}
}
}
}
if (lerp)
AddVertToVertexHelperWithLerpColor(vh, tp, zp, color, toColor, isY, min, max, i > 0);
else
{
if (lastDataIsIgnore)
UGL.AddVertToVertexHelper(vh, tp, zp, ColorUtil.clearColor32, true);
UGL.AddVertToVertexHelper(vh, tp, zp, toColor, color, i > 0);
if (isIgnore)
UGL.AddVertToVertexHelper(vh, tp, zp, ColorUtil.clearColor32, true);
}
lp = tp;
lastDataIsIgnore = isIgnore;
if (isBreak)
break;
}
}
private static void DrawSerieLineStackArea(VertexHelper vh, Serie serie, Serie lastStackSerie, bool isY,
float zero, float min, float max, Color32 color, Color32 toColor)
{
if (lastStackSerie == null)
return;
var upPoints = serie.context.drawPoints;
var downPoints = lastStackSerie.context.drawPoints;
var upCount = upPoints.Count;
var downCount = downPoints.Count;
if (upCount <= 0 || downCount <= 0)
return;
var lerp = !ChartHelper.IsValueEqualsColor(color, toColor);
var ltp = upPoints[0].position;
var lbp = downPoints[0].position;
if (lerp)
AddVertToVertexHelperWithLerpColor(vh, ltp, lbp, color, toColor, isY, min, max, false);
else
UGL.AddVertToVertexHelper(vh, ltp, lbp, color, false);
int u = 1, d = 1;
var isBreakTop = false;
var isBreakBottom = false;
while ((u < upCount || d < downCount))
{
var tp = u < upCount ? upPoints[u].position : upPoints[upCount - 1].position;
var bp = d < downCount ? downPoints[d].position : downPoints[downCount - 1].position;
var tnp = (u + 1) < upCount ? upPoints[u + 1].position : upPoints[upCount - 1].position;
var bnp = (d + 1) < downCount ? downPoints[d + 1].position : downPoints[downCount - 1].position;
if (serie.animation.CheckDetailBreak(tp, isY))
{
isBreakTop = true;
var progress = serie.animation.GetCurrDetail();
var ip = Vector3.zero;
if (UGLHelper.GetIntersection(ltp, tp,
new Vector3(progress, -10000),
new Vector3(progress, 10000), ref ip))
tp = ip;
else
tp = new Vector3(progress, tp.y);
}
if (serie.animation.CheckDetailBreak(bp, isY))
{
isBreakBottom = true;
var progress = serie.animation.GetCurrDetail();
var ip = Vector3.zero;
if (UGLHelper.GetIntersection(lbp, bp,
new Vector3(progress, -10000),
new Vector3(progress, 10000), ref ip))
bp = ip;
else
bp = new Vector3(progress, bp.y);
}
if (lerp)
AddVertToVertexHelperWithLerpColor(vh, tp, bp, color, toColor, isY, min, max, true);
else
UGL.AddVertToVertexHelper(vh, tp, bp, color, true);
u++;
d++;
if (bp.x < tp.x && bnp.x < tp.x)
u--;
if (tp.x < bp.x && tnp.x < bp.x)
d--;
ltp = tp;
lbp = bp;
if (isBreakTop && isBreakBottom)
break;
}
}
private static void AddVertToVertexHelperWithLerpColor(VertexHelper vh, Vector3 tp, Vector3 bp,
Color32 color, Color32 toColor, bool isY, float min, float max, bool needTriangle)
{
var range = max - min;
var color1 = Color32.Lerp(color, toColor, ((isY ? tp.x : tp.y) - min) / range);
var color2 = Color32.Lerp(color, toColor, ((isY ? bp.x : bp.y) - min) / range);
UGL.AddVertToVertexHelper(vh, tp, bp, color1, color2, needTriangle);
}
internal static void DrawSerieLine(VertexHelper vh, ThemeStyle theme, Serie serie, VisualMap visualMap,
GridCoord grid, Axis axis, Axis relativedAxis, float lineWidth)
{
var datas = serie.context.drawPoints;
var dataCount = datas.Count;
if (dataCount < 2)
return;
var ltp = Vector3.zero;
var lbp = Vector3.zero;
var ntp = Vector3.zero;
var nbp = Vector3.zero;
var itp = Vector3.zero;
var ibp = Vector3.zero;
var clp = Vector3.zero;
var crp = Vector3.zero;
var isBreak = false;
var isY = axis is YAxis;
var isVisualMapGradient = VisualMapHelper.IsNeedGradient(visualMap);
var isLineStyleGradient = serie.lineStyle.IsNeedGradient();
//var highlight = serie.highlight || serie.context.pointerEnter;
var lineColor = SerieHelper.GetLineColor(serie, theme, serie.context.colorIndex, false);
var lastDataIsIgnore = datas[0].isIgnoreBreak;
for (int i = 1; i < dataCount; i++)
{
var cdata = datas[i];
var isIgnore = cdata.isIgnoreBreak;
var cp = cdata.position;
var lp = datas[i - 1].position;
var np = i == dataCount - 1 ? cp : datas[i + 1].position;
if (serie.animation.CheckDetailBreak(cp, isY))
{
isBreak = true;
var ip = Vector3.zero;
var progress = serie.animation.GetCurrDetail();
if (AnimationStyleHelper.GetAnimationPosition(serie.animation, isY, lp, cp, progress, ref ip))
cp = np = ip;
}
bool bitp = true, bibp = true;
UGLHelper.GetLinePoints(lp, cp, np, lineWidth,
ref ltp, ref lbp,
ref ntp, ref nbp,
ref itp, ref ibp,
ref clp, ref crp,
ref bitp, ref bibp, i);
if (i == 1)
{
AddLineVertToVertexHelper(vh, ltp, lbp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, false, lastDataIsIgnore, isIgnore);
}
if (bitp == bibp)
{
if (bitp)
AddLineVertToVertexHelper(vh, itp, ibp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore);
else
{
AddLineVertToVertexHelper(vh, ltp, clp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore);
AddLineVertToVertexHelper(vh, ltp, crp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore);
}
}
else
{
if (bitp)
{
AddLineVertToVertexHelper(vh, itp, clp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore);
AddLineVertToVertexHelper(vh, itp, crp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore);
}
else if (bibp)
{
AddLineVertToVertexHelper(vh, clp, ibp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore);
AddLineVertToVertexHelper(vh, crp, ibp, lineColor, isVisualMapGradient, isLineStyleGradient,
visualMap, serie.lineStyle, grid, axis, relativedAxis, true, lastDataIsIgnore, isIgnore);
}
}
lastDataIsIgnore = isIgnore;
if (isBreak)
break;
}
}
public static float GetLineWidth(ref bool interacting, Serie serie, float defaultWidth)
{
var lineWidth = 0f;
if (!serie.interact.TryGetValue(ref lineWidth, ref interacting))
{
lineWidth = serie.lineStyle.GetWidth(defaultWidth);
serie.interact.SetValue(ref interacting, lineWidth);
}
return lineWidth;
}
private static void AddLineVertToVertexHelper(VertexHelper vh, Vector3 tp, Vector3 bp,
Color32 lineColor, bool visualMapGradient, bool lineStyleGradient, VisualMap visualMap,
LineStyle lineStyle, GridCoord grid, Axis axis, Axis relativedAxis, bool needTriangle,
bool lastIgnore, bool ignore)
{
if (lastIgnore && needTriangle)
UGL.AddVertToVertexHelper(vh, tp, bp, ColorUtil.clearColor32, true);
if (visualMapGradient)
{
var color1 = VisualMapHelper.GetLineGradientColor(visualMap, tp, grid, axis, relativedAxis, lineColor);
var color2 = VisualMapHelper.GetLineGradientColor(visualMap, bp, grid, axis, relativedAxis, lineColor);
UGL.AddVertToVertexHelper(vh, tp, bp, color1, color2, needTriangle);
}
else if (lineStyleGradient)
{
var color1 = VisualMapHelper.GetLineStyleGradientColor(lineStyle, tp, grid, axis, lineColor);
var color2 = VisualMapHelper.GetLineStyleGradientColor(lineStyle, bp, grid, axis, lineColor);
UGL.AddVertToVertexHelper(vh, tp, bp, color1, color2, needTriangle);
}
else
{
UGL.AddVertToVertexHelper(vh, tp, bp, lineColor, needTriangle);
}
if (lastIgnore && !needTriangle)
UGL.AddVertToVertexHelper(vh, tp, bp, ColorUtil.clearColor32, false);
if (ignore && needTriangle)
UGL.AddVertToVertexHelper(vh, tp, bp, ColorUtil.clearColor32, false);
}
internal static void UpdateSerieDrawPoints(Serie serie, Settings setting, ThemeStyle theme, float lineWidth, bool isY = false)
{
serie.context.drawPoints.Clear();
var last = Vector3.zero;
switch (serie.lineType)
{
case LineType.Smooth:
UpdateSmoothLineDrawPoints(serie, setting, isY);
break;
case LineType.StepStart:
case LineType.StepMiddle:
case LineType.StepEnd:
UpdateStepLineDrawPoints(serie, setting, theme, isY, lineWidth);
break;
default:
for (int i = 0; i < serie.context.dataPoints.Count; i++)
{
serie.context.drawPoints.Add(new PointInfo(serie.context.dataPoints[i], serie.context.dataIgnores[i]));
}
break;
}
}
private static void UpdateSmoothLineDrawPoints(Serie serie, Settings setting, bool isY)
{
var points = serie.context.dataPoints;
float smoothness = setting.lineSmoothness;
for (int i = 0; i < points.Count - 1; i++)
{
var sp = points[i];
var ep = points[i + 1];
var lsp = i > 0 ? points[i - 1] : sp;
var nep = i < points.Count - 2 ? points[i + 2] : ep;
var ignore = serie.context.dataIgnores[i];
if (isY)
UGLHelper.GetBezierListVertical(ref s_CurvesPosList, sp, ep, smoothness);
else
UGLHelper.GetBezierList(ref s_CurvesPosList, sp, ep, lsp, nep, smoothness);
for (int j = 1; j < s_CurvesPosList.Count; j++)
{
serie.context.drawPoints.Add(new PointInfo(s_CurvesPosList[j], ignore));
}
}
}
private static void UpdateStepLineDrawPoints(Serie serie, Settings setting, ThemeStyle theme, bool isY, float lineWidth)
{
var points = serie.context.dataPoints;
var lp = points[0];
serie.context.drawPoints.Clear();
serie.context.drawPoints.Add(new PointInfo(lp, serie.context.dataIgnores[0]));
for (int i = 1; i < points.Count; i++)
{
var cp = points[i];
var ignore = serie.context.dataIgnores[i];
if ((isY && Mathf.Abs(lp.x - cp.x) <= lineWidth)
|| (!isY && Mathf.Abs(lp.y - cp.y) <= lineWidth))
{
serie.context.drawPoints.Add(new PointInfo(cp, ignore));
lp = cp;
continue;
}
switch (serie.lineType)
{
case LineType.StepStart:
serie.context.drawPoints.Add(new PointInfo(isY
? new Vector3(cp.x, lp.y)
: new Vector3(lp.x, cp.y), ignore));
break;
case LineType.StepMiddle:
serie.context.drawPoints.Add(new PointInfo(isY
? new Vector3(lp.x, (lp.y + cp.y) / 2)
: new Vector3((lp.x + cp.x) / 2, lp.y), ignore));
serie.context.drawPoints.Add(new PointInfo(isY
? new Vector3(cp.x, (lp.y + cp.y) / 2)
: new Vector3((lp.x + cp.x) / 2, cp.y), ignore));
break;
case LineType.StepEnd:
serie.context.drawPoints.Add(new PointInfo(isY
? new Vector3(lp.x, cp.y)
: new Vector3(cp.x, lp.y), ignore));
break;
}
serie.context.drawPoints.Add(new PointInfo(cp, ignore));
lp = cp;
}
}
}
}

View File

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

View File

@@ -0,0 +1,39 @@
using System;
using UnityEngine;
namespace XCharts
{
[Serializable]
[SerieHandler(typeof(SimplifiedLineHandler), true)]
[SerieConvert(typeof(SimplifiedBar), typeof(Line))]
[CoordOptions(typeof(GridCoord))]
[DefaultAnimation(AnimationType.LeftToRight)]
[SerieExtraComponent(typeof(AreaStyle))]
public class SimplifiedLine : Serie, INeedSerieContainer, ISimplifiedSerie
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<SimplifiedLine>(serieName);
serie.symbol.show = false;
var lastValue = 0d;
for (int i = 0; i < 50; i++)
{
if (i < 20)
lastValue += UnityEngine.Random.Range(0, 5);
else
lastValue += UnityEngine.Random.Range(-3, 5);
chart.AddData(serie.index, lastValue);
}
}
public static SimplifiedLine CovertSerie(Serie serie)
{
var newSerie = serie.Clone<SimplifiedLine>();
return newSerie;
}
}
}

View File

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

View File

@@ -0,0 +1,281 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
/// <summary>
/// For grid coord
/// </summary>
[UnityEngine.Scripting.Preserve]
internal sealed class SimplifiedLineHandler : SerieHandler<SimplifiedLine>
{
private GridCoord m_SerieGrid;
public override void Update()
{
base.Update();
UpdateSerieContext();
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
UpdateCoordSerieParams(ref paramList, ref title, dataIndex, showCategory, category,
marker, itemFormatter, numericFormatter);
}
public override void DrawSerie(VertexHelper vh)
{
DrawLineSerie(vh, serie);
}
private void UpdateSerieContext()
{
if (m_SerieGrid == null)
return;
var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter()) || m_LegendEnter;
var lineWidth = 0f;
if (!needCheck)
{
if (m_LastCheckContextFlag != needCheck)
{
var needAnimation1 = false;
lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
serie.interact.SetValue(ref needAnimation1, lineWidth, false);
foreach (var serieData in serie.data)
{
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize);
serieData.context.highlight = false;
serieData.interact.SetValue(ref needAnimation1, symbolSize);
}
if (needAnimation1)
{
if (SeriesHelper.IsStack(chart.series))
chart.RefreshTopPainter();
else
chart.RefreshPainter(serie);
}
}
return;
}
m_LastCheckContextFlag = needCheck;
var themeSymbolSize = chart.theme.serie.lineSymbolSize;
var themeSymbolSelectedSize = chart.theme.serie.lineSymbolSelectedSize;
lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
var needInteract = false;
if (m_LegendEnter)
{
serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate);
for (int i = 0; i < serie.dataCount; i++)
{
var serieData = serie.data[i];
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSelectedSize = symbol.GetSelectedSize(serieData.data, themeSymbolSelectedSize);
serieData.context.highlight = true;
serieData.interact.SetValue(ref needInteract, symbolSelectedSize);
}
}
else if (serie.context.isTriggerByAxis)
{
serie.context.pointerEnter = true;
serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate);
for (int i = 0; i < serie.dataCount; i++)
{
var serieData = serie.data[i];
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, themeSymbolSize);
var symbolSelectedSize = symbol.GetSelectedSize(serieData.data, themeSymbolSelectedSize);
if (i == serie.context.pointerItemDataIndex)
{
serieData.context.highlight = true;
serieData.interact.SetValue(ref needInteract, symbolSelectedSize);
}
else
{
serieData.context.highlight = false;
serieData.interact.SetValue(ref needInteract, symbolSize);
}
}
}
else
{
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
var dist = Vector3.Distance(chart.pointerPos, serieData.context.position);
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, themeSymbolSize);
var symbolSelectedSize = symbol.GetSelectedSize(serieData.data, themeSymbolSelectedSize);
if (dist <= symbolSelectedSize)
{
serie.context.pointerItemDataIndex = serieData.index;
serie.context.pointerEnter = true;
serie.interact.SetValue(ref needInteract, lineWidth, true);
serieData.context.highlight = true;
serieData.interact.SetValue(ref needInteract, symbolSelectedSize);
}
else
{
serieData.context.highlight = false;
serieData.interact.SetValue(ref needInteract, symbolSize);
}
}
}
if (needInteract)
{
if (SeriesHelper.IsStack(chart.series))
chart.RefreshTopPainter();
else
chart.RefreshPainter(serie);
}
}
private void DrawLineSerie(VertexHelper vh, SimplifiedLine serie)
{
if (!serie.show)
return;
if (serie.animation.HasFadeOut())
return;
var isY = ComponentHelper.IsAnyCategoryOfYAxis(chart.components);
Axis axis;
Axis relativedAxis;
if (isY)
{
axis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
relativedAxis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
}
else
{
axis = chart.GetChartComponent<XAxis>(serie.xAxisIndex);
relativedAxis = chart.GetChartComponent<YAxis>(serie.yAxisIndex);
}
m_SerieGrid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
if (axis == null)
return;
if (relativedAxis == null)
return;
if (m_SerieGrid == null)
return;
var dataZoom = chart.GetDataZoomOfAxis(axis);
var showData = serie.GetDataList(dataZoom);
if (showData.Count <= 0)
return;
var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width;
var scaleWid = AxisHelper.GetDataWidth(axis, axisLength, showData.Count, dataZoom);
int maxCount = serie.maxShow > 0
? (serie.maxShow > showData.Count ? showData.Count : serie.maxShow)
: showData.Count;
int rate = LineHelper.GetDataAverageRate(serie, m_SerieGrid, maxCount, false);
var totalAverage = serie.sampleAverage > 0
? serie.sampleAverage
: DataHelper.DataAverage(ref showData, serie.sampleType, serie.minShow, maxCount, rate);
var dataChanging = false;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var interacting = false;
var lineWidth = LineHelper.GetLineWidth(ref interacting, serie, chart.theme.serie.lineWidth);
axis.context.scaleWidth = scaleWid;
serie.containerIndex = m_SerieGrid.index;
serie.containterInstanceId = m_SerieGrid.instanceId;
for (int i = serie.minShow; i < maxCount; i += rate)
{
var serieData = showData[i];
var isIgnore = serie.IsIgnoreValue(serieData);
if (isIgnore)
{
serieData.context.stackHeight = 0;
serieData.context.position = Vector3.zero;
if (serie.ignoreLineBreak && serie.context.dataIgnores.Count > 0)
{
serie.context.dataIgnores[serie.context.dataIgnores.Count - 1] = true;
}
}
else
{
var np = Vector3.zero;
var xValue = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse);
var relativedValue = DataHelper.SampleValue(ref showData, serie.sampleType, rate, serie.minShow,
maxCount, totalAverage, i, dataChangeDuration, ref dataChanging, relativedAxis);
serieData.context.stackHeight = GetDataPoint(isY, axis, relativedAxis, m_SerieGrid, xValue, relativedValue,
i, scaleWid, false, ref np);
serieData.context.position = np;
serie.context.dataPoints.Add(np);
serie.context.dataIgnores.Add(false);
}
}
if (dataChanging || interacting)
chart.RefreshPainter(serie);
if (serie.context.dataPoints.Count <= 0)
return;
serie.animation.InitProgress(serie.context.dataPoints, isY);
LineHelper.UpdateSerieDrawPoints(serie, chart.settings, chart.theme, lineWidth, isY);
LineHelper.DrawSerieLineArea(vh, serie, null, chart.theme, isY, axis, relativedAxis, m_SerieGrid);
LineHelper.DrawSerieLine(vh, chart.theme, serie, null, m_SerieGrid, axis, relativedAxis, lineWidth);
serie.context.vertCount = vh.currentVertCount;
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress();
chart.RefreshPainter(serie);
}
}
private float GetDataPoint(bool isY, Axis axis, Axis relativedAxis, GridCoord grid, double xValue,
double yValue, int i, float scaleWid, bool isStack, ref Vector3 np)
{
float xPos, yPos;
var gridXY = isY ? grid.context.x : grid.context.y;
if (isY)
{
var valueHig = AxisHelper.GetAxisValueLength(grid, relativedAxis, scaleWid, yValue);
valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig);
xPos = gridXY + valueHig;
yPos = AxisHelper.GetAxisPosition(grid, axis, scaleWid, xValue);
}
else
{
var valueHig = AxisHelper.GetAxisValueLength(grid, relativedAxis, scaleWid, yValue);
valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig);
yPos = gridXY + valueHig;
xPos = AxisHelper.GetAxisPosition(grid, axis, scaleWid, xValue);
}
np = new Vector3(xPos, yPos);
return yPos;
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 296736becc9a041c8ac957be56db7c8f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(LiquidHandler), true)]
[RequireChartComponent(typeof(Vessel))]
[SerieExtraComponent()]
public class Liquid : Serie, INeedSerieContainer
{
[SerializeField] private float m_WaveHeight = 10f;
[SerializeField] private float m_WaveLength = 20f;
[SerializeField] private float m_WaveSpeed = 5f;
[SerializeField] private float m_WaveOffset = 0f;
/// <summary>
/// Wave length of the wave, which is relative to the diameter.
/// 波长。为0-1小数时指直线的百分比。
/// </summary>
public float waveLength
{
get { return m_WaveLength; }
set { if (PropertyUtil.SetStruct(ref m_WaveLength, value)) SetVerticesDirty(); }
}
/// <summary>
/// 波高。
/// </summary>
public float waveHeight
{
get { return m_WaveHeight; }
set { if (PropertyUtil.SetStruct(ref m_WaveHeight, value)) SetVerticesDirty(); }
}
/// <summary>
/// 波偏移。
/// </summary>
public float waveOffset
{
get { return m_WaveOffset; }
set { if (PropertyUtil.SetStruct(ref m_WaveOffset, value)) SetVerticesDirty(); }
}
/// <summary>
/// 波速。正数时左移,负数时右移。
/// </summary>
public float waveSpeed
{
get { return m_WaveSpeed; }
set { if (PropertyUtil.SetStruct(ref m_WaveSpeed, value)) SetVerticesDirty(); }
}
public int containerIndex { get { return vesselIndex; } }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
chart.AddChartComponentWhenNoExist<Vessel>();
var serie = chart.AddSerie<Liquid>(serieName);
serie.min = 0;
serie.max = 100;
serie.AddExtraComponent<LabelStyle>();
serie.label.show = true;
serie.label.textStyle.fontSize = 40;
serie.label.formatter = "{d}%";
serie.label.textStyle.color = new Color32(70, 70, 240, 255);
chart.AddData(serie.index, UnityEngine.Random.Range(0, 100));
}
}
}

View File

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

View File

@@ -0,0 +1,371 @@
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class LiquidHandler : SerieHandler<Liquid>
{
private bool m_UpdateLabelText = false;
private float m_WaveSpeed;
public override void Update()
{
if (m_UpdateLabelText)
{
m_UpdateLabelText = false;
foreach (var serie in chart.series)
{
if (serie is Liquid)
{
var colorIndex = chart.m_LegendRealShowName.IndexOf(serie.serieName);
SerieLabelHelper.SetLiquidLabelText(serie, chart.theme, colorIndex);
}
}
}
}
public override void DrawSerie(VertexHelper vh)
{
UpdateRuntimeData(serie);
DrawVesselBackground(vh, serie);
DrawLiquid(vh, serie);
DrawVessel(vh, serie);
}
private void UpdateRuntimeData(Liquid serie)
{
Vessel vessel;
if (chart.TryGetChartComponent<Vessel>(out vessel, serie.vesselIndex))
{
VesselHelper.UpdateVesselCenter(vessel, chart.chartPosition, chart.chartWidth, chart.chartHeight);
}
}
private void DrawVesselBackground(VertexHelper vh, Liquid serie)
{
var vessel = chart.GetChartComponent<Vessel>(serie.vesselIndex);
if (vessel != null)
{
if (vessel.backgroundColor.a != 0)
{
switch (vessel.shape)
{
case Vessel.Shape.Circle:
var cenPos = vessel.context.center;
var radius = vessel.context.radius;
UGL.DrawCricle(vh, cenPos, vessel.context.innerRadius + vessel.gap, vessel.backgroundColor,
chart.settings.cicleSmoothness);
UGL.DrawDoughnut(vh, cenPos, vessel.context.innerRadius, vessel.context.innerRadius + vessel.gap,
vessel.backgroundColor, Color.clear, chart.settings.cicleSmoothness);
break;
case Vessel.Shape.Rect:
UGL.DrawRectangle(vh, vessel.context.center, vessel.context.width / 2, vessel.context.height / 2,
vessel.backgroundColor);
break;
default:
break;
}
}
}
}
private void DrawVessel(VertexHelper vh, Liquid serie)
{
var vessel = chart.GetChartComponent<Vessel>(serie.vesselIndex);
if (vessel != null)
{
switch (vessel.shape)
{
case Vessel.Shape.Circle:
DrawCirleVessel(vh, vessel);
break;
case Vessel.Shape.Rect:
DrawRectVessel(vh, vessel);
break;
default:
DrawCirleVessel(vh, vessel);
break;
}
}
}
private void DrawCirleVessel(VertexHelper vh, Vessel vessel)
{
var cenPos = vessel.context.center;
var radius = vessel.context.radius;
var serie = SeriesHelper.GetSerieByVesselIndex(chart.series, vessel.index);
var vesselColor = VesselHelper.GetColor(vessel, serie, chart.theme, chart.m_LegendRealShowName);
if (vessel.gap != 0)
{
UGL.DrawDoughnut(vh, cenPos, vessel.context.innerRadius, vessel.context.innerRadius + vessel.gap,
vessel.backgroundColor, Color.clear, chart.settings.cicleSmoothness);
}
UGL.DrawDoughnut(vh, cenPos, radius - vessel.shapeWidth, radius, vesselColor, Color.clear,
chart.settings.cicleSmoothness);
}
private void DrawRectVessel(VertexHelper vh, Vessel vessel)
{
var serie = SeriesHelper.GetSerieByVesselIndex(chart.series, vessel.index);
var vesselColor = VesselHelper.GetColor(vessel, serie, chart.theme, chart.m_LegendRealShowName);
if (vessel.gap != 0)
{
UGL.DrawBorder(vh, vessel.context.center, vessel.context.width,
vessel.context.height, vessel.gap, vessel.backgroundColor, 0, vessel.cornerRadius);
}
UGL.DrawBorder(vh, vessel.context.center, vessel.context.width + 2 * vessel.gap,
vessel.context.height + 2 * vessel.gap, vessel.shapeWidth, vesselColor, 0, vessel.cornerRadius);
}
private void DrawLiquid(VertexHelper vh, Liquid serie)
{
if (!serie.show) return;
if (serie.animation.HasFadeOut()) return;
var vessel = chart.GetChartComponent<Vessel>(serie.vesselIndex);
if (vessel == null) return;
switch (vessel.shape)
{
case Vessel.Shape.Circle:
DrawCirleLiquid(vh, serie, vessel);
break;
case Vessel.Shape.Rect:
DrawRectLiquid(vh, serie, vessel);
break;
default:
DrawCirleLiquid(vh, serie, vessel);
break;
}
}
private void DrawCirleLiquid(VertexHelper vh, Liquid serie, Vessel vessel)
{
var cenPos = vessel.context.center;
var radius = vessel.context.innerRadius;
var serieData = serie.GetSerieData(0);
if (serieData == null) return;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var value = serieData.GetCurrData(1, dataChangeDuration);
if (serie.context.checkValue != value)
{
serie.context.checkValue = value;
m_UpdateLabelText = true;
}
if (serieData.context.labelPosition != cenPos)
{
serieData.context.labelPosition = cenPos;
m_UpdateLabelText = true;
}
if (value <= 0) return;
var colorIndex = chart.m_LegendRealShowName.IndexOf(serie.serieName);
var realHig = (float)((value - serie.min) / (serie.max - serie.min) * radius * 2);
serie.animation.InitProgress(0, realHig);
var hig = serie.animation.IsFinish() ? realHig : serie.animation.GetCurrDetail();
var a = Mathf.Abs(radius - hig + (hig > radius ? serie.waveHeight : -serie.waveHeight));
var diff = Mathf.Sqrt(radius * radius - Mathf.Pow(a, 2));
var color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, false);
var toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, false);
var isNeedGradient = !ChartHelper.IsValueEqualsColor(color, toColor);
var isFull = hig >= 2 * radius;
if (hig >= 2 * radius) hig = 2 * radius;
if (isFull && !isNeedGradient)
{
UGL.DrawCricle(vh, cenPos, radius, toColor, chart.settings.cicleSmoothness);
}
else
{
var startY = cenPos.y - radius + hig;
var waveStartPos = new Vector3(cenPos.x - diff, startY);
var waveEndPos = new Vector3(cenPos.x + diff, startY);
var startX = hig > radius ? cenPos.x - radius : waveStartPos.x;
var endX = hig > radius ? cenPos.x + radius : waveEndPos.x;
var step = vessel.smoothness;
if (step < 0.5f) step = 0.5f;
var lup = hig > radius ? new Vector3(cenPos.x - radius, cenPos.y) : waveStartPos;
var ldp = lup;
var nup = Vector3.zero;
var ndp = Vector3.zero;
var angle = 0f;
m_WaveSpeed += serie.waveSpeed * Time.deltaTime;
var isStarted = false;
var isEnded = false;
var waveHeight = isFull ? 0 : serie.waveHeight;
while (startX < endX)
{
startX += step;
if (startX > endX) startX = endX;
if (startX > waveStartPos.x && !isStarted)
{
startX = waveStartPos.x;
isStarted = true;
}
if (startX > waveEndPos.x && !isEnded)
{
startX = waveEndPos.x;
isEnded = true;
}
var py = Mathf.Sqrt(Mathf.Pow(radius, 2) - Mathf.Pow(Mathf.Abs(cenPos.x - startX), 2));
if (startX < waveStartPos.x || startX > waveEndPos.x)
{
nup = new Vector3(startX, cenPos.y + py);
}
else
{
var py2 = waveHeight * Mathf.Sin(1 / serie.waveLength * angle + m_WaveSpeed + serie.waveOffset);
var nupY = waveStartPos.y + py2;
if (nupY > cenPos.y + py) nupY = cenPos.y + py;
else if (nupY < cenPos.y - py) nupY = cenPos.y - py;
nup = new Vector3(startX, nupY);
angle += step;
}
ndp = new Vector3(startX, cenPos.y - py);
if (!ChartHelper.IsValueEqualsColor(color, toColor))
{
var colorMin = cenPos.y - radius;
var colorMax = startY + serie.waveHeight;
var tcolor1 = Color32.Lerp(color, toColor, 1 - (lup.y - colorMin) / (colorMax - colorMin));
var tcolor2 = Color32.Lerp(color, toColor, 1 - (ldp.y - colorMin) / (colorMax - colorMin));
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, tcolor1, tcolor2);
}
else
{
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, color);
}
lup = nup;
ldp = ndp;
}
}
if (serie.waveSpeed != 0 && Application.isPlaying && !isFull)
{
chart.RefreshPainter(serie);
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(realHig);
chart.RefreshPainter(serie);
}
}
private void DrawRectLiquid(VertexHelper vh, Liquid serie, Vessel vessel)
{
var cenPos = vessel.context.center;
var serieData = serie.GetSerieData(0);
if (serieData == null) return;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var value = serieData.GetCurrData(1, dataChangeDuration);
if (serie.context.checkValue != value)
{
serie.context.checkValue = value;
m_UpdateLabelText = true;
}
if (serieData.context.labelPosition != cenPos)
{
serieData.context.labelPosition = cenPos;
m_UpdateLabelText = true;
}
if (value <= 0) return;
var colorIndex = chart.m_LegendRealShowName.IndexOf(serie.serieName);
var realHig = (value - serie.min) / (serie.max - serie.min) * vessel.context.height;
serie.animation.InitProgress(0, (float)realHig);
var hig = serie.animation.IsFinish() ? realHig : serie.animation.GetCurrDetail();
var color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, false);
var toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, false);
var isNeedGradient = !ChartHelper.IsValueEqualsColor(color, toColor);
var isFull = hig >= vessel.context.height;
if (hig >= vessel.context.height) hig = vessel.context.height;
if (isFull && !isNeedGradient)
{
UGL.DrawRectangle(vh, cenPos, vessel.context.width / 2, vessel.context.height / 2, toColor);
}
else
{
var startY = (float)(cenPos.y - vessel.context.height / 2 + hig);
var waveStartPos = new Vector3(cenPos.x - vessel.context.width / 2, startY);
var waveEndPos = new Vector3(cenPos.x + vessel.context.width / 2, startY);
var startX = waveStartPos.x;
var endX = waveEndPos.x;
var step = vessel.smoothness;
if (step < 0.5f) step = 0.5f;
var lup = waveStartPos;
var ldp = new Vector3(startX, vessel.context.center.y - vessel.context.height / 2);
var nup = Vector3.zero;
var ndp = Vector3.zero;
var angle = 0f;
var isStarted = false;
var isEnded = false;
var waveHeight = isFull ? 0 : serie.waveHeight;
m_WaveSpeed += serie.waveSpeed * Time.deltaTime;
while (startX < endX)
{
startX += step;
if (startX > endX) startX = endX;
if (startX > waveStartPos.x && !isStarted)
{
startX = waveStartPos.x;
isStarted = true;
}
if (startX > waveEndPos.x && !isEnded)
{
startX = waveEndPos.x;
isEnded = true;
}
var py = Mathf.Sqrt(Mathf.Pow(vessel.context.height, 2) - Mathf.Pow(Mathf.Abs(cenPos.x - startX), 2));
if (startX < waveStartPos.x || startX > waveEndPos.x)
{
nup = new Vector3(startX, cenPos.y + py);
}
else
{
var py2 = waveHeight * Mathf.Sin(1 / serie.waveLength * angle + m_WaveSpeed + serie.waveOffset);
var nupY = waveStartPos.y + py2;
nup = new Vector3(startX, nupY);
angle += step;
}
ndp = new Vector3(startX, cenPos.y - vessel.context.height / 2);
if (nup.y > cenPos.y + vessel.context.height / 2)
{
nup.y = cenPos.y + vessel.context.height / 2;
}
if (nup.y < cenPos.y - vessel.context.height / 2)
{
nup.y = cenPos.y - vessel.context.height / 2;
}
if (!ChartHelper.IsValueEqualsColor(color, toColor))
{
var colorMin = cenPos.y - vessel.context.height;
var colorMax = startY + serie.waveHeight;
var tcolor1 = Color32.Lerp(color, toColor, 1 - (lup.y - colorMin) / (colorMax - colorMin));
var tcolor2 = Color32.Lerp(color, toColor, 1 - (ldp.y - colorMin) / (colorMax - colorMin));
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, tcolor1, tcolor2);
}
else
{
UGL.DrawQuadrilateral(vh, lup, nup, ndp, ldp, color);
}
lup = nup;
ldp = ndp;
}
}
if (serie.waveSpeed != 0 && Application.isPlaying && !isFull)
{
chart.RefreshPainter(serie);
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(realHig);
chart.RefreshPainter(serie);
}
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c2ba7099a74f54617b446aeaf3d95672
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(ParallelHandler), true)]
[RequireChartComponent(typeof(ParallelCoord))]
public class Parallel : Serie, INeedSerieContainer
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Parallel>(serieName);
serie.lineStyle.width = 0.8f;
serie.lineStyle.opacity = 0.6f;
for (int i = 0; i < 100; i++)
{
var data = new List<double>(){
Random.Range(0f,50f),
Random.Range(0f,100f),
Random.Range(0f,1000f),
Random.Range(0,5),
};
serie.AddData(data, "data" + i);
}
chart.RefreshChart();
}
}
}

View File

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

View File

@@ -0,0 +1,153 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class ParallelHandler : SerieHandler<Parallel>
{
private List<Vector3> m_Points = new List<Vector3>();
public override void Update()
{
base.Update();
UpdateSerieContext();
}
public override void DrawSerie(VertexHelper vh)
{
var colorIndex = chart.GetLegendRealShowNameIndex(serie.legendName);
DrawParallelSerie(vh, colorIndex, serie);
}
private void UpdateSerieContext()
{
}
private void DrawParallelSerie(VertexHelper vh, int colorIndex, Parallel serie)
{
if (!serie.show) return;
if (serie.animation.HasFadeOut()) return;
var parallel = chart.GetChartComponent<ParallelCoord>(serie.parallelIndex);
if (parallel == null)
return;
var axisCount = parallel.context.parallelAxes.Count;
if (axisCount <= 0)
return;
var animationIndex = serie.animation.GetCurrIndex();
var isHorizonal = parallel.orient == Orient.Horizonal;
var lineColor = SerieHelper.GetLineColor(serie, chart.theme, colorIndex, false);
var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
float currDetailProgress = !isHorizonal
? parallel.context.x
: parallel.context.y;
float totalDetailProgress = !isHorizonal
? parallel.context.x + parallel.context.width
: parallel.context.y + parallel.context.height;
serie.animation.InitProgress(currDetailProgress, totalDetailProgress);
serie.context.dataPoints.Clear();
serie.containerIndex = parallel.index;
serie.containterInstanceId = parallel.instanceId;
var currProgress = serie.animation.GetCurrDetail();
var isSmooth = serie.lineType == LineType.Smooth;
foreach (var serieData in serie.data)
{
m_Points.Clear();
var count = Mathf.Min(axisCount, serieData.data.Count);
var lp = Vector3.zero;
for (int i = 0; i < count; i++)
{
if (animationIndex >= 0 && i > animationIndex) continue;
var pos = GetPos(parallel, i, serieData.data[i], isHorizonal);
if (!isHorizonal)
{
if (isSmooth)
{
m_Points.Add(pos);
}
else if (pos.x <= currProgress)
{
m_Points.Add(pos);
}
else
{
var currProgressStart = new Vector3(currProgress, parallel.context.y - 50);
var currProgressEnd = new Vector3(currProgress, parallel.context.y + parallel.context.height + 50);
var intersectionPos = Vector3.zero;
if (UGLHelper.GetIntersection(lp, pos, currProgressStart, currProgressEnd, ref intersectionPos))
m_Points.Add(intersectionPos);
else
m_Points.Add(pos);
break;
}
}
else
{
if (isSmooth)
{
m_Points.Add(pos);
}
else if (pos.y <= currProgress)
{
m_Points.Add(pos);
}
else
{
var currProgressStart = new Vector3(parallel.context.x - 50, currProgress);
var currProgressEnd = new Vector3(parallel.context.x + parallel.context.width + 50, currProgress);
var intersectionPos = Vector3.zero;
if (UGLHelper.GetIntersection(lp, pos, currProgressStart, currProgressEnd, ref intersectionPos))
m_Points.Add(intersectionPos);
else
m_Points.Add(pos);
break;
}
}
lp = pos;
}
if (isSmooth)
UGL.DrawCurves(vh, m_Points, lineWidth, lineColor, chart.settings.lineSmoothness, currProgress, isHorizonal);
else
UGL.DrawLine(vh, m_Points, lineWidth, lineColor, isSmooth);
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(totalDetailProgress - currDetailProgress);
chart.RefreshPainter(serie);
}
}
private static ParallelAxis GetAxis(ParallelCoord parallel, int index)
{
if (index >= 0 && index < parallel.context.parallelAxes.Count)
return parallel.context.parallelAxes[index];
else
return null;
}
private static Vector3 GetPos(ParallelCoord parallel, int axisIndex, double dataValue, bool isHorizonal)
{
var axis = GetAxis(parallel, axisIndex);
if (axis == null)
return Vector3.zero;
var sValueDist = axis.GetDistance(dataValue, axis.context.width);
return new Vector3(
isHorizonal ? axis.context.x + sValueDist : axis.context.x,
isHorizonal ? axis.context.y : axis.context.y + sValueDist);
}
}
}

View File

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

8
Runtime/Serie/Pie.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a5dfd0cb375a24f659bf56e113aa6fc8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

27
Runtime/Serie/Pie/Pie.cs Normal file
View File

@@ -0,0 +1,27 @@
namespace XCharts
{
[System.Serializable]
[SerieConvert(typeof(Line), typeof(Bar))]
[SerieHandler(typeof(PieHandler), true)]
[DefaultAnimation(AnimationType.Clockwise)]
[SerieExtraComponent(typeof(LabelStyle), typeof(LabelLine), typeof(IconStyle), typeof(Emphasis))]
public class Pie : Serie
{
public override bool useDataNameForColor { get { return true; } }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Pie>(serieName);
chart.AddData(serie.index, 70, "pie1");
chart.AddData(serie.index, 20, "pie2");
chart.AddData(serie.index, 10, "pie3");
}
public static Pie CovertSerie(Serie serie)
{
var newSerie = SerieHelper.CloneSerie<Pie>(serie);
return newSerie;
}
}
}

View File

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

View File

@@ -0,0 +1,597 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class PieHandler : SerieHandler<Pie>
{
public override void Update()
{
UpdateSerieContext();
}
public override void DrawSerie(VertexHelper vh)
{
UpdateRuntimeData(serie);
DrawPieLabelLine(vh, serie);
DrawPie(vh, serie);
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
UpdateItemSerieParams(ref paramList, ref title, dataIndex, category,
marker, itemFormatter, numericFormatter);
}
public override void RefreshLabelInternal()
{
var data = serie.data;
for (int n = 0; n < data.Count; n++)
{
var serieData = data[n];
if (!serieData.context.canShowLabel || serie.IsIgnoreValue(serieData))
{
serieData.SetLabelActive(false);
continue;
}
if (!serieData.show) continue;
var colorIndex = chart.GetLegendRealShowNameIndex(serieData.name);
Color color = chart.theme.GetColor(colorIndex);
DrawPieLabel(serie, n, serieData, color);
}
}
public override void OnLegendButtonClick(int index, string legendName, bool show)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataShow(serie, legendName, show);
chart.UpdateLegendColor(legendName, show);
chart.RefreshPainter(serie);
}
public override void OnLegendButtonEnter(int index, string legendName)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataHighlighted(serie, legendName, true);
chart.RefreshPainter(serie);
}
public override void OnLegendButtonExit(int index, string legendName)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataHighlighted(serie, legendName, false);
chart.RefreshPainter(serie);
}
public override void OnPointerDown(PointerEventData eventData)
{
if (!chart.HasSerie<Pie>()) return;
if (chart.pointerPos == Vector2.zero) return;
var refresh = false;
for (int i = 0; i < chart.series.Count; i++)
{
var serie = chart.GetSerie(i);
if (!(serie is Pie)) continue;
var index = GetPiePosIndex(serie, chart.pointerPos);
if (index >= 0)
{
refresh = true;
for (int j = 0; j < serie.data.Count; j++)
{
if (j == index) serie.data[j].selected = !serie.data[j].selected;
else serie.data[j].selected = false;
}
if (chart.onPointerClickPie != null)
{
chart.onPointerClickPie(eventData, i, index);
}
}
}
if (refresh) chart.RefreshChart();
}
private void UpdateSerieContext()
{
var needCheck = m_LegendEnter
|| (chart.isPointerInChart && PointerIsInPieSerie(serie, chart.pointerPos));
var needInteract = false;
if (!needCheck)
{
if (m_LastCheckContextFlag != needCheck)
{
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName);
var color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, false);
var toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, false);
serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor);
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
return;
}
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
var dataIndex = GetPiePosIndex(serie, chart.pointerPos);
for (int i = 0; i < serie.dataCount; i++)
{
var serieData = serie.data[i];
if (dataIndex == i || (m_LegendEnter && m_LegendEnterIndex == i))
{
serie.context.pointerItemDataIndex = i;
serieData.context.highlight = true;
var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName);
var color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, true);
var toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, true);
var value = serieData.context.outsideRadius + chart.theme.serie.pieTooltipExtraRadius;
serieData.interact.SetValueAndColor(ref needInteract, value, color, toColor);
}
else
{
serieData.context.highlight = false;
var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName);
var color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, false);
var toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, false);
serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor);
}
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
private void UpdateRuntimeData(Serie serie)
{
var data = serie.data;
serie.context.dataMax = serie.yMax;
var runtimePieDataTotal = serie.yTotal;
SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight);
float totalDegree = 0;
float startDegree = 0;
float zeroReplaceValue = 0;
int showdataCount = 0;
foreach (var sd in serie.data)
{
if (sd.show && serie.pieRoseType == RoseType.Area) showdataCount++;
sd.context.canShowLabel = false;
}
float dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
bool isAllZeroValue = SerieHelper.IsAllZeroValue(serie, 1);
var dataTotalFilterMinAngle = runtimePieDataTotal;
if (isAllZeroValue)
{
totalDegree = 360;
zeroReplaceValue = totalDegree / data.Count;
serie.context.dataMax = zeroReplaceValue;
runtimePieDataTotal = 360;
dataTotalFilterMinAngle = 360;
}
else
{
dataTotalFilterMinAngle = GetTotalAngle(serie, runtimePieDataTotal, ref totalDegree);
}
for (int n = 0; n < data.Count; n++)
{
var serieData = data[n];
serieData.index = n;
var value = isAllZeroValue ? zeroReplaceValue : serieData.GetCurrData(1, dataChangeDuration);
serieData.context.startAngle = startDegree;
serieData.context.toAngle = startDegree;
serieData.context.halfAngle = startDegree;
serieData.context.currentAngle = startDegree;
if (!serieData.show)
{
continue;
}
float degree = serie.pieRoseType == RoseType.Area
? (totalDegree / showdataCount)
: (float)(totalDegree * value / dataTotalFilterMinAngle);
if (serie.minAngle > 0 && degree < serie.minAngle) degree = serie.minAngle;
serieData.context.toAngle = startDegree + degree;
if (serieData.radius > 0)
serieData.context.outsideRadius = serieData.radius;
else
serieData.context.outsideRadius = serie.pieRoseType > 0 ?
serie.context.insideRadius + (float)((serie.context.outsideRadius - serie.context.insideRadius) * value / serie.context.dataMax) :
serie.context.outsideRadius;
if (serieData.context.highlight)
{
serieData.context.outsideRadius += chart.theme.serie.pieTooltipExtraRadius;
}
var offset = 0f;
if (serie.pieClickOffset && serieData.selected)
{
offset += chart.theme.serie.pieSelectedOffset;
}
if (serie.animation.CheckDetailBreak(serieData.context.toAngle))
{
serieData.context.currentAngle = serie.animation.GetCurrDetail();
}
else
{
serieData.context.currentAngle = serieData.context.toAngle;
}
var halfDegree = (serieData.context.toAngle - startDegree) / 2;
serieData.context.halfAngle = startDegree + halfDegree;
serieData.context.offsetCenter = serie.context.center;
serieData.context.insideRadius = serie.context.insideRadius;
if (offset > 0)
{
var currRad = serieData.context.halfAngle * Mathf.Deg2Rad;
var currSin = Mathf.Sin(currRad);
var currCos = Mathf.Cos(currRad);
serieData.context.offsetRadius = 0;
serieData.context.insideRadius -= serieData.context.offsetRadius;
serieData.context.outsideRadius -= serieData.context.offsetRadius;
if (serie.pieClickOffset && serieData.selected)
{
serieData.context.offsetRadius += chart.theme.serie.pieSelectedOffset;
if (serieData.context.insideRadius > 0)
{
serieData.context.insideRadius += chart.theme.serie.pieSelectedOffset;
}
serieData.context.outsideRadius += chart.theme.serie.pieSelectedOffset;
}
serieData.context.offsetCenter = new Vector3(
serie.context.center.x + serieData.context.offsetRadius * currSin,
serie.context.center.y + serieData.context.offsetRadius * currCos);
}
serieData.context.canShowLabel = serieData.context.currentAngle >= serieData.context.halfAngle;
startDegree = serieData.context.toAngle;
SerieLabelHelper.UpdatePieLabelPosition(serie, serieData);
}
SerieLabelHelper.AvoidLabelOverlap(serie, chart.theme.common);
}
private double GetTotalAngle(Serie serie, double dataTotal, ref float totalAngle)
{
totalAngle = 360f;
if (serie.minAngle > 0)
{
var rate = serie.minAngle / 360;
var minAngleValue = dataTotal * rate;
foreach (var serieData in serie.data)
{
var value = serieData.GetData(1);
if (value < minAngleValue)
{
totalAngle -= serie.minAngle;
dataTotal -= value;
}
}
return dataTotal;
}
else
{
return dataTotal;
}
}
private void DrawPieCenter(VertexHelper vh, Serie serie, ItemStyle itemStyle, float insideRadius)
{
if (!ChartHelper.IsClearColor(itemStyle.centerColor))
{
var radius = insideRadius - itemStyle.centerGap;
UGL.DrawCricle(vh, serie.context.center, radius, itemStyle.centerColor, chart.settings.cicleSmoothness);
}
}
private void DrawPie(VertexHelper vh, Serie serie)
{
if (!serie.show || serie.animation.HasFadeOut())
{
return;
}
var dataChanging = false;
var interacting = false;
var color = ColorUtil.clearColor32;
var toColor = ColorUtil.clearColor32;
var data = serie.data;
serie.animation.InitProgress(0, 360);
for (int n = 0; n < data.Count; n++)
{
var serieData = data[n];
if (!serieData.show)
{
continue;
}
if (serieData.IsDataChanged())
dataChanging = true;
var itemStyle = SerieHelper.GetItemStyle(serie, serieData, serieData.context.highlight);
var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName);
var outsideRadius = 0f;
var borderWidth = itemStyle.borderWidth;
var borderColor = itemStyle.borderColor;
var progress = AnimationStyleHelper.CheckDataAnimation(chart, serie, n, 1);
var insideRadius = serieData.context.insideRadius * progress;
//if (!serieData.interact.TryGetValueAndColor(ref outsideRadius, ref color, ref toColor, ref interacting))
{
color = SerieHelper.GetItemColor(serie, serieData, chart.theme, colorIndex, serieData.context.highlight);
toColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, colorIndex, serieData.context.highlight);
outsideRadius = serieData.context.outsideRadius * progress;
serieData.interact.SetValueAndColor(ref interacting, outsideRadius, color, toColor);
}
if (serie.pieClickOffset && serieData.selected)
{
var drawEndDegree = serieData.context.currentAngle;
var needRoundCap = serie.roundCap && insideRadius > 0;
UGL.DrawDoughnut(vh, serieData.context.offsetCenter, insideRadius,
outsideRadius, color, toColor, Color.clear, serieData.context.startAngle,
drawEndDegree, borderWidth, borderColor, serie.pieSpace / 2, chart.settings.cicleSmoothness,
needRoundCap, true);
}
else
{
var drawEndDegree = serieData.context.currentAngle;
var needRoundCap = serie.roundCap && insideRadius > 0;
UGL.DrawDoughnut(vh, serie.context.center, insideRadius,
outsideRadius, color, toColor, Color.clear, serieData.context.startAngle,
drawEndDegree, borderWidth, borderColor, serie.pieSpace / 2, chart.settings.cicleSmoothness,
needRoundCap, true);
DrawPieCenter(vh, serie, itemStyle, insideRadius);
}
if (serie.animation.CheckDetailBreak(serieData.context.toAngle))
break;
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress();
serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize));
chart.RefreshPainter(serie);
}
if (dataChanging)
{
chart.RefreshPainter(serie);
}
}
private bool IsAnyPieClickOffset()
{
foreach (var serie in chart.series)
{
if (serie is Pie && serie.pieClickOffset) return true;
}
return false;
}
private bool IsAnyPieDataHighlight()
{
foreach (var serie in chart.series)
{
if (serie is Pie)
{
foreach (var serieData in serie.data)
{
if (serieData.context.highlight) return true;
}
}
}
return false;
}
private void DrawPieLabelLine(VertexHelper vh, Serie serie)
{
foreach (var serieData in serie.data)
{
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
if (SerieLabelHelper.CanShowLabel(serie, serieData, serieLabel, 1))
{
int colorIndex = chart.m_LegendRealShowName.IndexOf(serieData.name);
Color color = chart.theme.GetColor(colorIndex);
DrawPieLabelLine(vh, serie, serieData, color);
}
}
}
private void DrawPieLabelLine(VertexHelper vh, Serie serie, SerieData serieData, Color color)
{
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData);
if (serieLabel != null && serieLabel.show
&& labelLine != null && labelLine.show
&& serieLabel.position == LabelStyle.Position.Outside)
{
var insideRadius = serieData.context.insideRadius;
var outSideRadius = serieData.context.outsideRadius;
var center = serie.context.center;
var currAngle = serieData.context.halfAngle;
if (!ChartHelper.IsClearColor(labelLine.lineColor)) color = labelLine.lineColor;
else if (labelLine.lineType == LabelLine.LineType.HorizontalLine) color *= color;
float currSin = Mathf.Sin(currAngle * Mathf.Deg2Rad);
float currCos = Mathf.Cos(currAngle * Mathf.Deg2Rad);
var radius1 = labelLine.lineType == LabelLine.LineType.HorizontalLine ?
serie.context.outsideRadius : outSideRadius;
var radius2 = serie.context.outsideRadius + labelLine.lineLength1;
var radius3 = insideRadius + (outSideRadius - insideRadius) / 2;
if (radius1 < serie.context.insideRadius) radius1 = serie.context.insideRadius;
radius1 -= 0.1f;
var pos0 = new Vector3(center.x + radius3 * currSin, center.y + radius3 * currCos);
var pos1 = new Vector3(center.x + radius1 * currSin, center.y + radius1 * currCos);
var pos2 = serieData.context.labelPosition;
if (pos2.x == 0)
{
pos2 = new Vector3(center.x + radius2 * currSin, center.y + radius2 * currCos);
}
Vector3 pos4, pos6;
var horizontalLineCircleRadius = labelLine.lineWidth * 4f;
var lineCircleDiff = horizontalLineCircleRadius - 0.3f;
if (currAngle < 90)
{
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3;
r4 += labelLine.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.right * lineCircleDiff;
pos4 = pos6 + Vector3.right * r4;
}
else if (currAngle < 180)
{
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3;
r4 += labelLine.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.right * lineCircleDiff;
pos4 = pos6 + Vector3.right * r4;
}
else if (currAngle < 270)
{
var currSin1 = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad);
var currCos1 = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad);
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos1 * radius3, 2)) - currSin1 * radius3;
r4 += labelLine.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.left * lineCircleDiff;
pos4 = pos6 + Vector3.left * r4;
}
else
{
var currSin1 = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad);
var currCos1 = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad);
var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos1 * radius3, 2)) - currSin1 * radius3;
r4 += labelLine.lineLength1 - lineCircleDiff;
pos6 = pos0 + Vector3.left * lineCircleDiff;
pos4 = pos6 + Vector3.left * r4;
}
var pos5X = currAngle > 180 ? pos2.x - labelLine.lineLength2 : pos2.x + labelLine.lineLength2;
var pos5 = new Vector3(pos5X, pos2.y);
switch (labelLine.lineType)
{
case LabelLine.LineType.BrokenLine:
UGL.DrawLine(vh, pos1, pos2, pos5, labelLine.lineWidth, color);
break;
case LabelLine.LineType.Curves:
UGL.DrawCurves(vh, pos1, pos5, pos1, pos2, labelLine.lineWidth, color,
chart.settings.lineSmoothness);
break;
case LabelLine.LineType.HorizontalLine:
UGL.DrawCricle(vh, pos0, horizontalLineCircleRadius, color);
UGL.DrawLine(vh, pos6, pos4, labelLine.lineWidth, color);
break;
}
}
}
private void DrawPieLabel(Serie serie, int dataIndex, SerieData serieData, Color serieColor)
{
if (serieData.labelObject == null) return;
var emphasis = serie.emphasis;
var currAngle = serieData.context.halfAngle;
var isHighlight = (serieData.context.highlight && emphasis != null && emphasis.label.show);
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData);
var iconStyle = SerieHelper.GetIconStyle(serie, serieData);
var showLabel = ((serieLabel.show || isHighlight) && serieData.context.canShowLabel);
if (showLabel)
{
serieData.SetLabelActive(showLabel);
float rotate = 0;
bool isInsidePosition = serieLabel.position == LabelStyle.Position.Inside;
if (serieLabel.textStyle.rotate > 0 && isInsidePosition)
{
if (currAngle > 180) rotate += 270 - currAngle;
else rotate += -(currAngle - 90);
}
Color color = serieColor;
if (isHighlight)
{
if (!ChartHelper.IsClearColor(emphasis.label.textStyle.color))
{
color = emphasis.label.textStyle.color;
}
}
else if (!ChartHelper.IsClearColor(serieLabel.textStyle.color))
{
color = serieLabel.textStyle.color;
}
else
{
color = isInsidePosition ? Color.white : serieColor;
}
var fontSize = isHighlight
? emphasis.label.textStyle.GetFontSize(chart.theme.common)
: serieLabel.textStyle.GetFontSize(chart.theme.common);
var fontStyle = isHighlight
? emphasis.label.textStyle.fontStyle
: serieLabel.textStyle.fontStyle;
serieData.labelObject.label.SetColor(color);
serieData.labelObject.label.SetFontSize(fontSize);
serieData.labelObject.label.SetFontStyle(fontStyle);
serieData.labelObject.SetLabelRotate(rotate);
if (!string.IsNullOrEmpty(serieLabel.formatter))
{
var value = serieData.data[1];
var total = serie.yTotal;
var content = SerieLabelHelper.GetFormatterContent(serie, serieData, value, total,
serieLabel, serieColor);
if (serieData.labelObject.SetText(content)) chart.RefreshPainter(serie);
}
else
{
if (serieData.labelObject.SetText(serieData.name)) chart.RefreshPainter(serie);
}
serieData.labelObject.SetPosition(SerieLabelHelper.GetRealLabelPosition(serieData, serieLabel, labelLine));
if (showLabel) serieData.labelObject.SetLabelPosition(serieLabel.offset);
else serieData.SetLabelActive(false);
}
else
{
serieData.SetLabelActive(false);
}
serieData.labelObject.UpdateIcon(iconStyle);
}
private int GetPiePosIndex(Serie serie, Vector2 local)
{
if (!(serie is Pie)) return -1;
var dist = Vector2.Distance(local, serie.context.center);
var maxRadius = serie.context.outsideRadius + 3 * chart.theme.serie.pieSelectedOffset;
if (dist < serie.context.insideRadius || dist > maxRadius) return -1;
Vector2 dir = local - new Vector2(serie.context.center.x, serie.context.center.y);
float angle = ChartHelper.GetAngle360(Vector2.up, dir);
for (int i = 0; i < serie.data.Count; i++)
{
var serieData = serie.data[i];
if (angle >= serieData.context.startAngle && angle <= serieData.context.toAngle)
{
var ndist = !serieData.selected ? dist :
Vector2.Distance(local, serieData.context.offsetCenter);
if (ndist >= serieData.context.insideRadius && ndist <= serieData.context.outsideRadius)
{
return i;
}
}
}
return -1;
}
private bool PointerIsInPieSerie(Serie serie, Vector2 local)
{
if (!(serie is Pie)) return false;
var dist = Vector2.Distance(local, serie.context.center);
if (dist >= serie.context.insideRadius && dist <= serie.context.outsideRadius) return true;
return false;
}
}
}

View File

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

8
Runtime/Serie/Radar.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 375cebcd4f8c54025ab608f35b1fa8c6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(RadarHandler), true)]
[RequireChartComponent(typeof(RadarCoord))]
[SerieExtraComponent(typeof(LabelStyle), typeof(LabelLine), typeof(AreaStyle), typeof(Emphasis))]
public class Radar : Serie, INeedSerieContainer
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
public override bool useDataNameForColor { get { return true; } }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
chart.AddChartComponentWhenNoExist<RadarCoord>();
var serie = chart.AddSerie<Radar>(serieName);
serie.symbol.show = true;
serie.symbol.type = SymbolType.Circle;
serie.showDataName = true;
List<double> data = new List<double>();
for (int i = 0; i < 5; i++)
{
data.Add(Random.Range(20, 90));
}
chart.AddData(serie.index, data, "legendName");
}
}
}

View File

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

View File

@@ -0,0 +1,520 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class RadarHandler : SerieHandler<Radar>
{
private RadarCoord m_RadarCoord;
public override void Update()
{
base.Update();
UpdateSerieContext();
}
public override void DrawSerie(VertexHelper vh)
{
if (!serie.show) return;
switch (serie.radarType)
{
case RadarType.Multiple:
DrawMutipleRadar(vh);
break;
case RadarType.Single:
DrawSingleRadar(vh);
break;
}
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
if (!serie.context.pointerEnter)
return;
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
if (serie.radarType == RadarType.Single)
{
UpdateItemSerieParams(ref paramList, ref title, dataIndex, category,
marker, itemFormatter, numericFormatter);
return;
}
var radar = chart.GetChartComponent<RadarCoord>(serie.radarIndex);
if (radar == null)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
var color = chart.theme.GetColor(dataIndex);
title = serieData.name;
for (int i = 0; i < serieData.data.Count; i++)
{
var indicator = radar.GetIndicator(i);
var param = new SerieParams();
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.dimension = i;
param.serieData = serieData;
param.value = serieData.GetData(i);
param.total = indicator.max;
param.color = color;
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(indicator == null ? string.Empty : indicator.name);
param.columns.Add(ChartCached.NumberToStr(serieData.GetData(i), param.numericFormatter));
paramList.Add(param);
}
}
public override void RefreshLabelInternal()
{
for (int i = 0; i < chart.series.Count; i++)
{
var serie = chart.GetSerie(i);
if (!(serie is Radar)) continue;
if (!serie.show && serie.radarType != RadarType.Single) continue;
var radar = chart.GetChartComponent<RadarCoord>(serie.radarIndex);
if (radar == null) continue;
var center = radar.context.center;
for (int n = 0; n < serie.dataCount; n++)
{
var serieData = serie.data[n];
if (serieData.labelObject == null) continue;
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
var iconStyle = SerieHelper.GetIconStyle(serie, serieData);
var labelPos = serieData.context.labelPosition;
if (serieLabel.margin != 0)
{
labelPos += serieLabel.margin * (labelPos - center).normalized;
}
serieData.labelObject.SetPosition(labelPos);
serieData.labelObject.UpdateIcon(iconStyle);
if (serie.show && serieLabel.show && serieData.context.canShowLabel)
{
var value = serieData.GetCurrData(1);
var max = radar.GetIndicatorMax(n);
SerieLabelHelper.ResetLabel(serieData.labelObject.label, serieLabel, chart.theme);
serieData.SetLabelActive(serieData.context.labelPosition != Vector3.zero);
serieData.labelObject.SetLabelPosition(serieLabel.offset);
var content = SerieLabelHelper.GetFormatterContent(serie, serieData, value, max,
serieLabel, Color.clear);
if (serieData.labelObject.SetText(content))
{
chart.RefreshPainter(serie);
}
}
else
{
serieData.SetLabelActive(false);
}
}
}
}
public override void OnLegendButtonClick(int index, string legendName, bool show)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataShow(serie, legendName, show);
chart.UpdateLegendColor(legendName, show);
chart.RefreshPainter(serie);
}
public override void OnLegendButtonEnter(int index, string legendName)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataHighlighted(serie, legendName, true);
chart.RefreshPainter(serie);
}
public override void OnLegendButtonExit(int index, string legendName)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataHighlighted(serie, legendName, false);
chart.RefreshPainter(serie);
}
private void UpdateSerieContext()
{
var needCheck = m_LegendEnter || (chart.isPointerInChart && m_RadarCoord.IsPointerEnter());
var needInteract = false;
var needHideAll = false;
if (!needCheck)
{
if (m_LastCheckContextFlag == needCheck)
return;
needHideAll = true;
}
m_LastCheckContextFlag = needCheck;
serie.context.pointerEnter = false;
serie.context.pointerItemDataIndex = -1;
switch (serie.radarType)
{
case RadarType.Multiple:
for (int i = 0; i < serie.data.Count; i++)
{
var serieData = serie.data[i];
serieData.index = i;
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize);
if (needHideAll || m_LegendEnter)
{
serieData.context.highlight = needHideAll ? false : true;
serieData.interact.SetValue(ref needInteract, symbolSize, serieData.context.highlight);
}
else
{
serieData.context.highlight = false;
foreach (var pos in serieData.context.dataPoints)
{
if (Vector3.Distance(chart.pointerPos, pos) < symbolSize * 2)
{
serie.context.pointerEnter = true;
serie.context.pointerItemDataIndex = i;
serieData.context.highlight = true;
break;
}
}
serieData.interact.SetValue(ref needInteract, symbolSize, serieData.context.highlight);
}
}
break;
case RadarType.Single:
for (int i = 0; i < serie.data.Count; i++)
{
var serieData = serie.data[i];
serieData.index = i;
if (Vector3.Distance(chart.pointerPos, serieData.context.position) < serie.symbol.size * 2)
{
serie.context.pointerEnter = true;
serie.context.pointerItemDataIndex = i;
return;
}
}
break;
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
private void DrawMutipleRadar(VertexHelper vh)
{
if (!serie.show) return;
m_RadarCoord = chart.GetChartComponent<RadarCoord>(serie.radarIndex);
if (m_RadarCoord == null) return;
serie.containerIndex = m_RadarCoord.index;
serie.containterInstanceId = m_RadarCoord.instanceId;
var areaStyle = serie.areaStyle;
var startPoint = Vector3.zero;
var toPoint = Vector3.zero;
var firstPoint = Vector3.zero;
var indicatorNum = m_RadarCoord.indicatorList.Count;
var angle = 2 * Mathf.PI / indicatorNum;
var centerPos = m_RadarCoord.context.center;
serie.animation.InitProgress(0, 1);
if (!serie.show || serie.animation.HasFadeOut())
{
return;
}
var rate = serie.animation.GetCurrRate();
var dataChanging = false;
var interacting = false;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
SerieHelper.GetAllMinMaxData(serie, m_RadarCoord.ceilRate);
for (int j = 0; j < serie.data.Count; j++)
{
var serieData = serie.data[j];
string dataName = serieData.name;
if (!serieData.show)
{
continue;
}
var isHighlight = serieData.context.highlight;
var areaColor = SerieHelper.GetAreaColor(serie, chart.theme, j, isHighlight);
var areaToColor = SerieHelper.GetAreaToColor(serie, chart.theme, j, isHighlight);
var lineColor = SerieHelper.GetLineColor(serie, chart.theme, j, isHighlight);
var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth);
int dataCount = m_RadarCoord.indicatorList.Count;
serieData.context.dataPoints.Clear();
for (int n = 0; n < dataCount; n++)
{
if (n >= serieData.data.Count) break;
var max = m_RadarCoord.GetIndicatorMax(n);
var value = serieData.GetCurrData(n, dataChangeDuration);
if (serieData.IsDataChanged()) dataChanging = true;
if (max == 0)
{
max = serie.context.dataMax;
}
var radius = (float)(max < 0 ? m_RadarCoord.context.dataRadius - m_RadarCoord.context.dataRadius * value / max
: m_RadarCoord.context.dataRadius * value / max);
var currAngle = (n + (m_RadarCoord.positionType == RadarCoord.PositionType.Between ? 0.5f : 0)) * angle;
radius *= rate;
if (n == 0)
{
startPoint = new Vector3(centerPos.x + radius * Mathf.Sin(currAngle),
centerPos.y + radius * Mathf.Cos(currAngle));
firstPoint = startPoint;
}
else
{
toPoint = new Vector3(centerPos.x + radius * Mathf.Sin(currAngle),
centerPos.y + radius * Mathf.Cos(currAngle));
if (areaStyle != null && areaStyle.show)
{
UGL.DrawTriangle(vh, startPoint, toPoint, centerPos, areaColor, areaColor, areaToColor);
}
if (serie.lineStyle.show)
{
ChartDrawer.DrawLineStyle(vh, serie.lineStyle.type, lineWidth, startPoint, toPoint, lineColor);
}
startPoint = toPoint;
}
serieData.context.dataPoints.Add(startPoint);
}
if (areaStyle != null && areaStyle.show)
{
UGL.DrawTriangle(vh, startPoint, firstPoint, centerPos, areaColor, areaColor, areaToColor);
}
if (serie.lineStyle.show)
{
ChartDrawer.DrawLineStyle(vh, serie.lineStyle.type, lineWidth, startPoint, firstPoint, lineColor);
}
if (serie.symbol.show && serie.symbol.type != SymbolType.None)
{
for (int m = 0; m < serieData.context.dataPoints.Count; m++)
{
var point = serieData.context.dataPoints[m];
var symbolSize = isHighlight
? serie.symbol.GetSelectedSize(null, chart.theme.serie.lineSymbolSelectedSize)
: serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize);
if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting))
{
symbolSize = isHighlight
? serie.symbol.GetSelectedSize(serieData.data, symbolSize)
: serie.symbol.GetSize(serieData.data, symbolSize);
serieData.interact.SetValue(ref interacting, symbolSize);
symbolSize = serie.animation.GetSysmbolSize(symbolSize);
}
var symbolColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, j, isHighlight);
var symbolToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, j, isHighlight);
var symbolEmptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, j, isHighlight, false);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, chart.theme, isHighlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, isHighlight);
chart.DrawSymbol(vh, serie.symbol.type, symbolSize, symbolBorder, point, symbolColor,
symbolToColor, symbolEmptyColor, serie.symbol.gap, cornerRadius);
}
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(1);
chart.RefreshPainter(serie);
}
if (dataChanging || interacting)
{
chart.RefreshPainter(serie);
}
}
private void DrawSingleRadar(VertexHelper vh)
{
var radar = chart.GetChartComponent<RadarCoord>(serie.radarIndex);
if (radar == null)
return;
var indicatorNum = radar.indicatorList.Count;
var angle = 2 * Mathf.PI / indicatorNum;
var centerPos = radar.context.center;
serie.animation.InitProgress(0, 1);
serie.context.dataPoints.Clear();
if (!serie.show || serie.animation.HasFadeOut())
{
return;
}
var startPoint = Vector3.zero;
var toPoint = Vector3.zero;
var firstPoint = Vector3.zero;
var lastColor = ColorUtil.clearColor32;
var firstColor = ColorUtil.clearColor32;
var rate = serie.animation.GetCurrRate();
var dataChanging = false;
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var startIndex = GetStartShowIndex(serie);
var endIndex = GetEndShowIndex(serie);
SerieHelper.UpdateMinMaxData(serie, 1, radar.ceilRate);
for (int j = 0; j < serie.data.Count; j++)
{
var serieData = serie.data[j];
serieData.index = j;
string dataName = serieData.name;
if (!serieData.show)
{
serieData.context.labelPosition = Vector3.zero;
continue;
}
var isHighlight = serie.context.pointerEnter;
var areaColor = SerieHelper.GetAreaColor(serie, chart.theme, j, isHighlight);
var areaToColor = SerieHelper.GetAreaToColor(serie, chart.theme, j, isHighlight);
var lineColor = SerieHelper.GetLineColor(serie, chart.theme, j, isHighlight);
int dataCount = radar.indicatorList.Count;
var index = serieData.index;
var p = radar.context.center;
var max = radar.GetIndicatorMax(index);
var value = serieData.GetCurrData(1, dataChangeDuration);
if (serieData.IsDataChanged()) dataChanging = true;
if (max == 0)
{
max = serie.context.dataMax;
}
if (!radar.IsInIndicatorRange(j, serieData.GetData(1)))
{
lineColor = radar.outRangeColor;
}
var radius = (float)(max < 0 ? radar.context.dataRadius - radar.context.dataRadius * value / max
: radar.context.dataRadius * value / max);
var currAngle = (index + (radar.positionType == RadarCoord.PositionType.Between ? 0.5f : 0)) * angle;
radius *= rate;
if (index == startIndex)
{
startPoint = new Vector3(p.x + radius * Mathf.Sin(currAngle),
p.y + radius * Mathf.Cos(currAngle));
firstPoint = startPoint;
lastColor = lineColor;
firstColor = lineColor;
}
else
{
toPoint = new Vector3(p.x + radius * Mathf.Sin(currAngle),
p.y + radius * Mathf.Cos(currAngle));
if (serie.areaStyle.show)
{
UGL.DrawTriangle(vh, startPoint, toPoint, p, areaColor, areaColor, areaToColor);
}
if (serie.lineStyle.show)
{
if (radar.connectCenter)
ChartDrawer.DrawLineStyle(vh, serie.lineStyle, startPoint, centerPos,
chart.theme.serie.lineWidth, LineStyle.Type.Solid, lastColor, lastColor);
ChartDrawer.DrawLineStyle(vh, serie.lineStyle, startPoint, toPoint, chart.theme.serie.lineWidth,
LineStyle.Type.Solid, radar.lineGradient ? lastColor : lineColor, lineColor);
}
startPoint = toPoint;
lastColor = lineColor;
}
serieData.context.position = startPoint;
serieData.context.labelPosition = startPoint;
if (serie.areaStyle.show && j == endIndex)
{
UGL.DrawTriangle(vh, startPoint, firstPoint, centerPos, areaColor, areaColor, areaToColor);
}
if (serie.lineStyle.show && j == endIndex)
{
if (radar.connectCenter)
ChartDrawer.DrawLineStyle(vh, serie.lineStyle, startPoint, centerPos,
chart.theme.serie.lineWidth, LineStyle.Type.Solid, lastColor, lastColor);
ChartDrawer.DrawLineStyle(vh, serie.lineStyle, startPoint, firstPoint, chart.theme.serie.lineWidth,
LineStyle.Type.Solid, lineColor, radar.lineGradient ? firstColor : lineColor);
}
}
if (serie.symbol.show && serie.symbol.type != SymbolType.None)
{
for (int j = 0; j < serie.data.Count; j++)
{
var serieData = serie.data[j];
if (!serieData.show) continue;
var isHighlight = serie.highlight || serieData.context.highlight || serie.context.pointerEnter;
var serieIndex = serieData.index;
var symbolSize = isHighlight
? serie.symbol.GetSelectedSize(serieData.data, chart.theme.serie.lineSymbolSelectedSize)
: serie.symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize);
var symbolColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serieIndex, isHighlight);
var symbolToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serieIndex, isHighlight);
var symbolEmptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, serieIndex, isHighlight, false);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, chart.theme, isHighlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, isHighlight);
if (!radar.IsInIndicatorRange(j, serieData.GetData(1)))
{
symbolColor = radar.outRangeColor;
symbolToColor = radar.outRangeColor;
}
chart.DrawSymbol(vh, serie.symbol.type, symbolSize, symbolBorder, serieData.context.labelPosition, symbolColor,
symbolToColor, symbolEmptyColor, serie.symbol.gap, cornerRadius);
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(1);
chart.RefreshPainter(serie);
}
if (dataChanging)
{
chart.RefreshPainter(serie);
}
}
private int GetStartShowIndex(Serie serie)
{
for (int i = 0; i < serie.dataCount; i++)
{
if (serie.data[i].show) return i;
}
return 0;
}
private int GetEndShowIndex(Serie serie)
{
for (int i = serie.dataCount - 1; i >= 0; i--)
{
if (serie.data[i].show) return i;
}
return 0;
}
private void DrawRadarSymbol(VertexHelper vh, Serie serie, SerieData serieData, int serieIndex, bool isHighlight,
List<Vector3> pointList)
{
if (serie.symbol.show && serie.symbol.type != SymbolType.None)
{
var symbolSize = isHighlight
? serie.symbol.GetSelectedSize(serieData.data, chart.theme.serie.lineSymbolSelectedSize)
: serie.symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize);
var symbolColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, serieIndex, isHighlight);
var symbolToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, serieIndex, isHighlight);
var symbolEmptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, serieIndex, isHighlight, false);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, chart.theme, isHighlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, isHighlight);
foreach (var point in pointList)
{
chart.DrawSymbol(vh, serie.symbol.type, symbolSize, symbolBorder, point, symbolColor,
symbolToColor, symbolEmptyColor, serie.symbol.gap, cornerRadius);
}
}
}
}
}

View File

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

8
Runtime/Serie/Ring.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c15a1b60f1d3c4daca1fcd88d96ae7e7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(RingHandler), true)]
[SerieExtraComponent(typeof(LabelStyle), typeof(Emphasis))]
public class Ring : Serie
{
public override bool useDataNameForColor { get { return true; } }
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Ring>(serieName);
serie.roundCap = true;
serie.radius = new float[] { 0.3f, 0.35f };
serie.titleStyle.show = false;
serie.titleStyle.textStyle.offset = new Vector2(0, 30);
serie.AddExtraComponent<LabelStyle>();
serie.label.show = true;
serie.label.position = LabelStyle.Position.Center;
serie.label.formatter = "{d:f0}%";
serie.label.textStyle.fontSize = 28;
var value = Random.Range(30, 90);
var max = 100;
chart.AddData(serie.index, value, max, "data1");
}
}
}

View File

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

View File

@@ -0,0 +1,322 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using XUGL;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class RingHandler : SerieHandler<Ring>
{
private bool m_UpdateTitleText = false;
private bool m_UpdateLabelText = false;
public override void Update()
{
if (m_UpdateTitleText)
{
m_UpdateTitleText = false;
foreach (var serie in chart.series)
{
if (serie is Ring)
{
serie.titleStyle.SetText(serie.serieName);
}
}
}
if (m_UpdateLabelText)
{
m_UpdateLabelText = false;
foreach (var serie in chart.series)
{
if (serie is Ring)
{
SerieLabelHelper.SetRingLabelText(serie, chart.theme);
}
}
}
var ringIndex = GetRingIndex(chart.pointerPos);
if (ringIndex >= 0)
{
serie.context.pointerEnter = true;
serie.context.pointerItemDataIndex = ringIndex;
}
else
{
serie.context.pointerEnter = false;
serie.context.pointerItemDataIndex = -1;
}
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
if (dataIndex < 0)
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
var param = serie.context.param;
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.category = category;
param.dimension = 0;
param.serieData = serieData;
param.value = serieData.GetData(0);
param.total = serieData.GetData(1);
param.color = chart.theme.GetColor(dataIndex);
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter); ;
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(serieData.name);
param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter));
paramList.Add(param);
}
public override void DrawSerie(VertexHelper vh)
{
if (!serie.show || serie.animation.HasFadeOut()) return;
var data = serie.data;
serie.animation.InitProgress(serie.startAngle, serie.startAngle + 360);
SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight);
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var ringWidth = serie.context.outsideRadius - serie.context.insideRadius;
var dataChanging = false;
for (int j = 0; j < data.Count; j++)
{
var serieData = data[j];
if (!serieData.show) continue;
if (serieData.IsDataChanged()) dataChanging = true;
var value = serieData.GetFirstData(dataChangeDuration);
var max = serieData.GetLastData();
var degree = (float)(360 * value / max);
var startDegree = GetStartAngle(serie);
var toDegree = GetToAngle(serie, degree);
var itemStyle = SerieHelper.GetItemStyle(serie, serieData, serieData.context.highlight);
var itemColor = SerieHelper.GetItemColor(serie, serieData, chart.theme, j, serieData.context.highlight);
var itemToColor = SerieHelper.GetItemToColor(serie, serieData, chart.theme, j, serieData.context.highlight);
var outsideRadius = serie.context.outsideRadius - j * (ringWidth + serie.ringGap);
var insideRadius = outsideRadius - ringWidth;
var centerRadius = (outsideRadius + insideRadius) / 2;
var borderWidth = itemStyle.borderWidth;
var borderColor = itemStyle.borderColor;
var roundCap = serie.roundCap && insideRadius > 0;
serieData.context.startAngle = serie.clockwise ? startDegree : toDegree;
serieData.context.toAngle = serie.clockwise ? toDegree : startDegree;
serieData.context.insideRadius = insideRadius;
serieData.context.outsideRadius = serieData.radius > 0 ? serieData.radius : outsideRadius;
if (itemStyle.backgroundColor.a != 0)
{
UGL.DrawDoughnut(vh, serie.context.center, insideRadius, outsideRadius, itemStyle.backgroundColor,
itemStyle.backgroundColor, Color.clear, 0, 360, borderWidth, borderColor, 0,
chart.settings.cicleSmoothness, false, serie.clockwise);
}
UGL.DrawDoughnut(vh, serie.context.center, insideRadius, outsideRadius, itemColor, itemToColor,
Color.clear, startDegree, toDegree, borderWidth, borderColor, 0, chart.settings.cicleSmoothness,
roundCap, serie.clockwise);
DrawCenter(vh, serie, serieData, insideRadius, j == data.Count - 1);
UpateLabelPosition(serie, serieData, j, startDegree, toDegree, centerRadius);
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(360);
chart.RefreshChart();
}
if (dataChanging)
{
chart.RefreshChart();
}
}
public override void OnLegendButtonClick(int index, string legendName, bool show)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataShow(serie, legendName, show);
chart.UpdateLegendColor(legendName, show);
chart.RefreshPainter(serie);
}
public override void OnLegendButtonEnter(int index, string legendName)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataHighlighted(serie, legendName, true);
chart.RefreshPainter(serie);
}
public override void OnLegendButtonExit(int index, string legendName)
{
if (!serie.IsLegendName(legendName))
return;
LegendHelper.CheckDataHighlighted(serie, legendName, false);
chart.RefreshPainter(serie);
}
public override void OnPointerDown(PointerEventData eventData)
{
}
private float GetStartAngle(Serie serie)
{
return serie.clockwise ? serie.startAngle : 360 - serie.startAngle;
}
private float GetToAngle(Serie serie, float angle)
{
var toAngle = angle + serie.startAngle;
if (!serie.clockwise)
{
toAngle = 360 - angle - serie.startAngle;
}
if (!serie.animation.IsFinish())
{
var currAngle = serie.animation.GetCurrDetail();
if (serie.clockwise)
{
toAngle = toAngle > currAngle ? currAngle : toAngle;
}
else
{
toAngle = toAngle < 360 - currAngle ? 360 - currAngle : toAngle;
}
}
return toAngle;
}
private void DrawCenter(VertexHelper vh, Serie serie, SerieData serieData, float insideRadius, bool last)
{
var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
if (!ChartHelper.IsClearColor(itemStyle.centerColor) && last)
{
var radius = insideRadius - itemStyle.centerGap;
var smoothness = chart.settings.cicleSmoothness;
UGL.DrawCricle(vh, serie.context.center, radius, itemStyle.centerColor, smoothness);
}
}
private void UpateLabelPosition(Serie serie, SerieData serieData, int index, float startAngle,
float toAngle, float centerRadius)
{
var label = serie.label;
if (label == null || !label.show) return;
if (serieData.labelObject == null) return;
switch (label.position)
{
case LabelStyle.Position.Center:
serieData.context.labelPosition = serie.context.center + label.offset;
break;
case LabelStyle.Position.Bottom:
var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius;
var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius;
var xDiff = serie.clockwise ? -label.margin : label.margin;
serieData.context.labelPosition = serie.context.center + new Vector3(px1 + xDiff, py1);
break;
case LabelStyle.Position.Top:
startAngle += serie.clockwise ? -label.margin : label.margin;
toAngle += serie.clockwise ? label.margin : -label.margin;
var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius;
var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius;
serieData.context.labelPosition = serie.context.center + new Vector3(px2, py2);
break;
}
serieData.labelObject.SetLabelPosition(serieData.context.labelPosition);
}
private void DrawBackground(VertexHelper vh, Serie serie, SerieData serieData, int index, float insideRadius, float outsideRadius)
{
var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
var backgroundColor = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, index, false);
if (itemStyle.backgroundWidth != 0)
{
var centerRadius = (outsideRadius + insideRadius) / 2;
var inradius = centerRadius - itemStyle.backgroundWidth / 2;
var outradius = centerRadius + itemStyle.backgroundWidth / 2;
UGL.DrawDoughnut(vh, serie.context.center, inradius,
outradius, backgroundColor, Color.clear, chart.settings.cicleSmoothness);
}
else
{
UGL.DrawDoughnut(vh, serie.context.center, insideRadius,
outsideRadius, backgroundColor, Color.clear, chart.settings.cicleSmoothness);
}
}
private void DrawBorder(VertexHelper vh, Serie serie, SerieData serieData, float insideRadius, float outsideRadius)
{
var itemStyle = SerieHelper.GetItemStyle(serie, serieData);
if (itemStyle.show && itemStyle.borderWidth > 0 && !ChartHelper.IsClearColor(itemStyle.borderColor))
{
UGL.DrawDoughnut(vh, serie.context.center, outsideRadius,
outsideRadius + itemStyle.borderWidth, itemStyle.borderColor,
Color.clear, chart.settings.cicleSmoothness);
UGL.DrawDoughnut(vh, serie.context.center, insideRadius,
insideRadius + itemStyle.borderWidth, itemStyle.borderColor,
Color.clear, chart.settings.cicleSmoothness);
}
}
private void DrawRoundCap(VertexHelper vh, Serie serie, Vector3 centerPos, Color color,
float insideRadius, float outsideRadius, ref float drawStartDegree, ref float drawEndDegree)
{
if (serie.roundCap && insideRadius > 0 && drawStartDegree != drawEndDegree)
{
var width = (outsideRadius - insideRadius) / 2;
var radius = insideRadius + width;
var diffDegree = Mathf.Asin(width / radius) * Mathf.Rad2Deg;
drawStartDegree += serie.clockwise ? diffDegree : -diffDegree;
drawEndDegree -= serie.clockwise ? diffDegree : -diffDegree;
UGL.DrawRoundCap(vh, centerPos, width, radius, drawStartDegree, serie.clockwise, color, false);
UGL.DrawRoundCap(vh, centerPos, width, radius, drawEndDegree, serie.clockwise, color, true);
}
}
private int GetRingIndex(Vector2 local)
{
var dist = Vector2.Distance(local, serie.context.center);
if (dist > serie.context.outsideRadius) return -1;
Vector2 dir = local - new Vector2(serie.context.center.x, serie.context.center.y);
float angle = VectorAngle(Vector2.up, dir);
for (int i = 0; i < serie.data.Count; i++)
{
var serieData = serie.data[i];
if (dist >= serieData.context.insideRadius &&
dist <= serieData.context.outsideRadius &&
angle >= serieData.context.startAngle &&
angle <= serieData.context.toAngle)
{
return i;
}
}
return -1;
}
private float VectorAngle(Vector2 from, Vector2 to)
{
float angle;
Vector3 cross = Vector3.Cross(from, to);
angle = Vector2.Angle(from, to);
angle = cross.z > 0 ? -angle : angle;
angle = (angle + 360) % 360;
return angle;
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 97fc5bddab1db4321aa7377ab8b8b8bc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
namespace XCharts
{
[System.Serializable]
public class BaseScatter : Serie, INeedSerieContainer
{
public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; }
}
}

View File

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

View File

@@ -0,0 +1,347 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal class BaseScatterHandler<T> : SerieHandler<T> where T : BaseScatter
{
private GridCoord m_Grid;
public override void Update()
{
UpdateSerieContext();
}
public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category,
string marker, string itemFormatter, string numericFormatter,
ref List<SerieParams> paramList, ref string title)
{
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
title = serie.serieName;
var param = serie.context.param;
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.category = category;
param.dimension = 1;
param.serieData = serieData;
param.color = chart.theme.GetColor(serie.index);
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
param.columns.Clear();
param.columns.Add(param.marker);
if (!string.IsNullOrEmpty(serieData.name))
param.columns.Add(serieData.name);
param.columns.Add(ChartCached.NumberToStr(serieData.GetData(1), param.numericFormatter));
paramList.Add(param);
}
public override void DrawSerie(VertexHelper vh)
{
var colorIndex = chart.GetLegendRealShowNameIndex(serie.legendName);
if (serie.IsUseCoord<SingleAxisCoord>())
{
DrawSingAxisScatterSerie(vh, colorIndex, serie);
}
else if (serie.IsUseCoord<GridCoord>())
{
DrawScatterSerie(vh, colorIndex, serie);
}
}
private void UpdateSerieContext()
{
var needCheck = m_LegendEnter || (chart.isPointerInChart && (m_Grid == null || m_Grid.IsPointerEnter()));
var needHideAll = false;
if (!needCheck)
{
if (m_LastCheckContextFlag == needCheck)
return;
needHideAll = true;
}
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
var themeSymbolSize = chart.theme.serie.scatterSymbolSize;
var themeSymbolSelectedSize = chart.theme.serie.scatterSymbolSelectedSize;
var needInteract = false;
for (int i = serie.dataCount - 1; i >= 0; i--)
{
var serieData = serie.data[i];
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
var symbolSize = symbol.GetSize(serieData.data, themeSymbolSize);
var symbolSelectedSize = symbol.GetSelectedSize(serieData.data, themeSymbolSelectedSize);
if (m_LegendEnter ||
(!needHideAll && Vector3.Distance(serieData.context.position, chart.pointerPos) <= symbolSize))
{
serie.context.pointerItemDataIndex = i;
serie.context.pointerEnter = true;
serieData.context.highlight = true;
serieData.interact.SetValue(ref needInteract, symbolSelectedSize);
}
else
{
serieData.context.highlight = false;
serieData.interact.SetValue(ref needInteract, symbolSize);
}
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
protected virtual void DrawScatterSerie(VertexHelper vh, int colorIndex, BaseScatter serie)
{
if (serie.animation.HasFadeOut())
return;
if (!serie.show)
return;
XAxis xAxis;
if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex))
return;
YAxis yAxis;
if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex))
return;
if (!chart.TryGetChartComponent<GridCoord>(out m_Grid, xAxis.gridIndex))
return;
DataZoom xDataZoom;
DataZoom yDataZoom;
chart.GetDataZoomOfSerie(serie, out xDataZoom, out yDataZoom);
var theme = chart.theme;
int maxCount = serie.maxShow > 0 ?
(serie.maxShow > serie.dataCount ? serie.dataCount : serie.maxShow)
: serie.dataCount;
serie.animation.InitProgress(0, 1);
var rate = serie.animation.GetCurrRate();
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var dataChanging = false;
var interacting = false;
var dataList = serie.GetDataList(xDataZoom);
var isEffectScatter = serie is EffectScatter;
serie.containerIndex = m_Grid.index;
serie.containterInstanceId = m_Grid.instanceId;
foreach (var serieData in dataList)
{
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
if (!symbol.ShowSymbol(serieData.index, maxCount))
continue;
var highlight = serie.highlight || serieData.context.highlight;
var color = SerieHelper.GetItemColor(serie, serieData, theme, colorIndex, highlight);
var toColor = SerieHelper.GetItemToColor(serie, serieData, theme, colorIndex, highlight);
var emptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, theme, colorIndex, highlight, false);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, theme, highlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, highlight);
double xValue = serieData.GetCurrData(0, dataChangeDuration, xAxis.inverse);
double yValue = serieData.GetCurrData(1, dataChangeDuration, yAxis.inverse);
if (serieData.IsDataChanged())
dataChanging = true;
float pX = m_Grid.context.x + xAxis.axisLine.GetWidth(theme.axis.lineWidth);
float pY = m_Grid.context.y + yAxis.axisLine.GetWidth(theme.axis.lineWidth);
float xDataHig = GetDataHig(xAxis, xValue, m_Grid.context.width);
float yDataHig = GetDataHig(yAxis, yValue, m_Grid.context.height);
var pos = new Vector3(pX + xDataHig, pY + yDataHig);
if (!m_Grid.Contains(pos))
continue;
serie.context.dataPoints.Add(pos);
serieData.context.position = pos;
var datas = serieData.data;
var symbolSize = serie.highlight || serieData.context.highlight
? theme.serie.scatterSymbolSelectedSize
: theme.serie.scatterSymbolSize;
if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting))
{
symbolSize = highlight
? symbol.GetSelectedSize(serieData.data, symbolSize)
: symbol.GetSize(serieData.data, symbolSize);
serieData.interact.SetValue(ref interacting, symbolSize);
}
symbolSize *= rate;
if (isEffectScatter)
{
for (int count = 0; count < symbol.animationSize.Count; count++)
{
var nowSize = symbol.animationSize[count];
color.a = (byte)(255 * (symbolSize - nowSize) / symbolSize);
chart.DrawSymbol(vh, symbol.type, nowSize, symbolBorder, pos, color, toColor, emptyColor, symbol.gap, cornerRadius);
}
chart.RefreshPainter(serie);
}
else
{
if (symbolSize > 100) symbolSize = 100;
chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, pos, color, toColor, emptyColor, symbol.gap, cornerRadius);
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(1);
chart.RefreshPainter(serie);
}
if (dataChanging || interacting)
{
chart.RefreshPainter(serie);
}
}
protected virtual void DrawSingAxisScatterSerie(VertexHelper vh, int colorIndex, BaseScatter serie)
{
if (serie.animation.HasFadeOut())
return;
if (!serie.show)
return;
var axis = chart.GetChartComponent<SingleAxis>(serie.singleAxisIndex);
if (axis == null)
return;
DataZoom xDataZoom;
DataZoom yDataZoom;
chart.GetDataZoomOfSerie(serie, out xDataZoom, out yDataZoom);
var theme = chart.theme;
int maxCount = serie.maxShow > 0 ?
(serie.maxShow > serie.dataCount ? serie.dataCount : serie.maxShow)
: serie.dataCount;
serie.animation.InitProgress(0, 1);
var rate = serie.animation.GetCurrRate();
var dataChangeDuration = serie.animation.GetUpdateAnimationDuration();
var dataChanging = false;
var dataList = serie.GetDataList(xDataZoom);
var isEffectScatter = serie is EffectScatter;
serie.containerIndex = axis.index;
serie.containterInstanceId = axis.instanceId;
foreach (var serieData in dataList)
{
var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
if (!symbol.ShowSymbol(serieData.index, maxCount))
continue;
var highlight = serie.highlight || serieData.context.highlight;
var color = SerieHelper.GetItemColor(serie, serieData, theme, colorIndex, highlight);
var toColor = SerieHelper.GetItemToColor(serie, serieData, theme, colorIndex, highlight);
var emptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, theme, colorIndex, highlight, false);
var symbolBorder = SerieHelper.GetSymbolBorder(serie, serieData, theme, highlight);
var cornerRadius = SerieHelper.GetSymbolCornerRadius(serie, serieData, highlight);
var xValue = serieData.GetCurrData(0, dataChangeDuration, axis.inverse);
if (serieData.IsDataChanged())
dataChanging = true;
var pos = Vector3.zero;
if (axis.orient == Orient.Horizonal)
{
var xDataHig = GetDataHig(axis, xValue, axis.context.width);
var yDataHig = axis.context.height / 2;
pos = new Vector3(axis.context.x + xDataHig, axis.context.y + yDataHig);
}
else
{
var yDataHig = GetDataHig(axis, xValue, axis.context.width);
var xDataHig = axis.context.height / 2;
pos = new Vector3(axis.context.x + xDataHig, axis.context.y + yDataHig);
}
serie.context.dataPoints.Add(pos);
serieData.context.position = pos;
var datas = serieData.data;
var symbolSize = 0f;
if (serie.highlight || serieData.context.highlight)
symbolSize = symbol.GetSelectedSize(datas, theme.serie.scatterSymbolSelectedSize);
else
symbolSize = symbol.GetSize(datas, theme.serie.scatterSymbolSize);
symbolSize *= rate;
if (isEffectScatter)
{
if (symbolSize > 100) symbolSize = 100;
for (int count = 0; count < symbol.animationSize.Count; count++)
{
var nowSize = symbol.animationSize[count];
color.a = (byte)(255 * (symbolSize - nowSize) / symbolSize);
chart.DrawSymbol(vh, symbol.type, nowSize, symbolBorder, pos,
color, toColor, emptyColor, symbol.gap, cornerRadius);
}
chart.RefreshPainter(serie);
}
else
{
if (symbolSize > 100) symbolSize = 100;
chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, pos,
color, toColor, emptyColor, symbol.gap, cornerRadius);
}
}
if (!serie.animation.IsFinish())
{
serie.animation.CheckProgress(1);
chart.RefreshPainter(serie);
}
if (dataChanging)
{
chart.RefreshPainter(serie);
}
}
private static float GetDataHig(Axis axis, double value, float totalWidth)
{
if (axis.IsLog())
{
int minIndex = axis.GetLogMinIndex();
float nowIndex = axis.GetLogValue(value);
return (nowIndex - minIndex) / axis.splitNumber * totalWidth;
}
else if (axis.IsCategory())
{
if (axis.boundaryGap)
{
float tick = (float)(totalWidth / (axis.context.minMaxRange + 1));
return tick / 2 + (float)(value - axis.context.minValue) * tick;
}
else
{
return (float)((value - axis.context.minValue) / axis.context.minMaxRange * totalWidth);
}
}
else
{
return (float)((value - axis.context.minValue) / axis.context.minMaxRange * totalWidth);
}
}
}
}

View File

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

View File

@@ -0,0 +1,25 @@
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(EffectScatterHandler), true)]
[CoordOptions(typeof(GridCoord), typeof(SingleAxisCoord))]
[SerieExtraComponent(typeof(LabelStyle), typeof(Emphasis))]
public class EffectScatter : BaseScatter
{
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<EffectScatter>(serieName);
serie.symbol.show = true;
serie.symbol.type = SymbolType.Circle;
serie.itemStyle.opacity = 0.8f;
serie.clip = false;
for (int i = 0; i < 10; i++)
{
chart.AddData(serie.index, Random.Range(10, 100), Random.Range(10, 100));
}
}
}
}

View File

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

View File

@@ -0,0 +1,26 @@
using UnityEngine;
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class EffectScatterHandler : BaseScatterHandler<EffectScatter>
{
private float m_EffectScatterSpeed = 15;
public override void Update()
{
base.Update();
var symbolSize = serie.symbol.GetSize(null, chart.theme.serie.scatterSymbolSize);
for (int i = 0; i < serie.symbol.animationSize.Count; ++i)
{
serie.symbol.animationSize[i] += m_EffectScatterSpeed * Time.deltaTime;
if (serie.symbol.animationSize[i] > symbolSize)
{
serie.symbol.animationSize[i] = i * 5;
}
chart.RefreshPainter(serie);
}
}
}
}

View File

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

View File

@@ -0,0 +1,27 @@
using UnityEngine;
namespace XCharts
{
[System.Serializable]
[SerieHandler(typeof(ScatterHandler), true)]
[CoordOptions(typeof(GridCoord), typeof(SingleAxisCoord))]
[SerieExtraComponent(typeof(LabelStyle), typeof(Emphasis))]
public class Scatter : BaseScatter
{
public static void AddDefaultSerie(BaseChart chart, string serieName)
{
var serie = chart.AddSerie<Scatter>(serieName);
serie.symbol.show = true;
serie.symbol.type = SymbolType.Circle;
serie.itemStyle.opacity = 0.8f;
serie.clip = false;
for (int i = 0; i < 10; i++)
{
chart.AddData(serie.index, Random.Range(10, 100), Random.Range(10, 100));
}
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
namespace XCharts
{
[UnityEngine.Scripting.Preserve]
internal sealed class ScatterHandler : BaseScatterHandler<Scatter>
{
}
}

View File

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

View File

@@ -0,0 +1,139 @@
using UnityEngine;
using System.Collections.Generic;
using System;
using System.Reflection;
namespace XCharts
{
public partial class Serie
{
public static Dictionary<Type, string> extraComponentFieldNameDict = new Dictionary<Type, string>
{
{typeof(LabelStyle), "m_Labels"},
{typeof(LabelLine), "m_LabelLines"},
{typeof(EndLabelStyle), "m_EndLabels"},
{typeof(LineArrow), "m_LineArrows"},
{typeof(AreaStyle), "m_AreaStyles"},
{typeof(IconStyle), "m_IconStyles"},
{typeof(Emphasis), "m_Emphases"},
};
[SerializeField] private List<LabelStyle> m_Labels = new List<LabelStyle>();
[SerializeField] private List<LabelLine> m_LabelLines = new List<LabelLine>();
[SerializeField] private List<EndLabelStyle> m_EndLabels = new List<EndLabelStyle>();
[SerializeField] private List<LineArrow> m_LineArrows = new List<LineArrow>();
[SerializeField] private List<AreaStyle> m_AreaStyles = new List<AreaStyle>();
[SerializeField] private List<IconStyle> m_IconStyles = new List<IconStyle>();
[SerializeField] private List<Emphasis> m_Emphases = new List<Emphasis>();
/// <summary>
/// The style of area.
/// 区域填充样式。
/// </summary>
public AreaStyle areaStyle { get { return m_AreaStyles.Count > 0 ? m_AreaStyles[0] : null; } }
/// <summary>
/// Text label of graphic element,to explain some data information about graphic item like value, name and so on.
/// 图形上的文本标签可用于说明图形的一些数据信息比如值名称等。s
/// </summary>
public LabelStyle label { get { return m_Labels.Count > 0 ? m_Labels[0] : null; } }
public LabelStyle endLabel { get { return m_EndLabels.Count > 0 ? m_EndLabels[0] : null; } }
/// <summary>
/// The line of label.
/// 标签上的视觉引导线。
/// </summary>
public LabelLine labelLine { get { return m_LabelLines.Count > 0 ? m_LabelLines[0] : null; } }
/// <summary>
/// The arrow of line.
/// 折线图的箭头。
/// </summary>
public LineArrow lineArrow { get { return m_LineArrows.Count > 0 ? m_LineArrows[0] : null; } }
/// <summary>
/// 高亮的图形样式和文本标签样式。
/// </summary>
public Emphasis emphasis { get { return m_Emphases.Count > 0 ? m_Emphases[0] : null; } }
/// <summary>
/// the icon of data.
/// 数据项图标样式。
/// </summary>
public IconStyle iconStyle { get { return m_IconStyles.Count > 0 ? m_IconStyles[0] : null; } }
public void RemoveAllExtraComponent()
{
var serieType = GetType();
foreach (var kv in extraComponentFieldNameDict)
{
ReflectionUtil.InvokeListClear(this, serieType.GetField(kv.Value));
}
SetAllDirty();
}
public T AddExtraComponent<T>() where T : ChildComponent
{
return AddExtraComponent(typeof(T)) as T;
}
public ISerieExtraComponent AddExtraComponent(Type type)
{
if (GetType().IsDefined(typeof(SerieExtraComponentAttribute), false))
{
var attr = GetType().GetAttribute<SerieExtraComponentAttribute>();
if (attr.Contains(type))
{
var fieldName = string.Empty;
if (extraComponentFieldNameDict.TryGetValue(type, out fieldName))
{
var field = typeof(Serie).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
if (ReflectionUtil.InvokeListCount(this, field) <= 0)
{
var extraComponent = Activator.CreateInstance(type) as ISerieExtraComponent;
ReflectionUtil.InvokeListAdd(this, field, extraComponent);
SetAllDirty();
return extraComponent;
}
else
{
return ReflectionUtil.InvokeListGet<ISerieExtraComponent>(this, field, 0);
}
}
}
}
throw new System.Exception(string.Format("Serie {0} not support extra component: {1}",
GetType().Name, type.Name));
}
public void RemoveExtraComponent<T>() where T : ISerieExtraComponent
{
RemoveExtraComponent(typeof(T));
}
public void RemoveExtraComponent(Type type)
{
if (GetType().IsDefined(typeof(SerieExtraComponentAttribute), false))
{
var attr = GetType().GetAttribute<SerieExtraComponentAttribute>();
if (attr.Contains(type))
{
var fieldName = string.Empty;
if (extraComponentFieldNameDict.TryGetValue(type, out fieldName))
{
var field = typeof(Serie).GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
ReflectionUtil.InvokeListClear(this, field);
SetAllDirty();
return;
}
}
}
throw new System.Exception(string.Format("Serie {0} not support extra component: {1}",
GetType().Name, type.Name));
}
private void RemoveExtraComponentList<T>(List<T> list) where T : ISerieExtraComponent
{
if (list.Count > 0)
{
list.Clear();
SetAllDirty();
}
}
}
}

View File

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

1752
Runtime/Serie/Serie.cs Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,102 @@
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
public struct PointInfo
{
public Vector3 position;
public bool isIgnoreBreak;
public PointInfo(Vector3 pos, bool ignore)
{
this.position = pos;
this.isIgnoreBreak = ignore;
}
}
[System.Serializable]
public class SerieContext
{
/// <summary>
/// 鼠标是否进入serie
/// </summary>
public bool pointerEnter;
/// <summary>
/// 鼠标当前指示的数据项索引(单个)
/// </summary>
public int pointerItemDataIndex = -1;
/// <summary>
/// 鼠标所在轴线上的数据项索引(可能有多个)
/// </summary>
public List<int> pointerAxisDataIndexs = new List<int>();
public bool isTriggerByAxis = false;
/// <summary>
/// 中心点
/// </summary>
public Vector3 center { get; internal set; }
/// <summary>
/// 内半径
/// </summary>
public float insideRadius { get; internal set; }
/// <summary>
/// 外半径
/// </summary>
public float outsideRadius { get; internal set; }
/// <summary>
/// 最大值
/// </summary>
public double dataMax { get; internal set; }
/// <summary>
/// 最小值
/// </summary>
public double dataMin { get; internal set; }
public double checkValue { get; set; }
/// <summary>
/// 左下角坐标X
/// </summary>
public float x { get; internal set; }
/// <summary>
/// 左下角坐标Y
/// </summary>
public float y { get; internal set; }
/// <summary>
/// 宽
/// </summary>
public float width { get; internal set; }
/// <summary>
/// 高
/// </summary>
public float height { get; internal set; }
/// <summary>
/// 矩形区域
/// </summary>
public Rect rect { get; internal set; }
/// <summary>
/// 绘制顶点数
/// </summary>
public int vertCount { get; internal set; }
/// <summary>
/// 数据对应的位置坐标。
/// </summary>
public List<Vector3> dataPoints = new List<Vector3>();
/// <summary>
/// 数据对应的位置坐标是否忽略忽略时连线是透明的dataIgnore 和 dataPoints 一一对应。
/// </summary>
public List<bool> dataIgnores = new List<bool>();
/// <summary>
/// 排序后的数据
/// </summary>
public List<SerieData> sortedData = new List<SerieData>();
/// <summary>
/// theme的颜色索引
/// </summary>
internal int colorIndex;
/// <summary>
/// 绘制点
/// </summary>
internal List<PointInfo> drawPoints = new List<PointInfo>();
public SerieParams param = new SerieParams();
}
}

View File

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

423
Runtime/Serie/SerieData.cs Normal file
View File

@@ -0,0 +1,423 @@

using System;
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
/// <summary>
/// A data item of serie.
/// 系列中的一个数据项。可存储数据名和1-n维个数据。
/// </summary>
[System.Serializable]
public class SerieData : ChildComponent
{
[SerializeField] private string m_Name;
[SerializeField] private string m_Uuid;
[SerializeField] private bool m_Selected;
[SerializeField] private bool m_Ignore = false;
[SerializeField] private float m_Radius;
[SerializeField] private List<ItemStyle> m_ItemStyles = new List<ItemStyle>();
[SerializeField] private List<LabelStyle> m_Labels = new List<LabelStyle>();
[SerializeField] private List<LabelLine> m_LabelLines = new List<LabelLine>();
[SerializeField] private List<Emphasis> m_Emphases = new List<Emphasis>();
[SerializeField] private List<SymbolStyle> m_Symbols = new List<SymbolStyle>();
[SerializeField] private List<IconStyle> m_IconStyles = new List<IconStyle>();
[SerializeField] private List<double> m_Data = new List<double>();
[SerializeField] private List<int> m_Children = new List<int>();
[NonSerialized] public SerieDataContext context = new SerieDataContext();
[NonSerialized] public InteractData interact = new InteractData();
public ChartLabel labelObject { get; set; }
private bool m_Show = true;
/// <summary>
/// the name of data item.
/// 数据项名称。
/// </summary>
public string name { get { return m_Name; } set { m_Name = value; } }
/// <summary>
/// 数据项的唯一id。唯一id不是必须设置的。
/// </summary>
public string uuid { get { return m_Uuid; } set { m_Uuid = value; } }
/// <summary>
/// 数据项图例名称。当数据项名称不为空时图例名称即为系列名称反之则为索引index。
/// </summary>
/// <value></value>
public string legendName { get { return string.IsNullOrEmpty(name) ? ChartCached.IntToStr(index) : name; } }
/// <summary>
/// 自定义半径。可用在饼图中自定义某个数据项的半径。
/// </summary>
public float radius { get { return m_Radius; } set { m_Radius = value; } }
/// <summary>
/// Whether the data item is selected.
/// 该数据项是否被选中。
/// </summary>
public bool selected { get { return m_Selected; } set { m_Selected = value; } }
/// <summary>
/// the icon of data.
/// 数据项图标样式。
/// </summary>
public IconStyle iconStyle { get { return m_IconStyles.Count > 0 ? m_IconStyles[0] : null; } }
/// <summary>
/// 单个数据项的标签设置。
/// </summary>
public LabelStyle label { get { return m_Labels.Count > 0 ? m_Labels[0] : null; } }
public LabelLine labelLine { get { return m_LabelLines.Count > 0 ? m_LabelLines[0] : null; } }
/// <summary>
/// 单个数据项的样式设置。
/// </summary>
public ItemStyle itemStyle { get { return m_ItemStyles.Count > 0 ? m_ItemStyles[0] : null; } }
/// <summary>
/// 单个数据项的高亮样式设置。
/// </summary>
public Emphasis emphasis { get { return m_Emphases.Count > 0 ? m_Emphases[0] : null; } }
/// <summary>
/// 单个数据项的标记设置。
/// </summary>
public SymbolStyle symbol { get { return m_Symbols.Count > 0 ? m_Symbols[0] : null; } }
/// <summary>
/// 是否忽略数据。当为 true 时,数据不进行绘制。
/// </summary>
public bool ignore
{
get { return m_Ignore; }
set { if (PropertyUtil.SetStruct(ref m_Ignore, value)) SetVerticesDirty(); }
}
/// <summary>
/// An arbitrary dimension data list of data item.
/// 可指定任意维数的数值列表。
/// </summary>
public List<double> data { get { return m_Data; } set { m_Data = value; } }
public List<int> children { get { return m_Children; } set { m_Children = value; } }
/// <summary>
/// [default:true] Whether the data item is showed.
/// 该数据项是否要显示。
/// </summary>
public bool show { get { return m_Show; } set { m_Show = value; } }
private List<double> m_PreviousData = new List<double>();
private List<float> m_DataUpdateTime = new List<float>();
private List<bool> m_DataUpdateFlag = new List<bool>();
private List<Vector2> m_PolygonPoints = new List<Vector2>();
public void Reset()
{
index = 0;
labelObject = null;
m_Name = string.Empty;
m_Show = true;
m_Selected = false;
context.canShowLabel = true;
context.highlight = false;
m_Radius = 0;
interact.Reset();
m_Data.Clear();
m_PreviousData.Clear();
m_DataUpdateTime.Clear();
m_DataUpdateFlag.Clear();
m_IconStyles.Clear();
m_Labels.Clear();
m_LabelLines.Clear();
m_ItemStyles.Clear();
m_Emphases.Clear();
m_Symbols.Clear();
}
public T GetOrAddComponent<T>() where T : ChildComponent
{
var type = typeof(T);
if (type == typeof(ItemStyle))
{
if (m_ItemStyles.Count == 0)
m_ItemStyles.Add(new ItemStyle() { show = true });
return m_ItemStyles[0] as T;
}
else if (type == typeof(IconStyle))
{
if (m_IconStyles.Count == 0)
m_IconStyles.Add(new IconStyle() { show = true });
return m_IconStyles[0] as T;
}
else if (type == typeof(LabelStyle))
{
if (m_Labels.Count == 0)
m_Labels.Add(new LabelStyle() { show = true });
return m_Labels[0] as T;
}
else if (type == typeof(LabelLine))
{
if (m_LabelLines.Count == 0)
m_LabelLines.Add(new LabelLine() { show = true });
return m_LabelLines[0] as T;
}
else if (type == typeof(Emphasis))
{
if (m_Emphases.Count == 0)
m_Emphases.Add(new Emphasis() { show = true });
return m_Emphases[0] as T;
}
else if (type == typeof(SymbolStyle))
{
if (m_Symbols.Count == 0)
m_Symbols.Add(new SymbolStyle() { show = true });
return m_Symbols[0] as T;
}
else
{
throw new System.Exception("SerieData not support component:" + type);
}
}
public void RemoveAllComponent()
{
m_ItemStyles.Clear();
m_IconStyles.Clear();
m_Labels.Clear();
m_LabelLines.Clear();
m_Symbols.Clear();
m_Emphases.Clear();
}
public void RemoveComponent<T>() where T : ISerieDataComponent
{
var type = typeof(T);
if (type == typeof(ItemStyle))
m_ItemStyles.Clear();
else if (type == typeof(IconStyle))
m_IconStyles.Clear();
else if (type == typeof(LabelStyle))
m_Labels.Clear();
else if (type == typeof(LabelLine))
m_LabelLines.Clear();
else if (type == typeof(Emphasis))
m_Emphases.Clear();
else if (type == typeof(SymbolStyle))
m_Symbols.Clear();
else
throw new System.Exception("SerieData not support component:" + type);
}
public double GetData(int index, bool inverse = false)
{
if (index >= 0 && index < m_Data.Count)
{
return inverse ? -m_Data[index] : m_Data[index];
}
else return 0;
}
public double GetData(int index, double min, double max)
{
if (index >= 0 && index < m_Data.Count)
{
var value = m_Data[index];
if (value < min) return min;
else if (value > max) return max;
else return value;
}
else return 0;
}
public double GetPreviousData(int index, bool inverse = false)
{
if (index >= 0 && index < m_PreviousData.Count)
{
return inverse ? -m_PreviousData[index] : m_PreviousData[index];
}
else return 0;
}
public double GetFirstData(float animationDuration = 500f)
{
if (m_Data.Count > 0) return GetCurrData(0, animationDuration);
return 0;
}
public double GetLastData()
{
if (m_Data.Count > 0) return m_Data[m_Data.Count - 1];
return 0;
}
public double GetCurrData(int index, float animationDuration = 500f, bool inverse = false)
{
return GetCurrData(index, animationDuration, inverse, 0, 0);
}
public double GetCurrData(int index, float animationDuration, bool inverse, double min, double max)
{
if (index < m_DataUpdateFlag.Count && m_DataUpdateFlag[index] && animationDuration > 0)
{
var time = Time.time - m_DataUpdateTime[index];
var total = animationDuration / 1000;
var rate = time / total;
if (rate > 1) rate = 1;
if (rate < 1)
{
CheckLastData();
var curr = MathUtil.Lerp(GetPreviousData(index), GetData(index), rate);
if (min != 0 || max != 0)
{
if (inverse)
{
var temp = min;
min = -max;
max = -temp;
}
var pre = m_PreviousData[index];
if (pre < min)
{
m_PreviousData[index] = min;
curr = min;
}
else if (pre > max)
{
m_PreviousData[index] = max;
curr = max;
}
}
curr = inverse ? -curr : curr;
return curr;
}
else
{
m_DataUpdateFlag[index] = false;
return GetData(index, inverse);
}
}
else
{
return GetData(index, inverse);
}
}
/// <summary>
/// the maxinum value.
/// 最大值。
/// </summary>
public double GetMaxData(bool inverse = false)
{
if (m_Data.Count == 0) return 0;
var temp = double.MinValue;
for (int i = 0; i < m_Data.Count; i++)
{
var value = GetData(i, inverse);
if (value > temp) temp = value;
}
return temp;
}
/// <summary>
/// the mininum value.
/// 最小值。
/// </summary>
public double GetMinData(bool inverse = false)
{
if (m_Data.Count == 0) return 0;
var temp = double.MaxValue;
for (int i = 0; i < m_Data.Count; i++)
{
var value = GetData(i, inverse);
if (value < temp) temp = value;
}
return temp;
}
public bool UpdateData(int dimension, double value, bool updateAnimation, float animationDuration = 500f)
{
if (dimension >= 0 && dimension < data.Count)
{
CheckLastData();
m_PreviousData[dimension] = GetCurrData(dimension, animationDuration);
//m_PreviousData[dimension] = data[dimension];;
m_DataUpdateTime[dimension] = Time.time;
m_DataUpdateFlag[dimension] = updateAnimation;
data[dimension] = value;
return true;
}
return false;
}
public bool UpdateData(int dimension, double value)
{
if (dimension >= 0 && dimension < data.Count)
{
data[dimension] = value;
return true;
}
return false;
}
private void CheckLastData()
{
if (m_PreviousData.Count != m_Data.Count)
{
m_PreviousData.Clear();
m_DataUpdateTime.Clear();
m_DataUpdateFlag.Clear();
for (int i = 0; i < m_Data.Count; i++)
{
m_PreviousData.Add(m_Data[i]);
m_DataUpdateTime.Add(Time.time);
m_DataUpdateFlag.Add(false);
}
}
}
public bool IsDataChanged()
{
foreach (var b in m_DataUpdateFlag)
if (b) return true;
return false;
}
public float GetLabelWidth()
{
if (labelObject != null) return labelObject.GetLabelWidth();
else return 0;
}
public float GetLabelHeight()
{
if (labelObject != null) return labelObject.GetLabelHeight();
return 0;
}
public void SetLabelActive(bool flag)
{
if (labelObject != null) labelObject.SetLabelActive(flag);
}
public void SetIconActive(bool flag)
{
if (labelObject != null) labelObject.SetIconActive(flag);
}
public void SetPolygon(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
{
m_PolygonPoints.Clear();
m_PolygonPoints.Add(p1);
m_PolygonPoints.Add(p2);
m_PolygonPoints.Add(p3);
m_PolygonPoints.Add(p4);
}
public bool IsInPolygon(Vector2 p)
{
if (m_PolygonPoints.Count == 0) return false;
var inside = false;
var j = m_PolygonPoints.Count - 1;
for (int i = 0; i < m_PolygonPoints.Count; j = i++)
{
var pi = m_PolygonPoints[i];
var pj = m_PolygonPoints[j];
if (((pi.y <= p.y && p.y < pj.y) || (pj.y <= p.y && p.y < pi.y)) &&
(p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x))
inside = !inside;
}
return inside;
}
}
}

View File

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

View File

@@ -0,0 +1,60 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace XCharts
{
public class SerieDataContext
{
public Vector3 labelPosition { get; set; }
/// <summary>
/// 开始角度
/// </summary>
public float startAngle { get; internal set; }
/// <summary>
/// 结束角度
/// </summary>
public float toAngle { get; internal set; }
/// <summary>
/// 一半时的角度
/// </summary>
public float halfAngle { get; internal set; }
/// <summary>
/// 当前角度
/// </summary>
public float currentAngle { get; internal set; }
/// <summary>
/// 饼图数据项的内半径
/// </summary>
public float insideRadius { get; internal set; }
/// <summary>
/// 饼图数据项的偏移半径
/// </summary>
public float offsetRadius { get; internal set; }
public float outsideRadius { get; set; }
public Vector3 position { get; set; }
public List<Vector3> dataPoints = new List<Vector3>();
/// <summary>
/// 绘制区域。
/// </summary>
public Rect rect { get; set; }
public Rect subRect { get; set; }
public int level { get; set; }
public SerieData parent { get; set; }
public Color32 color { get; set; }
public double area { get; set; }
public float angle { get; set; }
public Vector3 offsetCenter { get; set; }
public float stackHeight { get; set; }
public bool canShowLabel = true;
public Image symbol { get; set; }
/// <summary>
/// Whether the data item is highlighted.
/// 该数据项是否被高亮,一般由鼠标悬停或图例悬停触发高亮。
/// </summary>
public bool highlight { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,351 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace XCharts
{
public abstract class SerieHandler
{
public BaseChart chart { get; internal set; }
public SerieHandlerAttribute attribute { get; internal set; }
public virtual void InitComponent() { }
public virtual void RemoveComponent() { }
public virtual void CheckComponent(StringBuilder sb) { }
public virtual void Update() { }
public virtual void DrawBase(VertexHelper vh) { }
public virtual void DrawSerie(VertexHelper vh) { }
public virtual void DrawTop(VertexHelper vh) { }
public virtual void OnPointerClick(PointerEventData eventData) { }
public virtual void OnPointerDown(PointerEventData eventData) { }
public virtual void OnPointerUp(PointerEventData eventData) { }
public virtual void OnPointerEnter(PointerEventData eventData) { }
public virtual void OnPointerExit(PointerEventData eventData) { }
public virtual void OnDrag(PointerEventData eventData) { }
public virtual void OnBeginDrag(PointerEventData eventData) { }
public virtual void OnEndDrag(PointerEventData eventData) { }
public virtual void OnScroll(PointerEventData eventData) { }
public virtual void RefreshLabelNextFrame() { }
public virtual void RefreshLabelInternal() { }
public virtual void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, string marker, string itemFormatter, string numericFormatter, ref List<SerieParams> paramList, ref string title) { }
public virtual void OnLegendButtonClick(int index, string legendName, bool show) { }
public virtual void OnLegendButtonEnter(int index, string legendName) { }
public virtual void OnLegendButtonExit(int index, string legendName) { }
internal abstract void SetSerie(Serie serie);
}
public abstract class SerieHandler<T> : SerieHandler where T : Serie
{
private static readonly string s_SerieLabelObjectName = "label";
private static readonly string s_SerieTitleObjectName = "serie";
protected GameObject m_SerieRoot;
protected bool m_InitedLabel;
protected bool m_RefreshLabel;
protected bool m_LastCheckContextFlag = false;
protected bool m_LegendEnter = false;
protected int m_LegendEnterIndex;
public T serie { get; internal set; }
internal override void SetSerie(Serie serie)
{
this.serie = (T)serie;
this.serie.context.param.serieType = typeof(T);
}
public override void Update()
{
if (m_RefreshLabel)
{
m_RefreshLabel = false;
if (m_InitedLabel)
RefreshLabelInternal();
}
if (serie.label != null && (serie.labelDirty || serie.label.componentDirty))
{
serie.labelDirty = false;
serie.label.ClearComponentDirty();
InitSerieLabel();
}
if (serie.titleDirty || serie.titleStyle.componentDirty)
{
serie.titleDirty = false;
serie.titleStyle.ClearComponentDirty();
InitSerieTitle();
}
if (serie.nameDirty)
{
foreach (var component in chart.components)
{
if (component is Legend)
component.SetAllDirty();
}
chart.RefreshChart();
serie.ClearSerieNameDirty();
}
if (serie.vertsDirty)
{
chart.RefreshPainter(serie);
serie.ClearVerticesDirty();
}
}
public override void RefreshLabelNextFrame()
{
m_RefreshLabel = true;
}
public override void InitComponent()
{
InitRoot();
InitSerieLabel();
InitSerieTitle();
}
public override void RemoveComponent()
{
ChartHelper.SetActive(m_SerieRoot, false);
}
public override void OnLegendButtonClick(int index, string legendName, bool show)
{
if (serie.IsLegendName(legendName))
{
chart.SetSerieActive(serie, show);
chart.RefreshPainter(serie);
}
}
public override void OnLegendButtonEnter(int index, string legendName)
{
if (serie.IsLegendName(legendName))
{
m_LegendEnter = true;
chart.RefreshPainter(serie);
}
}
public override void OnLegendButtonExit(int index, string legendName)
{
if (serie.IsLegendName(legendName))
{
m_LegendEnter = false;
chart.RefreshPainter(serie);
}
}
private void InitRoot()
{
m_InitedLabel = false;
var objName = s_SerieTitleObjectName + "_" + serie.index;
m_SerieRoot = ChartHelper.AddObject(objName, chart.transform, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
m_SerieRoot.hideFlags = chart.chartHideFlags;
ChartHelper.SetActive(m_SerieRoot, true);
ChartHelper.HideAllObject(m_SerieRoot);
}
private void InitSerieLabel()
{
if (m_SerieRoot == null)
InitRoot();
var serieLabelRoot = ChartHelper.AddObject(s_SerieLabelObjectName, m_SerieRoot.transform, chart.chartMinAnchor,
chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta);
serieLabelRoot.hideFlags = chart.chartHideFlags;
SerieLabelPool.ReleaseAll(serieLabelRoot.transform);
int count = 0;
SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight);
for (int j = 0; j < serie.data.Count; j++)
{
var serieData = serie.data[j];
serieData.index = count;
serieData.labelObject = null;
if (AddSerieLabel(serieLabelRoot, serie, serieData, ref count))
{
m_InitedLabel = true;
count++;
}
}
}
protected bool AddSerieLabel(GameObject serieLabelRoot, Serie serie, SerieData serieData, ref int count)
{
if (serieLabelRoot == null)
return false;
if (serie.IsPerformanceMode())
return false;
if (count == -1) count = serie.dataCount;
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
if (serieLabel == null)
return false;
var serieEmphasisLabel = SerieHelper.GetSerieEmphasisLabel(serie, serieData);
var iconStyle = SerieHelper.GetIconStyle(serie, serieData);
if (!serieLabel.show && (serieEmphasisLabel == null || !serieEmphasisLabel.show)
&& (iconStyle != null && !iconStyle.show))
return false;
var textName = ChartCached.GetSerieLabelName(s_SerieLabelObjectName, serie.index, serieData.index);
var color = chart.theme.common.textColor;
var iconWidth = iconStyle != null ? iconStyle.width : 20;
var iconHeight = iconStyle != null ? iconStyle.height : 20;
var labelObj = SerieLabelPool.Get(textName, serieLabelRoot.transform, serieLabel, color,
iconWidth, iconHeight, chart.theme);
var iconImage = labelObj.transform.Find("Icon").GetComponent<Image>();
var isAutoSize = serieLabel.backgroundWidth == 0 || serieLabel.backgroundHeight == 0;
var item = ChartHelper.GetOrAddComponent<ChartLabel>(labelObj);
item.SetLabel(labelObj, isAutoSize, serieLabel.paddingLeftRight, serieLabel.paddingTopBottom);
item.SetIcon(iconImage);
item.SetIconActive(iconStyle != null && iconStyle.show);
item.color = serieLabel.textStyle.backgroundColor;
serieData.labelObject = item;
foreach (var data in serieData.children)
{
AddSerieLabel(serieLabelRoot, serie, serie.GetSerieData(data), ref count);
count++;
}
return true;
}
private void InitSerieTitle()
{
if (m_SerieRoot == null)
InitRoot();
var textStyle = serie.titleStyle.textStyle;
var titleColor = ChartHelper.IsClearColor(textStyle.color) ? chart.theme.GetColor(serie.index) : (Color32)textStyle.color;
var anchorMin = new Vector2(0.5f, 0.5f);
var anchorMax = new Vector2(0.5f, 0.5f);
var pivot = new Vector2(0.5f, 0.5f);
var fontSize = 10;
var sizeDelta = new Vector2(50, fontSize + 2);
var txt = ChartHelper.AddTextObject("title", m_SerieRoot.transform, anchorMin, anchorMax,
pivot, sizeDelta, textStyle, chart.theme.common);
txt.SetText("");
txt.SetColor(titleColor);
txt.SetLocalPosition(Vector2.zero);
txt.SetLocalEulerAngles(Vector2.zero);
txt.SetActive(serie.titleStyle.show);
serie.titleStyle.runtimeText = txt;
serie.titleStyle.UpdatePosition(serie.context.center);
var serieData = serie.GetSerieData(0);
if (serieData != null)
{
txt.SetText(serieData.name);
}
}
public override void RefreshLabelInternal()
{
if (!m_InitedLabel)
return;
var colorIndex = chart.GetLegendRealShowNameIndex(serie.legendName);
var total = serie.yTotal;
foreach (var serieData in serie.data)
{
if (serieData.labelObject == null)
continue;
var serieLabel = SerieHelper.GetSerieLabel(serie, serieData);
var iconStyle = SerieHelper.GetIconStyle(serie, serieData);
var isIgnore = serie.IsIgnoreIndex(serieData.index);
serieData.labelObject.SetPosition(serieData.context.position);
serieData.labelObject.UpdateIcon(iconStyle);
if (serie.show && serieLabel != null && serieLabel.show && serieData.context.canShowLabel && !isIgnore)
{
var value = serieData.GetData(1);
var content = SerieLabelHelper.GetFormatterContent(serie, serieData, value, total,
serieLabel, chart.theme.GetColor(colorIndex));
var invert = serieLabel.autoOffset
&& serie is Line
&& SerieHelper.IsDownPoint(serie, serieData.index)
&& (serie.areaStyle == null || !serie.areaStyle.show);
SerieLabelHelper.ResetLabel(serieData.labelObject.label, serieLabel, chart.theme);
serieData.SetLabelActive(!isIgnore);
serieData.labelObject.SetPosition(serieData.context.position + (invert ? -serieLabel.offset : serieLabel.offset));
serieData.labelObject.SetText(content);
}
else
{
serieData.SetLabelActive(false);
}
}
}
protected void UpdateCoordSerieParams(ref List<SerieParams> paramList, ref string title,
int dataIndex, bool showCategory, string category, string marker,
string itemFormatter, string numericFormatter)
{
if (dataIndex < 0)
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
var param = serie.context.param;
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.category = category;
param.dimension = 1;
param.serieData = serieData;
param.value = serieData.GetData(1);
param.total = serie.yTotal;
param.color = chart.GetLegendRealShowNameColor(serie.serieName);
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(showCategory ? category : serie.serieName);
param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter));
paramList.Add(param);
}
protected void UpdateItemSerieParams(ref List<SerieParams> paramList, ref string title,
int dataIndex, string category, string marker,
string itemFormatter, string numericFormatter, int dimension = 1)
{
if (dataIndex < 0)
dataIndex = serie.context.pointerItemDataIndex;
if (dataIndex < 0)
return;
var serieData = serie.GetSerieData(dataIndex);
if (serieData == null)
return;
var param = serie.context.param;
param.serieName = serie.serieName;
param.serieIndex = serie.index;
param.category = category;
param.dimension = dimension;
param.serieData = serieData;
param.value = serieData.GetData(param.dimension);
param.total = SerieHelper.GetMaxData(serie, dimension);
param.color = chart.theme.GetColor(dataIndex);
param.marker = SerieHelper.GetItemMarker(serie, serieData, marker);
param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter);
param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter); ;
param.columns.Clear();
param.columns.Add(param.marker);
param.columns.Add(serieData.name);
param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter));
paramList.Add(param);
}
}
}

View File

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

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace XCharts
{
public class SerieParams
{
public Type serieType;
public int serieIndex;
public string serieName;
public string marker = "●";
public string category;
public int dimension;
public SerieData serieData;
public double value;
public double total;
public Color32 color;
public string itemFormatter;
public string numericFormatter;
public List<string> columns = new List<string>();
}
}

View File

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