Compare commits

...

65 Commits

Author SHA1 Message Date
monitor1394
3deda8d9cc Merge branch 'master' into 3.0 2026-03-01 12:21:33 +08:00
monitor1394
7d4ba652ec 修复SaveAsImage保存的图片尺寸变大的问题 2026-02-28 21:56:35 +08:00
monitor1394
619246bee2 3.15.0 2026-02-27 21:14:53 +08:00
monitor1394
52b9b0a03a 增加SerieignoreZeroOccupy可设置0数据的Bar是否占位 (#286) 2026-02-26 22:31:50 +08:00
monitor1394
3301d5fd36 修复SaveAsImage被其他组件遮挡时无法正常保存的问题 (#337) 2026-02-26 21:53:29 +08:00
monitor1394
92abee1a6c 增加AxismainAxis参数设置主轴可控制柱图的朝向 (#331) 2026-02-26 08:47:51 +08:00
monitor1394
90e9187808 修复Pie的点击有时候不响应的问题 (#357) 2026-01-15 08:53:42 +08:00
monitor1394
b311d17d94 增加DataZoomminZoomRatio替换旧的minShowNum (#350) 2026-01-08 08:58:12 +08:00
monitor1394
880a6b1885 优化Candlestick对时间轴的支持 2025-11-05 23:05:15 +08:00
monitor1394
fb841a3498 修复AxisindicatorLabel无法隐藏的问题 2025-11-05 22:49:23 +08:00
monitor1394
ac41dd1d07 优化Candlestick对时间轴的支持 2025-11-05 08:55:02 +08:00
monitor1394
39cee1bd52 增加TooltipTitle可通过TitleLabelStylenumericFormatter格式化时间显示 (#353) 2025-11-03 07:41:41 +08:00
monitor1394
f1c9a3ac4b 增加ChartuseUtc参数设置显示时间是否用UTC时间 2025-10-31 08:39:29 +08:00
monitor1394
2cb82526bc 优化Candlestick对时间轴的支持 2025-10-30 22:48:36 +08:00
monitor1394
0499126e55 增加Scatterignore支持设置忽略数据 2025-10-30 22:46:53 +08:00
monitor1394
c2bafb8aa8 增加PiepieType支持实心饼图和线框柄图 (#349) 2025-10-22 09:06:28 +08:00
monitor1394
c83fe89a31 优化MarkLine的表现 2025-09-05 22:09:11 +08:00
monitor1394
dd473b7d29 增加AxisLinestartExtendLengthendExtendLength设置轴线的延长线 2025-09-01 23:05:49 +08:00
monitor1394
d1f424f3a1 修复SerieTitleStyle在数据变更时不及时刷新的问题 2025-08-27 09:10:58 +08:00
monitor1394
efbe16b804 修复TMP开启时Axis运行报错 2025-05-19 21:57:11 +08:00
monitor1394
2d2e45da80 修复TMP开启时Axis运行报错 2025-05-19 21:55:52 +08:00
monitor1394
06bd26dc5f 修复MarkArea指定yValuexValue时绘制区域不准确的问题 2025-04-25 22:42:11 +08:00
monitor1394
a0dba26318 重构Title相关代码 2025-04-17 22:10:47 +08:00
monitor1394
e124d38d3e 增加Bar支持通过VisualMap设置颜色 2025-04-15 23:11:05 +08:00
monitor1394
21ffcba0c0 增加AxisLabelshowZeroLabel设置是否显示0刻度 2025-04-15 22:51:59 +08:00
monitor1394
ccf815c853 优化AxisTime时间轴支持设置Custom和ceilRate 2025-04-07 22:30:17 +08:00
monitor1394
fc0451e535 update doc 2025-04-07 20:59:12 +08:00
monitor1394
b23c581b63 修复GridCoord在设置背景色且Serie开启Clip时会覆盖图表的问题 2025-04-07 11:16:33 +08:00
monitor1394
eafd7276c0 修复AxisTime时间轴无法显示大于2038的年份的问题 2025-04-07 10:03:19 +08:00
monitor1394
3818d1213e 修复AxisTime时间轴在有DataZoom缩放时文本显示异常的问题 2025-04-06 22:24:05 +08:00
monitor1394
85b92ca2cc 增加LegenditemInactiveOpacity可设置非激活状态时的颜色透明度 (#343) 2025-03-27 22:35:02 +08:00
monitor1394
546ff1f61a 增加AxisonLabelClick回调事件 2025-03-27 08:39:30 +08:00
monitor1394
da360693e6 增加AxisonLabelClick回调事件 2025-03-27 08:31:21 +08:00
monitor1394
ad3bc75d7c 重命名MarkLineType的None为Custom 2025-03-26 22:24:41 +08:00
monitor1394
0b218f6dfe 增加AnimationExchange排序交换动画 2025-03-26 08:28:27 +08:00
monitor1394
9e07617cc4 增加Commentlayer设置层级 2025-03-22 09:24:46 +08:00
monitor1394
8bc66ca30a 优化Comment坐标刷新 2025-03-21 21:39:12 +08:00
monitor1394
20da9dbe94 增加SerieLabelformatter支持{index}通配符 2025-03-21 08:44:33 +08:00
monitor1394
62f071e5a9 增加SerieLabelformatter支持{index}通配符 2025-03-19 23:03:11 +08:00
monitor1394
4c001c8130 增加Bar可添加TitleStyle组件支持 2025-03-18 23:10:52 +08:00
monitor1394
4ad4505720 增加Bar可添加TitleStyle组件支持 2025-03-18 08:18:22 +08:00
monitor1394
47caaa2113 增加LabelStylefixedXfixedY可固定label的坐标 2025-03-18 07:41:58 +08:00
monitor1394
2f8a1300d3 增加ItemStylebackgroundGap可设置数据项背景间隙 2025-03-18 07:37:15 +08:00
monitor1394
b9c72c8cb9 Merge branch 'master' into 3.0 2025-01-01 23:13:07 +08:00
monitor1394
d76b474a61 Merge branch 'master' into 3.0 2024-12-01 22:20:39 +08:00
monitor1394
2acb841d2e Merge branch 'master' into 3.0 2024-09-30 18:35:24 +08:00
monitor1394
8af1796ff8 Merge branch 'master' into 3.0 2024-06-16 22:08:09 +08:00
monitor1394
78a07aa2ae 修复Pie在设置ItemStyleopacity时颜色不对的问题 (#309) 2024-03-19 22:33:19 +08:00
monitor1394
fe867d18e6 Merge branch 'master' into 3.0 2024-03-19 22:03:31 +08:00
monitor1394
757ccb04fb 修复Tooltip移出坐标系后还显示的问题 2024-03-11 08:00:40 +08:00
monitor1394
b4cb62241f 修复Legendformatter在设置{d}通配符时显示可能不匹配的问题 (#304) 2024-03-11 07:01:22 +08:00
monitor1394
0fb1cab302 修复Legendformatter在设置{d}通配符时显示可能不匹配的问题 2024-03-11 07:00:31 +08:00
monitor1394
ead9034870 修复Tooltiptitle从旧版本升级后可能不显示的问题 2024-03-08 08:39:06 +08:00
monitor1394
20c87265a5 Merge branch 'master' into 3.0 2024-02-23 08:34:58 +08:00
monitor1394
1e31cf3010 Merge branch 'master' into 3.0 2023-12-01 22:22:51 +08:00
monitor1394
d33e2f66ef Merge branch 'master' into 3.0 2023-10-02 12:12:58 +08:00
monitor1394
ff4fbb2176 Merge branch 'master' into 3.0 2023-09-04 22:43:48 +08:00
monitor1394
9fc3ff862f Merge branch 'master' into 3.0 2023-06-09 08:05:20 +08:00
monitor1394
bc31f86fcf Merge branch 'master' into 3.0 2023-04-01 23:16:34 +08:00
monitor1394
c6412f5d78 Merge branch 'master' into 3.0 2022-12-01 21:45:30 +08:00
monitor1394
0e60a26333 Merge branch 'master' into 3.0 2022-11-01 07:54:45 +08:00
monitor1394
59bb60950b Merge branch 'master' into 3.0 2022-09-28 08:25:06 +08:00
monitor1394
b3320bd2cd Merge branch 'master' into 3.0 2022-08-16 08:31:50 +08:00
monitor1394
71cfbc15f3 Merge branch 'master' into 3.0 2022-07-12 07:43:08 +08:00
monitor1394
8fbda1fa73 v3.0.1 2022-06-16 08:18:07 +08:00
78 changed files with 2315 additions and 504 deletions

View File

@@ -13,6 +13,7 @@ slug: /api
- [AnimationAddition](#animationaddition) - [AnimationAddition](#animationaddition)
- [AnimationChange](#animationchange) - [AnimationChange](#animationchange)
- [AnimationEasing](#animationeasing) - [AnimationEasing](#animationeasing)
- [AnimationExchange](#animationexchange)
- [AnimationFadeIn](#animationfadein) - [AnimationFadeIn](#animationfadein)
- [AnimationFadeOut](#animationfadeout) - [AnimationFadeOut](#animationfadeout)
- [AnimationHiding](#animationhiding) - [AnimationHiding](#animationhiding)
@@ -70,6 +71,7 @@ slug: /api
- [ColorUtil](#colorutil) - [ColorUtil](#colorutil)
- [Comment](#comment) - [Comment](#comment)
- [CommentItem](#commentitem) - [CommentItem](#commentitem)
- [CommentLayer](#commentlayer)
- [CommentMarkStyle](#commentmarkstyle) - [CommentMarkStyle](#commentmarkstyle)
- [ComponentHandlerAttribute](#componenthandlerattribute) - [ComponentHandlerAttribute](#componenthandlerattribute)
- [ComponentHelper](#componenthelper) - [ComponentHelper](#componenthelper)
@@ -157,6 +159,7 @@ slug: /api
- [MainComponentContext](#maincomponentcontext) - [MainComponentContext](#maincomponentcontext)
- [MainComponentHandler](#maincomponenthandler) - [MainComponentHandler](#maincomponenthandler)
- [MainComponentHandler<T>](#maincomponenthandlert) - [MainComponentHandler<T>](#maincomponenthandlert)
- [MainComponentHandler<Title>](#maincomponenthandlertitle)
- [MarkArea](#markarea) - [MarkArea](#markarea)
- [MarkAreaData](#markareadata) - [MarkAreaData](#markareadata)
- [MarkAreaType](#markareatype) - [MarkAreaType](#markareatype)
@@ -179,6 +182,7 @@ slug: /api
- [ParallelCoordContext](#parallelcoordcontext) - [ParallelCoordContext](#parallelcoordcontext)
- [Pie](#pie) - [Pie](#pie)
- [PieChart](#piechart) - [PieChart](#piechart)
- [PieType](#pietype)
- [PolarAxisTheme](#polaraxistheme) - [PolarAxisTheme](#polaraxistheme)
- [PolarChart](#polarchart) - [PolarChart](#polarchart)
- [PolarCoord](#polarcoord) - [PolarCoord](#polarcoord)
@@ -255,6 +259,7 @@ slug: /api
- [ThemeStyle](#themestyle) - [ThemeStyle](#themestyle)
- [ThemeType](#themetype) - [ThemeType](#themetype)
- [Title](#title) - [Title](#title)
- [TitleHandler](#titlehandler)
- [TitleStyle](#titlestyle) - [TitleStyle](#titlestyle)
- [TitleTheme](#titletheme) - [TitleTheme](#titletheme)
- [Tooltip](#tooltip) - [Tooltip](#tooltip)
@@ -360,6 +365,14 @@ Options:
- `Linear`: - `Linear`:
## AnimationExchange
class in XCharts.Runtime / Inherits from: [AnimationInfo](#animationinfo)
> Since `v3.15.0`
Data exchange animation. Generally used for animation of data sorting.
## AnimationFadeIn ## AnimationFadeIn
class in XCharts.Runtime / Inherits from: [AnimationInfo](#animationinfo) class in XCharts.Runtime / Inherits from: [AnimationInfo](#animationinfo)
@@ -386,7 +399,7 @@ Data hiding animation.
## AnimationInfo ## AnimationInfo
class in XCharts.Runtime / Subclasses: [AnimationFadeIn](#animationfadein),[AnimationFadeOut](#animationfadeout),[AnimationChange](#animationchange),[AnimationAddition](#animationaddition),[AnimationHiding](#animationhiding),[AnimationInteraction](#animationinteraction) class in XCharts.Runtime / Subclasses: [AnimationFadeIn](#animationfadein),[AnimationFadeOut](#animationfadeout),[AnimationChange](#animationchange),[AnimationAddition](#animationaddition),[AnimationHiding](#animationhiding),[AnimationInteraction](#animationinteraction),[AnimationExchange](#animationexchange)
> Since `v3.8.0` > Since `v3.8.0`
@@ -531,7 +544,7 @@ public float GetWidth(float width)
class in XCharts.Runtime / Inherits from: [ChildComponent](#childcomponent) class in XCharts.Runtime / Inherits from: [ChildComponent](#childcomponent)
the animation of serie. support animation type: fadeIn, fadeOut, change, addition. the animation of serie. support animation type: fadeIn, fadeOut, change, addition, exchange.
### AnimationStyle.addition ### AnimationStyle.addition
@@ -548,6 +561,11 @@ Update data animation configuration.
public bool enable public bool enable
Whether to enable animation. Whether to enable animation.
### AnimationStyle.exchange
public AnimationExchange exchange
Exchange animation configuration. Valid in sort bar chart.
### AnimationStyle.fadeIn ### AnimationStyle.fadeIn
public AnimationFadeIn fadeIn public AnimationFadeIn fadeIn
@@ -639,6 +657,10 @@ public int GetCurrIndex()
public float GetCurrRate() public float GetCurrRate()
### AnimationStyle.GetExchangeDuration
public float GetExchangeDuration()
### AnimationStyle.GetInteractionDuration ### AnimationStyle.GetInteractionDuration
public float GetInteractionDuration() public float GetInteractionDuration()
@@ -789,6 +811,14 @@ class in XCharts.Runtime / Inherits from: [MainComponent](#maincomponent) / Subc
The axis in rectangular coordinate. The axis in rectangular coordinate.
### Axis.onLabelClick
public Action<int, string> onLabelClick
> Since `v3.15.0`
Callback function when click on the label. Parameters: labelIndex, labelName.
### Axis.AddData ### Axis.AddData
public void AddData(string category) public void AddData(string category)
@@ -888,7 +918,7 @@ public bool IsLog()
### Axis.IsNeedShowLabel ### Axis.IsNeedShowLabel
public bool IsNeedShowLabel(int index, int total = 0) public bool IsNeedShowLabel(int index, int total = 0, string content = null)
### Axis.IsRight ### Axis.IsRight
@@ -1059,6 +1089,14 @@ class in XCharts / Inherits from: [MainComponentHandler](#maincomponenthandler)
public T component public T component
### AxisHandler<T>.DrawTop
// public override void DrawTop(VertexHelper vh)
### AxisHandler<T>.OnPointerClick
public override void OnPointerClick(PointerEventData eventData)
## AxisHelper ## AxisHelper
class in XCharts.Runtime class in XCharts.Runtime
@@ -1097,7 +1135,7 @@ public static float GetAxisValueDistance(GridCoord grid, Axis axis, float scaleW
### AxisHelper.GetAxisValueLength ### AxisHelper.GetAxisValueLength
public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value) public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value, float gap = 0)
获得数值value在坐标轴上对应的长度 获得数值value在坐标轴上对应的长度
### AxisHelper.GetAxisValuePosition ### AxisHelper.GetAxisValuePosition
@@ -1184,7 +1222,7 @@ public override string GetFormatterContent(int labelIndex, int totalIndex, doubl
### AxisLabel.IsNeedShowLabel ### AxisLabel.IsNeedShowLabel
public bool IsNeedShowLabel(int index, int total) public bool IsNeedShowLabel(int index, int total, string content = null)
### AxisLabel.SetRelatedText ### AxisLabel.SetRelatedText
@@ -1674,6 +1712,10 @@ Global parameter setting component.
public ThemeStyle theme public ThemeStyle theme
### BaseChart.topPainter
public Painter topPainter
### BaseChart.typeListForComponent ### BaseChart.typeListForComponent
public Dictionary<Type, FieldInfo> typeListForComponent public Dictionary<Type, FieldInfo> typeListForComponent
@@ -1682,6 +1724,11 @@ public Dictionary<Type, FieldInfo> typeListForComponent
public Dictionary<Type, FieldInfo> typeListForSerie public Dictionary<Type, FieldInfo> typeListForSerie
### BaseChart.useUtc
public bool useUtc
Whether to use UTC time for the chart.
### BaseChart.AddChartComponent ### BaseChart.AddChartComponent
public MainComponent AddChartComponent(Type type) public MainComponent AddChartComponent(Type type)
@@ -1938,6 +1985,10 @@ public Color32 GetLegendRealShowNameColor(string name)
public int GetLegendRealShowNameIndex(string name) public int GetLegendRealShowNameIndex(string name)
### BaseChart.GetMainAxis
public Axis GetMainAxis()
### BaseChart.GetMarkColor ### BaseChart.GetMarkColor
public Color32 GetMarkColor(Serie serie, SerieData serieData) public Color32 GetMarkColor(Serie serie, SerieData serieData)
@@ -1996,10 +2047,6 @@ public float GetSerieTotalGap<T>(float categoryWidth, float gap, int index
public float GetSerieTotalWidth<T>(float categoryWidth, float gap, int realBarCount, int gridIndex) where T : Serie public float GetSerieTotalWidth<T>(float categoryWidth, float gap, int realBarCount, int gridIndex) where T : Serie
### BaseChart.GetTitlePosition
public Vector3 GetTitlePosition(Title title)
### BaseChart.GetVisualMapOfSerie ### BaseChart.GetVisualMapOfSerie
public VisualMap GetVisualMapOfSerie(Serie serie) public VisualMap GetVisualMapOfSerie(Serie serie)
@@ -2519,6 +2566,10 @@ public string warningInfo
public string CheckWarning() public string CheckWarning()
检测警告信息。 检测警告信息。
### BaseGraph.GetTitlePosition
public Vector3 GetTitlePosition(Title title)
### BaseGraph.LocalPointToScreenPoint ### BaseGraph.LocalPointToScreenPoint
public Vector2 LocalPointToScreenPoint(Vector2 localPoint) public Vector2 LocalPointToScreenPoint(Vector2 localPoint)
@@ -2585,11 +2636,6 @@ public void RefreshAllComponent()
public virtual void RefreshGraph() public virtual void RefreshGraph()
Redraw graph in next frame. Redraw graph in next frame.
### BaseGraph.SaveAsImage
public void SaveAsImage(string imageType = "png", string savePath = "")
保存图表为图片。
### BaseGraph.ScreenPointToChartPoint ### BaseGraph.ScreenPointToChartPoint
public bool ScreenPointToChartPoint(Vector2 screenPoint, out Vector2 chartPoint) public bool ScreenPointToChartPoint(Vector2 screenPoint, out Vector2 chartPoint)
@@ -2847,6 +2893,14 @@ public static string ColorToStr(Color color)
public static string FloatToStr(double value, string numericFormatter = "F", int precision = 0) public static string FloatToStr(double value, string numericFormatter = "F", int precision = 0)
### ChartCached.GetAxisLabelName
public static string GetAxisLabelName(int index)
### ChartCached.GetComponentObjectName
public static string GetComponentObjectName(MainComponent component)
### ChartCached.GetSerieLabelName ### ChartCached.GetSerieLabelName
public static string GetSerieLabelName(string prefix, int i, int j) public static string GetSerieLabelName(string prefix, int i, int j)
@@ -2855,17 +2909,25 @@ public static string GetSerieLabelName(string prefix, int i, int j)
public static string GetString(string prefix, int suffix) public static string GetString(string prefix, int suffix)
### ChartCached.GetTypeName
public static string GetTypeName(Type type)
### ChartCached.GetTypeName<T>
public static string GetTypeName<T>()
### ChartCached.IntToStr ### ChartCached.IntToStr
public static string IntToStr(int value, string numericFormatter = "") public static string IntToStr(int value, string numericFormatter = "")
### ChartCached.NumberToDateStr ### ChartCached.NumberToDateStr
public static string NumberToDateStr(double timestamp, string formatter) public static string NumberToDateStr(double timestamp, string formatter, bool local = false)
### ChartCached.NumberToDateTime ### ChartCached.NumberToDateTime
public static DateTime NumberToDateTime(double timestamp) public static DateTime NumberToDateTime(double timestamp, bool local = false)
### ChartCached.NumberToStr ### ChartCached.NumberToStr
@@ -3111,10 +3173,6 @@ public static void RemoveTMPComponents(GameObject gameObject)
public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle) public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
### ChartHelper.SaveAsImage
public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png", string path = "")
### ChartHelper.SetActive ### ChartHelper.SetActive
public static bool SetActive(Image image, bool active) public static bool SetActive(Image image, bool active)
@@ -3174,6 +3232,10 @@ public float GetTextWidth()
public float GetWidth() public float GetWidth()
### ChartLabel.InRect
public bool InRect(Vector2 local)
### ChartLabel.IsActiveByScale ### ChartLabel.IsActiveByScale
public bool IsActiveByScale() public bool IsActiveByScale()
@@ -3428,13 +3490,20 @@ Convert the html string to color.
class in XCharts.Runtime / Inherits from: [MainComponent](#maincomponent),[IPropertyChanged](#ipropertychanged) class in XCharts.Runtime / Inherits from: [MainComponent](#maincomponent),[IPropertyChanged](#ipropertychanged)
comment of chart. > Since `v3.15.0`
comment of chart. Used to annotate special information in the chart.
### Comment.items ### Comment.items
public List<CommentItem> items public List<CommentItem> items
The items of comment. The items of comment.
### Comment.layer
public CommentLayer layer
The layer of comment.
### Comment.show ### Comment.show
public bool show public bool show
@@ -3443,10 +3512,12 @@ Set this to false to prevent the comment from showing.
### Comment.GetLabelStyle ### Comment.GetLabelStyle
public LabelStyle GetLabelStyle(int index) public LabelStyle GetLabelStyle(int index)
Get the label style of comment item.
### Comment.GetMarkStyle ### Comment.GetMarkStyle
public CommentMarkStyle GetMarkStyle(int index) public CommentMarkStyle GetMarkStyle(int index)
Get the mark style of comment item.
### Comment.OnChanged ### Comment.OnChanged
@@ -3478,6 +3549,17 @@ the mark rect style.
public bool show public bool show
Set this to false to prevent this comment item from showing. Set this to false to prevent this comment item from showing.
## CommentLayer
class in XCharts.Runtime
The layer of comment.
Options:
- `Lower`: The comment is display under the serie.
- `Upper`: The comment is display above the serie.
## CommentMarkStyle ## CommentMarkStyle
class in XCharts.Runtime / Inherits from: [ChildComponent](#childcomponent) class in XCharts.Runtime / Inherits from: [ChildComponent](#childcomponent)
@@ -3763,17 +3845,17 @@ class in XCharts.Runtime
### DateTimeUtil.GetDateTime ### DateTimeUtil.GetDateTime
public static DateTime GetDateTime(double timestamp, bool local = true) public static DateTime GetDateTime(double timestamp, bool local = false)
### DateTimeUtil.GetDefaultDateTimeString ### DateTimeUtil.GetDefaultDateTimeString
public static string GetDefaultDateTimeString(int timestamp, double range = 0) public static string GetDefaultDateTimeString(double timestamp, double range = 0, bool local = false)
### DateTimeUtil.GetTimestamp ### DateTimeUtil.GetTimestamp
public static int GetTimestamp(DateTime time, bool local = false) public static double GetTimestamp(DateTime time, bool local = false)
public static int GetTimestamp(string dateTime, bool local = false) public static double GetTimestamp(string dateTime, bool local = false)
### DateTimeUtil.IsDateOrTimeRegex ### DateTimeUtil.IsDateOrTimeRegex
@@ -4683,7 +4765,7 @@ public virtual string GetFormatterContent(int labelIndex, int totalIndex, double
### LabelStyle.GetFormatterDateTime ### LabelStyle.GetFormatterDateTime
public string GetFormatterDateTime(int labelIndex, int totalIndex, double value, double minValue, double maxValue) public string GetFormatterDateTime(int labelIndex, int totalIndex, double value, double minValue, double maxValue, bool local)
### LabelStyle.GetOffset ### LabelStyle.GetOffset
@@ -5687,6 +5769,10 @@ class in XCharts.Runtime / Inherits from: [MainComponentHandler](#maincomponenth
public T component public T component
## MainComponentHandler<Title>
class in / Subclasses: [TitleHandler](#titlehandler)
## MarkArea ## MarkArea
class in XCharts.Runtime / Inherits from: [MainComponent](#maincomponent) class in XCharts.Runtime / Inherits from: [MainComponent](#maincomponent)
@@ -5781,15 +5867,15 @@ public double runtimeValue
class in XCharts.Runtime class in XCharts.Runtime
标线类型 Mark line type.
Options: Options:
- `None`: 标线类型 - `Custom`: Custom. You can customize the xy coordinates or values.
- `Min`: 最小值。 - `Min`: Minimum value.
- `Max`: 最大值。 - `Max`: Maximum value.
- `Average`: 平均值。 - `Average`: Average value.
- `Median`: 中位数。 - `Median`: Median.
## MarqueeStyle ## MarqueeStyle
@@ -5982,10 +6068,6 @@ class in XCharts.Runtime / Inherits from: [MaskableGraphic](https://docs.unity3d
public int index public int index
### Painter.onPopulateMesh
public Action<VertexHelper, Painter> onPopulateMesh
### Painter.type ### Painter.type
public Type type public Type type
@@ -6120,6 +6202,15 @@ default label pie chart.
public void DefaultRadiusRosePieChart() public void DefaultRadiusRosePieChart()
default rose pie chart. default rose pie chart.
## PieType
class in XCharts.Runtime
Options:
- `Solid`: solid pie chart - default fill style.
- `Wireframe`: wireframe pie chart - only show the outline wireframe.
## PolarAxisTheme ## PolarAxisTheme
class in XCharts.Runtime / Inherits from: [BaseAxisTheme](#baseaxistheme) class in XCharts.Runtime / Inherits from: [BaseAxisTheme](#baseaxistheme)
@@ -7141,12 +7232,12 @@ public double GetLastData()
### SerieData.GetMaxData ### SerieData.GetMaxData
public double GetMaxData(bool inverse = false) public double GetMaxData(bool inverse = false, int startDimensionIndex = 0)
the maxinum value. the maxinum value.
### SerieData.GetMinData ### SerieData.GetMinData
public double GetMinData(bool inverse = false) public double GetMinData(bool inverse = false, int startDimensionIndex = 0)
the mininum value. the mininum value.
### SerieData.GetMinMaxData ### SerieData.GetMinMaxData
@@ -7257,6 +7348,10 @@ class in XCharts.Runtime
public void Reset() public void Reset()
### SerieDataContext.UpdateExchangePosition
public void UpdateExchangePosition(ref float x, ref float y, float totalTime)
## SerieDataExtraFieldAttribute ## SerieDataExtraFieldAttribute
class in XCharts.Runtime / Inherits from: [Attribute](https://docs.unity3d.com/ScriptReference/30_search.html?q=attribute) class in XCharts.Runtime / Inherits from: [Attribute](https://docs.unity3d.com/ScriptReference/30_search.html?q=attribute)
@@ -7685,6 +7780,10 @@ public override void RefreshLabelInternal()
public override void RefreshLabelNextFrame() public override void RefreshLabelNextFrame()
### SerieHandler<T>.RefreshTitleLabelInternal
public void RefreshTitleLabelInternal()
### SerieHandler<T>.RemoveComponent ### SerieHandler<T>.RemoveComponent
public override void RemoveComponent() public override void RemoveComponent()
@@ -8605,6 +8704,30 @@ public override void ClearComponentDirty()
public void OnChanged() public void OnChanged()
## TitleHandler
class in XCharts.Runtime / Inherits from: [MainComponentHandler<Title>](#maincomponenthandlertitle)
### TitleHandler.AddSubTitleLabel
public static ChartLabel AddSubTitleLabel(Transform parent, Title title, ComponentTheme componentTheme, BaseChart chart = null)
### TitleHandler.AddTitleLabel
public static ChartLabel AddTitleLabel(Transform parent, Title title, ComponentTheme componentTheme, BaseChart chart = null)
### TitleHandler.AddTitleObject
public static GameObject AddTitleObject(BaseGraph graph, Title title, ComponentTheme componentTheme, int titleSiblingIndex, string objectName = null)
### TitleHandler.InitComponent
public override void InitComponent()
### TitleHandler.OnSerieDataUpdate
public override void OnSerieDataUpdate(int serieIndex)
## TitleStyle ## TitleStyle
class in XCharts.Runtime / Inherits from: [LabelStyle](#labelstyle),[ISerieDataComponent](#iseriedatacomponent),[ISerieComponent](#iseriecomponent) class in XCharts.Runtime / Inherits from: [LabelStyle](#labelstyle),[ISerieDataComponent](#iseriedatacomponent),[ISerieComponent](#iseriecomponent)

View File

@@ -6,6 +6,7 @@ slug: /changelog
# Changelog # Changelog
[master](#master) [master](#master)
[v3.15.0](#v3150)
[v3.14.0](#v3140) [v3.14.0](#v3140)
[v3.13.0](#v3130) [v3.13.0](#v3130)
[v3.12.1](#v3121) [v3.12.1](#v3121)
@@ -79,9 +80,62 @@ slug: /changelog
## master ## master
## v3.15.0
Version Highlights:
* __Enhanced Timeline & Zoom Capabilities__: Added `DataZoom.minZoomRatio` (replacing `minShowNum`), `Chart.useUtc`, and continuous optimization of `Axis Time` performance during zooming and handling of large year ranges.
* __More Flexible Bar Charts & Axis Configuration__: Added `Axis.mainAxis` to control bar chart orientation, `Serie.ignoreZeroOccupy` to control whether zero-value bars occupy space, and `AxisLine` extension line configurations.
* __Improved Chart Styling & Interactivity__: Added `Pie.pieType`, `Legend.itemInactiveOpacity`, `Axis.onLabelClick`, `Animation.Exchange`, `LabelStyle.fixedX/fixedY`, and more.
* __Ongoing Enhancement of Extended UI Components__: Added `Title` and `Viewport` configurations for `UITable`, enhanced `UIStatistic.desc`, and optimized `Comment.layer` and coordinate refresh experience.
* __Focused Stability & Compatibility Fixes__: Resolved critical issues including `SaveAsImage` being blocked by other components, `Pie` click failures, `TMP` compatibility, `Gantt` time range and year 2038 problem, `MarkArea/GridCoord/Axis` and more.
Changelog Details:
* (2026.03.01) Released version `v3.15.0`
* (2026.02.26) Added `ignoreZeroOccupy` to `Serie` to set whether zero-value Bars occupy space (#286)
* (2026.02.26) Fixed `SaveAsImage` not saving correctly when blocked by other components (#337)
* (2026.02.26) Added `mainAxis` parameter to `Axis` to set the main axis for controlling bar chart orientation (#331)
* (2026.02.03) Fixed `UITable` `viewport` potentially drawing incorrectly under different anchor points
* (2026.01.15) Fixed `Pie` click sometimes not responding (#357)
* (2026.01.08) Added `minZoomRatio` to `DataZoom` to replace the old `minShowNum` (#350)
* (2025.11.05) Fixed `Axis` `indicatorLabel` not being hideable
* (2025.11.03) Added `Tooltip` `Title` time formatting via `TitleLabelStyle` `numericFormatter` (#353)
* (2025.10.30) Added `useUtc` parameter to `Chart` to set whether displayed time uses UTC
* (2025.10.30) Optimized `Candlestick` support for time axis
* (2025.10.30) Added support for `ignore` in `Scatter` to skip data points
* (2025.10.24) Optimized line drawing order for `Sankey`
* (2025.10.22) Added `pieType` to `Pie` supporting solid pie charts and wireframe handle charts (#349)
* (2025.09.05) Optimized `MarkLine` performance
* (2025.09.01) Added `startExtendLength` and `endExtendLength` to `AxisLine` for setting axis line extensions
* (2025.08.27) Fixed `Serie` `TitleStyle` not refreshing promptly when data changed
* (2025.05.19) Fixed `Axis` runtime error when `TMP` is enabled
* (2025.04.25) Fixed `MarkArea` drawing inaccurately when specifying `yValue` or `xValue`
* (2025.04.17) Added `Title` support for `UITable` to set headers
* (2025.04.17) Added `Viewport` support for `UITable` to set table viewport margins and borders
* (2025.04.15) Added `Bar` support for color settings via `VisualMap`
* (2025.04.14) Added `showZeroLabel` to `AxisLabel` to set whether to display zero tick
* (2025.04.08) Added `desc` description text setting support for `UIStatistic`
* (2025.04.07) Fixed `Gantt` chart calculating inaccurate time ranges with multi-dimensional data
* (2025.04.07) Optimized `Axis` `Time` axis support for Custom and ceilRate settings
* (2025.04.07) Fixed `GridCoord` covering charts when background color set and Serie Clip enabled
* (2025.04.07) Fixed `Gantt` chart display errors when year exceeds 2038
* (2025.04.07) Fixed `Axis` `Time` axis not displaying years beyond 2038
* (2025.04.06) Fixed `Axis` `Time` axis text display errors when zoomed with `DataZoom`
* (2025.03.28) Fixed `Pie3D` `avoidLabelOverlap` not working
* (2025.03.27) Added `itemInactiveOpacity` to `Legend` to set color transparency for inactive states (#343)
* (2025.03.27) Added `onLabelClick` callback event to `Axis`
* (2025.03.26) Added `Exchange` sort swap animation to `Animation`
* (2025.03.22) Added `layer` setting to `Comment`
* (2025.03.21) Optimized coordinate refresh for `Comment`
* (2025.03.19) Added `{index}` wildcard support for `Serie` `Label` `formatter`
* (2025.03.18) Added `TitleStyle` component support for `Bar`
* (2025.03.18) Added `fixedX` and `fixedY` to `LabelStyle` to fix label coordinates
* (2025.03.17) Added `backgroundGap` to `ItemStyle` to set data item background gap
## v3.14.0 ## v3.14.0
**Key Highlights:** Version Highlights:
* Added real-time sorting functionality for `Bar` * Added real-time sorting functionality for `Bar`
* Added support for `\n` line breaks in `itemFormatter` for `Tooltip` * Added support for `\n` line breaks in `itemFormatter` for `Tooltip`
@@ -89,7 +143,7 @@ slug: /changelog
* Added `speed` to `Animation` to specify animation speed * Added `speed` to `Animation` to specify animation speed
* Optimized column alignment in `Tooltip` * Optimized column alignment in `Tooltip`
**Detailed Changelog:** Changelog Details:
* (2025.03.15) Released version `v3.14.0` * (2025.03.15) Released version `v3.14.0`
* (2025.03.09) Fixed an issue where `Bar` displayed abnormally when placed in different `Grids` within the same `Chart` * (2025.03.09) Fixed an issue where `Bar` displayed abnormally when placed in different `Grids` within the same `Chart`
@@ -111,7 +165,7 @@ slug: /changelog
## v3.13.0 ## v3.13.0
Key Features: Version Highlights:
* Added the `UIText` extension component * Added the `UIText` extension component
* Added the `UIToggle` extension component * Added the `UIToggle` extension component
@@ -121,7 +175,7 @@ Key Features:
* Added the `size2` parameter to `SymbolStyle` to support rectangular markers * Added the `size2` parameter to `SymbolStyle` to support rectangular markers
* Other optimizations and bug fixes * Other optimizations and bug fixes
Detailed Changelog: Changelog Details:
* (2025.01.01) Released `v3.13.0` * (2025.01.01) Released `v3.13.0`
* (2024.12.27) Added the `size2` parameter to `SymbolStyle` to support rectangular markers * (2024.12.27) Added the `size2` parameter to `SymbolStyle` to support rectangular markers
@@ -168,7 +222,7 @@ Version Highlights:
* Adjusted and perfected the documentation * Adjusted and perfected the documentation
* Other optimizations and fixes * Other optimizations and fixes
Log Details: Changelog Details:
* (2024.09.30) Released version `v3.12.0` * (2024.09.30) Released version `v3.12.0`
* (2024.09.27) Improved the `5-minute tutorial` * (2024.09.27) Improved the `5-minute tutorial`
@@ -201,7 +255,7 @@ Log Details:
## v3.11.0 ## v3.11.0
Release Highlights: Version Highlights:
* Added `Line3DChart` for 3D line charts * Added `Line3DChart` for 3D line charts
* Added `GraphChart` for relationship graphs * Added `GraphChart` for relationship graphs

View File

@@ -176,6 +176,7 @@ slug: /configuration
- [AnimationAddition](#animationaddition) - [AnimationAddition](#animationaddition)
- [AnimationChange](#animationchange) - [AnimationChange](#animationchange)
- [AnimationExchange](#animationexchange)
- [AnimationFadeIn](#animationfadein) - [AnimationFadeIn](#animationfadein)
- [AnimationFadeOut](#animationfadeout) - [AnimationFadeOut](#animationfadeout)
- [AnimationHiding](#animationhiding) - [AnimationHiding](#animationhiding)
@@ -234,6 +235,14 @@ class in XCharts.Runtime / Inherits from: [AnimationInfo](#animationinfo)
Data change animation. Data change animation.
## AnimationExchange
class in XCharts.Runtime / Inherits from: [AnimationInfo](#animationinfo)
> Since `v3.15.0`
Data exchange animation. Generally used for animation of data sorting.
## AnimationFadeIn ## AnimationFadeIn
class in XCharts.Runtime / Inherits from: [AnimationInfo](#animationinfo) class in XCharts.Runtime / Inherits from: [AnimationInfo](#animationinfo)
@@ -260,7 +269,7 @@ Data hiding animation.
## AnimationInfo ## AnimationInfo
class in XCharts.Runtime / Subclasses: [AnimationFadeIn](#animationfadein), [AnimationFadeOut](#animationfadeout), [AnimationChange](#animationchange), [AnimationAddition](#animationaddition), [AnimationHiding](#animationhiding), [AnimationInteraction](#animationinteraction) class in XCharts.Runtime / Subclasses: [AnimationFadeIn](#animationfadein), [AnimationFadeOut](#animationfadeout), [AnimationChange](#animationchange), [AnimationAddition](#animationaddition), [AnimationHiding](#animationhiding), [AnimationInteraction](#animationinteraction), [AnimationExchange](#animationexchange)
> Since `v3.8.0` > Since `v3.8.0`
@@ -326,7 +335,7 @@ the mlvalue of width.
class in XCharts.Runtime / Inherits from: [ChildComponent](#childcomponent) class in XCharts.Runtime / Inherits from: [ChildComponent](#childcomponent)
the animation of serie. support animation type: fadeIn, fadeOut, change, addition. the animation of serie. support animation type: fadeIn, fadeOut, change, addition, exchange.
### AnimationStyle.addition ### AnimationStyle.addition
@@ -356,6 +365,12 @@ Options:
Whether to enable animation. Whether to enable animation.
### AnimationStyle.exchange
[AnimationExchange](#animationexchange) `v3.15.0`
Exchange animation configuration. Valid in sort bar chart.
### AnimationStyle.fadeIn ### AnimationStyle.fadeIn
[AnimationFadeIn](#animationfadein) `v3.8.0` [AnimationFadeIn](#animationfadein) `v3.8.0`
@@ -603,6 +618,12 @@ Base of logarithm, which is valid only for numeric axes with type: 'Log'.
On the log axis, if base e is the natural number, and is true, logBase fails. On the log axis, if base e is the natural number, and is true, logBase fails.
### Axis.mainAxis
`bool` `false` `v3.15.0`
Whether it is the main axis. When both X and Y axes are of the same type, the axis set to main axis will determine the orientation, such as horizontal bar chart and vertical bar chart.
### Axis.max ### Axis.max
`double` `double`
@@ -789,6 +810,12 @@ Whether to display the last label.
Whether to display the first label. Whether to display the first label.
### AxisLabel.showZeroLabel
`bool` `true` `v3.15.0`
Whether to display the zero label.
### AxisLabel.textLimit ### AxisLabel.textLimit
[TextLimit](#textlimit) [TextLimit](#textlimit)
@@ -807,6 +834,12 @@ Settings related to axis line.
the arrow of line. the arrow of line.
### AxisLine.endExtendLength
`float`
Extend length of the axis line at the end.
### AxisLine.onZero ### AxisLine.onZero
`bool` `bool`
@@ -819,6 +852,12 @@ When mutiple axes exists, this option can be used to specify which axis can be "
Whether to show the arrow symbol of axis. Whether to show the arrow symbol of axis.
### AxisLine.startExtendLength
`float`
Extend length of the axis line at the start.
## AxisMinorSplitLine ## AxisMinorSplitLine
class in XCharts.Runtime / Inherits from: [BaseLine](#baseline) class in XCharts.Runtime / Inherits from: [BaseLine](#baseline)
@@ -1247,7 +1286,9 @@ class in XCharts.Runtime / Subclasses: [AnimationStyle](#animationstyle), [AxisA
class in XCharts.Runtime / Inherits from: [MainComponent](#maincomponent), [IPropertyChanged](#ipropertychanged) class in XCharts.Runtime / Inherits from: [MainComponent](#maincomponent), [IPropertyChanged](#ipropertychanged)
comment of chart. > Since `v3.15.0`
comment of chart. Used to annotate special information in the chart.
### Comment.items ### Comment.items
@@ -1261,6 +1302,17 @@ The items of comment.
The text style of all comments. The text style of all comments.
### Comment.layer
[CommentLayer](#commentlayer) `v3.15.0`
The layer of comment.
Options:
- `Lower`: The comment is display under the serie.
- `Upper`: The comment is display above the serie.
### Comment.markStyle ### Comment.markStyle
[CommentMarkStyle](#commentmarkstyle) [CommentMarkStyle](#commentmarkstyle)
@@ -1470,11 +1522,11 @@ Distance between dataZoom component and the left side of the container. left val
选取框样式。 选取框样式。
### DataZoom.minShowNum ### DataZoom.minZoomRatio
`int` `2` `float` `0.2f`
Minimum number of display data. Minimum number of data displayed when DataZoom is enlarged to maximum. The minimum zoom ratio of dataZoom. Range 0f-1f.
### DataZoom.orient ### DataZoom.orient
@@ -2238,6 +2290,12 @@ class in XCharts.Runtime / Inherits from: [ChildComponent](#childcomponent), [IS
数据项背景颜色。 数据项背景颜色。
### ItemStyle.backgroundGap
`float` `v3.15.0`
the gap between background and data item.
### ItemStyle.backgroundWidth ### ItemStyle.backgroundWidth
`float` `float`
@@ -2464,6 +2522,18 @@ the sytle of background.
the distance of label to axis line. the distance of label to axis line.
### LabelStyle.fixedX
`float` `0` `v3.15.0`
the fixed x of label. When not 0, it will be fixed on the specified x value.
### LabelStyle.fixedY
`float` `0` `v3.15.0`
the fixed y of label. When not 0, it will be fixed on the specified y value.
### LabelStyle.formatter ### LabelStyle.formatter
`string` `string`
@@ -2615,6 +2685,12 @@ The distance between each legend, horizontal distance in horizontal layout, and
Image height of legend symbol. Image height of legend symbol.
### Legend.itemInactiveOpacity
`float` `1` `v3.15.0`
the opacity of item color when item is inactive.
### Legend.itemOpacity ### Legend.itemOpacity
`float` `1` `float` `1`
@@ -2690,11 +2766,11 @@ the limit of text.
class in XCharts.Runtime / Inherits from: [ComponentTheme](#componenttheme) class in XCharts.Runtime / Inherits from: [ComponentTheme](#componenttheme)
### LegendTheme.unableColor ### LegendTheme.inactiveColor
`Color` `Color`
the color of text. the color when the component is inactive.
## Level ## Level
@@ -3110,11 +3186,11 @@ Special label types, are used to label maximum value, minimum value and so on.
Options: Options:
- `None`: 标线类型 - `Custom`: Custom. You can customize the xy coordinates or values.
- `Min`: 最小值。 - `Min`: Minimum value.
- `Max`: 最大值。 - `Max`: Maximum value.
- `Average`: 平均值。 - `Average`: Average value.
- `Median`: 中位数。 - `Median`: Median.
### MarkLineData.xPosition ### MarkLineData.xPosition
@@ -3303,6 +3379,17 @@ Distance between grid component and the top side of the container.
class in XCharts.Runtime / Inherits from: [Serie](#serie) class in XCharts.Runtime / Inherits from: [Serie](#serie)
### Pie.pieType
[PieType](#pietype) `v3.15.0`
Pie chart type.
Options:
- `Solid`: solid pie chart - default fill style.
- `Wireframe`: wireframe pie chart - only show the outline wireframe.
### Pie.radiusGradient ### Pie.radiusGradient
`bool` `false` `v3.8.1` `bool` `false` `v3.8.1`
@@ -3471,13 +3558,13 @@ The width of the bar. Adaptive when default 0.
`float` `2f` `float` `2f`
斑马线的间距。 The gap of zebra bar. It is the distance between two zebra stripes. When the value is 0, there is no gap between stripes.
### Serie.barZebraWidth ### Serie.barZebraWidth
`float` `4f` `float` `4f`
斑马线的粗细。 The width of zebra bar. It is the width of each zebra stripe. When the value is 0, there is no zebra stripe.
### Serie.bottom ### Serie.bottom
@@ -3581,6 +3668,12 @@ Index of layout component that serie uses. Default is -1 means not use layout, o
忽略数据的默认值。当ignore为true才有效。 忽略数据的默认值。当ignore为true才有效。
### Serie.ignoreZeroOccupy
`bool` `false` `v3.15.0`
Whether to ignore the zero value bar occupy. When enabled, the bar with zero value will not occupy space, and the gap between bars will be automatically adjusted according to the actual displayed bars. Generally used in bar chart.
### Serie.index ### Serie.index
`int` `int`

View File

@@ -13,6 +13,7 @@ slug: /api
- [AnimationAddition](#animationaddition) - [AnimationAddition](#animationaddition)
- [AnimationChange](#animationchange) - [AnimationChange](#animationchange)
- [AnimationEasing](#animationeasing) - [AnimationEasing](#animationeasing)
- [AnimationExchange](#animationexchange)
- [AnimationFadeIn](#animationfadein) - [AnimationFadeIn](#animationfadein)
- [AnimationFadeOut](#animationfadeout) - [AnimationFadeOut](#animationfadeout)
- [AnimationHiding](#animationhiding) - [AnimationHiding](#animationhiding)
@@ -70,6 +71,7 @@ slug: /api
- [ColorUtil](#colorutil) - [ColorUtil](#colorutil)
- [Comment](#comment) - [Comment](#comment)
- [CommentItem](#commentitem) - [CommentItem](#commentitem)
- [CommentLayer](#commentlayer)
- [CommentMarkStyle](#commentmarkstyle) - [CommentMarkStyle](#commentmarkstyle)
- [ComponentHandlerAttribute](#componenthandlerattribute) - [ComponentHandlerAttribute](#componenthandlerattribute)
- [ComponentHelper](#componenthelper) - [ComponentHelper](#componenthelper)
@@ -157,6 +159,7 @@ slug: /api
- [MainComponentContext](#maincomponentcontext) - [MainComponentContext](#maincomponentcontext)
- [MainComponentHandler](#maincomponenthandler) - [MainComponentHandler](#maincomponenthandler)
- [MainComponentHandler<T>](#maincomponenthandlert) - [MainComponentHandler<T>](#maincomponenthandlert)
- [MainComponentHandler<Title>](#maincomponenthandlertitle)
- [MarkArea](#markarea) - [MarkArea](#markarea)
- [MarkAreaData](#markareadata) - [MarkAreaData](#markareadata)
- [MarkAreaType](#markareatype) - [MarkAreaType](#markareatype)
@@ -179,6 +182,7 @@ slug: /api
- [ParallelCoordContext](#parallelcoordcontext) - [ParallelCoordContext](#parallelcoordcontext)
- [Pie](#pie) - [Pie](#pie)
- [PieChart](#piechart) - [PieChart](#piechart)
- [PieType](#pietype)
- [PolarAxisTheme](#polaraxistheme) - [PolarAxisTheme](#polaraxistheme)
- [PolarChart](#polarchart) - [PolarChart](#polarchart)
- [PolarCoord](#polarcoord) - [PolarCoord](#polarcoord)
@@ -255,6 +259,7 @@ slug: /api
- [ThemeStyle](#themestyle) - [ThemeStyle](#themestyle)
- [ThemeType](#themetype) - [ThemeType](#themetype)
- [Title](#title) - [Title](#title)
- [TitleHandler](#titlehandler)
- [TitleStyle](#titlestyle) - [TitleStyle](#titlestyle)
- [TitleTheme](#titletheme) - [TitleTheme](#titletheme)
- [Tooltip](#tooltip) - [Tooltip](#tooltip)
@@ -360,6 +365,14 @@ class in XCharts.Runtime
- `Linear`: - `Linear`:
## AnimationExchange
class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
> 从 `v3.15.0` 开始支持
数据交换动画。一般用于图表数据排序时顺序变化的动画。
## AnimationFadeIn ## AnimationFadeIn
class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo) class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
@@ -386,7 +399,7 @@ class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
## AnimationInfo ## AnimationInfo
class in XCharts.Runtime / 子类: [AnimationFadeIn](#animationfadein),[AnimationFadeOut](#animationfadeout),[AnimationChange](#animationchange),[AnimationAddition](#animationaddition),[AnimationHiding](#animationhiding),[AnimationInteraction](#animationinteraction) class in XCharts.Runtime / 子类: [AnimationFadeIn](#animationfadein),[AnimationFadeOut](#animationfadeout),[AnimationChange](#animationchange),[AnimationAddition](#animationaddition),[AnimationHiding](#animationhiding),[AnimationInteraction](#animationinteraction),[AnimationExchange](#animationexchange)
> 从 `v3.8.0` 开始支持 > 从 `v3.8.0` 开始支持
@@ -531,7 +544,7 @@ public float GetWidth(float width)
class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent) class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent)
动画组件用于控制图表的动画播放。支持配置五种动画表现FadeIn渐入动画FadeOut渐出动画Change变更动画Addition新增动画Interaction交互动画。 按作用的对象可以分为两类SerieAnimation系列动画和DataAnimation数据动画 动画组件用于控制图表的动画播放。支持配置五种动画表现FadeIn渐入动画FadeOut渐出动画Change变更动画Addition新增动画Interaction交互动画Exchange交换动画。 按作用的对象可以分为两类SerieAnimation系列动画和DataAnimation数据动画
### AnimationStyle.addition ### AnimationStyle.addition
@@ -548,6 +561,11 @@ public AnimationChange change
public bool enable public bool enable
是否开启动画效果。 是否开启动画效果。
### AnimationStyle.exchange
public AnimationExchange exchange
交换动画配置。如在排序柱图中有效。
### AnimationStyle.fadeIn ### AnimationStyle.fadeIn
public AnimationFadeIn fadeIn public AnimationFadeIn fadeIn
@@ -639,6 +657,10 @@ public int GetCurrIndex()
public float GetCurrRate() public float GetCurrRate()
### AnimationStyle.GetExchangeDuration
public float GetExchangeDuration()
### AnimationStyle.GetInteractionDuration ### AnimationStyle.GetInteractionDuration
public float GetInteractionDuration() public float GetInteractionDuration()
@@ -789,6 +811,14 @@ class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent) / 子类:
直角坐标系的坐标轴组件。 直角坐标系的坐标轴组件。
### Axis.onLabelClick
public Action<int, string> onLabelClick
> 从 `v3.15.0` 开始支持
点击文本标签回调函数。参数labelIndex, labelName。
### Axis.AddData ### Axis.AddData
public void AddData(string category) public void AddData(string category)
@@ -888,7 +918,7 @@ public bool IsLog()
### Axis.IsNeedShowLabel ### Axis.IsNeedShowLabel
public bool IsNeedShowLabel(int index, int total = 0) public bool IsNeedShowLabel(int index, int total = 0, string content = null)
### Axis.IsRight ### Axis.IsRight
@@ -1059,6 +1089,14 @@ class in XCharts / 继承自: [MainComponentHandler](#maincomponenthandler)
public T component public T component
### AxisHandler<T>.DrawTop
// public override void DrawTop(VertexHelper vh)
### AxisHandler<T>.OnPointerClick
public override void OnPointerClick(PointerEventData eventData)
## AxisHelper ## AxisHelper
class in XCharts.Runtime class in XCharts.Runtime
@@ -1097,7 +1135,7 @@ public static float GetAxisValueDistance(GridCoord grid, Axis axis, float scaleW
### AxisHelper.GetAxisValueLength ### AxisHelper.GetAxisValueLength
public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value) public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value, float gap = 0)
获得数值value在坐标轴上对应的长度 获得数值value在坐标轴上对应的长度
### AxisHelper.GetAxisValuePosition ### AxisHelper.GetAxisValuePosition
@@ -1184,7 +1222,7 @@ public override string GetFormatterContent(int labelIndex, int totalIndex, doubl
### AxisLabel.IsNeedShowLabel ### AxisLabel.IsNeedShowLabel
public bool IsNeedShowLabel(int index, int total) public bool IsNeedShowLabel(int index, int total, string content = null)
### AxisLabel.SetRelatedText ### AxisLabel.SetRelatedText
@@ -1674,6 +1712,10 @@ public Settings settings
public ThemeStyle theme public ThemeStyle theme
### BaseChart.topPainter
public Painter topPainter
### BaseChart.typeListForComponent ### BaseChart.typeListForComponent
public Dictionary<Type, FieldInfo> typeListForComponent public Dictionary<Type, FieldInfo> typeListForComponent
@@ -1682,6 +1724,11 @@ public Dictionary<Type, FieldInfo> typeListForComponent
public Dictionary<Type, FieldInfo> typeListForSerie public Dictionary<Type, FieldInfo> typeListForSerie
### BaseChart.useUtc
public bool useUtc
图表的时间是否都显示为UTC时间。
### BaseChart.AddChartComponent ### BaseChart.AddChartComponent
public MainComponent AddChartComponent(Type type) public MainComponent AddChartComponent(Type type)
@@ -1938,6 +1985,10 @@ public Color32 GetLegendRealShowNameColor(string name)
public int GetLegendRealShowNameIndex(string name) public int GetLegendRealShowNameIndex(string name)
### BaseChart.GetMainAxis
public Axis GetMainAxis()
### BaseChart.GetMarkColor ### BaseChart.GetMarkColor
public Color32 GetMarkColor(Serie serie, SerieData serieData) public Color32 GetMarkColor(Serie serie, SerieData serieData)
@@ -1996,10 +2047,6 @@ public float GetSerieTotalGap<T>(float categoryWidth, float gap, int index
public float GetSerieTotalWidth<T>(float categoryWidth, float gap, int realBarCount, int gridIndex) where T : Serie public float GetSerieTotalWidth<T>(float categoryWidth, float gap, int realBarCount, int gridIndex) where T : Serie
### BaseChart.GetTitlePosition
public Vector3 GetTitlePosition(Title title)
### BaseChart.GetVisualMapOfSerie ### BaseChart.GetVisualMapOfSerie
public VisualMap GetVisualMapOfSerie(Serie serie) public VisualMap GetVisualMapOfSerie(Serie serie)
@@ -2519,6 +2566,10 @@ public string warningInfo
public string CheckWarning() public string CheckWarning()
检测警告信息。 检测警告信息。
### BaseGraph.GetTitlePosition
public Vector3 GetTitlePosition(Title title)
### BaseGraph.LocalPointToScreenPoint ### BaseGraph.LocalPointToScreenPoint
public Vector2 LocalPointToScreenPoint(Vector2 localPoint) public Vector2 LocalPointToScreenPoint(Vector2 localPoint)
@@ -2585,11 +2636,6 @@ public void RefreshAllComponent()
public virtual void RefreshGraph() public virtual void RefreshGraph()
在下一帧刷新图形。 在下一帧刷新图形。
### BaseGraph.SaveAsImage
public void SaveAsImage(string imageType = "png", string savePath = "")
保存图表为图片。
### BaseGraph.ScreenPointToChartPoint ### BaseGraph.ScreenPointToChartPoint
public bool ScreenPointToChartPoint(Vector2 screenPoint, out Vector2 chartPoint) public bool ScreenPointToChartPoint(Vector2 screenPoint, out Vector2 chartPoint)
@@ -2847,6 +2893,14 @@ public static string ColorToStr(Color color)
public static string FloatToStr(double value, string numericFormatter = "F", int precision = 0) public static string FloatToStr(double value, string numericFormatter = "F", int precision = 0)
### ChartCached.GetAxisLabelName
public static string GetAxisLabelName(int index)
### ChartCached.GetComponentObjectName
public static string GetComponentObjectName(MainComponent component)
### ChartCached.GetSerieLabelName ### ChartCached.GetSerieLabelName
public static string GetSerieLabelName(string prefix, int i, int j) public static string GetSerieLabelName(string prefix, int i, int j)
@@ -2855,17 +2909,25 @@ public static string GetSerieLabelName(string prefix, int i, int j)
public static string GetString(string prefix, int suffix) public static string GetString(string prefix, int suffix)
### ChartCached.GetTypeName
public static string GetTypeName(Type type)
### ChartCached.GetTypeName<T>
public static string GetTypeName<T>()
### ChartCached.IntToStr ### ChartCached.IntToStr
public static string IntToStr(int value, string numericFormatter = "") public static string IntToStr(int value, string numericFormatter = "")
### ChartCached.NumberToDateStr ### ChartCached.NumberToDateStr
public static string NumberToDateStr(double timestamp, string formatter) public static string NumberToDateStr(double timestamp, string formatter, bool local = false)
### ChartCached.NumberToDateTime ### ChartCached.NumberToDateTime
public static DateTime NumberToDateTime(double timestamp) public static DateTime NumberToDateTime(double timestamp, bool local = false)
### ChartCached.NumberToStr ### ChartCached.NumberToStr
@@ -3111,10 +3173,6 @@ public static void RemoveTMPComponents(GameObject gameObject)
public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle) public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
### ChartHelper.SaveAsImage
public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png", string path = "")
### ChartHelper.SetActive ### ChartHelper.SetActive
public static bool SetActive(Image image, bool active) public static bool SetActive(Image image, bool active)
@@ -3174,6 +3232,10 @@ public float GetTextWidth()
public float GetWidth() public float GetWidth()
### ChartLabel.InRect
public bool InRect(Vector2 local)
### ChartLabel.IsActiveByScale ### ChartLabel.IsActiveByScale
public bool IsActiveByScale() public bool IsActiveByScale()
@@ -3428,13 +3490,20 @@ public static Color32 GetColor(string hexColorStr)
class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent),[IPropertyChanged](#ipropertychanged) class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent),[IPropertyChanged](#ipropertychanged)
图表注解组件。 > 从 `v3.15.0` 开始支持
图表注解组件。用于标注图表中的特殊信息。
### Comment.items ### Comment.items
public List<CommentItem> items public List<CommentItem> items
注解项。每个注解组件可以设置多个注解项。 注解项。每个注解组件可以设置多个注解项。
### Comment.layer
public CommentLayer layer
注解的显示层级。
### Comment.show ### Comment.show
public bool show public bool show
@@ -3443,10 +3512,12 @@ public bool show
### Comment.GetLabelStyle ### Comment.GetLabelStyle
public LabelStyle GetLabelStyle(int index) public LabelStyle GetLabelStyle(int index)
获取注解项的文本样式。
### Comment.GetMarkStyle ### Comment.GetMarkStyle
public CommentMarkStyle GetMarkStyle(int index) public CommentMarkStyle GetMarkStyle(int index)
获取注解项的标记样式。
### Comment.OnChanged ### Comment.OnChanged
@@ -3478,6 +3549,17 @@ public CommentMarkStyle markStyle
public bool show public bool show
是否显示当前注解项。 是否显示当前注解项。
## CommentLayer
class in XCharts.Runtime
注解的显示层级。
可选:
- `Lower`: 注解在系列下方。
- `Upper`: 注解在系列上方。
## CommentMarkStyle ## CommentMarkStyle
class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent) class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent)
@@ -3763,17 +3845,17 @@ class in XCharts.Runtime
### DateTimeUtil.GetDateTime ### DateTimeUtil.GetDateTime
public static DateTime GetDateTime(double timestamp, bool local = true) public static DateTime GetDateTime(double timestamp, bool local = false)
### DateTimeUtil.GetDefaultDateTimeString ### DateTimeUtil.GetDefaultDateTimeString
public static string GetDefaultDateTimeString(int timestamp, double range = 0) public static string GetDefaultDateTimeString(double timestamp, double range = 0, bool local = false)
### DateTimeUtil.GetTimestamp ### DateTimeUtil.GetTimestamp
public static int GetTimestamp(DateTime time, bool local = false) public static double GetTimestamp(DateTime time, bool local = false)
public static int GetTimestamp(string dateTime, bool local = false) public static double GetTimestamp(string dateTime, bool local = false)
### DateTimeUtil.IsDateOrTimeRegex ### DateTimeUtil.IsDateOrTimeRegex
@@ -4683,7 +4765,7 @@ public virtual string GetFormatterContent(int labelIndex, int totalIndex, double
### LabelStyle.GetFormatterDateTime ### LabelStyle.GetFormatterDateTime
public string GetFormatterDateTime(int labelIndex, int totalIndex, double value, double minValue, double maxValue) public string GetFormatterDateTime(int labelIndex, int totalIndex, double value, double minValue, double maxValue, bool local)
### LabelStyle.GetOffset ### LabelStyle.GetOffset
@@ -5687,6 +5769,10 @@ class in XCharts.Runtime / 继承自: [MainComponentHandler](#maincomponenthandl
public T component public T component
## MainComponentHandler<Title>
class in / 子类: [TitleHandler](#titlehandler)
## MarkArea ## MarkArea
class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent) class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent)
@@ -5785,7 +5871,7 @@ class in XCharts.Runtime
可选: 可选:
- `None`: 标线类型 - `Custom`: 自定义。可自定义xy坐标或数值。
- `Min`: 最小值。 - `Min`: 最小值。
- `Max`: 最大值。 - `Max`: 最大值。
- `Average`: 平均值。 - `Average`: 平均值。
@@ -5982,10 +6068,6 @@ class in XCharts.Runtime / 继承自: [MaskableGraphic](https://docs.unity3d.com
public int index public int index
### Painter.onPopulateMesh
public Action<VertexHelper, Painter> onPopulateMesh
### Painter.type ### Painter.type
public Type type public Type type
@@ -6120,6 +6202,15 @@ public void DefaultLabelPieChart()
public void DefaultRadiusRosePieChart() public void DefaultRadiusRosePieChart()
默认玫瑰饼图。 默认玫瑰饼图。
## PieType
class in XCharts.Runtime
可选:
- `Solid`: 实心饼图 - 默认填充样式
- `Wireframe`: 线框饼图 - 仅显示轮廓线框
## PolarAxisTheme ## PolarAxisTheme
class in XCharts.Runtime / 继承自: [BaseAxisTheme](#baseaxistheme) class in XCharts.Runtime / 继承自: [BaseAxisTheme](#baseaxistheme)
@@ -7141,12 +7232,12 @@ public double GetLastData()
### SerieData.GetMaxData ### SerieData.GetMaxData
public double GetMaxData(bool inverse = false) public double GetMaxData(bool inverse = false, int startDimensionIndex = 0)
最大值。 最大值。
### SerieData.GetMinData ### SerieData.GetMinData
public double GetMinData(bool inverse = false) public double GetMinData(bool inverse = false, int startDimensionIndex = 0)
最小值。 最小值。
### SerieData.GetMinMaxData ### SerieData.GetMinMaxData
@@ -7257,6 +7348,10 @@ class in XCharts.Runtime
public void Reset() public void Reset()
### SerieDataContext.UpdateExchangePosition
public void UpdateExchangePosition(ref float x, ref float y, float totalTime)
## SerieDataExtraFieldAttribute ## SerieDataExtraFieldAttribute
class in XCharts.Runtime / 继承自: [Attribute](https://docs.unity3d.com/ScriptReference/30_search.html?q=attribute) class in XCharts.Runtime / 继承自: [Attribute](https://docs.unity3d.com/ScriptReference/30_search.html?q=attribute)
@@ -7685,6 +7780,10 @@ public override void RefreshLabelInternal()
public override void RefreshLabelNextFrame() public override void RefreshLabelNextFrame()
### SerieHandler<T>.RefreshTitleLabelInternal
public void RefreshTitleLabelInternal()
### SerieHandler<T>.RemoveComponent ### SerieHandler<T>.RemoveComponent
public override void RemoveComponent() public override void RemoveComponent()
@@ -8605,6 +8704,30 @@ public override void ClearComponentDirty()
public void OnChanged() public void OnChanged()
## TitleHandler
class in XCharts.Runtime / 继承自: [MainComponentHandler<Title>](#maincomponenthandlertitle)
### TitleHandler.AddSubTitleLabel
public static ChartLabel AddSubTitleLabel(Transform parent, Title title, ComponentTheme componentTheme, BaseChart chart = null)
### TitleHandler.AddTitleLabel
public static ChartLabel AddTitleLabel(Transform parent, Title title, ComponentTheme componentTheme, BaseChart chart = null)
### TitleHandler.AddTitleObject
public static GameObject AddTitleObject(BaseGraph graph, Title title, ComponentTheme componentTheme, int titleSiblingIndex, string objectName = null)
### TitleHandler.InitComponent
public override void InitComponent()
### TitleHandler.OnSerieDataUpdate
public override void OnSerieDataUpdate(int serieIndex)
## TitleStyle ## TitleStyle
class in XCharts.Runtime / 继承自: [LabelStyle](#labelstyle),[ISerieDataComponent](#iseriedatacomponent),[ISerieComponent](#iseriecomponent) class in XCharts.Runtime / 继承自: [LabelStyle](#labelstyle),[ISerieDataComponent](#iseriedatacomponent),[ISerieComponent](#iseriecomponent)

View File

@@ -6,6 +6,7 @@ slug: /changelog
# 更新日志 # 更新日志
[master](#master) [master](#master)
[v3.15.0](#v3150)
[v3.14.0](#v3140) [v3.14.0](#v3140)
[v3.13.0](#v3130) [v3.13.0](#v3130)
[v3.12.1](#v3121) [v3.12.1](#v3121)
@@ -80,6 +81,59 @@ slug: /changelog
## master ## master
## v3.15.0
版本要点:
* __时间轴与缩放能力增强__新增 `DataZoom.minZoomRatio`(替代 `minShowNum`)、`Chart.useUtc`,并持续优化 `Axis Time` 在缩放与大年份场景下的表现。
* __柱图与坐标轴配置更灵活__新增 `Axis.mainAxis` 控制柱图朝向、`Serie.ignoreZeroOccupy` 控制 0 值柱是否占位、`AxisLine` 延长线配置等。
* __图表样式与交互能力提升__新增 `Pie.pieType``Legend.itemInactiveOpacity``Axis.onLabelClick``Animation.Exchange``LabelStyle.fixedX/fixedY` 等。
* __扩展 UI 组件持续完善__`UITable` 新增 `Title``Viewport` 配置,`UIStatistic.desc` 增强,`Comment.layer` 与坐标刷新体验优化。
* __稳定性与兼容性修复集中推进__修复 `SaveAsImage` 遮挡保存、`Pie` 点击失效、`TMP` 兼容、`Gantt` 时间区间与 2038 年问题、`MarkArea/GridCoord/Axis` 等多项关键问题。
日志详情:
* (2026.03.01) 发布`v3.15.0`版本
* (2026.02.26) 增加`Serie``ignoreZeroOccupy`可设置0数据的Bar是否占位 (#286)
* (2026.02.26) 修复`SaveAsImage`被其他组件遮挡时无法正常保存的问题 (#337)
* (2026.02.26) 增加`Axis``mainAxis`参数设置主轴可控制柱图的朝向 (#331)
* (2026.02.03) 修复`UITable``viewport`在不同的锚点下可能会绘制异常的问题
* (2026.01.15) 修复`Pie`的点击有时候不响应的问题 (#357)
* (2026.01.08) 增加`DataZoom``minZoomRatio`替换旧的`minShowNum` (#350)
* (2025.11.05) 修复`Axis``indicatorLabel`无法隐藏的问题
* (2025.11.03) 增加`Tooltip``Title`可通过`TitleLabelStyle``numericFormatter`格式化时间显示 (#353)
* (2025.10.30) 增加`Chart``useUtc`参数设置显示时间是否用UTC时间
* (2025.10.30) 优化`Candlestick`对时间轴的支持
* (2025.10.30) 增加`Scatter``ignore`支持设置忽略数据
* (2025.10.24) 优化`Sankey`的线条绘制排序
* (2025.10.22) 增加`Pie``pieType`支持实心饼图和线框柄图 (#349)
* (2025.09.05) 优化`MarkLine`的表现
* (2025.09.01) 增加`AxisLine``startExtendLength``endExtendLength`设置轴线的延长线
* (2025.08.27) 修复`Serie``TitleStyle`在数据变更时不及时刷新的问题
* (2025.05.19) 修复`TMP`开启时`Axis`运行报错
* (2025.04.25) 修复`MarkArea`指定`yValue``xValue`时绘制区域不准确的问题
* (2025.04.17) 增加`UITable``Title`支持设置标题
* (2025.04.17) 增加`UITable``Viewport`支持设置表格视口边距边框
* (2025.04.15) 增加`Bar`支持通过`VisualMap`设置颜色
* (2025.04.14) 增加`AxisLabel``showZeroLabel`设置是否显示0刻度
* (2025.04.08) 增加`UIStatistic``desc`描述文本设置支持
* (2025.04.07) 修复`Gantt`甘特图在有多维数据时计算的时间区间不准确的问题
* (2025.04.07) 优化`Axis``Time`时间轴支持设置Custom和ceilRate
* (2025.04.07) 修复`GridCoord`在设置背景色且Serie开启Clip时会覆盖图表的问题
* (2025.04.07) 修复`Gantt`甘特图年份大于2038时显示异常的问题
* (2025.04.07) 修复`Axis``Time`时间轴无法显示大于2038的年份的问题
* (2025.04.06) 修复`Axis``Time`时间轴在有`DataZoom`缩放时文本显示异常的问题
* (2025.03.28) 修复`Pie3D``avoidLabelOverlap`不生效的问题
* (2025.03.27) 增加`Legend``itemInactiveOpacity`可设置非激活状态时的颜色透明度 (#343)
* (2025.03.27) 增加`Axis``onLabelClick`回调事件
* (2025.03.26) 增加`Animation``Exchange`排序交换动画
* (2025.03.22) 增加`Comment``layer`设置层级
* (2025.03.21) 优化`Comment`的坐标刷新
* (2025.03.19) 增加`Serie``Label``formatter`支持`{index}`通配符
* (2025.03.18) 增加`Bar`可添加`TitleStyle`组件支持
* (2025.03.18) 增加`LabelStyle``fixedX``fixedY`可固定label的坐标
* (2025.03.17) 增加`ItemStyle``backgroundGap`可设置数据项背景间隙
## v3.14.0 ## v3.14.0
版本要点: 版本要点:

View File

@@ -176,6 +176,7 @@ slug: /configuration
- [AnimationAddition](#animationaddition) - [AnimationAddition](#animationaddition)
- [AnimationChange](#animationchange) - [AnimationChange](#animationchange)
- [AnimationExchange](#animationexchange)
- [AnimationFadeIn](#animationfadein) - [AnimationFadeIn](#animationfadein)
- [AnimationFadeOut](#animationfadeout) - [AnimationFadeOut](#animationfadeout)
- [AnimationHiding](#animationhiding) - [AnimationHiding](#animationhiding)
@@ -234,6 +235,14 @@ class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
数据变更动画。 数据变更动画。
## AnimationExchange
class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
> 从 `v3.15.0` 开始支持
数据交换动画。一般用于图表数据排序时顺序变化的动画。
## AnimationFadeIn ## AnimationFadeIn
class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo) class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
@@ -260,7 +269,7 @@ class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
## AnimationInfo ## AnimationInfo
class in XCharts.Runtime / 子类: [AnimationFadeIn](#animationfadein), [AnimationFadeOut](#animationfadeout), [AnimationChange](#animationchange), [AnimationAddition](#animationaddition), [AnimationHiding](#animationhiding), [AnimationInteraction](#animationinteraction) class in XCharts.Runtime / 子类: [AnimationFadeIn](#animationfadein), [AnimationFadeOut](#animationfadeout), [AnimationChange](#animationchange), [AnimationAddition](#animationaddition), [AnimationHiding](#animationhiding), [AnimationInteraction](#animationinteraction), [AnimationExchange](#animationexchange)
> 从 `v3.8.0` 开始支持 > 从 `v3.8.0` 开始支持
@@ -326,7 +335,7 @@ class in XCharts.Runtime / 继承自: [AnimationInfo](#animationinfo)
class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent) class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent)
动画组件用于控制图表的动画播放。支持配置五种动画表现FadeIn渐入动画FadeOut渐出动画Change变更动画Addition新增动画Interaction交互动画。 按作用的对象可以分为两类SerieAnimation系列动画和DataAnimation数据动画 动画组件用于控制图表的动画播放。支持配置五种动画表现FadeIn渐入动画FadeOut渐出动画Change变更动画Addition新增动画Interaction交互动画Exchange交换动画。 按作用的对象可以分为两类SerieAnimation系列动画和DataAnimation数据动画
### AnimationStyle.addition ### AnimationStyle.addition
@@ -356,6 +365,12 @@ class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent)
是否开启动画效果。 是否开启动画效果。
### AnimationStyle.exchange
[AnimationExchange](#animationexchange) `v3.15.0`
交换动画配置。如在排序柱图中有效。
### AnimationStyle.fadeIn ### AnimationStyle.fadeIn
[AnimationFadeIn](#animationfadein) `v3.8.0` [AnimationFadeIn](#animationfadein) `v3.8.0`
@@ -603,6 +618,12 @@ class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent) / 子类:
对数轴是否以自然数 e 为底数,为 true 时 logBase 失效。 对数轴是否以自然数 e 为底数,为 true 时 logBase 失效。
### Axis.mainAxis
`bool` `false` `v3.15.0`
是否为主轴。当XY轴类型都相同时设置为主轴的轴会决定朝向如横向柱图和纵向柱图。
### Axis.max ### Axis.max
`double` `double`
@@ -789,6 +810,12 @@ class in XCharts.Runtime / 继承自: [LabelStyle](#labelstyle)
是否显示第一个文本。 是否显示第一个文本。
### AxisLabel.showZeroLabel
`bool` `true` `v3.15.0`
是否显示0刻度文本。
### AxisLabel.textLimit ### AxisLabel.textLimit
[TextLimit](#textlimit) [TextLimit](#textlimit)
@@ -807,6 +834,12 @@ class in XCharts.Runtime / 继承自: [BaseLine](#baseline)
轴线箭头。 轴线箭头。
### AxisLine.endExtendLength
`float`
轴线终点延长线长度。
### AxisLine.onZero ### AxisLine.onZero
`bool` `bool`
@@ -819,6 +852,12 @@ X 轴或者 Y 轴的轴线是否在另一个轴的 0 刻度上,只有在另一
是否显示箭头。 是否显示箭头。
### AxisLine.startExtendLength
`float`
轴线起点延长线长度。
## AxisMinorSplitLine ## AxisMinorSplitLine
class in XCharts.Runtime / 继承自: [BaseLine](#baseline) class in XCharts.Runtime / 继承自: [BaseLine](#baseline)
@@ -1247,7 +1286,9 @@ class in XCharts.Runtime / 子类: [AnimationStyle](#animationstyle), [AxisAnima
class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent), [IPropertyChanged](#ipropertychanged) class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent), [IPropertyChanged](#ipropertychanged)
图表注解组件。 > 从 `v3.15.0` 开始支持
图表注解组件。用于标注图表中的特殊信息。
### Comment.items ### Comment.items
@@ -1261,6 +1302,17 @@ class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent), [IPropert
所有组件的文本样式。 所有组件的文本样式。
### Comment.layer
[CommentLayer](#commentlayer) `v3.15.0`
注解的显示层级。
可选:
- `Lower`: 注解在系列下方。
- `Upper`: 注解在系列上方。
### Comment.markStyle ### Comment.markStyle
[CommentMarkStyle](#commentmarkstyle) [CommentMarkStyle](#commentmarkstyle)
@@ -1470,11 +1522,11 @@ DataZoom 组件 用于区域缩放,从而能自由关注细节的数据信息
选取框样式。 选取框样式。
### DataZoom.minShowNum ### DataZoom.minZoomRatio
`int` `2` `float` `0.2f`
最小显示数据个数。当DataZoom放大到最大时最小显示的数据个数 缩放区域组件的最小缩放比例范围0f-1f
### DataZoom.orient ### DataZoom.orient
@@ -2238,6 +2290,12 @@ class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent), [ISerie
数据项背景颜色。 数据项背景颜色。
### ItemStyle.backgroundGap
`float` `v3.15.0`
数据项背景间隙。
### ItemStyle.backgroundWidth ### ItemStyle.backgroundWidth
`float` `float`
@@ -2464,6 +2522,18 @@ class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent), [ISerie
距离轴线的距离。 距离轴线的距离。
### LabelStyle.fixedX
`float` `0` `v3.15.0`
固定的X值。不为0时会固定在指定的X值上。
### LabelStyle.fixedY
`float` `0` `v3.15.0`
固定的Y值。不为0时会固定在指定的Y值上。
### LabelStyle.formatter ### LabelStyle.formatter
`string` `string`
@@ -2615,6 +2685,12 @@ class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent), [IPropert
图例标记的图形高度。 图例标记的图形高度。
### Legend.itemInactiveOpacity
`float` `1` `v3.15.0`
图例标记的图形在非激活状态下的颜色透明度。
### Legend.itemOpacity ### Legend.itemOpacity
`float` `1` `float` `1`
@@ -2690,11 +2766,11 @@ class in XCharts.Runtime / 继承自: [MainComponent](#maincomponent), [IPropert
class in XCharts.Runtime / 继承自: [ComponentTheme](#componenttheme) class in XCharts.Runtime / 继承自: [ComponentTheme](#componenttheme)
### LegendTheme.unableColor ### LegendTheme.inactiveColor
`Color` `Color`
文本颜色。 非激活状态时的颜色。
## Level ## Level
@@ -3110,7 +3186,7 @@ class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent)
可选: 可选:
- `None`: 标线类型 - `Custom`: 自定义。可自定义xy坐标或数值。
- `Min`: 最小值。 - `Min`: 最小值。
- `Max`: 最大值。 - `Max`: 最大值。
- `Average`: 平均值。 - `Average`: 平均值。
@@ -3120,25 +3196,25 @@ class in XCharts.Runtime / 继承自: [ChildComponent](#childcomponent)
`float` `float`
相对原点的 x 坐标单位像素。当type为None时有效。 相对原点的 x 坐标单位像素。当type为Custom时有效。
### MarkLineData.xValue ### MarkLineData.xValue
`double` `double`
X轴上的指定值。当X轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为None时有效。 X轴上的指定值。当X轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为Custom时有效。
### MarkLineData.yPosition ### MarkLineData.yPosition
`float` `float`
相对原点的 y 坐标单位像素。当type为None时有效。 相对原点的 y 坐标单位像素。当type为Custom时有效。
### MarkLineData.yValue ### MarkLineData.yValue
`double` `double`
Y轴上的指定值。当Y轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为None时有效。 Y轴上的指定值。当Y轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为Custom时有效。
### MarkLineData.zeroPosition ### MarkLineData.zeroPosition
@@ -3303,6 +3379,17 @@ grid 组件离容器上侧的距离。
class in XCharts.Runtime / 继承自: [Serie](#serie) class in XCharts.Runtime / 继承自: [Serie](#serie)
### Pie.pieType
[PieType](#pietype) `v3.15.0`
饼图类型。
可选:
- `Solid`: 实心饼图 - 默认填充样式
- `Wireframe`: 线框饼图 - 仅显示轮廓线框
### Pie.radiusGradient ### Pie.radiusGradient
`bool` `false` `v3.8.1` `bool` `false` `v3.8.1`
@@ -3581,6 +3668,12 @@ class in XCharts.Runtime / 继承自: [BaseSerie](#baseserie), [IComparable](htt
忽略数据的默认值。当ignore为true才有效。 忽略数据的默认值。当ignore为true才有效。
### Serie.ignoreZeroOccupy
`bool` `false` `v3.15.0`
柱图是否忽略值为0的柱子占位。开启后值为0的柱子将不会占用空间柱子之间的间距会根据实际显示的柱子自动调整。一般用在柱状图中。
### Serie.index ### Serie.index
`int` `int`

View File

@@ -26,6 +26,7 @@ namespace XCharts.Editor
protected SerializedProperty m_Settings; protected SerializedProperty m_Settings;
protected SerializedProperty m_Theme; protected SerializedProperty m_Theme;
protected SerializedProperty m_ChartName; protected SerializedProperty m_ChartName;
protected SerializedProperty m_UseUtc;
protected SerializedProperty m_DebugInfo; protected SerializedProperty m_DebugInfo;
protected SerializedProperty m_RaycastTarget; protected SerializedProperty m_RaycastTarget;
@@ -49,6 +50,7 @@ namespace XCharts.Editor
m_Script = serializedObject.FindProperty("m_Script"); m_Script = serializedObject.FindProperty("m_Script");
m_EnableTextMeshPro = serializedObject.FindProperty("m_EnableTextMeshPro"); m_EnableTextMeshPro = serializedObject.FindProperty("m_EnableTextMeshPro");
m_ChartName = serializedObject.FindProperty("m_ChartName"); m_ChartName = serializedObject.FindProperty("m_ChartName");
m_UseUtc = serializedObject.FindProperty("m_UseUtc");
m_Theme = serializedObject.FindProperty("m_Theme"); m_Theme = serializedObject.FindProperty("m_Theme");
m_Settings = serializedObject.FindProperty("m_Settings"); m_Settings = serializedObject.FindProperty("m_Settings");
m_DebugInfo = serializedObject.FindProperty("m_DebugInfo"); m_DebugInfo = serializedObject.FindProperty("m_DebugInfo");
@@ -124,6 +126,7 @@ namespace XCharts.Editor
{ {
EditorGUILayout.PropertyField(m_Script); EditorGUILayout.PropertyField(m_Script);
EditorGUILayout.PropertyField(m_ChartName); EditorGUILayout.PropertyField(m_ChartName);
EditorGUILayout.PropertyField(m_UseUtc);
EditorGUILayout.PropertyField(m_RaycastTarget); EditorGUILayout.PropertyField(m_RaycastTarget);
if (XChartsMgr.IsRepeatChartName(m_Chart, m_ChartName.stringValue)) if (XChartsMgr.IsRepeatChartName(m_Chart, m_ChartName.stringValue))
{ {
@@ -282,7 +285,7 @@ namespace XCharts.Editor
} }
if (GUILayout.Button(Styles.btnSaveAsImage)) if (GUILayout.Button(Styles.btnSaveAsImage))
{ {
m_Chart.SaveAsImage(); m_Chart.SaveAsImage("png", "", 4f);
} }
if (m_CheckWarning) if (m_CheckWarning)
{ {

View File

@@ -71,6 +71,21 @@ namespace XCharts.Editor
} }
} }
[CustomPropertyDrawer(typeof(XCharts.Runtime.AnimationExchange), true)]
public class AnimationExchangeDrawer : BasePropertyDrawer
{
public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label)
{
base.OnGUI(pos, prop, label);
if (MakeComponentFoldout(prop, "m_Enable", true))
{
++EditorGUI.indentLevel;
PropertyField(prop, "m_Duration");
--EditorGUI.indentLevel;
}
}
}
[CustomPropertyDrawer(typeof(AnimationStyle), true)] [CustomPropertyDrawer(typeof(AnimationStyle), true)]
public class AnimationDrawer : BasePropertyDrawer public class AnimationDrawer : BasePropertyDrawer
{ {
@@ -88,6 +103,7 @@ namespace XCharts.Editor
PropertyField(prop, "m_Change"); PropertyField(prop, "m_Change");
PropertyField(prop, "m_Addition"); PropertyField(prop, "m_Addition");
PropertyField(prop, "m_Interaction"); PropertyField(prop, "m_Interaction");
PropertyField(prop, "m_Exchange");
--EditorGUI.indentLevel; --EditorGUI.indentLevel;
} }
} }

View File

@@ -102,7 +102,7 @@ namespace XCharts.Editor
protected override void DrawExtendeds(SerializedProperty prop) protected override void DrawExtendeds(SerializedProperty prop)
{ {
base.DrawExtendeds(prop); base.DrawExtendeds(prop);
PropertyField(prop, "m_UnableColor"); PropertyField(prop, "m_InactiveColor");
} }
} }

View File

@@ -21,6 +21,7 @@ namespace XCharts.Editor
PropertyField(prop, "m_MarkColor"); PropertyField(prop, "m_MarkColor");
PropertyField(prop, "m_BackgroundColor"); PropertyField(prop, "m_BackgroundColor");
PropertyField(prop, "m_BackgroundWidth"); PropertyField(prop, "m_BackgroundWidth");
PropertyField(prop, "m_BackgroundGap");
PropertyField(prop, "m_CenterColor"); PropertyField(prop, "m_CenterColor");
PropertyField(prop, "m_CenterGap"); PropertyField(prop, "m_CenterGap");
PropertyField(prop, "m_BorderWidth"); PropertyField(prop, "m_BorderWidth");

View File

@@ -24,6 +24,8 @@ namespace XCharts.Editor
PropertyField(prop, "m_Rotate"); PropertyField(prop, "m_Rotate");
PropertyField(prop, "m_Width"); PropertyField(prop, "m_Width");
PropertyField(prop, "m_Height"); PropertyField(prop, "m_Height");
PropertyField(prop, "m_FixedX");
PropertyField(prop, "m_FixedY");
PropertyField(prop, "m_Icon"); PropertyField(prop, "m_Icon");
PropertyField(prop, "m_Background"); PropertyField(prop, "m_Background");
PropertyField(prop, "m_TextStyle"); PropertyField(prop, "m_TextStyle");

View File

@@ -29,6 +29,8 @@ namespace XCharts.Editor
{ {
base.DrawExtendeds(prop); base.DrawExtendeds(prop);
PropertyField(prop, "m_OnZero"); PropertyField(prop, "m_OnZero");
PropertyField(prop, "m_StartExtendLength");
PropertyField(prop, "m_EndExtendLength");
PropertyField(prop, "m_ShowArrow"); PropertyField(prop, "m_ShowArrow");
PropertyField(prop, "m_Arrow"); PropertyField(prop, "m_Arrow");
} }

View File

@@ -102,10 +102,24 @@ namespace XCharts.Editor
} }
[ComponentEditor(typeof(XAxis))] [ComponentEditor(typeof(XAxis))]
public class XAxisEditor : AxisEditor { } public class XAxisEditor : AxisEditor
{
protected override void DrawExtendeds()
{
base.DrawExtendeds();
PropertyField("m_MainAxis");
}
}
[ComponentEditor(typeof(YAxis))] [ComponentEditor(typeof(YAxis))]
public class YAxisEditor : AxisEditor { } public class YAxisEditor : AxisEditor
{
protected override void DrawExtendeds()
{
base.DrawExtendeds();
PropertyField("m_MainAxis");
}
}
[ComponentEditor(typeof(XAxis3D))] [ComponentEditor(typeof(XAxis3D))]
public class XAxis3DEditor : AxisEditor { } public class XAxis3DEditor : AxisEditor { }
@@ -164,6 +178,7 @@ namespace XCharts.Editor
PropertyField(prop, "m_ShowAsPositiveNumber"); PropertyField(prop, "m_ShowAsPositiveNumber");
PropertyField(prop, "m_OnZero"); PropertyField(prop, "m_OnZero");
PropertyField(prop, "m_ShowZeroLabel");
PropertyField(prop, "m_ShowStartLabel"); PropertyField(prop, "m_ShowStartLabel");
PropertyField(prop, "m_ShowEndLabel"); PropertyField(prop, "m_ShowEndLabel");

View File

@@ -9,6 +9,7 @@ namespace XCharts.Editor
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
++EditorGUI.indentLevel; ++EditorGUI.indentLevel;
PropertyField("m_Layer");
PropertyField("m_LabelStyle"); PropertyField("m_LabelStyle");
//PropertyField("m_MarkStyle"); //PropertyField("m_MarkStyle");
PropertyListField("m_Items", true); PropertyListField("m_Items", true);

View File

@@ -13,7 +13,7 @@ namespace XCharts.Editor
var m_SupportMarquee = baseProperty.FindPropertyRelative("m_SupportMarquee"); var m_SupportMarquee = baseProperty.FindPropertyRelative("m_SupportMarquee");
var m_Start = baseProperty.FindPropertyRelative("m_Start"); var m_Start = baseProperty.FindPropertyRelative("m_Start");
var m_End = baseProperty.FindPropertyRelative("m_End"); var m_End = baseProperty.FindPropertyRelative("m_End");
var m_MinShowNum = baseProperty.FindPropertyRelative("m_MinShowNum"); var m_MinZoomRatio = baseProperty.FindPropertyRelative("m_MinZoomRatio");
++EditorGUI.indentLevel; ++EditorGUI.indentLevel;
PropertyField("m_Orient"); PropertyField("m_Orient");
PropertyField("m_SupportInside"); PropertyField("m_SupportInside");
@@ -31,10 +31,11 @@ namespace XCharts.Editor
PropertyField(m_End); PropertyField(m_End);
PropertyField("m_StartLock"); PropertyField("m_StartLock");
PropertyField("m_EndLock"); PropertyField("m_EndLock");
PropertyField(m_MinShowNum); PropertyField(m_MinZoomRatio);
if (m_Start.floatValue < 0) m_Start.floatValue = 0; if (m_Start.floatValue < 0) m_Start.floatValue = 0;
if (m_End.floatValue > 100) m_End.floatValue = 100; if (m_End.floatValue > 100) m_End.floatValue = 100;
if (m_MinShowNum.intValue < 0) m_MinShowNum.intValue = 0; if (m_MinZoomRatio.floatValue < 0) m_MinZoomRatio.floatValue = 0;
if (m_MinZoomRatio.floatValue > 1) m_MinZoomRatio.floatValue = 1;
if (m_SupportSlider.boolValue) if (m_SupportSlider.boolValue)
{ {
PropertyField("m_ShowDataShadow"); PropertyField("m_ShowDataShadow");

View File

@@ -15,6 +15,7 @@ namespace XCharts.Editor
PropertyField("m_ItemGap"); PropertyField("m_ItemGap");
PropertyField("m_ItemAutoColor"); PropertyField("m_ItemAutoColor");
PropertyField("m_ItemOpacity"); PropertyField("m_ItemOpacity");
PropertyField("m_ItemInactiveOpacity");
PropertyField("m_SelectedMode"); PropertyField("m_SelectedMode");
PropertyField("m_Orient"); PropertyField("m_Orient");
PropertyField("m_Location"); PropertyField("m_Location");

View File

@@ -34,7 +34,7 @@ namespace XCharts.Editor
PropertyField(prop, "m_Name"); PropertyField(prop, "m_Name");
switch (type) switch (type)
{ {
case MarkLineType.None: case MarkLineType.Custom:
PropertyField(prop, "m_XPosition"); PropertyField(prop, "m_XPosition");
PropertyField(prop, "m_YPosition"); PropertyField(prop, "m_YPosition");
PropertyField(prop, "m_XValue"); PropertyField(prop, "m_XValue");
@@ -48,7 +48,7 @@ namespace XCharts.Editor
break; break;
} }
PropertyField(prop, "m_Group"); PropertyField(prop, "m_Group");
if (group > 0 && type == MarkLineType.None) PropertyField(prop, "m_ZeroPosition"); if (group > 0 && type == MarkLineType.Custom) PropertyField(prop, "m_ZeroPosition");
PropertyField(prop, "m_LineStyle"); PropertyField(prop, "m_LineStyle");
PropertyField(prop, "m_StartSymbol"); PropertyField(prop, "m_StartSymbol");
PropertyField(prop, "m_EndSymbol"); PropertyField(prop, "m_EndSymbol");

View File

@@ -54,7 +54,7 @@ namespace XCharts.Editor
} }
if (GUILayout.Button(Styles.btnSaveAsImage)) if (GUILayout.Button(Styles.btnSaveAsImage))
{ {
m_UIComponent.SaveAsImage(); m_UIComponent.SaveAsImage("png", "", 4f);
} }
OnDebugEndInspectorGUI(); OnDebugEndInspectorGUI();
} }

View File

@@ -22,6 +22,7 @@ namespace XCharts.Editor
PropertyField("m_BarWidth"); PropertyField("m_BarWidth");
PropertyField("m_BarGap"); PropertyField("m_BarGap");
PropertyField("m_BarMaxWidth"); PropertyField("m_BarMaxWidth");
PropertyField("m_IgnoreZeroOccupy");
PropertyField("m_RealtimeSort"); PropertyField("m_RealtimeSort");
if(serie.useSortData) if(serie.useSortData)
{ {

View File

@@ -8,6 +8,7 @@ namespace XCharts.Editor
public override void OnCustomInspectorGUI() public override void OnCustomInspectorGUI()
{ {
PropertyField("m_GridIndex"); PropertyField("m_GridIndex");
PropertyField("m_PieType");
PropertyField("m_RoseType"); PropertyField("m_RoseType");
PropertyField("m_Gap"); PropertyField("m_Gap");
PropertyTwoFiled("m_Center"); PropertyTwoFiled("m_Center");

View File

@@ -18,6 +18,8 @@ namespace XCharts.Editor
} }
PropertyField("m_MaxCache"); PropertyField("m_MaxCache");
PropertyField("m_Clip"); PropertyField("m_Clip");
PropertyField("m_Ignore");
PropertyField("m_IgnoreValue");
PropertyField("m_Symbol"); PropertyField("m_Symbol");
PropertyField("m_ItemStyle"); PropertyField("m_ItemStyle");

View File

@@ -493,4 +493,14 @@ namespace XCharts.Runtime
return m_Offset.value; return m_Offset.value;
} }
} }
/// <summary>
/// Data exchange animation. Generally used for animation of data sorting.
/// ||数据交换动画。一般用于图表数据排序时顺序变化的动画。
/// </summary>
[Since("v3.15.0")]
[System.Serializable]
public class AnimationExchange : AnimationInfo
{
}
} }

View File

@@ -44,8 +44,8 @@ namespace XCharts.Runtime
} }
/// <summary> /// <summary>
/// the animation of serie. support animation type: fadeIn, fadeOut, change, addition. /// the animation of serie. support animation type: fadeIn, fadeOut, change, addition, exchange.
/// ||动画组件用于控制图表的动画播放。支持配置五种动画表现FadeIn渐入动画FadeOut渐出动画Change变更动画Addition新增动画Interaction交互动画 /// ||动画组件用于控制图表的动画播放。支持配置五种动画表现FadeIn渐入动画FadeOut渐出动画Change变更动画Addition新增动画Interaction交互动画Exchange交换动画
/// 按作用的对象可以分为两类SerieAnimation系列动画和DataAnimation数据动画 /// 按作用的对象可以分为两类SerieAnimation系列动画和DataAnimation数据动画
/// </summary> /// </summary>
[System.Serializable] [System.Serializable]
@@ -62,6 +62,7 @@ namespace XCharts.Runtime
[SerializeField][Since("v3.8.0")] private AnimationAddition m_Addition = new AnimationAddition() { duration = 500 }; [SerializeField][Since("v3.8.0")] private AnimationAddition m_Addition = new AnimationAddition() { duration = 500 };
[SerializeField][Since("v3.8.0")] private AnimationHiding m_Hiding = new AnimationHiding() { duration = 500 }; [SerializeField][Since("v3.8.0")] private AnimationHiding m_Hiding = new AnimationHiding() { duration = 500 };
[SerializeField][Since("v3.8.0")] private AnimationInteraction m_Interaction = new AnimationInteraction() { duration = 250 }; [SerializeField][Since("v3.8.0")] private AnimationInteraction m_Interaction = new AnimationInteraction() { duration = 250 };
[SerializeField][Since("v3.15.0")] private AnimationExchange m_Exchange = new AnimationExchange() { duration = 250 };
[Obsolete("Use animation.fadeIn.delayFunction instead.", true)] [Obsolete("Use animation.fadeIn.delayFunction instead.", true)]
public AnimationDelayFunction fadeInDelayFunction; public AnimationDelayFunction fadeInDelayFunction;
@@ -138,6 +139,11 @@ namespace XCharts.Runtime
/// ||交互动画配置。 /// ||交互动画配置。
/// </summary> /// </summary>
public AnimationInteraction interaction { get { return m_Interaction; } } public AnimationInteraction interaction { get { return m_Interaction; } }
/// <summary>
/// Exchange animation configuration. Valid in sort bar chart.
/// ||交换动画配置。如在排序柱图中有效。
/// </summary>
public AnimationExchange exchange { get { return m_Exchange; } }
private Vector3 m_LinePathLastPos; private Vector3 m_LinePathLastPos;
private List<AnimationInfo> m_Animations; private List<AnimationInfo> m_Animations;
@@ -147,12 +153,15 @@ namespace XCharts.Runtime
{ {
if (m_Animations == null) if (m_Animations == null)
{ {
m_Animations = new List<AnimationInfo>(); m_Animations = new List<AnimationInfo>
m_Animations.Add(m_FadeIn); {
m_Animations.Add(m_FadeOut); m_FadeIn,
m_Animations.Add(m_Change); m_FadeOut,
m_Animations.Add(m_Addition); m_Change,
m_Animations.Add(m_Hiding); m_Addition,
m_Hiding,
m_Exchange
};
} }
return m_Animations; return m_Animations;
} }
@@ -565,6 +574,14 @@ namespace XCharts.Runtime
return 0; return 0;
} }
public float GetExchangeDuration()
{
if (m_Enable && m_Exchange.enable)
return m_Exchange.context.currDuration > 0 ? m_Exchange.context.currDuration : m_Exchange.duration;
else
return 0;
}
public float GetAdditionDuration() public float GetAdditionDuration()
{ {
if (m_Enable && m_Addition.enable) if (m_Enable && m_Addition.enable)

View File

@@ -85,7 +85,7 @@ namespace XCharts.Runtime
float scaleAngle = AxisHelper.GetScaleWidth(axis, total, i + 1, null); float scaleAngle = AxisHelper.GetScaleWidth(axis, total, i + 1, null);
bool inside = axis.axisLabel.inside; bool inside = axis.axisLabel.inside;
var labelName = AxisHelper.GetLabelName(axis, total, i, axis.context.minValue, axis.context.maxValue, var labelName = AxisHelper.GetLabelName(axis, total, i, axis.context.minValue, axis.context.maxValue,
null, isPercentStack); null, isPercentStack, chart.useUtc);
var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform, var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform,
new Vector2(scaleAngle, txtHig), axis, new Vector2(scaleAngle, txtHig), axis,
chart.theme.axis, labelName, Color.clear); chart.theme.axis, labelName, Color.clear);

View File

@@ -100,6 +100,7 @@ namespace XCharts.Runtime
[SerializeField] private bool m_Clockwise = true; [SerializeField] private bool m_Clockwise = true;
[SerializeField] private bool m_InsertDataToHead; [SerializeField] private bool m_InsertDataToHead;
[SerializeField][Since("v3.11.0")] private float m_MinCategorySpacing = 0; [SerializeField][Since("v3.11.0")] private float m_MinCategorySpacing = 0;
[SerializeField][Since("v3.15.0")] private bool m_MainAxis = false;
[SerializeField] protected List<Sprite> m_Icons = new List<Sprite>(); [SerializeField] protected List<Sprite> m_Icons = new List<Sprite>();
[SerializeField] protected List<string> m_Data = new List<string>(); [SerializeField] protected List<string> m_Data = new List<string>();
[SerializeField] protected AxisLine m_AxisLine = AxisLine.defaultAxisLine; [SerializeField] protected AxisLine m_AxisLine = AxisLine.defaultAxisLine;
@@ -115,6 +116,13 @@ namespace XCharts.Runtime
public AxisContext context = new AxisContext(); public AxisContext context = new AxisContext();
private Action<int, string> m_OnLabelClick;
/// <summary>
/// Callback function when click on the label. Parameters: labelIndex, labelName.
/// ||点击文本标签回调函数。参数labelIndex, labelName。
/// </summary>
[Since("v3.15.0")]
public Action<int, string> onLabelClick { internal get { return m_OnLabelClick; } set { m_OnLabelClick = value; } }
/// <summary> /// <summary>
/// Whether to show axis. /// Whether to show axis.
/// ||是否显示坐标轴。 /// ||是否显示坐标轴。
@@ -292,6 +300,17 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_Clockwise, value)) SetAllDirty(); } set { if (PropertyUtil.SetStruct(ref m_Clockwise, value)) SetAllDirty(); }
} }
/// <summary> /// <summary>
/// Whether it is the main axis. When both X and Y axes are of the same type, the axis set to main axis will determine the orientation,
/// such as horizontal bar chart and vertical bar chart.
/// ||是否为主轴。当XY轴类型都相同时设置为主轴的轴会决定朝向如横向柱图和纵向柱图。
/// </summary>
[Since("v3.15.0")]
public bool mainAxis
{
get { return m_MainAxis; }
set { if (PropertyUtil.SetStruct(ref m_MainAxis, value)) SetAllDirty(); }
}
/// <summary>
/// Category data, available in type: 'Category' axis. /// Category data, available in type: 'Category' axis.
/// ||类目数据在类目轴type: 'category')中有效。 /// ||类目数据在类目轴type: 'category')中有效。
/// </summary> /// </summary>
@@ -478,6 +497,7 @@ namespace XCharts.Runtime
context.maxValue = 0; context.maxValue = 0;
context.destMinValue = 0; context.destMinValue = 0;
context.destMaxValue = 0; context.destMaxValue = 0;
context.labelValueList.Clear();
} }
public Axis Clone() public Axis Clone()
@@ -609,13 +629,13 @@ namespace XCharts.Runtime
return m_Position == AxisPosition.Bottom; return m_Position == AxisPosition.Bottom;
} }
public bool IsNeedShowLabel(int index, int total = 0) public bool IsNeedShowLabel(int index, int total = 0, string content = null)
{ {
if (total == 0) if (total == 0)
{ {
total = context.labelValueList.Count; total = context.labelValueList.Count;
} }
return axisLabel.IsNeedShowLabel(index, total); return axisLabel.IsNeedShowLabel(index, total, content);
} }
public void SetNeedUpdateFilterData() public void SetNeedUpdateFilterData()

View File

@@ -120,24 +120,25 @@ namespace XCharts.Runtime
if (end > data.Count) end = data.Count; if (end > data.Count) end = data.Count;
} }
var minZoomRatio = (int)(data.Count * dataZoom.minZoomRatio);
if (start != filterStart || if (start != filterStart ||
end != filterEnd || end != filterEnd ||
dataZoom.minShowNum != filterMinShow || minZoomRatio != filterMinShow ||
isNeedUpdateFilterData) isNeedUpdateFilterData)
{ {
filterStart = start; filterStart = start;
filterEnd = end; filterEnd = end;
filterMinShow = dataZoom.minShowNum; filterMinShow = minZoomRatio;
isNeedUpdateFilterData = false; isNeedUpdateFilterData = false;
if (data.Count > 0) if (data.Count > 0)
{ {
if (range < dataZoom.minShowNum) if (range < minZoomRatio)
{ {
if (dataZoom.minShowNum > data.Count) if (dataZoom.minZoomRatio > data.Count)
range = data.Count; range = data.Count;
else else
range = dataZoom.minShowNum; range = minZoomRatio;
} }
if (range > data.Count - start) if (range > data.Count - start)
start = data.Count - range; start = data.Count - range;

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using XCharts.Runtime; using XCharts.Runtime;
using XUGL; using XUGL;
@@ -32,6 +33,33 @@ namespace XCharts
protected virtual Orient orient { get; set; } protected virtual Orient orient { get; set; }
public override void OnPointerClick(PointerEventData eventData)
{
if (component.onLabelClick == null) return;
var labelObjects = component.context.labelObjectList;
for (int i = 0; i < labelObjects.Count; i++)
{
var label = labelObjects[i];
if (label == null) continue;
if (label.InRect(chart.pointerPos))
{
component.onLabelClick.Invoke(i, label.text.GetText());
break;
}
}
}
// public override void DrawTop(VertexHelper vh)
// {
// var color = Color.red;
// color.a = 0.5f;
// foreach (var label in component.context.labelObjectList)
// {
// if (label == null) continue;
// UGL.DrawRectangle(vh, label.rect, color);
// }
// }
protected virtual void UpdatePointerValue(Axis axis) protected virtual void UpdatePointerValue(Axis axis)
{ {
var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex); var grid = chart.GetChartComponent<GridCoord>(axis.gridIndex);
@@ -253,21 +281,40 @@ namespace XCharts
var serie = chart.GetSerie(0); var serie = chart.GetSerie(0);
if (isCategory && serie != null && serie.useSortData) if (isCategory && serie != null && serie.useSortData)
{ {
var isY = axis is YAxis;
var showData = serie.GetDataList(dataZoom, true); var showData = serie.GetDataList(dataZoom, true);
var isChanged = CheckSortedDataChanged(axis, showData); if (CheckSortedDataChanged(axis, showData))
if (isChanged)
{ {
for (int i = 0; i < context.labelObjectList.Count; i++) for (int i = 0; i < context.labelObjectList.Count; i++)
{ {
if (context.labelObjectList[i] != null) if (context.labelObjectList[i] != null)
{ {
var index = i < showData.Count ? showData[i].index : i; var index = i < showData.Count ? showData[i].index : i;
var text = AxisHelper.GetLabelName(axis, coordinateWidth, index, destMinValue, destMaxValue, dataZoom, forcePercent, i); var text = AxisHelper.GetLabelName(axis, coordinateWidth, index, destMinValue, destMaxValue, dataZoom, forcePercent, chart.useUtc, i);
context.labelObjectList[i].SetText(text); context.labelObjectList[i].SetText(text);
} }
} }
SaveSortedDataIndex(axis, showData); SaveSortedDataIndex(axis, showData);
} }
if (CheckSortedDataAnimation(axis, showData))
{
float diff = axis.context.scaleWidth / 2;
for (int i = 0; i < context.labelObjectList.Count; i++)
{
var labelObject = context.labelObjectList[i];
if (labelObject != null)
{
if (i < showData.Count)
{
var serieData = showData[i];
var pos = serieData.context.exchangePosition;
if (ChartHelper.IsZeroVector(pos)) continue;
var sourPos = labelObject.GetPosition();
labelObject.SetPosition(isY ? new Vector3(sourPos.x, pos.y + diff) : new Vector3(pos.x + diff, sourPos.y));
}
}
}
}
} }
else else
{ {
@@ -275,14 +322,14 @@ namespace XCharts
{ {
if (context.labelObjectList[i] != null) if (context.labelObjectList[i] != null)
{ {
var text = AxisHelper.GetLabelName(axis, coordinateWidth, i, destMinValue, destMaxValue, dataZoom, forcePercent); var text = AxisHelper.GetLabelName(axis, coordinateWidth, i, destMinValue, destMaxValue, dataZoom, forcePercent, chart.useUtc);
context.labelObjectList[i].SetText(text); context.labelObjectList[i].SetText(text);
} }
} }
} }
} }
private bool CheckSortedDataChanged(Axis axis, List<SerieData> dataList) private static bool CheckSortedDataChanged(Axis axis, List<SerieData> dataList)
{ {
if (dataList.Count != axis.context.sortedDataIndices.Count) return true; if (dataList.Count != axis.context.sortedDataIndices.Count) return true;
for (int i = 0; i < dataList.Count; i++) for (int i = 0; i < dataList.Count; i++)
@@ -292,7 +339,17 @@ namespace XCharts
return false; return false;
} }
private void SaveSortedDataIndex(Axis axis, List<SerieData> dataList) private static bool CheckSortedDataAnimation(Axis axis, List<SerieData> dataList)
{
if (!axis.IsCategory()) return false;
foreach (var data in dataList)
{
if (!data.context.exchangeEnd) return true;
}
return false;
}
private static void SaveSortedDataIndex(Axis axis, List<SerieData> dataList)
{ {
axis.context.sortedDataIndices.Clear(); axis.context.sortedDataIndices.Clear();
for (int i = 0; i < dataList.Count; i++) for (int i = 0; i < dataList.Count; i++)
@@ -307,7 +364,7 @@ namespace XCharts
{ {
var lastCount = axis.context.labelValueList.Count; var lastCount = axis.context.labelValueList.Count;
axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList, axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList,
(int)axis.context.minValue, (int)axis.context.maxValue, axis.splitNumber); axis.context.minValue, axis.context.maxValue, axis.splitNumber, axis.ceilRate, !chart.useUtc);
if (axis.context.labelValueList.Count != lastCount) if (axis.context.labelValueList.Count != lastCount)
axis.SetAllDirty(); axis.SetAllDirty();
@@ -390,13 +447,17 @@ namespace XCharts
return Math.Pow(10, n); return Math.Pow(10, n);
} }
internal void CheckValueLabelActive(Axis axis, int i, ChartLabel label, Vector3 pos) internal void CheckValueLabelActive(Axis axis, int i, ChartLabel label, Vector3 pos, string content = null)
{ {
if (!axis.show || !axis.axisLabel.show) if (!axis.show || !axis.axisLabel.show)
{ {
label.SetTextActive(false); label.SetTextActive(false);
return; return;
} }
if (content == null)
{
content = label.text.GetText();
}
if (axis.IsValue()) if (axis.IsValue())
{ {
if (orient == Orient.Horizonal) if (orient == Orient.Horizonal)
@@ -404,12 +465,12 @@ namespace XCharts
if (i == 0) if (i == 0)
{ {
var dist = GetLabelPosition(0, 1).x - pos.x; var dist = GetLabelPosition(0, 1).x - pos.x;
label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredWidth()); label.SetTextActive(axis.IsNeedShowLabel(i, 0, content) && dist > label.text.GetPreferredWidth());
} }
else if (i == axis.context.labelValueList.Count - 1) else if (i == axis.context.labelValueList.Count - 1)
{ {
var dist = pos.x - GetLabelPosition(0, i - 1).x; var dist = pos.x - GetLabelPosition(0, i - 1).x;
label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredWidth()); label.SetTextActive(axis.IsNeedShowLabel(i, 0, content) && dist > label.text.GetPreferredWidth());
} }
} }
else else
@@ -417,12 +478,12 @@ namespace XCharts
if (i == 0) if (i == 0)
{ {
var dist = GetLabelPosition(0, 1).y - pos.y; var dist = GetLabelPosition(0, 1).y - pos.y;
label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredHeight()); label.SetTextActive(axis.IsNeedShowLabel(i, 0, content) && dist > label.text.GetPreferredHeight());
} }
else if (i == axis.context.labelValueList.Count - 1) else if (i == axis.context.labelValueList.Count - 1)
{ {
var dist = pos.y - GetLabelPosition(0, i - 1).y; var dist = pos.y - GetLabelPosition(0, i - 1).y;
label.SetTextActive(axis.IsNeedShowLabel(i) && dist > label.text.GetPreferredHeight()); label.SetTextActive(axis.IsNeedShowLabel(i, 0, content) && dist > label.text.GetPreferredHeight());
} }
} }
} }
@@ -484,7 +545,6 @@ namespace XCharts
SerieHelper.UpdateSerieRuntimeFilterData(sortSerie); SerieHelper.UpdateSerieRuntimeFilterData(sortSerie);
} }
var showData = sortSerie != null ? sortSerie.GetDataList(dataZoom, true) : null; var showData = sortSerie != null ? sortSerie.GetDataList(dataZoom, true) : null;
for (int i = 0; i < splitNumber; i++) for (int i = 0; i < splitNumber; i++)
{ {
var labelWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom); var labelWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom);
@@ -492,7 +552,7 @@ namespace XCharts
var labelName = AxisHelper.GetLabelName(axis, axisLength, sortIndex, var labelName = AxisHelper.GetLabelName(axis, axisLength, sortIndex,
axis.context.destMinValue, axis.context.destMinValue,
axis.context.destMaxValue, axis.context.destMaxValue,
dataZoom, isPercentStack, i); dataZoom, isPercentStack, chart.useUtc, i);
var label = ChartHelper.AddAxisLabelObject(splitNumber, i, var label = ChartHelper.AddAxisLabelObject(splitNumber, i,
ChartCached.GetAxisLabelName(i), ChartCached.GetAxisLabelName(i),
@@ -611,7 +671,7 @@ namespace XCharts
var labelName = AxisHelper.GetLabelName(axis, axisLength, sortIndex, var labelName = AxisHelper.GetLabelName(axis, axisLength, sortIndex,
axis.context.destMinValue, axis.context.destMinValue,
axis.context.destMaxValue, axis.context.destMaxValue,
dataZoom, isPercentStack, i); dataZoom, isPercentStack, chart.useUtc, i);
var label = ChartHelper.AddAxisLabelObject(splitNumber, i, var label = ChartHelper.AddAxisLabelObject(splitNumber, i,
ChartCached.GetAxisLabelName(i), ChartCached.GetAxisLabelName(i),
@@ -627,7 +687,7 @@ namespace XCharts
var pos = GetLabelPosition(totalWidth + gapWidth, i); var pos = GetLabelPosition(totalWidth + gapWidth, i);
label.SetPosition(pos); label.SetPosition(pos);
CheckValueLabelActive(axis, i, label, pos); CheckValueLabelActive(axis, i, label, pos, labelName);
axis.context.labelObjectList.Add(label); axis.context.labelObjectList.Add(label);
@@ -772,17 +832,19 @@ namespace XCharts
var lineWidth = axis.axisLine.GetWidth(theme.lineWidth); var lineWidth = axis.axisLine.GetWidth(theme.lineWidth);
var lineType = axis.axisLine.GetType(theme.lineType); var lineType = axis.axisLine.GetType(theme.lineType);
var lineColor = axis.axisLine.GetColor(theme.lineColor); var lineColor = axis.axisLine.GetColor(theme.lineColor);
var sExtendLength = axis.axisLine.startExtendLength;
var eExtendLength = axis.axisLine.endExtendLength;
if (orient == Orient.Horizonal) if (orient == Orient.Horizonal)
{ {
var left = new Vector3(startX - lineWidth - (inverse ? offset : 0), startY); var left = new Vector3(startX - lineWidth - (inverse ? offset : 0) - sExtendLength, startY);
var right = new Vector3(startX + axisLength + lineWidth + (!inverse ? offset : 0), startY); var right = new Vector3(startX + axisLength + lineWidth + (!inverse ? offset : 0) + eExtendLength, startY);
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, left, right, lineColor); ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, left, right, lineColor);
} }
else else
{ {
var bottom = new Vector3(startX, startY - lineWidth - (inverse ? offset : 0)); var bottom = new Vector3(startX, startY - lineWidth - (inverse ? offset : 0) - sExtendLength);
var top = new Vector3(startX, startY + axisLength + lineWidth + (!inverse ? offset : 0)); var top = new Vector3(startX, startY + axisLength + lineWidth + (!inverse ? offset : 0) + eExtendLength);
ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, bottom, top, lineColor); ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, bottom, top, lineColor);
} }
} }

View File

@@ -116,7 +116,7 @@ namespace XCharts.Runtime
/// <param name="dataZoom"></param> /// <param name="dataZoom"></param>
/// <returns></returns> /// <returns></returns>
public static string GetLabelName(Axis axis, float coordinateWidth, int index, double minValue, double maxValue, public static string GetLabelName(Axis axis, float coordinateWidth, int index, double minValue, double maxValue,
DataZoom dataZoom, bool forcePercent, int sortIndex = -1) DataZoom dataZoom, bool forcePercent, bool useUtc, int sortIndex = -1)
{ {
int split = GetSplitNumber(axis, coordinateWidth, dataZoom); int split = GetSplitNumber(axis, coordinateWidth, dataZoom);
if (sortIndex == -1) sortIndex = index; if (sortIndex == -1) sortIndex = index;
@@ -161,7 +161,7 @@ namespace XCharts.Runtime
return string.Empty; return string.Empty;
var value = axis.GetLabelValue(index); var value = axis.GetLabelValue(index);
return axis.axisLabel.GetFormatterDateTime(sortIndex, axis.context.labelValueList.Count, value, minValue, maxValue); return axis.axisLabel.GetFormatterDateTime(sortIndex, axis.context.labelValueList.Count, value, minValue, maxValue, !useUtc);
} }
var showData = axis.GetDataList(dataZoom); var showData = axis.GetDataList(dataZoom);
int dataCount = showData.Count; int dataCount = showData.Count;
@@ -354,8 +354,8 @@ namespace XCharts.Runtime
axis.splitNumber = splitNumber; axis.splitNumber = splitNumber;
return; return;
} }
if (axis.type == Axis.AxisType.Time) { } if (ceilRate == 0) ceilRate = axis.ceilRate;
else if (axis.minMaxType == Axis.AxisMinMaxType.Custom) if (axis.minMaxType == Axis.AxisMinMaxType.Custom)
{ {
if (axis.min != 0 || axis.max != 0) if (axis.min != 0 || axis.max != 0)
{ {
@@ -371,13 +371,19 @@ namespace XCharts.Runtime
} }
} }
} }
else if (axis.type == Axis.AxisType.Time)
{
if (ceilRate != 0)
{
minValue = ChartHelper.GetMinCeilRate(minValue, ceilRate);
maxValue = ChartHelper.GetMaxCeilRate(maxValue, ceilRate);
}
}
else else
{ {
if (ceilRate == 0) ceilRate = axis.ceilRate;
switch (axis.minMaxType) switch (axis.minMaxType)
{ {
case Axis.AxisMinMaxType.Default: case Axis.AxisMinMaxType.Default:
if (minValue == 0 && maxValue == 0) { } if (minValue == 0 && maxValue == 0) { }
else if (minValue > 0 && maxValue > 0) else if (minValue > 0 && maxValue > 0)
{ {
@@ -536,9 +542,9 @@ namespace XCharts.Runtime
/// <param name="scaleWidth"></param> /// <param name="scaleWidth"></param>
/// <param name="value"></param> /// <param name="value"></param>
/// <returns></returns> /// <returns></returns>
public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value) public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value, float gap = 0)
{ {
return GetAxisPositionInternal(grid, axis, scaleWidth, value, false, true); return GetAxisPositionInternal(grid, axis, scaleWidth, value, false, true, gap);
} }
/// <summary> /// <summary>
@@ -572,10 +578,11 @@ namespace XCharts.Runtime
} }
} }
private static float GetAxisPositionInternal(GridCoord grid, Axis axis, float scaleWidth, double value, bool includeGridXY, bool realLength) private static float GetAxisPositionInternal(GridCoord grid, Axis axis, float scaleWidth, double value, bool includeGridXY, bool realLength, float gap = 0)
{ {
var isY = axis is YAxis; var isY = axis is YAxis;
var gridHeight = isY ? grid.context.height : grid.context.width; var gridHeight = isY ? grid.context.height : grid.context.width;
gridHeight -= gap;
var gridXY = isY ? grid.context.y : grid.context.x; var gridXY = isY ? grid.context.y : grid.context.x;
if (axis.IsLog()) if (axis.IsLog())

View File

@@ -17,6 +17,7 @@ namespace XCharts.Runtime
[SerializeField] private bool m_OnZero = false; [SerializeField] private bool m_OnZero = false;
[SerializeField] private bool m_ShowStartLabel = true; [SerializeField] private bool m_ShowStartLabel = true;
[SerializeField] private bool m_ShowEndLabel = true; [SerializeField] private bool m_ShowEndLabel = true;
[SerializeField][Since("v3.15.0")] private bool m_ShowZeroLabel = true;
[SerializeField] private TextLimit m_TextLimit = new TextLimit(); [SerializeField] private TextLimit m_TextLimit = new TextLimit();
/// <summary> /// <summary>
@@ -74,6 +75,15 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_ShowEndLabel, value)) SetComponentDirty(); } set { if (PropertyUtil.SetStruct(ref m_ShowEndLabel, value)) SetComponentDirty(); }
} }
/// <summary> /// <summary>
/// Whether to display the zero label.
/// ||是否显示0刻度文本。
/// </summary>
public bool showZeroLabel
{
get { return m_ShowZeroLabel; }
set { if (PropertyUtil.SetStruct(ref m_ShowZeroLabel, value)) SetComponentDirty(); }
}
/// <summary>
/// 文本限制。 /// 文本限制。
/// </summary> /// </summary>
public TextLimit textLimit public TextLimit textLimit
@@ -118,6 +128,7 @@ namespace XCharts.Runtime
height = height, height = height,
showStartLabel = showStartLabel, showStartLabel = showStartLabel,
showEndLabel = showEndLabel, showEndLabel = showEndLabel,
showZeroLabel = showZeroLabel,
textLimit = textLimit.Clone() textLimit = textLimit.Clone()
}; };
axisLabel.textStyle.Copy(textStyle); axisLabel.textStyle.Copy(textStyle);
@@ -136,6 +147,7 @@ namespace XCharts.Runtime
height = axisLabel.height; height = axisLabel.height;
showStartLabel = axisLabel.showStartLabel; showStartLabel = axisLabel.showStartLabel;
showEndLabel = axisLabel.showEndLabel; showEndLabel = axisLabel.showEndLabel;
showZeroLabel = axisLabel.showZeroLabel;
textLimit.Copy(axisLabel.textLimit); textLimit.Copy(axisLabel.textLimit);
textStyle.Copy(axisLabel.textStyle); textStyle.Copy(axisLabel.textStyle);
} }
@@ -171,13 +183,14 @@ namespace XCharts.Runtime
return base.GetFormatterContent(labelIndex, totalIndex, value, minValue, maxValue, isLog); return base.GetFormatterContent(labelIndex, totalIndex, value, minValue, maxValue, isLog);
} }
public bool IsNeedShowLabel(int index, int total) public bool IsNeedShowLabel(int index, int total, string content = null)
{ {
var labelShow = show && (interval == 0 || index % (interval + 1) == 0); var labelShow = show && (interval == 0 || index % (interval + 1) == 0);
if (labelShow) if (labelShow)
{ {
if (!showStartLabel && index == 0) labelShow = false; if (!showStartLabel && index == 0) labelShow = false;
else if (!showEndLabel && index == total - 1) labelShow = false; else if (!showEndLabel && index == total - 1) labelShow = false;
if (labelShow && content == "0") labelShow = showZeroLabel;
} }
return labelShow; return labelShow;
} }

View File

@@ -10,6 +10,8 @@ namespace XCharts.Runtime
public class AxisLine : BaseLine public class AxisLine : BaseLine
{ {
[SerializeField] private bool m_OnZero; [SerializeField] private bool m_OnZero;
[SerializeField] private float m_StartExtendLength;
[SerializeField] private float m_EndExtendLength;
[SerializeField] private bool m_ShowArrow; [SerializeField] private bool m_ShowArrow;
[SerializeField] private ArrowStyle m_Arrow = new ArrowStyle(); [SerializeField] private ArrowStyle m_Arrow = new ArrowStyle();
@@ -23,6 +25,24 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_OnZero, value)) SetVerticesDirty(); } set { if (PropertyUtil.SetStruct(ref m_OnZero, value)) SetVerticesDirty(); }
} }
/// <summary> /// <summary>
/// Extend length of the axis line at the start.
/// ||轴线起点延长线长度。
/// </summary>
public float startExtendLength
{
get { return m_StartExtendLength; }
set { if (PropertyUtil.SetStruct(ref m_StartExtendLength, value)) SetVerticesDirty(); }
}
/// <summary>
/// Extend length of the axis line at the end.
/// ||轴线终点延长线长度。
/// </summary>
public float endExtendLength
{
get { return m_EndExtendLength; }
set { if (PropertyUtil.SetStruct(ref m_EndExtendLength, value)) SetVerticesDirty(); }
}
/// <summary>
/// Whether to show the arrow symbol of axis. /// Whether to show the arrow symbol of axis.
/// ||是否显示箭头。 /// ||是否显示箭头。
/// </summary> /// </summary>

View File

@@ -114,7 +114,7 @@ namespace XCharts.Runtime
var inside = axis.axisLabel.inside; var inside = axis.axisLabel.inside;
var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series); var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series);
var labelName = AxisHelper.GetLabelName(axis, radius, i, axis.context.minValue, axis.context.maxValue, var labelName = AxisHelper.GetLabelName(axis, radius, i, axis.context.minValue, axis.context.maxValue,
null, isPercentStack); null, isPercentStack, chart.useUtc);
var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform, var label = ChartHelper.AddAxisLabelObject(splitNumber, i, objName + i, axisObj.transform,
new Vector2(labelWidth, txtHig), axis, chart.theme.axis, labelName, Color.clear); new Vector2(labelWidth, txtHig), axis, chart.theme.axis, labelName, Color.clear);

View File

@@ -16,6 +16,7 @@ namespace XCharts.Runtime
[SerializeField][Since("v3.6.0")] private Color32 m_MarkColor; [SerializeField][Since("v3.6.0")] private Color32 m_MarkColor;
[SerializeField] private Color32 m_BackgroundColor; [SerializeField] private Color32 m_BackgroundColor;
[SerializeField] private float m_BackgroundWidth; [SerializeField] private float m_BackgroundWidth;
[SerializeField][Since("v3.15.0")] private float m_BackgroundGap;
[SerializeField] private Color32 m_CenterColor; [SerializeField] private Color32 m_CenterColor;
[SerializeField] private float m_CenterGap; [SerializeField] private float m_CenterGap;
[SerializeField] private float m_BorderWidth = 0; [SerializeField] private float m_BorderWidth = 0;
@@ -129,6 +130,15 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_BackgroundWidth, value)) SetVerticesDirty(); } set { if (PropertyUtil.SetStruct(ref m_BackgroundWidth, value)) SetVerticesDirty(); }
} }
/// <summary> /// <summary>
/// the gap between background and data item.
/// ||数据项背景间隙。
/// </summary>
public float backgroundGap
{
get { return m_BackgroundGap; }
set { if (PropertyUtil.SetStruct(ref m_BackgroundGap, value)) SetVerticesDirty(); }
}
/// <summary>
/// 中心区域颜色。 /// 中心区域颜色。
/// </summary> /// </summary>
public Color32 centerColor public Color32 centerColor

View File

@@ -5,14 +5,33 @@ using UnityEngine;
namespace XCharts.Runtime namespace XCharts.Runtime
{ {
/// <summary> /// <summary>
/// comment of chart. /// The layer of comment.
/// ||图表注解组件 /// ||注解的显示层级
/// </summary>
[Since("v3.15.0")]
public enum CommentLayer
{
/// <summary>
/// The comment is display under the serie.
/// ||注解在系列下方。
/// </summary>
Lower,
/// <summary>
/// The comment is display above the serie.
/// ||注解在系列上方。
/// </summary>
Upper
}
/// <summary>
/// comment of chart. Used to annotate special information in the chart.
/// ||图表注解组件。用于标注图表中的特殊信息。
/// </summary> /// </summary>
[Serializable] [Serializable]
[ComponentHandler(typeof(CommentHander), true)] [ComponentHandler(typeof(CommentHander), true)]
public class Comment : MainComponent, IPropertyChanged public class Comment : MainComponent, IPropertyChanged
{ {
[SerializeField] private bool m_Show = true; [SerializeField] private bool m_Show = true;
[SerializeField][Since("v3.15.0")] private CommentLayer m_Layer = CommentLayer.Lower;
[SerializeField] private LabelStyle m_LabelStyle = new LabelStyle(); [SerializeField] private LabelStyle m_LabelStyle = new LabelStyle();
[SerializeField] private CommentMarkStyle m_MarkStyle; [SerializeField] private CommentMarkStyle m_MarkStyle;
[SerializeField] private List<CommentItem> m_Items = new List<CommentItem>() { new CommentItem() }; [SerializeField] private List<CommentItem> m_Items = new List<CommentItem>() { new CommentItem() };
@@ -23,6 +42,11 @@ namespace XCharts.Runtime
/// </summary> /// </summary>
public bool show { get { return m_Show; } set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); } } public bool show { get { return m_Show; } set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); } }
/// <summary> /// <summary>
/// The layer of comment.
/// ||注解的显示层级。
/// </summary>
public CommentLayer layer { get { return m_Layer; } set { if (PropertyUtil.SetStruct(ref m_Layer, value)) SetComponentDirty(); } }
/// <summary>
/// The items of comment. /// The items of comment.
/// ||注解项。每个注解组件可以设置多个注解项。 /// ||注解项。每个注解组件可以设置多个注解项。
/// </summary> /// </summary>
@@ -45,7 +69,12 @@ namespace XCharts.Runtime
get { return m_MarkStyle; } get { return m_MarkStyle; }
set { if (PropertyUtil.SetClass(ref m_MarkStyle, value)) SetVerticesDirty(); } set { if (PropertyUtil.SetClass(ref m_MarkStyle, value)) SetVerticesDirty(); }
} }
/// <summary>
/// Get the label style of comment item.
/// ||获取注解项的文本样式。
/// </summary>
/// <param name="index">the index of item</param>
/// <returns></returns>
public LabelStyle GetLabelStyle(int index) public LabelStyle GetLabelStyle(int index)
{ {
if (index >= 0 && index < items.Count) if (index >= 0 && index < items.Count)
@@ -55,7 +84,12 @@ namespace XCharts.Runtime
} }
return m_LabelStyle; return m_LabelStyle;
} }
/// <summary>
/// Get the mark style of comment item.
/// ||获取注解项的标记样式。
/// </summary>
/// <param name="index">the index of item</param>
/// <returns></returns>
public CommentMarkStyle GetMarkStyle(int index) public CommentMarkStyle GetMarkStyle(int index)
{ {
if (index >= 0 && index < items.Count) if (index >= 0 && index < items.Count)

View File

@@ -14,7 +14,7 @@ namespace XCharts.Runtime
var comment = component; var comment = component;
comment.OnChanged(); comment.OnChanged();
comment.painter = null; comment.painter = null;
comment.refreshComponent = delegate() comment.refreshComponent = delegate ()
{ {
var objName = ChartCached.GetComponentObjectName(comment); var objName = ChartCached.GetComponentObjectName(comment);
var commentObj = ChartHelper.AddObject(objName, var commentObj = ChartHelper.AddObject(objName,
@@ -23,20 +23,24 @@ namespace XCharts.Runtime
chart.chartMaxAnchor, chart.chartMaxAnchor,
chart.chartPivot, chart.chartPivot,
chart.chartSizeDelta, -1, chart.childrenNodeNames); chart.chartSizeDelta, -1, chart.childrenNodeNames);
var siblingIndex = comment.layer == CommentLayer.Upper
? chart.topPainter.transform.GetSiblingIndex() - 1
: chart.painter.transform.GetSiblingIndex() + 1;
commentObj.SetActive(comment.show); commentObj.SetActive(comment.show);
commentObj.transform.SetSiblingIndex(siblingIndex);
commentObj.hideFlags = chart.chartHideFlags; commentObj.hideFlags = chart.chartHideFlags;
ChartHelper.HideAllObject(commentObj); ChartHelper.HideAllObject(commentObj);
for (int i = 0; i < comment.items.Count; i++) for (int i = 0; i < comment.items.Count; i++)
{ {
var item = comment.items[i]; var item = comment.items[i];
var labelStyle = comment.GetLabelStyle(i); var labelStyle = comment.GetLabelStyle(i);
item.location.OnChanged();
var labelPos = chart.chartPosition + item.location.GetPosition(chart.chartWidth, chart.chartHeight); var labelPos = chart.chartPosition + item.location.GetPosition(chart.chartWidth, chart.chartHeight);
var label = ChartHelper.AddChartLabel(s_CommentObjectName + i, commentObj.transform, labelStyle, chart.theme.common, var label = ChartHelper.AddChartLabel(s_CommentObjectName + i, commentObj.transform, labelStyle, chart.theme.common,
GetContent(item), Color.clear, TextAnchor.MiddleCenter); GetContent(item), Color.clear, TextAnchor.MiddleCenter);
label.SetActive(comment.show && item.show, true); label.SetActive(comment.show && item.show, true);
label.SetPosition(labelPos); label.SetPosition(labelPos + labelStyle.offset);
label.text.SetLocalPosition(labelStyle.offset);
item.labelObject = label; item.labelObject = label;
} }
}; };

View File

@@ -11,11 +11,11 @@ namespace XCharts.Runtime
public class CommentItem : ChildComponent public class CommentItem : ChildComponent
{ {
[SerializeField] private bool m_Show = true; [SerializeField] private bool m_Show = true;
[SerializeField] private string m_Content = "comment"; [SerializeField] private string m_Content = "xcharts";
[SerializeField] private Rect m_MarkRect; [SerializeField] private Rect m_MarkRect;
[SerializeField] private CommentMarkStyle m_MarkStyle = new CommentMarkStyle() { show = false }; [SerializeField] private CommentMarkStyle m_MarkStyle = new CommentMarkStyle() { show = false };
[SerializeField] private LabelStyle m_LabelStyle = new LabelStyle() { show = false }; [SerializeField] private LabelStyle m_LabelStyle = new LabelStyle() { show = false };
[SerializeField][Since("v3.5.0")] private Location m_Location = new Location() { align = Location.Align.TopLeft, top = 0.125f }; [SerializeField][Since("v3.5.0")] private Location m_Location = new Location() { align = Location.Align.BottomRight, right = 0.1f, bottom = 0.05f };
public ChartLabel labelObject { get; set; } public ChartLabel labelObject { get; set; }

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@@ -81,7 +82,7 @@ namespace XCharts.Runtime
[SerializeField] private RangeMode m_RangeMode; [SerializeField] private RangeMode m_RangeMode;
[SerializeField] private float m_Start; [SerializeField] private float m_Start;
[SerializeField] private float m_End; [SerializeField] private float m_End;
[SerializeField] private int m_MinShowNum = 2; [SerializeField] private float m_MinZoomRatio = 0.2f;
[Range(1f, 20f)] [Range(1f, 20f)]
[SerializeField] private float m_ScrollSensitivity = 1.1f; [SerializeField] private float m_ScrollSensitivity = 1.1f;
[SerializeField] private Orient m_Orient = Orient.Horizonal; [SerializeField] private Orient m_Orient = Orient.Horizonal;
@@ -336,10 +337,19 @@ namespace XCharts.Runtime
/// Minimum number of display data. Minimum number of data displayed when DataZoom is enlarged to maximum. /// Minimum number of display data. Minimum number of data displayed when DataZoom is enlarged to maximum.
/// ||最小显示数据个数。当DataZoom放大到最大时最小显示的数据个数。 /// ||最小显示数据个数。当DataZoom放大到最大时最小显示的数据个数。
/// </summary> /// </summary>
public int minShowNum [Obsolete("Use \"minZoomRatio\" instead", true)]
public float minShowNum
{ {
get { return m_MinShowNum; } set;get;
set { if (PropertyUtil.SetStruct(ref m_MinShowNum, value)) SetVerticesDirty(); } }
/// <summary>
/// The minimum zoom ratio of dataZoom. Range 0f-1f.
/// ||缩放区域组件的最小缩放比例范围0f-1f。
/// </summary>
public float minZoomRatio
{
get { return m_MinZoomRatio; }
set { if (PropertyUtil.SetStruct(ref m_MinZoomRatio, value)) SetVerticesDirty(); }
} }
/// <summary> /// <summary>
/// The sensitivity of dataZoom scroll. /// The sensitivity of dataZoom scroll.

View File

@@ -215,7 +215,7 @@ namespace XCharts.Runtime
var grid = chart.GetGridOfDataZoom(dataZoom); var grid = chart.GetGridOfDataZoom(dataZoom);
var start = (dataZoom.context.marqueeRect.x - grid.context.x) / grid.context.width * 100; var start = (dataZoom.context.marqueeRect.x - grid.context.x) / grid.context.width * 100;
var end = (dataZoom.context.marqueeRect.x - grid.context.x + dataZoom.context.marqueeRect.width) / grid.context.width * 100; var end = (dataZoom.context.marqueeRect.x - grid.context.x + dataZoom.context.marqueeRect.width) / grid.context.width * 100;
UpdateDataZoomRange(dataZoom, start, end); UpdateDataZoomRange(dataZoom, start, end, grid);
} }
if (dataZoom.marqueeStyle.onEnd != null) if (dataZoom.marqueeStyle.onEnd != null)
{ {
@@ -271,7 +271,7 @@ namespace XCharts.Runtime
} }
var start = (startX - grid.context.x) / grid.context.width * 100; var start = (startX - grid.context.x) / grid.context.width * 100;
var end = (endX - grid.context.x) / grid.context.width * 100; var end = (endX - grid.context.x) / grid.context.width * 100;
UpdateDataZoomRange(dataZoom, start, end); UpdateDataZoomRange(dataZoom, start, end, grid);
} }
} }
@@ -294,7 +294,7 @@ namespace XCharts.Runtime
if ((dataZoom.supportInside && dataZoom.supportInsideScroll && grid.Contains(pos)) || if ((dataZoom.supportInside && dataZoom.supportInsideScroll && grid.Contains(pos)) ||
dataZoom.IsInZoom(pos)) dataZoom.IsInZoom(pos))
{ {
ScaleDataZoom(dataZoom, eventData.scrollDelta.y * dataZoom.scrollSensitivity); ScaleDataZoom(dataZoom, eventData.scrollDelta.y * dataZoom.scrollSensitivity, grid);
} }
} }
@@ -375,25 +375,27 @@ namespace XCharts.Runtime
} }
} }
private void ScaleDataZoom(DataZoom dataZoom, float delta) private void ScaleDataZoom(DataZoom dataZoom, float delta, GridCoord grid = null)
{ {
var grid = chart.GetGridOfDataZoom(dataZoom); if (grid == null) grid = chart.GetGridOfDataZoom(dataZoom);
var deltaPercent = dataZoom.orient == Orient.Horizonal ? var range = dataZoom.orient == Orient.Horizonal ? grid.context.width : grid.context.height;
Mathf.Abs(delta / grid.context.width * 100) : var deltaPercent = Mathf.Abs(delta / range * 100);
Mathf.Abs(delta / grid.context.height * 100); float start, end;
if (delta > 0) if (delta > 0)
{ {
if (dataZoom.end <= dataZoom.start) if (dataZoom.end <= dataZoom.start) return;
return; start = dataZoom.start + deltaPercent;
UpdateDataZoomRange(dataZoom, dataZoom.start + deltaPercent, dataZoom.end - deltaPercent); end = dataZoom.end - deltaPercent;
} }
else else
{ {
UpdateDataZoomRange(dataZoom, dataZoom.start - deltaPercent, dataZoom.end + deltaPercent); start = dataZoom.start - deltaPercent;
end = dataZoom.end + deltaPercent;
} }
UpdateDataZoomRange(dataZoom, start, end, grid);
} }
public void UpdateDataZoomRange(DataZoom dataZoom, float start, float end) public void UpdateDataZoomRange(DataZoom dataZoom, float start, float end, GridCoord grid = null)
{ {
if (end > 100) if (end > 100)
end = 100; end = 100;
@@ -403,13 +405,26 @@ namespace XCharts.Runtime
if (end < start) if (end < start)
end = start; end = start;
if (dataZoom.startEndFunction != null)
dataZoom.startEndFunction(ref start, ref end); if(dataZoom.minZoomRatio > 0)
{
if(grid == null) grid = chart.GetGridOfDataZoom(dataZoom);
var range = dataZoom.orient == Orient.Horizonal ? grid.context.width : grid.context.height;
var minRange = dataZoom.minZoomRatio * range;
if (end - start < minRange / range * 100)
{
return;
}
}
if (!dataZoom.startLock) if (!dataZoom.startLock)
dataZoom.start = start; dataZoom.start = start;
if (!dataZoom.endLock) if (!dataZoom.endLock)
dataZoom.end = end; dataZoom.end = end;
if (dataZoom.startEndFunction != null)
dataZoom.startEndFunction(ref start, ref end);
m_LastStart = dataZoom.start; m_LastStart = dataZoom.start;
m_LastEnd = dataZoom.end; m_LastEnd = dataZoom.end;
if (dataZoom.realtime) if (dataZoom.realtime)
@@ -444,7 +459,7 @@ namespace XCharts.Runtime
var tempPos1 = touch1.position; var tempPos1 = touch1.position;
var currDist = Vector2.Distance(tempPos0, tempPos1); var currDist = Vector2.Distance(tempPos0, tempPos1);
var lastDist = Vector2.Distance(m_LastTouchPos0, m_LastTouchPos1); var lastDist = Vector2.Distance(m_LastTouchPos0, m_LastTouchPos1);
var delta = (currDist - lastDist); var delta = currDist - lastDist;
ScaleDataZoom(dataZoom, delta / dataZoom.scrollSensitivity); ScaleDataZoom(dataZoom, delta / dataZoom.scrollSensitivity);
m_LastTouchPos0 = tempPos0; m_LastTouchPos0 = tempPos0;
m_LastTouchPos1 = tempPos1; m_LastTouchPos1 = tempPos1;
@@ -492,7 +507,6 @@ namespace XCharts.Runtime
} }
else if (xAxis.IsTime()) else if (xAxis.IsTime())
{ {
//TODO:
dataZoom.SetStartLabelText(""); dataZoom.SetStartLabelText("");
dataZoom.SetEndLabelText(""); dataZoom.SetEndLabelText("");
} }

View File

@@ -80,6 +80,8 @@ namespace XCharts.Runtime
[SerializeField] protected string m_NumericFormatter = ""; [SerializeField] protected string m_NumericFormatter = "";
[SerializeField] protected float m_Width = 0; [SerializeField] protected float m_Width = 0;
[SerializeField] protected float m_Height = 0; [SerializeField] protected float m_Height = 0;
[SerializeField][Since("v3.15.0")] protected float m_FixedX = 0;
[SerializeField][Since("v3.15.0")] protected float m_FixedY = 0;
[SerializeField] protected IconStyle m_Icon = new IconStyle(); [SerializeField] protected IconStyle m_Icon = new IconStyle();
[SerializeField] protected ImageStyle m_Background = new ImageStyle(); [SerializeField] protected ImageStyle m_Background = new ImageStyle();
@@ -288,6 +290,24 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_AutoOffset, value)) SetAllDirty(); } set { if (PropertyUtil.SetStruct(ref m_AutoOffset, value)) SetAllDirty(); }
} }
/// <summary> /// <summary>
/// the fixed x of label. When not 0, it will be fixed on the specified x value.
/// ||固定的X值。不为0时会固定在指定的X值上。
/// </summary>
public float fixedX
{
get { return m_FixedX; }
set { if (PropertyUtil.SetStruct(ref m_FixedX, value)) SetComponentDirty(); }
}
/// <summary>
/// the fixed y of label. When not 0, it will be fixed on the specified y value.
/// ||固定的Y值。不为0时会固定在指定的Y值上。
/// </summary>
public float fixedY
{
get { return m_FixedY; }
set { if (PropertyUtil.SetStruct(ref m_FixedY, value)) SetComponentDirty(); }
}
/// <summary>
/// the sytle of background. /// the sytle of background.
/// ||背景图样式。 /// ||背景图样式。
/// </summary> /// </summary>
@@ -375,6 +395,8 @@ namespace XCharts.Runtime
label.m_Height = m_Height; label.m_Height = m_Height;
label.m_NumericFormatter = m_NumericFormatter; label.m_NumericFormatter = m_NumericFormatter;
label.m_AutoOffset = m_AutoOffset; label.m_AutoOffset = m_AutoOffset;
label.m_FixedX = m_FixedX;
label.m_FixedY = m_FixedY;
label.m_Icon.Copy(m_Icon); label.m_Icon.Copy(m_Icon);
label.m_Background.Copy(m_Background); label.m_Background.Copy(m_Background);
label.m_TextPadding = m_TextPadding; label.m_TextPadding = m_TextPadding;
@@ -394,6 +416,8 @@ namespace XCharts.Runtime
m_Height = label.m_Height; m_Height = label.m_Height;
m_NumericFormatter = label.m_NumericFormatter; m_NumericFormatter = label.m_NumericFormatter;
m_AutoOffset = label.m_AutoOffset; m_AutoOffset = label.m_AutoOffset;
m_FixedX = label.m_FixedX;
m_FixedY = label.m_FixedY;
m_Icon.Copy(label.m_Icon); m_Icon.Copy(label.m_Icon);
m_Background.Copy(label.m_Background); m_Background.Copy(label.m_Background);
m_TextPadding = label.m_TextPadding; m_TextPadding = label.m_TextPadding;
@@ -461,10 +485,10 @@ namespace XCharts.Runtime
private static bool isDateFormatter = false; private static bool isDateFormatter = false;
private static string newFormatter = null; private static string newFormatter = null;
public string GetFormatterDateTime(int labelIndex, int totalIndex, double value, double minValue, double maxValue) public string GetFormatterDateTime(int labelIndex, int totalIndex, double value, double minValue, double maxValue, bool local)
{ {
var timestamp = (int)value; var timestamp = value;
var dateTime = DateTimeUtil.GetDateTime(timestamp); var dateTime = DateTimeUtil.GetDateTime(timestamp, local);
var dateString = string.Empty; var dateString = string.Empty;
if (string.IsNullOrEmpty(numericFormatter) || numericFormatter.Equals("f2")) if (string.IsNullOrEmpty(numericFormatter) || numericFormatter.Equals("f2"))
{ {
@@ -477,7 +501,7 @@ namespace XCharts.Runtime
if (DateTimeUtil.IsDateOrTimeRegex(numericFormatter, ref isDateFormatter, ref newFormatter)) if (DateTimeUtil.IsDateOrTimeRegex(numericFormatter, ref isDateFormatter, ref newFormatter))
{ {
if (isDateFormatter) if (isDateFormatter)
dateString = ChartCached.NumberToDateStr(timestamp, newFormatter); dateString = ChartCached.NumberToDateStr(timestamp, newFormatter, local);
else else
dateString = ChartCached.NumberToTimeStr(timestamp, newFormatter); dateString = ChartCached.NumberToTimeStr(timestamp, newFormatter);
} }

View File

@@ -45,7 +45,7 @@ namespace XCharts.Runtime
{ {
var content = serieLabel.formatter; var content = serieLabel.formatter;
FormatterHelper.ReplaceSerieLabelContent(ref content, numericFormatter, serie.dataCount, dataValue, FormatterHelper.ReplaceSerieLabelContent(ref content, numericFormatter, serie.dataCount, dataValue,
dataTotal, serieName, dataName, dataName, color, serieData, chart, serie.index); dataTotal, serieName, dataName, dataName, color, serieData, chart, serie.index, serie.useSortData);
if (serieLabel.formatterFunction == null) if (serieLabel.formatterFunction == null)
return content; return content;
else else
@@ -53,6 +53,22 @@ namespace XCharts.Runtime
} }
} }
public static string GetTitleFormatterContent(Serie serie, SerieData serieData,
int dataIndex, LabelStyle titleStyle, BaseChart chart)
{
string content;
if (string.IsNullOrEmpty(titleStyle.formatter))
{
content = serieData.name;
}
else
{
content = titleStyle.formatter;
FormatterHelper.ReplaceContent(ref content, dataIndex, titleStyle.numericFormatter, serie, chart, null, serieData);
}
return content;
}
public static void SetGaugeLabelText(Serie serie) public static void SetGaugeLabelText(Serie serie)
{ {
var serieData = serie.GetSerieData(0); var serieData = serie.GetSerieData(0);

View File

@@ -79,6 +79,7 @@ namespace XCharts.Runtime
[SerializeField] private float m_ItemGap = 10f; [SerializeField] private float m_ItemGap = 10f;
[SerializeField] private bool m_ItemAutoColor = true; [SerializeField] private bool m_ItemAutoColor = true;
[SerializeField] private float m_ItemOpacity = 1; [SerializeField] private float m_ItemOpacity = 1;
[SerializeField][Since("v3.15.0")] private float m_ItemInactiveOpacity = 1;
[SerializeField] private string m_Formatter; [SerializeField] private string m_Formatter;
[SerializeField] private LabelStyle m_LabelStyle = new LabelStyle(); [SerializeField] private LabelStyle m_LabelStyle = new LabelStyle();
[SerializeField][Since("v3.10.0")] private TextLimit m_TextLimit = new TextLimit(); [SerializeField][Since("v3.10.0")] private TextLimit m_TextLimit = new TextLimit();
@@ -182,6 +183,15 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_ItemOpacity, value)) SetComponentDirty(); } set { if (PropertyUtil.SetStruct(ref m_ItemOpacity, value)) SetComponentDirty(); }
} }
/// <summary> /// <summary>
/// the opacity of item color when item is inactive.
/// ||图例标记的图形在非激活状态下的颜色透明度。
/// </summary>
public float itemInactiveOpacity
{
get { return m_ItemInactiveOpacity; }
set { if (PropertyUtil.SetStruct(ref m_ItemInactiveOpacity, value)) SetComponentDirty(); }
}
/// <summary>
/// No longer used, the use of LabelStyle.formatter instead. /// No longer used, the use of LabelStyle.formatter instead.
/// ||不再使用使用LabelStyle.formatter代替。 /// ||不再使用使用LabelStyle.formatter代替。
/// </summary> /// </summary>

View File

@@ -92,15 +92,15 @@ namespace XCharts.Runtime
{ {
if (!SeriesHelper.IsLegalLegendName(datas[i])) continue; if (!SeriesHelper.IsLegalLegendName(datas[i])) continue;
string legendName = datas[i]; string legendName = datas[i];
var serieIndex = isAnySerieColorByData ? 0 : i; var serieIndex = isAnySerieColorByData ? 0 : i;
var dataIndex = isAnySerieColorByData ? i : 0; var dataIndex = isAnySerieColorByData ? i : 0;
var legendContent = GetFormatterContent(legend, dataIndex, datas[i], serieIndex); var legendContent = GetFormatterContent(legend, dataIndex, datas[i], serieIndex);
if (legend.textLimit.enable) if (legend.textLimit.enable)
legendContent = legend.textLimit.GetLimitContent(legendContent); legendContent = legend.textLimit.GetLimitContent(legendContent);
var readIndex = chart.m_LegendRealShowName.IndexOf(datas[i]); var readIndex = chart.m_LegendRealShowName.IndexOf(datas[i]);
var active = chart.IsActiveByLegend(datas[i]); var active = chart.IsActiveByLegend(datas[i]);
var bgColor = LegendHelper.GetIconColor(chart, legend, readIndex, datas[i], active); var bgColor = LegendHelper.GetIconColor(chart, legend, readIndex, datas[i], active);
bgColor.a = legend.itemOpacity; bgColor.a = active ? legend.itemOpacity : legend.itemInactiveOpacity;
var item = LegendHelper.AddLegendItem(chart, legend, i, legendName, legendObject.transform, chart.theme, var item = LegendHelper.AddLegendItem(chart, legend, i, legendName, legendObject.transform, chart.theme,
legendContent, bgColor, active, readIndex); legendContent, bgColor, active, readIndex);
legend.SetButton(legendName, item, totalLegend); legend.SetButton(legendName, item, totalLegend);

View File

@@ -16,7 +16,7 @@ namespace XCharts.Runtime
else else
return !ChartHelper.IsClearColor(textStyle.color) ? textStyle.color : theme.legend.textColor; return !ChartHelper.IsClearColor(textStyle.color) ? textStyle.color : theme.legend.textColor;
} }
else return theme.legend.unableColor; else return theme.legend.inactiveColor;
} }
public static Color GetIconColor(BaseChart chart, Legend legend, int readIndex, string legendName, bool active) public static Color GetIconColor(BaseChart chart, Legend legend, int readIndex, string legendName, bool active)
@@ -30,7 +30,7 @@ namespace XCharts.Runtime
else else
return legend.GetColor(readIndex); return legend.GetColor(readIndex);
} }
else return chart.theme.legend.unableColor; else return chart.theme.legend.inactiveColor;
} }
public static LegendItem AddLegendItem(BaseChart chart, Legend legend, int i, string legendName, Transform parent, public static LegendItem AddLegendItem(BaseChart chart, Legend legend, int i, string legendName, Transform parent,

View File

@@ -40,7 +40,7 @@ namespace XCharts.Runtime
private void InitMarkArea(MarkArea markArea) private void InitMarkArea(MarkArea markArea)
{ {
markArea.painter = chart.m_PainterUpper; markArea.painter = chart.m_PainterUpper;
markArea.refreshComponent = delegate() markArea.refreshComponent = delegate ()
{ {
var label = ChartHelper.AddChartLabel("label", m_MarkLineLabelRoot.transform, markArea.label, chart.theme.axis, var label = ChartHelper.AddChartLabel("label", m_MarkLineLabelRoot.transform, markArea.label, chart.theme.axis,
component.text, Color.clear, TextAnchor.MiddleCenter); component.text, Color.clear, TextAnchor.MiddleCenter);
@@ -142,31 +142,12 @@ namespace XCharts.Runtime
else if (data.yValue != 0) else if (data.yValue != 0)
{ {
data.runtimeValue = data.yValue; data.runtimeValue = data.yValue;
if (yAxis.IsCategory()) return GetPosition(yAxis, grid, data.runtimeValue, start);
{
var pY = AxisHelper.GetAxisPosition(grid, yAxis, data.yValue, showData.Count, dataZoom);
return start ?
new Vector3(grid.context.x, pY) :
new Vector3(grid.context.x + grid.context.width, pY);
}
else
{
return GetPosition(xAxis, yAxis, grid, data.runtimeValue, start);
}
} }
else else
{ {
data.runtimeValue = data.xValue; data.runtimeValue = data.xValue;
if (xAxis.IsCategory()) return GetPosition(xAxis, grid, data.xValue, start);
{
var pX = AxisHelper.GetAxisPosition(grid, xAxis, data.xValue, showData.Count, dataZoom);
return start ? new Vector3(pX, grid.context.y + grid.context.height) :
new Vector3(pX, grid.context.y);
}
else
{
return GetPosition(xAxis, yAxis, grid, data.xValue, start);
}
} }
default: default:
break; break;
@@ -178,16 +159,28 @@ namespace XCharts.Runtime
{ {
if (yAxis.IsCategory()) if (yAxis.IsCategory())
{ {
var pX = AxisHelper.GetAxisPosition(grid, xAxis, value); return GetPosition(xAxis, grid, value, start);
}
else
{
return GetPosition(yAxis, grid, value, start);
}
}
private Vector3 GetPosition(Axis axis, GridCoord grid, double value, bool start)
{
if (axis is XAxis)
{
var pX = AxisHelper.GetAxisPosition(grid, axis, value);
return start ? return start ?
new Vector3(pX, grid.context.y + grid.context.height) : new Vector3(pX, grid.context.y + grid.context.height) :
new Vector3(pX, grid.context.y); new Vector3(pX, grid.context.y);
} }
else else
{ {
var pY = AxisHelper.GetAxisPosition(grid, yAxis, value); var pY = AxisHelper.GetAxisPosition(grid, axis, value);
return start ? return start ?
new Vector3(grid.context.x, pY + grid.context.height) : new Vector3(grid.context.x, pY) :
new Vector3(grid.context.x + grid.context.width, pY); new Vector3(grid.context.x + grid.context.width, pY);
} }
} }

View File

@@ -4,25 +4,34 @@ using UnityEngine;
namespace XCharts.Runtime namespace XCharts.Runtime
{ {
/// <summary> /// <summary>
/// 标线类型 /// Mark line type.
/// ||标线类型
/// </summary> /// </summary>
public enum MarkLineType public enum MarkLineType
{ {
None,
/// <summary> /// <summary>
/// 最小值。 /// Custom. You can customize the xy coordinates or values.
/// ||自定义。可自定义xy坐标或数值。
/// </summary>
Custom,
/// <summary>
/// Minimum value.
/// ||最小值。
/// </summary> /// </summary>
Min, Min,
/// <summary> /// <summary>
/// 最大值。 /// Maximum value.
/// ||最大值。
/// </summary> /// </summary>
Max, Max,
/// <summary> /// <summary>
/// 平均值。 /// Average value.
/// ||平均值。
/// </summary> /// </summary>
Average, Average,
/// <summary> /// <summary>
/// 中位数。 /// Median.
/// ||中位数。
/// </summary> /// </summary>
Median Median
} }
@@ -118,7 +127,7 @@ namespace XCharts.Runtime
[System.Serializable] [System.Serializable]
public class MarkLineData : ChildComponent public class MarkLineData : ChildComponent
{ {
[SerializeField] private MarkLineType m_Type = MarkLineType.None; [SerializeField] private MarkLineType m_Type = MarkLineType.Custom;
[SerializeField] private string m_Name; [SerializeField] private string m_Name;
[SerializeField] private int m_Dimension = 1; [SerializeField] private int m_Dimension = 1;
[SerializeField] private float m_XPosition; [SerializeField] private float m_XPosition;
@@ -170,7 +179,7 @@ namespace XCharts.Runtime
} }
/// <summary> /// <summary>
/// The x coordinate relative to the origin, in pixels. /// The x coordinate relative to the origin, in pixels.
/// ||相对原点的 x 坐标单位像素。当type为None时有效。 /// ||相对原点的 x 坐标单位像素。当type为Custom时有效。
/// </summary> /// </summary>
public float xPosition public float xPosition
{ {
@@ -179,7 +188,7 @@ namespace XCharts.Runtime
} }
/// <summary> /// <summary>
/// The y coordinate relative to the origin, in pixels. /// The y coordinate relative to the origin, in pixels.
/// ||相对原点的 y 坐标单位像素。当type为None时有效。 /// ||相对原点的 y 坐标单位像素。当type为Custom时有效。
/// </summary> /// </summary>
public float yPosition public float yPosition
{ {
@@ -188,7 +197,7 @@ namespace XCharts.Runtime
} }
/// <summary> /// <summary>
/// The value specified on the X-axis. A value specified when the X-axis is the category axis represents the index of the category axis data, otherwise a specific value. /// The value specified on the X-axis. A value specified when the X-axis is the category axis represents the index of the category axis data, otherwise a specific value.
/// ||X轴上的指定值。当X轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为None时有效。 /// ||X轴上的指定值。当X轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为Custom时有效。
/// </summary> /// </summary>
public double xValue public double xValue
{ {
@@ -197,7 +206,7 @@ namespace XCharts.Runtime
} }
/// <summary> /// <summary>
/// That's the value on the Y-axis. The value specified when the Y axis is the category axis represents the index of the category axis data, otherwise the specific value. /// That's the value on the Y-axis. The value specified when the Y axis is the category axis represents the index of the category axis data, otherwise the specific value.
/// ||Y轴上的指定值。当Y轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为None时有效。 /// ||Y轴上的指定值。当Y轴为类目轴时指定值表示类目轴数据的索引否则为具体的值。当type为Custom时有效。
/// </summary> /// </summary>
public double yValue public double yValue
{ {

View File

@@ -146,7 +146,7 @@ namespace XCharts.Runtime
data.runtimeValue = SerieHelper.GetMedianData(serie, data.dimension, dataZoom); data.runtimeValue = SerieHelper.GetMedianData(serie, data.dimension, dataZoom);
GetStartEndPos(yAxis, grid, data.runtimeValue, ref sp, ref ep); GetStartEndPos(yAxis, grid, data.runtimeValue, ref sp, ref ep);
break; break;
case MarkLineType.None: case MarkLineType.Custom:
if (data.xPosition != 0) if (data.xPosition != 0)
{ {
data.runtimeValue = data.xPosition; data.runtimeValue = data.xPosition;
@@ -292,18 +292,20 @@ namespace XCharts.Runtime
switch (data.type) switch (data.type)
{ {
case MarkLineType.Min: case MarkLineType.Min:
var serieData = SerieHelper.GetMinSerieData(serie, data.dimension, dataZoom); var serieData = SerieHelper.GetMinSerieData(serie, data.dimension, null);
data.runtimeValue = serieData.GetData(data.dimension); data.runtimeValue = serieData.GetData(data.dimension);
var pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index); var pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
var pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue); var pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
return new Vector3(pX, pY); //return new Vector3(pX, pY);
return serieData.context.position;
case MarkLineType.Max: case MarkLineType.Max:
serieData = SerieHelper.GetMaxSerieData(serie, data.dimension, dataZoom); serieData = SerieHelper.GetMaxSerieData(serie, data.dimension, null);
data.runtimeValue = serieData.GetData(data.dimension); data.runtimeValue = serieData.GetData(data.dimension);
pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index); pX = GetAxisPosition(grid, xAxis, dataZoom, serieDataCount, serieData.index);
pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue); pY = GetAxisPosition(grid, yAxis, dataZoom, serieDataCount, data.runtimeValue);
return new Vector3(pX, pY); //return new Vector3(pX, pY);
case MarkLineType.None: return serieData.context.position;
case MarkLineType.Custom:
if (data.zeroPosition) if (data.zeroPosition)
{ {
data.runtimeValue = 0; data.runtimeValue = 0;

View File

@@ -8,7 +8,7 @@ namespace XCharts.Runtime
/// ||标题组件,包含主标题和副标题。 /// ||标题组件,包含主标题和副标题。
/// </summary> /// </summary>
[Serializable] [Serializable]
[ComponentHandler(typeof(TitleHander), true)] [ComponentHandler(typeof(TitleHandler), true)]
public class Title : MainComponent, IPropertyChanged public class Title : MainComponent, IPropertyChanged
{ {
[SerializeField] private bool m_Show = true; [SerializeField] private bool m_Show = true;

View File

@@ -3,7 +3,7 @@ using UnityEngine;
namespace XCharts.Runtime namespace XCharts.Runtime
{ {
[UnityEngine.Scripting.Preserve] [UnityEngine.Scripting.Preserve]
internal sealed class TitleHander : MainComponentHandler<Title> public sealed class TitleHandler : MainComponentHandler<Title>
{ {
private static readonly string s_TitleObjectName = "title"; private static readonly string s_TitleObjectName = "title";
private static readonly string s_SubTitleObjectName = "title_sub"; private static readonly string s_SubTitleObjectName = "title_sub";
@@ -14,50 +14,68 @@ namespace XCharts.Runtime
{ {
var title = component; var title = component;
title.painter = null; title.painter = null;
title.refreshComponent = delegate() title.refreshComponent = delegate ()
{ {
title.OnChanged(); title.OnChanged();
var anchorMin = title.location.runtimeAnchorMin; var titleObject = AddTitleObject(chart, title, chart.theme.title, chart.m_PainterUpper.transform.GetSiblingIndex() + 1);
var anchorMax = title.location.runtimeAnchorMax;
var pivot = title.location.runtimePivot;
var objName = ChartCached.GetComponentObjectName(title);
var titleObject = ChartHelper.AddObject(objName, chart.transform, anchorMin, anchorMax,
pivot, chart.chartSizeDelta, -1, chart.childrenNodeNames);
title.gameObject = titleObject;
title.gameObject.transform.SetSiblingIndex(chart.m_PainterUpper.transform.GetSiblingIndex() + 1);
anchorMin = title.location.runtimeAnchorMin;
anchorMax = title.location.runtimeAnchorMax;
pivot = title.location.runtimePivot;
var fontSize = title.labelStyle.textStyle.GetFontSize(chart.theme.title);
ChartHelper.UpdateRectTransform(titleObject, anchorMin, anchorMax, pivot, new Vector2(chart.chartWidth, chart.chartHeight));
var titlePosition = chart.GetTitlePosition(title);
var subTitlePosition = -new Vector3(0, fontSize + title.itemGap, 0);
titleObject.transform.localPosition = titlePosition; m_LabelObject = AddTitleLabel(titleObject.transform, title, chart.theme.title, chart);
titleObject.hideFlags = chart.chartHideFlags; m_SubLabelObject = AddSubTitleLabel(titleObject.transform, title, chart.theme.subTitle, chart);
ChartHelper.HideAllObject(titleObject);
m_LabelObject = ChartHelper.AddChartLabel(s_TitleObjectName, titleObject.transform, title.labelStyle, chart.theme.title,
GetTitleText(title), Color.clear, title.location.runtimeTextAlignment);
m_LabelObject.SetActive(title.show && title.labelStyle.show, true);
m_SubLabelObject = ChartHelper.AddChartLabel(s_SubTitleObjectName, titleObject.transform, title.subLabelStyle, chart.theme.subTitle,
GetSubTitleText(title), Color.clear, title.location.runtimeTextAlignment);
m_SubLabelObject.SetActive(title.show && title.subLabelStyle.show, true);
m_SubLabelObject.transform.localPosition = subTitlePosition + title.subLabelStyle.offset;
}; };
title.refreshComponent(); title.refreshComponent();
} }
public static GameObject AddTitleObject(BaseGraph graph, Title title, ComponentTheme componentTheme, int titleSiblingIndex, string objectName = null)
{
var anchorMin = title.location.runtimeAnchorMin;
var anchorMax = title.location.runtimeAnchorMax;
var pivot = title.location.runtimePivot;
var objName = objectName == null ? ChartCached.GetComponentObjectName(title) : objectName;
var titleObject = ChartHelper.AddObject(objName, graph.transform, anchorMin, anchorMax,
pivot, graph.graphSizeDelta, -1, graph.childrenNodeNames);
title.gameObject = titleObject;
title.gameObject.transform.SetSiblingIndex(titleSiblingIndex);
anchorMin = title.location.runtimeAnchorMin;
anchorMax = title.location.runtimeAnchorMax;
pivot = title.location.runtimePivot;
ChartHelper.UpdateRectTransform(titleObject, anchorMin, anchorMax, pivot, new Vector2(graph.graphWidth, graph.graphHeight));
var titlePosition = graph.GetTitlePosition(title);
titleObject.transform.localPosition = titlePosition;
titleObject.hideFlags = graph.chartHideFlags;
ChartHelper.HideAllObject(titleObject);
return titleObject;
}
public static ChartLabel AddTitleLabel(Transform parent, Title title, ComponentTheme componentTheme, BaseChart chart = null)
{
var m_LabelObject = ChartHelper.AddChartLabel(s_TitleObjectName, parent, title.labelStyle, componentTheme,
GetTitleText(title, chart), Color.clear, title.location.runtimeTextAlignment);
m_LabelObject.SetActive(title.show && title.labelStyle.show, true);
return m_LabelObject;
}
public static ChartLabel AddSubTitleLabel(Transform parent, Title title, ComponentTheme componentTheme, BaseChart chart = null)
{
var fontSize = title.labelStyle.textStyle.GetFontSize(componentTheme);
var subTitlePosition = -new Vector3(0, fontSize + title.itemGap, 0);
var m_SubLabelObject = ChartHelper.AddChartLabel(s_SubTitleObjectName, parent, title.subLabelStyle, componentTheme,
GetSubTitleText(title, chart), Color.clear, title.location.runtimeTextAlignment);
m_SubLabelObject.SetActive(title.show && title.subLabelStyle.show, true);
m_SubLabelObject.transform.localPosition = subTitlePosition + title.subLabelStyle.offset;
return m_SubLabelObject;
}
public override void OnSerieDataUpdate(int serieIndex) public override void OnSerieDataUpdate(int serieIndex)
{ {
if (m_LabelObject != null && FormatterHelper.NeedFormat(component.text)) if (m_LabelObject != null && FormatterHelper.NeedFormat(component.text))
m_LabelObject.SetText(GetTitleText(component)); m_LabelObject.SetText(GetTitleText(component, chart));
if (m_SubLabelObject != null && FormatterHelper.NeedFormat(component.subText)) if (m_SubLabelObject != null && FormatterHelper.NeedFormat(component.subText))
m_SubLabelObject.SetText(GetSubTitleText(component)); m_SubLabelObject.SetText(GetSubTitleText(component, chart));
} }
private string GetTitleText(Title title) private static string GetTitleText(Title title, BaseChart chart)
{ {
if (FormatterHelper.NeedFormat(title.text)) if (FormatterHelper.NeedFormat(title.text))
{ {
@@ -71,7 +89,7 @@ namespace XCharts.Runtime
} }
} }
private string GetSubTitleText(Title title) private static string GetSubTitleText(Title title, BaseChart chart)
{ {
if (FormatterHelper.NeedFormat(title.subText)) if (FormatterHelper.NeedFormat(title.subText))
{ {

View File

@@ -255,6 +255,11 @@ namespace XCharts.Runtime
{ {
if (label == null) return; if (label == null) return;
if (double.IsNaN(axis.context.pointerValue)) return; if (double.IsNaN(axis.context.pointerValue)) return;
if (!axis.show || !axis.indicatorLabel.show)
{
label.SetActive(false, false);
return;
}
label.SetActive(true, true); label.SetActive(true, true);
label.SetTextActive(true); label.SetTextActive(true);
label.SetPosition(axis.context.pointerLabelPosition + axis.indicatorLabel.offset); label.SetPosition(axis.context.pointerLabelPosition + axis.indicatorLabel.offset);
@@ -268,7 +273,7 @@ namespace XCharts.Runtime
} }
else if (axis.IsTime()) else if (axis.IsTime())
{ {
label.SetText(axis.indicatorLabel.GetFormatterDateTime(0, 0, axis.context.pointerValue, axis.context.minValue, axis.context.maxValue)); label.SetText(axis.indicatorLabel.GetFormatterDateTime(0, 0, axis.context.pointerValue, axis.context.minValue, axis.context.maxValue, !chart.useUtc));
} }
else else
{ {
@@ -356,7 +361,7 @@ namespace XCharts.Runtime
if (isTriggerAxis) if (isTriggerAxis)
{ {
var index = serie.context.dataZoomStartIndex + (int)yAxis.context.pointerValue; var index = serie.context.dataZoomStartIndex + (int)yAxis.context.pointerValue;
if(serie.useSortData) index = yAxis.context.sortedDataIndices[index]; if (serie.useSortData) index = yAxis.context.sortedDataIndices[index];
serie.context.pointerEnter = true; serie.context.pointerEnter = true;
serie.context.pointerAxisDataIndexs.Add(index); serie.context.pointerAxisDataIndexs.Add(index);
serie.context.pointerItemDataIndex = index; serie.context.pointerItemDataIndex = index;
@@ -376,7 +381,7 @@ namespace XCharts.Runtime
if (isTriggerAxis) if (isTriggerAxis)
{ {
var index = serie.context.dataZoomStartIndex + (int)xAxis.context.pointerValue; var index = serie.context.dataZoomStartIndex + (int)xAxis.context.pointerValue;
if(serie.useSortData) index = xAxis.context.sortedDataIndices[index]; if (serie.useSortData) index = xAxis.context.sortedDataIndices[index];
if (chart.isTriggerOnClick) if (chart.isTriggerOnClick)
{ {
if (serie.insertDataToHead) if (serie.insertDataToHead)
@@ -473,13 +478,25 @@ namespace XCharts.Runtime
{ {
var serieData = data[i]; var serieData = data[i];
currValue = serieData.GetData(dimension); currValue = serieData.GetData(dimension);
if (i == 0 && i + 1 < dataCount) if (i == 0)
{ {
nextValue = data[i + 1].GetData(dimension); if (i + 1 < dataCount)
if (axisValue <= currValue + (nextValue - currValue) / 2)
{ {
serie.context.pointerAxisDataIndexs.Add(serieData.index); nextValue = data[i + 1].GetData(dimension);
break; if (axisValue <= currValue + (nextValue - currValue) / 2)
{
serie.context.pointerAxisDataIndexs.Add(serieData.index);
break;
}
}
else
{
var diff = axis.context.tickValue * 0.5f;
if (axisValue >= currValue - diff && axisValue <= currValue + diff)
{
serie.context.pointerAxisDataIndexs.Add(serieData.index);
break;
}
} }
} }
else if (i == dataCount - 1) else if (i == dataCount - 1)
@@ -616,7 +633,21 @@ namespace XCharts.Runtime
var serieData = serie.GetSerieData(serie.context.pointerItemDataIndex); var serieData = serie.GetSerieData(serie.context.pointerItemDataIndex);
if (serieData != null) if (serieData != null)
{ {
tooltip.context.data.title = DateTimeUtil.GetDefaultDateTimeString((int)serieData.GetData(0), axisRange); var value = (int)serieData.GetData(0);
if (string.IsNullOrEmpty(tooltip.titleLabelStyle.numericFormatter))
tooltip.context.data.title = DateTimeUtil.GetDefaultDateTimeString(value, axisRange, !chart.useUtc);
else
{
var dateTime = DateTimeUtil.GetDateTime(value, !chart.useUtc);
try
{
tooltip.context.data.title = dateTime.ToString(tooltip.titleLabelStyle.numericFormatter);
}
catch
{
tooltip.context.data.title = DateTimeUtil.GetDefaultDateTimeString(value, axisRange, !chart.useUtc);
}
}
} }
} }
serie.handler.UpdateTooltipSerieParams(dataIndex, showCategory, category, serie.handler.UpdateTooltipSerieParams(dataIndex, showCategory, category,
@@ -706,6 +737,7 @@ namespace XCharts.Runtime
private void DrawXAxisIndicator(VertexHelper vh, Tooltip tooltip, GridCoord grid) private void DrawXAxisIndicator(VertexHelper vh, Tooltip tooltip, GridCoord grid)
{ {
if (!tooltip.lineStyle.show) return;
var xAxes = chart.GetChartComponents<XAxis>(); var xAxes = chart.GetChartComponents<XAxis>();
var lineType = tooltip.lineStyle.GetType(chart.theme.tooltip.lineType); var lineType = tooltip.lineStyle.GetType(chart.theme.tooltip.lineType);
var lineWidth = tooltip.lineStyle.GetWidth(chart.theme.tooltip.lineWidth); var lineWidth = tooltip.lineStyle.GetWidth(chart.theme.tooltip.lineWidth);

View File

@@ -16,8 +16,9 @@ namespace XCharts.Runtime
else else
{ {
tooltip.context.data.title = tooltip.titleFormatter; tooltip.context.data.title = tooltip.titleFormatter;
FormatterHelper.ReplaceContent(ref tooltip.context.data.title, -1, var numericFormatter = string.IsNullOrEmpty(tooltip.titleLabelStyle.numericFormatter)
tooltip.numericFormatter, null, chart); ? tooltip.numericFormatter : tooltip.titleLabelStyle.numericFormatter;
FormatterHelper.ReplaceContent(ref tooltip.context.data.title, -1, numericFormatter, null, chart);
} }
} }
for (int i = tooltip.context.data.param.Count - 1; i >= 0; i--) for (int i = tooltip.context.data.param.Count - 1; i >= 0; i--)
@@ -56,7 +57,7 @@ namespace XCharts.Runtime
public static bool IsIgnoreFormatter(string itemFormatter) public static bool IsIgnoreFormatter(string itemFormatter)
{ {
return "-".Equals(itemFormatter) ||"{i}".Equals(itemFormatter, StringComparison.CurrentCultureIgnoreCase); return "-".Equals(itemFormatter) || "{i}".Equals(itemFormatter, StringComparison.CurrentCultureIgnoreCase);
} }
public static void LimitInRect(BaseChart chart, Tooltip tooltip, Rect chartRect) public static void LimitInRect(BaseChart chart, Tooltip tooltip, Rect chartRect)

View File

@@ -12,7 +12,7 @@ namespace XCharts.Runtime
{ {
var grid = component; var grid = component;
grid.painter = chart.painter; grid.painter = chart.painter;
grid.refreshComponent = delegate() grid.refreshComponent = delegate ()
{ {
grid.UpdateRuntimeData(chart); grid.UpdateRuntimeData(chart);
chart.OnCoordinateChanged(); chart.OnCoordinateChanged();
@@ -51,6 +51,7 @@ namespace XCharts.Runtime
public override void DrawBase(VertexHelper vh) public override void DrawBase(VertexHelper vh)
{ {
DrawBackground(vh, component);
if (!SeriesHelper.IsAnyClipSerie(chart.series)) if (!SeriesHelper.IsAnyClipSerie(chart.series))
{ {
DrawCoord(vh, component); DrawCoord(vh, component);
@@ -64,7 +65,7 @@ namespace XCharts.Runtime
} }
} }
private void DrawCoord(VertexHelper vh, GridCoord grid) private void DrawBackground(VertexHelper vh, GridCoord grid)
{ {
if (!grid.show) return; if (!grid.show) return;
if (!ChartHelper.IsClearColor(grid.backgroundColor)) if (!ChartHelper.IsClearColor(grid.backgroundColor))
@@ -75,6 +76,11 @@ namespace XCharts.Runtime
var p4 = new Vector2(grid.context.x + grid.context.width, grid.context.y); var p4 = new Vector2(grid.context.x + grid.context.width, grid.context.y);
UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, grid.backgroundColor); UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, grid.backgroundColor);
} }
}
private void DrawCoord(VertexHelper vh, GridCoord grid)
{
if (!grid.show) return;
if (grid.showBorder) if (grid.showBorder)
{ {
var borderWidth = grid.borderWidth == 0 ? chart.theme.axis.lineWidth * 2 : grid.borderWidth; var borderWidth = grid.borderWidth == 0 ? chart.theme.axis.lineWidth * 2 : grid.borderWidth;

View File

@@ -37,7 +37,7 @@ namespace XCharts.Runtime
/// <param name="category">选中的类目,一般用在折线图和柱状图</param> /// <param name="category">选中的类目,一般用在折线图和柱状图</param>
/// <returns></returns> /// <returns></returns>
public static bool ReplaceContent(ref string content, int dataIndex, string numericFormatter, Serie serie, public static bool ReplaceContent(ref string content, int dataIndex, string numericFormatter, Serie serie,
BaseChart chart, string colorName = null) BaseChart chart, string colorName = null, SerieData serieData = null)
{ {
var foundDot = false; var foundDot = false;
var mc = s_Regex.Matches(content); var mc = s_Regex.Matches(content);
@@ -112,7 +112,7 @@ namespace XCharts.Runtime
} }
else else
{ {
var serieData = serie.GetSerieData(bIndex); serieData = serie.GetSerieData(bIndex);
content = content.Replace(old, serieData.name); content = content.Replace(old, serieData.name);
} }
} }
@@ -207,12 +207,17 @@ namespace XCharts.Runtime
} }
} }
} }
if (serieData != null)
{
ReplaceIndexContent(ref content, serie.useSortData ? serieData.sortIndex : serieData.index, serie.dataCount);
}
content = s_RegexNewLine.Replace(content, PH_NN); content = s_RegexNewLine.Replace(content, PH_NN);
return foundDot; return foundDot;
} }
public static void ReplaceSerieLabelContent(ref string content, string numericFormatter, int dataCount, double value, double total, public static void ReplaceSerieLabelContent(ref string content, string numericFormatter, int dataCount, double value, double total,
string serieName, string category, string dataName, Color color, SerieData serieData, BaseChart chart = null, int serieIndex = 0) string serieName, string category, string dataName, Color color, SerieData serieData, BaseChart chart = null, int serieIndex = 0,
bool sortData = false)
{ {
var mc = s_RegexForSerieLabel.Matches(content); var mc = s_RegexForSerieLabel.Matches(content);
foreach (var m in mc) foreach (var m in mc)
@@ -309,6 +314,10 @@ namespace XCharts.Runtime
} }
} }
} }
if (serieData != null)
{
ReplaceIndexContent(ref content, sortData ? serieData.sortIndex : serieData.index, dataCount);
}
content = TrimAndReplaceLine(content); content = TrimAndReplaceLine(content);
} }

View File

@@ -31,6 +31,11 @@ namespace XCharts.Runtime
} }
} }
/// <summary> /// <summary>
/// Whether to use UTC time for the chart.
/// ||图表的时间是否都显示为UTC时间。
/// </summary>
public bool useUtc { get { return m_UseUtc; } set { m_UseUtc = value; } }
/// <summary>
/// The theme. /// The theme.
/// ||</summary> /// ||</summary>
public ThemeStyle theme { get { return m_Theme; } set { m_Theme = value; } } public ThemeStyle theme { get { return m_Theme; } set { m_Theme = value; } }
@@ -69,6 +74,7 @@ namespace XCharts.Runtime
/// </summary> /// </summary>
public Vector3 chartPosition { get { return m_ChartPosition; } } public Vector3 chartPosition { get { return m_ChartPosition; } }
public Rect chartRect { get { return m_ChartRect; } } public Rect chartRect { get { return m_ChartRect; } }
public Painter topPainter { get { return m_PainterTop; } }
/// <summary> /// <summary>
/// The callback function of chart init. /// The callback function of chart init.
/// ||图表的初始化完成回调。 /// ||图表的初始化完成回调。
@@ -587,11 +593,6 @@ namespace XCharts.Runtime
} }
} }
public Vector3 GetTitlePosition(Title title)
{
return chartPosition + title.location.GetPosition(chartWidth, chartHeight);
}
public int GetLegendRealShowNameIndex(string name) public int GetLegendRealShowNameIndex(string name)
{ {
return m_LegendRealShowName.IndexOf(name); return m_LegendRealShowName.IndexOf(name);

View File

@@ -429,6 +429,19 @@ namespace XCharts.Runtime
return true; return true;
} }
public Axis GetMainAxis()
{
foreach (var component in m_Components)
{
if (component is Axis)
{
var axis = component as Axis;
if (axis.show && axis.mainAxis) return axis;
}
}
return null;
}
/// <summary> /// <summary>
/// 纯类目轴。 /// 纯类目轴。
/// </summary> /// </summary>
@@ -483,7 +496,15 @@ namespace XCharts.Runtime
relativedAxis = null; relativedAxis = null;
return false; return false;
} }
var isY = yAxis.IsCategory() && !xAxis.IsCategory(); bool isY;
if (xAxis.type == yAxis.type)
{
isY = yAxis.mainAxis;
}
else
{
isY = yAxis.IsCategory() && !xAxis.IsCategory();
}
if (isY) if (isY)
{ {
axis = yAxis; axis = yAxis;

View File

@@ -11,33 +11,61 @@ namespace XCharts.Runtime
public virtual void GetSeriesMinMaxValue(Axis axis, int axisIndex, out double tempMinValue, out double tempMaxValue) public virtual void GetSeriesMinMaxValue(Axis axis, int axisIndex, out double tempMinValue, out double tempMaxValue)
{ {
var needAnimationData = !axis.context.needAnimation; var needAnimationData = !axis.context.needAnimation;
bool isX = false, isY = false, isZ = false;
tempMinValue = 0;
tempMaxValue = 0;
if (axis is XAxis3D) if (axis is XAxis3D)
{ isX = true;
SeriesHelper.GetXMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData);
}
else if (axis is ZAxis3D) else if (axis is ZAxis3D)
{ {
SeriesHelper.GetZMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData); isZ = true;
} }
else if (axis is YAxis3D) else if (axis is YAxis3D)
{ {
SeriesHelper.GetYMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData); isY = true;
} }
else if (IsAllAxisValue()) else if (IsAllAxisValue())
{ {
if (axis is XAxis) var mainAxis = GetMainAxis();
if (mainAxis == null)
{ {
SeriesHelper.GetXMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData); if (axis is XAxis)
{
isX = true;
}
else
{
isY = true;
}
} }
else else
{ {
SeriesHelper.GetYMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData); if (axis == mainAxis)
{
isX = true;
}
else
{
isY = true;
}
} }
} }
else else
{
isY = true;
}
if (isX)
{
SeriesHelper.GetXMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData);
}
else if (isY)
{ {
SeriesHelper.GetYMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData); SeriesHelper.GetYMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData);
} }
else if(isZ)
{
SeriesHelper.GetZMinMaxValue(this, axisIndex, axis.inverse, out tempMinValue, out tempMaxValue, false, false, needAnimationData);
}
AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true); AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true);
} }
} }

View File

@@ -16,6 +16,7 @@ namespace XCharts.Runtime
public partial class BaseChart : BaseGraph, ISerializationCallbackReceiver public partial class BaseChart : BaseGraph, ISerializationCallbackReceiver
{ {
[SerializeField] protected string m_ChartName; [SerializeField] protected string m_ChartName;
[SerializeField] protected bool m_UseUtc = true;
[SerializeField] protected ThemeStyle m_Theme = new ThemeStyle(); [SerializeField] protected ThemeStyle m_Theme = new ThemeStyle();
[SerializeField] protected Settings m_Settings; [SerializeField] protected Settings m_Settings;
[SerializeField] protected DebugInfo m_DebugInfo = new DebugInfo(); [SerializeField] protected DebugInfo m_DebugInfo = new DebugInfo();
@@ -204,7 +205,7 @@ namespace XCharts.Runtime
protected override void OnValidate() protected override void OnValidate()
{ {
base.OnValidate(); base.OnValidate();
foreach (var handler in m_SerieHandlers) handler.ForceUpdateSerieContext(); ResetChartStatus();
} }
#endif #endif
@@ -626,6 +627,8 @@ namespace XCharts.Runtime
vh.Clear(); vh.Clear();
var maxPainter = settings.maxPainter; var maxPainter = settings.maxPainter;
var maxSeries = m_Series.Count; var maxSeries = m_Series.Count;
if (painter == null || painter.index < 0 || painter.index >= maxPainter)
return;
var rate = Mathf.CeilToInt(maxSeries * 1.0f / maxPainter); var rate = Mathf.CeilToInt(maxSeries * 1.0f / maxPainter);
m_PainterUpper.Refresh(); m_PainterUpper.Refresh();
m_PainterTop.Refresh(); m_PainterTop.Refresh();

View File

@@ -209,15 +209,25 @@ namespace XCharts.Runtime
/// </summary> /// </summary>
/// <param name="imageType">type of image: png, jpg, exr</param> /// <param name="imageType">type of image: png, jpg, exr</param>
/// <param name="savePath">save path</param> /// <param name="savePath">save path</param>
public void SaveAsImage(string imageType = "png", string savePath = "") /// <param name="exportScale">export resolution scale. 1 means original size</param>
/// <param name="useRecursiveBackgroundColor">whether to recursively use lower-level UI background color</param>
public void SaveAsImage(string imageType = "png", string savePath = "", float exportScale = 1f,
bool useRecursiveBackgroundColor = false)
{ {
StartCoroutine(SaveAsImageSync(imageType, savePath)); StartCoroutine(SaveAsImageSync(imageType, savePath, exportScale, useRecursiveBackgroundColor));
} }
private IEnumerator SaveAsImageSync(string imageType, string path) private IEnumerator SaveAsImageSync(string imageType, string path, float exportScale,
bool useRecursiveBackgroundColor)
{ {
yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame();
ChartHelper.SaveAsImage(rectTransform, canvas, imageType, path); ChartHelper.SaveAsImage(rectTransform, canvas, imageType, path, exportScale,
useRecursiveBackgroundColor);
}
public Vector3 GetTitlePosition(Title title)
{
return graphPosition + title.location.GetPosition(graphWidth, graphHeight);
} }
} }
} }

View File

@@ -53,6 +53,11 @@ namespace XCharts.Runtime
} }
} }
public bool InRect(Vector2 local)
{
return rect.Contains(local);
}
protected override void Awake() protected override void Awake()
{ {
raycastTarget = false; raycastTarget = false;
@@ -183,6 +188,7 @@ namespace XCharts.Runtime
public void SetPosition(Vector3 position) public void SetPosition(Vector3 position)
{ {
transform.localPosition = position; transform.localPosition = position;
UpdateRect();
} }
public void SetRectPosition(Vector3 position) public void SetRectPosition(Vector3 position)
@@ -264,6 +270,45 @@ namespace XCharts.Runtime
m_Width = sizeDelta.x + m_PaddingLeft + m_PaddingRight; m_Width = sizeDelta.x + m_PaddingLeft + m_PaddingRight;
m_Height = sizeDelta.y + m_PaddingTop + m_PaddingBottom; m_Height = sizeDelta.y + m_PaddingTop + m_PaddingBottom;
objectRect.sizeDelta = new Vector2(m_Width, m_Height); objectRect.sizeDelta = new Vector2(m_Width, m_Height);
UpdateRect();
}
}
private void UpdateRect()
{
if (m_TextRect == null) return;
switch (text.alignment)
{
case TextAnchor.LowerLeft:
rect = new Rect(transform.localPosition.x, transform.localPosition.y, m_Width, m_Height);
break;
case TextAnchor.UpperLeft:
rect = new Rect(transform.localPosition.x, transform.localPosition.y - m_Height, m_Width, m_Height);
break;
case TextAnchor.MiddleLeft:
rect = new Rect(transform.localPosition.x, transform.localPosition.y - m_Height / 2, m_Width, m_Height);
break;
case TextAnchor.LowerRight:
rect = new Rect(transform.localPosition.x - m_Width, transform.localPosition.y, m_Width, m_Height);
break;
case TextAnchor.UpperRight:
rect = new Rect(transform.localPosition.x - m_Width, transform.localPosition.y - m_Height, m_Width, m_Height);
break;
case TextAnchor.MiddleRight:
rect = new Rect(transform.localPosition.x - m_Width, transform.localPosition.y - m_Height / 2, m_Width, m_Height);
break;
case TextAnchor.LowerCenter:
rect = new Rect(transform.localPosition.x - m_Width / 2, transform.localPosition.y, m_Width, m_Height);
break;
case TextAnchor.UpperCenter:
rect = new Rect(transform.localPosition.x - m_Width / 2, transform.localPosition.y - m_Height, m_Width, m_Height);
break;
case TextAnchor.MiddleCenter:
rect = new Rect(transform.localPosition.x - m_Width / 2, transform.localPosition.y - m_Height / 2, m_Width, m_Height);
break;
default:
rect = new Rect(transform.localPosition.x - m_Width / 2, transform.localPosition.y - m_Height / 2, m_Width, m_Height);
break;
} }
} }

View File

@@ -18,7 +18,11 @@ namespace XCharts.Runtime
protected bool m_Refresh; protected bool m_Refresh;
protected Action<VertexHelper, Painter> m_OnPopulateMesh; protected Action<VertexHelper, Painter> m_OnPopulateMesh;
public Action<VertexHelper, Painter> onPopulateMesh { set { m_OnPopulateMesh = value; } } public Action<VertexHelper, Painter> onPopulateMesh
{
get { return m_OnPopulateMesh; }
set { m_OnPopulateMesh = value; }
}
public int index { get { return m_Index; } set { m_Index = value; } } public int index { get { return m_Index; } set { m_Index = value; } }
public Type type { get { return m_Type; } set { m_Type = value; } } public Type type { get { return m_Type; } set { m_Type = value; } }
public void Refresh() public void Refresh()

View File

@@ -100,9 +100,9 @@ namespace XCharts.Runtime
return NumberToStr(value, numericFormatter); return NumberToStr(value, numericFormatter);
} }
public static string NumberToDateStr(double timestamp, string formatter) public static string NumberToDateStr(double timestamp, string formatter, bool local = false)
{ {
var dt = NumberToDateTime(timestamp); var dt = NumberToDateTime(timestamp, local);
try try
{ {
return dt.ToString(formatter, ci); return dt.ToString(formatter, ci);
@@ -132,11 +132,11 @@ namespace XCharts.Runtime
} }
} }
public static DateTime NumberToDateTime(double timestamp) public static DateTime NumberToDateTime(double timestamp, bool local = false)
{ {
if (!s_TimestampToDateTimeDict.ContainsKey(timestamp)) if (!s_TimestampToDateTimeDict.ContainsKey(timestamp))
{ {
s_TimestampToDateTimeDict[timestamp] = DateTimeUtil.GetDateTime(timestamp); s_TimestampToDateTimeDict[timestamp] = DateTimeUtil.GetDateTime(timestamp, local);
} }
return s_TimestampToDateTimeDict[timestamp]; return s_TimestampToDateTimeDict[timestamp];
} }
@@ -200,7 +200,7 @@ namespace XCharts.Runtime
return s_StringIntDict[prefix][suffix]; return s_StringIntDict[prefix][suffix];
} }
internal static string GetComponentObjectName(MainComponent component) public static string GetComponentObjectName(MainComponent component)
{ {
Dictionary<int, string> dict; Dictionary<int, string> dict;
var type = component.GetType(); var type = component.GetType();
@@ -224,7 +224,7 @@ namespace XCharts.Runtime
} }
} }
internal static string GetAxisLabelName(int index) public static string GetAxisLabelName(int index)
{ {
string name; string name;
if (!s_AxisLabelName.TryGetValue(index, out name)) if (!s_AxisLabelName.TryGetValue(index, out name))
@@ -239,12 +239,12 @@ namespace XCharts.Runtime
} }
} }
internal static string GetTypeName<T>() public static string GetTypeName<T>()
{ {
return GetTypeName(typeof(T)); return GetTypeName(typeof(T));
} }
internal static string GetTypeName(Type type) public static string GetTypeName(Type type)
{ {
if (s_TypeName.ContainsKey(type)) return s_TypeName[type]; if (s_TypeName.ContainsKey(type)) return s_TypeName[type];
else else

View File

@@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using XUGL;
#if dUI_TextMeshPro #if dUI_TextMeshPro
using TMPro; using TMPro;
#endif #endif
@@ -461,7 +462,7 @@ namespace XCharts.Runtime
{ {
var textStyle = axis.axisLabel.textStyle; var textStyle = axis.axisLabel.textStyle;
var label = AddChartLabel(name, parent, axis.axisLabel, theme, content, autoColor, autoAlignment); var label = AddChartLabel(name, parent, axis.axisLabel, theme, content, autoColor, autoAlignment);
var labelShow = axis.IsNeedShowLabel(index, total); var labelShow = axis.IsNeedShowLabel(index, total, content);
label.UpdateIcon(axis.axisLabel.icon, axis.GetIcon(index), iconDefaultColor); label.UpdateIcon(axis.axisLabel.icon, axis.GetIcon(index), iconDefaultColor);
label.text.SetActive(labelShow); label.text.SetActive(labelShow);
return label; return label;
@@ -1060,34 +1061,383 @@ namespace XCharts.Runtime
private static extern void Download(string base64str, string fileName); private static extern void Download(string base64str, string fileName);
#endif #endif
public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png", string path = "") private static void SetLayerRecursively(GameObject obj, int layer)
{
if (obj == null) return;
obj.layer = layer;
var trans = obj.transform;
for (int i = 0; i < trans.childCount; i++)
{
SetLayerRecursively(trans.GetChild(i).gameObject, layer);
}
}
private static void CloneChildrenRecursively(Transform source, Transform targetParent, int layer)
{
if (source == null || targetParent == null) return;
for (int i = 0; i < source.childCount; i++)
{
var child = source.GetChild(i);
var childClone = GameObject.Instantiate(child.gameObject, targetParent, false);
SetLayerRecursively(childClone, layer);
SyncPainterCallbacks(child, childClone.transform);
}
}
private static void SyncPainterCallbacks(Transform source, Transform clone)
{
if (source == null || clone == null) return;
var sourcePainter = source.GetComponent<Painter>();
var clonePainter = clone.GetComponent<Painter>();
if (sourcePainter != null && clonePainter != null)
{
clonePainter.onPopulateMesh = sourcePainter.onPopulateMesh;
clonePainter.index = sourcePainter.index;
clonePainter.type = sourcePainter.type;
clonePainter.material = sourcePainter.material;
clonePainter.Refresh();
}
var count = Mathf.Min(source.childCount, clone.childCount);
for (int i = 0; i < count; i++)
{
SyncPainterCallbacks(source.GetChild(i), clone.GetChild(i));
}
}
private static void DestroyObject(GameObject obj)
{
if (obj == null) return;
#if UNITY_EDITOR
if (!Application.isPlaying)
GameObject.DestroyImmediate(obj, true);
else
GameObject.Destroy(obj);
#else
GameObject.Destroy(obj);
#endif
}
private static byte[] EncodeImage(Texture2D tex, string imageType)
{ {
var cam = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera;
var pos = RectTransformUtility.WorldToScreenPoint(cam, rectTransform.position);
var width = (int)(rectTransform.rect.width * canvas.scaleFactor);
var height = (int)(rectTransform.rect.height * canvas.scaleFactor);
var posX = pos.x + rectTransform.rect.xMin * canvas.scaleFactor;
var posY = pos.y + rectTransform.rect.yMin * canvas.scaleFactor;
var rect = new Rect(posX, posY, width, height);
var tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
tex.ReadPixels(rect, 0, 0);
tex.Apply();
byte[] bytes;
switch (imageType) switch (imageType)
{ {
case "png": case "png":
bytes = tex.EncodeToPNG(); return tex.EncodeToPNG();
break;
case "jpg": case "jpg":
bytes = tex.EncodeToJPG(); return tex.EncodeToJPG();
break;
case "exr": case "exr":
bytes = tex.EncodeToEXR(); return tex.EncodeToEXR();
break;
default: default:
Debug.LogError("SaveAsImage ERROR: not support image type:" + imageType); Debug.LogError("SaveAsImage ERROR: not support image type:" + imageType);
return null; return null;
} }
}
private static float[] GetChartCornerRadius(BaseChart chart, float chartWidth, float chartHeight, float scaleFactor)
{
if (chart == null || chartWidth <= 0 || chartHeight <= 0)
return null;
var background = chart.GetChartComponent<Background>();
if (background == null || background.borderStyle == null || !background.borderStyle.roundedCorner)
return null;
var cornerRadius = background.borderStyle.cornerRadius;
if (cornerRadius == null || cornerRadius.Length == 0)
return null;
float brLt = 0, brRt = 0, brRb = 0, brLb = 0;
bool needRound = false;
UGL.InitCornerRadius(cornerRadius, chartWidth, chartHeight, false, false,
ref brLt, ref brRt, ref brRb, ref brLb, ref needRound);
if (!needRound)
return null;
return new float[]
{
brLt * scaleFactor,
brRt * scaleFactor,
brRb * scaleFactor,
brLb * scaleFactor
};
}
private static float GetRoundedRectCoverage(float x, float y, float width, float height,
float radiusLt, float radiusRt, float radiusRb, float radiusLb, float aaWidth = 1f)
{
if (radiusLb > 0 && x < radiusLb && y < radiusLb)
{
var dx = x - radiusLb;
var dy = y - radiusLb;
var dist = Mathf.Sqrt(dx * dx + dy * dy);
var delta = radiusLb - dist;
if (delta >= aaWidth) return 1f;
if (delta <= -aaWidth) return 0f;
return Mathf.Clamp01((delta + aaWidth) / (2f * aaWidth));
}
if (radiusLt > 0 && x < radiusLt && y > height - radiusLt)
{
var dx = x - radiusLt;
var dy = y - (height - radiusLt);
var dist = Mathf.Sqrt(dx * dx + dy * dy);
var delta = radiusLt - dist;
if (delta >= aaWidth) return 1f;
if (delta <= -aaWidth) return 0f;
return Mathf.Clamp01((delta + aaWidth) / (2f * aaWidth));
}
if (radiusRt > 0 && x > width - radiusRt && y > height - radiusRt)
{
var dx = x - (width - radiusRt);
var dy = y - (height - radiusRt);
var dist = Mathf.Sqrt(dx * dx + dy * dy);
var delta = radiusRt - dist;
if (delta >= aaWidth) return 1f;
if (delta <= -aaWidth) return 0f;
return Mathf.Clamp01((delta + aaWidth) / (2f * aaWidth));
}
if (radiusRb > 0 && x > width - radiusRb && y < radiusRb)
{
var dx = x - (width - radiusRb);
var dy = y - radiusRb;
var dist = Mathf.Sqrt(dx * dx + dy * dy);
var delta = radiusRb - dist;
if (delta >= aaWidth) return 1f;
if (delta <= -aaWidth) return 0f;
return Mathf.Clamp01((delta + aaWidth) / (2f * aaWidth));
}
return 1f;
}
private static void ApplyRoundedCornerClip(Texture2D tex, float[] cornerRadii)
{
if (tex == null || cornerRadii == null || cornerRadii.Length < 4)
return;
var width = tex.width;
var height = tex.height;
if (width <= 0 || height <= 0)
return;
var radiusLt = Mathf.Max(0, cornerRadii[0]);
var radiusRt = Mathf.Max(0, cornerRadii[1]);
var radiusRb = Mathf.Max(0, cornerRadii[2]);
var radiusLb = Mathf.Max(0, cornerRadii[3]);
if (radiusLt <= 0 && radiusRt <= 0 && radiusRb <= 0 && radiusLb <= 0)
return;
var colors = tex.GetPixels32();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
var px = x + 0.5f;
var py = y + 0.5f;
var coverage = GetRoundedRectCoverage(px, py, width, height,
radiusLt, radiusRt, radiusRb, radiusLb, 1f);
if (coverage <= 0f)
{
var index = y * width + x;
var color = colors[index];
color.a = 0;
colors[index] = color;
}
else if (coverage < 1f)
{
var index = y * width + x;
var color = colors[index];
color.a = (byte)Mathf.Clamp(Mathf.RoundToInt(color.a * coverage), 0, 255);
colors[index] = color;
}
}
}
tex.SetPixels32(colors);
tex.Apply();
}
private static Color32 GetBackgroundColorRecursive(Transform parent)
{
if (parent == null) return new Color32(255, 255, 255, 255);
// Try to find Image components with colors in child nodes
for (int i = 0; i < parent.childCount; i++)
{
var child = parent.GetChild(i);
var image = child.GetComponent<Image>();
if (image != null && image.enabled && child.gameObject.activeInHierarchy)
{
var color = image.color;
if (color.a > 0)
{
// Found a visible background image
color.a = 1f; // Make it fully opaque for proper blending
return color;
}
}
// Recursively search child nodes
var foundColor = GetBackgroundColorRecursive(child);
if (foundColor.a > 0)
return foundColor;
}
return Color.white;
}
public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png",
string path = "", float exportScale = 1f, bool useRecursiveBackgroundColor = false)
{
if (rectTransform == null || canvas == null)
return null;
var clampedExportScale = Mathf.Max(1f, exportScale);
var scaleFactor = canvas.scaleFactor <= 0 ? 1f : canvas.scaleFactor;
var outputScaleFactor = scaleFactor * clampedExportScale;
var width = Mathf.Max(1, Mathf.CeilToInt(rectTransform.rect.width * outputScaleFactor));
var height = Mathf.Max(1, Mathf.CeilToInt(rectTransform.rect.height * outputScaleFactor));
var chart = rectTransform.GetComponent<BaseChart>();
var cornerRadii = GetChartCornerRadius(chart, rectTransform.rect.width, rectTransform.rect.height, outputScaleFactor);
Texture2D tex = null;
var rt = RenderTexture.GetTemporary(width, height, 24, RenderTextureFormat.ARGB32);
var antiAliasing = QualitySettings.antiAliasing > 0 ? QualitySettings.antiAliasing : 4;
rt.antiAliasing = Mathf.Clamp(antiAliasing, 1, 8);
var oldActive = RenderTexture.active;
var captureLayer = 31;
var rootObj = new GameObject("xcharts_save_image_root");
var camObj = new GameObject("xcharts_save_image_camera");
var canvasObj = new GameObject("xcharts_save_image_canvas");
var contentObj = new GameObject("xcharts_save_image_content", typeof(RectTransform));
try
{
SetLayerRecursively(rootObj, captureLayer);
SetLayerRecursively(camObj, captureLayer);
SetLayerRecursively(canvasObj, captureLayer);
SetLayerRecursively(contentObj, captureLayer);
camObj.transform.SetParent(rootObj.transform, false);
var camera = camObj.AddComponent<Camera>();
camera.clearFlags = CameraClearFlags.SolidColor;
// Get background color - try multiple sources for better results
Color32 bgColor = new Color32(255, 255, 255, 255);
var chartParent = rectTransform.parent;
// First, try to get from chart's Background component
if (chart != null)
{
bgColor = chart.GetChartBackgroundColor();
//bgColor.a = 255;
}
// If enabled, find background color recursively from sibling nodes
if (useRecursiveBackgroundColor && (bgColor.a < 255 ||
(bgColor.r == 255 && bgColor.g == 255 && bgColor.b == 255)))
{
var siblingBgColor = GetBackgroundColorRecursive(chartParent);
if (siblingBgColor.a > 0)
bgColor = siblingBgColor;
}
camera.backgroundColor = bgColor;
camera.cullingMask = 1 << captureLayer;
camera.orthographic = true;
camera.orthographicSize = height / 2f;
camera.nearClipPlane = -100;
camera.farClipPlane = 100;
camera.allowHDR = false;
camera.allowMSAA = rt.antiAliasing > 1;
camera.targetTexture = rt;
canvasObj.transform.SetParent(rootObj.transform, false);
var captureCanvas = canvasObj.AddComponent<Canvas>();
captureCanvas.renderMode = RenderMode.ScreenSpaceCamera;
captureCanvas.worldCamera = camera;
captureCanvas.planeDistance = 1;
captureCanvas.pixelPerfect = canvas.pixelPerfect;
captureCanvas.sortingOrder = 0;
canvasObj.AddComponent<GraphicRaycaster>();
var canvasRect = canvasObj.GetComponent<RectTransform>();
canvasRect.anchorMin = Vector2.zero;
canvasRect.anchorMax = Vector2.one;
canvasRect.pivot = new Vector2(0.5f, 0.5f);
canvasRect.anchoredPosition = Vector2.zero;
canvasRect.sizeDelta = new Vector2(width, height);
contentObj.transform.SetParent(canvasObj.transform, false);
var contentRect = contentObj.GetComponent<RectTransform>();
contentRect.anchorMin = new Vector2(0.5f, 0.5f);
contentRect.anchorMax = new Vector2(0.5f, 0.5f);
contentRect.pivot = rectTransform.pivot;
contentRect.anchoredPosition = Vector2.zero;
contentRect.sizeDelta = rectTransform.rect.size;
contentRect.localScale = new Vector3(clampedExportScale, clampedExportScale, 1f);
// Clone sibling nodes (including background layers below chart)
var chartSiblingIndex = rectTransform.GetSiblingIndex();
if (chartParent != null)
{
for (int i = 0; i < chartParent.childCount; i++)
{
var sibling = chartParent.GetChild(i);
// Only clone siblings below the chart (smaller sibling index)
if (i < chartSiblingIndex)
{
var siblingClone = GameObject.Instantiate(sibling.gameObject, contentObj.transform, false);
SetLayerRecursively(siblingClone, captureLayer);
}
}
}
CloneChildrenRecursively(rectTransform, contentObj.transform, captureLayer);
Canvas.ForceUpdateCanvases();
camera.Render();
RenderTexture.active = rt;
// If exportScale > 1 we want to save the image back to the original logical
// size (option B): render at higher density, then downscale to target pixels
// so the saved image has original width/height but higher quality.
if (clampedExportScale > 1f)
{
var targetWidth = Mathf.Max(1, Mathf.CeilToInt(rectTransform.rect.width * scaleFactor));
var targetHeight = Mathf.Max(1, Mathf.CeilToInt(rectTransform.rect.height * scaleFactor));
var smallRT = RenderTexture.GetTemporary(targetWidth, targetHeight, 0, rt.format);
Graphics.Blit(rt, smallRT);
RenderTexture.active = smallRT;
tex = new Texture2D(targetWidth, targetHeight, TextureFormat.ARGB32, false);
tex.ReadPixels(new Rect(0, 0, targetWidth, targetHeight), 0, 0);
tex.Apply();
RenderTexture.ReleaseTemporary(smallRT);
var cornerRadiiFinal = GetChartCornerRadius(chart, rectTransform.rect.width, rectTransform.rect.height, scaleFactor);
ApplyRoundedCornerClip(tex, cornerRadiiFinal);
}
else
{
tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
tex.Apply();
ApplyRoundedCornerClip(tex, cornerRadii);
}
}
finally
{
RenderTexture.active = oldActive;
RenderTexture.ReleaseTemporary(rt);
DestroyObject(rootObj);
}
var bytes = EncodeImage(tex, imageType);
if (bytes == null)
return null;
var fileName = rectTransform.name + "." + imageType; var fileName = rectTransform.name + "." + imageType;
#if UNITY_WEBGL #if UNITY_WEBGL
string base64str = Convert.ToBase64String(bytes); string base64str = Convert.ToBase64String(bytes);

View File

@@ -21,8 +21,8 @@ namespace XCharts.Runtime
[ExecuteInEditMode] [ExecuteInEditMode]
public static class XChartsMgr public static class XChartsMgr
{ {
public static readonly string version = "3.14.0"; public static readonly string version = "3.15.0";
public static readonly int versionDate = 20250315; public static readonly int versionDate = 20260301;
public static string fullVersion { get { return version + "-" + versionDate; } } public static string fullVersion { get { return version + "-" + versionDate; } }
internal static List<BaseChart> chartList = new List<BaseChart>(); internal static List<BaseChart> chartList = new List<BaseChart>();

View File

@@ -8,13 +8,13 @@ namespace XCharts.Runtime
[CoordOptions(typeof(GridCoord), typeof(PolarCoord))] [CoordOptions(typeof(GridCoord), typeof(PolarCoord))]
[DefaultAnimation(AnimationType.BottomToTop)] [DefaultAnimation(AnimationType.BottomToTop)]
[DefaultTooltip(Tooltip.Type.Shadow, Tooltip.Trigger.Axis)] [DefaultTooltip(Tooltip.Type.Shadow, Tooltip.Trigger.Axis)]
[SerieComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieComponent(typeof(TitleStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))]
[SerieDataComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataComponent(typeof(ItemStyle), typeof(TitleStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))]
[SerieDataExtraField("m_Ignore")] [SerieDataExtraField("m_Ignore")]
public class Bar : Serie, INeedSerieContainer public class Bar : Serie, INeedSerieContainer
{ {
public override bool useSortData { get { return realtimeSort; } } public override bool useSortData { get { return realtimeSort; } }
public int containerIndex { get; internal set; } public int containerIndex { get; internal set; }
public int containterInstanceId { get; internal set; } public int containterInstanceId { get; internal set; }

View File

@@ -47,12 +47,14 @@ namespace XCharts.Runtime
{ {
switch (label.position) switch (label.position)
{ {
case LabelStyle.Position.Start:
case LabelStyle.Position.Bottom: case LabelStyle.Position.Bottom:
var center = serieData.context.areaCenter; var center = serieData.context.areaCenter;
var angle = serieData.context.halfAngle; var angle = serieData.context.halfAngle;
var radius = serieData.context.insideRadius; var radius = serieData.context.insideRadius;
return ChartHelper.GetPosition(center, angle, radius); return ChartHelper.GetPosition(center, angle, radius);
case LabelStyle.Position.Top: case LabelStyle.Position.Top:
case LabelStyle.Position.End:
center = serieData.context.areaCenter; center = serieData.context.areaCenter;
angle = serieData.context.halfAngle; angle = serieData.context.halfAngle;
radius = serieData.context.outsideRadius; radius = serieData.context.outsideRadius;
@@ -65,6 +67,7 @@ namespace XCharts.Runtime
{ {
switch (label.position) switch (label.position)
{ {
case LabelStyle.Position.Start:
case LabelStyle.Position.Bottom: case LabelStyle.Position.Bottom:
var center = serieData.context.rect.center; var center = serieData.context.rect.center;
if (serie.context.isHorizontal) if (serie.context.isHorizontal)
@@ -73,6 +76,7 @@ namespace XCharts.Runtime
return new Vector3(center.x, center.y - serieData.context.rect.height / 2); return new Vector3(center.x, center.y - serieData.context.rect.height / 2);
case LabelStyle.Position.Center: case LabelStyle.Position.Center:
case LabelStyle.Position.Inside: case LabelStyle.Position.Inside:
case LabelStyle.Position.Middle:
return serieData.context.rect.center; return serieData.context.rect.center;
default: default:
return serieData.context.position; return serieData.context.position;
@@ -80,6 +84,11 @@ namespace XCharts.Runtime
} }
} }
public override Vector3 GetSerieDataTitlePosition(SerieData serieData, TitleStyle titleStyle)
{
return GetSerieDataLabelPosition(serieData, titleStyle);
}
private void UpdateSerieGridContext() private void UpdateSerieGridContext()
{ {
if (m_SerieGrid == null) if (m_SerieGrid == null)
@@ -171,7 +180,7 @@ namespace XCharts.Runtime
if (showData.Count <= 0) if (showData.Count <= 0)
return; return;
var visualMap = chart.GetVisualMapOfSerie(serie);
var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width; var axisLength = isY ? m_SerieGrid.context.height : m_SerieGrid.context.width;
var relativedAxisLength = isY ? m_SerieGrid.context.width : m_SerieGrid.context.height; var relativedAxisLength = isY ? m_SerieGrid.context.width : m_SerieGrid.context.height;
var axisXY = isY ? m_SerieGrid.context.y : m_SerieGrid.context.x; var axisXY = isY ? m_SerieGrid.context.y : m_SerieGrid.context.x;
@@ -198,15 +207,24 @@ namespace XCharts.Runtime
var dataChangeDuration = serie.animation.GetChangeDuration(); var dataChangeDuration = serie.animation.GetChangeDuration();
var dataAddDuration = serie.animation.GetAdditionDuration(); var dataAddDuration = serie.animation.GetAdditionDuration();
var interactDuration = serie.animation.GetInteractionDuration(); var interactDuration = serie.animation.GetInteractionDuration();
var exchangeDuration = serie.animation.GetExchangeDuration();
var areaColor = ColorUtil.clearColor32; var areaColor = ColorUtil.clearColor32;
var areaToColor = ColorUtil.clearColor32; var areaToColor = ColorUtil.clearColor32;
var interacting = false; var interacting = false;
axis.context.scaleWidth = categoryWidth;
serie.context.isHorizontal = isY; serie.context.isHorizontal = isY;
serie.containerIndex = m_SerieGrid.index; serie.containerIndex = m_SerieGrid.index;
serie.containterInstanceId = m_SerieGrid.instanceId; serie.containterInstanceId = m_SerieGrid.instanceId;
serie.animation.InitProgress(axisXY, axisXY + axisLength); serie.animation.InitProgress(axisXY, axisXY + axisLength);
var visualMapDimension = VisualMapHelper.GetDimension(visualMap, defaultDimension);
if (visualMap != null && visualMap.show && visualMap.autoMinMax)
{
double maxValue, minValue;
SerieHelper.GetMinMaxData(serie, visualMapDimension, out minValue, out maxValue);
VisualMapHelper.SetMinMax(visualMap, minValue, maxValue);
}
for (int i = serie.minShow; i < maxCount; i++) for (int i = serie.minShow; i < maxCount; i++)
{ {
var serieData = showData[i]; var serieData = showData[i];
@@ -228,37 +246,55 @@ namespace XCharts.Runtime
var borderGap = relativedValue == 0 ? 0 : itemStyle.borderGap; var borderGap = relativedValue == 0 ? 0 : itemStyle.borderGap;
var borderGapAndWidth = borderWidth + borderGap; var borderGapAndWidth = borderWidth + borderGap;
var backgroundColor = itemStyle.backgroundColor; var backgroundColor = itemStyle.backgroundColor;
var backgroundGap = itemStyle.backgroundGap;
if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting, interactDuration)) if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting, interactDuration))
{ {
SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme); SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme);
if (visualMap != null && visualMap.show)
{
var visualValue = serieData.GetData(visualMapDimension, relativedAxis.inverse);
areaColor = visualMap.GetColor(visualValue);
areaToColor = areaColor;
}
serieData.interact.SetColor(ref interacting, areaColor, areaToColor); serieData.interact.SetColor(ref interacting, areaColor, areaToColor);
} }
var pX = 0f; var pX = 0f;
var pY = 0f; var pY = 0f;
UpdateXYPosition(m_SerieGrid, isY, axis, relativedAxis, i, categoryWidth, relativedCategoryWidth, barWidth, isStack, value, ref pX, ref pY); var runtimeBarWidth = barWidth;
var barHig = 0f; var runtimeGap = gap;
if (serie.ignoreZeroOccupy)
{
UpdateActiveBarLayout(serie, dataZoom, i, categoryWidth, barGap, runtimeBarWidth, ref runtimeGap);
}
UpdateXYPosition(m_SerieGrid, isY, axis, relativedAxis, i, categoryWidth, relativedCategoryWidth,
runtimeBarWidth, isStack, value, backgroundGap, ref pX, ref pY);
if (serie.useSortData)
{
serieData.context.UpdateExchangePosition(ref pX, ref pY, exchangeDuration);
}
float barHig;
if (isPercentStack) if (isPercentStack)
{ {
var valueTotal = chart.GetSerieSameStackTotalValue<Bar>(serie.stack, i, m_SerieGrid.index); var valueTotal = chart.GetSerieSameStackTotalValue<Bar>(serie.stack, i, m_SerieGrid.index);
barHig = valueTotal != 0 ? (float)(relativedValue / valueTotal * relativedAxisLength) : 0; barHig = valueTotal != 0 ? (float)(relativedValue / valueTotal * (relativedAxisLength - 2 * backgroundGap)) : 0;
} }
else else
{ {
barHig = AxisHelper.GetAxisValueLength(m_SerieGrid, relativedAxis, relativedCategoryWidth, relativedValue); barHig = AxisHelper.GetAxisValueLength(m_SerieGrid, relativedAxis, relativedCategoryWidth, relativedValue, 2 * backgroundGap);
} }
float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig); float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig);
Vector3 plb, plt, prt, prb, top; Vector3 plb, plt, prt, prb, top;
UpdateRectPosition(m_SerieGrid, isY, relativedValue, pX, pY, gap, borderWidth, barWidth, currHig, UpdateRectPosition(m_SerieGrid, isY, relativedValue, pX, pY, runtimeGap, borderWidth, runtimeBarWidth, currHig,
out plb, out plt, out prt, out prb, out top); out plb, out plt, out prt, out prb, out top);
serieData.context.stackHeight = barHig; serieData.context.stackHeight = barHig;
serieData.context.position = top; serieData.context.position = top;
serieData.context.rect = Rect.MinMaxRect(plb.x + borderGapAndWidth, plb.y + borderGapAndWidth, serieData.context.rect = Rect.MinMaxRect(plb.x + borderGapAndWidth, plb.y + borderGapAndWidth,
prt.x - borderGapAndWidth, prt.y - borderGapAndWidth); prt.x - borderGapAndWidth, prt.y - borderGapAndWidth);
serieData.context.backgroundRect = isY ? serieData.context.backgroundRect = isY ?
Rect.MinMaxRect(m_SerieGrid.context.x, plb.y, m_SerieGrid.context.x + relativedAxisLength, prt.y) : Rect.MinMaxRect(m_SerieGrid.context.x, plb.y - backgroundGap, m_SerieGrid.context.x + relativedAxisLength, prt.y + backgroundGap) :
Rect.MinMaxRect(plb.x, m_SerieGrid.context.y, prb.x, m_SerieGrid.context.y + relativedAxisLength); Rect.MinMaxRect(plb.x - backgroundGap, m_SerieGrid.context.y, prb.x + backgroundGap, m_SerieGrid.context.y + relativedAxisLength);
if (!serie.clip || (serie.clip && m_SerieGrid.Contains(top))) if (!serie.clip || (serie.clip && m_SerieGrid.Contains(top)))
{ {
@@ -276,11 +312,11 @@ namespace XCharts.Runtime
{ {
case BarType.Normal: case BarType.Normal:
case BarType.Capsule: case BarType.Capsule:
DrawNormalBar(vh, serie, serieData, itemStyle, backgroundColor, gap, barWidth, DrawNormalBar(vh, serie, serieData, itemStyle, backgroundColor, runtimeGap, runtimeBarWidth,
pX, pY, plb, plt, prt, prb, isY, m_SerieGrid, axis, areaColor, areaToColor, relativedValue); pX, pY, plb, plt, prt, prb, isY, m_SerieGrid, axis, areaColor, areaToColor, relativedValue);
break; break;
case BarType.Zebra: case BarType.Zebra:
DrawZebraBar(vh, serie, serieData, itemStyle, backgroundColor, gap, barWidth, DrawZebraBar(vh, serie, serieData, itemStyle, backgroundColor, runtimeGap, runtimeBarWidth,
pX, pY, plb, plt, prt, prb, isY, m_SerieGrid, axis, areaColor, areaToColor); pX, pY, plb, plt, prt, prb, isY, m_SerieGrid, axis, areaColor, areaToColor);
break; break;
} }
@@ -301,9 +337,106 @@ namespace XCharts.Runtime
} }
} }
List<string> m_SlotOrder = new List<string>();
Dictionary<string, bool> m_ActiveSlot = new Dictionary<string, bool>();
private void UpdateActiveBarLayout(Bar currentSerie, DataZoom dataZoom, int dataIndex,
float categoryWidth, float barGap, float barWidth, ref float gap)
{
m_SlotOrder.Clear();
m_ActiveSlot.Clear();
for (int n = 0; n < chart.series.Count; n++)
{
var serie = chart.series[n] as Bar;
if (serie == null || !serie.show || serie.placeHolder)
continue;
if (!IsSerieInGrid(serie, m_SerieGrid.index))
continue;
var slotKey = GetBarSlotKey(serie);
if (!m_ActiveSlot.ContainsKey(slotKey))
{
m_ActiveSlot[slotKey] = false;
m_SlotOrder.Add(slotKey);
}
if (IsSerieDataActiveForLayout(serie, dataZoom, dataIndex))
{
m_ActiveSlot[slotKey] = true;
}
}
var currentSlotKey = GetBarSlotKey(currentSerie);
if (!m_ActiveSlot.ContainsKey(currentSlotKey) || !m_ActiveSlot[currentSlotKey])
return;
var activeCount = 0;
var activeSlotIndex = -1;
for (int n = 0; n < m_SlotOrder.Count; n++)
{
var slotKey = m_SlotOrder[n];
if (!m_ActiveSlot[slotKey])
continue;
if (slotKey == currentSlotKey)
activeSlotIndex = activeCount;
activeCount++;
}
if (activeCount <= 0 || activeSlotIndex < 0)
return;
var actualGap = ChartHelper.GetActualValue(barGap, barWidth);
var totalBarWidth = barGap == -1
? barWidth
: activeCount * barWidth + (activeCount - 1) * actualGap;
var offset = (categoryWidth - totalBarWidth) * 0.5f;
gap = barGap == -1
? offset
: offset + activeSlotIndex * (barWidth + actualGap);
}
private string GetBarSlotKey(Bar serie)
{
return string.IsNullOrEmpty(serie.stack) ? "s_" + serie.index : "k_" + serie.stack;
}
private bool IsSerieDataActiveForLayout(Bar serie, DataZoom dataZoom, int dataIndex)
{
var dataList = serie.GetDataList(dataZoom, true);
if (dataList == null || dataIndex < 0 || dataIndex >= dataList.Count)
return false;
var serieData = dataList[dataIndex];
if (serieData == null || !serieData.show || serie.IsIgnoreValue(serieData))
return false;
if (!serie.ignoreZeroOccupy)
return true;
return !MathUtil.Approximately(serieData.GetData(1), 0);
}
private bool IsSerieInGrid(Bar serie, int gridIndex)
{
XAxis xAxis;
if (chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex))
{
if (xAxis.gridIndex != gridIndex)
return false;
}
YAxis yAxis;
if (chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex))
{
if (yAxis.gridIndex != gridIndex)
return false;
}
return true;
}
private void UpdateXYPosition(GridCoord grid, bool isY, Axis axis, Axis relativedAxis, int i, private void UpdateXYPosition(GridCoord grid, bool isY, Axis axis, Axis relativedAxis, int i,
float categoryWidth, float relativedCategoryWidth, float barWidth, bool isStack, float categoryWidth, float relativedCategoryWidth, float barWidth, bool isStack,
double value, ref float pX, ref float pY) double value, float backgroundGap, ref float pX, ref float pY)
{ {
if (isY) if (isY)
{ {
@@ -320,7 +453,7 @@ namespace XCharts.Runtime
pY = grid.context.y + valueLen - categoryWidth * 0.5f; pY = grid.context.y + valueLen - categoryWidth * 0.5f;
} }
} }
pX = AxisHelper.GetAxisValuePosition(grid, relativedAxis, relativedCategoryWidth, 0); pX = AxisHelper.GetAxisValuePosition(grid, relativedAxis, relativedCategoryWidth, 0) + backgroundGap;
if (isStack) if (isStack)
{ {
for (int n = 0; n < m_StackSerieData.Count - 1; n++) for (int n = 0; n < m_StackSerieData.Count - 1; n++)
@@ -342,7 +475,7 @@ namespace XCharts.Runtime
pX = grid.context.x + valueLen - categoryWidth * 0.5f; pX = grid.context.x + valueLen - categoryWidth * 0.5f;
} }
} }
pY = AxisHelper.GetAxisValuePosition(grid, relativedAxis, relativedCategoryWidth, 0); pY = AxisHelper.GetAxisValuePosition(grid, relativedAxis, relativedCategoryWidth, 0) + backgroundGap;
if (isStack) if (isStack)
{ {
for (int n = 0; n < m_StackSerieData.Count - 1; n++) for (int n = 0; n < m_StackSerieData.Count - 1; n++)

View File

@@ -8,6 +8,7 @@ namespace XCharts.Runtime
[UnityEngine.Scripting.Preserve] [UnityEngine.Scripting.Preserve]
internal sealed class CandlestickHandler : SerieHandler<Candlestick> internal sealed class CandlestickHandler : SerieHandler<Candlestick>
{ {
private GridCoord m_SerieGrid;
public override void DrawSerie(VertexHelper vh) public override void DrawSerie(VertexHelper vh)
{ {
DrawCandlestickSerie(vh, serie); DrawCandlestickSerie(vh, serie);
@@ -106,20 +107,84 @@ namespace XCharts.Runtime
} }
} }
public override void UpdateSerieContext()
{
if (m_SerieGrid == null)
return;
var needCheck = (chart.isPointerInChart && m_SerieGrid.IsPointerEnter() && !serie.placeHolder) || m_LegendEnter;
var needInteract = false;
if (!needCheck)
{
if (m_LastCheckContextFlag != needCheck)
{
m_LastCheckContextFlag = needCheck;
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
Color32 color1, toColor1;
foreach (var serieData in serie.data)
{
serieData.context.highlight = false;
var state = SerieHelper.GetSerieState(serie, serieData, true);
SerieHelper.GetItemColor(out color1, out toColor1, serie, serieData, chart.theme, state);
serieData.interact.SetColor(ref needInteract, color1, toColor1);
}
chart.RefreshPainter(serie);
}
return;
}
m_LastCheckContextFlag = needCheck;
Color32 color, toColor;
if (m_LegendEnter)
{
serie.context.pointerEnter = true;
foreach (var serieData in serie.data)
{
SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme);
serieData.interact.SetColor(ref needInteract, color, toColor);
}
}
else
{
serie.context.pointerItemDataIndex = -1;
serie.context.pointerEnter = false;
foreach (var serieData in serie.data)
{
if (serie.context.pointerAxisDataIndexs.Contains(serieData.index) ||
serieData.context.rect.Contains(chart.pointerPos))
{
serie.context.pointerItemDataIndex = serieData.index;
serie.context.pointerEnter = true;
serieData.context.highlight = true;
}
else
{
serieData.context.highlight = false;
}
var state = SerieHelper.GetSerieState(serie, serieData, true);
SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, state);
serieData.interact.SetColor(ref needInteract, color, toColor);
}
}
if (needInteract)
{
chart.RefreshPainter(serie);
}
}
private void DrawCandlestickSerie(VertexHelper vh, Candlestick serie) private void DrawCandlestickSerie(VertexHelper vh, Candlestick serie)
{ {
if (!serie.show) return; if (!serie.show) return;
if (serie.animation.HasFadeOut()) return; if (serie.animation.HasFadeOut()) return;
XAxis xAxis; XAxis xAxis;
YAxis yAxis; YAxis yAxis;
GridCoord grid;
if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return; if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return;
if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return; if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return;
if (!chart.TryGetChartComponent<GridCoord>(out grid, xAxis.gridIndex)) return; if (!chart.TryGetChartComponent<GridCoord>(out m_SerieGrid, xAxis.gridIndex)) return;
var theme = chart.theme; var theme = chart.theme;
var dataZoom = chart.GetDataZoomOfAxis(xAxis); var dataZoom = chart.GetDataZoomOfAxis(xAxis);
var showData = serie.GetDataList(dataZoom); var showData = serie.GetDataList(dataZoom);
float categoryWidth = AxisHelper.GetDataWidth(xAxis, grid.context.width, showData.Count, dataZoom); float categoryWidth = AxisHelper.GetDataWidth(xAxis, m_SerieGrid.context.width, showData.Count, dataZoom);
float barWidth = serie.GetBarWidth(categoryWidth); float barWidth = serie.GetBarWidth(categoryWidth);
float gap = (categoryWidth - barWidth) / 2; float gap = (categoryWidth - barWidth) / 2;
int maxCount = serie.maxShow > 0 ? int maxCount = serie.maxShow > 0 ?
@@ -133,9 +198,9 @@ namespace XCharts.Runtime
double yMinValue = yAxis.context.minValue; double yMinValue = yAxis.context.minValue;
double yMaxValue = yAxis.context.maxValue; double yMaxValue = yAxis.context.maxValue;
var isYAxis = false; var isYAxis = false;
serie.containerIndex = grid.index; serie.containerIndex = m_SerieGrid.index;
serie.containterInstanceId = grid.instanceId; serie.containterInstanceId = m_SerieGrid.instanceId;
var intensive = grid.context.width / (maxCount - serie.minShow) < 0.6f; var intensive = m_SerieGrid.context.width / (maxCount - serie.minShow) < 0.6f;
for (int i = serie.minShow; i < maxCount; i++) for (int i = serie.minShow; i < maxCount; i++)
{ {
var serieData = showData[i]; var serieData = showData[i];
@@ -157,17 +222,17 @@ namespace XCharts.Runtime
(itemStyle.borderWidth == 0 ? theme.serie.candlestickBorderWidth : (itemStyle.borderWidth == 0 ? theme.serie.candlestickBorderWidth :
itemStyle.borderWidth); itemStyle.borderWidth);
if (serieData.IsDataChanged()) dataChanging = true; if (serieData.IsDataChanged()) dataChanging = true;
float pX = grid.context.x + i * categoryWidth; float pX = xAxis.IsCategory() ? m_SerieGrid.context.x + i * categoryWidth : AxisHelper.GetAxisValuePosition(m_SerieGrid, xAxis, categoryWidth, serieData.GetData(0));
float zeroY = grid.context.y + yAxis.context.offset; float zeroY = m_SerieGrid.context.y + yAxis.context.offset;
if (!xAxis.boundaryGap) pX -= categoryWidth / 2; if (!xAxis.boundaryGap) pX -= categoryWidth / 2;
float pY = zeroY; float pY = zeroY;
var barHig = 0f; var barHig = 0f;
double valueTotal = yMaxValue - yMinValue; double valueTotal = yMaxValue - yMinValue;
var minCut = (yMinValue > 0 ? yMinValue : 0); var minCut = yMinValue > 0 ? yMinValue : 0;
if (valueTotal != 0) if (valueTotal != 0)
{ {
barHig = (float)((close - open) / valueTotal * grid.context.height); barHig = (float)((close - open) / valueTotal * m_SerieGrid.context.height);
pY += (float)((open - minCut) / valueTotal * grid.context.height); pY += (float)((open - minCut) / valueTotal * m_SerieGrid.context.height);
} }
serieData.context.stackHeight = barHig; serieData.context.stackHeight = barHig;
float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig); float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig);
@@ -192,11 +257,11 @@ namespace XCharts.Runtime
} }
if (serie.clip) if (serie.clip)
{ {
plb = chart.ClampInGrid(grid, plb); plb = chart.ClampInGrid(m_SerieGrid, plb);
plt = chart.ClampInGrid(grid, plt); plt = chart.ClampInGrid(m_SerieGrid, plt);
prt = chart.ClampInGrid(grid, prt); prt = chart.ClampInGrid(m_SerieGrid, prt);
prb = chart.ClampInGrid(grid, prb); prb = chart.ClampInGrid(m_SerieGrid, prb);
top = chart.ClampInGrid(grid, top); top = chart.ClampInGrid(m_SerieGrid, top);
} }
serie.context.dataPoints.Add(top); serie.context.dataPoints.Add(top);
serie.context.dataIndexs.Add(serieData.index); serie.context.dataIndexs.Add(serieData.index);
@@ -209,10 +274,16 @@ namespace XCharts.Runtime
var itemWidth = Mathf.Abs(prt.x - plb.x); var itemWidth = Mathf.Abs(prt.x - plb.x);
var itemHeight = Mathf.Abs(plt.y - prb.y); var itemHeight = Mathf.Abs(plt.y - prb.y);
var center = new Vector3((plb.x + prt.x) / 2, (plt.y + prb.y) / 2); 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 lowPos = new Vector3(center.x, zeroY + (float)((lowest - minCut) / valueTotal * m_SerieGrid.context.height));
var heighPos = new Vector3(center.x, zeroY + (float)((heighest - minCut) / valueTotal * grid.context.height)); var heighPos = new Vector3(center.x, zeroY + (float)((heighest - minCut) / valueTotal * m_SerieGrid.context.height));
var openCenterPos = new Vector3(center.x, prb.y); var openCenterPos = new Vector3(center.x, prb.y);
var closeCenterPos = new Vector3(center.x, prt.y); var closeCenterPos = new Vector3(center.x, prt.y);
var rectMinX = Mathf.Min(plb.x, prb.x, plt.x, prt.x);
var rectMaxX = Mathf.Max(plb.x, prb.x, plt.x, prt.x);
var rectMinY = Mathf.Min(plb.y, prb.y, plt.y, prt.y, lowPos.y, heighPos.y);
var rectMaxY = Mathf.Max(plb.y, prb.y, plt.y, prt.y, lowPos.y, heighPos.y);
serieData.context.rect = new Rect(rectMinX, rectMinY, rectMaxX - rectMinX, rectMaxY - rectMinY);
if (intensive) if (intensive)
{ {
UGL.DrawLine(vh, lowPos, heighPos, borderWidth, borderColor); UGL.DrawLine(vh, lowPos, heighPos, borderWidth, borderColor);
@@ -231,7 +302,7 @@ namespace XCharts.Runtime
else else
{ {
chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor, chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor,
serie.clip, grid); serie.clip, m_SerieGrid);
} }
UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0, UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0,
itemStyle.cornerRadius, isYAxis, 0.5f); itemStyle.cornerRadius, isYAxis, 0.5f);

View File

@@ -100,7 +100,7 @@ namespace XCharts.Runtime
var serieData = serie.data[i]; var serieData = serie.data[i];
var dist = Vector3.Distance(chart.pointerPos, serieData.context.position); var dist = Vector3.Distance(chart.pointerPos, serieData.context.position);
var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize); var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize);
var highlight = dist <= size; var highlight = dist <= size * 2.5f;
serieData.context.highlight = highlight; serieData.context.highlight = highlight;
var state = SerieHelper.GetSerieState(serie, serieData, true); var state = SerieHelper.GetSerieState(serie, serieData, true);
size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state); size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state);

View File

@@ -2,6 +2,21 @@ using UnityEngine;
namespace XCharts.Runtime namespace XCharts.Runtime
{ {
public enum PieType
{
/// <summary>
/// solid pie chart - default fill style.
/// ||实心饼图 - 默认填充样式
/// </summary>
Solid,
/// <summary>
/// wireframe pie chart - only show the outline wireframe.
/// ||线框饼图 - 仅显示轮廓线框
/// </summary>
Wireframe
}
[System.Serializable] [System.Serializable]
[SerieConvert(typeof(Line), typeof(Bar))] [SerieConvert(typeof(Line), typeof(Bar))]
[SerieHandler(typeof(PieHandler), true)] [SerieHandler(typeof(PieHandler), true)]
@@ -12,10 +27,20 @@ namespace XCharts.Runtime
public class Pie : Serie public class Pie : Serie
{ {
[SerializeField][Since("v3.8.1")] private bool m_RadiusGradient = false; [SerializeField][Since("v3.8.1")] private bool m_RadiusGradient = false;
[SerializeField][Since("v3.15.0")] private PieType m_PieType = PieType.Solid;
public override SerieColorBy defaultColorBy { get { return SerieColorBy.Data; } } public override SerieColorBy defaultColorBy { get { return SerieColorBy.Data; } }
public override bool titleJustForSerie { get { return true; } } public override bool titleJustForSerie { get { return true; } }
/// <summary>
/// Pie chart type.
/// || 饼图类型。
/// </summary>
public PieType pieType
{
get { return m_PieType; }
set { if (PropertyUtil.SetStruct(ref m_PieType, value)) { SetVerticesDirty(); } }
}
/// <summary> /// <summary>
/// Whether to use gradient color in pie chart. /// Whether to use gradient color in pie chart.
/// || 是否开启半径方向的渐变效果。 /// || 是否开启半径方向的渐变效果。

View File

@@ -271,6 +271,7 @@ namespace XCharts.Runtime
} }
var offset = 0f; var offset = 0f;
var interactOffset = serie.animation.interaction.GetOffset(serie.context.outsideRadius); var interactOffset = serie.animation.interaction.GetOffset(serie.context.outsideRadius);
serieData.context.insideRadius = serie.context.insideRadius;
if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) if (serie.pieClickOffset && (serieData.selected || serieData.context.selected))
{ {
offset += interactOffset; offset += interactOffset;
@@ -358,7 +359,7 @@ namespace XCharts.Runtime
{ {
var itemStyle = SerieHelper.GetItemStyle(serie, null); var itemStyle = SerieHelper.GetItemStyle(serie, null);
var fillColor = ChartHelper.IsClearColor(itemStyle.backgroundColor) ? var fillColor = ChartHelper.IsClearColor(itemStyle.backgroundColor) ?
(Color32)chart.theme.legend.unableColor : itemStyle.backgroundColor; (Color32)chart.theme.legend.inactiveColor : itemStyle.backgroundColor;
UGL.DrawDoughnut(vh, serie.context.center, serie.context.insideRadius, UGL.DrawDoughnut(vh, serie.context.center, serie.context.insideRadius,
serie.context.outsideRadius, fillColor, fillColor, Color.clear, 0, serie.context.outsideRadius, fillColor, fillColor, Color.clear, 0,
360, itemStyle.borderWidth, itemStyle.borderColor, serie.gap / 2, chart.settings.cicleSmoothness, 360, itemStyle.borderWidth, itemStyle.borderColor, serie.gap / 2, chart.settings.cicleSmoothness,
@@ -381,8 +382,6 @@ namespace XCharts.Runtime
var needOffset = (serie.pieClickOffset && (serieData.selected || serieData.context.selected)); var needOffset = (serie.pieClickOffset && (serieData.selected || serieData.context.selected));
var offsetCenter = needOffset ? serieData.context.offsetCenter : serie.context.center; var offsetCenter = needOffset ? serieData.context.offsetCenter : serie.context.center;
var borderWidth = itemStyle.borderWidth;
var borderColor = itemStyle.borderColor;
var progress = AnimationStyleHelper.CheckDataAnimation(chart, serie, n, 1); var progress = AnimationStyleHelper.CheckDataAnimation(chart, serie, n, 1);
var insideRadius = serieData.context.insideRadius * progress; var insideRadius = serieData.context.insideRadius * progress;
@@ -398,6 +397,17 @@ namespace XCharts.Runtime
serieData.interact.SetPosition(ref interacting, offsetCenter); serieData.interact.SetPosition(ref interacting, offsetCenter);
} }
} }
var borderWidth = itemStyle.borderWidth;
var borderColor = itemStyle.GetBorderColor(color);
if (serie.pieType == PieType.Wireframe)
{
color = ColorUtil.clearColor32;
toColor = ColorUtil.clearColor32;
if (borderWidth <= 0)
{
borderWidth = 4;
}
}
var drawEndDegree = serieData.context.currentAngle; var drawEndDegree = serieData.context.currentAngle;
var needRoundCap = serie.roundCap && insideRadius > 0; var needRoundCap = serie.roundCap && insideRadius > 0;
UGL.DrawDoughnut(vh, offsetCenter, insideRadius, UGL.DrawDoughnut(vh, offsetCenter, insideRadius,
@@ -545,10 +555,11 @@ namespace XCharts.Runtime
var dist = Vector2.Distance(local, serie.context.center); var dist = Vector2.Distance(local, serie.context.center);
var interactOffset = serie.animation.interaction.GetOffset(serie.context.outsideRadius); var interactOffset = serie.animation.interaction.GetOffset(serie.context.outsideRadius);
var maxRadius = serie.context.outsideRadius + 2 * interactOffset; var maxRadius = serie.context.outsideRadius + interactOffset;
if (dist < serie.context.insideRadius || dist > maxRadius) if (dist < serie.context.insideRadius - interactOffset || dist > maxRadius)
{
return -1; return -1;
}
var dir = local - new Vector2(serie.context.center.x, serie.context.center.y); var dir = local - new Vector2(serie.context.center.x, serie.context.center.y);
var angle = ChartHelper.GetAngle360(Vector2.up, dir); var angle = ChartHelper.GetAngle360(Vector2.up, dir);
for (int i = 0; i < serie.data.Count; i++) for (int i = 0; i < serie.data.Count; i++)
@@ -559,7 +570,8 @@ namespace XCharts.Runtime
var ndist = (serieData.selected || serieData.context.selected) ? var ndist = (serieData.selected || serieData.context.selected) ?
Vector2.Distance(local, serieData.context.offsetCenter) : Vector2.Distance(local, serieData.context.offsetCenter) :
dist; dist;
if (ndist >= serieData.context.insideRadius && ndist <= serieData.context.outsideRadius) ndist = dist;
if (ndist >= serieData.context.insideRadius - interactOffset && ndist <= serieData.context.outsideRadius)
{ {
return i; return i;
} }

View File

@@ -166,6 +166,8 @@ namespace XCharts.Runtime
var symbol = SerieHelper.GetSerieSymbol(serie, serieData); var symbol = SerieHelper.GetSerieSymbol(serie, serieData);
if (!symbol.ShowSymbol(serieData.index, maxCount)) if (!symbol.ShowSymbol(serieData.index, maxCount))
continue; continue;
if (serie.IsIgnoreValue(serieData))
continue;
var state = SerieHelper.GetSerieState(serie, serieData, true); var state = SerieHelper.GetSerieState(serie, serieData, true);

View File

@@ -264,6 +264,7 @@ namespace XCharts.Runtime
[SerializeField] private float m_BarGap = 0.1f; [SerializeField] private float m_BarGap = 0.1f;
[SerializeField] private float m_BarZebraWidth = 4f; [SerializeField] private float m_BarZebraWidth = 4f;
[SerializeField] private float m_BarZebraGap = 2f; [SerializeField] private float m_BarZebraGap = 2f;
[SerializeField] [Since("v3.15.0")]private bool m_IgnoreZeroOccupy = false;
[SerializeField] private float m_Min; [SerializeField] private float m_Min;
[SerializeField] private float m_Max; [SerializeField] private float m_Max;
@@ -632,7 +633,8 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_BarGap, value)) SetVerticesDirty(); } set { if (PropertyUtil.SetStruct(ref m_BarGap, value)) SetVerticesDirty(); }
} }
/// <summary> /// <summary>
/// 斑马线的粗细。 /// The width of zebra bar. It is the width of each zebra stripe. When the value is 0, there is no zebra stripe.
/// ||斑马线的粗细。
/// </summary> /// </summary>
public float barZebraWidth public float barZebraWidth
{ {
@@ -640,13 +642,24 @@ namespace XCharts.Runtime
set { if (PropertyUtil.SetStruct(ref m_BarZebraWidth, value < 0 ? 0 : value)) SetVerticesDirty(); } set { if (PropertyUtil.SetStruct(ref m_BarZebraWidth, value < 0 ? 0 : value)) SetVerticesDirty(); }
} }
/// <summary> /// <summary>
/// 斑马线的间距。 /// The gap of zebra bar. It is the distance between two zebra stripes. When the value is 0, there is no gap between stripes.
/// ||斑马线的间距。
/// </summary> /// </summary>
public float barZebraGap public float barZebraGap
{ {
get { return m_BarZebraGap; } get { return m_BarZebraGap; }
set { if (PropertyUtil.SetStruct(ref m_BarZebraGap, value < 0 ? 0 : value)) SetVerticesDirty(); } set { if (PropertyUtil.SetStruct(ref m_BarZebraGap, value < 0 ? 0 : value)) SetVerticesDirty(); }
} }
/// <summary>
/// Whether to ignore the zero value bar occupy. When enabled, the bar with zero value will not occupy space,
/// and the gap between bars will be automatically adjusted according to the actual displayed bars. Generally used in bar chart.
/// ||柱图是否忽略值为0的柱子占位。开启后值为0的柱子将不会占用空间柱子之间的间距会根据实际显示的柱子自动调整。一般用在柱状图中。
/// </summary>
public bool ignoreZeroOccupy
{
get { return m_IgnoreZeroOccupy; }
set { if (PropertyUtil.SetStruct(ref m_IgnoreZeroOccupy, value)) SetVerticesDirty(); }
}
/// <summary> /// <summary>
/// Whether offset when mouse click pie chart item. /// Whether offset when mouse click pie chart item.
@@ -1337,6 +1350,7 @@ namespace XCharts.Runtime
m_Data.RemoveAt(index); m_Data.RemoveAt(index);
m_NeedUpdateFilterData = true; m_NeedUpdateFilterData = true;
labelDirty = true; labelDirty = true;
titleDirty = true;
dataDirty = true; dataDirty = true;
} }
} }
@@ -1363,6 +1377,7 @@ namespace XCharts.Runtime
SetVerticesDirty(); SetVerticesDirty();
CheckDataName(dataName); CheckDataName(dataName);
labelDirty = true; labelDirty = true;
titleDirty = true;
dataDirty = true; dataDirty = true;
return serieData; return serieData;
} }
@@ -1377,6 +1392,8 @@ namespace XCharts.Runtime
context.totalDataIndex++; context.totalDataIndex++;
SetVerticesDirty(); SetVerticesDirty();
dataDirty = true; dataDirty = true;
labelDirty = true;
titleDirty = true;
m_NeedUpdateFilterData = true; m_NeedUpdateFilterData = true;
} }
@@ -1411,6 +1428,7 @@ namespace XCharts.Runtime
SetVerticesDirty(); SetVerticesDirty();
CheckDataName(dataName); CheckDataName(dataName);
labelDirty = true; labelDirty = true;
titleDirty = true;
return serieData; return serieData;
} }
@@ -1443,6 +1461,7 @@ namespace XCharts.Runtime
SetVerticesDirty(); SetVerticesDirty();
CheckDataName(dataName); CheckDataName(dataName);
labelDirty = true; labelDirty = true;
titleDirty = true;
return serieData; return serieData;
} }
@@ -1477,6 +1496,7 @@ namespace XCharts.Runtime
SetVerticesDirty(); SetVerticesDirty();
CheckDataName(dataName); CheckDataName(dataName);
labelDirty = true; labelDirty = true;
titleDirty = true;
return serieData; return serieData;
} }
} }
@@ -1512,6 +1532,7 @@ namespace XCharts.Runtime
SetVerticesDirty(); SetVerticesDirty();
CheckDataName(dataName); CheckDataName(dataName);
labelDirty = true; labelDirty = true;
titleDirty = true;
return serieData; return serieData;
} }
} }
@@ -1805,6 +1826,7 @@ namespace XCharts.Runtime
{ {
SetVerticesDirty(); SetVerticesDirty();
dataDirty = true; dataDirty = true;
titleDirty = true;
} }
return flag; return flag;
} }

View File

@@ -645,11 +645,12 @@ namespace XCharts.Runtime
/// the maxinum value. /// the maxinum value.
/// ||最大值。 /// ||最大值。
/// </summary> /// </summary>
public double GetMaxData(bool inverse = false) public double GetMaxData(bool inverse = false, int startDimensionIndex = 0)
{ {
if (m_Data.Count == 0) return 0; if (m_Data.Count == 0) return 0;
var temp = double.MinValue; var temp = double.MinValue;
for (int i = 0; i < m_Data.Count; i++) if (startDimensionIndex < 0) startDimensionIndex = 0;
for (int i = startDimensionIndex; i < m_Data.Count; i++)
{ {
var value = GetData(i, inverse); var value = GetData(i, inverse);
if (value > temp) temp = value; if (value > temp) temp = value;
@@ -661,11 +662,12 @@ namespace XCharts.Runtime
/// the mininum value. /// the mininum value.
/// ||最小值。 /// ||最小值。
/// </summary> /// </summary>
public double GetMinData(bool inverse = false) public double GetMinData(bool inverse = false, int startDimensionIndex = 0)
{ {
if (m_Data.Count == 0) return 0; if (m_Data.Count == 0) return 0;
var temp = double.MaxValue; var temp = double.MaxValue;
for (int i = 0; i < m_Data.Count; i++) if (startDimensionIndex < 0) startDimensionIndex = 0;
for (int i = startDimensionIndex; i < m_Data.Count; i++)
{ {
var value = GetData(i, inverse); var value = GetData(i, inverse);
if (value < temp) temp = value; if (value < temp) temp = value;

View File

@@ -35,6 +35,19 @@ namespace XCharts.Runtime
public float offsetRadius; public float offsetRadius;
public float outsideRadius; public float outsideRadius;
public Vector3 position; public Vector3 position;
/// <summary>
/// is the exchange animation end.
/// ||交换动画是否结束。
/// </summary>
public bool exchangeEnd;
/// <summary>
/// the current position of the exchange animation.
/// ||交换动画的当前位置。
/// </summary>
public Vector3 exchangePosition;
private float exchangeStartTime;
private Vector3 exchangeStartPosition;
private Vector3 exchangeEndPosition;
public List<Vector3> dataPoints = new List<Vector3>(); public List<Vector3> dataPoints = new List<Vector3>();
public List<ChartLabel> dataLabels = new List<ChartLabel>(); public List<ChartLabel> dataLabels = new List<ChartLabel>();
public List<SerieData> children = new List<SerieData>(); public List<SerieData> children = new List<SerieData>();
@@ -77,9 +90,61 @@ namespace XCharts.Runtime
symbol = null; symbol = null;
rect = Rect.zero; rect = Rect.zero;
subRect = Rect.zero; subRect = Rect.zero;
exchangeEnd = true;
exchangeStartPosition = Vector3.zero;
exchangePosition = Vector3.zero;
exchangeEndPosition = Vector3.zero;
children.Clear(); children.Clear();
dataPoints.Clear(); dataPoints.Clear();
dataLabels.Clear(); dataLabels.Clear();
} }
public void UpdateExchangePosition(ref float x, ref float y, float totalTime)
{
if (exchangeEndPosition.x != x || exchangeEndPosition.y != y)
{
if (exchangeStartPosition == Vector3.zero || Time.time - exchangeStartTime < 0.1f)
{
exchangeEnd = true;
exchangeStartTime = Time.time;
exchangeEndPosition.x = x;
exchangeEndPosition.y = y;
exchangeStartPosition = exchangeEndPosition;
exchangePosition = exchangeEndPosition;
return;
}
else
{
exchangeEnd = false;
exchangeStartTime = Time.time;
exchangeStartPosition = exchangePosition;
exchangeEndPosition.x = x;
exchangeEndPosition.y = y;
}
}
if (exchangeStartPosition == exchangeEndPosition)
{
exchangeEnd = true;
exchangePosition = exchangeEndPosition;
x = exchangePosition.x;
y = exchangePosition.y;
return;
}
var spendTime = Time.time - exchangeStartTime;
totalTime /= 1000;
if (spendTime >= totalTime)
{
exchangeEnd = true;
exchangeStartPosition = exchangeEndPosition;
exchangePosition = exchangeEndPosition;
x = exchangePosition.x;
y = exchangePosition.y;
return;
}
exchangePosition = Vector3.Lerp(exchangeStartPosition, exchangeEndPosition, spendTime / totalTime);
x = exchangePosition.x;
y = exchangePosition.y;
return;
}
} }
} }

View File

@@ -59,6 +59,7 @@ namespace XCharts.Runtime
protected GameObject m_SerieRoot; protected GameObject m_SerieRoot;
protected GameObject m_SerieLabelRoot; protected GameObject m_SerieLabelRoot;
protected bool m_InitedLabel; protected bool m_InitedLabel;
protected bool m_InitTitleLabel;
protected bool m_NeedInitComponent; protected bool m_NeedInitComponent;
protected bool m_RefreshLabel; protected bool m_RefreshLabel;
protected bool m_LastCheckContextFlag = false; protected bool m_LastCheckContextFlag = false;
@@ -107,6 +108,7 @@ namespace XCharts.Runtime
m_RefreshLabel = false; m_RefreshLabel = false;
RefreshLabelInternal(); RefreshLabelInternal();
RefreshEndLabelInternal(); RefreshEndLabelInternal();
RefreshTitleLabelInternal();
} }
if (serie.dataDirty) if (serie.dataDirty)
{ {
@@ -241,6 +243,8 @@ namespace XCharts.Runtime
public override void InitComponent() public override void InitComponent()
{ {
m_InitedLabel = false; m_InitedLabel = false;
m_InitTitleLabel = false;
serie.context.totalDataIndex = serie.dataCount - 1; serie.context.totalDataIndex = serie.dataCount - 1;
InitRoot(); InitRoot();
InitSerieLabel(); InitSerieLabel();
@@ -428,23 +432,15 @@ namespace XCharts.Runtime
if (titleStyle != null) if (titleStyle != null)
{ {
var color = chart.GetItemColor(serie, null); var color = chart.GetItemColor(serie, null);
var content = string.Empty; var content = SerieLabelHelper.GetTitleFormatterContent(serie, null, -1, titleStyle, chart);
if (string.IsNullOrEmpty(titleStyle.formatter)) var label = ChartHelper.AddChartLabel("title_0", serieTitleRoot.transform, titleStyle, chart.theme.common,
{
content = serie.serieName;
}
else
{
content = titleStyle.formatter;
FormatterHelper.ReplaceContent(ref content, -1, titleStyle.numericFormatter, serie, chart);
}
var label = ChartHelper.AddChartLabel("title_" + 0, serieTitleRoot.transform, titleStyle, chart.theme.common,
content, color, TextAnchor.MiddleCenter); content, color, TextAnchor.MiddleCenter);
serie.context.titleObject = label; serie.context.titleObject = label;
label.SetActive(titleStyle.show, true); label.SetActive(titleStyle.show, true);
var labelPosition = GetSerieDataTitlePosition(null, titleStyle); var labelPosition = GetSerieDataTitlePosition(null, titleStyle);
var offset = titleStyle.GetOffset(serie.context.insideRadius); var offset = titleStyle.GetOffset(serie.context.insideRadius);
label.SetPosition(labelPosition + offset); label.SetPosition(labelPosition + offset);
m_InitTitleLabel = true;
} }
} }
else else
@@ -454,17 +450,9 @@ namespace XCharts.Runtime
var serieData = serie.data[i]; var serieData = serie.data[i];
var titleStyle = SerieHelper.GetTitleStyle(serie, serieData); var titleStyle = SerieHelper.GetTitleStyle(serie, serieData);
if (titleStyle == null) continue; if (titleStyle == null) continue;
m_InitTitleLabel = true;
var color = chart.GetItemColor(serie, serieData); var color = chart.GetItemColor(serie, serieData);
var content = string.Empty; var content = SerieLabelHelper.GetTitleFormatterContent(serie, serieData, i, titleStyle, chart);
if (string.IsNullOrEmpty(titleStyle.formatter))
{
content = serieData.name;
}
else
{
content = titleStyle.formatter;
FormatterHelper.ReplaceContent(ref content, i, titleStyle.numericFormatter, serie, chart);
}
var label = ChartHelper.AddChartLabel("title_" + i, serieTitleRoot.transform, titleStyle, chart.theme.common, var label = ChartHelper.AddChartLabel("title_" + i, serieTitleRoot.transform, titleStyle, chart.theme.common,
content, color, TextAnchor.MiddleCenter); content, color, TextAnchor.MiddleCenter);
serieData.titleObject = label; serieData.titleObject = label;
@@ -476,6 +464,38 @@ namespace XCharts.Runtime
} }
} }
public void RefreshTitleLabelInternal()
{
if (!m_InitTitleLabel) return;
if (serie.titleJustForSerie)
{
if (serie.context.titleObject != null)
{
var titleStyle = SerieHelper.GetTitleStyle(serie, null);
var labelPosition = GetSerieDataTitlePosition(null, titleStyle);
var offset = titleStyle.GetOffset(serie.context.insideRadius);
serie.context.titleObject.SetPosition(labelPosition + offset);
var content = SerieLabelHelper.GetTitleFormatterContent(serie, null, -1, titleStyle, chart);
serie.context.titleObject.SetText(content);
}
}
else
{
for (int i = 0; i < serie.dataCount; i++)
{
var serieData = serie.data[i];
if (serieData.titleObject == null) continue;
var titleStyle = SerieHelper.GetTitleStyle(serie, serieData);
if (titleStyle == null) continue;
var labelPosition = GetSerieDataTitlePosition(serieData, titleStyle);
var offset = titleStyle.GetOffset(serie.context.insideRadius);
serieData.titleObject.SetPosition(labelPosition + offset);
var content = SerieLabelHelper.GetTitleFormatterContent(serie, serieData, i, titleStyle, chart);
serieData.titleObject.SetText(content);
}
}
}
public override void RefreshLabelInternal() public override void RefreshLabelInternal()
{ {
if (!m_InitedLabel) if (!m_InitedLabel)
@@ -594,7 +614,7 @@ namespace XCharts.Runtime
if (endLabelStyle == null) if (endLabelStyle == null)
return; return;
var dataCount = serie.context.dataPoints.Count; var dataCount = serie.context.dataPoints.Count;
var active = endLabelStyle.show && dataCount > 0; var active = endLabelStyle.show && dataCount > 0 && !ChartHelper.IsZeroVector(serie.context.lineEndPostion);
m_EndLabel.SetActive(active); m_EndLabel.SetActive(active);
if (active) if (active)
{ {
@@ -610,6 +630,8 @@ namespace XCharts.Runtime
protected Vector3 UpdateLabelPosition(SerieData serieData, LabelStyle currLabel) protected Vector3 UpdateLabelPosition(SerieData serieData, LabelStyle currLabel)
{ {
var labelPosition = GetSerieDataLabelPosition(serieData, currLabel); var labelPosition = GetSerieDataLabelPosition(serieData, currLabel);
if (currLabel.fixedX != 0) labelPosition.x = currLabel.fixedX;
if (currLabel.fixedY != 0) labelPosition.y = currLabel.fixedY;
var offset = GetSerieDataLabelOffset(serieData, currLabel); var offset = GetSerieDataLabelOffset(serieData, currLabel);
serieData.labelObject.SetPosition(labelPosition + offset); serieData.labelObject.SetPosition(labelPosition + offset);
if (currLabel.autoRotate && serieData.context.angle != 0) if (currLabel.autoRotate && serieData.context.angle != 0)

View File

@@ -833,13 +833,14 @@ namespace XCharts.Runtime
var data = serie.data; var data = serie.data;
var startValue = min; var startValue = min;
var endValue = max; var endValue = max;
var minZoomRatio = (int)((max-min) * dataZoom.minZoomRatio);
if (endValue < startValue) endValue = startValue; if (endValue < startValue) endValue = startValue;
if (startValue != serie.m_FilterStartValue || endValue != serie.m_FilterEndValue || if (startValue != serie.m_FilterStartValue || endValue != serie.m_FilterEndValue ||
dataZoom.minShowNum != serie.m_FilterMinShow || serie.m_NeedUpdateFilterData) dataZoom.minZoomRatio != serie.m_FilterMinShow || serie.m_NeedUpdateFilterData)
{ {
serie.m_FilterStartValue = startValue; serie.m_FilterStartValue = startValue;
serie.m_FilterEndValue = endValue; serie.m_FilterEndValue = endValue;
serie.m_FilterMinShow = dataZoom.minShowNum; serie.m_FilterMinShow = minZoomRatio;
serie.m_NeedUpdateFilterData = false; serie.m_NeedUpdateFilterData = false;
if (ReferenceEquals(serie.m_FilterData, data)) if (ReferenceEquals(serie.m_FilterData, data))
@@ -883,19 +884,20 @@ namespace XCharts.Runtime
end = start + range; end = start + range;
if (end > data.Count) end = data.Count; if (end > data.Count) end = data.Count;
} }
var minZoomRatio = (int)(data.Count * dataZoom.minZoomRatio);
if (start != serie.m_FilterStart || end != serie.m_FilterEnd || if (start != serie.m_FilterStart || end != serie.m_FilterEnd ||
dataZoom.minShowNum != serie.m_FilterMinShow || serie.m_NeedUpdateFilterData) minZoomRatio != serie.m_FilterMinShow || serie.m_NeedUpdateFilterData)
{ {
serie.m_FilterStart = start; serie.m_FilterStart = start;
serie.m_FilterEnd = end; serie.m_FilterEnd = end;
serie.m_FilterMinShow = dataZoom.minShowNum; serie.m_FilterMinShow = minZoomRatio;
serie.m_NeedUpdateFilterData = false; serie.m_NeedUpdateFilterData = false;
if (data.Count > 0) if (data.Count > 0)
{ {
if (range < dataZoom.minShowNum) if (range < minZoomRatio)
{ {
if (dataZoom.minShowNum > data.Count) range = data.Count; if (minZoomRatio > data.Count) range = data.Count;
else range = dataZoom.minShowNum; else range = minZoomRatio;
} }
if (range > data.Count - start) if (range > data.Count - start)
start = data.Count - range; start = data.Count - range;

View File

@@ -384,7 +384,7 @@ namespace XCharts.Runtime
else else
{ {
var showData = serie.GetDataList(filterByDataZoom ? chart.GetXDataZoomOfSerie(serie) : null); var showData = serie.GetDataList(filterByDataZoom ? chart.GetXDataZoomOfSerie(serie) : null);
if (serie is Candlestick || serie is SimplifiedCandlestick) if (dimension > 0 && (serie is Candlestick || serie is SimplifiedCandlestick))
{ {
foreach (var data in showData) foreach (var data in showData)
{ {
@@ -441,9 +441,9 @@ namespace XCharts.Runtime
if (!_serieTotalValueForMinMax.ContainsKey(j)) if (!_serieTotalValueForMinMax.ContainsKey(j))
_serieTotalValueForMinMax[j] = 0; _serieTotalValueForMinMax[j] = 0;
double currData = 0; double currData = 0;
if (serie is Candlestick) if (serie is Candlestick || serie is SimplifiedCandlestick)
{ {
currData = showData[j].GetMaxData(false); currData = showData[j].GetMaxData(false, dimension);
} }
else else
{ {

View File

@@ -1,5 +1,6 @@
using System; using System;
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
#if dUI_TextMeshPro #if dUI_TextMeshPro
using TMPro; using TMPro;
#endif #endif
@@ -9,27 +10,37 @@ namespace XCharts.Runtime
[Serializable] [Serializable]
public class LegendTheme : ComponentTheme public class LegendTheme : ComponentTheme
{ {
[SerializeField] protected Color m_UnableColor; [SerializeField][FormerlySerializedAs("m_UnableColor")] protected Color m_InactiveColor;
/// <summary> /// <summary>
/// the color of text. /// the color of text.
/// ||文本颜色。 /// ||文本颜色。
/// </summary> /// </summary>
[Obsolete("Use inactiveColor instead.", true)]
public Color unableColor public Color unableColor
{ {
get { return m_UnableColor; } get { return m_InactiveColor; }
set { if (PropertyUtil.SetColor(ref m_UnableColor, value)) SetComponentDirty(); } set { if (PropertyUtil.SetColor(ref m_InactiveColor, value)) SetComponentDirty(); }
}
/// <summary>
/// the color when the component is inactive.
/// ||非激活状态时的颜色。
/// </summary>
public Color inactiveColor
{
get { return m_InactiveColor; }
set { if (PropertyUtil.SetColor(ref m_InactiveColor, value)) SetComponentDirty(); }
} }
public void Copy(LegendTheme theme) public void Copy(LegendTheme theme)
{ {
base.Copy(theme); base.Copy(theme);
m_UnableColor = theme.unableColor; m_InactiveColor = theme.inactiveColor;
} }
public LegendTheme(ThemeType theme) : base(theme) public LegendTheme(ThemeType theme) : base(theme)
{ {
m_UnableColor = ColorUtil.GetColor("#cccccc"); m_InactiveColor = ColorUtil.GetColor("#cccccc");
} }
} }

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using UnityEngine;
namespace XCharts.Runtime namespace XCharts.Runtime
{ {
@@ -37,9 +36,9 @@ namespace XCharts.Runtime
public static bool IsDateOrTimeRegex(string regex, ref bool date, ref string formatter) public static bool IsDateOrTimeRegex(string regex, ref bool date, ref string formatter)
{ {
if(IsDateOrTimeRegex(regex)) if (IsDateOrTimeRegex(regex))
{ {
if(regex == "date" || regex == "time") if (regex == "date" || regex == "time")
{ {
date = regex == "date"; date = regex == "date";
formatter = ""; formatter = "";
@@ -53,24 +52,24 @@ namespace XCharts.Runtime
return false; return false;
} }
public static int GetTimestamp() public static double GetTimestamp()
{ {
return (int)(DateTime.Now - k_LocalDateTime1970).TotalSeconds; return (DateTime.Now - k_LocalDateTime1970).TotalSeconds;
} }
public static int GetTimestamp(DateTime time, bool local = false) public static double GetTimestamp(DateTime time, bool local = false)
{ {
if (local) if (local)
{ {
return (int)(time - k_LocalDateTime1970).TotalSeconds; return (time - k_LocalDateTime1970).TotalSeconds;
} }
else else
{ {
return (int)(time - k_DateTime1970).TotalSeconds; return (time - k_DateTime1970).TotalSeconds;
} }
} }
public static int GetTimestamp(string dateTime, bool local = false) public static double GetTimestamp(string dateTime, bool local = false)
{ {
try try
{ {
@@ -83,15 +82,16 @@ namespace XCharts.Runtime
} }
} }
public static DateTime GetDateTime(double timestamp, bool local = true) public static DateTime GetDateTime(double timestamp, bool local = false)
{ {
return local ? k_LocalDateTime1970.AddSeconds(timestamp) : k_DateTime1970.AddSeconds(timestamp); var dateTime = local ? k_LocalDateTime1970.AddSeconds(timestamp) : k_DateTime1970.AddSeconds(timestamp);
return dateTime;
} }
public static string GetDefaultDateTimeString(int timestamp, double range = 0) public static string GetDefaultDateTimeString(double timestamp, double range = 0, bool local = false)
{ {
var dateString = String.Empty; var dateString = String.Empty;
var dateTime = GetDateTime(timestamp); var dateTime = GetDateTime(timestamp, local);
if (range <= 0 || range >= DateTimeUtil.ONE_DAY) if (range <= 0 || range >= DateTimeUtil.ONE_DAY)
{ {
dateString = dateTime.ToString("yyyy-MM-dd"); dateString = dateTime.ToString("yyyy-MM-dd");
@@ -144,76 +144,130 @@ namespace XCharts.Runtime
/// <param name="minTimestamp"></param> /// <param name="minTimestamp"></param>
/// <param name="maxTimestamp"></param> /// <param name="maxTimestamp"></param>
/// <param name="splitNumber"></param> /// <param name="splitNumber"></param>
internal static float UpdateTimeAxisDateTimeList(List<double> list, int minTimestamp, int maxTimestamp, int splitNumber) internal static float UpdateTimeAxisDateTimeList(List<double> list, double minTimestamp, double maxTimestamp, int splitNumber, double ceilRate, bool local)
{ {
var firstValue = list.Count > 0 ? list[0] : 0;
var secondValue = list.Count > 1 ? list[1] : 0;
list.Clear();
var range = maxTimestamp - minTimestamp; var range = maxTimestamp - minTimestamp;
if (range <= 0) return 0; if (range <= 0)
var dtMin = DateTimeUtil.GetDateTime(minTimestamp);
var dtMax = DateTimeUtil.GetDateTime(maxTimestamp);
int tick = 0;
if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER)
{ {
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_YEAR) : Math.Max(range / (splitNumber * ONE_YEAR), 1); list.Clear();
var dtStart = (firstValue == 0 || secondValue == 0 || (minTimestamp > firstValue && minTimestamp > secondValue)) return 0;
? (new DateTime(dtMin.Year, dtMin.Month, 1).AddMonths(1)) }
: (minTimestamp > firstValue ? DateTimeUtil.GetDateTime(secondValue) : DateTimeUtil.GetDateTime(firstValue)); var dtMin = GetDateTime(minTimestamp, local);
tick = num * 365 * 24 * 3600; var dtMax = GetDateTime(maxTimestamp, local);
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1); int tick;
while (dtStart.Ticks < dtMax.Ticks) if (ceilRate != 0)
{
var tickSecond = (int)ceilRate;
tick = GetTickSecond(range, 0, tickSecond);
var let = minTimestamp % tickSecond;
var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tickSecond;
var startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp);
while (startTimestamp > minTimestamp)
{ {
list.Add(DateTimeUtil.GetTimestamp(dtStart)); startTimestamp -= tick;
dtStart = dtStart.AddYears(num);
} }
} if (startTimestamp < minTimestamp)
else if (range >= ONE_MONTH * MIN_TIME_SPLIT_NUMBER)
{
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_MONTH) : Math.Max(range / (splitNumber * ONE_MONTH), 1);
var dtStart = (firstValue == 0 || secondValue == 0 || (minTimestamp > firstValue && minTimestamp > secondValue))
? (new DateTime(dtMin.Year, dtMin.Month, 1).AddMonths(1))
: (minTimestamp > firstValue ? DateTimeUtil.GetDateTime(secondValue) : DateTimeUtil.GetDateTime(firstValue));
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
tick = num * 30 * 24 * 3600;
while (dtStart.Ticks < dtMax.Ticks)
{ {
list.Add(DateTimeUtil.GetTimestamp(dtStart)); startTimestamp += tick;
dtStart = dtStart.AddMonths(num);
} }
} list.Clear();
else if (range >= ONE_DAY * MIN_TIME_SPLIT_NUMBER)
{
tick = GetTickSecond(range, splitNumber, ONE_DAY);
var let = minTimestamp % tick;
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick;
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
else if (range >= ONE_HOUR * MIN_TIME_SPLIT_NUMBER)
{
tick = GetTickSecond(range, splitNumber, ONE_HOUR);
var let = minTimestamp % tick;
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick;
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
else if (range >= ONE_MINUTE * MIN_TIME_SPLIT_NUMBER)
{
tick = GetTickSecond(range, splitNumber, ONE_MINUTE);
var let = minTimestamp % tick;
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick;
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick); AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
} }
else else
{ {
tick = GetTickSecond(range, splitNumber, ONE_SECOND); if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER)
var let = minTimestamp % tick; {
var startTimestamp = let == 0 ? minTimestamp : (minTimestamp - let) + tick; var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_YEAR) : (int)Math.Max(range / (splitNumber * ONE_YEAR), 1);
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick); var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp), local);
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
while (dtStart > dtMin)
{
dtStart = dtStart.AddYears(-num);
}
if (dtStart < dtMin)
{
dtStart = dtStart.AddYears(num);
}
tick = num * 365 * 24 * 3600;
list.Clear();
while (dtStart.Ticks < dtMax.Ticks)
{
list.Add(DateTimeUtil.GetTimestamp(dtStart, local));
dtStart = dtStart.AddYears(num);
}
}
else if (range >= ONE_MONTH * MIN_TIME_SPLIT_NUMBER)
{
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_MONTH) : (int)Math.Max(range / (splitNumber * ONE_MONTH), 1);
var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp), local);
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
while (dtStart > dtMin)
{
dtStart = dtStart.AddMonths(-num);
}
if (dtStart < dtMin)
{
dtStart = dtStart.AddMonths(num);
}
tick = num * 30 * 24 * 3600;
list.Clear();
while (dtStart.Ticks < dtMax.Ticks)
{
list.Add(DateTimeUtil.GetTimestamp(dtStart, local));
dtStart = dtStart.AddMonths(num);
}
}
else
{
int tickSecond;
if (range >= ONE_DAY * MIN_TIME_SPLIT_NUMBER)
{
tickSecond = ONE_DAY;
}
else if (range >= ONE_HOUR * MIN_TIME_SPLIT_NUMBER)
{
tickSecond = ONE_HOUR;
}
else if (range >= ONE_MINUTE * MIN_TIME_SPLIT_NUMBER)
{
tickSecond = ONE_MINUTE;
}
else
{
tickSecond = ONE_SECOND;
}
tick = GetTickSecond(range, splitNumber, tickSecond);
var let = minTimestamp % tickSecond;
var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tickSecond;
var startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp);
while (startTimestamp > minTimestamp)
{
startTimestamp -= tick;
}
if (startTimestamp < minTimestamp)
{
startTimestamp += tick;
}
list.Clear();
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
} }
return tick; return tick;
} }
private static int GetSplitNumber(int range, int tickSecond) private static double GetFirstMaxValue(List<double> list, double minTimestamp, double defaultTimestamp = 0)
{
for (int i = 0; i < list.Count; i++)
{
if (list[i] >= minTimestamp)
{
return list[i];
}
}
return defaultTimestamp == 0 ? minTimestamp : defaultTimestamp;
}
private static int GetSplitNumber(double range, int tickSecond)
{ {
var num = 1; var num = 1;
while (range / (num * tickSecond) > 8) while (range / (num * tickSecond) > 8)
@@ -223,12 +277,12 @@ namespace XCharts.Runtime
return num; return num;
} }
private static int GetTickSecond(int range, int splitNumber, int tickSecond) private static int GetTickSecond(double range, int splitNumber, int tickSecond)
{ {
var num = 0; var num = 0;
if (splitNumber > 0) if (splitNumber > 0)
{ {
num = Math.Max(range / (splitNumber * tickSecond), 1); num = (int)Math.Max(range / (splitNumber * tickSecond), 1);
} }
else else
{ {
@@ -243,7 +297,7 @@ namespace XCharts.Runtime
return num * tickSecond; return num * tickSecond;
} }
private static void AddTickTimestamp(List<double> list, int startTimestamp, int maxTimestamp, int tickSecond) private static void AddTickTimestamp(List<double> list, double startTimestamp, double maxTimestamp, int tickSecond)
{ {
while (startTimestamp <= maxTimestamp) while (startTimestamp <= maxTimestamp)
{ {

View File

@@ -1446,7 +1446,7 @@ namespace XUGL
var lastP4 = center; var lastP4 = center;
var lastColor = color; var lastColor = color;
var needBorder = borderWidth != 0; var needBorder = borderWidth != 0;
var needSpace = gap != 0; var needSpace = gap != 0 || borderWidth != 0;
var borderLineWidth = needSpace ? borderWidth : borderWidth / 2; var borderLineWidth = needSpace ? borderWidth : borderWidth / 2;
var lastPos = Vector3.zero; var lastPos = Vector3.zero;
var middleDire = UGLHelper.GetDire(startAngle + halfAngle); var middleDire = UGLHelper.GetDire(startAngle + halfAngle);

View File

@@ -3,9 +3,9 @@
"displayName": "XCharts", "displayName": "XCharts",
"author": "monitor1394", "author": "monitor1394",
"license": "MIT", "license": "MIT",
"version": "3.14.0", "version": "3.15.0",
"date": "20250315", "date": "20260301",
"checkdate": "20250315", "checkdate": "20260301",
"unity": "2018.3", "unity": "2018.3",
"description": "A charting and data visualization library for Unity. Support line chart, bar chart, pie chart, radar chart, scatter chart, heatmap chart, ring chart, candlestick chart, polar chart and parallel coordinates.", "description": "A charting and data visualization library for Unity. Support line chart, bar chart, pie chart, radar chart, scatter chart, heatmap chart, ring chart, candlestick chart, polar chart and parallel coordinates.",
"keywords": [ "keywords": [