diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index bf1d471a..70d8a672 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -10,4 +10,4 @@ liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -custom: ['https://www.paypal.me/monitor1394','https://github.com/XCharts-Team/XCharts/blob/master/Documentation~/img/support_alipay.png','https://github.com/XCharts-Team/XCharts/blob/master/Documentation~/img/support_wechat.png'] +custom: ['https://github.com/XCharts-Team/XCharts/blob/master/Documentation~/zh/img/support_alipay.png','https://github.com/XCharts-Team/XCharts/blob/master/Documentation~/zh/img/support_wechat.png'] diff --git a/Documentation~/en/api.md b/Documentation~/en/api.md index 74f9845f..0424493e 100644 --- a/Documentation~/en/api.md +++ b/Documentation~/en/api.md @@ -7,6 +7,7 @@ slug: /api ## All Class +- [AnimationInfoContext](#animationinfocontext) - [AnimationStyleHelper](#animationstylehelper) - [AxisContext](#axiscontext) - [AxisHandler<T>](#axishandlert) @@ -30,9 +31,11 @@ slug: /api - [DataZoomHelper](#datazoomhelper) - [DateTimeUtil](#datetimeutil) - [DefaultAnimationAttribute](#defaultanimationattribute) +- [DefaultTooltipAttribute](#defaulttooltipattribute) - [DefineSymbolsUtil](#definesymbolsutil) - [FormatterHelper](#formatterhelper) - [GridCoordContext](#gridcoordcontext) +- [GridLayoutContext](#gridlayoutcontext) - [HeatmapChart](#heatmapchart) - [IgnoreDoc](#ignoredoc) - [INeedSerieContainer](#ineedseriecontainer) @@ -56,6 +59,7 @@ slug: /api - [MainComponentHandler](#maincomponenthandler) - [MainComponentHandler<T>](#maincomponenthandlert) - [MathUtil](#mathutil) +- [MonoBehaviour](#monobehaviour) - [Painter](#painter) - [ParallelChart](#parallelchart) - [ParallelCoordContext](#parallelcoordcontext) @@ -109,8 +113,13 @@ slug: /api - [XChartsMgr](#xchartsmgr) - [XCResourceImporterWindow](#xcresourceimporterwindow) - [XCThemeMgr](#xcthememgr) +- [XLog](#xlog) +## AnimationInfoContext + +> XCharts.Runtime.AnimationInfoContext + ## AnimationStyleHelper > XCharts.Runtime.AnimationStyleHelper @@ -119,7 +128,7 @@ slug: /api |--|--|--| |CheckDataAnimation()||public static float CheckDataAnimation(BaseChart chart, Serie serie, int dataIndex, float destProgress, float startPorgress = 0)| |GetAnimationPosition()||public static bool GetAnimationPosition(AnimationStyle animation, bool isY, Vector3 lp, Vector3 cp, float progress, ref Vector3 ip)| -|UpdateAnimationType()||public static void UpdateAnimationType(AnimationStyle animation, AnimationType defaultType)| +|UpdateAnimationType()||public static void UpdateAnimationType(AnimationStyle animation, AnimationType defaultType, bool enableSerieDataAnimation)| |UpdateSerieAnimation()||public static void UpdateSerieAnimation(Serie serie)| ## AxisContext @@ -206,12 +215,12 @@ slug: /api |AddXAxisIcon()||public void AddXAxisIcon(Sprite icon, int xAxisIndex = 0)
Add an icon to xAxis. | |AddYAxisData()||public void AddYAxisData(string category, int yAxisIndex = 0)
Add a category data to yAxis. | |AddYAxisIcon()||public void AddYAxisIcon(Sprite icon, int yAxisIndex = 0)
Add an icon to yAxis. | -|AnimationEnable()||public void AnimationEnable(bool flag)
Whether series animation enabel. | -|AnimationFadeIn()||public void AnimationFadeIn(bool reset = true)
fadeIn animation. | -|AnimationFadeOut()||public void AnimationFadeOut()
fadeIn animation. | -|AnimationPause()||public void AnimationPause()
Pause animation. | -|AnimationReset()||public void AnimationReset()
Reset animation. | -|AnimationResume()||public void AnimationResume()
Stop play animation. | +|AnimationEnable()||public void AnimationEnable(bool flag)
Whether enable serie animations. | +|AnimationFadeIn()||public void AnimationFadeIn(bool reset = true)
Start all serie fadein animations. | +|AnimationFadeOut()||public void AnimationFadeOut()
Start all serie fadeout animations. | +|AnimationPause()||public void AnimationPause()
Pause all animations. | +|AnimationReset()||public void AnimationReset()
Reset all animations. | +|AnimationResume()||public void AnimationResume()
Resume all animations. | |CanAddChartComponent()||public bool CanAddChartComponent(Type type)| |CanAddSerie()||public bool CanAddSerie(Type type)| |CanAddSerie<T>()||public bool CanAddSerie<T>() where T : Serie| @@ -493,7 +502,7 @@ slug: /api |GetTextHeight()||public float GetTextHeight()| |GetTextWidth()||public float GetTextWidth()| |GetWidth()||public float GetWidth()| -|IsActive()||public override bool IsActive()| +|IsActiveByScale()||public bool IsActiveByScale()| |SetActive()||public void SetActive(bool flag)| |SetIcon()||public void SetIcon(Image image)| |SetIconActive()||public void SetIconActive(bool flag)| @@ -509,7 +518,7 @@ slug: /api |SetTextColor()||public void SetTextColor(Color color)| |SetTextPadding()||public void SetTextPadding(TextPadding padding)| |SetTextRotate()||public void SetTextRotate(float rotate)| -|UpdateIcon()||public void UpdateIcon(IconStyle iconStyle, Sprite sprite = null)| +|UpdateIcon()||public void UpdateIcon(IconStyle iconStyle, Sprite sprite = null, Color color = default(Color))| ## ChartObject @@ -599,6 +608,15 @@ slug: /api |public method|since|description| |--|--|--| |DefaultAnimationAttribute()||public DefaultAnimationAttribute(AnimationType handler)| +|DefaultAnimationAttribute()||public DefaultAnimationAttribute(AnimationType handler, bool enableSerieDataAddedAnimation)| + +## DefaultTooltipAttribute + +> XCharts.Runtime.DefaultTooltipAttribute : [Attribute](https://docs.unity3d.com/ScriptReference/30_search.html?q=attribute) + +|public method|since|description| +|--|--|--| +|DefaultTooltipAttribute()||public DefaultTooltipAttribute(Tooltip.Type type, Tooltip.Trigger trigger)| ## DefineSymbolsUtil @@ -625,6 +643,10 @@ slug: /api > XCharts.Runtime.GridCoordContext : [MainComponentContext](#maincomponentcontext) +## GridLayoutContext + +> XCharts.Runtime.GridLayoutContext : [MainComponentContext](#maincomponentcontext) + ## HeatmapChart > XCharts.Runtime.HeatmapChart : [BaseChart](#basechart) @@ -659,14 +681,19 @@ slug: /api |Reset()||public void Reset()| |SetColor()||public void SetColor(ref bool needInteract, Color32 color)| |SetColor()||public void SetColor(ref bool needInteract, Color32 color, Color32 toColor)| -|SetValue()||public void SetValue(ref bool needInteract, float size)| -|SetValue()||public void SetValue(ref bool needInteract, float size, bool highlight, float rate = 1.3f)| +|SetPosition()||public void SetPosition(ref bool needInteract, Vector3 pos)| +|SetValue()||public void SetValue(ref bool needInteract, float value, bool highlight, float rate = 1.3f)| +|SetValue()||public void SetValue(ref bool needInteract, float value, bool previousValueZero = false)| |SetValueAndColor()||public void SetValueAndColor(ref bool needInteract, float value, Color32 color)| |SetValueAndColor()||public void SetValueAndColor(ref bool needInteract, float value, Color32 color, Color32 toColor)| +|ToString()||public override string ToString()| |TryGetColor()||public bool TryGetColor(ref Color32 color, ref bool interacting, float animationDuration = 250)| |TryGetColor()||public bool TryGetColor(ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)| +|TryGetPosition()||public bool TryGetPosition(ref Vector3 pos, ref bool interacting, float animationDuration = 250)| |TryGetValue()||public bool TryGetValue(ref float value, ref bool interacting, float animationDuration = 250)| |TryGetValueAndColor()||public bool TryGetValueAndColor(ref float value, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)| +|TryGetValueAndColor()||public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref bool interacting, float animationDuration = 250)| +|TryGetValueAndColor()||public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)| ## IPropertyChanged @@ -693,7 +720,7 @@ The interface for serie data component. ## IUpdateRuntimeData -> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis),[DataZoom](#datazoom),[CalendarCoord](#calendarcoord),[GridCoord](#gridcoord),[ParallelCoord](#parallelcoord) +> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis),[DataZoom](#datazoom),[CalendarCoord](#calendarcoord),[GridCoord](#gridcoord),[GridLayout](#gridlayout),[ParallelCoord](#parallelcoord) ## LayerHelper @@ -714,7 +741,7 @@ The interface for serie data component. |public method|since|description| |--|--|--| -|CheckDataHighlighted()||public static bool CheckDataHighlighted(Serie serie, string legendName, bool heighlight)| +|CheckDataHighlighted()||public static int CheckDataHighlighted(Serie serie, string legendName, bool heighlight)| |CheckDataShow()||public static bool CheckDataShow(Serie serie, string legendName, bool show)| |GetContentColor()||public static Color GetContentColor(BaseChart chart, int legendIndex, string legendName, Legend legend, ThemeStyle theme, bool active)| |GetIconColor()||public static Color GetIconColor(BaseChart chart, Legend legend, int readIndex, string legendName, bool active)| @@ -776,7 +803,7 @@ The interface for serie data component. ## MainComponentContext -> XCharts.Runtime.MainComponentContext / Subclasses: [AxisContext](#axiscontext),[DataZoomContext](#datazoomcontext),[LegendContext](#legendcontext),[RadarCoordContext](#radarcoordcontext),[VisualMapContext](#visualmapcontext),[GridCoordContext](#gridcoordcontext),[ParallelCoordContext](#parallelcoordcontext),[PolarCoordContext](#polarcoordcontext) +> XCharts.Runtime.MainComponentContext / Subclasses: [AxisContext](#axiscontext),[DataZoomContext](#datazoomcontext),[LegendContext](#legendcontext),[RadarCoordContext](#radarcoordcontext),[VisualMapContext](#visualmapcontext),[GridCoordContext](#gridcoordcontext),[GridLayoutContext](#gridlayoutcontext),[ParallelCoordContext](#parallelcoordcontext),[PolarCoordContext](#polarcoordcontext) ## MainComponentHandler @@ -820,6 +847,10 @@ The interface for serie data component. |IsInteger()||public static bool IsInteger(double value)| |Lerp()||public static double Lerp(double a, double b, double t)| +## MonoBehaviour + +> .MonoBehaviour / Subclasses: [XLog](#xlog) + ## ObjectPool<T> where T > XCharts.Runtime.ObjectPool<T> where T : [new()](#new()) @@ -1029,11 +1060,14 @@ the data of serie event. |public method|since|description| |--|--|--| +|AfterUpdate()||public virtual void AfterUpdate() { }| +|BeforeUpdate()||public virtual void BeforeUpdate() { }| |CheckComponent()||public virtual void CheckComponent(StringBuilder sb) { }| |DrawBase()||public virtual void DrawBase(VertexHelper vh) { }| |DrawSerie()||public virtual void DrawSerie(VertexHelper vh) { }| |DrawTop()||public virtual void DrawTop(VertexHelper vh) { }| |DrawUpper()||public virtual void DrawUpper(VertexHelper vh) { }| +|ForceUpdateSerieContext()||public virtual void ForceUpdateSerieContext() { }| |InitComponent()||public virtual void InitComponent() { }| |OnBeginDrag()||public virtual void OnBeginDrag(PointerEventData eventData) { }| |OnDrag()||public virtual void OnDrag(PointerEventData eventData) { }| @@ -1063,7 +1097,10 @@ the data of serie event. |public method|since|description| |--|--|--| +|AfterUpdate()||public override void AfterUpdate()| +|BeforeUpdate()||public override void BeforeUpdate()| |DrawLabelLineSymbol()||public void DrawLabelLineSymbol(VertexHelper vh, LabelLine labelLine, Vector3 startPos, Vector3 endPos, Color32 defaultColor)| +|ForceUpdateSerieContext()||public override void ForceUpdateSerieContext()| |GetPointerItemDataDimension()||public override int GetPointerItemDataDimension()| |GetPointerItemDataIndex()||public override int GetPointerItemDataIndex()| |GetSerieDataAutoColor()||public virtual Color GetSerieDataAutoColor(SerieData serieData)| @@ -1125,11 +1162,11 @@ the data of serie event. |GetSerieState()||public static SerieState GetSerieState(SerieData serieData)| |GetSerieSymbol()||public static SerieSymbol GetSerieSymbol(Serie serie, SerieData serieData, SerieState state = SerieState.Auto)| |GetStateStyle()||public static StateStyle GetStateStyle(Serie serie, SerieData serieData, SerieState state)| -|GetSysmbolSize()||public static float GetSysmbolSize(Serie serie, SerieData serieData, ThemeStyle theme, float defaultSize, SerieState state = SerieState.Auto)| +|GetSysmbolSize()||public static float GetSysmbolSize(Serie serie, SerieData serieData, float defaultSize, SerieState state = SerieState.Auto, bool checkAnimation = false)| |GetTitleStyle()||public static TitleStyle GetTitleStyle(Serie serie, SerieData serieData)| |IsAllZeroValue()||public static bool IsAllZeroValue(Serie serie, int dimension = 1)
Whether the data for the specified dimension of serie are all 0. | |IsDownPoint()||public static bool IsDownPoint(Serie serie, int index)| -|UpdateCenter()||public static void UpdateCenter(Serie serie, Vector3 chartPosition, float chartWidth, float chartHeight)
更新运行时中心点和半径 | +|UpdateCenter()||public static void UpdateCenter(Serie serie, BaseChart chart)
更新运行时中心点和半径 | |UpdateFilterData()||public static void UpdateFilterData(Serie serie, DataZoom dataZoom)
根据dataZoom更新数据列表缓存 | |UpdateMinMaxData()||public static void UpdateMinMaxData(Serie serie, int dimension, double ceilRate = 0, DataZoom dataZoom = null)
获得指定维数的最大最小值 | |UpdateRect()||public static void UpdateRect(Serie serie, Vector3 chartPosition, float chartWidth, float chartHeight)| @@ -1141,12 +1178,9 @@ the data of serie event. |public method|since|description| |--|--|--| -|AvoidLabelOverlap()||public static void AvoidLabelOverlap(Serie serie, ComponentTheme theme)| |CanShowLabel()||public static bool CanShowLabel(Serie serie, SerieData serieData, LabelStyle label, int dimesion)| |GetLabelColor()||public static Color GetLabelColor(Serie serie, ThemeStyle theme, int index)| -|GetRealLabelPosition()||public static Vector3 GetRealLabelPosition(Serie serie, SerieData serieData, LabelStyle label, LabelLine labelLine)| |SetGaugeLabelText()||public static void SetGaugeLabelText(Serie serie)| -|UpdatePieLabelPosition()||public static void UpdatePieLabelPosition(Serie serie, SerieData serieData)| ## SerieLabelPool @@ -1280,10 +1314,17 @@ UGUI Graphics Library. |--|--|--| |DrawDiamond()||public static void DrawDiamond(VertexHelper vh, Vector3 center, float size, Color32 color)
Draw a diamond. 画菱形(钻石形状) | |DrawDiamond()||public static void DrawDiamond(VertexHelper vh, Vector3 center, float size, Color32 color, Color32 toColor)
Draw a diamond. 画菱形(钻石形状) | +|DrawDiamond()||public static void DrawDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, Color32 color, Color32 toColor)| |DrawEllipse()||public static void DrawEllipse(VertexHelper vh, Vector3 center, float w, float h, Color32 color, float smoothness = 1)| +|DrawEmptyDiamond()||public static void DrawEmptyDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, float tickness, Color32 color)| +|DrawEmptyDiamond()||public static void DrawEmptyDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, float tickness, Color32 color, Color32 emptyColor)| +|DrawEmptyTriangle()||public static void DrawEmptyTriangle(VertexHelper vh, Vector3 pos, float size, float tickness, Color32 color)| +|DrawEmptyTriangle()||public static void DrawEmptyTriangle(VertexHelper vh, Vector3 pos, float size, float tickness, Color32 color, Color32 backgroundColor)| |DrawLine()||public static void DrawLine(VertexHelper vh, List<Vector3> points, float width, Color32 color, bool smooth, bool closepath = false)| |DrawLine()||public static void DrawLine(VertexHelper vh, Vector3 startPoint, Vector3 endPoint, float width, Color32 color)
Draw a line. 画直线 | |DrawLine()||public static void DrawLine(VertexHelper vh, Vector3 startPoint, Vector3 endPoint, float width, Color32 color, Color32 toColor)
Draw a line. 画直线 | +|DrawMinus()||public static void DrawMinus(VertexHelper vh, Vector3 center, float radius, float tickness, Color32 color)
Draw minus sign. | +|DrawPlus()||public static void DrawPlus(VertexHelper vh, Vector3 center, float radius, float tickness, Color32 color)
Draw plus sign. | |DrawPolygon()||public static void DrawPolygon(VertexHelper vh, List<Vector3> points, Color32 color)
填充任意多边形(目前只支持凸多边形) | |DrawRectangle()||public static void DrawRectangle(VertexHelper vh, Rect rect, Color32 color)| |DrawRectangle()||public static void DrawRectangle(VertexHelper vh, Rect rect, Color32 color, Color32 toColor)| @@ -1410,3 +1451,26 @@ UI帮助类。 |ReloadThemeList()||public static void ReloadThemeList()
重新加载主题列表 | |SwitchTheme()||public static void SwitchTheme(BaseChart chart, string themeName)| +## XLog + +> XCharts.Runtime.XLog : [MonoBehaviour](#monobehaviour) +Log system. Used to output logs with date and log type, support output to file, support custom output log type. + +|public method|since|description| +|--|--|--| +|CanLog()||public static bool CanLog(int level)| +|ClearAllLog()||public static void ClearAllLog()| +|Debug()||public static void Debug(string log)| +|EnableLog()||public static void EnableLog(int logType)| +|Error()||public static void Error(string log)| +|FlushLog()||public static void FlushLog()| +|GetNowTime()||public static string GetNowTime(string formatter = null)| +|GetTimestamp()||public static ulong GetTimestamp()| +|Info()||public static void Info(string log)| +|Log()||public static void Log(string log)| +|LogError()||public static void LogError(string log)| +|LogWarning()||public static void LogWarning(string log)| +|Proto()||public static void Proto(string log)| +|Vital()||public static void Vital(string log)| +|Warning()||public static void Warning(string log)| + diff --git a/Documentation~/en/changelog.md b/Documentation~/en/changelog.md index f3efe7ea..b964587e 100644 --- a/Documentation~/en/changelog.md +++ b/Documentation~/en/changelog.md @@ -2,6 +2,7 @@ # 更新日志 [master](#master) +[v3.8.0](#v380) [v3.7.0](#v370) [v3.6.0](#v360) [v3.5.0](#v350) @@ -62,6 +63,62 @@ ## master +## v3.8.0 + +Highlights: + +* Refactoring `Animation` animation system, adding support for `New Animation` and `Interactive animation` +* Improved `PieChart` animation interactive representation +* Added four new markers for `Symbol` : `EmptyTriangle`, `EmptyDiamond`, `Plus` and `Minus` +* Improved `Chart` mouse interaction callback +* Added the function of `LabelLine` to fix the horizontal coordinate +* Added `GridLayout` grid layout component +* Added `Auto` type for `Tooltip` +* Optimizes and fixes several other issues + +Log details: + +* (2023.09.03) Release `v3.8.0` +* (2023.09.01) Added `Tooltip` Auto to automatically set display type and trigger type +* (2023.08.29) Added gridIndex support for `Ring` to set the specified grid +* (2023.08.29) Added gridIndex support for Radar to set the specified grid +* (2023.08.29) Added gridIndex support for `Pie` to set specified grids +* (2023.08.29) Added the GridLayout component for managing multiple GridCoord layouts +* (2023.08.25) Fixed display only one Label when there are multiple Marklines +* (2023.08.25) Fixed MarkLine drawing outside the coordinate system after opening Clip +* (2023.08.24) Optimizes `YAxis` to default 0-1 range when all data is 0 +* (2023.08.23) Fixed an issue where `Label` of `YAxis` could duplicate +* (2023.08.22) Fixed `Bar` display hidden drawing performance exception +* (2023.08.22) Improved Zebra histogram rendering performance (#276) +* (2023.08.16) Added Daemon daemon to resolve an error after TMP is enabled locally +* (2023.08.15) Fixed `Data` displaying axes incorrectly when data is between -1 and 1 (#273) (by __Ambitroc__) +* (2023.08.14) Fixed `XCharts` updating error after` TextMeshPro `and` NewInputSystem `are enabled locally (#272) +* (2023.08.12) Fixed `Chart` error when deleted at runtime (#269) +* (2023.08.11) Fixed an issue where data could not be added when DataZoom was enabled +* (2023.08.11) Fixed `itemFormatter` not working when `SerieData` sets ItemStyle separately +* (2023.08.10) Improved BarChart`s performance when Tooltip`s Trigger is an Item +* (2023.08.09) Added `Axis` to support dynamic icon colors by setting `color` of `IconStyle` to `clear` +* (2023.08.08) Added support for `Pie` for `LabelLine`s` lineEndX ` +* (2023.08.05) Clean up the code for `Examples` and remove unnecessary use cases +* (2023.08.04) Added support for `LabelLine`'s `lineEndX` to set the boot line to fixed X position +* (2023.08.04) Added support for Ring`s avoidLabelOverlap to avoid text stacking (#247) +* (2023.08.03) Improved Chart`s onSerieEnter, onSerieExit, and onSerieClick callbacks +* (2023.08.02) Fixed invalid `onSerieEnter` and `onSerieExit` callbacks for `BarChart` +* (2023.08.02) Added support for Symbol's `Plus` and `Minus` signs +* (2023.07.31) Added support for Symbol's `EmptyTriangle` and `EmptyDiamond`, improved `Symbol` performance +* (2023.07.31) Improved the default configuration effect of `Line` +* (2023.07.27) Add `Serie` to `minRadius` to set minimum radius +* (2023.07.26) Added `MLValue` multiple values +* (2023.07.25) Added `XLog` log system +* (2023.07.18) Improved the interactive animation effect of `Pie` pie chart +* (2023.07.14) Added support for `Animation` `Interaction` interactive animation configuration +* (2023.07.11) Added `Animation` `Addition` new animation configuration support +* (2023.07.11) Reconstructs `Animation` animation system to improve animation experience +* (2023.06.30) Added support for PolarCood`s indicatorLabelOffset setting indicating text offsets +* (2023.06.30) Fixed an issue where the background color of Axis `IndicatorLabel` could be abnormal +* (2023.06.30) Added support for Axis `IndicatorLabel` customizable `color` +* (2023.06.12) Fixed an issue where AxisLabel's formatterFunction had the wrong value on the value axis + ## v3.7.0 Highlights: @@ -75,17 +132,17 @@ Log details: * (2022.06.08) Release v3.7.0 * (2023.06.04) Added `HelpDoc` help document skip -* (2023.05.30) Fix to Serie name with `_` line causing `Legend` to not fire (#252) (by __svr2kos2__) +* (2023.05.30) Fixed Serie name with `_` line causing `Legend` to not fire (#252) (by __svr2kos2__) * (2023.05.10) Added `MinMaxAuto` range type for `Axis` * (2023.05.10) Added support for `Clip` for `Line` * (2023.05.04) Fixed `Axis` setting` CeilRate `not taking effect in range -1 to 1 * (2023.05.04) Optimizes MinMax type range calculations for Axis -* (2023.05.04) Fix to AxisLabel displaying `Label` formatting incorrectly when the data is all floating point numbers less than 1 -* (2023.05.04) Fix to `Theme` being reset after modifying default theme parameters +* (2023.05.04) Fixed AxisLabel displaying `Label` formatting incorrectly when the data is all floating point numbers less than 1 +* (2023.05.04) Fixed `Theme` being reset after modifying default theme parameters * (2023.05.04) Added `Warning` when `Symbol` selects `Custom` type -* (2023.04.15) Fix to `DataZoom` may be abnormal in multiple charts (#252) -* (2023.04.14) Fix to `Tooltip` may be abnormal when there is only one data -* (2023.04.14) added `BaseChart`s `TriggerTooltip()` interface to try to trigger `ToolTip` +* (2023.04.15) Fixed `DataZoom` may be abnormal in multiple charts (#252) +* (2023.04.14) Fixed `Tooltip` may be abnormal when there is only one data +* (2023.04.14) Added `BaseChart`s `TriggerTooltip()` interface to try to trigger `ToolTip` * (2023.04.12) Optimizes` RadarCood `setting` startAngle `with text following the adjustment position * (2023.04.12) Added `Radar` support for wildcard `{b}` * (2023.04.11) Fixed an issue where Inspector could be abnormal when dynamically adding components @@ -153,7 +210,7 @@ Log details: * (2022.11.26) Fixed an exception when selecting `DataZoom` from right to left * (2022.11.20) Rename `UdpateXAxisIcon()` interface to `UpdateXAxisIcon()` (#235) * (2022.11.12) Added `Pie` `LabelLine` support `Symbol` -* (2022.11.12) added `DataZoom` `MarqueeStyle` support box selection area +* (2022.11.12) Added `DataZoom` `MarqueeStyle` support box selection area * (2022.11.10) Optimized area color fill effect for `Radar` when type is` Single ` * (2022.11.04) Fixed exception after itemFormatter `Tooltip` set wildcard `{d}` @@ -217,7 +274,7 @@ Details: * (2022.09.06) Added support for `SerieSymbol` `minSize` and `maxSize` parameters to set maximum and minimum sizes * (2022.09.06) Added support for `showStartLine` and `showEndLine` parameters for `AxisSplitLine` to set whether to display the first splitter * (2022.09.06) Added `Heatmap` support for different patterns via `symbol` -* (2022.09.05) added `Heatmap` `heatmapType` support for setting `Data` and `Count` two different mapping methods of Heatmap +* (2022.09.05) Added `Heatmap` `heatmapType` support for setting `Data` and `Count` two different mapping methods of Heatmap * (2022.09.05) Optimizes `Tooltip` when indicating numerical axis in thermograph * (2022.09.02) Added `onPointerEnterPie` callback support * (2022.09.02) Optimize the HeatmapChart ` @@ -227,7 +284,7 @@ Details: * (2022.08.29) optimizes `YAxis` Max/min calculations when `DataZoom` is enabled * (2022.08.29) optimized `CandlestickChart` massive data rendering * (2022.08.28) fixed an issue where `LineChart` does not appear properly in the case of stacking and custom Y-axis range -* (2022.08.26) added `Legend` new icon type `Candlestick` +* (2022.08.26) Added `Legend` new icon type `Candlestick` * (2022.08.26) optimizes` CandlestickChart `performance and adjusts related` AddData() `interface parameters * (2022.08.26) Added support for setting different display positions in Tooltip's `position` parameter * (2022.08.26) Delete the `fixedXEnable` and `fixedYEnable` arguments of Tooltip @@ -259,7 +316,7 @@ Details: * (2022.08.10) Optimized font synchronization for Theme * (2022.08.10) optimizes the default `layer` of Chart to `UI` * (2022.08.09) optimizes the `Time` timeline of `Axis` -* (2022.08.09) added AreaStyle `innerFill` parameter to support filling convex polygons +* (2022.08.09) Added AreaStyle `innerFill` parameter to support filling convex polygons * (2022.08.08) Optimized the maintenance of data item indexes in `Serie`, added detection and repair functions, and fixed related problems * (2022.07.29) Fixed `Unity` version compatibility: Chart creation exception after some versions import * (2022.07.29) Add `Axis` to` Time `timeline, support sub-scale and sub-divider @@ -273,10 +330,10 @@ Details: * (2022.07.22) Omit the `Emphasis`,` EmphasisItemStyle `, `EmphasisLabelStyle`, `EmphasisLabelLine` component * (2022.07.20) Added `Since` feature support for classes * (2022.07.20) fixed the `showStartLabel` and `showEndLabel` parameter Settings for `AxisLabel` not taking effect when `Axis` is on the` Value `Axis -* (2022.07.19) added `Axis` to` MinorSplitLine `to set the Axis degree divider -* (2022.07.19) added `Axis` `MinorTick` to set the Axis sub-scale +* (2022.07.19) Added `Axis` to` MinorSplitLine `to set the Axis degree divider +* (2022.07.19) Added `Axis` `MinorTick` to set the Axis sub-scale * (2022.07.17) Add the `smooth` parameter for Radar to set the smooth curve -* (2022.07.15) added DataZoom support for the `Time` timeline +* (2022.07.15) Added DataZoom support for the `Time` timeline ## v3.1.0 @@ -287,7 +344,7 @@ Details: * (2022.07.04) Added the axisMaxSplitNumber parameter of `Settings` to set the maximum number of partitions for `Axis` * (2022.07.04) Fixed Axis` Tick `drawing position after setting `offset`(#209) * (2022.07.03) Optimize the `AxisLabel` formatterFunction custom delegate -* (2022.07.03) added the `onZero` parameter of `AxisName` to support setting the coordinate AxisName and position to match the Y-axis 0 scale (#207) +* (2022.07.03) Added the `onZero` parameter of `AxisName` to support setting the coordinate AxisName and position to match the Y-axis 0 scale (#207) * (2022.07.02) Fixed bug where `Legend` was not working when `PieChart` was being created dynamically with code (#206) * (2022.07.02) Fixed `YAxis` AxisLabel setting `onZero` not working * (2022.07.02) Fixed `AxisLabel` code refreshing after setting `distance` property diff --git a/Documentation~/en/configuration.md b/Documentation~/en/configuration.md index ddf8328e..807a7430 100644 --- a/Documentation~/en/configuration.md +++ b/Documentation~/en/configuration.md @@ -56,6 +56,7 @@ import APITable from '@site/src/components/APITable'; - [CoordSystem](#coordsystem) - [DataZoom](#datazoom) - [GridCoord](#gridcoord) +- [GridLayout](#gridlayout) - [Legend](#legend) - [MarkArea](#markarea) - [MarkLine](#markline) @@ -112,6 +113,7 @@ import APITable from '@site/src/components/APITable'; - [MarkAreaData](#markareadata) - [MarkLineData](#marklinedata) - [MarqueeStyle](#marqueestyle) +- [MLValue](#mlvalue) - [Padding](#padding) - [PolarAxisTheme](#polaraxistheme) - [RadarAxisTheme](#radaraxistheme) @@ -166,6 +168,13 @@ import APITable from '@site/src/components/APITable'; ## Other +- [AnimationAddition](#animationaddition) +- [AnimationChange](#animationchange) +- [AnimationFadeIn](#animationfadein) +- [AnimationFadeOut](#animationfadeout) +- [AnimationHiding](#animationhiding) +- [AnimationInfo](#animationinfo) +- [AnimationInteraction](#animationinteraction) - [BaseSerie](#baseserie) - [ChartText](#charttext) - [ChildComponent](#childcomponent) @@ -209,11 +218,98 @@ Angle axis of Polar Coordinate. > XCharts.Runtime.AngleAxisTheme : [BaseAxisTheme](#baseaxistheme) +## AnimationAddition + +> XCharts.Runtime.AnimationAddition : [AnimationInfo](#animationinfo) + +> Since `v3.8.0` + +Data addition animation. + +## AnimationChange + +> XCharts.Runtime.AnimationChange : [AnimationInfo](#animationinfo) + +> Since `v3.8.0` + +Data change animation. + +## AnimationFadeIn + +> XCharts.Runtime.AnimationFadeIn : [AnimationInfo](#animationinfo) + +> Since `v3.8.0` + +Fade in animation. + +## AnimationFadeOut + +> XCharts.Runtime.AnimationFadeOut : [AnimationInfo](#animationinfo) + +> Since `v3.8.0` + +Fade out animation. + +## AnimationHiding + +> XCharts.Runtime.AnimationHiding : [AnimationInfo](#animationinfo) + +> Since `v3.8.0` + +Data hiding animation. + +## AnimationInfo + +> XCharts.Runtime.AnimationInfo / Subclasses: [AnimationFadeIn](#animationfadein), [AnimationFadeOut](#animationfadeout), [AnimationChange](#animationchange), [AnimationAddition](#animationaddition), [AnimationHiding](#animationhiding), [AnimationInteraction](#animationinteraction) + +> Since `v3.8.0` + +the animation info. + +```mdx-code-block + +``` + + +|field|default|since|comment| +|--|--|--|--| +|enable|true|v3.8.0|whether enable animation. +|reverse|false|v3.8.0|whether enable reverse animation. +|delay|0|v3.8.0|the delay time before animation start. +|duration|1000|v3.8.0|the duration of animation. + +```mdx-code-block + +``` + +## AnimationInteraction + +> XCharts.Runtime.AnimationInteraction : [AnimationInfo](#animationinfo) + +> Since `v3.8.0` + +Interactive animation of charts. + +```mdx-code-block + +``` + + +|field|default|since|comment| +|--|--|--|--| +|width||v3.8.0|the mlvalue of width. [MLValue](#mlvalue)| +|radius||v3.8.0|the mlvalue of radius. [MLValue](#mlvalue)| +|offset||v3.8.0|the mlvalue of offset. Such as the offset of the pie chart when the sector is selected. [MLValue](#mlvalue)| + +```mdx-code-block + +``` + ## AnimationStyle > XCharts.Runtime.AnimationStyle : [ChildComponent](#childcomponent) -the animation of serie. +the animation of serie. support animation type: fadeIn, fadeOut, change, addition. ```mdx-code-block @@ -224,16 +320,15 @@ the animation of serie. |--|--|--|--| |enable|true||Whether to enable animation. |type|||The type of animation.
`AnimationType`:
- `Default`: he default. An animation playback mode will be selected according to the actual situation.
- `LeftToRight`: Play the animation from left to right.
- `BottomToTop`: Play the animation from bottom to top.
- `InsideOut`: Play animations from the inside out.
- `AlongPath`: Play the animation along the path.
- `Clockwise`: Play the animation clockwise.
| -|easting|||Easing method used for the first animation.
`AnimationEasing`:
- `Linear`:
| +|easting|||
`AnimationEasing`:
- `Linear`:
| |threshold|2000||Whether to set graphic number threshold to animation. Animation will be disabled when graphic number is larger than threshold. -|fadeInDuration|1000||The milliseconds duration of the fadeIn animation. -|fadeInDelay|0||The milliseconds delay before updating the first animation. -|fadeOutDuration|1000f||The milliseconds duration of the fadeOut animation. -|fadeOutDelay|0||渐出动画延时(毫秒)。如果要设置单个数据项的延时,可以用代码定制:customFadeOutDelay。 -|dataChangeEnable|true||是否开启数据变更动画。 -|dataChangeDuration|500||The milliseconds duration of the data change animation. -|actualDuration|||The milliseconds actual duration of the first animation. |unscaledTime||v3.4.0|Animation updates independently of Time.timeScale. +|fadeIn||v3.8.0|Fade in animation configuration. [AnimationFadeIn](#animationfadein)| +|fadeOut||v3.8.0|Fade out animation configuration. [AnimationFadeOut](#animationfadeout)| +|change||v3.8.0|Update data animation configuration. [AnimationChange](#animationchange)| +|addition||v3.8.0|Add data animation configuration. [AnimationAddition](#animationaddition)| +|hiding||v3.8.0|Data hiding animation configuration. [AnimationHiding](#animationhiding)| +|interaction||v3.8.0|Interaction animation configuration. [AnimationInteraction](#animationinteraction)| ```mdx-code-block
@@ -624,7 +719,7 @@ Configurations of blur state. ## ChildComponent -> XCharts.Runtime.ChildComponent / Subclasses: [AnimationStyle](#animationstyle), [AxisName](#axisname), [AxisSplitArea](#axissplitarea), [AreaStyle](#areastyle), [ArrowStyle](#arrowstyle), [BaseLine](#baseline), [IconStyle](#iconstyle), [ImageStyle](#imagestyle), [ItemStyle](#itemstyle), [Level](#level), [LevelStyle](#levelstyle), [LineArrow](#linearrow), [LineStyle](#linestyle), [Location](#location), [MarqueeStyle](#marqueestyle), [Padding](#padding), [StageColor](#stagecolor), [SymbolStyle](#symbolstyle), [TextLimit](#textlimit), [TextStyle](#textstyle), [CommentItem](#commentitem), [CommentMarkStyle](#commentmarkstyle), [LabelLine](#labelline), [LabelStyle](#labelstyle), [MarkAreaData](#markareadata), [MarkLineData](#marklinedata), [StateStyle](#statestyle), [VisualMapRange](#visualmaprange), [UIComponentTheme](#uicomponenttheme), [SerieData](#seriedata), [ComponentTheme](#componenttheme), [SerieTheme](#serietheme), [ThemeStyle](#themestyle) +> XCharts.Runtime.ChildComponent / Subclasses: [AnimationStyle](#animationstyle), [AxisName](#axisname), [AxisSplitArea](#axissplitarea), [AreaStyle](#areastyle), [ArrowStyle](#arrowstyle), [BaseLine](#baseline), [IconStyle](#iconstyle), [ImageStyle](#imagestyle), [ItemStyle](#itemstyle), [Level](#level), [LevelStyle](#levelstyle), [LineArrow](#linearrow), [LineStyle](#linestyle), [Location](#location), [MLValue](#mlvalue), [MarqueeStyle](#marqueestyle), [Padding](#padding), [StageColor](#stagecolor), [SymbolStyle](#symbolstyle), [TextLimit](#textlimit), [TextStyle](#textstyle), [CommentItem](#commentitem), [CommentMarkStyle](#commentmarkstyle), [LabelLine](#labelline), [LabelStyle](#labelstyle), [MarkAreaData](#markareadata), [MarkLineData](#marklinedata), [StateStyle](#statestyle), [VisualMapRange](#visualmaprange), [UIComponentTheme](#uicomponenttheme), [SerieData](#seriedata), [ComponentTheme](#componenttheme), [SerieTheme](#serietheme), [ThemeStyle](#themestyle) ## Comment @@ -858,6 +953,7 @@ Grid component. |field|default|since|comment| |--|--|--|--| |show|true||Whether to show the grid in rectangular coordinate. +|layoutIndex|-1|v3.8.0|The index of the grid layout component to which the grid belongs. The default is -1, which means that it does not belong to any grid layout component. When this value is set, the left, right, top, and bottom properties will be invalid. |left|0.1f||Distance between grid component and the left side of the container. |right|0.08f||Distance between grid component and the right side of the container. |top|0.22f||Distance between grid component and the top side of the container. @@ -871,6 +967,35 @@ Grid component. ``` +## GridLayout + +> XCharts.Runtime.GridLayout : [MainComponent](#maincomponent), [IUpdateRuntimeData](#iupdateruntimedata) + +> Since `v3.8.0` + +Grid layout component. Used to manage the layout of multiple `GridCoord`, and the number of rows and columns of the grid can be controlled by `row` and `column`. + +```mdx-code-block + +``` + + +|field|default|since|comment| +|--|--|--|--| +|show|true||Whether to show the grid in rectangular coordinate. +|left|0.1f||Distance between grid component and the left side of the container. +|right|0.08f||Distance between grid component and the right side of the container. +|top|0.22f||Distance between grid component and the top side of the container. +|bottom|0.12f||Distance between grid component and the bottom side of the container. +|row|2||the row count of grid layout. +|column|2||the column count of grid layout. +|spacing|Vector2.zero||the spacing of grid layout. +|inverse|false||Whether to inverse the grid layout. + +```mdx-code-block + +``` + ## Heatmap > XCharts.Runtime.Heatmap : [Serie](#serie), [INeedSerieContainer](#ineedseriecontainer) @@ -972,6 +1097,7 @@ Indicator of radar chart, which is used to assign multiple variables(dimensions) |connectCenter|false||Whether serie data connect to radar center with line. |lineGradient|true||Whether need gradient for data line. |startAngle||v3.4.0|起始角度。和时钟一样,12点钟位置是0度,顺时针到360度。 +|gridIndex|-1|v3.8.0|Index of layout component that serie uses. Default is -1 means not use layout, otherwise use the first layout component. |indicatorList|||the indicator list. ```mdx-code-block @@ -1048,7 +1174,7 @@ The interface for serie data component. ## IUpdateRuntimeData -> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis), [DataZoom](#datazoom), [CalendarCoord](#calendarcoord), [GridCoord](#gridcoord), [ParallelCoord](#parallelcoord) +> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis), [DataZoom](#datazoom), [CalendarCoord](#calendarcoord), [GridCoord](#gridcoord), [GridLayout](#gridlayout), [ParallelCoord](#parallelcoord) ## LabelLine @@ -1066,11 +1192,12 @@ The interface for serie data component. |show|true||Whether the label line is showed. |lineType|||the type of visual guide line.
`LabelLine.LineType`:
- `BrokenLine`: 折线
- `Curves`: 曲线
- `HorizontalLine`: 水平线
| |lineColor|Color32(0,0,0,0)||the color of visual guild line. -|lineAngle|0||the angle of visual guild line. +|lineAngle|60||the angle of visual guild line. Valid for broken line and curve line. Invalid in Pie. |lineWidth|1.0f||the width of visual guild line. |lineGap|1.0f||the gap of container and guild line. |lineLength1|25f||The length of the first segment of visual guide line. |lineLength2|15f||The length of the second segment of visual guide line. +|lineEndX|0f|v3.8.0|The fixed x position of the end point of visual guide line. |startSymbol|||The symbol of the start point of labelline. [SymbolStyle](#symbolstyle)| |endSymbol|||The symbol of the end point of labelline. [SymbolStyle](#symbolstyle)| @@ -1290,7 +1417,7 @@ Location type. Quick to set the general location. ## MainComponent -> XCharts.Runtime.MainComponent : [IComparable](https://docs.unity3d.com/ScriptReference/30_search.html?q=IComparable) / Subclasses: [Axis](#axis), [Background](#background), [Comment](#comment), [DataZoom](#datazoom), [Legend](#legend), [MarkArea](#markarea), [MarkLine](#markline), [Settings](#settings), [Title](#title), [Tooltip](#tooltip), [VisualMap](#visualmap), [CoordSystem](#coordsystem) +> XCharts.Runtime.MainComponent : [IComparable](https://docs.unity3d.com/ScriptReference/30_search.html?q=IComparable) / Subclasses: [Axis](#axis), [Background](#background), [Comment](#comment), [DataZoom](#datazoom), [Legend](#legend), [MarkArea](#markarea), [MarkLine](#markline), [Settings](#settings), [Title](#title), [Tooltip](#tooltip), [VisualMap](#visualmap), [GridLayout](#gridlayout), [CoordSystem](#coordsystem) ## MarkArea @@ -1419,6 +1546,28 @@ Marquee style. It can be used for the DataZoom component. 选取框样式。可 ``` +## MLValue + +> XCharts.Runtime.MLValue : [ChildComponent](#childcomponent) + +> Since `v3.8.0` + +多样式数值。 + +```mdx-code-block + +``` + + +|field|default|since|comment| +|--|--|--|--| +|type|||
`MLValue.Type`:
- `Percent`: Percent value form.
- `Absolute`: Absolute value form.
- `Extra`: Extra value form.
| +|value||| + +```mdx-code-block +
+``` + ## Padding > XCharts.Runtime.Padding : [ChildComponent](#childcomponent) / Subclasses: [TextPadding](#textpadding) @@ -1500,6 +1649,7 @@ Polar coordinate can be used in scatter and line chart. Every polar coordinate h |center|||The center of ploar. The center[0] is the x-coordinate, and the center[1] is the y-coordinate. When value between 0 and 1 represents a percentage relative to the chart. |radius|||the radius of polar. |backgroundColor|||Background color of polar, which is transparent by default. +|indicatorLabelOffset|30f|v3.8.0|The offset of indicator label. ```mdx-code-block @@ -1586,6 +1736,7 @@ Configurations of select state. |polarIndex|0||Index of polar component that serie uses. |singleAxisIndex|0||Index of single axis component that serie uses. |parallelIndex|0||Index of parallel coord component that serie uses. +|gridIndex|-1|v3.8.0|Index of layout component that serie uses. Default is -1 means not use layout, otherwise use the first layout component. |minShow|||The min number of data to show in chart. |maxShow|||The max number of data to show in chart. |maxCache|||The max number of serie data cache. The first data will be remove when the size of serie data is larger then maxCache. @@ -1616,6 +1767,7 @@ Configurations of select state. |gap|||gap of item. |center|||the center of chart. |radius|||the radius of chart. +|minRadius|0f|v3.8.0|the min radius of chart. It can be used to limit the minimum radius of the rose chart. |showDataDimension|||数据项里的数据维数。 |showDataName|||在Editor的inpsector上是否显示name参数 |clip|false||If clip the overflow on the coordinate system. @@ -1715,9 +1867,6 @@ A data item of serie. |lineWidth|||the color of text. |lineSymbolSize|||the symbol size of line serie. |scatterSymbolSize|||the symbol size of scatter serie. -|pieTooltipExtraRadius|||the extra radius of pie when actived by tooltip. -|selectedRate|1.3f||the rate of symbol size of line or scatter serie. -|pieSelectedOffset|||the center offset of pie if selected. |candlestickColor|Color32(235, 84, 84, 255)||K线图阳线(涨)填充色 |candlestickColor0|Color32(71, 178, 98, 255)||K线图阴线(跌)填充色 |candlestickBorderWidth|1||K线图边框宽度 @@ -1864,7 +2013,7 @@ the state style of serie. |field|default|since|comment| |--|--|--|--| |show|true||Whether the symbol is showed. -|type|||the type of symbol.
`SymbolType`:
- `None`: 不显示标记。
- `Custom`: 自定义标记。
- `Circle`: 圆形。
- `EmptyCircle`: 空心圆。
- `Rect`: 正方形。可通过设置`itemStyle`的`cornerRadius`变成圆角矩形。
- `EmptyRect`: 空心正方形。
- `Triangle`: 三角形。
- `EmptyTriangle`: 空心三角形。
- `Diamond`: 菱形。
- `EmptyDiamond`: 空心菱形。
- `Arrow`: 箭头。
- `EmptyArrow`: 空心箭头。
| +|type|||the type of symbol.
`SymbolType`:
- `None`: 不显示标记。
- `Custom`: 自定义标记。
- `Circle`: 圆形。
- `EmptyCircle`: 空心圆。
- `Rect`: 正方形。可通过设置`itemStyle`的`cornerRadius`变成圆角矩形。
- `EmptyRect`: 空心正方形。
- `Triangle`: 三角形。
- `EmptyTriangle`: 空心三角形。
- `Diamond`: 菱形。
- `EmptyDiamond`: 空心菱形。
- `Arrow`: 箭头。
- `EmptyArrow`: 空心箭头。
- `Plus`: 加号。
- `Minus`: 减号。
| |size|0f||the size of symbol. |gap|0||the gap of symbol and line segment. |width|0f||图形的宽。 @@ -2047,8 +2196,8 @@ Tooltip component. |field|default|since|comment| |--|--|--|--| |show|true||Whether to show the tooltip component. -|type|||Indicator type.
`Tooltip.Type`:
- `Line`: line indicator.
- `Shadow`: shadow crosshair indicator.
- `None`: no indicator displayed.
- `Corss`: crosshair indicator, which is actually the shortcut of enable two axisPointers of two orthometric axes.
| -|trigger|||Type of triggering.
`Tooltip.Trigger`:
- `Item`: Triggered by data item, which is mainly used for charts that don't have a category axis like scatter charts or pie charts.
- `Axis`: Triggered by axes, which is mainly used for charts that have category axes, like bar charts or line charts.
- `None`: Trigger nothing.
| +|type|||Indicator type.
`Tooltip.Type`:
- `Line`: line indicator.
- `Shadow`: shadow crosshair indicator.
- `None`: no indicator displayed.
- `Corss`: crosshair indicator, which is actually the shortcut of enable two axisPointers of two orthometric axes.
- `Auto`: Auto select indicator according to serie type.
| +|trigger|||Type of triggering.
`Tooltip.Trigger`:
- `Item`: Triggered by data item, which is mainly used for charts that don't have a category axis like scatter charts or pie charts.
- `Axis`: Triggered by axes, which is mainly used for charts that have category axes, like bar charts or line charts.
- `None`: Trigger nothing.
- `Auto`: Auto select trigger according to serie type.
| |position||v3.3.0|Type of position.
`Tooltip.Position`:
- `Auto`: Auto. The mobile platform is displayed at the top, and the non-mobile platform follows the mouse position.
- `Custom`: Custom. Fully customize display position (x,y).
- `FixedX`: Just fix the coordinate X. Y follows the mouse position.
- `FixedY`:
| |itemFormatter|||a string template formatter for a single Serie or data item content. Support for wrapping lines with \n. Template variables are {.}, {a}, {b}, {c}, {d}.
{.} is the dot of the corresponding color of a Serie that is currently indicated or whose index is 0.
{a} is the series name of the serie that is currently indicated or whose index is 0.
{b} is the name of the data item serieData that is currently indicated or whose index is 0, or a category value (such as the X-axis of a line chart).
{c} is the value of a Y-dimension (dimesion is 1) from a Serie that is currently indicated or whose index is 0.
{d} is the percentage value of Y-dimensions (dimesion is 1) from serie that is currently indicated or whose index is 0, with no % sign.
{e} is the name of the data item serieData that is currently indicated or whose index is 0.
{f} is sum of data.
{.1} represents a dot from serie corresponding color that specifies index as 1.
1 in {a1}, {b1}, {c1} represents a serie that specifies an index of 1.
{c1:2} represents the third data from serie's current indication data item indexed to 1 (a data item has multiple data, index 2 represents the third data).
{c1:2-2} represents the third data item from serie's third data item indexed to 1 (i.e., which data item must be specified to specify).
{d1:2: F2} indicates that a formatted string with a value specified separately is F2 (numericFormatter is used when numericFormatter is not specified).
{d:0.##} indicates that a formatted string with a value specified separately is 0.## (used for percentage, reserved 2 valid digits while avoiding the situation similar to "100.00%" when using f2 ).
Example: "{a}, {c}", "{a1}, {c1: f1}", "{a1}, {c1:0: f1}", "{a1} : {c1:1-1: f1}"
|titleFormatter|||The string template formatter for the tooltip title content. Support for wrapping lines with \n. The placeholder {I} can be set separately to indicate that the title is ignored and not displayed. Template see itemFormatter. @@ -2262,8 +2411,6 @@ The x axis in cartesian(rectangular) coordinate. |lineSegmentDistance|3f|| |cicleSmoothness|2f|| |visualMapTriangeLen|20f|| -|pieTooltipExtraRadius|8f|| -|pieSelectedOffset|8f|| |customThemes||| ```mdx-code-block diff --git a/Documentation~/en/tutorial01.md b/Documentation~/en/tutorial01.md index 621a4e0d..bf2e710f 100644 --- a/Documentation~/en/tutorial01.md +++ b/Documentation~/en/tutorial01.md @@ -1,85 +1,103 @@ -# 教程:5分钟上手 XCharts 3.0 +--- +title: Introductory tutorial: Get started with XCharts 3.0 in 5 minutes +sidebar_position: 11 +slug: /tutorial01 +--- -## 获取和导入 XCharts +# Tutorial: Get started with XCharts 3.0 in 5 minutes -XCharts可通过以下任意一种方式导入到项目: +> Note: This tutorial is for XCharts 3.x version only -- 直接将XCharts源码到项目 +## What do I need to know before using XCharts - 下载好XCharts源码后,直接将XCharts目录拷贝到Unity项目工程的Assets目录或Packages目录下,编译通过后即可使用。 +- Have used Unity, know the basic operation of Unity. +- Understand UGUI and can use UGUI. +- Understand MonoBehavior script usage in Unity, know how to hang scripts, manipulate scripts with code. -- 通过`Assets/Import Package`导入XCharts +## Get and import XCharts - 下载好XCharts的.unitypackage文件后,打开Unity,菜单栏 Assets-->Import Package-->选中.unitypackage导入即可开始使用XCharts。 +XCharts can be imported into a project in any of the following ways: -- 通过`Package Manager`导入XCharts +- Source XCharts directly into the project - 对于Unity 2018.3以上版本,可通过 Package Manager来导入XCharts,打开Package Manager后,通过 `Add package form git URL...`,输入XCharts3.0的GitHub URL: `https://github.com/XCharts-Team/XCharts.git#3.0` 稍等片刻后即可使用XCharts。 + After downloading the XCharts source code, copy the XCharts directory directly to the Assets directory of the Unity project. - 也可以直接将package加入到`manifest.json`文件:打开`Packages`目录下的`manifest.json`文件,在`dependencies`下加入: +- Import XCharts through `Assets/Import Package` + + After downloading the.unitypackage file for XCharts, open Unity and go to the menu bar Assets--> Import Package--> Select.unitypackage import to start using XCharts. + +- Import XCharts through the Package Manager + + For Unity 2018.3 and later, XCharts can be imported through the Package Manager. After opening the Package Manager, run the `Add package form git URL...`, input XCharts dead simple URL: ` https://github.com/XCharts-Team/XCharts.git use XCharts after ` wait a moment. + + You can also add the package directly to the manifest.json file: Open the manifest.json file in the Packages directory and add it under dependencies: ``` json - "com.monitor1394.xcharts": "https://github.com/XCharts-Team/XCharts.git#3.0", + "com.monitor1394.xcharts" : "https://github.com/XCharts-Team/XCharts.git", ``` - 如需更新`XCharts`,删除`manifest.json`文件(部分Unity版本可能是packages-lock.json文件)的`lock`下的`com.monitor1394.xcharts`相关内容即会重新下载编译。 + To update XCharts, remove com.monitor1394.xcharts from the manifest.json file under lock (some versions of Unity may be packages-lock.json) and re-download and compile. -## 添加一个简单图表 +- Recommended daemon into XCharts (not required) -在`Hierarchy`视图下右键或菜单栏`GameObject`下拉选择`XCharts->LineChart`,即可快速创建一个默认的折线图出来: + [XCharts Daemon](https://github.com/XCharts-Team/XCharts-Daemon) can ensure update compilation is normal, when the local open TextMeshPro or NewInputSystem would be very useful. After importing Xchart-daemon into a project, when updating XCharts, the Daemon will automatically refresh asmdef according to the status of local TMP, etc., to ensure normal compilation and facilitate the execution of automated processes such as CI-CD. + +## Add a simple chart + +Right-click in `Hierarchy` view or menu bar `GameObject` drop down and select `XCharts->LineChart`, can quickly create a default line chart out: ![linechart1](img/tutorial01_linechart1.png) -## 添加多个Seire +## Add multiple Seire -在`Inspector`视图,找到`LineChart`的面板,通过`Add Serie`按钮,可以添加第二条`Line`折线: +In the Inspector view, locate LineChart's panel, and with the `Add Serie` button, you can add a second Line line: ![op_addserie](img/tutorial01_addserie.png) ![linechart2](img/tutorial01_linechart2.png) -## 添加其他组件 +## Add other components -默认图表没有`Legend`,需要`Legend`组件可通过`Add Component`按钮添加: +The default chart does not have a `Legend`, and a `Legend` Component can be added via the `Add Component` button: ![op_addcomponent](img/tutorial01_addcomponent.png) -## 添加Serie组件 +## Add Serie components -Serie只自带了几个常见的组件,其他组件要根据需求额外添加,不同的Serie支持不同的额外组件。比如,需要给折线图区域填充颜色,可单独给`Serie`添加`AreaStyle`组件: +Serie comes with only a few common components, and others are added as needed. For example, if you need to fill a line chart area with color, you can add a separate `AreaStyle` component to Serie: ![op_addseriecomponent](img/tutorial01_addseriecomponent.png) ![linechart3](img/tutorial01_linechart3.png) -## 添加SerieData组件 +## Add the SerieData component -如果需要个性化定制每个数据项的配置,可以单独给每个`SerieData`添加`Component`。比如我们给折线图的第二个数据单独显示`Label`: +If you need to personalize the configuration of each data item, you can add a Component to each SerieData separately. For example, we give the second data of the line chart a separate display `Label`: ![op_addseriedatacomponent](img/tutorial01_addseriedatacomponent.png) ![linechart4](img/tutorial01_linechart4.png) -## 更多组件和配置参数 +## More components and configuration parameters -功能越丰富就越需要更多的组件和参数支持。XCharts有多达几十种的主组件和子组件,每个组件有几个至几十个不等的可配置参数,以支持各种灵活而复杂的功能。 +XCharts has been iteratively optimized and now has dozens of main and sub-components, each with a few to dozens of configurable parameters to support a variety of flexible and complex functions. -首次接触XCharts者可在 `Inspector` 视图下可以添加和调整各个组件,`Game` 视图会实时反馈调整的效果,以熟悉各种组件实现的效果。各个组件的详细参数说明可查阅[XCharts配置项手册](configuration.md)。 +Using XCharts for the first time, you can add various charts in the `Inspector` view, add or adjust the components in the chart, and the `Game` view gives real-time feedback on the effects of adjustments to familiarize yourself with the use of various components. Detailed parameter descriptions of each component can be found in the [XCharts Configuration](Configuration.md). -## 如何快速调整参数 +## How to adjust parameters quickly -`XCharts`是配置参数驱动。想要什么效果,你只需要去调整对应组件下的配置参数就可以,不需要去改`Hierarchy`视图下的节点,因为那些节点是由`XCharts`内部根据配置参数生成的,即使改了也会在刷新时被还原回来。 +XCharts is configuration and data driven. Want what effect, only need to adjust the configuration parameters under the corresponding component can be, do not need to change the nodes under the `Hierarchy` view, because those nodes are generated by the `XCharts` internal according to the configuration and data, even if changed will be restored in the refresh. -快速定位你想要改的效果对应的组件。这就需要对组件有一定的了解。比如我们想要让X轴的轴线末端显示箭头,如何定位?第一步,X轴定位到`XAxis0`;第二步,轴线定位到`AxisLine`;最后,再去看`AxisLine`组件下有没有这样的参数可以实现这个效果。 +How to quickly locate the component corresponding to the effect you want to change requires a certain understanding of the component. For example, if we want to show an arrow at the end of the X-axis, how do we position it? First, position the X-axis to `XAxis0`; Second, locate the axis to `AxisLine`; Finally, check to see if there are any parameters in the AxisLine component that can achieve this effect, and check [XCharts configuration](Configuration.md) for uncertain parameters. -`XCharts`提供从全局`Theme`、系列`Serie`、单个数据项`SerieData`全方位的参数配置。优先级从大到小为:`SerieData`->`Serie`->`Theme`。以`ItemStyle`的颜色为例: +`XCharts` provides a full range of parameter configuration from the global` Theme `, series` Serie `, and single data item `SerieData`. The priority in descending order is: `SerieData` -> `Serie` -> `Theme`. Take the color of `ItemStyle` for example: -1. 如果`SerieData`的`ItemStyle`配置有非`0000`颜色值,则优先用这个颜色值。 -2. 如果`Serie`的`ItemStyle`配置有非`0000`颜色值,则优先用这个颜色值。 -3. 否则颜色值取自主题`Theme`的`Color Palette`。 +1. If the `ItemStyle` of `SerieData` has a color value other than `0000`, this color value is preferred. +2. If the ItemStyle of `Serie` is configured with a color value other than `0000`, this color value takes precedence. +3. Otherwise, the Color value is taken from the Color Palette of the Theme. -通常配置的颜色值为0000时表示用主题默认颜色;配置参数的值为0或null时表示用主题默认配置。 +Usually, `0000` indicates the theme default color, and 0 or null indicates the theme default. -## 用代码添加折线图 +## Add line charts with code -给`gameObject`挂上`LineChart`脚本: +Attach the `LineChart` script to the gameObject: ```C# var chart = gameObject.GetComponent(); @@ -89,22 +107,21 @@ if (chart == null) chart.Init(); } ``` -用代码生成的Chart需要调用一次Init()。 -调整大小: +Resize: ```C# chart.SetSize(580, 300);//代码动态设置尺寸,或直接操作chart.rectTransform,或直接在Inspector上改 ``` -设置标题: +Set the title: ```C# var title = chart.EnsureChartComponent(); title.text = "Simple Line"; ``` -设置提示框和图例是否显示: +Set whether prompt boxes and legends are displayed: ```C# var tooltip = chart.EnsureChartComponent<Tooltip>(); @@ -114,7 +131,7 @@ var legend = chart.EnsureChartComponent<Legend>(); legend.show = false; ``` -设置坐标轴: +Set axes: ```C# var xAxis = chart.EnsureChartComponent<XAxis>(); @@ -126,14 +143,14 @@ var yAxis = chart.EnsureChartComponent<YAxis>(); yAxis.type = Axis.AxisType.Value; ``` -清空默认数据,添加`Line`类型的`Serie`用于接收数据: +Clear default data and add `Line` type `Serie` for receiving data: ```C# chart.RemoveData(); chart.AddSerie<Line>("line"); ``` -添加10个数据: +Add 10 data: ```C# for (int i = 0; i < 10; i++) @@ -143,56 +160,59 @@ for (int i = 0; i < 10; i++) } ``` -这样一个简单的折线图就出来了: +So a simple line chart comes out: ![tutorial01_linechart_simple](img/tutorial01_linechart_simple.png) -如果一个Chart里面有多个系列时,则Axis的data只需要加一次,不要多个循环加重复了。记住:Axis的数据个数要和Serie的数据个数一致。 +If there are multiple series in a Chart, the data of Axis only needs to be added once, rather than repeated in multiple cycles. Remember: the number of data in Axis should be the same as the number in Serie. -完整代码请查阅`Examples`:`Example13_LineSimple.cs` +See `Examples`: `Example13_LineSimple.cs` for the complete code -你还可以用代码控制更多的参数,`Examples`下还有更多的其他例子,凡是`Inspector`上看到的可配置的参数,都可以通过代码来设置。[XCharts配置项手册](configuration.md)里面的所有参数都是可以通过代码控制的。 +You can also use code to control more parameters, there are more Examples under `Examples`, all the configurable parameters seen in the `Inspector` can be set by code. All parameters in [XCharts configuration](Configuration.md) can be controlled by code. -另外,除非定制,建议调用`Chart`下提供的`public`接口,特别是数据相关操作部分。这些接口内部会做一些关联处理,比如刷新图表等。常见的接口有: +In addition, unless customized, it is recommended to call the `public` interface provided under `Chart`, especially in the data-related operations section. These interfaces do some associated processing inside, such as refreshing charts. Common interfaces are: -1. `chart.ClearData()`:清空图表数据(不移除Series) -2. `chart.RemoveData()`:清除图表数据(会移除所有Serie) -3. `chart.AddSerie()`:添加Serie -4. `chart.AddXAxisData()`:添加X轴数据 -5. `chart.AddData()`:添加Serie数据 -6. `chart.UpdateData()`:更新Serie数据 -7. `chart.UpdateXAxisData()`:更新X轴数据 -8. `chart.UpdateDataName()`:更新Serie数据的名字 +1. `Chart.ClearData()` : Clear chart data (without removing Series) +2. `Chart.RemoveData()` : Clear chart data (will remove all Serie) +3. `chart.AddSerie()` : AddSerie +4. `chart.AddXAxisData()` : Add X-axis data +5. `chart.AddData()` : Adds Serie data +6. `chart.UpdateData()` : Updates Serie data +7. `chart.UpdateXAxisData()` : Updates the X-axis data +8. `chart.UpdateDataName()` : Updates the Serie data name -XCharts内部有自动刷新机制,但也是在一定条件下。如果自己调用了内部组件的接口,碰到组件没有刷新,确实找不到原因的话,可以用以下两个接口强制刷新: +XCharts has an automatic refresh mechanism inside, but it only triggers under certain conditions. If you call the interface of the internal component, encounter the component did not refresh, and indeed can not find the reason, you can use the following two interfaces to force refresh: -1. `chart.RefreshAllComponent()`:刷新图表组件,会重新初始化所有组件,不建议频繁使用。 -2. `chart.RefreshChart()`:刷新图表绘制,只刷新绘制部分,不会刷新组件文本,位置等部分。 +1. `chart.RefreshAllComponent()` : refresh chart component, to initialize all of the components, often is not recommended. +2. `chart.RefreshChart()` : refreshes the chart drawing, only the drawing part is refreshed, and the component text, position, etc., is not refreshed. +3. Individual components can also refresh only themselves by `SetAllDirty()`. -## 使用TextMeshPro +## Use TextMeshPro -XCharts支持TextMeshPro,但默认是不开启的,需要自己手动切换。可通过以下方式开启和关闭: +XCharts supports TextMeshPro, but it is disabled by default and needs to be switched manually. It can be turned on and off in the following ways: ![textmeshpro1](img/tutorial01_textmeshpro.png) -开启后需要设置好TextMeshPro要用的全局字体,也可以在主题Theme里单独设置: +After opening, you need to set the global font used by TextMeshPro, or you can set it separately in the Theme: ![textmeshpro-font](img/tutorial01_textmeshpro_font.png) -建议在项目初就规划好是否使用TextMeshPro,并设置好字体。在已有很多图表的情况下切换TMP时,可能某些图表无法自动刷新,可以手动点击`Rebuild Chart Object`按钮来重建图表,即可正常初始化。 +It is recommended to plan whether to use TextMeshPro at the beginning of the project and set the font. When switching TMP with many existing charts, some charts may not refresh automatically. You can manually click the `Rebuild Chart Object` button to rebuild the chart, which can be initialized normally. -开启了TMP项目在更新XCharts时,可能会碰到丢失了TMP引用而无法编译通过的问题,可通过以下两种方式解决: +When updating XCharts for TMP projects, you may encounter problems with missing TMP references and failing to compile. These problems can be solved in one of two ways: -1. 找到`XCharts.Runtime.asmdef`和`XCharts.Editor.asmdef`,手动加上 `TextMeshPro`的引用 -2. 移除`PlayerSetting`中`Scripting Define Symbols`的`dUI_TextMeshPro`宏 +1. Find `XCharts.Runtime.asmdef` and `XCharts.Editor.asmdef` and manually add references to `TextMeshPro` +2. Remove the `dUI_TextMeshPro` macro for Scripting Define Symbols in PlayerSetting -## 用代码改图表参数 +Version `3.8.0` after adding daemon[XCharts - Daemon](https://github.com/XCharts-Team/XCharts-Daemon), will be XCharts-Daemon import project, When updating XCharts, the daemon automatically refreshes the asmdef based on the locally enabled TMP to ensure proper compilation. -`Inspector`上看到的所有参数都可以用代码来修改,关键是要定位好你要改的参数是在组件上、还是serie上、还是在具体的数据项上改。 +## Change chart parameters with code -### 改主组件上的参数 +All parameters seen on Inspector can be modified with code, the key is to identify whether the parameters you want to change are on the component, on the Serie, or on the specific data item SerieData. -需要先获取组件,再修改里面的参数: +### Change the parameters on the main component + +You need to obtain the component first, and then modify the parameters in it: ```C# var title = chart.EnsureChartComponent<Title>(); @@ -205,9 +225,11 @@ xAxis.boundaryGap = true; xAxis.type = Axis.AxisType.Category; ``` -### 改Serie的参数 +> Note: When the earlier version does not have the EnsureChartComponent() interface, GetOrAddChartComponent() is used. -新添加的Serie: +### Change Serie parameters + +For newly added Serie: ```C# var serie = chart.AddSerie<Pie>(); @@ -219,7 +241,7 @@ serie.animation.dataChangeEnable = true; serie.roundCap = true; ``` -已存在的Serie: +For existing Serie: ```C# var serie = chart.GetSerie<Pie>(); @@ -231,7 +253,7 @@ serie.animation.dataChangeEnable = true; serie.roundCap = true; ``` -给Serie添加额外组件: +Add additional components to Serie: ```C# serie.EnsureComponent<AreaStyle>(); @@ -240,7 +262,7 @@ var label = serie1.EnsureComponent<LabelStyle>(); label.offset = new Vector3(0,20,0); ``` -### 改数据项SerieData上的参数 +### Change the parameter on the data item SerieData ```C# var serieData = chart.AddData(0, 20); @@ -250,4 +272,4 @@ serieData.radius = 10; var itemStyle = serieData.EnsureComponent<ItemStyle>(); //给数据项添加ItemStyle组件 itemStyle.color = Color.blue; -``` +``` \ No newline at end of file diff --git a/Documentation~/zh/api.md b/Documentation~/zh/api.md index 78faadc1..c89e9ef7 100644 --- a/Documentation~/zh/api.md +++ b/Documentation~/zh/api.md @@ -7,6 +7,7 @@ slug: /api ## 所有类 +- [AnimationInfoContext](#animationinfocontext) - [AnimationStyleHelper](#animationstylehelper) - [AxisContext](#axiscontext) - [AxisHandler<T>](#axishandlert) @@ -30,9 +31,11 @@ slug: /api - [DataZoomHelper](#datazoomhelper) - [DateTimeUtil](#datetimeutil) - [DefaultAnimationAttribute](#defaultanimationattribute) +- [DefaultTooltipAttribute](#defaulttooltipattribute) - [DefineSymbolsUtil](#definesymbolsutil) - [FormatterHelper](#formatterhelper) - [GridCoordContext](#gridcoordcontext) +- [GridLayoutContext](#gridlayoutcontext) - [HeatmapChart](#heatmapchart) - [IgnoreDoc](#ignoredoc) - [INeedSerieContainer](#ineedseriecontainer) @@ -56,6 +59,7 @@ slug: /api - [MainComponentHandler](#maincomponenthandler) - [MainComponentHandler<T>](#maincomponenthandlert) - [MathUtil](#mathutil) +- [MonoBehaviour](#monobehaviour) - [Painter](#painter) - [ParallelChart](#parallelchart) - [ParallelCoordContext](#parallelcoordcontext) @@ -109,8 +113,13 @@ slug: /api - [XChartsMgr](#xchartsmgr) - [XCResourceImporterWindow](#xcresourceimporterwindow) - [XCThemeMgr](#xcthememgr) +- [XLog](#xlog) +## AnimationInfoContext + +> XCharts.Runtime.AnimationInfoContext + ## AnimationStyleHelper > XCharts.Runtime.AnimationStyleHelper @@ -119,7 +128,7 @@ slug: /api |--|--|--| |CheckDataAnimation()||public static float CheckDataAnimation(BaseChart chart, Serie serie, int dataIndex, float destProgress, float startPorgress = 0)| |GetAnimationPosition()||public static bool GetAnimationPosition(AnimationStyle animation, bool isY, Vector3 lp, Vector3 cp, float progress, ref Vector3 ip)| -|UpdateAnimationType()||public static void UpdateAnimationType(AnimationStyle animation, AnimationType defaultType)| +|UpdateAnimationType()||public static void UpdateAnimationType(AnimationStyle animation, AnimationType defaultType, bool enableSerieDataAnimation)| |UpdateSerieAnimation()||public static void UpdateSerieAnimation(Serie serie)| ## AxisContext @@ -206,12 +215,12 @@ slug: /api |AddXAxisIcon()||public void AddXAxisIcon(Sprite icon, int xAxisIndex = 0)<br/>添加一个图标到指定的x轴。 | |AddYAxisData()||public void AddYAxisData(string category, int yAxisIndex = 0)<br/>添加一个类目数据到指定的y轴。 | |AddYAxisIcon()||public void AddYAxisIcon(Sprite icon, int yAxisIndex = 0)<br/>添加一个图标到指定的y轴。 | -|AnimationEnable()||public void AnimationEnable(bool flag)<br/>启用或关闭起始动画。 | -|AnimationFadeIn()||public void AnimationFadeIn(bool reset = true)<br/>开始渐入动画。 | -|AnimationFadeOut()||public void AnimationFadeOut()<br/>开始渐出动画。 | -|AnimationPause()||public void AnimationPause()<br/>暂停动画。 | -|AnimationReset()||public void AnimationReset()<br/>重置动画。 | -|AnimationResume()||public void AnimationResume()<br/>继续动画。 | +|AnimationEnable()||public void AnimationEnable(bool flag)<br/>是否启用Serie动画。 | +|AnimationFadeIn()||public void AnimationFadeIn(bool reset = true)<br/>开始所有Serie的渐入动画。 | +|AnimationFadeOut()||public void AnimationFadeOut()<br/>开始所有Serie的渐出动画。 | +|AnimationPause()||public void AnimationPause()<br/>暂停所有Serie的动画。 | +|AnimationReset()||public void AnimationReset()<br/>重置所有Serie的动画。 | +|AnimationResume()||public void AnimationResume()<br/>继续所有Serie的动画。 | |CanAddChartComponent()||public bool CanAddChartComponent(Type type)| |CanAddSerie()||public bool CanAddSerie(Type type)| |CanAddSerie<T>()||public bool CanAddSerie<T>() where T : Serie| @@ -493,7 +502,7 @@ slug: /api |GetTextHeight()||public float GetTextHeight()| |GetTextWidth()||public float GetTextWidth()| |GetWidth()||public float GetWidth()| -|IsActive()||public override bool IsActive()| +|IsActiveByScale()||public bool IsActiveByScale()| |SetActive()||public void SetActive(bool flag)| |SetIcon()||public void SetIcon(Image image)| |SetIconActive()||public void SetIconActive(bool flag)| @@ -509,7 +518,7 @@ slug: /api |SetTextColor()||public void SetTextColor(Color color)| |SetTextPadding()||public void SetTextPadding(TextPadding padding)| |SetTextRotate()||public void SetTextRotate(float rotate)| -|UpdateIcon()||public void UpdateIcon(IconStyle iconStyle, Sprite sprite = null)| +|UpdateIcon()||public void UpdateIcon(IconStyle iconStyle, Sprite sprite = null, Color color = default(Color))| ## ChartObject @@ -599,6 +608,15 @@ slug: /api |public method|since|description| |--|--|--| |DefaultAnimationAttribute()||public DefaultAnimationAttribute(AnimationType handler)| +|DefaultAnimationAttribute()||public DefaultAnimationAttribute(AnimationType handler, bool enableSerieDataAddedAnimation)| + +## DefaultTooltipAttribute + +> XCharts.Runtime.DefaultTooltipAttribute : [Attribute](https://docs.unity3d.com/ScriptReference/30_search.html?q=attribute) + +|public method|since|description| +|--|--|--| +|DefaultTooltipAttribute()||public DefaultTooltipAttribute(Tooltip.Type type, Tooltip.Trigger trigger)| ## DefineSymbolsUtil @@ -625,6 +643,10 @@ slug: /api > XCharts.Runtime.GridCoordContext : [MainComponentContext](#maincomponentcontext) +## GridLayoutContext + +> XCharts.Runtime.GridLayoutContext : [MainComponentContext](#maincomponentcontext) + ## HeatmapChart > XCharts.Runtime.HeatmapChart : [BaseChart](#basechart) @@ -659,14 +681,19 @@ slug: /api |Reset()||public void Reset()| |SetColor()||public void SetColor(ref bool needInteract, Color32 color)| |SetColor()||public void SetColor(ref bool needInteract, Color32 color, Color32 toColor)| -|SetValue()||public void SetValue(ref bool needInteract, float size)| -|SetValue()||public void SetValue(ref bool needInteract, float size, bool highlight, float rate = 1.3f)| +|SetPosition()||public void SetPosition(ref bool needInteract, Vector3 pos)| +|SetValue()||public void SetValue(ref bool needInteract, float value, bool highlight, float rate = 1.3f)| +|SetValue()||public void SetValue(ref bool needInteract, float value, bool previousValueZero = false)| |SetValueAndColor()||public void SetValueAndColor(ref bool needInteract, float value, Color32 color)| |SetValueAndColor()||public void SetValueAndColor(ref bool needInteract, float value, Color32 color, Color32 toColor)| +|ToString()||public override string ToString()| |TryGetColor()||public bool TryGetColor(ref Color32 color, ref bool interacting, float animationDuration = 250)| |TryGetColor()||public bool TryGetColor(ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)| +|TryGetPosition()||public bool TryGetPosition(ref Vector3 pos, ref bool interacting, float animationDuration = 250)| |TryGetValue()||public bool TryGetValue(ref float value, ref bool interacting, float animationDuration = 250)| |TryGetValueAndColor()||public bool TryGetValueAndColor(ref float value, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)| +|TryGetValueAndColor()||public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref bool interacting, float animationDuration = 250)| +|TryGetValueAndColor()||public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250)| ## IPropertyChanged @@ -693,7 +720,7 @@ slug: /api ## IUpdateRuntimeData -> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis),[DataZoom](#datazoom),[CalendarCoord](#calendarcoord),[GridCoord](#gridcoord),[ParallelCoord](#parallelcoord) +> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis),[DataZoom](#datazoom),[CalendarCoord](#calendarcoord),[GridCoord](#gridcoord),[GridLayout](#gridlayout),[ParallelCoord](#parallelcoord) ## LayerHelper @@ -714,7 +741,7 @@ slug: /api |public method|since|description| |--|--|--| -|CheckDataHighlighted()||public static bool CheckDataHighlighted(Serie serie, string legendName, bool heighlight)| +|CheckDataHighlighted()||public static int CheckDataHighlighted(Serie serie, string legendName, bool heighlight)| |CheckDataShow()||public static bool CheckDataShow(Serie serie, string legendName, bool show)| |GetContentColor()||public static Color GetContentColor(BaseChart chart, int legendIndex, string legendName, Legend legend, ThemeStyle theme, bool active)| |GetIconColor()||public static Color GetIconColor(BaseChart chart, Legend legend, int readIndex, string legendName, bool active)| @@ -776,7 +803,7 @@ slug: /api ## MainComponentContext -> XCharts.Runtime.MainComponentContext / Subclasses: [AxisContext](#axiscontext),[DataZoomContext](#datazoomcontext),[LegendContext](#legendcontext),[RadarCoordContext](#radarcoordcontext),[VisualMapContext](#visualmapcontext),[GridCoordContext](#gridcoordcontext),[ParallelCoordContext](#parallelcoordcontext),[PolarCoordContext](#polarcoordcontext) +> XCharts.Runtime.MainComponentContext / Subclasses: [AxisContext](#axiscontext),[DataZoomContext](#datazoomcontext),[LegendContext](#legendcontext),[RadarCoordContext](#radarcoordcontext),[VisualMapContext](#visualmapcontext),[GridCoordContext](#gridcoordcontext),[GridLayoutContext](#gridlayoutcontext),[ParallelCoordContext](#parallelcoordcontext),[PolarCoordContext](#polarcoordcontext) ## MainComponentHandler @@ -820,6 +847,10 @@ slug: /api |IsInteger()||public static bool IsInteger(double value)| |Lerp()||public static double Lerp(double a, double b, double t)| +## MonoBehaviour + +> .MonoBehaviour / Subclasses: [XLog](#xlog) + ## ObjectPool<T> where T > XCharts.Runtime.ObjectPool<T> where T : [new()](#new()) @@ -1029,11 +1060,14 @@ serie事件的数据。 |public method|since|description| |--|--|--| +|AfterUpdate()||public virtual void AfterUpdate() { }| +|BeforeUpdate()||public virtual void BeforeUpdate() { }| |CheckComponent()||public virtual void CheckComponent(StringBuilder sb) { }| |DrawBase()||public virtual void DrawBase(VertexHelper vh) { }| |DrawSerie()||public virtual void DrawSerie(VertexHelper vh) { }| |DrawTop()||public virtual void DrawTop(VertexHelper vh) { }| |DrawUpper()||public virtual void DrawUpper(VertexHelper vh) { }| +|ForceUpdateSerieContext()||public virtual void ForceUpdateSerieContext() { }| |InitComponent()||public virtual void InitComponent() { }| |OnBeginDrag()||public virtual void OnBeginDrag(PointerEventData eventData) { }| |OnDrag()||public virtual void OnDrag(PointerEventData eventData) { }| @@ -1063,7 +1097,10 @@ serie事件的数据。 |public method|since|description| |--|--|--| +|AfterUpdate()||public override void AfterUpdate()| +|BeforeUpdate()||public override void BeforeUpdate()| |DrawLabelLineSymbol()||public void DrawLabelLineSymbol(VertexHelper vh, LabelLine labelLine, Vector3 startPos, Vector3 endPos, Color32 defaultColor)| +|ForceUpdateSerieContext()||public override void ForceUpdateSerieContext()| |GetPointerItemDataDimension()||public override int GetPointerItemDataDimension()| |GetPointerItemDataIndex()||public override int GetPointerItemDataIndex()| |GetSerieDataAutoColor()||public virtual Color GetSerieDataAutoColor(SerieData serieData)| @@ -1125,11 +1162,11 @@ serie事件的数据。 |GetSerieState()||public static SerieState GetSerieState(SerieData serieData)| |GetSerieSymbol()||public static SerieSymbol GetSerieSymbol(Serie serie, SerieData serieData, SerieState state = SerieState.Auto)| |GetStateStyle()||public static StateStyle GetStateStyle(Serie serie, SerieData serieData, SerieState state)| -|GetSysmbolSize()||public static float GetSysmbolSize(Serie serie, SerieData serieData, ThemeStyle theme, float defaultSize, SerieState state = SerieState.Auto)| +|GetSysmbolSize()||public static float GetSysmbolSize(Serie serie, SerieData serieData, float defaultSize, SerieState state = SerieState.Auto, bool checkAnimation = false)| |GetTitleStyle()||public static TitleStyle GetTitleStyle(Serie serie, SerieData serieData)| |IsAllZeroValue()||public static bool IsAllZeroValue(Serie serie, int dimension = 1)<br/>系列指定维数的数据是否全部为0。 | |IsDownPoint()||public static bool IsDownPoint(Serie serie, int index)| -|UpdateCenter()||public static void UpdateCenter(Serie serie, Vector3 chartPosition, float chartWidth, float chartHeight)<br/>更新运行时中心点和半径 | +|UpdateCenter()||public static void UpdateCenter(Serie serie, BaseChart chart)<br/>更新运行时中心点和半径 | |UpdateFilterData()||public static void UpdateFilterData(Serie serie, DataZoom dataZoom)<br/>根据dataZoom更新数据列表缓存 | |UpdateMinMaxData()||public static void UpdateMinMaxData(Serie serie, int dimension, double ceilRate = 0, DataZoom dataZoom = null)<br/>获得指定维数的最大最小值 | |UpdateRect()||public static void UpdateRect(Serie serie, Vector3 chartPosition, float chartWidth, float chartHeight)| @@ -1141,12 +1178,9 @@ serie事件的数据。 |public method|since|description| |--|--|--| -|AvoidLabelOverlap()||public static void AvoidLabelOverlap(Serie serie, ComponentTheme theme)| |CanShowLabel()||public static bool CanShowLabel(Serie serie, SerieData serieData, LabelStyle label, int dimesion)| |GetLabelColor()||public static Color GetLabelColor(Serie serie, ThemeStyle theme, int index)| -|GetRealLabelPosition()||public static Vector3 GetRealLabelPosition(Serie serie, SerieData serieData, LabelStyle label, LabelLine labelLine)| |SetGaugeLabelText()||public static void SetGaugeLabelText(Serie serie)| -|UpdatePieLabelPosition()||public static void UpdatePieLabelPosition(Serie serie, SerieData serieData)| ## SerieLabelPool @@ -1280,10 +1314,17 @@ UGUI 图形库 |--|--|--| |DrawDiamond()||public static void DrawDiamond(VertexHelper vh, Vector3 center, float size, Color32 color)<br/>Draw a diamond. 画菱形(钻石形状) | |DrawDiamond()||public static void DrawDiamond(VertexHelper vh, Vector3 center, float size, Color32 color, Color32 toColor)<br/>Draw a diamond. 画菱形(钻石形状) | +|DrawDiamond()||public static void DrawDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, Color32 color, Color32 toColor)| |DrawEllipse()||public static void DrawEllipse(VertexHelper vh, Vector3 center, float w, float h, Color32 color, float smoothness = 1)| +|DrawEmptyDiamond()||public static void DrawEmptyDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, float tickness, Color32 color)| +|DrawEmptyDiamond()||public static void DrawEmptyDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, float tickness, Color32 color, Color32 emptyColor)| +|DrawEmptyTriangle()||public static void DrawEmptyTriangle(VertexHelper vh, Vector3 pos, float size, float tickness, Color32 color)| +|DrawEmptyTriangle()||public static void DrawEmptyTriangle(VertexHelper vh, Vector3 pos, float size, float tickness, Color32 color, Color32 backgroundColor)| |DrawLine()||public static void DrawLine(VertexHelper vh, List<Vector3> points, float width, Color32 color, bool smooth, bool closepath = false)| |DrawLine()||public static void DrawLine(VertexHelper vh, Vector3 startPoint, Vector3 endPoint, float width, Color32 color)<br/>Draw a line. 画直线 | |DrawLine()||public static void DrawLine(VertexHelper vh, Vector3 startPoint, Vector3 endPoint, float width, Color32 color, Color32 toColor)<br/>Draw a line. 画直线 | +|DrawMinus()||public static void DrawMinus(VertexHelper vh, Vector3 center, float radius, float tickness, Color32 color)<br/>绘制减号 | +|DrawPlus()||public static void DrawPlus(VertexHelper vh, Vector3 center, float radius, float tickness, Color32 color)<br/>绘制加号 | |DrawPolygon()||public static void DrawPolygon(VertexHelper vh, List<Vector3> points, Color32 color)<br/>填充任意多边形(目前只支持凸多边形) | |DrawRectangle()||public static void DrawRectangle(VertexHelper vh, Rect rect, Color32 color)| |DrawRectangle()||public static void DrawRectangle(VertexHelper vh, Rect rect, Color32 color, Color32 toColor)| @@ -1410,3 +1451,26 @@ UI帮助类。 |ReloadThemeList()||public static void ReloadThemeList()<br/>重新加载主题列表 | |SwitchTheme()||public static void SwitchTheme(BaseChart chart, string themeName)| +## XLog + +> XCharts.Runtime.XLog : [MonoBehaviour](#monobehaviour) +日志系统。用于输出带日期和日志类型的日志,支持输出到文件,支持自定义输出的日志类型。 + +|public method|since|description| +|--|--|--| +|CanLog()||public static bool CanLog(int level)| +|ClearAllLog()||public static void ClearAllLog()| +|Debug()||public static void Debug(string log)| +|EnableLog()||public static void EnableLog(int logType)| +|Error()||public static void Error(string log)| +|FlushLog()||public static void FlushLog()| +|GetNowTime()||public static string GetNowTime(string formatter = null)| +|GetTimestamp()||public static ulong GetTimestamp()| +|Info()||public static void Info(string log)| +|Log()||public static void Log(string log)| +|LogError()||public static void LogError(string log)| +|LogWarning()||public static void LogWarning(string log)| +|Proto()||public static void Proto(string log)| +|Vital()||public static void Vital(string log)| +|Warning()||public static void Warning(string log)| + diff --git a/Documentation~/zh/changelog.md b/Documentation~/zh/changelog.md index 06875db3..9659d0d4 100644 --- a/Documentation~/zh/changelog.md +++ b/Documentation~/zh/changelog.md @@ -6,7 +6,9 @@ slug: /changelog # 更新日志 [master](#master) +[v3.8.0](#v380) [v3.7.0](#v370) +[v3.6.0](#v360) [v3.5.0](#v350) [v3.4.0](#v340) [v3.3.0](#v330) @@ -66,6 +68,62 @@ slug: /changelog ## master +## v3.8.0 + +版本要点: + +* 重构`Animation`动画系统,增加`新增动画`和`交互动画`的支持 +* 完善`PieChart`的动画交互表现 +* 增加`Symbol`的`EmptyTriangle`、`EmptyDiamond`、`Plus`、`Minus`四种新标记 +* 完善`Chart`的鼠标交互回调 +* 增加`LabelLine`可固定横坐标的功能 +* 增加`GridLayout`网格布局组件 +* 增加`Tooltip`的`Auto`类型 +* 优化和修复若干其他问题 + +日志详情: + +* (2023.09.03) 发布`v3.8.0`版本 +* (2023.09.01) 增加`Tooltip`的`Auto`自动设置显示类型和触发类型 +* (2023.08.29) 增加`Ring`的`gridIndex`支持设置指定网格 +* (2023.08.29) 增加`Radar`的`gridIndex`支持设置指定网格 +* (2023.08.29) 增加`Pie`的`gridIndex`支持设置指定网格 +* (2023.08.29) 增加`GridLayout`网格布局组件用于管理多个`GridCoord`的布局 +* (2023.08.25) 修复`MarkLine`多个时只显示一个`Label`的问题 +* (2023.08.25) 修复`MarkLine`在开启`Clip`后还绘制在坐标系外的问题 +* (2023.08.24) 优化`YAxis`在数据全为0时默认设置0-1的范围 +* (2023.08.23) 修复`YAxis`的`Label`可能会重复的问题 +* (2023.08.22) 修复`Bar`显示隐藏时绘制表现异常的问题 +* (2023.08.22) 优化`Zebra`斑马柱图的绘制表现 (#276) +* (2023.08.16) 增加`Daemon`守护程序,解决本地开启TMP后更新版本报错问题 +* (2023.08.15) 修复`Data`数据在-1到1之间时坐标轴显示错误的问题 (#273) (by __Ambitroc__) +* (2023.08.14) 修复`XCharts`本地开启`TextMeshPro`和 `NewInputSystem`后更新版本会报错的问题 (#272) +* (2023.08.12) 修复`Chart`在运行时被删除时会异常报错的问题 (#269) +* (2023.08.11) 修复`DataZoom`开启时可能会导致无法添加数据的问题 +* (2023.08.11) 修复`SerieData`单独设置`ItemStyle`的`itemFormatter`不生效的问题 +* (2023.08.10) 优化`BarChart`在`Tooltip`的`Trigger`为`Item`时的表现 +* (2023.08.09) 增加`Axis`可通过设置`IconStyle`的`color`为`clear`来实现动态图标颜色的支持 +* (2023.08.08) 增加`Pie`对`LabelLine`的`lineEndX`的支持 +* (2023.08.05) 整理`Examples`的代码,删除不必要的用例 +* (2023.08.04) 增加`LabelLine`的`lineEndX`可设置引导线固定X位置的支持 +* (2023.08.04) 增加`Ring`的`avoidLabelOverlap`避免文本堆叠的支持 (#247) +* (2023.08.03) 完善`Chart`的`onSerieEnter`,`onSerieExit`和`onSerieClick`回调 +* (2023.08.02) 修复`BarChart`的`onSerieEnter`和`onSerieExit`回调无效的问题 +* (2023.08.02) 增加`Symbol`的`Plus`加号和`Minus`减号的支持 +* (2023.07.31) 增加`Symbol`的`EmptyTriangle`和`EmptyDiamond`的支持,优化`Symbol`表现效果 +* (2023.07.31) 优化`Line`的默认配置效果 +* (2023.07.27) 增加`Serie`的`minRadius`可设置最小半径 +* (2023.07.26) 增加`MLValue`多样式数值 +* (2023.07.25) 增加`XLog`日志系统 +* (2023.07.18) 完善`Pie`饼图的交互动画效果 +* (2023.07.14) 增加`Animation`的`Interaction`交互动画配置支持 +* (2023.07.11) 增加`Animation`的`Addition`新增动画配置支持 +* (2023.07.11) 重构`Animation`动画系统,完善动画体验 +* (2023.06.30) 增加`PolarCood`的`indicatorLabelOffset`设置指示文本偏移的支持 +* (2023.06.30) 修复`Axis`的`IndicatorLabel`的背景颜色可能不正常的问题 +* (2023.06.30) 增加`Axis`的`IndicatorLabel`可自定义`color`的支持 +* (2023.06.12) 修复`AxisLabel`的`formatterFunction`在数值轴时`value`不对的问题 + ## v3.7.0 版本要点: diff --git a/Documentation~/zh/configuration.md b/Documentation~/zh/configuration.md index 13874920..69c6ccf9 100644 --- a/Documentation~/zh/configuration.md +++ b/Documentation~/zh/configuration.md @@ -56,6 +56,7 @@ import APITable from '@site/src/components/APITable'; - [CoordSystem](#coordsystem) - [DataZoom](#datazoom) - [GridCoord](#gridcoord) +- [GridLayout](#gridlayout) - [Legend](#legend) - [MarkArea](#markarea) - [MarkLine](#markline) @@ -112,6 +113,7 @@ import APITable from '@site/src/components/APITable'; - [MarkAreaData](#markareadata) - [MarkLineData](#marklinedata) - [MarqueeStyle](#marqueestyle) +- [MLValue](#mlvalue) - [Padding](#padding) - [PolarAxisTheme](#polaraxistheme) - [RadarAxisTheme](#radaraxistheme) @@ -166,6 +168,13 @@ import APITable from '@site/src/components/APITable'; ## Other 其他 +- [AnimationAddition](#animationaddition) +- [AnimationChange](#animationchange) +- [AnimationFadeIn](#animationfadein) +- [AnimationFadeOut](#animationfadeout) +- [AnimationHiding](#animationhiding) +- [AnimationInfo](#animationinfo) +- [AnimationInteraction](#animationinteraction) - [BaseSerie](#baseserie) - [ChartText](#charttext) - [ChildComponent](#childcomponent) @@ -209,11 +218,98 @@ import APITable from '@site/src/components/APITable'; > XCharts.Runtime.AngleAxisTheme : [BaseAxisTheme](#baseaxistheme) +## AnimationAddition + +> XCharts.Runtime.AnimationAddition : [AnimationInfo](#animationinfo) + +> 从 `v3.8.0` 开始支持 + +数据新增动画。 + +## AnimationChange + +> XCharts.Runtime.AnimationChange : [AnimationInfo](#animationinfo) + +> 从 `v3.8.0` 开始支持 + +数据变更动画。 + +## AnimationFadeIn + +> XCharts.Runtime.AnimationFadeIn : [AnimationInfo](#animationinfo) + +> 从 `v3.8.0` 开始支持 + +淡入动画。 + +## AnimationFadeOut + +> XCharts.Runtime.AnimationFadeOut : [AnimationInfo](#animationinfo) + +> 从 `v3.8.0` 开始支持 + +淡出动画。 + +## AnimationHiding + +> XCharts.Runtime.AnimationHiding : [AnimationInfo](#animationinfo) + +> 从 `v3.8.0` 开始支持 + +数据隐藏动画。 + +## AnimationInfo + +> XCharts.Runtime.AnimationInfo / Subclasses: [AnimationFadeIn](#animationfadein), [AnimationFadeOut](#animationfadeout), [AnimationChange](#animationchange), [AnimationAddition](#animationaddition), [AnimationHiding](#animationhiding), [AnimationInteraction](#animationinteraction) + +> 从 `v3.8.0` 开始支持 + +动画配置参数。 + +```mdx-code-block +<APITable name="AnimationInfo"> +``` + + +|field|default|since|comment| +|--|--|--|--| +|enable|true|v3.8.0|是否开启动画效果。 +|reverse|false|v3.8.0|是否开启反向动画效果。 +|delay|0|v3.8.0|动画开始前的延迟时间。 +|duration|1000|v3.8.0|动画的时长。 + +```mdx-code-block +</APITable> +``` + +## AnimationInteraction + +> XCharts.Runtime.AnimationInteraction : [AnimationInfo](#animationinfo) + +> 从 `v3.8.0` 开始支持 + +交互动画。 + +```mdx-code-block +<APITable name="AnimationInteraction"> +``` + + +|field|default|since|comment| +|--|--|--|--| +|width||v3.8.0|宽度的多样式数值。 [MLValue](#mlvalue)| +|radius||v3.8.0|半径的多样式数值。 [MLValue](#mlvalue)| +|offset||v3.8.0|交互的多样式数值。如饼图的扇形选中时的偏移。 [MLValue](#mlvalue)| + +```mdx-code-block +</APITable> +``` + ## AnimationStyle > XCharts.Runtime.AnimationStyle : [ChildComponent](#childcomponent) -动画表现。 +动画组件,用于控制图表的动画播放。支持配置五种动画表现:FadeIn(渐入动画),FadeOut(渐出动画),Change(变更动画),Addition(新增动画),Interaction(交互动画)。 按作用的对象可以分为两类:SerieAnimation(系列动画)和DataAnimation(数据动画)。 ```mdx-code-block <APITable name="AnimationStyle"> @@ -224,16 +320,15 @@ import APITable from '@site/src/components/APITable'; |--|--|--|--| |enable|true||是否开启动画效果。 |type|||动画类型。<br/>`AnimationType`:<br/>- `Default`: 默认。内部会根据实际情况选择一种动画播放方式。<br/>- `LeftToRight`: 从左往右播放动画。<br/>- `BottomToTop`: 从下往上播放动画。<br/>- `InsideOut`: 由内到外播放动画。<br/>- `AlongPath`: 沿着路径播放动画。当折线图从左到右无序或有折返时,可以使用该模式。<br/>- `Clockwise`: 顺时针播放动画。<br/>| -|easting|||动画的缓动效果。<br/>`AnimationEasing`:<br/>- `Linear`: <br/>| +|easting|||<br/>`AnimationEasing`:<br/>- `Linear`: <br/>| |threshold|2000||是否开启动画的阈值,当单个系列显示的图形数量大于这个阈值时会关闭动画。 -|fadeInDuration|1000||设定的渐入动画时长(毫秒)。如果要设置单个数据项的渐入时长,可以用代码定制:customFadeInDuration。 -|fadeInDelay|0||渐入动画延时(毫秒)。如果要设置单个数据项的延时,可以用代码定制:customFadeInDelay。 -|fadeOutDuration|1000f||设定的渐出动画时长(毫秒)。如果要设置单个数据项的渐出时长,可以用代码定制:customFadeOutDuration。 -|fadeOutDelay|0||渐出动画延时(毫秒)。如果要设置单个数据项的延时,可以用代码定制:customFadeOutDelay。 -|dataChangeEnable|true||是否开启数据变更动画。 -|dataChangeDuration|500||数据变更的动画时长(毫秒)。 -|actualDuration|||实际的动画时长(毫秒)。 |unscaledTime||v3.4.0|动画是否受TimeScaled的影响。默认为 false 受TimeScaled的影响。 +|fadeIn||v3.8.0|渐入动画配置。 [AnimationFadeIn](#animationfadein)| +|fadeOut||v3.8.0|渐出动画配置。 [AnimationFadeOut](#animationfadeout)| +|change||v3.8.0|数据变更动画配置。 [AnimationChange](#animationchange)| +|addition||v3.8.0|数据新增动画配置。 [AnimationAddition](#animationaddition)| +|hiding||v3.8.0|数据隐藏动画配置。 [AnimationHiding](#animationhiding)| +|interaction||v3.8.0|交互动画配置。 [AnimationInteraction](#animationinteraction)| ```mdx-code-block </APITable> @@ -624,7 +719,7 @@ import APITable from '@site/src/components/APITable'; ## ChildComponent -> XCharts.Runtime.ChildComponent / Subclasses: [AnimationStyle](#animationstyle), [AxisName](#axisname), [AxisSplitArea](#axissplitarea), [AreaStyle](#areastyle), [ArrowStyle](#arrowstyle), [BaseLine](#baseline), [IconStyle](#iconstyle), [ImageStyle](#imagestyle), [ItemStyle](#itemstyle), [Level](#level), [LevelStyle](#levelstyle), [LineArrow](#linearrow), [LineStyle](#linestyle), [Location](#location), [MarqueeStyle](#marqueestyle), [Padding](#padding), [StageColor](#stagecolor), [SymbolStyle](#symbolstyle), [TextLimit](#textlimit), [TextStyle](#textstyle), [CommentItem](#commentitem), [CommentMarkStyle](#commentmarkstyle), [LabelLine](#labelline), [LabelStyle](#labelstyle), [MarkAreaData](#markareadata), [MarkLineData](#marklinedata), [StateStyle](#statestyle), [VisualMapRange](#visualmaprange), [UIComponentTheme](#uicomponenttheme), [SerieData](#seriedata), [ComponentTheme](#componenttheme), [SerieTheme](#serietheme), [ThemeStyle](#themestyle) +> XCharts.Runtime.ChildComponent / Subclasses: [AnimationStyle](#animationstyle), [AxisName](#axisname), [AxisSplitArea](#axissplitarea), [AreaStyle](#areastyle), [ArrowStyle](#arrowstyle), [BaseLine](#baseline), [IconStyle](#iconstyle), [ImageStyle](#imagestyle), [ItemStyle](#itemstyle), [Level](#level), [LevelStyle](#levelstyle), [LineArrow](#linearrow), [LineStyle](#linestyle), [Location](#location), [MLValue](#mlvalue), [MarqueeStyle](#marqueestyle), [Padding](#padding), [StageColor](#stagecolor), [SymbolStyle](#symbolstyle), [TextLimit](#textlimit), [TextStyle](#textstyle), [CommentItem](#commentitem), [CommentMarkStyle](#commentmarkstyle), [LabelLine](#labelline), [LabelStyle](#labelstyle), [MarkAreaData](#markareadata), [MarkLineData](#marklinedata), [StateStyle](#statestyle), [VisualMapRange](#visualmaprange), [UIComponentTheme](#uicomponenttheme), [SerieData](#seriedata), [ComponentTheme](#componenttheme), [SerieTheme](#serietheme), [ThemeStyle](#themestyle) ## Comment @@ -858,6 +953,7 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart |field|default|since|comment| |--|--|--|--| |show|true||是否显示直角坐标系网格。 +|layoutIndex|-1|v3.8.0|网格所属的网格布局组件的索引。默认为-1,表示不属于任何网格布局组件。当设置了该值时,left、right、top、bottom属性将失效。 |left|0.1f||grid 组件离容器左侧的距离。 |right|0.08f||grid 组件离容器右侧的距离。 |top|0.22f||grid 组件离容器上侧的距离。 @@ -871,6 +967,35 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart </APITable> ``` +## GridLayout + +> XCharts.Runtime.GridLayout : [MainComponent](#maincomponent), [IUpdateRuntimeData](#iupdateruntimedata) + +> 从 `v3.8.0` 开始支持 + +网格布局组件。用于管理多个`GridCoord`的布局,可以通过`row`和`column`来控制网格的行列数。 + +```mdx-code-block +<APITable name="GridLayout"> +``` + + +|field|default|since|comment| +|--|--|--|--| +|show|true||是否显示直角坐标系网格。 +|left|0.1f||grid 组件离容器左侧的距离。 +|right|0.08f||grid 组件离容器右侧的距离。 +|top|0.22f||grid 组件离容器上侧的距离。 +|bottom|0.12f||grid 组件离容器下侧的距离。 +|row|2||网格布局的行数。 +|column|2||网格布局的列数。 +|spacing|Vector2.zero||网格布局的间距。 +|inverse|false||是否反转网格布局。 + +```mdx-code-block +</APITable> +``` + ## Heatmap > XCharts.Runtime.Heatmap : [Serie](#serie), [INeedSerieContainer](#ineedseriecontainer) @@ -972,6 +1097,7 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart |connectCenter|false||数值是否连线到中心点。 |lineGradient|true||数值线段是否需要渐变。 |startAngle||v3.4.0|起始角度。和时钟一样,12点钟位置是0度,顺时针到360度。 +|gridIndex|-1|v3.8.0|所使用的 layout 组件的 index。 默认为-1不指定index, 当为大于或等于0时, 为第一个layout组件的第index个格子。 |indicatorList|||指示器列表。 ```mdx-code-block @@ -1048,7 +1174,7 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart ## IUpdateRuntimeData -> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis), [DataZoom](#datazoom), [CalendarCoord](#calendarcoord), [GridCoord](#gridcoord), [ParallelCoord](#parallelcoord) +> XCharts.Runtime.IUpdateRuntimeData / Subclasses: [SingleAxis](#singleaxis), [DataZoom](#datazoom), [CalendarCoord](#calendarcoord), [GridCoord](#gridcoord), [GridLayout](#gridlayout), [ParallelCoord](#parallelcoord) ## LabelLine @@ -1066,11 +1192,12 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart |show|true||是否显示视觉引导线。 |lineType|||视觉引导线类型。<br/>`LabelLine.LineType`:<br/>- `BrokenLine`: 折线<br/>- `Curves`: 曲线<br/>- `HorizontalLine`: 水平线<br/>| |lineColor|Color32(0,0,0,0)||视觉引导线颜色。默认和serie一致取自调色板。 -|lineAngle|0||视觉引导线的固定角度。对折线和曲线有效。 +|lineAngle|60||视觉引导线的固定角度。对折线和曲线有效。在Pie中无效。 |lineWidth|1.0f||视觉引导线的宽度。 |lineGap|1.0f||视觉引导线和容器的间距。 |lineLength1|25f||视觉引导线第一段的长度。 |lineLength2|15f||视觉引导线第二段的长度。 +|lineEndX|0f|v3.8.0|视觉引导线结束点的固定x位置。当不为0时,会代替lineLength2设定引导线的x位置。 |startSymbol|||起始点的图形标记。 [SymbolStyle](#symbolstyle)| |endSymbol|||结束点的图形标记。 [SymbolStyle](#symbolstyle)| @@ -1290,7 +1417,7 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart ## MainComponent -> XCharts.Runtime.MainComponent : [IComparable](https://docs.unity3d.com/ScriptReference/30_search.html?q=IComparable) / Subclasses: [Axis](#axis), [Background](#background), [Comment](#comment), [DataZoom](#datazoom), [Legend](#legend), [MarkArea](#markarea), [MarkLine](#markline), [Settings](#settings), [Title](#title), [Tooltip](#tooltip), [VisualMap](#visualmap), [CoordSystem](#coordsystem) +> XCharts.Runtime.MainComponent : [IComparable](https://docs.unity3d.com/ScriptReference/30_search.html?q=IComparable) / Subclasses: [Axis](#axis), [Background](#background), [Comment](#comment), [DataZoom](#datazoom), [Legend](#legend), [MarkArea](#markarea), [MarkLine](#markline), [Settings](#settings), [Title](#title), [Tooltip](#tooltip), [VisualMap](#visualmap), [GridLayout](#gridlayout), [CoordSystem](#coordsystem) ## MarkArea @@ -1419,6 +1546,28 @@ Marquee style. It can be used for the DataZoom component. 选取框样式。可 </APITable> ``` +## MLValue + +> XCharts.Runtime.MLValue : [ChildComponent](#childcomponent) + +> 从 `v3.8.0` 开始支持 + +多样式数值。 + +```mdx-code-block +<APITable name="MLValue"> +``` + + +|field|default|since|comment| +|--|--|--|--| +|type|||<br/>`MLValue.Type`:<br/>- `Percent`: 百分比形式。<br/>- `Absolute`: 绝对值形式。<br/>- `Extra`: 额外形式。<br/>| +|value||| + +```mdx-code-block +</APITable> +``` + ## Padding > XCharts.Runtime.Padding : [ChildComponent](#childcomponent) / Subclasses: [TextPadding](#textpadding) @@ -1500,6 +1649,7 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart |center|||极坐标的中心点。数组的第一项是横坐标,第二项是纵坐标。 当值为0-1之间时表示百分比,设置成百分比时第一项是相对于容器宽度,第二项是相对于容器高度。 |radius|||半径。radius[0]表示内径,radius[1]表示外径。 |backgroundColor|||极坐标的背景色,默认透明。 +|indicatorLabelOffset|30f|v3.8.0|指示器标签的偏移量。 ```mdx-code-block </APITable> @@ -1586,6 +1736,7 @@ Radar coordinate conponnet for radar charts. 雷达图坐标系组件,只适 |polarIndex|0||所使用的 polar 组件的 index。 |singleAxisIndex|0||所使用的 singleAxis 组件的 index。 |parallelIndex|0||所使用的 parallel coord 组件的 index。 +|gridIndex|-1|v3.8.0|所使用的 layout 组件的 index。 默认为-1不指定index, 当为大于或等于0时, 为第一个layout组件的第index个格子。 |minShow|||系列所显示数据的最小索引 |maxShow|||系列所显示数据的最大索引 |maxCache|||系列中可缓存的最大数据量。默认为0没有限制,大于0时超过指定值会移除旧数据再插入新数据。 @@ -1616,6 +1767,7 @@ Radar coordinate conponnet for radar charts. 雷达图坐标系组件,只适 |gap|||间距。 |center|||中心点。 |radius|||半径。radius[0]表示内径,radius[1]表示外径。 +|minRadius|0f|v3.8.0|最小半径。可用于限制玫瑰图的最小半径。 |showDataDimension|||数据项里的数据维数。 |showDataName|||在Editor的inpsector上是否显示name参数 |clip|false||是否裁剪超出坐标系部分的图形。 @@ -1715,9 +1867,6 @@ Radar coordinate conponnet for radar charts. 雷达图坐标系组件,只适 |lineWidth|||文本颜色。 |lineSymbolSize|||折线图的Symbol大小。 |scatterSymbolSize|||散点图的Symbol大小。 -|pieTooltipExtraRadius|||饼图鼠标移到高亮时的额外半径 -|selectedRate|1.3f||折线图或散点图在被选中时的放大倍数。 -|pieSelectedOffset|||饼图选中时的中心点偏移。 |candlestickColor|Color32(235, 84, 84, 255)||K线图阳线(涨)填充色 |candlestickColor0|Color32(71, 178, 98, 255)||K线图阴线(跌)填充色 |candlestickBorderWidth|1||K线图边框宽度 @@ -1864,7 +2013,7 @@ Serie的状态样式。Serie的状态有正常,高亮,淡出,选中四种 |field|default|since|comment| |--|--|--|--| |show|true||是否显示标记。 -|type|||标记类型。<br/>`SymbolType`:<br/>- `None`: 不显示标记。<br/>- `Custom`: 自定义标记。<br/>- `Circle`: 圆形。<br/>- `EmptyCircle`: 空心圆。<br/>- `Rect`: 正方形。可通过设置`itemStyle`的`cornerRadius`变成圆角矩形。<br/>- `EmptyRect`: 空心正方形。<br/>- `Triangle`: 三角形。<br/>- `EmptyTriangle`: 空心三角形。<br/>- `Diamond`: 菱形。<br/>- `EmptyDiamond`: 空心菱形。<br/>- `Arrow`: 箭头。<br/>- `EmptyArrow`: 空心箭头。<br/>| +|type|||标记类型。<br/>`SymbolType`:<br/>- `None`: 不显示标记。<br/>- `Custom`: 自定义标记。<br/>- `Circle`: 圆形。<br/>- `EmptyCircle`: 空心圆。<br/>- `Rect`: 正方形。可通过设置`itemStyle`的`cornerRadius`变成圆角矩形。<br/>- `EmptyRect`: 空心正方形。<br/>- `Triangle`: 三角形。<br/>- `EmptyTriangle`: 空心三角形。<br/>- `Diamond`: 菱形。<br/>- `EmptyDiamond`: 空心菱形。<br/>- `Arrow`: 箭头。<br/>- `EmptyArrow`: 空心箭头。<br/>- `Plus`: 加号。<br/>- `Minus`: 减号。<br/>| |size|0f||标记的大小。 |gap|0||图形标记和线条的间隙距离。 |width|0f||图形的宽。 @@ -2047,8 +2196,8 @@ Serie的状态样式。Serie的状态有正常,高亮,淡出,选中四种 |field|default|since|comment| |--|--|--|--| |show|true||是否显示提示框组件。 -|type|||提示框指示器类型。<br/>`Tooltip.Type`:<br/>- `Line`: 直线指示器<br/>- `Shadow`: 阴影指示器<br/>- `None`: 无指示器<br/>- `Corss`: 十字准星指示器。坐标轴显示Label和交叉线。<br/>| -|trigger|||触发类型。<br/>`Tooltip.Trigger`:<br/>- `Item`: 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。<br/>- `Axis`: 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。<br/>- `None`: 什么都不触发。<br/>| +|type|||提示框指示器类型。<br/>`Tooltip.Type`:<br/>- `Line`: 直线指示器<br/>- `Shadow`: 阴影指示器<br/>- `None`: 无指示器<br/>- `Corss`: 十字准星指示器。坐标轴显示Label和交叉线。<br/>- `Auto`: 根据serie的类型自动选择显示指示器。<br/>| +|trigger|||触发类型。<br/>`Tooltip.Trigger`:<br/>- `Item`: 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。<br/>- `Axis`: 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。<br/>- `None`: 什么都不触发。<br/>- `Auto`: 根据serie的类型自动选择触发类型。<br/>| |position||v3.3.0|显示位置类型。<br/>`Tooltip.Position`:<br/>- `Auto`: 自适应。移动平台靠顶部显示,非移动平台跟随鼠标位置。<br/>- `Custom`: 自定义。完全自定义显示位置(x,y)。<br/>- `FixedX`: 只固定坐标X。Y跟随鼠标位置。<br/>- `FixedY`: <br/>| |itemFormatter|||提示框单个serie或数据项内容的字符串模版格式器。支持用 \n 换行。用 |titleFormatter|||提示框标题内容的字符串模版格式器。支持用 \n 换行。可以单独设置占位符{i}表示忽略不显示title。 模板变量有{.}、{a}、{b}、{c}、{d}、{e}、{f}、{g}。<br/> {.}为当前所指示或index为0的serie的对应颜色的圆点。<br/> {a}为当前所指示或index为0的serie的系列名name。<br/> {b}为当前所指示或index为0的serie的数据项serieData的name,或者类目值(如折线图的X轴)。<br/> {c}为当前所指示或index为0的serie的y维(dimesion为1)的数值。<br/> {d}为当前所指示或index为0的serie的y维(dimesion为1)百分比值,注意不带%号。<br/> {e}为当前所指示或index为0的serie的数据项serieData的name。<br/> {h}为当前所指示或index为0的serie的数据项serieData的十六进制颜色值。<br/> {f}为数据总和。<br/> {g}为数据总个数。<br/> {.1}表示指定index为1的serie对应颜色的圆点。<br/> {a1}、{b1}、{c1}中的1表示指定index为1的serie。<br/> {c1:2}表示索引为1的serie的当前指示数据项的第3个数据(一个数据项有多个数据,index为2表示第3个数据)。<br/> {c1:2-2}表示索引为1的serie的第3个数据项的第3个数据(也就是要指定第几个数据项时必须要指定第几个数据)。<br/> {d1:2:f2}表示单独指定了数值的格式化字符串为f2(不指定时用numericFormatter)。<br/> {d:0.##} 表示单独指定了数值的格式化字符串为 0.## (用于百分比,保留2位有效数同时又能避免使用 f2 而出现的类似于"100.00%"的情况 )。<br/> 示例:"{a}:{c}"、"{a1}:{c1:f1}"、"{a1}:{c1:0:f1}"、"{a1}:{c1:1-1:f1}" @@ -2262,8 +2411,6 @@ Serie的状态样式。Serie的状态有正常,高亮,淡出,选中四种 |lineSegmentDistance|3f|| |cicleSmoothness|2f|| |visualMapTriangeLen|20f|| -|pieTooltipExtraRadius|8f|| -|pieSelectedOffset|8f|| |customThemes||| ```mdx-code-block diff --git a/Documentation~/zh/faq.md b/Documentation~/zh/faq.md index 51054ce8..98b42f71 100644 --- a/Documentation~/zh/faq.md +++ b/Documentation~/zh/faq.md @@ -7,49 +7,49 @@ slug: /faq [QA 1:如何调整坐标轴与背景的边距?](#如何调整坐标轴与背景的边距) [QA 2:如何让初始动画重新播放?](#如何让初始动画重新播放) -[QA 3:如何自定义折线图、饼图等数据项的颜色?](#如何自定义折线图_饼图等数据项的颜色) -[QA 4:如何格式化文字,如我想给坐标轴标签加上单位?](#如何格式化文字_如我想给坐标轴标签加上单位) +[QA 3:如何自定义折线图饼图的颜色?](#如何自定义折线图饼图的颜色) +[QA 4:如何给坐标轴上的文本加上单位?](#如何给坐标轴上的文本加上单位) [QA 5:如何让柱形图的柱子堆叠显示?](#如何让柱形图的柱子堆叠显示) [QA 6:如何让柱形图的柱子同柱但不重叠?](#如何让柱形图的柱子同柱但不重叠) [QA 7:如何调整柱形图的柱子宽度和间距?](#如何调整柱形图的柱子宽度和间距) [QA 8:如何调整柱形图单个柱子的颜色?](#如何调整柱形图单个柱子的颜色) [QA 9:如何调整图表的对齐方式?](#如何调整图表的对齐方式) [QA 10:可以显示超过1000以上的大数据吗?](#可以显示超过1000以上的大数据吗) -[QA 11:折线图可以画虚线、点线、点划线吗?](#折线图可以画虚线_点线_点划线吗) -[QA 12:如何限定Y轴(Value轴)的值范围?](#如何限定Y轴的值范围) +[QA 11:折线图可以画虚线、点线、点划线吗?](#折线图可以画虚线点线点划线吗) +[QA 12:如何限定Y轴的值范围?](#如何限定Y轴的值范围) [QA 13:如何自定义数值轴刻度大小?](#如何自定义数值轴刻度大小) [QA 14:如何在数据项顶上显示文本?](#如何在数据项顶上显示文本) [QA 15:如何给数据项自定义图标?](#如何给数据项自定义图标) -[QA 16:锯齿太严重,如何让图表更顺滑?](#锯齿太严重_如何让图表更顺滑) +[QA 16:锯齿太严重,如何让图表更顺滑?](#锯齿太严重如何让图表更顺滑) [QA 17:为什么鼠标移上图表 Tooltip 不显示?](#为什么鼠标移上图表Tooltip不显示) [QA 18:如何取消 Tooltip 的竖线?](#如何取消Tooltip的竖线) [QA 19:如何自定义 Tooltip 的显示内容?](#如何自定义Tooltip的显示内容) -[QA 20:如何让Y轴(数值轴)显示多位小数?](#如何让Y轴显示多位小数) +[QA 20:如何让Y轴显示多位小数?](#如何让Y轴显示多位小数) [QA 21:如何用代码动态更新数据?](#如何用代码动态更新数据) -[QA 22:如何显示图例?为什么有时候图例无法显示?](#如何显示图例_为什么有时候图例无法显示) +[QA 22:如何显示图例?为什么有时候图例无法显示?](#如何显示图例为什么有时候图例无法显示) [QA 23:如何做成预设?](#如何做成预设) [QA 24:如何在图表上画点画线等自定义内容?](#如何在图表上画点画线等自定义内容) [QA 25:如何实现心电图类似的数据移动效果?](#如何实现心电图类似的数据移动效果) -[QA 26:如何使用背景组件?有什么条件限制?](#如何使用背景组件_有什么条件限制) +[QA 26:如何使用背景组件?有什么条件限制?](#如何使用背景组件有什么条件限制) [QA 27:Mesh can not have more than 65000 vertices?](#Mesh_cannot_have_more_than_65000_vertices) [QA 28:为什么serie里设置的参数运行后又被重置了?](#为什么serie里设置的参数运行后又被重置了) [QA 29:如何修改Serie的Symbol的颜色?](#如何修改Serie的Symbol的颜色) -[QA 30:导入或更新XCharts时TMP报错怎么办?](#导入或更新XCharts时TMP报错怎么办) -[QA 31:支持空数据吗?如何实现折线图断开的效果?](#支持空数据吗_如何实现折线图断开的效果) +[QA 30:导入或更新XCharts时TMP报错如何处理?](#导入或更新XCharts时TMP报错怎么办) +[QA 31:支持空数据吗?如何实现折线图断开的效果?](#支持空数据吗如何实现折线图断开的效果) ## 如何调整坐标轴与背景的边距 -答:`Grid`组件,可调整上下左右边距。 +答:调整`Grid`组件,可调整上下左右边距。 ## 如何让初始动画重新播放 -答:调用`AnimationReset()`接口。 +答:调用`chart.AnimationReset()`接口。 -## 如何自定义折线图_饼图等数据项的颜色 +## 如何自定义折线图饼图的颜色 答:通过`Theme`的`colorPalette`调整,或者部分`Serie`下的`LineStyle`和`ItemStyle`。 -## 如何格式化文字_如我想给坐标轴标签加上单位 +## 如何给坐标轴上的文本加上单位 答:通过`formatter`和`numericFormatter`参数,在`Legend`、`Axis`的`AxisLabel`、`Tooltop`、`Serie`的`Label`都提供该参数的配置。 @@ -77,7 +77,7 @@ slug: /faq 答:可以。但`UGUI`对单个`Graphic`限制`65000`个顶点,所以太多的数据不一定能显示完全。可通过设置采样距离`sampleDist`开启采样简化过密曲线。也可以通过设置一些参数来减少图表的顶点数有助于显示更多数据。如缩小图表的尺寸,关闭或减少坐标轴的客户端绘制,关闭`Serie`的`symbol`和`label`显示等。折线图的普通线图`Normal`比平滑线图`Smooth`占用顶点数更少。`1.5.0`以上版本可以设置`large`和`largeThreshold`参数来开启性能模式。 -## 折线图可以画虚线_点线_点划线吗 +## 折线图可以画虚线点线点划线吗 答:可以。通过`Serie`下的`lineType`选择线条样式。当要显示的数据过多(成千以上)数据间过密时建议使用`Normal`或者`Step`样式。 @@ -97,7 +97,7 @@ slug: /faq 答:通过设置`Serie`的`data`下的数据项可单独设置`icon`相关参数。 -## 锯齿太严重_如何让图表更顺滑 +## 锯齿太严重如何让图表更顺滑 答:开启抗锯齿设置(在`Unity`里设置)。调整UI渲染模式为`Camera`模式,开启`MSAA`,设置`4`倍或更高抗锯齿。 @@ -111,7 +111,7 @@ slug: /faq ## 如何自定义Tooltip的显示内容 -答:自定义总的内容可以通过`Tooltip`的`formatter`。如果只是想调整所有的`serie`的显示格式可以用`itemFormatter`和`titleFormatter`结合。如果想每个`serie`的显示格式不一样,可以定制`serie`的`itemStyle`里的`tooltipFormatter`。具体的用法请查阅[XCharts配置项手册](configuration.md)。 +答:自定义总的内容可以通过`Tooltip`的`formatter`。如果只是想调整所有的`serie`的显示格式可以用`itemFormatter`和`titleFormatter`结合。如果想每个`serie`的显示格式不一样,可以定制`serie`的`itemStyle`里的`tooltipFormatter`。具体的用法请查阅[XCharts配置项手册](https://xcharts-team.github.io/docs/configuration#Tooltip-itemFormatter)。 ## 如何让Y轴显示多位小数 @@ -121,7 +121,7 @@ slug: /faq 答:请查阅`Example`下的代码,`Example13_LineSimple.cs`就是一个简单添加数据构建折线图的例子,其他`Demo`也都是通过代码控制不同的组件实现不同的功能,相关API请查看文档:[XChartsAPI接口](api.md) 。 -## 如何显示图例_为什么有时候图例无法显示 +## 如何显示图例为什么有时候图例无法显示 答:首先,你的`serie`里的`name`需有值不为空。然后开启`Legend`显示,里面的`data`可以默认为空,表示显示所有的图例。如果你只想显示部分`serie`的图例,在`data`中填入要显示的图例的`name`即可。如果`data`中的值都不是系列的`name`,那图例就不会显示。 @@ -137,7 +137,7 @@ slug: /faq 答:参考`Example`目录下的`Example_Dynamic.cs`。主要通过设置`maxCache`参数实现。`axis`和`serie`都设置相同的`maxCache`。`maxCache`可固定数据个数,当数据超过设定时会先删除第一个在添加新数据,实现数据移动效果。 -## 如何使用背景组件_有什么条件限制 +## 如何使用背景组件有什么条件限制 答:设置`background`组件的`show`为`true`。 @@ -164,7 +164,8 @@ slug: /faq 1. 找到`XCharts.Runtime.asmdef`和`XCharts.Editor.asmdef`,手动加上 `TextMeshPro`的引用 2. 移除`PlayerSetting`中`Scripting Define Symbols`的`dUI_TextMeshPro`宏 -## 支持空数据吗_如何实现折线图断开的效果 +`3.8.0`版本后增加[XCharts-Daemon](https://github.com/XCharts-Team/XCharts-Daemon)守护程序,将XCharts-Daemon导入项目后,在更新XCharts时守护程序会自动根据本地开启的TMP情况刷新asmdef,确保编译正常。 + +## 支持空数据吗如何实现折线图断开的效果 答:`Serie`的`data`是`double`类型,所以无法表示空数据。可通过开启`Serie`的`ignore`和指定`ignoreValue`来达到空数据的效果。也可以每个`SerieData`设置`ignore`参数。忽略数据后断开还是连接可设置`ignoreLineBreak`参数。 - diff --git a/Documentation~/zh/support.md b/Documentation~/zh/support.md index c7bdbe71..6a186d64 100644 --- a/Documentation~/zh/support.md +++ b/Documentation~/zh/support.md @@ -6,82 +6,91 @@ slug: /support # 订阅服务 -如需技术支持,可订阅`个人VIP`服务。扫后面的二维码付费后可加VIP群`867291970`,验证信息请输入付费的账号。 -企业商务合作可联系QQ:3525422251(XCharts技术支持)。 +如需技术支持和购买扩展图表,可订阅`VIP`服务。详情可查看以下内容,也可以加QQ`3525422251(XCharts技术支持)`或发邮件到`monitor1394@gmail.com`进行咨询。 + +企业商务合作可QQ和邮件咨询。 ## 订阅VIP服务 订阅服务分`个人订阅`和`企业订阅`: -- `个人订阅`:`个人VIP`属于个人,不可转让,`XCharts`团队只服务于订阅当事人。 -- `企业订阅`:`企业VIP`属于企业,席位内可安排固定职员,职员离职后席位可重新安排,`XCharts`团队通过专属企业群为企业服务。 +- __个人订阅__:`个人VIP`属于个人,不可转让,`XCharts`团队只服务于订阅当事人。 +- __企业订阅__:`企业VIP`属于企业,席位内可安排固定职员,职员离职后席位可重新安排,`XCharts`团队通过专属企业群为企业服务。 订阅服务有哪些优势? -- 提高工作效率,节省时间成本。一方面,`XCharts`功能强大,相关配置项非常多,`VIP`服务可快速帮您定位,节省去查找和核对的时间;另一方面,`VIP`的即时回答服务可快速为您答疑解惑,避免中断开发流程,快速上手,快速处理问题,至少能提高`10`倍以上的工作效率。 -- 更多技术交流,更多经验交流。`XCharts`团队成员从业多年,有丰富的技术和工作经验。`VIP`服务不仅可以交流`XCharts`相关的内容,也可以咨询其他方面的技术。`VIP`群也有更多的交流。 -- 扩展图表需要订阅`VIP`服务后才能购买,扩展图表超过1年后的更新支持也需要持续订阅`VIP`服务。 -- `VIP`用户可加入`XCharts`的`GitHub`组织,参与`XCharts`的社区构建,访问专有仓库。拥有`扩展UI组件`等专属功能。 -- 在`XCharts交流群`里拥有`VIP`专属标识,问题会第一时间得到响应,有问即答。 +- __提高工作效率,节省时间成本__。`XCharts`功能强大,配置项众多,`VIP`服务可快速帮您定位,节省查找和核对的时间;`VIP`的即时回答服务可快速为您答疑解惑,快速上手,提高工作效率。 +- __更多技术交流,更多经验交流__。`XCharts`团队成员从业多年,有丰富的技术和工作经验。`VIP`服务不仅可以交流`XCharts`相关的内容,也可以咨询其他方面内容。`VIP`群也有更多的交流碰撞。 +- __订阅扩展图表,获得更新支持__。扩展图表需要订阅`VIP`服务后才能购买,扩展图表超过1年后的更新支持也需要持续订阅`VIP`服务。 +- __加入团队组织,参与社区建设__。订阅`VIP`后可加入`GitHub`组织,参与社区建设,访问专有仓库,扩展图表仓库等其他私有仓库。 +- __专属高级功能,专属身份标识__。订阅`VIP`后可以享有扩展UI组件,扩展图表等其他高级功能,XCharts后续也会陆续推出更多高级功能。在`XCharts交流群`里拥有`专属头衔`,方便快速识别,优先响应,第一时间回复VIP用户的各种问题。 -| |免费用户|付费咨询|个人`VIP` | 个人`SVIP` | 企业`VIP` | -| ----- |--|--|--|--|--| -| 订阅费用 | -- | `98`¥ | `298`¥ | 首年`1298`¥<br/>后续`298¥`* | `联系我们` | -| 订阅时长 | -- | `7`天* | `1`年 | `1`年* | `1`年 -| 订阅席位 | -- | `1`个席位 | `1`个席位 |`1`个席位|`5`个以上席位| +| |免费用户|付费咨询|个人`VIP` | 个人`SVIP` | 企业`VIP` | 企业`SVIP` | +| ----- |--|--|--|--|--|--| +| 订阅费用 | -- | `98`¥ | `298`¥ | 首年`1298`¥<br/>后续`298¥`* | 首年`1698`¥<br/>后续`298¥`* | `联系我们` | +| 订阅时长 | -- | `7`天* | `1`年 | `1`年 | `1`年 | `1`年 | +| 订阅席位 | -- | `1`个席位 | `1`个席位 |`1`个席位|`1`个席位|`5`个以上席位| +| 订阅条件 | -- | | Github帐号 | Github帐号 |Github帐号<br/>企业银行帐号|Github帐号<br/>企业银行帐号| | __`服务方式:`__| -| 官方QQ群交流 | √ | √ | √ | √ | √ | -| 即时一对一交流 | | √ | √ | √ | √ | -| 专属VIP群交流 | | | √ | √ | √(专属企业群) | +| 官方QQ群交流 | √ | √ | √ | √ | √ | √ | +| QQ一对一交流 | | √ | √ | √ | √ | √ | +| 专属VIP群交流 | | | √ | √ | √ | | +| 微信交流 | | | | | √ | √(企业专属群) | | __`服务内容:`__| -| 可商用 | √ | √ | √ | √ | √ | -| 可二次开发 | √ | √ | √ | √ | √ | -| 有问即答 | | √ | √ | √ | √ | -| 新手指导 | | √ | √ | √ | √ | -| 开发指导 | | √ | √ | √ | √ | -| 优化指导 | | √ | √ | √ | √ | -| 其他技术支持 | | | √ | √ | √ | -| 问题及时处理 | | | √ | √ | √ | -| 需求优先考虑 | | | √ | √ | √ | -| 可另付费定制 | | | √ | √ | √ | -| 可另付费加急 | | | √ | √ | √ | -| 扩展UI组件 | | | √ | √ | √ | -| 扩展图表购买 | | | 按需购买 | __全部免费__ | __全部免费__ | -| 扩展图表源码 | | | 永久持有 | 永久持有 | 永久持有 | -| 扩展图表更新 | | | 1年更新支持 | 1年更新支持 | 1年更新支持 | +| 可商用 | √ | √ | √ | √ | √ | √ | +| 可二次开发 | √ | √ | √ | √ | √ | √ | +| 有问即答 | | √ | √ | √ | √ | √ | +| 新手入门指导 | | √ | √ | √ | √ | √ | +| 开发优化指导 | | √ | √ | √ | √ | √ | +| 其他技术支持 | | | √ | √ | √ | √ | +| 问题及时处理 | | | √ | √ | √ | √ | +| 需求优先考虑 | | | √ | √ | √ | √ | +| 可另付费定制 | | | √ | √ | √ | √ | +| 可另付费加急 | | | √ | √ | √ | √ | +| 扩展UI组件 | | | √ | √ | √ | √ | +| 付费方式 | | | 二维码 | 二维码 | __对公转账__* | __对公转账__* | +| 支持开发票 | | | 普票 | 普票 | __专票__ | __专票__ | +| 扩展图表购买 | | | 按需购买 | __全部免费__* | __全部免费__* | __全部免费__* | +| 扩展图表源码 | | | 永久持有 | 永久持有 | 永久持有 | 永久持有 | +| 扩展图表更新 | | | 1年更新支持 | 1年更新支持 | 1年更新支持 | 1年更新支持 | + +>备注: +>*__`付费定制`__ 用户可根据自己的需求可付费定制不同的图表或新功能,只有`VIP`用户才享有`付费定制`权利。 +>*__`付费加急`__ 用户可对已在开发计划中或正在开发中的功能进行付费加急,将开发优先级提到最高,并可要求在指定`截止日期`内交付,只有`VIP`用户才享有`付费加急`权利。 +>*__`付费咨询`__ 付费咨询有效期`7`天,且总咨询时长不超过`7`个小时。 +>*__`扩展图表`__ 购买后代码可永久持有和商用,1年的更新和技术支持。可继续订阅VIP延长服务时间。 +>*__`全部免费`__ 是指在订阅期间的`个人SVIP`和`企业VIP`的订阅用户,可免费使用全部的扩展图表。 +>*__`次年付费`__ 个人SVIP和企业VIP的首年和次年付费不一样,次年付费都是`298¥`。 +>*__`对公转账`__ 有开专票需求时,可用企业银行帐号进行公对公转账支付。二维码支付不支持开专票,只能开普票。发票默认都是电子发票。 +>*__`登记资料`__ 订阅成功后,需提供手机号和Github帐号进行登记,手机号用于确认归属,Github帐号用于下载源码。 ## 购买扩展图表 -扩展图表为另付费购买图表,只对订阅了`VIP`服务的用户开放购买。对于`SVIP`的订阅用户,所有扩展图表仓库可免费使用,不用再单独购买。 +扩展图表为另付费购买图表,只对订阅了`VIP`服务的用户开放购买。对于`个人SVIP`和`企业VIP`的订阅用户,所有扩展图表仓库在订阅期间可全部免费使用,不用再单独购买。 -对所有已购买的扩展图表,源码可永久持有,并获得持续一年的更新支持,一年后如需更新支持服务,可再继续订阅`VIP`服务。 +对所有已购买的扩展图表,源码可永久持有,并获得持续一年的更新支持和技术服务,一年后如需更新支持服务,可再继续订阅`VIP`服务。 -|编号|扩展图表|价格|备注| +|编号|扩展图表|扩展图表|价格| |--|--|--|--| -| 101 | PictorialBarChart | 98¥ | 象形柱图 | -| 102 | FunnelChart | 98¥ | 漏斗图 | -| 103 | PyramidChart | 98¥ | 3D金字塔 | -| 104 | TreemapChart | 98¥ | 树形矩图 | -| 201 | Bar3DChart | 198¥ | 3D柱图 | -| 202 | Pie3DChart | 198¥ | 3D饼图 | -| 203 | GanttChart | 198¥ | 甘特图 | -| 204 | GaugeChart | 198¥ | 仪表盘 | -| 205 | LiquidChart | 198¥ | 水位图 | +| 101 | [象形柱图](https://xcharts-team.github.io/docs/pictorialbar) |PictorialBarChart | 98¥ | +| 102 | [漏斗图](https://xcharts-team.github.io/docs/funnel) |FunnelChart | 98¥ | +| 103 | [3D金字塔](https://xcharts-team.github.io/docs/pyramid) |PyramidChart | 98¥ | +| 104 | [树形矩图](https://xcharts-team.github.io/docs/treemap) |TreemapChart | 98¥ | +| 201 | [3D柱图](https://xcharts-team.github.io/docs/bar3d) |Bar3DChart | 198¥ | +| 202 | [3D饼图](https://xcharts-team.github.io/docs/pie3d) |Pie3DChart | 198¥ | +| 203 | [甘特图](https://xcharts-team.github.io/docs/gantt) |GanttChart | 198¥ | +| 204 | [仪表盘](https://xcharts-team.github.io/docs/gauge) |GaugeChart | 198¥ | +| 205 | [水位图](https://xcharts-team.github.io/docs/liquid) |LiquidChart | 198¥ | -## 备注说明 - -1. __`付费定制`__ 是指用户可根据自己的需求定制不同的图表或新功能,只有`VIP`用户才享有`付费定制`权利。 -2. __`付费加急`__ 是指用户可对自己非常紧急的需求进行付费,将开发优先级提到最高,并可要求在指定`截止日期`内交付,只有`VIP`用户才享有`付费加急`权利。 -3. __`付费咨询`__ 付费咨询有效期`7`天,且总咨询时长不超过`7`个小时。 -4. __`扩展图表`__ 购买后代码可永久持有和商用,1年的更新和技术支持。 +扩展图表的在线效果图也可以查看[WebGL在线Demo](https://xcharts-team.github.io/examples/) ## 捐助支持 -如果这个项目对您有帮助,请右上方点 `Star` 予以支持!也欢迎任意金额的捐助,非常感谢您的支持! +如果这个项目对您有帮助,请右上方点 `Star` 予以支持!也欢迎扫后面的二维码进行任意金额的捐助,XCharts需要您的支持和帮助。 ## 二维码 -如果看不到二维码图片,可以加QQ`XCharts技术支持:3525422251`或邮件`monitor1394@gmail.com`咨询。 +如果看不到二维码图片,可以加Q联系`XCharts技术支持:3525422251`或邮件`monitor1394@gmail.com`咨询。 ![alipay-qrcode](img/support_alipay.png) ![wechat-qrcode](img/support_wechat.png) diff --git a/Documentation~/zh/tutorial01.md b/Documentation~/zh/tutorial01.md index 2d0732d8..46a74d05 100644 --- a/Documentation~/zh/tutorial01.md +++ b/Documentation~/zh/tutorial01.md @@ -38,6 +38,10 @@ XCharts可通过以下任意一种方式导入到项目: 如需更新`XCharts`,删除`manifest.json`文件(部分Unity版本可能是packages-lock.json文件)的`lock`下的`com.monitor1394.xcharts`相关内容即会重新下载编译。 +- 建议先导入XCharts的守护程序(非必须) + + 守护程序[XCharts-Daemon](https://github.com/XCharts-Team/XCharts-Daemon)可以确保更新时编译正常,当本地开启TextMeshPro或NewInputSystem时将会非常有用。将XCharts-Daemon导入项目后,在更新XCharts时守护程序会自动根据本地TMP等的开启情况刷新asmdef,确保编译正常,不用手动去解决,方便CI-CD等自动化流程执行。 + ## 添加一个简单图表 在`Hierarchy`视图下右键或菜单栏`GameObject`下拉选择`XCharts->LineChart`,即可快速创建一个默认的折线图出来: @@ -200,6 +204,8 @@ XCharts支持TextMeshPro,但默认是不开启的,需要自己手动切换 1. 找到`XCharts.Runtime.asmdef`和`XCharts.Editor.asmdef`,手动加上 `TextMeshPro`的引用 2. 移除`PlayerSetting`中`Scripting Define Symbols`的`dUI_TextMeshPro`宏 +`3.8.0`版本后增加[XCharts-Daemon](https://github.com/XCharts-Team/XCharts-Daemon)守护程序,将XCharts-Daemon导入项目后,在更新XCharts时守护程序会自动根据本地开启的TMP情况刷新asmdef,确保编译正常。 + ## 用代码改图表参数 `Inspector`上看到的所有参数都可以用代码来修改,关键是要定位好你要改的参数是在组件上、还是Serie上、还是在具体的数据项SerieData上。 diff --git a/Editor/ChildComponents/AnimationDrawer.cs b/Editor/ChildComponents/AnimationDrawer.cs index 0594b9b5..4e28aa5d 100644 --- a/Editor/ChildComponents/AnimationDrawer.cs +++ b/Editor/ChildComponents/AnimationDrawer.cs @@ -4,6 +4,70 @@ using XCharts.Runtime; namespace XCharts.Editor { + [CustomPropertyDrawer(typeof(XCharts.Runtime.AnimationInfo), true)] + public class AnimationInfoDrawer : 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_Delay"); + PropertyField(prop, "m_Duration"); + --EditorGUI.indentLevel; + } + } + } + + [CustomPropertyDrawer(typeof(XCharts.Runtime.AnimationChange), true)] + public class AnimationChangeDrawer : 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(XCharts.Runtime.AnimationAddition), true)] + public class AnimationAdditionDrawer : 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(XCharts.Runtime.AnimationInteraction), true)] + public class AnimationInteractionDrawer : 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"); + PropertyField(prop, "m_Width"); + PropertyField(prop, "m_Radius"); + PropertyField(prop, "m_Offset"); + --EditorGUI.indentLevel; + } + } + } + [CustomPropertyDrawer(typeof(AnimationStyle), true)] public class AnimationDrawer : BasePropertyDrawer { @@ -15,17 +79,12 @@ namespace XCharts.Editor { ++EditorGUI.indentLevel; PropertyField(prop, "m_Type"); - PropertyField(prop, "m_FadeInDuration"); - PropertyField(prop, "m_FadeInDelay"); - PropertyField(prop, "m_FadeOutDuration"); - PropertyField(prop, "m_FadeOutDelay"); - PropertyField(prop, "m_DataChangeEnable"); - PropertyField(prop, "m_DataChangeDuration"); PropertyField(prop, "m_UnscaledTime"); - // using(new EditorGUI.DisabledGroupScope(true)) - // { - // PropertyField(prop, "m_ActualDuration"); - // } + PropertyField(prop, "m_FadeIn"); + PropertyField(prop, "m_FadeOut"); + PropertyField(prop, "m_Change"); + PropertyField(prop, "m_Addition"); + PropertyField(prop, "m_Interaction"); --EditorGUI.indentLevel; } } diff --git a/Editor/ChildComponents/ComponentThemeDrawer.cs b/Editor/ChildComponents/ComponentThemeDrawer.cs index 06bec277..128f0f9e 100644 --- a/Editor/ChildComponents/ComponentThemeDrawer.cs +++ b/Editor/ChildComponents/ComponentThemeDrawer.cs @@ -148,9 +148,6 @@ namespace XCharts.Editor PropertyField(prop, "m_LineWidth"); PropertyField(prop, "m_LineSymbolSize"); PropertyField(prop, "m_ScatterSymbolSize"); - PropertyField(prop, "m_SelectedRate"); - PropertyField(prop, "m_PieTooltipExtraRadius"); - PropertyField(prop, "m_PieSelectedOffset"); PropertyField(prop, "m_CandlestickColor"); PropertyField(prop, "m_CandlestickColor0"); PropertyField(prop, "m_CandlestickBorderColor"); diff --git a/Editor/ChildComponents/LabelLineDrawer.cs b/Editor/ChildComponents/LabelLineDrawer.cs index dcd2d6c3..e26fd567 100644 --- a/Editor/ChildComponents/LabelLineDrawer.cs +++ b/Editor/ChildComponents/LabelLineDrawer.cs @@ -21,6 +21,7 @@ namespace XCharts.Editor PropertyField(prop, "m_LineGap"); PropertyField(prop, "m_LineLength1"); PropertyField(prop, "m_LineLength2"); + PropertyField(prop, "m_LineEndX"); PropertyField(prop, "m_StartSymbol"); PropertyField(prop, "m_EndSymbol"); --EditorGUI.indentLevel; diff --git a/Editor/ChildComponents/MLValueDrawer.cs b/Editor/ChildComponents/MLValueDrawer.cs new file mode 100644 index 00000000..fe515641 --- /dev/null +++ b/Editor/ChildComponents/MLValueDrawer.cs @@ -0,0 +1,27 @@ +using UnityEditor; +using UnityEngine; +using XCharts.Runtime; + +namespace XCharts.Editor +{ + + [CustomPropertyDrawer(typeof(MLValue), true)] + public class MLValueDrawer : BasePropertyDrawer + { + public override void OnGUI(Rect pos, SerializedProperty prop, GUIContent label) + { + Rect drawRect = pos; + drawRect.height = EditorGUIUtility.singleLineHeight; + SerializedProperty m_Percent = prop.FindPropertyRelative("m_Type"); + SerializedProperty m_Color = prop.FindPropertyRelative("m_Value"); + + ChartEditorHelper.MakeTwoField(ref drawRect, drawRect.width, m_Percent, m_Color, prop.displayName); + drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; + } + + public override float GetPropertyHeight(SerializedProperty prop, GUIContent label) + { + return 1 * EditorGUIUtility.singleLineHeight + 1 * EditorGUIUtility.standardVerticalSpacing; + } + } +} \ No newline at end of file diff --git a/Examples/Example_AddChart.cs.meta b/Editor/ChildComponents/MLValueDrawer.cs.meta similarity index 83% rename from Examples/Example_AddChart.cs.meta rename to Editor/ChildComponents/MLValueDrawer.cs.meta index 2fdb2eaa..e551a920 100644 --- a/Examples/Example_AddChart.cs.meta +++ b/Editor/ChildComponents/MLValueDrawer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8e5c24ed461624b8d924dfb1285e0a95 +guid: 364b6129b88e14605b1a1454b7bf876b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/MainComponents/GridCoordEditor.cs b/Editor/MainComponents/GridCoordEditor.cs index 460161ce..cc39f58b 100644 --- a/Editor/MainComponents/GridCoordEditor.cs +++ b/Editor/MainComponents/GridCoordEditor.cs @@ -9,10 +9,15 @@ namespace XCharts.Editor public override void OnInspectorGUI() { ++EditorGUI.indentLevel; - PropertyField("m_Left"); - PropertyField("m_Right"); - PropertyField("m_Top"); - PropertyField("m_Bottom"); + var layoutIndex = baseProperty.FindPropertyRelative("m_LayoutIndex").intValue; + PropertyField("m_LayoutIndex"); + if (layoutIndex < 0) + { + PropertyField("m_Left"); + PropertyField("m_Right"); + PropertyField("m_Top"); + PropertyField("m_Bottom"); + } PropertyField("m_BackgroundColor"); PropertyField("m_ShowBorder"); PropertyField("m_BorderWidth"); diff --git a/Editor/MainComponents/GridLayoutEditor.cs b/Editor/MainComponents/GridLayoutEditor.cs new file mode 100644 index 00000000..b20aea51 --- /dev/null +++ b/Editor/MainComponents/GridLayoutEditor.cs @@ -0,0 +1,23 @@ +using UnityEditor; +using XCharts.Runtime; + +namespace XCharts.Editor +{ + [ComponentEditor(typeof(GridLayout))] + public class GridLayoutEditor : MainComponentEditor<GridLayout> + { + public override void OnInspectorGUI() + { + ++EditorGUI.indentLevel; + PropertyField("m_Left"); + PropertyField("m_Right"); + PropertyField("m_Top"); + PropertyField("m_Bottom"); + PropertyField("m_Row"); + PropertyField("m_Column"); + PropertyField("m_Spacing"); + PropertyField("m_Inverse"); + --EditorGUI.indentLevel; + } + } +} \ No newline at end of file diff --git a/Editor/Utilities/ThemeCheck.cs.meta b/Editor/MainComponents/GridLayoutEditor.cs.meta similarity index 83% rename from Editor/Utilities/ThemeCheck.cs.meta rename to Editor/MainComponents/GridLayoutEditor.cs.meta index 17375c18..54b6ae71 100644 --- a/Editor/Utilities/ThemeCheck.cs.meta +++ b/Editor/MainComponents/GridLayoutEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4b4ba2a9503ae46b1b7b1ae94ec59127 +guid: 4288bf299494d43d497436ace4b7a5a3 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/MainComponents/PolarCoordEditor.cs b/Editor/MainComponents/PolarCoordEditor.cs index 28d867a6..bb94c951 100644 --- a/Editor/MainComponents/PolarCoordEditor.cs +++ b/Editor/MainComponents/PolarCoordEditor.cs @@ -12,6 +12,7 @@ namespace XCharts.Editor PropertyTwoFiled("m_Center"); PropertyTwoFiled("m_Radius"); PropertyField("m_BackgroundColor"); + PropertyField("m_IndicatorLabelOffset"); --EditorGUI.indentLevel; } } diff --git a/Editor/MainComponents/RadarCoordEditor.cs b/Editor/MainComponents/RadarCoordEditor.cs index c3a3420a..8caf9527 100644 --- a/Editor/MainComponents/RadarCoordEditor.cs +++ b/Editor/MainComponents/RadarCoordEditor.cs @@ -10,6 +10,7 @@ namespace XCharts.Editor public override void OnInspectorGUI() { ++EditorGUI.indentLevel; + PropertyField("m_GridIndex"); PropertyField("m_Shape"); PropertyField("m_PositionType"); PropertyTwoFiled("m_Center"); diff --git a/Editor/Series/PieEditor.cs b/Editor/Series/PieEditor.cs index f8e19be5..34e8633f 100644 --- a/Editor/Series/PieEditor.cs +++ b/Editor/Series/PieEditor.cs @@ -7,6 +7,7 @@ namespace XCharts.Editor { public override void OnCustomInspectorGUI() { + PropertyField("m_GridIndex"); PropertyField("m_RoseType"); PropertyField("m_Gap"); PropertyTwoFiled("m_Center"); @@ -14,7 +15,9 @@ namespace XCharts.Editor PropertyField("m_AvoidLabelOverlap"); PropertyFiledMore(() => { + PropertyField("m_MaxCache"); PropertyField("m_MinAngle"); + PropertyField("m_MinRadius"); PropertyField("m_RoundCap"); PropertyField("m_Ignore"); PropertyField("m_IgnoreValue"); diff --git a/Editor/Series/RadarEditor.cs b/Editor/Series/RadarEditor.cs index 60e5fb43..aee5f2ee 100644 --- a/Editor/Series/RadarEditor.cs +++ b/Editor/Series/RadarEditor.cs @@ -10,6 +10,7 @@ namespace XCharts.Editor PropertyField("m_ColorBy"); PropertyField("m_RadarType"); PropertyField("m_RadarIndex"); + PropertyField("m_MaxCache"); PropertyField("m_Smooth"); PropertyField("m_Symbol"); diff --git a/Editor/Series/RingEditor.cs b/Editor/Series/RingEditor.cs index 71ec6db6..26a35856 100644 --- a/Editor/Series/RingEditor.cs +++ b/Editor/Series/RingEditor.cs @@ -7,12 +7,15 @@ namespace XCharts.Editor { public override void OnCustomInspectorGUI() { + PropertyField("m_GridIndex"); PropertyTwoFiled("m_Center"); PropertyTwoFiled("m_Radius"); PropertyField("m_StartAngle"); PropertyField("m_Gap"); + PropertyField("m_MaxCache"); PropertyField("m_RoundCap"); PropertyField("m_Clockwise"); + PropertyField("m_AvoidLabelOverlap"); PropertyField("m_ItemStyle"); PropertyField("m_Animation"); diff --git a/Editor/Series/ScatterEditor.cs b/Editor/Series/ScatterEditor.cs index 77cd8bba..5519bcb7 100644 --- a/Editor/Series/ScatterEditor.cs +++ b/Editor/Series/ScatterEditor.cs @@ -16,6 +16,7 @@ namespace XCharts.Editor PropertyField("m_XAxisIndex"); PropertyField("m_YAxisIndex"); } + PropertyField("m_MaxCache"); PropertyField("m_Clip"); PropertyField("m_Symbol"); diff --git a/Editor/Utilities/ThemeCheck.cs b/Editor/Utilities/XChartsDaemon.cs similarity index 68% rename from Editor/Utilities/ThemeCheck.cs rename to Editor/Utilities/XChartsDaemon.cs index bb31b353..6b3b3224 100644 --- a/Editor/Utilities/ThemeCheck.cs +++ b/Editor/Utilities/XChartsDaemon.cs @@ -5,9 +5,9 @@ using XCharts.Runtime; namespace XCharts.Editor { - internal static class ThemeCheck + internal static class XChartsDaemon { - public class ThemeAssetPostprocessor : AssetPostprocessor + public class XChartsAssetPostprocessor : AssetPostprocessor { static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetsPaths) @@ -28,17 +28,36 @@ namespace XCharts.Editor var fileName = Path.GetFileName(assetPath); if (fileName.Equals("XCSettings.asset")) { + CheckAsmdef(); XCThemeMgr.ReloadThemeList(); - return; } - if (!IsThemeAsset(assetPath)) return; - var theme = AssetDatabase.LoadAssetAtPath<Theme>(assetPath); - if (XCSettings.AddCustomTheme(theme)) + else if (IsThemeAsset(assetPath)) { - XCThemeMgr.ReloadThemeList(); + var theme = AssetDatabase.LoadAssetAtPath<Theme>(assetPath); + if (XCSettings.AddCustomTheme(theme)) + { + XCThemeMgr.ReloadThemeList(); + } } } + public static void CheckAsmdef() + { +#if UNITY_2017_1_OR_NEWER +#if dUI_TextMeshPro + XChartsEditor.CheckAsmdefTmpReference(true); +#else + XChartsEditor.CheckAsmdefTmpReference(false); +#endif +#elif UNITY_2019_1_OR_NEWER +#if INPUT_SYSTEM_ENABLED + XChartsEditor.CheckAsmdefInputSystemReference(true); +#else + XChartsEditor.CheckAsmdefInputSystemReference(false); +#endif +#endif + } + public static void CheckDeletedAsset(string assetPath) { if (!IsThemeAsset(assetPath)) return; diff --git a/Examples/Example_Component.cs.meta b/Editor/Utilities/XChartsDaemon.cs.meta similarity index 83% rename from Examples/Example_Component.cs.meta rename to Editor/Utilities/XChartsDaemon.cs.meta index add53bcb..3841cc58 100644 --- a/Examples/Example_Component.cs.meta +++ b/Editor/Utilities/XChartsDaemon.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2e9941e7d67e44b18899e6048d4ef25a +guid: 036a714dab7744d76849114f5bcf59a9 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/Windows/XChartsEditor.cs b/Editor/Windows/XChartsEditor.cs index 99ed4adc..7443400f 100644 --- a/Editor/Windows/XChartsEditor.cs +++ b/Editor/Windows/XChartsEditor.cs @@ -199,7 +199,9 @@ namespace XCharts.Editor const string SYMBOL_TMP = "dUI_TextMeshPro"; const string ASMDEF_TMP = "Unity.TextMeshPro"; +#if !dUI_TextMeshPro [MenuItem("XCharts/TextMeshPro Enable")] +#endif public static void EnableTextMeshPro() { if (!IsSpecifyAssemblyExist(ASMDEF_TMP)) @@ -207,19 +209,39 @@ namespace XCharts.Editor Debug.LogError("TextMeshPro is not in the project, please import TextMeshPro package first."); return; } - DefineSymbolsUtil.AddGlobalDefine(SYMBOL_TMP); - XChartsMgr.RemoveAllChartObject(); - InsertSpecifyReferenceIntoAssembly(Platform.Editor, ASMDEF_TMP); - InsertSpecifyReferenceIntoAssembly(Platform.Runtime, ASMDEF_TMP); + if (EditorUtility.DisplayDialog("TextMeshPro Enable", "TextMeshPro is disabled, do you want to enable it?", "Yes", "Cancel")) + { + DefineSymbolsUtil.AddGlobalDefine(SYMBOL_TMP); + XChartsMgr.RemoveAllChartObject(); + CheckAsmdefTmpReference(true); + } } +#if dUI_TextMeshPro [MenuItem("XCharts/TextMeshPro Disable")] +#endif public static void DisableTextMeshPro() { - RemoveSpecifyReferenceFromAssembly(Platform.Editor, ASMDEF_TMP); - RemoveSpecifyReferenceFromAssembly(Platform.Runtime, ASMDEF_TMP); - DefineSymbolsUtil.RemoveGlobalDefine(SYMBOL_TMP); - XChartsMgr.RemoveAllChartObject(); + if (EditorUtility.DisplayDialog("TextMeshPro Disable", "TextMeshPro is enabled, do you want to disable it?", "Yes", "Cancel")) + { + CheckAsmdefTmpReference(false); + DefineSymbolsUtil.RemoveGlobalDefine(SYMBOL_TMP); + XChartsMgr.RemoveAllChartObject(); + } + } + + public static void CheckAsmdefTmpReference(bool enable) + { + if (enable) + { + InsertSpecifyReferenceIntoAssembly(Platform.Editor, ASMDEF_TMP); + InsertSpecifyReferenceIntoAssembly(Platform.Runtime, ASMDEF_TMP); + } + else + { + RemoveSpecifyReferenceFromAssembly(Platform.Editor, ASMDEF_TMP); + RemoveSpecifyReferenceFromAssembly(Platform.Runtime, ASMDEF_TMP); + } } #endif #endregion @@ -229,7 +251,10 @@ namespace XCharts.Editor //As InputSystem is released in 2019.1+ ,when unity version is 2019.1+ , enable InputSystem Support const string SYMBOL_I_S = "INPUT_SYSTEM_ENABLED"; const string ASMDEF_I_S = "Unity.InputSystem"; + +#if !INPUT_SYSTEM_ENABLED [MenuItem("XCharts/InputSystem Enable")] +#endif public static void EnableInputSystem() { if (!IsSpecifyAssemblyExist(ASMDEF_I_S)) @@ -237,20 +262,37 @@ namespace XCharts.Editor Debug.LogError("InputSystem is not in the project, please import InputSystem package first."); return; } - // insert input system package into editor and runtime assembly - InsertSpecifyReferenceIntoAssembly(Platform.Editor, ASMDEF_I_S); - InsertSpecifyReferenceIntoAssembly(Platform.Runtime, ASMDEF_I_S); - // add scripting define symbols - DefineSymbolsUtil.AddGlobalDefine(SYMBOL_I_S); + if (EditorUtility.DisplayDialog("InputSystem Enable", "InputSystem is disabled, do you want to enable it?", "Yes", "Cancel")) + { + CheckAsmdefInputSystemReference(true); + DefineSymbolsUtil.AddGlobalDefine(SYMBOL_I_S); + } } + +#if INPUT_SYSTEM_ENABLED [MenuItem("XCharts/InputSystem Disable")] +#endif public static void DisableInputSystem() { - // remove input system package into editor and runtime assembly - RemoveSpecifyReferenceFromAssembly(Platform.Editor, ASMDEF_I_S); - RemoveSpecifyReferenceFromAssembly(Platform.Runtime, ASMDEF_I_S); - // remove scripting define symbols - DefineSymbolsUtil.RemoveGlobalDefine(SYMBOL_I_S); + if (EditorUtility.DisplayDialog("InputSystem Disable", "InputSystem is enabled, do you want to disable it?", "Yes", "Cancel")) + { + CheckAsmdefInputSystemReference(false); + DefineSymbolsUtil.RemoveGlobalDefine(SYMBOL_I_S); + } + } + + public static void CheckAsmdefInputSystemReference(bool enable) + { + if(enable) + { + InsertSpecifyReferenceIntoAssembly(Platform.Editor, ASMDEF_I_S); + InsertSpecifyReferenceIntoAssembly(Platform.Runtime, ASMDEF_I_S); + } + else + { + RemoveSpecifyReferenceFromAssembly(Platform.Editor, ASMDEF_I_S); + RemoveSpecifyReferenceFromAssembly(Platform.Runtime, ASMDEF_I_S); + } } #endif #endregion diff --git a/Examples/Example00_CheatSheet.cs b/Examples/Example00_CheatSheet.cs index 0b22b89b..defa7e7c 100644 --- a/Examples/Example00_CheatSheet.cs +++ b/Examples/Example00_CheatSheet.cs @@ -6,6 +6,7 @@ using XCharts.Runtime; namespace XCharts.Example { [DisallowMultipleComponent] + [RequireComponent(typeof(LineChart))] public class Example00_CheatSheet : MonoBehaviour { private LineChart chart; @@ -43,7 +44,6 @@ namespace XCharts.Example IEnumerator InitChart() { chart = gameObject.GetComponent<LineChart>(); - if (chart == null) gameObject.AddComponent<LineChart>(); chart.EnsureChartComponent<Title>().show = true; chart.EnsureChartComponent<Title>().text = "术语解析-组件"; diff --git a/Examples/Example01_RandomData.cs b/Examples/Example01_RandomData.cs new file mode 100644 index 00000000..e34e8e9a --- /dev/null +++ b/Examples/Example01_RandomData.cs @@ -0,0 +1,189 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; +using XCharts.Runtime; +#if INPUT_SYSTEM_ENABLED +using Input = XCharts.Runtime.InputHelper; +#endif +namespace XCharts.Example +{ + [DisallowMultipleComponent] + [RequireComponent(typeof(BaseChart))] + public class Example01_RandomData : MonoBehaviour + { + public bool loopAdd = false; + public float loopAddTime = 1f; + public bool loopUpdate = false; + public float loopUpadteTime = 1f; + public int maxCache = 0; + + BaseChart chart; + float lastAddTime; + float lastUpdateTime; + int dataCount; + + void Awake() + { + chart = gameObject.GetComponent<BaseChart>(); + } + + void Start() + { + if (maxCache > 0) + { + chart.SetMaxCache(maxCache); + } + dataCount = chart.GetSerie(0).dataCount; + } + + void Update() + { + if (Input.GetKeyDown(KeyCode.Space)) + { + AddData(); + } + else if (Input.GetKeyDown(KeyCode.U)) + { + UpdateData(); + } + lastAddTime += Time.deltaTime; + if (loopAdd && lastAddTime >= loopAddTime) + { + lastAddTime = 0; + AddData(); + } + + lastUpdateTime += Time.deltaTime; + if (loopUpdate && lastUpdateTime >= loopUpadteTime) + { + lastUpdateTime = 0; + UpdateData(); + } + } + + void AddData() + { + if (chart is HeatmapChart) + { + var xAxis = chart.GetChartComponent<XAxis>(); + var yAxis = chart.GetChartComponent<YAxis>(); + if (xAxis != null && yAxis != null) + { + chart.AddXAxisData((xAxis.data.Count + 1).ToString()); + for (int i = 0; i < yAxis.data.Count; i++) + { + chart.AddData(0, xAxis.data.Count - 1, i, Random.Range(10, 90)); + } + } + return; + } + else + { + var xAxis = chart.GetChartComponent<XAxis>(); + if (xAxis != null) + { + if (xAxis.type == Axis.AxisType.Category) + { + chart.AddXAxisData("x" + (xAxis.data.Count + 1)); + } + } + foreach (var serie in chart.series) + { + AddSerieRandomData(serie, xAxis); + } + } + } + + void UpdateData() + { + foreach (var serie in chart.series) + { + UpdateSerieRandomData(serie); + } + } + + void AddSerieRandomData(Serie serie, XAxis xAxis) + { + if (serie is Line || serie is Bar || serie is Scatter || serie is EffectScatter) + { + if (xAxis.type == Axis.AxisType.Category) + { + chart.AddData(serie.index, Random.Range(10, 90), "data" + serie.dataCount); + } + else + { + if (serie is Line) + chart.AddData(serie.index, dataCount++, Random.Range(10, 90), "data" + serie.dataCount); + else + chart.AddData(serie.index, Random.Range(10, 90), Random.Range(10, 90), "data" + serie.dataCount); + } + } + else if (serie is Ring) + { + chart.AddData(serie.index, Random.Range(10, 90), 100, "data" + serie.dataCount); + } + else if (serie is Radar) + { + var list = new System.Collections.Generic.List<double>(); + for (int i = 0; i < 5; i++) + list.Add(Random.Range(10, 90)); + chart.AddData(serie.index, list, "data" + serie.dataCount); + } + else if (serie is Candlestick) + { + var open = Random.Range(20, 60); + var close = Random.Range(40, 90); + var lowest = Random.Range(0, 50); + var heighest = Random.Range(50, 100); + chart.AddData(serie.index, serie.dataCount, open, close, lowest, heighest); + } + else if (serie is Heatmap) + { + var yAxis = chart.GetChartComponent<YAxis>(serie.yAxisIndex); + for (int i = 0; i < yAxis.data.Count; i++) + { + chart.AddData(serie.index, xAxis.data.Count - 1, i, Random.Range(0, 150)); + } + } + else + { + chart.AddData(serie.index, Random.Range(10, 90), "data" + serie.dataCount); + } + } + + void UpdateSerieRandomData(Serie serie) + { + var index = Random.Range(0, serie.dataCount); + if (serie is Ring) + { + chart.UpdateData(serie.index, index, 0, Random.Range(10, 90)); + } + else if (serie is Radar) + { + var dimension = Random.Range(0, 5); + chart.UpdateData(serie.index, index, dimension, Random.Range(10, 90)); + } + else if (serie is Heatmap) + { + var xAxis = chart.GetChartComponent<XAxis>(); + var yAxis = chart.GetChartComponent<YAxis>(); + var xIndex = Random.Range(0, xAxis.data.Count); + var yIndex = Random.Range(0, yAxis.data.Count); + chart.UpdateData(serie.index, xIndex, yIndex, Random.Range(10, 90)); + } + else if (serie is Candlestick) + { + var open = Random.Range(20, 60); + var close = Random.Range(40, 90); + var lowest = Random.Range(0, 50); + var heighest = Random.Range(50, 100); + chart.UpdateData(serie.index, index, new List<double> { open, close, lowest, heighest }); + } + else + { + chart.UpdateData(serie.index, index, Random.Range(10, 90)); + } + } + } +} \ No newline at end of file diff --git a/Examples/Example01_UpdateData.cs.meta b/Examples/Example01_RandomData.cs.meta similarity index 83% rename from Examples/Example01_UpdateData.cs.meta rename to Examples/Example01_RandomData.cs.meta index 827c0515..e06c78bb 100644 --- a/Examples/Example01_UpdateData.cs.meta +++ b/Examples/Example01_RandomData.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d369a0cba6716422cb15efa26bef0918 +guid: 5c7cdc29e9a8040fdbc7100c3325e9ba MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Examples/Example01_UpdateData.cs b/Examples/Example01_UpdateData.cs deleted file mode 100644 index 171de5d9..00000000 --- a/Examples/Example01_UpdateData.cs +++ /dev/null @@ -1,46 +0,0 @@ -using UnityEngine; -using XCharts.Runtime; - -namespace XCharts.Example -{ - [DisallowMultipleComponent] - [ExecuteInEditMode] - public class Example01_UpdateData : MonoBehaviour - { - private float updateTime = 0; - BaseChart chart; - void Awake() - { - chart = gameObject.GetComponent<BaseChart>(); - } - - void Update() - { - updateTime += Time.deltaTime; - if (chart && updateTime > 2) - { - updateTime = 0; - var serie = chart.GetSerie(0); - //serie.animation.dataChangeEnable = true; - var dataCount = serie.dataCount; - if (chart is RadarChart) - { - var dimension = serie.GetSerieData(0).data.Count - 1; - chart.UpdateData(0, 0, Random.Range(0, dimension + 1), Random.Range(0, 100)); - } - else if (chart is HeatmapChart) - { - var dimension = serie.GetSerieData(0).data.Count - 1; - for (int i = 0; i < dataCount; i++) - { - chart.UpdateData(0, i, dimension, Random.Range(0, 10)); - } - } - else - { - chart.UpdateData(0, Random.Range(0, dataCount), Random.Range(10, 90)); - } - } - } - } -} \ No newline at end of file diff --git a/Examples/Example02_ChartEvent.cs b/Examples/Example02_ChartEvent.cs index 59066a4a..7847cf77 100644 --- a/Examples/Example02_ChartEvent.cs +++ b/Examples/Example02_ChartEvent.cs @@ -1,11 +1,13 @@ using UnityEngine; using UnityEngine.EventSystems; +using UnityEngine.UI; using XCharts.Runtime; +using XUGL; namespace XCharts.Example { [DisallowMultipleComponent] - [ExecuteInEditMode] + [RequireComponent(typeof(BaseChart))] public class Example02_ChartEvent : MonoBehaviour { BaseChart chart; @@ -13,46 +15,99 @@ namespace XCharts.Example void Awake() { chart = gameObject.GetComponent<BaseChart>(); - if (chart == null) - { - chart = gameObject.AddComponent<LineChart>(); - } + chart.onPointerEnter = OnPointerEnter; chart.onPointerExit = OnPointerExit; chart.onPointerDown = OnPointerDown; chart.onPointerUp = OnPointerUp; chart.onPointerClick = OnPointerClick; chart.onScroll = OnScroll; + + chart.onSerieClick = OnSerieClick; + chart.onSerieEnter = OnSerieEnter; + chart.onSerieExit = OnSerieExit; + + chart.onDraw = OnDraw; + chart.onDrawBeforeSerie = OnDrawBeforeSerie; + chart.onDrawAfterSerie = OnDrawAfterSerie; + chart.onDrawTop = OnDrawTop; } void OnPointerEnter(PointerEventData eventData, BaseGraph chart) { - //Debug.LogError("enter:" + chart); + Debug.Log("enter:" + chart); } void OnPointerExit(PointerEventData eventData, BaseGraph chart) { - //Debug.LogError("exit:" + chart); + Debug.Log("exit:" + chart); } void OnPointerDown(PointerEventData eventData, BaseGraph chart) { - //Debug.LogError("down:" + chart); + Debug.Log("down:" + chart); } void OnPointerUp(PointerEventData eventData, BaseGraph chart) { - //Debug.LogError("up:" + chart); + Debug.Log("up:" + chart); } void OnPointerClick(PointerEventData eventData, BaseGraph chart) { - //Debug.LogError("click:" + chart); + Debug.Log("click:" + chart); } void OnScroll(PointerEventData eventData, BaseGraph chart) { - //Debug.LogError("scroll:" + chart); + Debug.Log("scroll:" + chart); + } + + void OnSerieClick(SerieEventData data) + { + Debug.Log("OnSerieClick: " + data.serieIndex + " " + data.dataIndex + " " + data.dimension); + } + + void OnSerieEnter(SerieEventData data) + { + Debug.Log("OnSerieEnter: " + data.serieIndex + " " + data.dataIndex + " " + data.dimension); + } + + void OnSerieExit(SerieEventData data) + { + Debug.Log("OnSerieExit: " + data.serieIndex + " " + data.dataIndex + " " + data.dimension); + } + + void OnDraw(VertexHelper vh) + { + //Debug.Log("OnDraw"); + } + + void OnDrawBeforeSerie(VertexHelper vh, Serie serie) + { + //Debug.Log("OnDrawBeforeSerie: " + serie.index); + } + + void OnDrawAfterSerie(VertexHelper vh, Serie serie) + { + //Debug.Log("OnDrawAfterSerie: " + serie.index); + if (serie.index != 0) return; + var dataPoints = serie.context.dataPoints; + if (dataPoints.Count > 0) + { + var pos = dataPoints[3]; + var grid = chart.GetChartComponent<GridCoord>(); + var zeroPos = new Vector3(grid.context.x, grid.context.y); + var startPos = new Vector3(pos.x, zeroPos.y); + var endPos = new Vector3(pos.x, zeroPos.y + grid.context.height); + UGL.DrawLine(vh, startPos, endPos, chart.theme.serie.lineWidth, Color.blue); + UGL.DrawCricle(vh, pos, 5, Color.blue); + } + } + + void OnDrawTop(VertexHelper vh) + { + //Debug.Log("OnDrawTop"); } } } \ No newline at end of file diff --git a/Examples/Example03_ChartAnimation.cs b/Examples/Example03_ChartAnimation.cs index 736ff80e..f02e478b 100644 --- a/Examples/Example03_ChartAnimation.cs +++ b/Examples/Example03_ChartAnimation.cs @@ -19,9 +19,9 @@ namespace XCharts.Example var serie = chart.GetSerie(0); serie.animation.enable = true; //自定义每个数据项的渐入延时 - serie.animation.fadeInDelayFunction = CustomFadeInDelay; + serie.animation.fadeIn.delayFunction = CustomFadeInDelay; //自定义每个数据项的渐入时长 - serie.animation.fadeInDurationFunction = CustomFadeInDuration; + serie.animation.fadeIn.durationFunction = CustomFadeInDuration; } float CustomFadeInDelay(int dataIndex) diff --git a/Examples/Example_DynamicChart.cs b/Examples/Example05_DynamicChart.cs similarity index 96% rename from Examples/Example_DynamicChart.cs rename to Examples/Example05_DynamicChart.cs index 24b9f26a..5818517c 100644 --- a/Examples/Example_DynamicChart.cs +++ b/Examples/Example05_DynamicChart.cs @@ -6,7 +6,7 @@ using Input = XCharts.Runtime.InputHelper; namespace XCharts.Example { [DisallowMultipleComponent] - public class Example_DynamicChart : MonoBehaviour + public class Example05_DynamicChart : MonoBehaviour { BaseChart chart; @@ -14,7 +14,7 @@ namespace XCharts.Example void Update() { - if (Input.GetKeyDown(KeyCode.Space)) + if (Input.GetKeyDown(KeyCode.P)) { AddPieChart("Dynamic PieChart"); } diff --git a/Examples/Example05_DynamicChart.cs.meta b/Examples/Example05_DynamicChart.cs.meta new file mode 100644 index 00000000..f60ff2e6 --- /dev/null +++ b/Examples/Example05_DynamicChart.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3dbcd4fb120c4508b7bba52b41fbdb9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Examples/Example30_PieChart.cs b/Examples/Example30_PieChart.cs index a92d19b7..4d90c9c8 100644 --- a/Examples/Example30_PieChart.cs +++ b/Examples/Example30_PieChart.cs @@ -53,7 +53,7 @@ namespace XCharts.Example legend.orient = Orient.Vertical; chart.RemoveData(); - serie = chart.AddSerie<Bar>("访问来源"); + serie = chart.AddSerie<Pie>("访问来源"); serie.radius[0] = 0; serie.radius[1] = 110; serie.center[0] = 0.5f; diff --git a/Examples/Example_AddChart.cs b/Examples/Example_AddChart.cs deleted file mode 100644 index 143e03c7..00000000 --- a/Examples/Example_AddChart.cs +++ /dev/null @@ -1,69 +0,0 @@ -using UnityEngine; -using XCharts.Runtime; -#if INPUT_SYSTEM_ENABLED -using Input = XCharts.Runtime.InputHelper; -#endif - -namespace XCharts.Example -{ - [DisallowMultipleComponent] - //[ExecuteInEditMode] - public class Example_AddChart : MonoBehaviour - { - BaseChart chart; - void Awake() - { - //AddChart(); - } - - void Update() - { - if (Input.GetKeyDown(KeyCode.Space)) - { - AddChart(); - } - } - - void AddChart() - { - chart = gameObject.GetComponent<BaseChart>(); - if (chart == null) - { - chart = gameObject.AddComponent<LineChart>(); - chart.Init(); - chart.SetSize(1200, 600); - } - var title = chart.EnsureChartComponent<Title>(); - title.text = "Simple LineChart"; - title.subText = "normal line"; - - var tooltip = chart.EnsureChartComponent<Tooltip>(); - tooltip.show = true; - - var legend = chart.EnsureChartComponent<Legend>(); - legend.show = false; - - var xAxis = chart.EnsureChartComponent<XAxis>(); - xAxis.splitNumber = 10; - xAxis.boundaryGap = true; - xAxis.type = Axis.AxisType.Category; - - var yAxis = chart.EnsureChartComponent<YAxis>(); - yAxis.type = Axis.AxisType.Value; - - chart.RemoveData(); - chart.AddSerie<Line>("line"); - - for (int i = 0; i < 5; i++) - { - chart.AddXAxisData("x" + i); - chart.AddData(0, Random.Range(10, 20)); - } - } - - void ModifyComponent() - { - - } - } -} \ No newline at end of file diff --git a/Examples/Example_Component.cs b/Examples/Example_Component.cs deleted file mode 100644 index d6a68a03..00000000 --- a/Examples/Example_Component.cs +++ /dev/null @@ -1,35 +0,0 @@ -using UnityEngine; -using XCharts.Runtime; - -namespace XCharts.Example -{ - [DisallowMultipleComponent] - //[ExecuteInEditMode] - public class Example_Component : MonoBehaviour - { - BaseChart chart; - void Awake() - { - chart = gameObject.GetComponent<BaseChart>(); - } - - void ModifyComponent() - { - var title = chart.EnsureChartComponent<Title>(); - title.text = "Simple LineChart"; - title.subText = "normal line"; - - var serie1 = chart.AddSerie<Line>(); - //var serie2 = chart.GetSerie<Line>(); - - serie1.EnsureComponent<AreaStyle>(); - var label = serie1.EnsureComponent<LabelStyle>(); - label.offset = new Vector3(0, 20, 0); - - var serieData = chart.AddData(0, 20); - serieData.radius = 10; - var itemStyle = serieData.EnsureComponent<ItemStyle>(); - itemStyle.color = Color.blue; - } - } -} \ No newline at end of file diff --git a/Examples/Example_Dynamic.cs b/Examples/Example_Dynamic.cs deleted file mode 100644 index 260f490b..00000000 --- a/Examples/Example_Dynamic.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using UnityEngine; -using XCharts.Runtime; - -namespace XCharts.Example -{ - [DisallowMultipleComponent] - //[ExecuteInEditMode] - [RequireComponent(typeof(BaseChart))] - public class Example_Dynamic : MonoBehaviour - { - public int maxCacheDataNumber = 100; - public float initDataTime = 2; - public bool insertDataToHead = false; - - private BaseChart chart; - private float updateTime; - private float initTime; - private int initCount; - private int count; - private bool isInited; - private DateTime timeNow; - - void Awake() - { - chart = gameObject.GetComponent<BaseChart>(); - var serie = chart.GetSerie(0); - serie.symbol.show = false; - serie.maxCache = maxCacheDataNumber; - - var xAxis = chart.EnsureChartComponent<XAxis>(); - xAxis.maxCache = maxCacheDataNumber; - timeNow = DateTime.Now; - timeNow = timeNow.AddSeconds(-maxCacheDataNumber); - - serie.insertDataToHead = insertDataToHead; - xAxis.insertDataToHead = insertDataToHead; - } - - void Update() - { - if (initCount < maxCacheDataNumber) - { - int count = (int) (maxCacheDataNumber / initDataTime * Time.deltaTime); - for (int i = 0; i < count; i++) - { - timeNow = timeNow.AddSeconds(1); - var category = timeNow.ToString("hh:mm:ss"); - var value = UnityEngine.Random.Range(60, 150); - chart.AddXAxisData(category); - chart.AddData(0, value); - initCount++; - if (initCount > maxCacheDataNumber) break; - } - chart.RefreshChart(); - } - updateTime += Time.deltaTime; - if (updateTime >= 1) - { - var category = DateTime.Now.ToString("hh:mm:ss"); - var value = UnityEngine.Random.Range(60, 150); - updateTime = 0; - count++; - chart.AddXAxisData(category); - chart.AddData(0, value); - chart.RefreshChart(); - } - } - } -} \ No newline at end of file diff --git a/Examples/Example_Dynamic.cs.meta b/Examples/Example_Dynamic.cs.meta deleted file mode 100644 index 4dd42ea7..00000000 --- a/Examples/Example_Dynamic.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 310037ac5daa645058285cf176cc9eab -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Examples/Example_DynamicChart.cs.meta b/Examples/Example_DynamicChart.cs.meta deleted file mode 100644 index de3ec96a..00000000 --- a/Examples/Example_DynamicChart.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 37d46ee8250bd4bdf84966a435e543dd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Examples/Example_LargeData.cs b/Examples/Example_LargeData.cs deleted file mode 100644 index 6165c141..00000000 --- a/Examples/Example_LargeData.cs +++ /dev/null @@ -1,52 +0,0 @@ -using UnityEngine; -using XCharts.Runtime; - -namespace XCharts.Example -{ - [DisallowMultipleComponent] - [ExecuteInEditMode] - [RequireComponent(typeof(BaseChart))] - public class Example_LargeData : MonoBehaviour - { - public int maxCacheDataNumber = 1000; - public float initDataTime = 5; - - private BaseChart chart; - private float initTime; - private int initCount = 0; - private System.DateTime timeNow; - - void Awake() - { - chart = gameObject.GetComponentInChildren<BaseChart>(); - timeNow = System.DateTime.Now; - chart.ClearData(); - chart.SetMaxCache(maxCacheDataNumber); - chart.GetChartComponent<Title>().text = maxCacheDataNumber + "数据"; - } - - private double lastValue = 0d; - - private void Update() - { - if (initCount < maxCacheDataNumber) - { - for (int i = 0; i < 20; i++) - { - initCount++; - if (initCount > maxCacheDataNumber) break; - chart.GetChartComponent<Title>().text = initCount + "数据"; - - timeNow = timeNow.AddSeconds(1); - if (lastValue < 20) - lastValue += UnityEngine.Random.Range(0, 5); - else - lastValue += UnityEngine.Random.Range(-5f, 5f); - chart.AddData(0, lastValue); - - chart.AddXAxisData(timeNow.ToString("hh:mm:ss")); - } - } - } - } -} \ No newline at end of file diff --git a/Examples/Example_LargeData.cs.meta b/Examples/Example_LargeData.cs.meta deleted file mode 100644 index f832dd3c..00000000 --- a/Examples/Example_LargeData.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 188d38c155a804c7d9d31730d3b12885 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Examples/Example_PieChart.cs b/Examples/Example_PieChart.cs deleted file mode 100644 index 173b55cc..00000000 --- a/Examples/Example_PieChart.cs +++ /dev/null @@ -1,40 +0,0 @@ -using UnityEngine; -using XCharts.Runtime; - -namespace XCharts.Example -{ - [DisallowMultipleComponent] - [ExecuteInEditMode] - [RequireComponent(typeof(PieChart))] - public class Example_PieChart : MonoBehaviour - { - private PieChart chart; - private float time; - private int count = 0; - - private void Awake() - { - chart = transform.GetComponent<PieChart>(); - chart.ClearData(); - } - - private void Update() - { - time += Time.deltaTime; - if (time > 1) - { - time = 0; - if (count < 5) - { - chart.AddData(0, Random.Range(10, 100), "time" + count); - } - else - { - int index = count % 5; - chart.UpdateData(0, Random.Range(10, 100), index); - } - count++; - } - } - } -} \ No newline at end of file diff --git a/Examples/Example_PieChart.cs.meta b/Examples/Example_PieChart.cs.meta deleted file mode 100644 index 925d44ce..00000000 --- a/Examples/Example_PieChart.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a36ce96ed11a24212aafad603286a3ad -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Examples/Example_Test.cs b/Examples/Example_Test.cs index b70b7c5c..0a7e69e1 100644 --- a/Examples/Example_Test.cs +++ b/Examples/Example_Test.cs @@ -1,10 +1,9 @@ using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; -using XCharts.Runtime; #if INPUT_SYSTEM_ENABLED using Input = XCharts.Runtime.InputHelper; #endif +using XCharts.Runtime; + namespace XCharts.Example { [DisallowMultipleComponent] @@ -12,32 +11,10 @@ namespace XCharts.Example public class Example_Test : MonoBehaviour { BaseChart chart; + void Awake() { chart = gameObject.GetComponent<BaseChart>(); - chart.onSerieClick = OnPointerClickLine; - chart.onSerieEnter = OnPointerEnterLine; - chart.onSerieExit = OnPointerExitLine; - var btnTrans = transform.parent.Find("Button"); - if (btnTrans) - { - btnTrans.gameObject.GetComponent<Button>().onClick.AddListener(OnTestBtn); - } - } - - void OnPointerClickLine(SerieEventData data) - { - Debug.Log("OnPointerClick: " + data.serieIndex+ " " + data.dataIndex +" "+ data.dimension); - } - - void OnPointerEnterLine(SerieEventData data) - { - Debug.Log("OnPointerEnter: " + data.serieIndex + " " + data.dataIndex + " " + data.dimension); - } - - void OnPointerExitLine(SerieEventData data) - { - Debug.Log("OnPointerExit: " + data.serieIndex + " " + data.dataIndex + " " + data.dimension); } void Update() @@ -45,37 +22,18 @@ namespace XCharts.Example if (Input.GetKeyDown(KeyCode.Space)) { AddData(); - //OnTestBtn(); } - } - - void OnTestBtn() - { - object[][] m_TestData = new object[][] + else if(Input.GetKeyDown(KeyCode.R)) { - new object[] { "01/06/20", 2.2d, 5.6d }, - new object[] { "22/06/20", 2.4d, 5.3d }, - new object[] { "04/08/21", 4.5d, 5.4d }, - new object[] { "05/08/21", 6.3d, 6.4d }, - new object[] { "06/08/21", 3.1d, 6.4d }, - new object[] { "09/08/21", 3.9d, 6.3d }, - new object[] { "10/08/21", 1.9d, 4.6d }, - }; - chart.ClearData(); - foreach (var list in m_TestData) - { - chart.AddXAxisData((string) list[0]); - chart.AddData(0, (double) list[1]); - chart.AddData(1, (double) list[2]); + chart.AnimationReset(); + chart.AnimationFadeIn(); } } void AddData() { - var serie = chart.InsertSerie<Bar>(0); - for(int i=0;i<5;i++){ - chart.AddData(serie.index, Random.Range(10,90)); - } + chart.AnimationReset(); + chart.AnimationFadeOut(); } } } \ No newline at end of file diff --git a/Examples/Example_TestTime.cs b/Examples/Example_TestTime.cs deleted file mode 100644 index 1ed2804b..00000000 --- a/Examples/Example_TestTime.cs +++ /dev/null @@ -1,52 +0,0 @@ -using UnityEngine; -using XCharts.Runtime; -#if INPUT_SYSTEM_ENABLED -using Input = XCharts.Runtime.InputHelper; -#endif -namespace XCharts.Example -{ - [DisallowMultipleComponent] - [ExecuteInEditMode] - public class Example_TestTime : MonoBehaviour - { - public int maxCache = 100; - LineChart chart; - int timestamp; - void Awake() - { - chart = gameObject.GetComponent<LineChart>(); - AddData(); - chart.SetMaxCache(maxCache); - } - - float m_LastTime = 0; - double m_Value = 100; - void Update() - { - if (Input.GetKeyDown(KeyCode.Space)) - { - //AddData(); - } - if (Time.time - m_LastTime > 0.1f) - { - timestamp += 3600; - m_Value += 10; - chart.AddData(0, timestamp, m_Value); - m_LastTime = Time.time; - - } - } - - void AddData() - { - chart.ClearData(); - timestamp = DateTimeUtil.GetTimestamp() - 10; - for (int i = 0; i < 10; i++) - { - timestamp += i * 3600; - double value = Random.Range(50, 200); - chart.AddData(0, timestamp, value); - } - } - } -} \ No newline at end of file diff --git a/Examples/Example_TestTime.cs.meta b/Examples/Example_TestTime.cs.meta deleted file mode 100644 index 98f3d2d1..00000000 --- a/Examples/Example_TestTime.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 43b48222f7ffc420098593a8fe4bfc24 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/README-en.md b/README-en.md index 3438bdd1..3c0f8a23 100644 --- a/README-en.md +++ b/README-en.md @@ -9,8 +9,7 @@ <br> Unity数据可视化图表插件。 <br> - <a href="https://github.com/XCharts-Team/XCharts">中文</a> - <a href="https://github.com/XCharts-Team/XCharts">中文</a> + <a href="https://github.com/XCharts-Team/XCharts">中文文档</a> </p> <p align="center"> <a href="https://github.com/XCharts-Team/XCharts/blob/master/LICENSE"> @@ -44,7 +43,7 @@ </a> </p> -A powerful, easy-to-use, configurable charting and data visualization library for Unity. Supporting line, bar, pie, radar, scatter, heatmap, ring, candlestick, polar, liquid and other common chart. Also support 3d pie, 3d bar, 3d pyramid, funnel, gauge, liquid, pictorialbar, gantt, treemap and ther extended chart. +A powerful and easy-to-use data visualization library for Unity. It supports more than ten built-in charts, including line, bar, pie, radar, scatter, heatmap, ring, candlestick, polar, parallel coordinates, as well as extended charts such as 3d pie, 3d bar, 3d pyramid, funnel, gauge, liquid, pictorialbar, gantt, and treemap. [XCharts3.0 Homepage](https://xcharts-team.github.io) @@ -57,52 +56,25 @@ A powerful, easy-to-use, configurable charting and data visualization library fo ## Features -* Rich built-in examples and templates, parameter visualization configuration, effect real-time preview, pure code drawing. -* Support line, bar, pie, radar, scatter, heatmaps, gauge, ring, polar, liquid and other common chart. -* Support line graph, curve graph, area graph, step graph and other LineChart. -* Support parallel bar, stack bar, stack percentage bar, zebra bar and other BarChart. -* Support ring, rose and other PieChart. -* Support line-bar chart, scatter-line chart and other combination chart. -* Support solid line, curve, ladder line, dotted line, dash line, dot line, double dot line and other lines. -* Support custom theme, built-in theme switching. -* Support custom chart content drawing, drawing points, line, curve, triangle, quadrilateral, circle, ring, sector, border, arrow and other drawing API. -* Support interactive operations such as data filtering, view zooming and detail display on PC and mobile terminals. -* Support 10,000-level big data rendering. -* Support TextMeshPro. - -## XCharts3.0 new feature - -* Added `Time` axis. -* Added `SingleAxis`. -* Added multiple coordinate systems: `Grid`, `Polar`, `Radar`, `SingleAxis`. -* Added multiple animation methods. -* Added multiple chart interactions. -* Added internationalization support. -* Added `Widgets`. -* Added multiple extension charts. - -## XCharts3.0 improvements over XCharts2.0 - -* More robust underlying framework. -* More powerful performance. -* Smaller serialized files. -* Better interactive experience. -* More component support. -* More powerful ability to self-report text. -* More reasonable component adjustments. -* More flexible component insertion and removal. -* More efficient secondary development. -* Richer Demo examples. - -## XCharts3.0 and 2.0 data comparison - -| Case | XCharts2.0 | XCharts3.0 | Note | -| -- | -- | -- | -- | -| Fps of 2000 data line chart | ` 20 ` | ` 83 ` | Performance improvements `3` times | -| Vertices of 2000 data line chart | ` 36.5 k ` | ` 6.7 k ` | Vertices reduce `4` times | -| Prefab size of 2000 data line chart | ` 11.1 MB ` | ` 802 KB ` | Serialized file size to reduce `10` times | -| Max data of a single line chart | ` 4.1 k ` | ` 19 k ` | Single Serie data capacity improvement `4` times | -| Num of chart support | ` 11 ` | ` 23 ` | More than `1` times as many chart are supported | +* __Pure code rendering__: The chart is completely rendered with pure code, without the need for additional texture or shader resources. +* __Visual configuration__: Visual configuration of parameters with real-time preview of the effect, and support for dynamic modification of configuration and data during runtime. +* __High customizability__: Supports arbitrary adjustments from theme and configuration parameters; supports custom drawing, callback functions, and custom implementations of charts. +* __Multiple built-in charts__: Supports various built-in charts such as line charts, bar charts, pie charts, radar charts, scatter plots, heat maps, polar charts, K-line charts, parallel coordinates, etc. +* __Multiple extended charts__: Supports extended charts such as 3D column charts, 3D pie charts, funnel charts, pyramids, dashboards, water level charts, iconic bar charts, Gantt charts, and tree maps. +* __Multiple extended features__: Supports extended UI components such as tables and statistical values. +* __Multiple chart combinations__: Supports arbitrary combinations of built-in charts, with multiple same or different types of charts displayed simultaneously in the same chart. +* __Various coordinate systems__: Supports coordinate systems such as Cartesian coordinates, polar coordinates, and single axes. +* __Rich components__: Supports common components such as titles, legends, tooltips, markings, marking areas, data area zooming, and visual mapping. +* __Rich line charts__: Supports various line charts such as straight line charts, curved line charts, dashed line charts, area charts, step line charts, etc. +* __Rich bar charts__: Supports various bar charts such as stacked bar charts, stacked percentage bar charts, zebra bar charts, and capsule bar charts. +* __Rich pie charts__: Supports various pie charts such as ring charts, rose charts, ring rose charts, etc. +* __Rich lines__: Supports various lines such as solid lines, curves, step lines, dashed lines, dot lines, dotted lines, and double dot-dashed lines. +* __Custom drawing__: Supports custom chart content drawing with powerful drawing APIs for drawing points, lines, and other graphics. +* __Large data rendering__: Supports rendering of tens of thousands of data points; supports sampling rendering; special simplified charts support better performance. +* __Custom themes__: Supports theme customization and import/export; includes both light and dark default themes. +* __Animations and interactions__: Supports various animations such as fade-in animation, fade-out animation, change animation, addition animation, and * interactive animation; supports interactive operations such as data filtering, view zooming, and detailed display on multiple platforms. +* __Third-party extensions__: Supports integration with TexMeshPro and New Input System. +* __Version and compatibility__: Supports all Unity versions above 5.6 and runs on all platforms. ## Screenshots @@ -110,34 +82,54 @@ A powerful, easy-to-use, configurable charting and data visualization library fo ![extendchart](Documentation~/en/img/readme_extendchart.png) -For more examples, see [XCharts-Demo](https://github.com/XCharts-Team/XCharts-Demo), You can also go to [Online Demo](https://xcharts-team.github.io/examples/) to see the running effect of `WebGL`. +## Attention + +* `XCharts3.0` is not fully compatible with `XCharts2.0` version, upgrading `3.0` may require some code adjustments, and some chart configurations need to be readjusting. It is recommended that old projects can continue to use `XCharts2.0`, and new projects are recommended to use `XCharts3.0`. +* `XCharts2.0` enters the maintenance phase, and only serious `bugs` will be fixed later, in principle, no more new features will be added. +* `XCharts` theoretically supports `Unity 5.6` and above, but due to limited version testing, it is inevitable to slip up, and version compatibility issues can be raised. +* This repository only contains `XCharts` source code, does not contain `Demo` sample section. Need to look at ` Demo ` please go to the sample source code [XCharts - Demo](https://github.com/XCharts-Team/XCharts-Demo) repo. You can also view the running effect of `WebGL` in your browser [Online Demo](https://xcharts-team.github.io/examples/). ## Use -1. Import `XCharts` unitypackage or source code into the project. -2. Right-click `Hierarchy` view and choose `XCharts->LineChart` to create a default LineChart. -3. You can adjust the parameters of each component in `Inspector` and see the real-time effects in `Game` view. +* Import `XCharts` unitypackage or source code into the project. +* Right-click `Hierarchy` view and choose `XCharts->LineChart` to create a default LineChart. +* You can adjust the parameters of each component in `Inspector` and see the real-time effects in `Game` view. +* For more details, see [[XCharts Tutorial: 5-minute tutorial]](Documentation~/zh/tutorial01.md) +* For the first time, it is recommended to read the tutorial carefully. -See more tutorial: [XCharts tutorial: 5 minutes overhand tutorial](Documentation~/en/tutorial01.md) +## Branch + +* `master` : indicates the development branch. The latest changes and new features are first committed to the `master` branch, and after some time from the `master` branch `merge` to the `3.0` branch, and the `release` version. +* `3.0` : Stable branch of XCharts 3.0. It is generally updated once a month, with the latest changes from the `master` branch `merge`, and the `release` version is released. +* `2.0` : A stable branch of XCharts 2.0. With Demo, currently no longer maintenance, only to modify serious bugs. +* `2.0-upm` : Stable UMP branch of XCharts 2.0. Only the Package part is included without Demo. It is dedicated to the UMP and is not maintained. +* `1.0` : Stable branch of XCharts 1.0. With Demo, no maintenance. +* `1.0-upm` : stable UMP branch of XCharts 1.0. No Demo, no maintenance. ## FAQ -1. Is `XCharts` free to use? +* Is `XCharts` free to use? A: `XCharts` uses the `MIT` licence and is free to use. You can also subscribe to `VIP` to enjoy more value-added services. -2. Does `XCharts` support code to dynamically add and modify data? Does it support getting data from `Excel` or a database? +* Does `XCharts` support code to dynamically add and modify data? Does it support getting data from `Excel` or a database? A: Support code to dynamically add and modify data, but data needs to be parsed or retrieved by itself, and then added to `XCharts` by calling the public interface of `XCharts`. -3. Does this plugin work on other platforms (e.g. Winform or WPF) besides Unity? +* Does this plugin work on other platforms (e.g. Winform or WPF) besides Unity? A: It is currently only supported on Unity. Theoretically any version of Unity that supports `UGUI` can run `XCharts`. +* What about the jags? What magnitude of data is supported? +A: XCharts is based on UGUI implementation, so the problems encountered in UGUI will also exist in XCharts. For example, the sawtooth problem, such as the number of vertices in `Mesh` exceeds `65535`. Solutions to these two problems can be found in [Q&A 16](Documentation~/zh/faq.md) and [Q&A 27](Documentation~/zh/faq.md). +Due to the `Mesh` of the `65535` vertex limit, the current `XCharts` single `Line` supports about `20,000` of data, of course, open sampling can support more data to draw, but at the same time it will consume more CPU. + ## Changelog -[Changelog](Documentation~/en/changelog.md) +* [Changelog](Documentation~/en/changelog.md) ## Licenses -[MIT License](https://github.com/XCharts-Team/XCharts/blob/master/LICENSE.md) +* [MIT License](https://github.com/XCharts-Team/XCharts/blob/master/LICENSE.md) +* Free commercial, secondary development +* The extended charts and advanced features sections require a separate purchase license ## Other diff --git a/README.md b/README.md index 15f9b36e..19a276ad 100644 --- a/README.md +++ b/README.md @@ -45,33 +45,37 @@ 一款基于`UGUI`的功能强大、简单易用的数据可视化图表插件。支持`折线图`、`柱状图`、`饼图`、`雷达图`、`散点图`、`热力图`、`环形图`、`K线图`、`极坐标`、`平行坐标`等十多种内置图表,以及`3D饼图`、`3D柱图`、`3D金字塔`、`漏斗图`、`仪表盘`、`水位图`、`象形柱图`、`甘特图`、`矩形树图`等扩展图表。 -[XCharts3.0 官方主页](https://xcharts-team.github.io) -[XCharts3.0 在线示例](https://xcharts-team.github.io/examples) +[XCharts 官方主页](https://xcharts-team.github.io) +[XCharts 在线示例](https://xcharts-team.github.io/examples) -[XCharts3.0 教程:5分钟上手 XCharts](Documentation~/zh/tutorial01.md) -[XCharts3.0 API](Documentation~/zh/api.md) -[XCharts3.0 问答](Documentation~/zh/faq.md) -[XCharts3.0 配置项手册](Documentation~/zh/configuration.md) -[XCharts3.0 更新日志](Documentation~/zh/changelog.md) -[XCharts3.0 订阅服务](Documentation~/zh/support.md) +[XCharts 教程:5分钟上手 XCharts](Documentation~/zh/tutorial01.md) +[XCharts API文档](Documentation~/zh/api.md) +[XCharts 问答](Documentation~/zh/faq.md) +[XCharts 配置项手册](Documentation~/zh/configuration.md) +[XCharts 更新日志](Documentation~/zh/changelog.md) +[XCharts 订阅服务](Documentation~/zh/support.md) ## 特性 -- 参数可视化配置,效果实时预览,纯代码绘制,无需额外资源。 -- 支持折线图、柱状图、饼图、雷达图、散点图、热力图、环形图、K线图、极坐标、平行坐标等十种内置图表。 -- 支持3D柱图、漏斗图、金字塔、仪表盘、水位图、象形柱图、甘特图、矩形树图等多种扩展图表。 -- 支持直线图、曲线图、面积图、阶梯线图等折线图。 -- 支持并列柱图、堆叠柱图、堆积百分比柱图、斑马柱图等柱状图。 -- 支持环形图、玫瑰图等饼图。 -- 支持内置图表的任意组合,同一图中可同时显示多个相同或不同类型的图表。 -- 支持实线、曲线、阶梯线、虚线、点线、点划线、双点划线等线条。 -- 支持主题定制、导入和导出,内置明暗两种默认主题。 -- 支持自定义图表内容绘制,提供绘制点、线、面等其他图形的强大的绘图API。 -- 支持PC端和手机端上的数据筛选、视图缩放、细节展示等交互操作。 -- 支持万级大数据量绘制,支持采样绘制。 -- 支持`TexMeshPro`。 -- 支持所有`5.6`以上的`Unity`版本。 -- 支持 Input System ([如何从 Input Manager 转 Input System](https://xcharts-team.github.io/docs/inputsystem))。 +- __纯代码绘制__:图表完全纯代码绘制,无需额外的贴图和Shader资源。 +- __可视化配置__:参数可视化配置,效果实时预览,也支持运行时代码动态修改配置和数据。 +- __高自由定制__:支持从主题和配置参数上任意调整;支持代码自定义绘制,自定义回调以及自定义实现图表。 +- __多内置图表__:支持线图、状图、饼图、雷达图、散点图、热力图、环形图、K线图、极坐标、平行坐标等多种内置图表。 +- __多扩展图表__:支持3D柱图、3D饼图、漏斗图、金字塔、仪表盘、水位图、象形柱图、甘特图、矩形树图等多种扩展图表。 +- __多扩展功能__:支持表格、统计数值等扩展UI组件。 +- __多图表组合__:支持内置图表的任意组合,同一图中可同时显示多个相同或不同类型的图表。 +- __多种坐标系__:支持直角坐标系、极坐标系、单轴等多种坐标系。 +- __丰富的组件__:支持标题、图例、提示框、标线、标域、数据区域缩放、视觉映射等常用组件。 +- __丰富的线图__:支持直线图、曲线图、虚线图、面积图、阶梯线图等多种线图。 +- __丰富的柱图__:支持并列柱图、堆叠柱图、堆积百分比柱图、斑马柱图、胶囊柱图等多种柱状图。 +- __丰富的饼图__:支持环形图、玫瑰图、环形玫瑰图等多种饼图。 +- __丰富的线条__:支持实线、曲线、阶梯线、虚线、点线、点划线、双点划线等线条。 +- __自定义绘制__:支持自定义图表内容绘制,提供绘制点、线、面等其他图形的强大的绘图API。 +- __大数据绘制__:支持万级大数据量绘制;支持采样绘制;特殊的简化图表支持更优的性能。 +- __自定义主题__:支持主题定制、导入和导出,内置明暗两种默认主题。 +- __动画和交互__:支持渐入动画、渐出动画、变更动画、新增动画、交互动画等多种动画;支持多平台的数据筛选、视图缩放、细节展示等交互操作。 +- __第三方扩展__:支持接入`TexMeshPro`和`New Input System`。 +- __版本和兼容__:支持所有`5.6`以上的`Unity`版本;支持全平台运行。 ## 截图 @@ -79,8 +83,6 @@ ![扩展图表](Documentation~/zh/img/readme_extendchart.png) -![XCharts 3.0和2.0的对比](Documentation~/zh/img/readme_xcharts3.png) - ## 注意 - `XCharts3.0` 不完全兼容 `XCharts2.0` 版本,升级`3.0`可能需要调整部分代码,图表部分配置需要重新调整。建议旧项目可以继续使用`XCharts2.0`,新项目推荐使用`XCharts3.0`。 @@ -90,11 +92,10 @@ ## 使用 -1. 导入`XCharts`的`unitypackage`或者源码到项目。 -2. 在`Hierarchy`视图下右键选择`XCharts->LineChart`,即可创建一个默认的折线图。 -3. 在`Inspector`视图可以调整各个组件的参数,`Game`视图可看到实时效果。 - -- 更多细节,请看:[XCharts教程:5分钟上手教程](Documentation~/zh/tutorial01.md) +- 导入`XCharts`的`unitypackage`或者源码到项目。 +- 在`Hierarchy`视图下右键选择`XCharts->LineChart`,即可创建一个默认的折线图。 +- 在`Inspector`视图可以调整各个组件的参数,`Game`视图可看到实时效果。 +- 更多细节,请看[【XCharts教程:5分钟上手教程】](Documentation~/zh/tutorial01.md) - 首次使用,建议先认真看一遍教程。 ## 分支 @@ -106,23 +107,18 @@ - `1.0`:XCharts 1.0的稳定分支。带Demo,不再维护。 - `1.0-upm`:XCharts 1.0的稳定UMP分支。不带Demo,不再维护。 -## 扩展 - -- [扩展图表](https://xcharts-team.github.io/docs/extra) 扩展图表订阅`VIP`后再按需购买,订阅详情请查看[☞ 看这里](Documentation~/zh/support.md) -- [扩展组件](https://xcharts-team.github.io/docs/ui) 扩展组件订阅`VIP`后即可免费使用。 - ## FAQ -1. `XCharts`可以免费使用吗? +- `XCharts`可以免费使用吗? 答:`XCharts`使用`MIT`协议,可以免费使用。也可以订阅`VIP`享受更多增值服务。 -2. `XCharts`支持代码动态添加和修改数据吗?支持从`Excel`或数据库中获取数据吗? +- `XCharts`支持代码动态添加和修改数据吗?支持从`Excel`或数据库中获取数据吗? 答:`XCharts`提供了各种数据操作的接口,支持代码动态修改配置,添加和修改数据,但数据来源需要自己解析和获取,再调用`XCharts`的接口添加到图表。 -3. 这个插件除了用在`Unity`,还能用在其他平台(如`Winform`或`WPF`)吗? - 答:目前只支持在`Unity`平台使用。理论上任何支持`UGUI`的`Unity`版本都能运行`XCharts`。 +- `XCharts`除了用在`Unity`平台,还能用在`Winform`或`WPF`等平台吗? + 答:`XCharts`只支持在`Unity`平台使用。理论上任何支持`UGUI`的`Unity`版本都能运行`XCharts`。 -4. 锯齿怎么解决?支持多大量级的数据? +- 锯齿怎么解决?支持多大量级的数据? 答:`XCharts`是基于`UGUI`实现的,所以`UGUI`中碰到的问题,在`XCharts`中也会存在。比如锯齿问题,比如`Mesh`顶点数超`65535`的问题。这两个问题的解决可参考[问答16](Documentation~/zh/faq.md)和[问答27](Documentation~/zh/faq.md)。 由于`Mesh`的`65535`顶点数的限制,目前`XCharts`的单条`Line`支持约`2万`的数据量,当然开启采样可以支持更多数据的绘制,但同时也会更消耗CPU。 @@ -130,12 +126,19 @@ - [MIT License](https://github.com/XCharts-Team/XCharts/blob/master/LICENSE.md) - 可免费商用,可二次开发 -- 扩展图表需单独购买授权 +- 扩展图表和高级功能部分需单独购买授权 ## 日志 - [更新日志](Documentation~/zh/changelog.md) +## 订阅 + +- `XCharts`核心库是开源的,可免费使用的。在此基础上,我们也提供多种订阅服务以满足不同用户的需求,订阅详情[☞ 请看这里](Documentation~/zh/support.md) +- 订阅不是必须的,不影响`XCharts`的常用功能使用。 +- 订阅是按年付费制,部分订阅服务的首年费用比次年要高,是因为包含了购买部分源码。次年的费用基本都是服务费。 +- 订阅到期后,不要求必须续订,但中断订阅期间无法享受技术支持等服务。如需继续服务,可从当日继续续订即可。 + ## 其他 - 邮箱:`monitor1394@gmail.com` diff --git a/Resources/XCSettings.asset b/Resources/XCSettings.asset index 5587633c..07e20fb5 100644 --- a/Resources/XCSettings.asset +++ b/Resources/XCSettings.asset @@ -45,8 +45,6 @@ MonoBehaviour: m_LineSegmentDistance: 3 m_CicleSmoothness: 2 m_VisualMapTriangeLen: 20 - m_PieTooltipExtraRadius: 8 - m_PieSelectedOffset: 8 m_CustomThemes: - {fileID: 11400000, guid: 289d2fc7f4ce24f73b9ed8ec52639f72, type: 2} - {fileID: 11400000, guid: e1dc23a10de1e4c5dbfbaf74c4dfd218, type: 2} diff --git a/Resources/XCTheme-Dark.asset b/Resources/XCTheme-Dark.asset index 11c2806d..63d26000 100644 --- a/Resources/XCTheme-Dark.asset +++ b/Resources/XCTheme-Dark.asset @@ -188,9 +188,6 @@ MonoBehaviour: m_LineWidth: 1.8 m_LineSymbolSize: 5 m_ScatterSymbolSize: 20 - m_PieTooltipExtraRadius: 8 - m_SelectedRate: 1.3 - m_PieSelectedOffset: 8 m_CandlestickColor: serializedVersion: 2 rgba: 4283846390 diff --git a/Resources/XCTheme-Default.asset b/Resources/XCTheme-Default.asset index e05e5787..53fae3ef 100644 --- a/Resources/XCTheme-Default.asset +++ b/Resources/XCTheme-Default.asset @@ -145,9 +145,6 @@ MonoBehaviour: m_LineWidth: 1.8 m_LineSymbolSize: 5 m_ScatterSymbolSize: 20 - m_PieTooltipExtraRadius: 8 - m_SelectedRate: 1.3 - m_PieSelectedOffset: 8 m_CandlestickColor: serializedVersion: 2 rgba: 4283716843 diff --git a/Runtime/Chart/BarChart.cs b/Runtime/Chart/BarChart.cs index 77a6aa67..f27f9964 100644 --- a/Runtime/Chart/BarChart.cs +++ b/Runtime/Chart/BarChart.cs @@ -11,13 +11,9 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<GridCoord>(); - AddChartComponentWhenNoExist<XAxis>(); - AddChartComponentWhenNoExist<YAxis>(); - - var tooltip = EnsureChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.Shadow; - tooltip.trigger = Tooltip.Trigger.Axis; + EnsureChartComponent<GridCoord>(); + EnsureChartComponent<XAxis>(); + EnsureChartComponent<YAxis>(); RemoveData(); Bar.AddDefaultSerie(this, GenerateDefaultSerieName()); diff --git a/Runtime/Chart/CandlestickChart.cs b/Runtime/Chart/CandlestickChart.cs index 34672fc8..d136b28d 100644 --- a/Runtime/Chart/CandlestickChart.cs +++ b/Runtime/Chart/CandlestickChart.cs @@ -11,13 +11,9 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<GridCoord>(); - AddChartComponentWhenNoExist<XAxis>(); - AddChartComponentWhenNoExist<YAxis>(); - - var tooltip = EnsureChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.Shadow; - tooltip.trigger = Tooltip.Trigger.Axis; + EnsureChartComponent<GridCoord>(); + EnsureChartComponent<XAxis>(); + EnsureChartComponent<YAxis>(); RemoveData(); var serie = Candlestick.AddDefaultSerie(this, GenerateDefaultSerieName()); diff --git a/Runtime/Chart/HeatmapChart.cs b/Runtime/Chart/HeatmapChart.cs index d7e4533e..5f4e39fe 100644 --- a/Runtime/Chart/HeatmapChart.cs +++ b/Runtime/Chart/HeatmapChart.cs @@ -12,10 +12,6 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - var tooltip = GetChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.None; - tooltip.trigger = Tooltip.Trigger.Axis; - var grid = EnsureChartComponent<GridCoord>(); grid.left = 0.12f; diff --git a/Runtime/Chart/LineChart.cs b/Runtime/Chart/LineChart.cs index d1185871..e09b6e62 100644 --- a/Runtime/Chart/LineChart.cs +++ b/Runtime/Chart/LineChart.cs @@ -11,13 +11,9 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<GridCoord>(); - AddChartComponentWhenNoExist<XAxis>(); - AddChartComponentWhenNoExist<YAxis>(); - - var tooltip = EnsureChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.Line; - tooltip.trigger = Tooltip.Trigger.Axis; + EnsureChartComponent<GridCoord>(); + EnsureChartComponent<XAxis>(); + EnsureChartComponent<YAxis>(); RemoveData(); Line.AddDefaultSerie(this, GenerateDefaultSerieName()); diff --git a/Runtime/Chart/PolarChart.cs b/Runtime/Chart/PolarChart.cs index 95b268b2..82d1cd7f 100644 --- a/Runtime/Chart/PolarChart.cs +++ b/Runtime/Chart/PolarChart.cs @@ -11,11 +11,11 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<PolarCoord>(); - AddChartComponentWhenNoExist<AngleAxis>(); - AddChartComponentWhenNoExist<RadiusAxis>(); + EnsureChartComponent<PolarCoord>(); + EnsureChartComponent<AngleAxis>(); + EnsureChartComponent<RadiusAxis>(); - var tooltip = GetChartComponent<Tooltip>(); + var tooltip = EnsureChartComponent<Tooltip>(); tooltip.type = Tooltip.Type.Corss; tooltip.trigger = Tooltip.Trigger.Axis; diff --git a/Runtime/Chart/ScatterChart.cs b/Runtime/Chart/ScatterChart.cs index de04423e..1087fbda 100644 --- a/Runtime/Chart/ScatterChart.cs +++ b/Runtime/Chart/ScatterChart.cs @@ -11,11 +11,7 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<GridCoord>(); - - var tooltip = EnsureChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.None; - tooltip.trigger = Tooltip.Trigger.Item; + EnsureChartComponent<GridCoord>(); var xAxis = EnsureChartComponent<XAxis>(); xAxis.type = Axis.AxisType.Value; diff --git a/Runtime/Chart/SimplifiedBarChart.cs b/Runtime/Chart/SimplifiedBarChart.cs index 0fef9ccd..c5d676d8 100644 --- a/Runtime/Chart/SimplifiedBarChart.cs +++ b/Runtime/Chart/SimplifiedBarChart.cs @@ -11,13 +11,9 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<GridCoord>(); - AddChartComponentWhenNoExist<XAxis>(); - AddChartComponentWhenNoExist<YAxis>(); - - var tooltip = GetChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.Line; - tooltip.trigger = Tooltip.Trigger.Axis; + EnsureChartComponent<GridCoord>(); + EnsureChartComponent<XAxis>(); + EnsureChartComponent<YAxis>(); RemoveData(); SimplifiedBar.AddDefaultSerie(this, GenerateDefaultSerieName()); diff --git a/Runtime/Chart/SimplifiedCandlestickChart.cs b/Runtime/Chart/SimplifiedCandlestickChart.cs index e8d90aa1..ec11d10f 100644 --- a/Runtime/Chart/SimplifiedCandlestickChart.cs +++ b/Runtime/Chart/SimplifiedCandlestickChart.cs @@ -11,13 +11,9 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<GridCoord>(); - AddChartComponentWhenNoExist<XAxis>(); - AddChartComponentWhenNoExist<YAxis>(); - - var tooltip = GetChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.Shadow; - tooltip.trigger = Tooltip.Trigger.Axis; + EnsureChartComponent<GridCoord>(); + EnsureChartComponent<XAxis>(); + EnsureChartComponent<YAxis>(); RemoveData(); SimplifiedCandlestick.AddDefaultSerie(this, GenerateDefaultSerieName()); diff --git a/Runtime/Chart/SimplifiedLineChart.cs b/Runtime/Chart/SimplifiedLineChart.cs index bf023dc6..f6b7a76b 100644 --- a/Runtime/Chart/SimplifiedLineChart.cs +++ b/Runtime/Chart/SimplifiedLineChart.cs @@ -11,13 +11,9 @@ namespace XCharts.Runtime { protected override void DefaultChart() { - AddChartComponentWhenNoExist<GridCoord>(); - AddChartComponentWhenNoExist<XAxis>(); - AddChartComponentWhenNoExist<YAxis>(); - - var tooltip = GetChartComponent<Tooltip>(); - tooltip.type = Tooltip.Type.Line; - tooltip.trigger = Tooltip.Trigger.Axis; + EnsureChartComponent<GridCoord>(); + EnsureChartComponent<XAxis>(); + EnsureChartComponent<YAxis>(); RemoveData(); SimplifiedLine.AddDefaultSerie(this, GenerateDefaultSerieName()); diff --git a/Runtime/Component/Animation/AnimationInfo.cs b/Runtime/Component/Animation/AnimationInfo.cs new file mode 100644 index 00000000..bffabfef --- /dev/null +++ b/Runtime/Component/Animation/AnimationInfo.cs @@ -0,0 +1,480 @@ + +using System; +using UnityEngine; + +namespace XCharts.Runtime +{ + /// <summary> + /// the animation info. + /// |动画配置参数。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class AnimationInfo + { + [SerializeField][Since("v3.8.0")] private bool m_Enable = true; + [SerializeField][Since("v3.8.0")] private bool m_Reverse = false; + [SerializeField][Since("v3.8.0")] private float m_Delay = 0; + [SerializeField][Since("v3.8.0")] private float m_Duration = 1000; + public AnimationInfoContext context = new AnimationInfoContext(); + + /// <summary> + /// whether enable animation. + /// |是否开启动画效果。 + /// </summary> + public bool enable { get { return m_Enable; } set { m_Enable = value; } } + /// <summary> + /// whether enable reverse animation. + /// |是否开启反向动画效果。 + /// </summary> + public bool reverse { get { return m_Reverse; } set { m_Reverse = value; } } + /// <summary> + /// the delay time before animation start. + /// |动画开始前的延迟时间。 + /// </summary> + public float delay { get { return m_Delay; } set { m_Delay = value; } } + /// <summary> + /// the duration of animation. + /// |动画的时长。 + /// </summary> + public float duration { get { return m_Duration; } set { m_Duration = value; } } + + /// <summary> + /// the callback function of animation start. + /// |动画开始的回调。 + /// </summary> + public Action OnAnimationStart { get; set; } + /// <summary> + /// the callback function of animation end. + /// |动画结束的回调。 + /// </summary> + public Action OnAnimationEnd { get; set; } + + /// <summary> + /// the delegate function of animation delay. + /// |动画延迟的委托函数。 + /// </summary> + public AnimationDelayFunction delayFunction { get; set; } + /// <summary> + /// the delegate function of animation duration. + /// |动画时长的委托函数。 + /// </summary> + public AnimationDurationFunction durationFunction { get; set; } + + /// <summary> + /// Reset animation. + /// |重置动画。 + /// </summary> + public void Reset() + { + if (!enable) return; + context.init = false; + context.start = false; + context.pause = false; + context.end = false; + context.startTime = 0; + context.currProgress = 0; + context.destProgress = 0; + context.totalProgress = 0; + context.sizeProgress = 0; + context.currPointIndex = 0; + context.currPoint = Vector3.zero; + context.destPoint = Vector3.zero; + context.dataCurrProgress.Clear(); + context.dataDestProgress.Clear(); + } + + /// <summary> + /// Start animation. + /// |开始动画。 + /// </summary> + /// <param name="reset">是否重置上一次的参数</param> + public void Start(bool reset = true) + { + if (!enable) return; + if (context.start) + { + context.pause = false; + return; + } + context.init = false; + context.start = true; + context.end = false; + context.pause = false; + context.startTime = Time.time; + if (reset) + { + context.currProgress = 0; + context.destProgress = 1; + context.totalProgress = 0; + context.sizeProgress = 0; + context.dataCurrProgress.Clear(); + context.dataDestProgress.Clear(); + } + if (OnAnimationStart != null) + { + OnAnimationStart(); + } + } + + /// <summary> + /// Pause animation. + /// |暂停动画。 + /// </summary> + public void Pause() + { + if (!enable) return; + if (!context.start || context.end) return; + context.pause = true; + } + + /// <summary> + /// Resume animation. + /// |恢复动画。 + /// </summary> + public void Resume() + { + if (!enable) return; + if (!context.pause) return; + context.pause = false; + } + + /// <summary> + /// End animation. + /// |结束动画。 + /// </summary> + public void End() + { + if (!enable) return; + if (!context.start || context.end) return; + context.start = false; + context.end = true; + context.currPointIndex = context.destPointIndex; + context.startTime = Time.time; + if (OnAnimationEnd != null) + { + OnAnimationEnd(); + } + } + + /// <summary> + /// Initialize animation. + /// |初始化动画。 + /// </summary> + /// <param name="curr">当前进度</param> + /// <param name="dest">目标进度</param> + /// <param name="totalPointIndex">目标索引</param> + /// <returns></returns> + public bool Init(float curr, float dest, int totalPointIndex) + { + if (!enable || !context.start) return false; + if (context.init || context.end) return false; + context.init = true; + context.totalProgress = dest - curr; + context.destPointIndex = totalPointIndex; + if (reverse) + { + context.currProgress = dest; + context.destProgress = curr; + } + else + { + context.currProgress = curr; + context.destProgress = dest; + } + return true; + } + + /// <summary> + /// Whether animation is finish. + /// |动画是否结束。 + /// </summary> + public bool IsFinish() + { + if (!context.start) return true; + if (context.end) return true; + if (context.pause) return false; + if (!context.init) return false; + return m_Reverse ? context.currProgress <= context.destProgress + : context.currProgress >= context.destProgress; + } + + /// <summary> + /// Whether animation is in delay. + /// |动画是否在延迟中。 + /// </summary> + public bool IsInDelay() + { + if (!context.start) + return false; + else + return (m_Delay > 0 && Time.time - context.startTime < m_Delay / 1000); + } + + /// <summary> + /// Whether animation is in index delay. + /// |动画是否在索引延迟中。 + /// </summary> + /// <param name="dataIndex"></param> + /// <returns></returns> + public bool IsInIndexDelay(int dataIndex) + { + if (context.start) + return Time.time - context.startTime < GetIndexDelay(dataIndex) / 1000f; + else + return false; + } + + /// <summary> + /// Get animation delay. + /// |获取动画延迟。 + /// </summary> + /// <param name="dataIndex"></param> + /// <returns></returns> + public float GetIndexDelay(int dataIndex) + { + if (!context.start) return 0; + if (delayFunction != null) + return delayFunction(dataIndex); + return delay; + } + + internal float GetCurrAnimationDuration(int dataIndex = -1) + { + if (dataIndex >= 0) + { + if (context.start && durationFunction != null) + return durationFunction(dataIndex) / 1000f; + } + return m_Duration > 0 ? m_Duration / 1000 : 1f; + } + + internal void SetDataCurrProgress(int index, float state) + { + context.dataCurrProgress[index] = state; + } + + + internal float GetDataCurrProgress(int index, float initValue, float destValue, ref bool isBarEnd) + { + if (IsInDelay()) + { + isBarEnd = false; + return initValue; + } + var c1 = !context.dataCurrProgress.ContainsKey(index); + var c2 = !context.dataDestProgress.ContainsKey(index); + if (c1 || c2) + { + if (c1) + context.dataCurrProgress.Add(index, initValue); + + if (c2) + context.dataDestProgress.Add(index, destValue); + + isBarEnd = false; + } + else + { + isBarEnd = context.dataCurrProgress[index] == context.dataDestProgress[index]; + } + return context.dataCurrProgress[index]; + } + + internal void CheckProgress(double total, bool m_UnscaledTime) + { + if (!context.start || !context.init || context.pause) return; + if (IsInDelay()) return; + var duration = GetCurrAnimationDuration(); + var delta = (float)(total / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime)); + if (reverse) + { + context.currProgress -= delta; + if (context.currProgress <= context.destProgress) + { + context.currProgress = context.destProgress; + End(); + } + } + else + { + context.currProgress += delta; + if (context.currProgress >= context.destProgress) + { + context.currProgress = context.destProgress; + End(); + } + } + } + + internal float CheckItemProgress(int dataIndex, float destProgress, ref bool isEnd, float startProgress, bool m_UnscaledTime) + { + if (m_Reverse) + { + var temp = startProgress; + startProgress = destProgress; + destProgress = temp; + } + var currHig = GetDataCurrProgress(dataIndex, startProgress, destProgress, ref isEnd); + if (IsFinish()) + { + return destProgress; + } + else if (IsInDelay() || IsInIndexDelay(dataIndex)) + { + return startProgress; + } + else if (context.pause) + { + return currHig; + } + else + { + var duration = GetCurrAnimationDuration(dataIndex); + var delta = (destProgress - startProgress) / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime); + currHig += delta; + if (reverse) + { + if ((destProgress > 0 && currHig <= 0) || (destProgress < 0 && currHig >= 0)) + { + currHig = 0; + isEnd = true; + } + } + else + { + if ((destProgress - startProgress > 0 && currHig > destProgress) || + (destProgress - startProgress < 0 && currHig < destProgress)) + { + currHig = destProgress; + isEnd = true; + } + } + SetDataCurrProgress(dataIndex, currHig); + return currHig; + } + } + + internal void CheckSymbol(float dest, bool m_UnscaledTime) + { + if (!context.start || !context.init || context.pause) return; + + if (IsInDelay()) + return; + + var duration = GetCurrAnimationDuration(); + var delta = dest / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime); + if (reverse) + { + context.sizeProgress -= delta; + if (context.sizeProgress < 0) + context.sizeProgress = 0; + } + else + { + context.sizeProgress += delta; + if (context.sizeProgress > dest) + context.sizeProgress = dest; + } + } + } + + /// <summary> + /// Fade in animation. + /// |淡入动画。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class AnimationFadeIn : AnimationInfo + { + } + + /// <summary> + /// Fade out animation. + /// |淡出动画。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class AnimationFadeOut : AnimationInfo + { + } + + /// <summary> + /// Data change animation. + /// |数据变更动画。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class AnimationChange : AnimationInfo + { + } + + /// <summary> + /// Data addition animation. + /// |数据新增动画。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class AnimationAddition : AnimationInfo + { + } + + /// <summary> + /// Data hiding animation. + /// |数据隐藏动画。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class AnimationHiding : AnimationInfo + { + } + + /// <summary> + /// Interactive animation of charts. + /// |交互动画。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class AnimationInteraction : AnimationInfo + { + [SerializeField][Since("v3.8.0")] private MLValue m_Width = new MLValue(1.1f); + [SerializeField][Since("v3.8.0")] private MLValue m_Radius = new MLValue(1.1f); + [SerializeField][Since("v3.8.0")] private MLValue m_Offset = new MLValue(MLValue.Type.Absolute, 5f); + + /// <summary> + /// the mlvalue of width. + /// |宽度的多样式数值。 + /// </summary> + public MLValue width { get { return m_Width; } set { m_Width = value; } } + /// <summary> + /// the mlvalue of radius. + /// |半径的多样式数值。 + /// </summary> + public MLValue radius { get { return m_Radius; } set { m_Radius = value; } } + /// <summary> + /// the mlvalue of offset. Such as the offset of the pie chart when the sector is selected. + /// |交互的多样式数值。如饼图的扇形选中时的偏移。 + /// </summary> + public MLValue offset { get { return m_Offset; } set { m_Offset = value; } } + + public float GetRadius(float radius) + { + return m_Radius.GetValue(radius); + } + + public float GetWidth(float width) + { + return m_Width.GetValue(width); + } + + public float GetOffset(float total) + { + return m_Offset.GetValue(total); + } + + public float GetOffset() + { + return m_Offset.value; + } + } +} \ No newline at end of file diff --git a/Runtime/Component/Animation/AnimationInfo.cs.meta b/Runtime/Component/Animation/AnimationInfo.cs.meta new file mode 100644 index 00000000..ed254f07 --- /dev/null +++ b/Runtime/Component/Animation/AnimationInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae54b92d6276445ac9524b598bfb6e84 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Component/Animation/AnimationInfoContext.cs b/Runtime/Component/Animation/AnimationInfoContext.cs new file mode 100644 index 00000000..b524e63e --- /dev/null +++ b/Runtime/Component/Animation/AnimationInfoContext.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace XCharts.Runtime +{ + public sealed class AnimationInfoContext + { + public bool init; + public bool start; + public bool pause; + public bool end; + public float startTime; + public float currProgress; + public float destProgress; + public float totalProgress; + public float sizeProgress; + public int currPointIndex; + public int destPointIndex; + public Vector3 currPoint; + public Vector3 destPoint; + public Dictionary<int, float> dataCurrProgress = new Dictionary<int, float>(); + public Dictionary<int, float> dataDestProgress = new Dictionary<int, float>(); + } +} \ No newline at end of file diff --git a/Runtime/Component/Animation/AnimationInfoContext.cs.meta b/Runtime/Component/Animation/AnimationInfoContext.cs.meta new file mode 100644 index 00000000..3d6a8716 --- /dev/null +++ b/Runtime/Component/Animation/AnimationInfoContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 023c7390605c34a72b13f5db7a647f06 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Component/Animation/AnimationStyle.cs b/Runtime/Component/Animation/AnimationStyle.cs index beaabd01..efcb75f8 100644 --- a/Runtime/Component/Animation/AnimationStyle.cs +++ b/Runtime/Component/Animation/AnimationStyle.cs @@ -44,8 +44,9 @@ namespace XCharts.Runtime } /// <summary> - /// the animation of serie. - /// |动画表现。 + /// the animation of serie. support animation type: fadeIn, fadeOut, change, addition. + /// |动画组件,用于控制图表的动画播放。支持配置五种动画表现:FadeIn(渐入动画),FadeOut(渐出动画),Change(变更动画),Addition(新增动画),Interaction(交互动画)。 + /// 按作用的对象可以分为两类:SerieAnimation(系列动画)和DataAnimation(数据动画)。 /// </summary> [System.Serializable] public class AnimationStyle : ChildComponent @@ -54,30 +55,26 @@ namespace XCharts.Runtime [SerializeField] private AnimationType m_Type; [SerializeField] private AnimationEasing m_Easting; [SerializeField] private int m_Threshold = 2000; - [SerializeField] private float m_FadeInDuration = 1000; - [SerializeField] private float m_FadeInDelay = 0; - [SerializeField] private float m_FadeOutDuration = 1000f; - [SerializeField] private float m_FadeOutDelay = 0; - [SerializeField] private bool m_DataChangeEnable = true; - [SerializeField] private float m_DataChangeDuration = 500; - [SerializeField] private float m_ActualDuration; [SerializeField][Since("v3.4.0")] private bool m_UnscaledTime; - /// <summary> - /// 自定义渐入动画延时函数。返回ms值。 - /// </summary> + [SerializeField][Since("v3.8.0")] private AnimationFadeIn m_FadeIn = new AnimationFadeIn(); + [SerializeField][Since("v3.8.0")] private AnimationFadeOut m_FadeOut = new AnimationFadeOut() { reverse = true }; + [SerializeField][Since("v3.8.0")] private AnimationChange m_Change = new AnimationChange() { 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 AnimationInteraction m_Interaction = new AnimationInteraction() { duration = 250 }; + + [Obsolete("Use animation.fadeIn.delayFunction instead.", true)] public AnimationDelayFunction fadeInDelayFunction; - /// <summary> - /// 自定义渐入动画时长函数。返回ms值。 - /// </summary> + [Obsolete("Use animation.fadeIn.durationFunction instead.", true)] public AnimationDurationFunction fadeInDurationFunction; - /// <summary> - /// 自定义渐出动画延时函数。返回ms值。 - /// </summary> + [Obsolete("Use animation.fadeOut.delayFunction instead.", true)] public AnimationDelayFunction fadeOutDelayFunction; - /// <summary> - /// 自定义渐出动画时长函数。返回ms值。 - /// </summary> + [Obsolete("Use animation.fadeOut.durationFunction instead.", true)] public AnimationDurationFunction fadeOutDurationFunction; + [Obsolete("Use animation.fadeIn.OnAnimationEnd() instead.", true)] + public Action fadeInFinishCallback { get; set; } + [Obsolete("Use animation.fadeOut.OnAnimationEnd() instead.", true)] + public Action fadeOutFinishCallback { get; set; } public AnimationStyleContext context = new AnimationStyleContext(); /// <summary> @@ -91,211 +88,228 @@ namespace XCharts.Runtime /// </summary> public AnimationType type { get { return m_Type; } set { m_Type = value; } } /// <summary> - /// Easing method used for the first animation. - /// |动画的缓动效果。 - /// </summary> - //public Easing easting { get { return m_Easting; } set { m_Easting = value; } } - /// <summary> - /// The milliseconds duration of the fadeIn animation. - /// |设定的渐入动画时长(毫秒)。如果要设置单个数据项的渐入时长,可以用代码定制:customFadeInDuration。 - /// </summary> - public float fadeInDuration { get { return m_FadeInDuration; } set { m_FadeInDuration = value < 0 ? 0 : value; } } - /// <summary> - /// The milliseconds duration of the fadeOut animation. - /// |设定的渐出动画时长(毫秒)。如果要设置单个数据项的渐出时长,可以用代码定制:customFadeOutDuration。 - /// </summary> - public float fadeOutDuration { get { return m_FadeOutDuration; } set { m_FadeOutDuration = value < 0 ? 0 : value; } } - /// <summary> - /// The milliseconds actual duration of the first animation. - /// |实际的动画时长(毫秒)。 - /// </summary> - public float actualDuration { get { return m_ActualDuration; } } - /// <summary> /// Whether to set graphic number threshold to animation. Animation will be disabled when graphic number is larger than threshold. /// |是否开启动画的阈值,当单个系列显示的图形数量大于这个阈值时会关闭动画。 /// </summary> public int threshold { get { return m_Threshold; } set { m_Threshold = value; } } /// <summary> - /// The milliseconds delay before updating the first animation. - /// |渐入动画延时(毫秒)。如果要设置单个数据项的延时,可以用代码定制:customFadeInDelay。 - /// </summary> - public float fadeInDelay { get { return m_FadeInDelay; } set { m_FadeInDelay = value < 0 ? 0 : value; } } - /// <summary> - /// 渐出动画延时(毫秒)。如果要设置单个数据项的延时,可以用代码定制:customFadeOutDelay。 - /// </summary> - public float fadeOutDelay { get { return m_FadeOutDelay; } set { m_FadeInDelay = value < 0 ? 0 : value; } } - /// <summary> - /// 是否开启数据变更动画。 - /// </summary> - public bool dataChangeEnable { get { return m_DataChangeEnable; } set { m_DataChangeEnable = value; } } - /// <summary> - /// The milliseconds duration of the data change animation. - /// |数据变更的动画时长(毫秒)。 - /// </summary> - public float dataChangeDuration { get { return m_DataChangeDuration; } set { m_DataChangeDuration = value < 0 ? 0 : value; } } - /// <summary> /// Animation updates independently of Time.timeScale. /// |动画是否受TimeScaled的影响。默认为 false 受TimeScaled的影响。 /// </summary> public bool unscaledTime { get { return m_UnscaledTime; } set { m_UnscaledTime = value; } } /// <summary> - /// 渐入动画完成回调 + /// Fade in animation configuration. + /// |渐入动画配置。 /// </summary> - public Action fadeInFinishCallback { get; set; } + public AnimationFadeIn fadeIn { get { return m_FadeIn; } } /// <summary> - /// 渐出动画完成回调 + /// Fade out animation configuration. + /// |渐出动画配置。 /// </summary> - public Action fadeOutFinishCallback { get; set; } - private Dictionary<int, float> m_ItemCurrProgress = new Dictionary<int, float>(); - private Dictionary<int, float> m_ItemDestProgress = new Dictionary<int, float>(); - private bool m_FadeIn = false; - private bool m_IsEnd = true; - private bool m_IsPause = false; - private bool m_FadeOut = false; - private bool m_FadeOuted = false; - private bool m_IsInit = false; + public AnimationFadeOut fadeOut { get { return m_FadeOut; } } + /// <summary> + /// Update data animation configuration. + /// |数据变更动画配置。 + /// </summary> + public AnimationChange change { get { return m_Change; } } + /// <summary> + /// Add data animation configuration. + /// |数据新增动画配置。 + /// </summary> + public AnimationAddition addition { get { return m_Addition; } } + /// <summary> + /// Data hiding animation configuration. + /// |数据隐藏动画配置。 + /// </summary> + /// <value></value> + public AnimationHiding hiding { get { return m_Hiding; } } + /// <summary> + /// Interaction animation configuration. + /// |交互动画配置。 + /// </summary> + public AnimationInteraction interaction { get { return m_Interaction; } } - private float startTime { get; set; } - private float m_CurrDetailProgress; - private float m_DestDetailProgress; - private float m_TotalDetailProgress; - private float m_CurrSymbolProgress; private Vector3 m_LinePathLastPos; + private List<AnimationInfo> m_Animations; + private List<AnimationInfo> animations + { + get + { + if (m_Animations == null) + { + m_Animations = new List<AnimationInfo>(); + m_Animations.Add(m_FadeIn); + m_Animations.Add(m_FadeOut); + m_Animations.Add(m_Change); + m_Animations.Add(m_Addition); + m_Animations.Add(m_Hiding); + } + return m_Animations; + } + } + /// <summary> + /// The actived animation. + /// |当前激活的动画。 + /// </summary> + public AnimationInfo activedAnimation + { + get + { + foreach (var anim in animations) + { + if (anim.context.start) return anim; + } + return null; + } + } + + /// <summary> + /// Start fadein animation. + /// |开始渐入动画。 + /// </summary> public void FadeIn() { - if (m_FadeOut) - return; - - if (m_IsPause) - { - m_IsPause = false; - return; - } - - if (m_FadeIn) - return; - - startTime = Time.time; - m_FadeIn = true; - m_IsEnd = false; - m_IsInit = false; - m_IsPause = false; - m_FadeOuted = false; - m_CurrDetailProgress = 0; - m_DestDetailProgress = 1; - m_CurrSymbolProgress = 0; - m_ItemCurrProgress.Clear(); - m_ItemDestProgress.Clear(); + if (m_FadeOut.context.start) return; + m_FadeIn.Start(); } + /// <summary> + /// Restart the actived animation. + /// |重启当前激活的动画。 + /// </summary> public void Restart() { + var anim = activedAnimation; Reset(); - FadeIn(); + if (anim != null) + { + anim.Start(); + } } + /// <summary> + /// Start fadeout animation. + /// |开始渐出动画。 + /// </summary> public void FadeOut() { - if (m_IsPause) - { - m_IsPause = false; - return; - } - - m_FadeOut = true; - startTime = Time.time; - m_FadeIn = true; - m_IsEnd = false; - m_IsInit = false; - m_IsPause = false; - m_CurrDetailProgress = 0; - m_DestDetailProgress = 1; - m_CurrSymbolProgress = 0; - m_ItemCurrProgress.Clear(); - m_ItemDestProgress.Clear(); + m_FadeOut.Start(); } + /// <summary> + /// Start additon animation. + /// |开始数据新增动画。 + /// </summary> + public void Addition() + { + if (!enable) return; + if (!m_FadeIn.context.start && !m_FadeOut.context.start) + { + m_Addition.Start(false); + } + } + + /// <summary> + /// Pause all animations. + /// |暂停所有动画。 + /// </summary> public void Pause() { - if (!m_IsPause) + foreach (var anim in animations) { - m_IsPause = true; + anim.Pause(); } } + /// <summary> + /// Resume all animations. + /// |恢复所有动画。 + /// </summary> public void Resume() { - if (m_IsPause) + foreach (var anim in animations) { - m_IsPause = false; - } - } - - private void End() - { - if (m_IsEnd) - return; - - m_ActualDuration = (int) ((Time.time - startTime) * 1000) - (m_FadeOut ? fadeOutDelay : fadeInDelay); - m_IsEnd = true; - m_IsInit = false; - - if (m_FadeIn) - { - m_FadeIn = false; - if (fadeInFinishCallback != null) - { - fadeInFinishCallback(); - } - } - if (m_FadeOut) - { - m_FadeOut = false; - m_FadeOuted = true; - if (fadeOutFinishCallback != null) - { - fadeOutFinishCallback(); - } + anim.Resume(); } } + /// <summary> + /// Reset all animations. + /// </summary> public void Reset() { - m_FadeIn = false; - m_IsEnd = true; - m_IsInit = false; - m_IsPause = false; - m_FadeOut = false; - m_FadeOuted = false; - m_ItemCurrProgress.Clear(); + foreach (var anim in animations) + { + anim.Reset(); + } } + /// <summary> + /// Initialize animation configuration. + /// |初始化动画配置。 + /// </summary> + /// <param name="curr">当前进度</param> + /// <param name="dest">目标进度</param> public void InitProgress(float curr, float dest) { - if (m_IsInit || m_IsEnd) - return; - - m_IsInit = true; - m_TotalDetailProgress = dest - curr; - - if (m_FadeOut) + var anim = activedAnimation; + if (anim == null) return; + var isAddedAnim = anim is AnimationAddition; + if (IsSerieAnimation()) { - m_CurrDetailProgress = dest; - m_DestDetailProgress = curr; + if (isAddedAnim) + { + anim.Init(anim.context.currPointIndex, dest, (int)dest - 1); + } + else + { + m_Addition.context.currPointIndex = (int)dest - 1; + anim.Init(curr, dest, (int)dest - 1); + } } else { - m_CurrDetailProgress = curr; - m_DestDetailProgress = dest; + anim.Init(curr, dest, 0); } } + /// <summary> + /// Initialize animation configuration. + /// |初始化动画配置。 + /// </summary> + /// <param name="paths">路径坐标点列表</param> + /// <param name="isY">是Y轴还是X轴</param> public void InitProgress(List<Vector3> paths, bool isY) { if (paths.Count < 1) return; - var sp = paths[0]; + var anim = activedAnimation; + if (anim == null) + { + m_Addition.context.currPointIndex = paths.Count - 1; + return; + } + var isAddedAnim = anim is AnimationAddition; + var startIndex = 0; + if (isAddedAnim) + { + startIndex = anim.context.currPointIndex == paths.Count - 1 ? + paths.Count - 2 : + anim.context.currPointIndex; + if (startIndex < 0 || startIndex > paths.Count - 2) startIndex = 0; + } + else + { + m_Addition.context.currPointIndex = paths.Count - 1; + } + var sp = paths[startIndex]; var ep = paths[paths.Count - 1]; + if (sp == anim.context.currPoint && ep == anim.context.destPoint) + { + return; + } + anim.context.currPoint = sp; + anim.context.destPoint = ep; var currDetailProgress = isY ? sp.y : sp.x; var totalDetailProgress = isY ? ep.y : ep.x; if (context.type == AnimationType.AlongPath) @@ -308,43 +322,25 @@ namespace XCharts.Runtime var np = paths[i]; totalDetailProgress += Vector3.Distance(np, lp); lp = np; + if (startIndex > 0 && i == startIndex) + currDetailProgress = totalDetailProgress; } m_LinePathLastPos = sp; context.currentPathDistance = 0; } - InitProgress(currDetailProgress, totalDetailProgress); + anim.Init(currDetailProgress, totalDetailProgress, paths.Count - 1); } - private void SetDataCurrProgress(int index, float state) + public bool IsEnd() { - m_ItemCurrProgress[index] = state; + foreach (var animation in animations) + { + if (animation.context.start) + return animation.context.end; + } + return m_FadeIn.context.end; } - private float GetDataCurrProgress(int index, float initValue, float destValue, ref bool isBarEnd) - { - if (IsInDelay()) - { - isBarEnd = false; - return initValue; - } - var c1 = !m_ItemCurrProgress.ContainsKey(index); - var c2 = !m_ItemDestProgress.ContainsKey(index); - if (c1 || c2) - { - if (c1) - m_ItemCurrProgress.Add(index, initValue); - - if (c2) - m_ItemDestProgress.Add(index, destValue); - - isBarEnd = false; - } - else - { - isBarEnd = m_ItemCurrProgress[index] == m_ItemDestProgress[index]; - } - return m_ItemCurrProgress[index]; - } public bool IsFinish() { @@ -352,79 +348,67 @@ namespace XCharts.Runtime if (!Application.isPlaying) return true; #endif - if (!m_Enable || m_IsEnd) + if (!m_Enable) return true; - if (IsIndexAnimation()) + var animation = activedAnimation; + if (animation != null && animation.context.end) + return true; + if (IsSerieAnimation()) { - if (m_FadeOut) return m_CurrDetailProgress <= m_DestDetailProgress; - else return m_CurrDetailProgress > m_DestDetailProgress; + if (m_FadeOut.context.start) return m_FadeOut.context.currProgress <= m_FadeOut.context.destProgress; + else if (m_Addition.context.start) return m_Addition.context.currProgress >= m_Addition.context.destProgress; + else return m_FadeIn.context.currProgress >= m_FadeIn.context.destProgress; + } + else if (IsDataAnimation()) + { + if (animation == null) return true; + else return animation.context.end; } - if (IsItemAnimation()) - return false; return true; } - public bool IsInFadeOut() - { - return m_FadeOut; - } - public bool IsInDelay() { - if (m_FadeOut) - return (fadeOutDelay > 0 && Time.time - startTime < fadeOutDelay / 1000); - else - return (fadeInDelay > 0 && Time.time - startTime < fadeInDelay / 1000); + var anim = activedAnimation; + if (anim != null) + return anim.IsInDelay(); + return false; } - public bool IsItemAnimation() + /// <summary> + /// whther animaiton is data animation. BottomToTop and InsideOut are data animation. + /// |是否为数据动画。BottomToTop和InsideOut类型的为数据动画。 + /// </summary> + public bool IsDataAnimation() { return context.type == AnimationType.BottomToTop || context.type == AnimationType.InsideOut; } - public bool IsIndexAnimation() + /// <summary> + /// whther animaiton is serie animation. LeftToRight, AlongPath and Clockwise are serie animation. + /// |是否为系列动画。LeftToRight、AlongPath和Clockwise类型的为系列动画。 + /// </summary> + public bool IsSerieAnimation() { return context.type == AnimationType.LeftToRight || - context.type == AnimationType.Clockwise || - context.type == AnimationType.AlongPath; - } - - public float GetIndexDelay(int dataIndex) - { - if (m_FadeOut && fadeOutDelayFunction != null) - return fadeOutDelayFunction(dataIndex); - else if (m_FadeIn && fadeInDelayFunction != null) - return fadeInDelayFunction(dataIndex); - else - return 0; - } - - public bool IsInIndexDelay(int dataIndex) - { - return Time.time - startTime < GetIndexDelay(dataIndex) / 1000f; - } - - public bool IsAllOutDelay(int dataCount) - { - var nowTime = Time.time - startTime; - for (int i = 0; i < dataCount; i++) - { - if (nowTime < GetIndexDelay(i) / 1000) - return false; - } - return true; + context.type == AnimationType.AlongPath || context.type == AnimationType.Clockwise; } public bool CheckDetailBreak(float detail) { - if (!IsIndexAnimation()) + if (!IsSerieAnimation()) return false; - return !IsFinish() && detail > m_CurrDetailProgress; + foreach (var animation in animations) + { + if (animation.context.start) + return !IsFinish() && detail > animation.context.currProgress; + } + return false; } public bool CheckDetailBreak(Vector3 pos, bool isYAxis) { - if (!IsIndexAnimation()) + if (!IsSerieAnimation()) return false; if (IsFinish()) @@ -439,139 +423,54 @@ namespace XCharts.Runtime else { if (isYAxis) - return pos.y > m_CurrDetailProgress; + return pos.y > GetCurrDetail(); else - return pos.x > m_CurrDetailProgress; + return pos.x > GetCurrDetail(); } } public void CheckProgress() { - if (IsItemAnimation() && context.isAllItemAnimationEnd) + if (IsDataAnimation() && context.isAllItemAnimationEnd) { - End(); + foreach (var animation in animations) + { + animation.End(); + } return; } - CheckProgress(m_TotalDetailProgress); + foreach (var animation in animations) + { + animation.CheckProgress(animation.context.totalProgress, m_UnscaledTime); + } } public void CheckProgress(double total) { if (IsFinish()) return; - - if (!m_IsInit || m_IsPause || m_IsEnd) - return; - - if (IsInDelay()) - return; - - m_ActualDuration = (int) ((Time.time - startTime) * 1000) - fadeInDelay; - var duration = GetCurrAnimationDuration(); - var delta = (float) (total / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime)); - if (m_FadeOut) + foreach (var animation in animations) { - m_CurrDetailProgress -= delta; - if (m_CurrDetailProgress <= m_DestDetailProgress) - { - m_CurrDetailProgress = m_DestDetailProgress; - End(); - } + animation.CheckProgress(total, m_UnscaledTime); } - else - { - m_CurrDetailProgress += delta; - if (m_CurrDetailProgress >= m_DestDetailProgress) - { - m_CurrDetailProgress = m_DestDetailProgress; - End(); - } - } - } - - internal float GetCurrAnimationDuration(int dataIndex = -1) - { - if (dataIndex >= 0) - { - if (m_FadeOut && fadeOutDurationFunction != null) - return fadeOutDurationFunction(dataIndex) / 1000f; - if (m_FadeIn && fadeInDurationFunction != null) - return fadeInDurationFunction(dataIndex) / 1000f; - } - - if (m_FadeOut) - return m_FadeOutDuration > 0 ? m_FadeOutDuration / 1000 : 1f; - else - return m_FadeInDuration > 0 ? m_FadeInDuration / 1000 : 1f; } internal float CheckItemProgress(int dataIndex, float destProgress, ref bool isEnd, float startProgress = 0) { isEnd = false; - var initHig = m_FadeOut ? destProgress : startProgress; - var destHig = m_FadeOut ? startProgress : destProgress; - var currHig = GetDataCurrProgress(dataIndex, initHig, destHig, ref isEnd); - if (isEnd || IsFinish()) + var anim = activedAnimation; + if (anim == null) { - return m_FadeOuted ? startProgress : destProgress; - } - else if (IsInDelay() || IsInIndexDelay(dataIndex)) - { - return m_FadeOut ? destProgress : startProgress; - } - else if (m_IsPause) - { - return currHig; - } - else - { - var duration = GetCurrAnimationDuration(dataIndex); - var delta = (destProgress - startProgress) / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime); - currHig = currHig + (m_FadeOut ? -delta : delta); - if (m_FadeOut) - { - if ((initHig > 0 && currHig <= 0) || (initHig < 0 && currHig >= 0)) - { - currHig = 0; - isEnd = true; - } - } - else - { - if ((destProgress - startProgress > 0 && currHig > destProgress) || - (destProgress - startProgress < 0 && currHig < destProgress)) - { - currHig = destProgress; - isEnd = true; - } - } - SetDataCurrProgress(dataIndex, currHig); - return currHig; + isEnd = true; + return destProgress; } + return anim.CheckItemProgress(dataIndex, destProgress, ref isEnd, startProgress, m_UnscaledTime); } public void CheckSymbol(float dest) { - if (!enable || m_IsEnd || m_IsPause || !m_IsInit) - return; - - if (IsInDelay()) - return; - - var duration = GetCurrAnimationDuration(); - var delta = dest / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime); - if (m_FadeOut) - { - m_CurrSymbolProgress -= delta; - if (m_CurrSymbolProgress < 0) - m_CurrSymbolProgress = 0; - } - else - { - m_CurrSymbolProgress += delta; - if (m_CurrSymbolProgress > dest) - m_CurrSymbolProgress = dest; - } + m_FadeIn.CheckSymbol(dest, m_UnscaledTime); + m_FadeOut.CheckSymbol(dest, m_UnscaledTime); } public float GetSysmbolSize(float dest) @@ -583,19 +482,30 @@ namespace XCharts.Runtime if (!enable) return dest; - if (m_IsEnd) - return m_FadeOut ? 0 : dest; + if (IsEnd()) + return m_FadeOut.context.start ? 0 : dest; - return m_CurrSymbolProgress; + return m_FadeOut.context.start ? m_FadeOut.context.sizeProgress : m_FadeIn.context.sizeProgress; } public float GetCurrDetail() { #if UNITY_EDITOR if (!Application.isPlaying) - return m_DestDetailProgress; + { + foreach (var animation in animations) + { + if (animation.context.start) + return animation.context.destProgress; + } + } #endif - return m_CurrDetailProgress; + foreach (var animation in animations) + { + if (animation.context.start) + return animation.context.currProgress; + } + return m_FadeIn.context.currProgress; } public float GetCurrRate() @@ -604,9 +514,9 @@ namespace XCharts.Runtime if (!Application.isPlaying) return 1; #endif - if (!enable || m_IsEnd) + if (!enable || IsEnd()) return 1; - return m_CurrDetailProgress; + return m_FadeOut.context.start ? m_FadeOut.context.currProgress : m_FadeIn.context.currProgress; } public int GetCurrIndex() @@ -615,22 +525,65 @@ namespace XCharts.Runtime if (!Application.isPlaying) return -1; #endif - if (!enable || m_IsEnd) + if (!enable) return -1; - return (int) m_CurrDetailProgress; + var anim = activedAnimation; + if (anim == null) + return -1; + return (int)anim.context.currProgress; } - public float GetUpdateAnimationDuration() + public float GetChangeDuration() { - if (m_Enable && m_DataChangeEnable) - return m_DataChangeDuration; + if (m_Enable && m_Change.enable) + return m_Change.duration; else return 0; } + public float GetAdditionDuration() + { + if (m_Enable && m_Addition.enable) + return m_Addition.duration; + else + return 0; + } + + public float GetInteractionDuration() + { + if (m_Enable && m_Interaction.enable) + return m_Interaction.duration; + else + return 0; + } + + public float GetInteractionRadius(float radius) + { + if (m_Enable && m_Interaction.enable) + return m_Interaction.GetRadius(radius); + else + return radius; + } + public bool HasFadeOut() { - return enable && m_FadeOuted && m_IsEnd; + return enable && m_FadeOut.context.end; + } + + public bool IsFadeIn() + { + return enable && m_FadeIn.context.start; + } + + public bool IsFadeOut() + { + return enable && m_FadeOut.context.start; + } + + public bool CanCheckInteract() + { + return enable && interaction.enable + && !IsFadeIn() && !IsFadeOut(); } } } \ No newline at end of file diff --git a/Runtime/Component/Animation/AnimationStyleContext.cs b/Runtime/Component/Animation/AnimationStyleContext.cs index 9184e0a7..f49244fd 100644 --- a/Runtime/Component/Animation/AnimationStyleContext.cs +++ b/Runtime/Component/Animation/AnimationStyleContext.cs @@ -7,6 +7,7 @@ namespace XCharts.Runtime public struct AnimationStyleContext { public AnimationType type; + public bool enableSerieDataAddedAnimation; public float currentPathDistance; public bool isAllItemAnimationEnd; } diff --git a/Runtime/Component/Animation/AnimationStyleHelper.cs b/Runtime/Component/Animation/AnimationStyleHelper.cs index 332236da..bc8a5bf5 100644 --- a/Runtime/Component/Animation/AnimationStyleHelper.cs +++ b/Runtime/Component/Animation/AnimationStyleHelper.cs @@ -7,7 +7,7 @@ namespace XCharts.Runtime { public static float CheckDataAnimation(BaseChart chart, Serie serie, int dataIndex, float destProgress, float startPorgress = 0) { - if (!serie.animation.IsItemAnimation()) + if (!serie.animation.IsDataAnimation()) { serie.animation.context.isAllItemAnimationEnd = false; return destProgress; @@ -30,18 +30,22 @@ namespace XCharts.Runtime { var serieType = serie.GetType(); var animationType = AnimationType.LeftToRight; + var enableSerieDataAnimation = true; if (serieType.IsDefined(typeof(DefaultAnimationAttribute), false)) { - animationType = serieType.GetAttribute<DefaultAnimationAttribute>().type; + var attribute = serieType.GetAttribute<DefaultAnimationAttribute>(); + animationType = attribute.type; + enableSerieDataAnimation = attribute.enableSerieDataAddedAnimation; } - UpdateAnimationType(serie.animation, animationType); + UpdateAnimationType(serie.animation, animationType,enableSerieDataAnimation); } - public static void UpdateAnimationType(AnimationStyle animation, AnimationType defaultType) + public static void UpdateAnimationType(AnimationStyle animation, AnimationType defaultType, bool enableSerieDataAnimation) { animation.context.type = animation.type == AnimationType.Default ? defaultType : animation.type; + animation.context.enableSerieDataAddedAnimation = enableSerieDataAnimation; } public static bool GetAnimationPosition(AnimationStyle animation, bool isY, Vector3 lp, Vector3 cp, float progress, ref Vector3 ip) diff --git a/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs b/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs index 5ac345e7..41d6658f 100644 --- a/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs +++ b/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs @@ -168,7 +168,7 @@ namespace XCharts.Runtime var dir = (chart.pointerPos - new Vector2(polar.context.center.x, polar.context.center.y)).normalized; var angle = ChartHelper.GetAngle360(Vector2.up, dir); axis.context.pointerValue = (angle - component.context.startAngle + 360) % 360; - axis.context.pointerLabelPosition = polar.context.center + new Vector3(dir.x, dir.y) * (polar.context.outsideRadius + 25); + axis.context.pointerLabelPosition = polar.context.center + new Vector3(dir.x, dir.y) * (polar.context.outsideRadius + polar.indicatorLabelOffset); } } } \ No newline at end of file diff --git a/Runtime/Component/Axis/AxisHandler.cs b/Runtime/Component/Axis/AxisHandler.cs index 0b7f8ae6..4651da8a 100644 --- a/Runtime/Component/Axis/AxisHandler.cs +++ b/Runtime/Component/Axis/AxisHandler.cs @@ -152,7 +152,6 @@ namespace XCharts else dataZoom.SetYAxisIndexValueInfo(axisIndex, ref tempMinValue, ref tempMaxValue); } - if (tempMinValue != axis.context.minValue || tempMaxValue != axis.context.maxValue || m_LastInterval != axis.interval || @@ -388,7 +387,8 @@ namespace XCharts new Vector2(textWidth, textHeight), axis, chart.theme.axis, labelName, Color.clear, - defaultAlignment); + defaultAlignment, + chart.theme.GetColor(i)); if (i == 0) axis.axisLabel.SetRelatedText(label.text, labelWidth); diff --git a/Runtime/Component/Axis/AxisHelper.cs b/Runtime/Component/Axis/AxisHelper.cs index 7d750607..ff39cb7b 100644 --- a/Runtime/Component/Axis/AxisHelper.cs +++ b/Runtime/Component/Axis/AxisHelper.cs @@ -621,7 +621,8 @@ namespace XCharts.Runtime var startY = grid.context.y + xAxis.offset; if (xAxis.IsTop()) startY += grid.context.height; - else if (xAxis.axisLine.onZero && relativedAxis.IsValue() && relativedAxis.gridIndex == xAxis.gridIndex) + else if (xAxis.axisLine.onZero && relativedAxis != null && relativedAxis.IsValue() + && relativedAxis.gridIndex == xAxis.gridIndex) startY += relativedAxis.context.offset; return startY; } @@ -631,7 +632,8 @@ namespace XCharts.Runtime var startX = grid.context.x + yAxis.offset; if (yAxis.IsRight()) startX += grid.context.width; - else if (yAxis.axisLine.onZero && relativedAxis.IsValue() && relativedAxis.gridIndex == yAxis.gridIndex) + else if (yAxis.axisLine.onZero && relativedAxis != null && relativedAxis.IsValue() + && relativedAxis.gridIndex == yAxis.gridIndex) startX += relativedAxis.context.offset; return startX; } diff --git a/Runtime/Component/Axis/SingleAxis/SingleAxis.cs b/Runtime/Component/Axis/SingleAxis/SingleAxis.cs index 263d37b4..8f29b518 100644 --- a/Runtime/Component/Axis/SingleAxis/SingleAxis.cs +++ b/Runtime/Component/Axis/SingleAxis/SingleAxis.cs @@ -83,8 +83,12 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_Height, value)) SetAllDirty(); } } - public void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight) + public void UpdateRuntimeData(BaseChart chart) { + var chartX = chart.chartX; + var chartY = chart.chartY; + var chartWidth = chart.chartWidth; + var chartHeight = chart.chartHeight; context.left = left <= 1 ? left * chartWidth : left; context.bottom = bottom <= 1 ? bottom * chartHeight : bottom; context.top = top <= 1 ? top * chartHeight : top; diff --git a/Runtime/Component/Axis/SingleAxis/SingleAxisHandler.cs b/Runtime/Component/Axis/SingleAxis/SingleAxisHandler.cs index 28b33ef8..46aa9973 100644 --- a/Runtime/Component/Axis/SingleAxis/SingleAxisHandler.cs +++ b/Runtime/Component/Axis/SingleAxis/SingleAxisHandler.cs @@ -33,10 +33,7 @@ namespace XCharts.Runtime axis.painter = chart.painter; axis.refreshComponent = delegate() { - axis.UpdateRuntimeData(chart.chartX, - chart.chartY, - chart.chartWidth, - chart.chartHeight); + axis.UpdateRuntimeData(chart); InitAxis(null, axis.orient, diff --git a/Runtime/Component/Child/MLValue.cs b/Runtime/Component/Child/MLValue.cs new file mode 100644 index 00000000..589127ba --- /dev/null +++ b/Runtime/Component/Child/MLValue.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace XCharts.Runtime +{ + /// <summary> + /// 多样式数值。 + /// </summary> + [Since("v3.8.0")] + [System.Serializable] + public class MLValue : ChildComponent + { + /// <summary> + /// the type of value. + /// |数值类型。 + /// </summary> + public enum Type + { + /// <summary> + /// Percent value form. + /// |百分比形式。 + /// </summary> + Percent, + /// <summary> + /// Absolute value form. + /// |绝对值形式。 + /// </summary> + Absolute, + /// <summary> + /// Extra value form. + /// |额外形式。 + /// </summary> + Extra + } + [SerializeField] private Type m_Type; + [SerializeField] private float m_Value; + + public Type type { get { return m_Type; } set { m_Type = value; } } + public float value { get { return m_Value; } set { m_Value = value; } } + + public MLValue(float value) + { + m_Type = Type.Percent; + m_Value = value; + } + + public MLValue(Type type, float value) + { + m_Type = type; + m_Value = value; + } + + /// <summary> + /// Get the value by type. + /// |根据类型获取值。 + /// </summary> + /// <param name="total">默认值</param> + /// <returns></returns> + public float GetValue(float total) + { + switch (m_Type) + { + case Type.Percent: + return m_Value * total; + case Type.Absolute: + return m_Value; + case Type.Extra: + return total + m_Value; + default: return 0; + } + } + } +} \ No newline at end of file diff --git a/Runtime/Component/Child/MLValue.cs.meta b/Runtime/Component/Child/MLValue.cs.meta new file mode 100644 index 00000000..194febee --- /dev/null +++ b/Runtime/Component/Child/MLValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 10f15d7e58cf24fa6a1986793ba2a36b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Component/Child/SymbolStyle.cs b/Runtime/Component/Child/SymbolStyle.cs index 3b8677a5..3e394a78 100644 --- a/Runtime/Component/Child/SymbolStyle.cs +++ b/Runtime/Component/Child/SymbolStyle.cs @@ -57,7 +57,15 @@ namespace XCharts.Runtime /// <summary> /// 空心箭头。 /// </summary> - EmptyArrow + EmptyArrow, + /// <summary> + /// 加号。 + /// </summary> + Plus, + /// <summary> + /// 减号。 + /// </summary> + Minus, } /// <summary> diff --git a/Runtime/Component/DataZoom/DataZoom.cs b/Runtime/Component/DataZoom/DataZoom.cs index f6ae0547..4f8a72ce 100644 --- a/Runtime/Component/DataZoom/DataZoom.cs +++ b/Runtime/Component/DataZoom/DataZoom.cs @@ -662,8 +662,12 @@ namespace XCharts.Runtime if (m_EndLabel != null) m_EndLabel.SetPosition(pos); } - public void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight) + public void UpdateRuntimeData(BaseChart chart) { + var chartX = chart.chartX; + var chartY = chart.chartY; + var chartWidth = chart.chartWidth; + var chartHeight = chart.chartHeight; var runtimeLeft = left <= 1 ? left * chartWidth : left; var runtimeBottom = bottom <= 1 ? bottom * chartHeight : bottom; var runtimeTop = top <= 1 ? top * chartHeight : top; diff --git a/Runtime/Component/DataZoom/DataZoomHandler.cs b/Runtime/Component/DataZoom/DataZoomHandler.cs index a98cd540..0778d7c8 100644 --- a/Runtime/Component/DataZoom/DataZoomHandler.cs +++ b/Runtime/Component/DataZoom/DataZoomHandler.cs @@ -543,13 +543,14 @@ namespace XCharts.Runtime var totalAverage = serie.sampleAverage > 0 ? serie.sampleAverage : DataHelper.DataAverage(ref showData, serie.sampleType, serie.minShow, maxCount, rate); var dataChanging = false; - var animationDuration = serie.animation.GetUpdateAnimationDuration(); + var animationDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; for (int i = 0; i < maxCount; i += rate) { double value = DataHelper.SampleValue(ref showData, serie.sampleType, rate, serie.minShow, maxCount, totalAverage, i, - animationDuration, ref dataChanging, axis, unscaledTime); + dataAddDuration, animationDuration, ref dataChanging, axis, unscaledTime); float pX = dataZoom.context.x + i * scaleWid; float dataHig = (float)((maxValue - minValue) == 0 ? 0 : (value - minValue) / (maxValue - minValue) * dataZoom.context.height); @@ -634,13 +635,14 @@ namespace XCharts.Runtime var totalAverage = serie.sampleAverage > 0 ? serie.sampleAverage : DataHelper.DataAverage(ref showData, serie.sampleType, serie.minShow, maxCount, rate); var dataChanging = false; - var animationDuration = serie.animation.GetUpdateAnimationDuration(); + var animationDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; for (int i = 0; i < maxCount; i += rate) { double value = DataHelper.SampleValue(ref showData, serie.sampleType, rate, serie.minShow, maxCount, totalAverage, i, - animationDuration, ref dataChanging, axis, unscaledTime); + dataAddDuration, animationDuration, ref dataChanging, axis, unscaledTime); float pY = dataZoom.context.y + i * scaleWid; float dataHig = (maxValue - minValue) == 0 ? 0 : (float)((value - minValue) / (maxValue - minValue) * dataZoom.context.width); diff --git a/Runtime/Component/Interaction/InteractData.cs b/Runtime/Component/Interaction/InteractData.cs index fd9122cb..23f210df 100644 --- a/Runtime/Component/Interaction/InteractData.cs +++ b/Runtime/Component/Interaction/InteractData.cs @@ -5,33 +5,61 @@ namespace XCharts.Runtime public class InteractData { private float m_PreviousValue = 0; - private float m_TargetValue = 0; - private Color32 m_PreviousColor; - private Color32 m_TargetColor; - private Color32 m_PreviousToColor; - private Color32 m_TargetToColor; + private float m_CurrentValue = float.NaN; + private float m_TargetValue = float.NaN; + private Vector3 m_PreviousPosition = Vector3.one; + private Vector3 m_TargetPosition = Vector3.one; + private Color32 m_PreviousColor = ColorUtil.clearColor32; + private Color32 m_TargetColor = ColorUtil.clearColor32; + private Color32 m_PreviousToColor = ColorUtil.clearColor32; + private Color32 m_TargetToColor = ColorUtil.clearColor32; private float m_UpdateTime = 0; private bool m_UpdateFlag = false; private bool m_ValueEnable = false; internal float targetVaue { get { return m_TargetValue; } } + internal float previousValue { get { return m_PreviousValue; } } + internal bool valueEnable { get { return m_ValueEnable; } } + internal bool updateFlag { get { return m_UpdateFlag; } } - public void SetValue(ref bool needInteract, float size, bool highlight, float rate = 1.3f) + public override string ToString() { - size = highlight ? size * rate : size; - SetValue(ref needInteract, size); + return string.Format("m_PreviousValue:{0},m_TargetValue:{1},m_UpdateTime:{2},m_UpdateFlag:{3},m_ValueEnable:{4},m_PreviousPosition:{5},m_TargetPosition:{6}", + m_PreviousValue, m_TargetValue, m_UpdateTime, m_UpdateFlag, m_ValueEnable, m_PreviousPosition, m_TargetPosition); } - public void SetValue(ref bool needInteract, float size) + public void SetValue(ref bool needInteract, float value, bool highlight, float rate = 1.3f) { - if (m_TargetValue != size) + value = highlight && rate != 0 ? value * rate : value; + SetValue(ref needInteract, value); + } + + public void SetValue(ref bool needInteract, float value, bool previousValueZero = false) + { + if (m_TargetValue != value) { needInteract = true; - m_UpdateFlag = true; - m_ValueEnable = true; - m_UpdateTime = Time.time; - m_PreviousValue = m_TargetValue; - m_TargetValue = size; + if (!m_ValueEnable) + m_PreviousValue = previousValueZero ? 0 : value; + else + m_PreviousValue = m_CurrentValue; + UpdateStart(); + m_TargetValue = value; + } + else if (m_UpdateFlag) + { + needInteract = true; + } + } + + public void SetPosition(ref bool needInteract, Vector3 pos) + { + if (m_TargetPosition != pos) + { + needInteract = true; + UpdateStart(); + m_PreviousPosition = m_TargetPosition == Vector3.one ? pos : m_TargetPosition; + m_TargetPosition = pos; } } @@ -39,30 +67,24 @@ namespace XCharts.Runtime { if (!ChartHelper.IsValueEqualsColor(color, m_TargetColor)) { - if (!ChartHelper.IsClearColor(m_TargetColor)) - { - needInteract = true; - m_UpdateFlag = true; - m_ValueEnable = true; - m_UpdateTime = Time.time; - m_PreviousColor = m_TargetColor; - } + needInteract = true; + UpdateStart(); + m_PreviousColor = ChartHelper.IsClearColor(m_TargetColor) ? color : m_TargetColor; m_TargetColor = color; } + else if (m_UpdateFlag) + { + needInteract = true; + } } public void SetColor(ref bool needInteract, Color32 color, Color32 toColor) { SetColor(ref needInteract, color); if (!ChartHelper.IsValueEqualsColor(toColor, m_TargetToColor)) { - if (!ChartHelper.IsClearColor(m_TargetToColor)) - { - needInteract = true; - m_UpdateFlag = true; - m_ValueEnable = true; - m_UpdateTime = Time.time; - m_PreviousToColor = m_TargetToColor; - } + needInteract = true; + UpdateStart(); + m_PreviousToColor = ChartHelper.IsClearColor(m_TargetToColor) ? color : m_TargetToColor; m_TargetToColor = toColor; } } @@ -81,39 +103,62 @@ namespace XCharts.Runtime public bool TryGetValue(ref float value, ref bool interacting, float animationDuration = 250) { - if (!IsValueEnable() || m_PreviousValue == 0) + if (!IsValueEnable() || animationDuration == 0) return false; - if (m_UpdateFlag) + if (float.IsNaN(m_TargetValue)) + return false; + if (m_UpdateFlag && !float.IsNaN(m_PreviousValue)) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; value = Mathf.Lerp(m_PreviousValue, m_TargetValue, rate); + m_CurrentValue = value; return true; } else { - m_UpdateFlag = false; + UpdateEnd(); } } value = m_TargetValue; return true; } + public bool TryGetPosition(ref Vector3 pos, ref bool interacting, float animationDuration = 250) + { + if (!IsValueEnable() || animationDuration == 0) + return false; + if (m_TargetPosition == Vector3.one) + { + return false; + } + if (m_UpdateFlag && m_PreviousPosition != Vector3.one) + { + var rate = GetRate(animationDuration); + if (rate < 1) + { + interacting = true; + pos = Vector3.Lerp(m_PreviousPosition, m_TargetPosition, rate); + return true; + } + else + { + UpdateEnd(); + } + } + pos = m_TargetPosition; + return true; + } + public bool TryGetColor(ref Color32 color, ref bool interacting, float animationDuration = 250) { - if (!IsValueEnable()) + if (!IsValueEnable() || animationDuration == 0) return false; if (m_UpdateFlag) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; @@ -122,7 +167,7 @@ namespace XCharts.Runtime } else { - m_UpdateFlag = false; + UpdateEnd(); } } color = m_TargetColor; @@ -131,14 +176,11 @@ namespace XCharts.Runtime public bool TryGetColor(ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250) { - if (!IsValueEnable()) + if (!IsValueEnable() || animationDuration == 0) return false; if (m_UpdateFlag) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; @@ -148,7 +190,7 @@ namespace XCharts.Runtime } else { - m_UpdateFlag = false; + UpdateEnd(); } } color = m_TargetColor; @@ -157,25 +199,25 @@ namespace XCharts.Runtime } public bool TryGetValueAndColor(ref float value, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250) { - if (!IsValueEnable()) + if (!IsValueEnable() || animationDuration == 0) return false; - if (m_UpdateFlag) + if (float.IsNaN(m_TargetValue)) + return false; + if (m_UpdateFlag && !float.IsNaN(m_PreviousValue)) { - var time = Time.time - m_UpdateTime; - var total = animationDuration / 1000; - var rate = time / total; - if (rate > 1) rate = 1; + var rate = GetRate(animationDuration); if (rate < 1) { interacting = true; value = Mathf.Lerp(m_PreviousValue, m_TargetValue, rate); color = Color32.Lerp(m_PreviousColor, m_TargetColor, rate); toColor = Color32.Lerp(m_PreviousToColor, m_TargetToColor, rate); + m_CurrentValue = value; return true; } else { - m_UpdateFlag = false; + UpdateEnd(); } } value = m_TargetValue; @@ -184,11 +226,56 @@ namespace XCharts.Runtime return true; } + private float GetRate(float animationDuration) + { + var time = Time.time - m_UpdateTime; + var total = animationDuration / 1000; + var rate = time / total; + if (rate > 1) rate = 1; + return rate; + } + + private void UpdateStart() + { + m_ValueEnable = true; + m_UpdateFlag = true; + m_UpdateTime = Time.time; + } + + private void UpdateEnd() + { + if (!m_UpdateFlag) return; + m_UpdateFlag = false; + m_PreviousColor = m_TargetColor; + m_PreviousToColor = m_TargetToColor; + m_PreviousValue = m_TargetValue; + m_CurrentValue = m_TargetValue; + m_PreviousPosition = m_TargetPosition; + } + + public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref Color32 color, ref Color32 toColor, ref bool interacting, float animationDuration = 250) + { + var flag = TryGetValueAndColor(ref value, ref color, ref toColor, ref interacting, animationDuration); + flag |= TryGetPosition(ref pos, ref interacting, animationDuration); + return flag; + } + + public bool TryGetValueAndColor(ref float value, ref Vector3 pos, ref bool interacting, float animationDuration = 250) + { + var flag = TryGetValue(ref value, ref interacting, animationDuration); + flag |= TryGetPosition(ref pos, ref interacting, animationDuration); + return flag; + } + public void Reset() { m_UpdateFlag = false; m_ValueEnable = false; + m_TargetValue = float.NaN; m_PreviousValue = float.NaN; + m_CurrentValue = float.NaN; + m_PreviousPosition = Vector3.one; + m_TargetPosition = Vector3.one; m_TargetColor = ColorUtil.clearColor32; m_TargetToColor = ColorUtil.clearColor32; m_PreviousColor = ColorUtil.clearColor32; diff --git a/Runtime/Component/Label/LabelLine.cs b/Runtime/Component/Label/LabelLine.cs index 3f48c53f..dd41e8db 100644 --- a/Runtime/Component/Label/LabelLine.cs +++ b/Runtime/Component/Label/LabelLine.cs @@ -31,11 +31,12 @@ namespace XCharts.Runtime [SerializeField] private bool m_Show = true; [SerializeField] private LineType m_LineType = LineType.BrokenLine; [SerializeField] private Color32 m_LineColor = ChartConst.clearColor32; - [SerializeField] private float m_LineAngle = 0; + [SerializeField] private float m_LineAngle = 60; [SerializeField] private float m_LineWidth = 1.0f; [SerializeField] private float m_LineGap = 1.0f; [SerializeField] private float m_LineLength1 = 25f; [SerializeField] private float m_LineLength2 = 15f; + [SerializeField][Since("v3.8.0")] private float m_LineEndX = 0f; [SerializeField] private SymbolStyle m_StartSymbol = new SymbolStyle() { show = false, type = SymbolType.Circle, size = 3 }; [SerializeField] private SymbolStyle m_EndSymbol = new SymbolStyle() { show = false, type = SymbolType.Circle, size = 3 }; @@ -44,11 +45,12 @@ namespace XCharts.Runtime m_Show = false; m_LineType = LineType.BrokenLine; m_LineColor = Color.clear; - m_LineAngle = 0; + m_LineAngle = 60; m_LineWidth = 1.0f; m_LineGap = 1.0f; m_LineLength1 = 25f; m_LineLength2 = 15f; + m_LineEndX = 0; } /// <summary> @@ -79,8 +81,8 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_LineColor, value)) SetVerticesDirty(); } } /// <summary> - /// the angle of visual guild line. - /// |视觉引导线的固定角度。对折线和曲线有效。 + /// the angle of visual guild line. Valid for broken line and curve line. Invalid in Pie. + /// |视觉引导线的固定角度。对折线和曲线有效。在Pie中无效。 /// </summary> public float lineAngle { @@ -124,6 +126,15 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_LineLength2, value)) SetVerticesDirty(); } } /// <summary> + /// The fixed x position of the end point of visual guide line. + /// |视觉引导线结束点的固定x位置。当不为0时,会代替lineLength2设定引导线的x位置。 + /// </summary> + public float lineEndX + { + get { return m_LineEndX; } + set { if (PropertyUtil.SetStruct(ref m_LineEndX, value)) SetVerticesDirty(); } + } + /// <summary> /// The symbol of the start point of labelline. /// |起始点的图形标记。 /// </summary> @@ -144,12 +155,12 @@ namespace XCharts.Runtime public Vector3 GetStartSymbolOffset() { - return m_StartSymbol != null && m_StartSymbol.show? m_StartSymbol.offset3 : Vector3.zero; + return m_StartSymbol != null && m_StartSymbol.show ? m_StartSymbol.offset3 : Vector3.zero; } public Vector3 GetEndSymbolOffset() { - return m_EndSymbol != null && m_EndSymbol.show? m_EndSymbol.offset3 : Vector3.zero; + return m_EndSymbol != null && m_EndSymbol.show ? m_EndSymbol.offset3 : Vector3.zero; } } } \ No newline at end of file diff --git a/Runtime/Component/Label/LabelStyle.cs b/Runtime/Component/Label/LabelStyle.cs index a97e5ae4..00920dda 100644 --- a/Runtime/Component/Label/LabelStyle.cs +++ b/Runtime/Component/Label/LabelStyle.cs @@ -353,7 +353,14 @@ namespace XCharts.Runtime } else if (string.IsNullOrEmpty(newNumericFormatter) && !isLog) { - newNumericFormatter = MathUtil.IsInteger(maxValue) ? "f0" : "f" + MathUtil.GetPrecision(maxValue); + if (Math.Abs(maxValue) >= Math.Abs(minValue)) + { + newNumericFormatter = MathUtil.IsInteger(maxValue) ? "0.#" : "f" + MathUtil.GetPrecision(maxValue); + } + else + { + newNumericFormatter = MathUtil.IsInteger(minValue) ? "0.#" : "f" + MathUtil.GetPrecision(minValue); + } } if (string.IsNullOrEmpty(m_Formatter)) { @@ -413,7 +420,7 @@ namespace XCharts.Runtime protected string GetFormatterFunctionContent(int labelIndex, double value, string currentContent) { return m_FormatterFunction == null ? currentContent : - m_FormatterFunction(labelIndex, labelIndex, null, currentContent); + m_FormatterFunction(labelIndex, value, null, currentContent); } } } \ No newline at end of file diff --git a/Runtime/Component/Label/SerieLabelHelper.cs b/Runtime/Component/Label/SerieLabelHelper.cs index 5d9c5a65..48532686 100644 --- a/Runtime/Component/Label/SerieLabelHelper.cs +++ b/Runtime/Component/Label/SerieLabelHelper.cs @@ -71,163 +71,6 @@ namespace XCharts.Runtime } } - public static void UpdatePieLabelPosition(Serie serie, SerieData serieData) - { - if (serieData.labelObject == null) return; - var startAngle = serie.context.startAngle; - var currAngle = serieData.context.halfAngle; - var currRad = currAngle * Mathf.Deg2Rad; - var offsetRadius = serieData.context.offsetRadius; - var insideRadius = serieData.context.insideRadius; - var outsideRadius = serieData.context.outsideRadius; - var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); - var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); - switch (serieLabel.position) - { - case LabelStyle.Position.Center: - serieData.context.labelPosition = serie.context.center; - break; - case LabelStyle.Position.Inside: - var labelRadius = offsetRadius + insideRadius + (outsideRadius - insideRadius) / 2 + serieLabel.distance; - var labelCenter = new Vector2(serie.context.center.x + labelRadius * Mathf.Sin(currRad), - serie.context.center.y + labelRadius * Mathf.Cos(currRad)); - serieData.context.labelPosition = labelCenter; - break; - default: - //LabelStyle.Position.Outside - if (labelLine != null && labelLine.lineType == LabelLine.LineType.HorizontalLine) - { - var radius1 = serie.context.outsideRadius; - var radius3 = insideRadius + (outsideRadius - insideRadius) / 2; - var currSin = Mathf.Sin(currRad); - var currCos = Mathf.Cos(currRad); - var pos0 = new Vector3(serie.context.center.x + radius3 * currSin, serie.context.center.y + radius3 * currCos); - if ((currAngle - startAngle) % 360 > 180) - { - currSin = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad); - currCos = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad); - } - var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3; - r4 += labelLine.lineLength1 + labelLine.lineWidth * 4; - r4 += serieData.labelObject.text.GetPreferredWidth() / 2; - serieData.context.labelPosition = pos0 + ((currAngle - startAngle) % 360 > 180 ? Vector3.left : Vector3.right) * r4; - } - else - { - labelRadius = serie.context.outsideRadius + (labelLine == null ? 0 : labelLine.lineLength1); - labelCenter = new Vector2(serie.context.center.x + labelRadius * Mathf.Sin(currRad), - serie.context.center.y + labelRadius * Mathf.Cos(currRad)); - serieData.context.labelPosition = labelCenter; - } - break; - } - } - - public static void AvoidLabelOverlap(Serie serie, ComponentTheme theme) - { - if (!serie.avoidLabelOverlap) return; - var lastCheckPos = Vector3.zero; - var lastX = 0f; - var data = serie.data; - var splitCount = 0; - for (int n = 0; n < data.Count; n++) - { - var serieData = data[n]; - if (serieData.context.labelPosition.x != 0 && serieData.context.labelPosition.x < serie.context.center.x) - { - splitCount = n; - break; - } - } - - for (int n = 0; n < splitCount; n++) - { - CheckSerieDataLabel(serie, data[n], splitCount, false, theme, ref lastCheckPos, ref lastX); - } - lastCheckPos = Vector3.zero; - for (int n = data.Count - 1; n >= splitCount; n--) - { - CheckSerieDataLabel(serie, data[n], data.Count - splitCount, true, theme, ref lastCheckPos, ref lastX); - } - } - - private static void CheckSerieDataLabel(Serie serie, SerieData serieData, int total, bool isLeft, ComponentTheme theme, - ref Vector3 lastCheckPos, ref float lastX) - { - if (!serieData.context.canShowLabel) - { - serieData.SetLabelActive(false); - return; - } - if (!serieData.show) return; - var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); - var isOutside = serieLabel.position == LabelStyle.Position.Outside || - serieLabel.position == LabelStyle.Position.Default; - if (!serieLabel.show) return; - if (!isOutside) return; - var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); - var fontSize = serieData.labelObject.GetHeight(); - if (lastCheckPos == Vector3.zero) - { - lastCheckPos = serieData.context.labelPosition; - } - else if (serieData.context.labelPosition.x != 0) - { - if (lastCheckPos.y - serieData.context.labelPosition.y < fontSize) - { - var labelRadius = serie.context.outsideRadius + labelLine.lineLength1; - var y1 = lastCheckPos.y - fontSize; - var cy = serie.context.center.y; - var diff = Mathf.Abs(y1 - cy); - var diffX = labelRadius * labelRadius - diff * diff; - diffX = diffX <= 0 ? 0 : diffX; - var x1 = serie.context.center.x + Mathf.Sqrt(diffX) * (isLeft ? -1 : 1); - var newPos = new Vector3(x1, y1); - serieData.context.labelPosition = newPos; - var angle = ChartHelper.GetAngle360(Vector2.up, newPos - serie.context.center); - if (angle >= 180 && angle <= 270) - { - serieData.context.labelPosition = new Vector3(isLeft?(++lastX): (--lastX), y1); - } - else if (angle < 180 && angle >= 90) - { - serieData.context.labelPosition = new Vector3(isLeft?(++lastX): (--lastX), y1); - } - else - { - lastX = x1; - } - } - else - { - lastX = serieData.context.labelPosition.x; - } - lastCheckPos = serieData.context.labelPosition; - serieData.labelObject.SetPosition(SerieLabelHelper.GetRealLabelPosition(serie, serieData, serieLabel, labelLine)); - } - } - - public static Vector3 GetRealLabelPosition(Serie serie, SerieData serieData, LabelStyle label, LabelLine labelLine) - { - if (label == null || labelLine == null) - return serieData.context.labelPosition; - var isOutside = label.position == LabelStyle.Position.Outside || - label.position == LabelStyle.Position.Default; - if (isOutside && labelLine.lineType != LabelLine.LineType.HorizontalLine) - { - var currAngle = serieData.context.halfAngle; - var offset = labelLine.lineLength2 + serieData.labelObject.GetTextWidth() / 2; - var angle = (currAngle - serie.context.startAngle) % 360; - var isLeft = angle > 180 || (angle == 0 && serieData.context.startAngle > 0); - if (isLeft) - return serieData.context.labelPosition + new Vector3(-offset, 0, 0); - else - return serieData.context.labelPosition + new Vector3(offset, 0, 0); - } - else - { - return serieData.context.labelPosition; - } - } + } } \ No newline at end of file diff --git a/Runtime/Component/Legend/LegendHelper.cs b/Runtime/Component/Legend/LegendHelper.cs index 352c8a78..3df72232 100644 --- a/Runtime/Component/Legend/LegendHelper.cs +++ b/Runtime/Component/Legend/LegendHelper.cs @@ -284,9 +284,9 @@ namespace XCharts.Runtime return needShow; } - public static bool CheckDataHighlighted(Serie serie, string legendName, bool heighlight) + public static int CheckDataHighlighted(Serie serie, string legendName, bool heighlight) { - bool show = false; + var highlightedDataIndex = 0; if (legendName.Equals(serie.serieName)) { serie.highlight = heighlight; @@ -298,11 +298,14 @@ namespace XCharts.Runtime if (legendName.Equals(data.name)) { data.context.highlight = heighlight; - if (data.context.highlight) show = true; + if (data.context.highlight) + { + highlightedDataIndex = data.index; + } } } } - return show; + return highlightedDataIndex; } } } \ No newline at end of file diff --git a/Runtime/Component/Mark/MarkLine.cs b/Runtime/Component/Mark/MarkLine.cs index 76929290..3a7b135f 100644 --- a/Runtime/Component/Mark/MarkLine.cs +++ b/Runtime/Component/Mark/MarkLine.cs @@ -129,6 +129,7 @@ namespace XCharts.Runtime public Vector3 runtimeCurrentEndPosition { get; internal set; } public ChartLabel runtimeLabel { get; internal set; } public double runtimeValue { get; internal set; } + public bool runtimeInGrid { get; internal set; } /// <summary> /// Name of the marker, which will display as a label. diff --git a/Runtime/Component/Mark/MarkLineHandler.cs b/Runtime/Component/Mark/MarkLineHandler.cs index 6ac01410..858097f1 100644 --- a/Runtime/Component/Mark/MarkLineHandler.cs +++ b/Runtime/Component/Mark/MarkLineHandler.cs @@ -36,7 +36,7 @@ namespace XCharts.Runtime if (data.runtimeLabel != null) { var pos = MarkLineHelper.GetLabelPosition(data); - data.runtimeLabel.SetActive(data.label.show && pos != Vector3.zero); + data.runtimeLabel.SetActive(data.label.show && data.runtimeInGrid); data.runtimeLabel.SetPosition(pos); data.runtimeLabel.SetText(MarkLineHelper.GetFormatterContent(serie, data)); } @@ -49,7 +49,7 @@ namespace XCharts.Runtime var serie = chart.GetSerie(markLine.serieIndex); if (!serie.show || !markLine.show) return; ResetTempMarkLineGroupData(markLine); - var serieColor = (Color) chart.GetItemColor(serie); + var serieColor = (Color)chart.GetItemColor(serie); if (m_TempGroupData.Count > 0) { foreach (var kv in m_TempGroupData) @@ -71,15 +71,15 @@ namespace XCharts.Runtime private void InitMarkLineLabel(Serie serie, MarkLineData data, Color serieColor) { data.painter = chart.m_PainterUpper; - data.refreshComponent = delegate() + data.refreshComponent = delegate () { - var textName = string.Format("markLine_{0}_{1}", serie.index, data.index); + var textName = string.Format("markLine_{0}_{1}", component.index, data.index); var content = MarkLineHelper.GetFormatterContent(serie, data); var label = ChartHelper.AddChartLabel(textName, m_MarkLineLabelRoot.transform, data.label, chart.theme.axis, content, Color.clear, TextAnchor.MiddleCenter); var pos = MarkLineHelper.GetLabelPosition(data); label.SetIconActive(false); - label.SetActive(data.label.show && pos != Vector3.zero); + label.SetActive(data.label.show && data.runtimeInGrid); label.SetPosition(pos); data.runtimeLabel = label; }; @@ -154,7 +154,7 @@ namespace XCharts.Runtime sp = new Vector3(grid.context.x, pY); ep = new Vector3(grid.context.x + grid.context.width, pY); } - else if (data.yValue != 0) + else if (data.yValue != 0 || (data.xValue == 0 && data.yValue == 0 && yAxis.IsValue())) { data.runtimeValue = data.yValue; if (yAxis.IsCategory()) @@ -218,9 +218,17 @@ namespace XCharts.Runtime { if (!animation.IsFinish()) ep = Vector3.Lerp(sp, ep, animation.GetCurrDetail()); + if ((!chart.IsInChart(sp) && !chart.IsInChart(ep)) || + (serie.clip && !grid.Contains(sp) && !grid.Contains(ep))) + { + data.runtimeInGrid = false; + m_RefreshLabel = true; + return; + } data.runtimeCurrentEndPosition = ep; if (sp != Vector3.zero || ep != Vector3.zero) { + data.runtimeInGrid = true; m_RefreshLabel = true; chart.ClampInChart(ref sp); chart.ClampInChart(ref ep); @@ -247,7 +255,7 @@ namespace XCharts.Runtime Color32 borderColor; SerieHelper.GetSymbolInfo(out borderColor, out tickness, out cornerRadius, serie, null, chart.theme); chart.DrawClipSymbol(vh, symbol.type, symbol.size, tickness, pos, lineColor, lineColor, - ColorUtil.clearColor32, borderColor, symbol.gap, true, cornerRadius, grid, startPos); + ColorUtil.clearColor32, borderColor, symbol.gap, serie.clip, cornerRadius, grid, startPos); } private void GetStartEndPos(Axis xAxis, Axis yAxis, GridCoord grid, double value, ref Vector3 sp, ref Vector3 ep) diff --git a/Runtime/Component/Radar/RadarCoord.cs b/Runtime/Component/Radar/RadarCoord.cs index 250659af..72ff346f 100644 --- a/Runtime/Component/Radar/RadarCoord.cs +++ b/Runtime/Component/Radar/RadarCoord.cs @@ -109,6 +109,7 @@ namespace XCharts.Runtime [SerializeField] private bool m_ConnectCenter = false; [SerializeField] private bool m_LineGradient = true; [SerializeField][Since("v3.4.0")] private float m_StartAngle; + [SerializeField][Since("v3.8.0")] private int m_GridIndex = -1; [SerializeField] private List<Indicator> m_IndicatorList = new List<Indicator>(); public RadarCoordContext context = new RadarCoordContext(); @@ -120,6 +121,15 @@ namespace XCharts.Runtime /// </summary> public bool show { get { return m_Show; } set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetComponentDirty(); } } /// <summary> + /// Index of layout component that serie uses. Default is -1 means not use layout, otherwise use the first layout component. + /// |所使用的 layout 组件的 index。 默认为-1不指定index, 当为大于或等于0时, 为第一个layout组件的第index个格子。 + /// </summary> + public int gridIndex + { + get { return m_GridIndex; } + set { if (PropertyUtil.SetStruct(ref m_GridIndex, value)) SetVerticesDirty(); } + } + /// <summary> /// Radar render type, in which 'Polygon' and 'Circle' are supported. /// |雷达图绘制类型,支持 'Polygon' 和 'Circle'。 /// </summary> @@ -286,6 +296,7 @@ namespace XCharts.Runtime public override void SetDefaultValue() { m_Show = true; + m_GridIndex = -1; m_Shape = Shape.Polygon; m_Radius = 0.35f; m_SplitNumber = 5; @@ -341,9 +352,21 @@ namespace XCharts.Runtime return 0; } - internal void UpdateRadarCenter(Vector3 chartPosition, float chartWidth, float chartHeight) + internal void UpdateRadarCenter(BaseChart chart) { if (center.Length < 2) return; + var chartPosition = chart.chartPosition; + var chartWidth = chart.chartWidth; + var chartHeight = chart.chartHeight; + if (gridIndex >= 0) + { + var layout = chart.GetChartComponent<GridLayout>(0); + if (layout != null) + { + layout.UpdateRuntimeData(chart); + layout.UpdateGridContext(gridIndex, ref chartPosition, ref chartWidth, ref chartHeight); + } + } var centerX = center[0] <= 1 ? chartWidth * center[0] : center[0]; var centerY = center[1] <= 1 ? chartHeight * center[1] : center[1]; context.center = chartPosition + new Vector3(centerX, centerY); diff --git a/Runtime/Component/Radar/RadarCoordHandler.cs b/Runtime/Component/Radar/RadarCoordHandler.cs index 8de4db62..9301a0b3 100644 --- a/Runtime/Component/Radar/RadarCoordHandler.cs +++ b/Runtime/Component/Radar/RadarCoordHandler.cs @@ -39,7 +39,7 @@ namespace XCharts.Runtime radar.painter = chart.GetPainter(radar.index); radar.refreshComponent = delegate() { - radar.UpdateRadarCenter(chart.chartPosition, chart.chartWidth, chart.chartHeight); + radar.UpdateRadarCenter(chart); var radarObject = ChartHelper.AddObject("Radar" + radar.index, chart.transform, chart.chartMinAnchor, chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta); radar.gameObject = radarObject; @@ -53,7 +53,7 @@ namespace XCharts.Runtime var label = ChartHelper.AddChartLabel(objName, radarObject.transform, radar.axisName.labelStyle, chart.theme.common, radar.GetFormatterIndicatorContent(i), Color.clear, TextAnchor.MiddleCenter); - label.SetActive(radar.indicator && radar.axisName.labelStyle.show); + label.SetActive(radar.axisName.show && radar.indicator && radar.axisName.labelStyle.show); AxisHelper.AdjustCircleLabelPos(label, pos, radar.context.center, txtHig, radar.axisName.labelStyle.offset); } chart.RefreshBasePainter(); @@ -64,7 +64,7 @@ namespace XCharts.Runtime private void DrawRadarCoord(VertexHelper vh, RadarCoord radar) { if (!radar.show) return; - radar.UpdateRadarCenter(chart.chartPosition, chart.chartWidth, chart.chartHeight); + radar.UpdateRadarCenter(chart); if (radar.shape == RadarCoord.Shape.Circle) { DrawCricleRadar(vh, radar); diff --git a/Runtime/Component/Tooltip/Tooltip.cs b/Runtime/Component/Tooltip/Tooltip.cs index 9a823d71..eea09674 100644 --- a/Runtime/Component/Tooltip/Tooltip.cs +++ b/Runtime/Component/Tooltip/Tooltip.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; -using System.Text; using UnityEngine; using UnityEngine.UI; -using XUGL; namespace XCharts.Runtime { @@ -39,7 +37,12 @@ namespace XCharts.Runtime /// crosshair indicator, which is actually the shortcut of enable two axisPointers of two orthometric axes. /// |十字准星指示器。坐标轴显示Label和交叉线。 /// </summary> - Corss + Corss, + /// <summary> + /// Auto select indicator according to serie type. + /// |根据serie的类型自动选择显示指示器。 + /// </summary> + Auto } /// <summary> @@ -62,7 +65,12 @@ namespace XCharts.Runtime /// Trigger nothing. /// |什么都不触发。 /// </summary> - None + None, + /// <summary> + /// Auto select trigger according to serie type. + /// |根据serie的类型自动选择触发类型。 + /// </summary> + Auto } /// <summary> /// Position type. @@ -92,8 +100,8 @@ namespace XCharts.Runtime } [SerializeField] private bool m_Show = true; - [SerializeField] private Type m_Type; - [SerializeField] private Trigger m_Trigger = Trigger.Item; + [SerializeField] private Type m_Type = Type.Auto; + [SerializeField] private Trigger m_Trigger = Trigger.Auto; [SerializeField][Since("v3.3.0")] private Position m_Position = Position.Auto; [SerializeField] private string m_ItemFormatter; [SerializeField] private string m_TitleFormatter; @@ -429,7 +437,7 @@ namespace XCharts.Runtime /// |当前提示框所指示的数据项索引。 /// </summary> public List<int> runtimeDataIndex { get { return m_RuntimeDateIndex; } internal set { m_RuntimeDateIndex = value; } } - private List<int> m_RuntimeDateIndex = new List<int>() {-1, -1 }; + private List<int> m_RuntimeDateIndex = new List<int>() { -1, -1 }; /// <summary> /// Keep Tooltiop displayed at the top. @@ -569,12 +577,12 @@ namespace XCharts.Runtime public bool IsTriggerItem() { - return trigger == Trigger.Item; + return trigger == Trigger.Auto ? context.trigger == Trigger.Item : trigger == Trigger.Item; } public bool IsTriggerAxis() { - return trigger == Trigger.Axis; + return trigger == Trigger.Auto ? context.trigger == Trigger.Axis : trigger == Trigger.Axis; } public LabelStyle GetContentLabelStyle(int index) diff --git a/Runtime/Component/Tooltip/TooltipContext.cs b/Runtime/Component/Tooltip/TooltipContext.cs index f00c7d0b..e0674e3a 100644 --- a/Runtime/Component/Tooltip/TooltipContext.cs +++ b/Runtime/Component/Tooltip/TooltipContext.cs @@ -19,6 +19,8 @@ namespace XCharts.Runtime public float width; public float height; public float angle; + public Tooltip.Type type; + public Tooltip.Trigger trigger; public TooltipData data = new TooltipData(); } } \ No newline at end of file diff --git a/Runtime/Component/Tooltip/TooltipHandler.cs b/Runtime/Component/Tooltip/TooltipHandler.cs index c730a820..2aaa016e 100644 --- a/Runtime/Component/Tooltip/TooltipHandler.cs +++ b/Runtime/Component/Tooltip/TooltipHandler.cs @@ -57,9 +57,10 @@ namespace XCharts.Runtime if (com is Axis) { var axis = com as Axis; + var aligment = (com is AngleAxis) ? TextAnchor.MiddleCenter : axis.context.aligment; var labelName = ChartCached.GetComponentObjectName(axis); var item = ChartHelper.AddTooltipIndicatorLabel(component, labelName, m_LabelRoot.transform, - chart.theme, axis.context.aligment, axis.indicatorLabel); + chart.theme, aligment, axis.indicatorLabel); item.SetActive(false); m_IndicatorLabels[labelName] = item; } @@ -112,7 +113,7 @@ namespace XCharts.Runtime } } var containerSeries = ListPool<Serie>.Get(); - m_PointerContainer = GetPointerContainerAndSeries(tooltip, containerSeries); + UpdatePointerContainerAndSeriesAndTooltip(tooltip, ref containerSeries); if (containerSeries.Count > 0) { if (SetSerieTooltip(tooltip, containerSeries)) @@ -121,7 +122,7 @@ namespace XCharts.Runtime ListPool<Serie>.Release(containerSeries); if (!showTooltip) { - if (tooltip.type == Tooltip.Type.Corss && m_PointerContainer != null && m_PointerContainer.IsPointerEnter()) + if (tooltip.context.type == Tooltip.Type.Corss && m_PointerContainer != null && m_PointerContainer.IsPointerEnter()) { tooltip.SetActive(true); tooltip.SetContentActive(false); @@ -137,13 +138,17 @@ namespace XCharts.Runtime } } + private void UpdateTooltipTypeAndTrigger(Tooltip tootip) + { + } + private void UpdateTooltipIndicatorLabelText(Tooltip tooltip) { if (!tooltip.show) return; - if (tooltip.type == Tooltip.Type.None) return; + if (tooltip.context.type == Tooltip.Type.None) return; if (m_PointerContainer != null) { - if (tooltip.type == Tooltip.Type.Corss) + if (tooltip.context.type == Tooltip.Type.Corss) { if (m_PointerContainer is GridCoord) { @@ -210,13 +215,18 @@ namespace XCharts.Runtime label.color = textColor; else label.color = axis.indicatorLabel.background.color; - label.SetTextColor(Color.white); + + if (ChartHelper.IsClearColor(axis.indicatorLabel.textStyle.color)) + label.SetTextColor(Color.white); + else + label.SetTextColor(axis.indicatorLabel.textStyle.color); } - private ISerieContainer GetPointerContainerAndSeries(Tooltip tooltip, List<Serie> list) + private void UpdatePointerContainerAndSeriesAndTooltip(Tooltip tooltip, ref List<Serie> list) { list.Clear(); - ISerieContainer target = null; + m_PointerContainer = null; + var updateTooltipTypeAndTrigger = false; for (int i = chart.components.Count - 1; i >= 0; i--) { var component = chart.components[i]; @@ -231,6 +241,14 @@ namespace XCharts.Runtime (serie as INeedSerieContainer).containterInstanceId == component.instanceId && !serie.placeHolder) { + if (!updateTooltipTypeAndTrigger) + { + updateTooltipTypeAndTrigger = true; + tooltip.context.type = tooltip.type == Tooltip.Type.Auto ? + serie.context.tooltipType : tooltip.type; + tooltip.context.trigger = tooltip.trigger == Tooltip.Trigger.Auto ? + serie.context.tooltipTrigger : tooltip.trigger; + } var isTriggerAxis = tooltip.IsTriggerAxis(); if (container is GridCoord) { @@ -248,16 +266,16 @@ namespace XCharts.Runtime chart.RefreshTopPainter(); } } - target = container; + m_PointerContainer = container; } } } - return target; } private void UpdateAxisPointerDataIndex(Serie serie, XAxis xAxis, YAxis yAxis, GridCoord grid, bool isTriggerAxis) { serie.context.pointerAxisDataIndexs.Clear(); + if (xAxis == null || yAxis == null) return; if (serie is Heatmap) { GetSerieDataByXYAxis(serie, xAxis, yAxis); @@ -414,9 +432,10 @@ namespace XCharts.Runtime private bool SetSerieTooltip(Tooltip tooltip, Serie serie) { - if (tooltip.trigger == Tooltip.Trigger.None) return false; if (serie.context.pointerItemDataIndex < 0) return false; - + tooltip.context.type = tooltip.type == Tooltip.Type.Auto ? serie.context.tooltipType : tooltip.type; + tooltip.context.trigger = tooltip.trigger == Tooltip.Trigger.Auto ? serie.context.tooltipTrigger : tooltip.trigger; + if (tooltip.context.trigger == Tooltip.Trigger.None) return false; tooltip.context.data.param.Clear(); tooltip.context.data.title = serie.serieName; tooltip.context.pointer = chart.pointerPos; @@ -435,7 +454,7 @@ namespace XCharts.Runtime private bool SetSerieTooltip(Tooltip tooltip, List<Serie> series) { - if (tooltip.trigger == Tooltip.Trigger.None) + if (tooltip.context.trigger == Tooltip.Trigger.None) return false; if (series.Count <= 0) @@ -444,15 +463,16 @@ namespace XCharts.Runtime string category = null; var showCategory = false; var isTriggerByAxis = false; + var isTriggerByItem = false; var dataIndex = -1; tooltip.context.data.param.Clear(); tooltip.context.pointer = chart.pointerPos; if (m_PointerContainer is GridCoord) { - if (tooltip.trigger == Tooltip.Trigger.Axis) + GetAxisCategory(m_PointerContainer.index, ref dataIndex, ref category); + if (tooltip.context.trigger == Tooltip.Trigger.Axis) { isTriggerByAxis = true; - GetAxisCategory(m_PointerContainer.index, ref dataIndex, ref category); if (series.Count <= 1) { showCategory = true; @@ -461,12 +481,18 @@ namespace XCharts.Runtime else tooltip.context.data.title = category; } + else if (tooltip.context.trigger == Tooltip.Trigger.Item) + { + isTriggerByItem = true; + showCategory = series.Count <= 1; + } } for (int i = 0; i < series.Count; i++) { var serie = series[i]; if (!serie.show) continue; + if (isTriggerByItem && serie.context.pointerItemDataIndex < 0) continue; serie.context.isTriggerByAxis = isTriggerByAxis; if (isTriggerByAxis && dataIndex >= 0 && serie.context.pointerItemDataIndex < 0) serie.context.pointerItemDataIndex = dataIndex; @@ -497,7 +523,9 @@ namespace XCharts.Runtime var axis = component as Axis; if (axis.gridIndex == gridIndex && axis.IsCategory()) { - dataIndex = axis.context.dataZoomStartIndex + (int)axis.context.pointerValue; + dataIndex = double.IsNaN(axis.context.pointerValue) + ? axis.context.dataZoomStartIndex + : axis.context.dataZoomStartIndex + (int)axis.context.pointerValue; category = axis.GetData(dataIndex); return true; } @@ -509,7 +537,7 @@ namespace XCharts.Runtime private void DrawTooltipIndicator(VertexHelper vh, Tooltip tooltip) { if (!tooltip.show) return; - if (tooltip.type == Tooltip.Type.None) return; + if (tooltip.context.type == Tooltip.Type.None) return; if (!IsAnySerieNeedTooltip()) return; if (m_PointerContainer is GridCoord) { @@ -552,7 +580,7 @@ namespace XCharts.Runtime var dataZoom = chart.GetDataZoomOfAxis(xAxis); int dataCount = chart.series.Count > 0 ? chart.series[0].GetDataList(dataZoom).Count : 0; float splitWidth = AxisHelper.GetDataWidth(xAxis, grid.context.width, dataCount, dataZoom); - switch (tooltip.type) + switch (tooltip.context.type) { case Tooltip.Type.Corss: case Tooltip.Type.Line: @@ -566,7 +594,7 @@ namespace XCharts.Runtime Vector2 ep = new Vector2(pX, grid.context.y + grid.context.height); var lineColor = TooltipHelper.GetLineColor(tooltip, chart.theme.tooltip.lineColor); ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor); - if (tooltip.type == Tooltip.Type.Corss) + if (tooltip.context.type == Tooltip.Type.Corss) { sp = new Vector2(grid.context.x, chart.pointerPos.y); ep = new Vector2(grid.context.x + grid.context.width, chart.pointerPos.y); @@ -618,7 +646,7 @@ namespace XCharts.Runtime var dataZoom = chart.GetDataZoomOfAxis(yAxis); int dataCount = chart.series.Count > 0 ? chart.series[0].GetDataList(dataZoom).Count : 0; float splitWidth = AxisHelper.GetDataWidth(yAxis, grid.context.height, dataCount, dataZoom); - switch (tooltip.type) + switch (tooltip.context.type) { case Tooltip.Type.Corss: case Tooltip.Type.Line: @@ -630,7 +658,7 @@ namespace XCharts.Runtime Vector2 ep = new Vector2(grid.context.x + grid.context.width, pY); var lineColor = TooltipHelper.GetLineColor(tooltip, chart.theme.tooltip.lineColor); ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor); - if (tooltip.type == Tooltip.Type.Corss) + if (tooltip.context.type == Tooltip.Type.Corss) { sp = new Vector2(chart.pointerPos.x, grid.context.y); ep = new Vector2(chart.pointerPos.x, grid.context.y + grid.context.height); @@ -673,7 +701,7 @@ namespace XCharts.Runtime var sp = ChartHelper.GetPos(m_Polar.context.center, m_Polar.context.insideRadius, tooltipAngle, true); var ep = ChartHelper.GetPos(m_Polar.context.center, m_Polar.context.outsideRadius, tooltipAngle, true); - switch (tooltip.type) + switch (tooltip.context.type) { case Tooltip.Type.Corss: ChartDrawer.DrawLineStyle(vh, lineType, lineWidth, sp, ep, lineColor); diff --git a/Runtime/Component/Tooltip/TooltipView.cs b/Runtime/Component/Tooltip/TooltipView.cs index ba2d84bc..410cb1e9 100644 --- a/Runtime/Component/Tooltip/TooltipView.cs +++ b/Runtime/Component/Tooltip/TooltipView.cs @@ -72,8 +72,7 @@ namespace XCharts.Runtime var ignoreColumn = string.IsNullOrEmpty(tooltip.ignoreDataDefaultContent); var titleActive = !string.IsNullOrEmpty(data.title); - if (titleActive != title.gameObject.activeSelf) - title.gameObject.SetActive(titleActive); + ChartHelper.SetActive(title, titleActive); title.SetText(data.title); m_ColumnMaxWidth.Clear(); diff --git a/Runtime/Coord/Calendar/CalendarCoord.cs b/Runtime/Coord/Calendar/CalendarCoord.cs index 8d162105..28318ab6 100644 --- a/Runtime/Coord/Calendar/CalendarCoord.cs +++ b/Runtime/Coord/Calendar/CalendarCoord.cs @@ -12,7 +12,8 @@ namespace XCharts.Runtime return false; } - public void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight) - { } + public void UpdateRuntimeData(BaseChart chart) + { + } } } \ No newline at end of file diff --git a/Runtime/Coord/Grid/GridCoord.cs b/Runtime/Coord/Grid/GridCoord.cs index 9d4fe754..2e2760e1 100644 --- a/Runtime/Coord/Grid/GridCoord.cs +++ b/Runtime/Coord/Grid/GridCoord.cs @@ -16,6 +16,7 @@ namespace XCharts.Runtime public class GridCoord : CoordSystem, IUpdateRuntimeData, ISerieContainer { [SerializeField] private bool m_Show = true; + [SerializeField][Since("v3.8.0")] private int m_LayoutIndex = -1; [SerializeField] private float m_Left = 0.1f; [SerializeField] private float m_Right = 0.08f; [SerializeField] private float m_Top = 0.22f; @@ -37,6 +38,18 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); } } /// <summary> + /// The index of the grid layout component to which the grid belongs. + /// The default is -1, which means that it does not belong to any grid layout component. + /// When this value is set, the left, right, top, and bottom properties will be invalid. + /// |网格所属的网格布局组件的索引。默认为-1,表示不属于任何网格布局组件。当设置了该值时,left、right、top、bottom属性将失效。 + /// </summary> + /// <value></value> + public int layoutIndex + { + get { return m_LayoutIndex; } + set { if (PropertyUtil.SetStruct(ref m_LayoutIndex, value)) SetVerticesDirty(); } + } + /// <summary> /// Distance between grid component and the left side of the container. /// |grid 组件离容器左侧的距离。 /// </summary> @@ -109,53 +122,108 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetColor(ref m_BorderColor, value)) SetVerticesDirty(); } } + public void UpdateRuntimeData(BaseChart chart) + { + var chartX = chart.chartX; + var chartY = chart.chartY; + var chartWidth = chart.chartWidth; + var chartHeight = chart.chartHeight; + if (layoutIndex >= 0) + { + var layout = chart.GetChartComponent<GridLayout>(layoutIndex); + if (layout != null) + { + layout.UpdateRuntimeData(chart); + layout.UpdateGridContext(index, ref chartX, ref chartY, ref chartWidth, ref chartHeight); + } + } + var actualLeft = left <= 1 ? left * chartWidth : left; + var actualBottom = bottom <= 1 ? bottom * chartHeight : bottom; + var actualTop = top <= 1 ? top * chartHeight : top; + var actualRight = right <= 1 ? right * chartWidth : right; + context.x = chartX + actualLeft; + context.y = chartY + actualBottom; + context.width = chartWidth - actualLeft - actualRight; + context.height = chartHeight - actualTop - actualBottom; + context.position = new Vector3(context.x, context.y); + context.center = new Vector3(context.x + context.width / 2, context.y + context.height / 2); + } + + /// <summary> + /// Whether the pointer is in the grid. + /// |指针是否在网格内。 + /// </summary> + /// <returns></returns> public bool IsPointerEnter() { return context.isPointerEnter; } - public void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight) - { - context.left = left <= 1 ? left * chartWidth : left; - context.bottom = bottom <= 1 ? bottom * chartHeight : bottom; - context.top = top <= 1 ? top * chartHeight : top; - context.right = right <= 1 ? right * chartWidth : right; - context.x = chartX + context.left; - context.y = chartY + context.bottom; - context.width = chartWidth - context.left - context.right; - context.height = chartHeight - context.top - context.bottom; - context.position = new Vector3(context.x, context.y); - context.center = new Vector3(context.x + context.width / 2, context.y + context.height / 2); - } - + /// <summary> + /// Whether the given position is in the grid. + /// |给定的位置是否在网格内。 + /// </summary> + /// <param name="pos"></param> + /// <returns></returns> public bool Contains(Vector3 pos) { return Contains(pos.x, pos.y); } + /// <summary> + /// Whether the given position is in the grid. + /// |给定的位置是否在网格内。 + /// </summary> + /// <param name="pos"></param> + /// <param name="isYAxis"></param> + /// <returns></returns> [Since("v3.7.0")] public bool Contains(Vector3 pos, bool isYAxis) { return isYAxis ? ContainsY(pos.y) : ContainsX(pos.x); } + /// <summary> + /// Whether the given position is in the grid. + /// |给定的位置是否在网格内。 + /// </summary> + /// <param name="x"></param> + /// <param name="y"></param> + /// <returns></returns> public bool Contains(float x, float y) { return ContainsX(x) && ContainsY(y); } + /// <summary> + /// Whether the given x is in the grid. + /// |给定的x是否在网格内。 + /// </summary> + /// <param name="x"></param> + /// <returns></returns> [Since("v3.7.0")] public bool ContainsX(float x) { return x >= context.x && x <= context.x + context.width; } + /// <summary> + /// Whether the given y is in the grid. + /// |给定的y是否在网格内。 + /// </summary> + /// <param name="y"></param> + /// <returns></returns> [Since("v3.7.0")] public bool ContainsY(float y) { return y >= context.y && y <= context.y + context.height; } + /// <summary> + /// Clamp the position of pos to the grid. + /// |将位置限制在网格内。 + /// </summary> + /// <param name="pos"></param> [Since("v3.7.0")] public void Clamp(ref Vector3 pos) { @@ -163,6 +231,11 @@ namespace XCharts.Runtime ClampY(ref pos); } + /// <summary> + /// Clamp the x position of pos to the grid. + /// |将位置的X限制在网格内。 + /// </summary> + /// <param name="pos"></param> [Since("v3.7.0")] public void ClampX(ref Vector3 pos) { @@ -170,6 +243,11 @@ namespace XCharts.Runtime else if (pos.x > context.x + context.width) pos.x = context.x + context.width; } + /// <summary> + /// Clamp the y position of pos to the grid. + /// |将位置的Y限制在网格内。 + /// </summary> + /// <param name="pos"></param> [Since("v3.7.0")] public void ClampY(ref Vector3 pos) { diff --git a/Runtime/Coord/Grid/GridCoordContext.cs b/Runtime/Coord/Grid/GridCoordContext.cs index be4ac7a7..5f794d7e 100644 --- a/Runtime/Coord/Grid/GridCoordContext.cs +++ b/Runtime/Coord/Grid/GridCoordContext.cs @@ -11,10 +11,6 @@ namespace XCharts.Runtime public float height; public Vector3 position; public Vector3 center; - public float left; - public float right; - public float bottom; - public float top; public bool isPointerEnter; public List<ChartLabel> endLabelList = new List<ChartLabel>(); } diff --git a/Runtime/Coord/Grid/GridCoordHandler.cs b/Runtime/Coord/Grid/GridCoordHandler.cs index cf37bad7..b38b769e 100644 --- a/Runtime/Coord/Grid/GridCoordHandler.cs +++ b/Runtime/Coord/Grid/GridCoordHandler.cs @@ -1,4 +1,3 @@ -using System; using System.Text; using UnityEngine; using UnityEngine.UI; @@ -15,7 +14,7 @@ namespace XCharts.Runtime grid.painter = chart.painter; grid.refreshComponent = delegate() { - grid.UpdateRuntimeData(chart.chartX, chart.chartY, chart.chartWidth, chart.chartHeight); + grid.UpdateRuntimeData(chart); chart.OnCoordinateChanged(); }; grid.refreshComponent(); diff --git a/Runtime/Coord/Grid/GridLayoutContext.cs b/Runtime/Coord/Grid/GridLayoutContext.cs new file mode 100644 index 00000000..bc107bac --- /dev/null +++ b/Runtime/Coord/Grid/GridLayoutContext.cs @@ -0,0 +1,12 @@ +namespace XCharts.Runtime +{ + public class GridLayoutContext : MainComponentContext + { + public float x; + public float y; + public float width; + public float height; + public float eachWidth; + public float eachHeight; + } +} \ No newline at end of file diff --git a/Runtime/Coord/Grid/GridLayoutContext.cs.meta b/Runtime/Coord/Grid/GridLayoutContext.cs.meta new file mode 100644 index 00000000..20a58689 --- /dev/null +++ b/Runtime/Coord/Grid/GridLayoutContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7265c042ebd33458eb12c112d46d9a60 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Coord/Grid/GridLayoutHandler.cs b/Runtime/Coord/Grid/GridLayoutHandler.cs new file mode 100644 index 00000000..3df8623c --- /dev/null +++ b/Runtime/Coord/Grid/GridLayoutHandler.cs @@ -0,0 +1,7 @@ +namespace XCharts.Runtime +{ + [UnityEngine.Scripting.Preserve] + internal sealed class GridLayoutHandler : MainComponentHandler<GridLayout> + { + } +} \ No newline at end of file diff --git a/Runtime/Coord/Grid/GridLayoutHandler.cs.meta b/Runtime/Coord/Grid/GridLayoutHandler.cs.meta new file mode 100644 index 00000000..87a7842e --- /dev/null +++ b/Runtime/Coord/Grid/GridLayoutHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b1c1f0fa475b484286b0b2c688dc3c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Coord/Grid/XGridLayout.cs b/Runtime/Coord/Grid/XGridLayout.cs new file mode 100644 index 00000000..3a28fba3 --- /dev/null +++ b/Runtime/Coord/Grid/XGridLayout.cs @@ -0,0 +1,148 @@ +using System; +using UnityEngine; + +namespace XCharts.Runtime +{ + /// <summary> + /// Grid layout component. Used to manage the layout of multiple `GridCoord`, and the number of rows and columns of the grid can be controlled by `row` and `column`. + /// |网格布局组件。用于管理多个`GridCoord`的布局,可以通过`row`和`column`来控制网格的行列数。 + /// </summary> + [Since("v3.8.0")] + [Serializable] + [ComponentHandler(typeof(GridLayoutHandler), true)] + public class GridLayout : MainComponent, IUpdateRuntimeData + { + [SerializeField] private bool m_Show = true; + [SerializeField] private float m_Left = 0.1f; + [SerializeField] private float m_Right = 0.08f; + [SerializeField] private float m_Top = 0.22f; + [SerializeField] private float m_Bottom = 0.12f; + [SerializeField] private int m_Row = 2; + [SerializeField] private int m_Column = 2; + [SerializeField] private Vector2 m_Spacing = Vector2.zero; + [SerializeField] protected bool m_Inverse = false; + + public GridLayoutContext context = new GridLayoutContext(); + + /// <summary> + /// Whether to show the grid in rectangular coordinate. + /// |是否显示直角坐标系网格。 + /// </summary> + public bool show + { + get { return m_Show; } + set { if (PropertyUtil.SetStruct(ref m_Show, value)) SetVerticesDirty(); } + } + /// <summary> + /// Distance between grid component and the left side of the container. + /// |grid 组件离容器左侧的距离。 + /// </summary> + public float left + { + get { return m_Left; } + set { if (PropertyUtil.SetStruct(ref m_Left, value)) SetAllDirty(); } + } + /// <summary> + /// Distance between grid component and the right side of the container. + /// |grid 组件离容器右侧的距离。 + /// </summary> + public float right + { + get { return m_Right; } + set { if (PropertyUtil.SetStruct(ref m_Right, value)) SetAllDirty(); } + } + /// <summary> + /// Distance between grid component and the top side of the container. + /// |grid 组件离容器上侧的距离。 + /// </summary> + public float top + { + get { return m_Top; } + set { if (PropertyUtil.SetStruct(ref m_Top, value)) SetAllDirty(); } + } + /// <summary> + /// Distance between grid component and the bottom side of the container. + /// |grid 组件离容器下侧的距离。 + /// </summary> + public float bottom + { + get { return m_Bottom; } + set { if (PropertyUtil.SetStruct(ref m_Bottom, value)) SetAllDirty(); } + } + /// <summary> + /// the row count of grid layout. + /// |网格布局的行数。 + /// </summary> + public int row + { + get { return m_Row; } + set { if (PropertyUtil.SetStruct(ref m_Row, value)) SetAllDirty(); } + } + /// <summary> + /// the column count of grid layout. + /// |网格布局的列数。 + /// </summary> + public int column + { + get { return m_Column; } + set { if (PropertyUtil.SetStruct(ref m_Column, value)) SetAllDirty(); } + } + /// <summary> + /// the spacing of grid layout. + /// |网格布局的间距。 + /// </summary> + public Vector2 spacing + { + get { return m_Spacing; } + set { if (PropertyUtil.SetStruct(ref m_Spacing, value)) SetAllDirty(); } + } + /// <summary> + /// Whether to inverse the grid layout. + /// |是否反转网格布局。 + /// </summary> + public bool inverse + { + get { return m_Inverse; } + set { if (PropertyUtil.SetStruct(ref m_Inverse, value)) SetAllDirty(); } + } + + public void UpdateRuntimeData(BaseChart chart) + { + var chartX = chart.chartX; + var chartY = chart.chartY; + var chartWidth = chart.chartWidth; + var chartHeight = chart.chartHeight; + var actualLeft = left <= 1 ? left * chartWidth : left; + var actualBottom = bottom <= 1 ? bottom * chartHeight : bottom; + var actualTop = top <= 1 ? top * chartHeight : top; + var actualRight = right <= 1 ? right * chartWidth : right; + context.x = chartX + actualLeft; + context.y = chartY + actualBottom; + context.width = chartWidth - actualLeft - actualRight; + context.height = chartHeight - actualTop - actualBottom; + context.eachWidth = (context.width - spacing.x * (column - 1)) / column; + context.eachHeight = (context.height - spacing.y * (row - 1)) / row; + } + + internal void UpdateGridContext(int index, ref float x, ref float y, ref float width, ref float height) + { + var row = index / m_Column; + var column = index % m_Column; + + x = context.x + column * (context.eachWidth + spacing.x); + if(m_Inverse) + y = context.y + row * (context.eachHeight + spacing.y); + else + y = context.y + context.height - (row + 1) * context.eachHeight - row * spacing.y; + width = context.eachWidth; + height = context.eachHeight; + } + + internal void UpdateGridContext(int index, ref Vector3 position, ref float width, ref float height) + { + float x = 0, y = 0; + UpdateGridContext(index, ref x, ref y, ref width, ref height); + position = new Vector3(x, y); + } + } +} \ No newline at end of file diff --git a/Runtime/Coord/Grid/XGridLayout.cs.meta b/Runtime/Coord/Grid/XGridLayout.cs.meta new file mode 100644 index 00000000..84093dae --- /dev/null +++ b/Runtime/Coord/Grid/XGridLayout.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 691ae1f57760b4a948c94f3faa0ef6f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Coord/Parallel/ParallelCoord.cs b/Runtime/Coord/Parallel/ParallelCoord.cs index 73147bc5..ebcc2186 100644 --- a/Runtime/Coord/Parallel/ParallelCoord.cs +++ b/Runtime/Coord/Parallel/ParallelCoord.cs @@ -92,8 +92,12 @@ namespace XCharts.Runtime return context.runtimeIsPointerEnter; } - public void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight) + public void UpdateRuntimeData(BaseChart chart) { + var chartX = chart.chartX; + var chartY = chart.chartY; + var chartWidth = chart.chartWidth; + var chartHeight = chart.chartHeight; context.left = left <= 1 ? left * chartWidth : left; context.bottom = bottom <= 1 ? bottom * chartHeight : bottom; context.top = top <= 1 ? top * chartHeight : top; diff --git a/Runtime/Coord/Parallel/ParallelCoordHandler.cs b/Runtime/Coord/Parallel/ParallelCoordHandler.cs index 7e68ada6..05e1b607 100644 --- a/Runtime/Coord/Parallel/ParallelCoordHandler.cs +++ b/Runtime/Coord/Parallel/ParallelCoordHandler.cs @@ -20,7 +20,7 @@ namespace XCharts.Runtime grid.painter = chart.painter; grid.refreshComponent = delegate() { - grid.UpdateRuntimeData(chart.chartX, chart.chartY, chart.chartWidth, chart.chartHeight); + grid.UpdateRuntimeData(chart); chart.OnCoordinateChanged(); }; grid.refreshComponent(); diff --git a/Runtime/Coord/Polar/PolarCoord.cs b/Runtime/Coord/Polar/PolarCoord.cs index a68ea39c..7d185f96 100644 --- a/Runtime/Coord/Polar/PolarCoord.cs +++ b/Runtime/Coord/Polar/PolarCoord.cs @@ -16,6 +16,7 @@ namespace XCharts.Runtime [SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.45f }; [SerializeField] private float[] m_Radius = new float[2] { 0, 0.35f }; [SerializeField] private Color m_BackgroundColor; + [SerializeField][Since("v3.8.0")] private float m_IndicatorLabelOffset = 30f; public PolarCoordContext context = new PolarCoordContext(); @@ -58,6 +59,16 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetColor(ref m_BackgroundColor, value)) SetVerticesDirty(); } } + /// <summary> + /// The offset of indicator label. + /// |指示器标签的偏移量。 + /// </summary> + public float indicatorLabelOffset + { + get { return m_IndicatorLabelOffset; } + set { if (PropertyUtil.SetStruct(ref m_IndicatorLabelOffset, value)) SetVerticesDirty(); } + } + public bool IsPointerEnter() { return context.isPointerEnter; diff --git a/Runtime/Internal/Attributes/DefaultAnimationAttribute.cs b/Runtime/Internal/Attributes/DefaultAnimationAttribute.cs index d6807612..f8b06461 100644 --- a/Runtime/Internal/Attributes/DefaultAnimationAttribute.cs +++ b/Runtime/Internal/Attributes/DefaultAnimationAttribute.cs @@ -6,10 +6,17 @@ namespace XCharts.Runtime public sealed class DefaultAnimationAttribute : Attribute { public readonly AnimationType type; + public readonly bool enableSerieDataAddedAnimation = true; public DefaultAnimationAttribute(AnimationType handler) { this.type = handler; } + + public DefaultAnimationAttribute(AnimationType handler, bool enableSerieDataAddedAnimation) + { + this.type = handler; + this.enableSerieDataAddedAnimation = enableSerieDataAddedAnimation; + } } } \ No newline at end of file diff --git a/Runtime/Internal/Attributes/DefaultTooltipAttribute.cs b/Runtime/Internal/Attributes/DefaultTooltipAttribute.cs new file mode 100644 index 00000000..c5eaff30 --- /dev/null +++ b/Runtime/Internal/Attributes/DefaultTooltipAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace XCharts.Runtime +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public sealed class DefaultTooltipAttribute : Attribute + { + public readonly Tooltip.Type type; + public readonly Tooltip.Trigger trigger; + + public DefaultTooltipAttribute(Tooltip.Type type, Tooltip.Trigger trigger) + { + this.type = type; + this.trigger = trigger; + } + } +} \ No newline at end of file diff --git a/Runtime/Internal/Attributes/DefaultTooltipAttribute.cs.meta b/Runtime/Internal/Attributes/DefaultTooltipAttribute.cs.meta new file mode 100644 index 00000000..0aa04329 --- /dev/null +++ b/Runtime/Internal/Attributes/DefaultTooltipAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a994dc47021bb4031ba6cf23eaf82e7e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Internal/BaseChart.API.cs b/Runtime/Internal/BaseChart.API.cs index e999614b..c1d4de97 100644 --- a/Runtime/Internal/BaseChart.API.cs +++ b/Runtime/Internal/BaseChart.API.cs @@ -183,8 +183,6 @@ namespace XCharts.Runtime /// </summary> public void RefreshChart() { - foreach (var serie in m_Series) - serie.ResetInteract(); m_RefreshChart = true; if (m_Painter) m_Painter.Refresh(); foreach (var painter in m_PainterList) painter.Refresh(); @@ -213,7 +211,7 @@ namespace XCharts.Runtime public void RefreshChart(Serie serie) { if (serie == null) return; - serie.ResetInteract(); + // serie.ResetInteract(); RefreshPainter(serie); } @@ -382,8 +380,8 @@ namespace XCharts.Runtime } /// <summary> - /// Whether series animation enabel. - /// |启用或关闭起始动画。 + /// Whether enable serie animations. + /// |是否启用Serie动画。 /// </summary> /// <param name="flag"></param> public void AnimationEnable(bool flag) @@ -392,19 +390,19 @@ namespace XCharts.Runtime } /// <summary> - /// fadeIn animation. - /// |开始渐入动画。 + /// Start all serie fadein animations. + /// |开始所有Serie的渐入动画。 /// </summary> + /// <param name="reset">reset animation</param> public void AnimationFadeIn(bool reset = true) { - if (reset) - AnimationReset(); + if (reset) AnimationReset(); foreach (var serie in m_Series) serie.AnimationFadeIn(); } /// <summary> - /// fadeIn animation. - /// |开始渐出动画。 + /// Start all serie fadeout animations. + /// |开始所有Serie的渐出动画。 /// </summary> public void AnimationFadeOut() { @@ -412,8 +410,8 @@ namespace XCharts.Runtime } /// <summary> - /// Pause animation. - /// |暂停动画。 + /// Pause all animations. + /// |暂停所有Serie的动画。 /// </summary> public void AnimationPause() { @@ -421,8 +419,8 @@ namespace XCharts.Runtime } /// <summary> - /// Stop play animation. - /// |继续动画。 + /// Resume all animations. + /// |继续所有Serie的动画。 /// </summary> public void AnimationResume() { @@ -430,8 +428,8 @@ namespace XCharts.Runtime } /// <summary> - /// Reset animation. - /// |重置动画。 + /// Reset all animations. + /// |重置所有Serie的动画。 /// </summary> public void AnimationReset() { diff --git a/Runtime/Internal/BaseChart.Component.cs b/Runtime/Internal/BaseChart.Component.cs index 1d009716..4a895b8f 100644 --- a/Runtime/Internal/BaseChart.Component.cs +++ b/Runtime/Internal/BaseChart.Component.cs @@ -66,7 +66,7 @@ namespace XCharts.Runtime } component.SetDefaultValue(); if (component is IUpdateRuntimeData) - (component as IUpdateRuntimeData).UpdateRuntimeData(chartX, chartY, chartWidth, chartHeight); + (component as IUpdateRuntimeData).UpdateRuntimeData(this); AddComponent(component); m_Components.Sort(); CreateComponentHandler(component); @@ -248,7 +248,11 @@ namespace XCharts.Runtime public List<MainComponent> GetChartComponents<T>() where T : MainComponent { - return m_ComponentMaps[typeof(T)]; + var type = typeof(T); + if (m_ComponentMaps.ContainsKey(type)) + return m_ComponentMaps[type]; + else + return null; } [Obsolete("'GetOrAddChartComponent' is obsolete, Use 'EnsureChartComponent' instead.")] diff --git a/Runtime/Internal/BaseChart.Serie.cs b/Runtime/Internal/BaseChart.Serie.cs index 282e5da5..2f6bf388 100644 --- a/Runtime/Internal/BaseChart.Serie.cs +++ b/Runtime/Internal/BaseChart.Serie.cs @@ -782,7 +782,7 @@ namespace XCharts.Runtime for (int i = 0; i < m_Series.Count; i++) { var serie = m_Series[i]; - if (serie is T) + if (serie.show && serie is T) { if (serie.barGap != 0) { @@ -935,6 +935,7 @@ namespace XCharts.Runtime for (int i = 0; i < m_Series.Count; i++) { var serie = m_Series[i]; + if (!serie.show) continue; if (!(serie is T)) continue; if (string.IsNullOrEmpty(serie.stack)) { @@ -975,13 +976,22 @@ namespace XCharts.Runtime if (serie == null) throw new ArgumentNullException("serie is null"); + if (serie.GetType().IsDefined(typeof(DefaultTooltipAttribute), false)) + { + var attribute1 = serie.GetType().GetAttribute<DefaultTooltipAttribute>(); + if (attribute1 != null) + { + serie.context.tooltipTrigger = attribute1.trigger; + serie.context.tooltipType = attribute1.type; + } + } if (!serie.GetType().IsDefined(typeof(SerieHandlerAttribute), false)) { Debug.LogError("Serie no Handler:" + serie.GetType()); return; } var attribute = serie.GetType().GetAttribute<SerieHandlerAttribute>(); - var handler = (SerieHandler) Activator.CreateInstance(attribute.handler); + var handler = (SerieHandler)Activator.CreateInstance(attribute.handler); handler.attribute = attribute; handler.chart = this; handler.defaultDimension = 1; diff --git a/Runtime/Internal/BaseChart.cs b/Runtime/Internal/BaseChart.cs index 80964be9..e991ceb9 100644 --- a/Runtime/Internal/BaseChart.cs +++ b/Runtime/Internal/BaseChart.cs @@ -25,6 +25,8 @@ namespace XCharts.Runtime [SerializeField][ListForComponent(typeof(Background))] private List<Background> m_Backgrounds = new List<Background>(); [SerializeField][ListForComponent(typeof(DataZoom))] private List<DataZoom> m_DataZooms = new List<DataZoom>(); [SerializeField][ListForComponent(typeof(GridCoord))] private List<GridCoord> m_Grids = new List<GridCoord>(); + [SerializeField][ListForComponent(typeof(GridLayout))] private List<GridLayout> m_GridsLayout = new List<GridLayout>(); + [SerializeField][ListForComponent(typeof(Legend))] private List<Legend> m_Legends = new List<Legend>(); [SerializeField][ListForComponent(typeof(MarkLine))] private List<MarkLine> m_MarkLines = new List<MarkLine>(); [SerializeField][ListForComponent(typeof(MarkArea))] private List<MarkArea> m_MarkAreas = new List<MarkArea>(); @@ -144,10 +146,9 @@ namespace XCharts.Runtime { RemoveAllChartComponent(); OnBeforeSerialize(); - AddChartComponentWhenNoExist<Title>(); - AddChartComponentWhenNoExist<Tooltip>(); - - GetChartComponent<Title>().text = GetType().Name; + EnsureChartComponent<Title>(); + EnsureChartComponent<Tooltip>(); + EnsureChartComponent<Title>().text = GetType().Name; if (m_Theme.sharedTheme != null) m_Theme.sharedTheme.CopyTheme(ThemeType.Default); @@ -172,6 +173,12 @@ namespace XCharts.Runtime DefaultChart(); Awake(); } + + protected override void OnValidate() + { + base.OnValidate(); + foreach (var handler in m_SerieHandlers) handler.ForceUpdateSerieContext(); + } #endif protected override void Start() @@ -186,7 +193,9 @@ namespace XCharts.Runtime CheckPainter(); CheckRefreshChart(); Internal_CheckAnimation(); + foreach (var handler in m_SerieHandlers) handler.BeforeUpdate(); foreach (var handler in m_SerieHandlers) handler.Update(); + foreach (var handler in m_SerieHandlers) handler.AfterUpdate(); foreach (var handler in m_ComponentHandlers) handler.Update(); m_DebugInfo.Update(); if (m_OnUpdate != null) @@ -315,6 +324,8 @@ namespace XCharts.Runtime protected override void OnDestroy() { + base.OnDestroy(); + XChartsMgr.RemoveChart(chartName); for (int i = transform.childCount - 1; i >= 0; i--) { DestroyImmediate(transform.GetChild(i).gameObject); @@ -450,7 +461,7 @@ namespace XCharts.Runtime if (component is Axis) component.SetAllDirty(); if (component is IUpdateRuntimeData) - (component as IUpdateRuntimeData).UpdateRuntimeData(m_ChartX, m_ChartY, m_ChartWidth, m_ChartHeight); + (component as IUpdateRuntimeData).UpdateRuntimeData(this); } } @@ -592,8 +603,6 @@ namespace XCharts.Runtime serie.animation.context.isAllItemAnimationEnd = true; if (serie.show && !serie.animation.HasFadeOut()) { - if (!serie.context.pointerEnter) - serie.ResetInteract(); if (m_OnDrawSerieBefore != null) { m_OnDrawSerieBefore.Invoke(vh, serie); diff --git a/Runtime/Internal/BaseGraph.cs b/Runtime/Internal/BaseGraph.cs index 8e1a8bca..c723a829 100644 --- a/Runtime/Internal/BaseGraph.cs +++ b/Runtime/Internal/BaseGraph.cs @@ -127,16 +127,21 @@ namespace XCharts.Runtime } #if UNITY_EDITOR - protected override void Reset() { } + protected override void Reset() + { + base.Reset(); + } protected override void OnValidate() { + base.OnValidate(); m_IsOnValidate = true; } #endif protected override void OnDestroy() { + base.OnDestroy(); for (int i = transform.childCount - 1; i >= 0; i--) { DestroyImmediate(transform.GetChild(i).gameObject); diff --git a/Runtime/Internal/Misc/IUpdateRuntimeData.cs b/Runtime/Internal/Misc/IUpdateRuntimeData.cs index c1d7f0fc..cf4c0191 100644 --- a/Runtime/Internal/Misc/IUpdateRuntimeData.cs +++ b/Runtime/Internal/Misc/IUpdateRuntimeData.cs @@ -6,6 +6,6 @@ namespace XCharts.Runtime { public interface IUpdateRuntimeData { - void UpdateRuntimeData(float chartX, float chartY, float chartWidth, float chartHeight); + void UpdateRuntimeData(BaseChart chart); } } \ No newline at end of file diff --git a/Runtime/Internal/Object/ChartLabel.cs b/Runtime/Internal/Object/ChartLabel.cs index 89ff9ee3..50d685e7 100644 --- a/Runtime/Internal/Object/ChartLabel.cs +++ b/Runtime/Internal/Object/ChartLabel.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using UnityEngine.UI; namespace XCharts.Runtime @@ -56,6 +56,7 @@ namespace XCharts.Runtime protected override void Awake() { raycastTarget = false; + SetActive(true); } public void SetTextPadding(TextPadding padding) @@ -129,7 +130,7 @@ namespace XCharts.Runtime if (m_IconRect != null) m_IconRect.sizeDelta = new Vector3(width, height); } - public void UpdateIcon(IconStyle iconStyle, Sprite sprite = null) + public void UpdateIcon(IconStyle iconStyle, Sprite sprite = null, Color color = default(Color)) { if (m_IconImage == null || iconStyle == null) return; @@ -138,7 +139,7 @@ namespace XCharts.Runtime if (iconStyle.show) { m_IconImage.sprite = sprite == null ? iconStyle.sprite : sprite; - m_IconImage.color = iconStyle.color; + m_IconImage.color = ChartHelper.IsClearColor(iconStyle.color) ? color : iconStyle.color; m_IconImage.type = iconStyle.type; m_IconRect.sizeDelta = new Vector2(iconStyle.width, iconStyle.height); m_IconOffest = iconStyle.offset; @@ -194,7 +195,7 @@ namespace XCharts.Runtime return transform.localPosition; } - public override bool IsActive() + public bool IsActiveByScale() { return m_Active; } diff --git a/Runtime/Internal/Utilities/ChartDrawer.cs b/Runtime/Internal/Utilities/ChartDrawer.cs index 69b7e2c5..c6cfbf9b 100644 --- a/Runtime/Internal/Utilities/ChartDrawer.cs +++ b/Runtime/Internal/Utilities/ChartDrawer.cs @@ -49,53 +49,104 @@ namespace XCharts.Runtime { if (tickness > 0) { - UGL.DrawRoundRectangle(vh, pos, symbolSize, symbolSize, color, color, 0, cornerRadius, true); + UGL.DrawRoundRectangle(vh, pos, symbolSize * 2, symbolSize * 2, color, color, 0, cornerRadius, true); UGL.DrawBorder(vh, pos, symbolSize, symbolSize, tickness, borderColor, 0, cornerRadius); } else - UGL.DrawRoundRectangle(vh, pos, symbolSize, symbolSize, color, color, 0, cornerRadius, true); + UGL.DrawRoundRectangle(vh, pos, symbolSize * 2, symbolSize * 2, color, color, 0, cornerRadius, true); } break; case SymbolType.EmptyRect: if (gap > 0) { UGL.DrawSquare(vh, pos, symbolSize + gap, backgroundColor); - UGL.DrawBorder(vh, pos, symbolSize / 2, symbolSize / 2, tickness, color); + UGL.DrawBorder(vh, pos, symbolSize * 2, symbolSize * 2, tickness, color); } else { - UGL.DrawBorder(vh, pos, symbolSize / 2, symbolSize / 2, tickness, color); + UGL.DrawBorder(vh, pos, symbolSize * 2 - tickness * 2, symbolSize * 2 - tickness * 2, tickness, color); } break; case SymbolType.Triangle: + case SymbolType.EmptyTriangle: if (gap > 0) { - UGL.DrawTriangle(vh, pos, symbolSize + gap, backgroundColor); - UGL.DrawTriangle(vh, pos, symbolSize, color, toColor); + UGL.DrawEmptyTriangle(vh, pos, symbolSize * 1.4f + gap * 2, gap * 2, backgroundColor); + } + if (type == SymbolType.EmptyTriangle) + { + UGL.DrawEmptyTriangle(vh, pos, symbolSize * 1.4f, tickness * 2f, color, emptyColor); } else { - UGL.DrawTriangle(vh, pos, symbolSize, color, toColor); + UGL.DrawTriangle(vh, pos, symbolSize * 1.4f, color, toColor); } break; case SymbolType.Diamond: + case SymbolType.EmptyDiamond: + var xRadius = symbolSize; + var yRadius = symbolSize * 1.5f; if (gap > 0) { - UGL.DrawDiamond(vh, pos, symbolSize + gap, backgroundColor); - UGL.DrawDiamond(vh, pos, symbolSize, color, toColor); + UGL.DrawEmptyDiamond(vh, pos, xRadius + gap, yRadius + gap, gap, backgroundColor); + } + if (type == SymbolType.EmptyDiamond) + { + UGL.DrawEmptyDiamond(vh, pos, xRadius, yRadius, tickness, color, emptyColor); } else { - UGL.DrawDiamond(vh, pos, symbolSize, color, toColor); + UGL.DrawDiamond(vh, pos, xRadius, yRadius, color, toColor); } break; case SymbolType.Arrow: + case SymbolType.EmptyArrow: var arrowWidth = symbolSize * 2; var arrowHeight = arrowWidth * 1.5f; var arrowOffset = 0; var arrowDent = arrowWidth / 3.3f; + if (gap > 0) + { + arrowWidth = (symbolSize + gap) * 2; + arrowHeight = arrowWidth * 1.5f; + arrowOffset = 0; + arrowDent = arrowWidth / 3.3f; + var dir = (pos - startPos).normalized; + var sharpPos = pos + gap * dir; + UGL.DrawArrow(vh, startPos, sharpPos, arrowWidth, arrowHeight, + arrowOffset, arrowDent, backgroundColor); + } + arrowWidth = symbolSize * 2; + arrowHeight = arrowWidth * 1.5f; + arrowOffset = 0; + arrowDent = arrowWidth / 3.3f; UGL.DrawArrow(vh, startPos, pos, arrowWidth, arrowHeight, arrowOffset, arrowDent, color); + if (type == SymbolType.EmptyArrow) + { + arrowWidth = (symbolSize - tickness) * 2; + arrowHeight = arrowWidth * 1.5f; + arrowOffset = 0; + arrowDent = arrowWidth / 3.3f; + var dir = (pos - startPos).normalized; + var sharpPos = pos - tickness * dir; + UGL.DrawArrow(vh, startPos, sharpPos, arrowWidth, arrowHeight, + arrowOffset, arrowDent, backgroundColor); + } + break; + case SymbolType.Plus: + if (gap > 0) + { + UGL.DrawPlus(vh, pos, symbolSize + gap, tickness + gap, backgroundColor); + } + UGL.DrawPlus(vh, pos, symbolSize, tickness, color); + break; + case SymbolType.Minus: + if (gap > 0) + { + UGL.DrawMinus(vh, pos, symbolSize + gap, tickness + gap, backgroundColor); + } + UGL.DrawMinus(vh, pos, symbolSize, tickness, color); break; } } diff --git a/Runtime/Internal/Utilities/ChartHelper.cs b/Runtime/Internal/Utilities/ChartHelper.cs index da84ae41..c32f6a88 100644 --- a/Runtime/Internal/Utilities/ChartHelper.cs +++ b/Runtime/Internal/Utilities/ChartHelper.cs @@ -273,7 +273,7 @@ namespace XCharts.Runtime chartText = new ChartText(); #if dUI_TextMeshPro RemoveComponent<Text>(txtObj); - chartText.tmpText = GetOrAddComponent<TextMeshProUGUI>(txtObj); + chartText.tmpText = EnsureComponent<TextMeshProUGUI>(txtObj); chartText.tmpText.font = textStyle.tmpFont == null ? theme.tmpFont : textStyle.tmpFont; chartText.tmpText.fontStyle = textStyle.tmpFontStyle; chartText.tmpText.richText = true; @@ -370,12 +370,12 @@ namespace XCharts.Runtime public static ChartLabel AddAxisLabelObject(int total, int index, string name, Transform parent, Vector2 sizeDelta, Axis axis, ComponentTheme theme, - string content, Color autoColor, TextAnchor autoAlignment = TextAnchor.MiddleCenter) + string content, Color autoColor, TextAnchor autoAlignment = TextAnchor.MiddleCenter, Color32 iconDefaultColor = default(Color32)) { var textStyle = axis.axisLabel.textStyle; var label = AddChartLabel(name, parent, axis.axisLabel, theme, content, autoColor, autoAlignment); var labelShow = axis.IsNeedShowLabel(index, total); - label.UpdateIcon(axis.axisLabel.icon, axis.GetIcon(index)); + label.UpdateIcon(axis.axisLabel.icon, axis.GetIcon(index), iconDefaultColor); label.text.SetActive(labelShow); return label; } @@ -682,19 +682,11 @@ namespace XCharts.Runtime public static double GetMaxDivisibleValue(double max, double ceilRate) { if (max == 0) return 0; + double pow = 1; if (max > -1 && max < 1) { - int count = 1; - int intvalue = (int)(max * Mathf.Pow(10, count)); - while (intvalue == 0 && count < 12) - { - count++; - intvalue = (int)(max * Mathf.Pow(10, count)); - } - var pow = Mathf.Pow(10, count); - var value = max > 0 ? (int)((max * (pow + 1))) / pow : - (int)((max * (pow - 1))) / pow; - return GetMaxCeilRate(value, ceilRate); + pow = Mathf.Pow(10, MathUtil.GetPrecision(max)); + max *= pow; } if (ceilRate == 0) { @@ -720,11 +712,11 @@ namespace XCharts.Runtime if (mmm >= (powmax - pown) && mmm < powmax) mmm = powmax; if (max < 0) return -Math.Ceiling(mmm > -max ? mmm : mm); - else return Math.Ceiling(mmm > max ? mmm : mm); + else return Math.Ceiling(mmm > max ? mmm : mm) / pow; } else { - return GetMaxCeilRate(max, ceilRate); + return GetMaxCeilRate(max, ceilRate) / pow; } } @@ -747,19 +739,11 @@ namespace XCharts.Runtime public static double GetMinDivisibleValue(double min, double ceilRate) { if (min == 0) return 0; + double pow = 1; if (min > -1 && min < 1) { - int count = 1; - int intvalue = (int)(min * Mathf.Pow(10, count)); - while (intvalue == 0 && count < 12) - { - count++; - intvalue = (int)(min * Mathf.Pow(10, count)); - } - var pow = Mathf.Pow(10, count); - var value = min > 0 ? ((int)(min * (pow - 1))) / pow : - ((int)(min * (pow + 1))) / pow; - return GetMinCeilRate(value, ceilRate); + pow = Mathf.Pow(10, MathUtil.GetPrecision(min)); + min *= pow; } if (ceilRate == 0) { @@ -775,12 +759,12 @@ namespace XCharts.Runtime mm = bigger - bigger % (Mathf.Pow(10, n)); mm += min < 0 ? Mathf.Pow(10, n) : -Mathf.Pow(10, n); } - if (min < 0) return -Math.Floor(mm); - else return Math.Floor(mm); + if (min < 0) return -Math.Floor(mm) / pow; + else return Math.Floor(mm) / pow; } else { - return GetMinCeilRate(min, ceilRate); + return GetMinCeilRate(min, ceilRate) / pow; } } diff --git a/Runtime/Internal/Utilities/DataHelper.cs b/Runtime/Internal/Utilities/DataHelper.cs index fa180842..a0d181ac 100644 --- a/Runtime/Internal/Utilities/DataHelper.cs +++ b/Runtime/Internal/Utilities/DataHelper.cs @@ -22,7 +22,7 @@ namespace XCharts.Runtime } public static double SampleValue(ref List<SerieData> showData, SampleType sampleType, int rate, - int minCount, int maxCount, double totalAverage, int index, float dataChangeDuration, + int minCount, int maxCount, double totalAverage, int index, float dataAddDuration, float dataChangeDuration, ref bool dataChanging, Axis axis, bool unscaledTime) { var inverse = axis.inverse; @@ -33,7 +33,7 @@ namespace XCharts.Runtime if (showData[index].IsDataChanged()) dataChanging = true; - return showData[index].GetCurrData(1, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); + return showData[index].GetCurrData(1, dataAddDuration, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); } switch (sampleType) { @@ -44,7 +44,7 @@ namespace XCharts.Runtime for (int i = index; i > index - rate; i--) { count++; - total += showData[i].GetCurrData(1, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); + total += showData[i].GetCurrData(1, dataAddDuration, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); if (showData[i].IsDataChanged()) dataChanging = true; } @@ -57,7 +57,7 @@ namespace XCharts.Runtime double max = double.MinValue; for (int i = index; i > index - rate; i--) { - var value = showData[i].GetCurrData(1, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); + var value = showData[i].GetCurrData(1, dataAddDuration, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); if (value > max) max = value; @@ -70,7 +70,7 @@ namespace XCharts.Runtime double min = double.MaxValue; for (int i = index; i > index - rate; i--) { - var value = showData[i].GetCurrData(1, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); + var value = showData[i].GetCurrData(1, dataAddDuration, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); if (value < min) min = value; @@ -85,7 +85,7 @@ namespace XCharts.Runtime total = 0; for (int i = index; i > index - rate; i--) { - var value = showData[i].GetCurrData(1, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); + var value = showData[i].GetCurrData(1, dataAddDuration, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); total += value; if (value < min) min = value; @@ -104,7 +104,7 @@ namespace XCharts.Runtime if (showData[index].IsDataChanged()) dataChanging = true; - return showData[index].GetCurrData(1, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); + return showData[index].GetCurrData(1, dataAddDuration, dataChangeDuration, inverse, minValue, maxValue, unscaledTime); } } } \ No newline at end of file diff --git a/Runtime/Internal/XCSettings.cs b/Runtime/Internal/XCSettings.cs index d1617bcc..6d5f7a9e 100644 --- a/Runtime/Internal/XCSettings.cs +++ b/Runtime/Internal/XCSettings.cs @@ -60,8 +60,6 @@ namespace XCharts.Runtime [SerializeField][Range(1f, 20)] protected float m_LineSegmentDistance = 3f; [SerializeField][Range(1, 10)] protected float m_CicleSmoothness = 2f; [SerializeField][Range(10, 50)] protected float m_VisualMapTriangeLen = 20f; - [SerializeField][Range(1, 20)] protected float m_PieTooltipExtraRadius = 8f; - [SerializeField][Range(1, 20)] protected float m_PieSelectedOffset = 8f; [SerializeField] protected List<Theme> m_CustomThemes = new List<Theme>(); public static Lang lang { get { return Instance.m_Lang; } } @@ -112,8 +110,6 @@ namespace XCharts.Runtime public static float lineSegmentDistance { get { return Instance.m_LineSegmentDistance; } } public static float cicleSmoothness { get { return Instance.m_CicleSmoothness; } } public static float visualMapTriangeLen { get { return Instance.m_VisualMapTriangeLen; } } - public static float pieTooltipExtraRadius { get { return Instance.m_PieTooltipExtraRadius; } } - public static float pieSelectedOffset { get { return Instance.m_PieSelectedOffset; } } #endregion public static List<Theme> customThemes { get { return Instance.m_CustomThemes; } } diff --git a/Runtime/Internal/XChartsMgr.cs b/Runtime/Internal/XChartsMgr.cs index 5a03cfc5..afddde51 100644 --- a/Runtime/Internal/XChartsMgr.cs +++ b/Runtime/Internal/XChartsMgr.cs @@ -21,8 +21,8 @@ namespace XCharts.Runtime [ExecuteInEditMode] public static class XChartsMgr { - public static readonly string version = "3.7.0"; - public static readonly int versionDate = 20230601; + public static readonly string version = "3.8.0"; + public static readonly int versionDate = 20230903; public static string fullVersion { get { return version + "-" + versionDate; } } internal static List<BaseChart> chartList = new List<BaseChart>(); diff --git a/Runtime/Serie/Bar/Bar.cs b/Runtime/Serie/Bar/Bar.cs index 21066d66..5ad093e3 100644 --- a/Runtime/Serie/Bar/Bar.cs +++ b/Runtime/Serie/Bar/Bar.cs @@ -5,6 +5,7 @@ namespace XCharts.Runtime [SerieConvert(typeof(Line), typeof(Pie))] [CoordOptions(typeof(GridCoord), typeof(PolarCoord))] [DefaultAnimation(AnimationType.BottomToTop)] + [DefaultTooltip(Tooltip.Type.Shadow, Tooltip.Trigger.Axis)] [SerieComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField("m_Ignore")] diff --git a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs index f2c860ec..5cb75bc1 100644 --- a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs +++ b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs @@ -27,7 +27,7 @@ namespace XCharts.Runtime m_LastCheckContextFlag = needCheck; serie.context.pointerItemDataIndex = -1; serie.context.pointerEnter = false; - serie.interact.SetValue(ref needAnimation1, lineWidth, false); + serie.interact.SetValue(ref needAnimation1, lineWidth); foreach (var serieData in serie.data) { var symbol = SerieHelper.GetSerieSymbol(serie, serieData); @@ -53,11 +53,11 @@ namespace XCharts.Runtime if (m_LegendEnter) { serie.context.pointerEnter = true; - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, SerieState.Emphasis); serieData.context.highlight = true; serieData.interact.SetValue(ref needInteract, size); } @@ -139,6 +139,7 @@ namespace XCharts.Runtime var areaColor = ColorUtil.clearColor32; var areaToColor = ColorUtil.clearColor32; var interacting = false; + var interactDuration = serie.animation.GetInteractionDuration(); float start, end; float inside, outside; @@ -184,7 +185,7 @@ namespace XCharts.Runtime serieData.context.toAngle = end; serieData.context.halfAngle = (start + end) / 2; - if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting)) + if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting, interactDuration)) { SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme); serieData.interact.SetColor(ref interacting, areaColor, areaToColor); diff --git a/Runtime/Serie/Bar/BarHandler.cs b/Runtime/Serie/Bar/BarHandler.cs index f3360129..0cc1faa3 100644 --- a/Runtime/Serie/Bar/BarHandler.cs +++ b/Runtime/Serie/Bar/BarHandler.cs @@ -13,9 +13,8 @@ namespace XCharts.Runtime private GridCoord m_SerieGrid; private float[] m_CapusleDefaultCornerRadius = new float[] { 1, 1, 1, 1 }; - public override void Update() + public override void UpdateSerieContext() { - base.Update(); if (serie.IsUseCoord<GridCoord>()) UpdateSerieGridContext(); else if (serie.IsUseCoord<PolarCoord>()) @@ -183,10 +182,12 @@ namespace XCharts.Runtime (serie.maxShow > showData.Count ? showData.Count : serie.maxShow) : showData.Count; var isPercentStack = SeriesHelper.IsPercentStack<Bar>(chart.series, serie.stack); - bool dataChanging = false; - float dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); - double yMinValue = relativedAxis.context.minValue; - double yMaxValue = relativedAxis.context.maxValue; + var dataChanging = false; + var dataChangeDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); + var interactDuration = serie.animation.GetInteractionDuration(); + var yMinValue = relativedAxis.context.minValue; + var yMaxValue = relativedAxis.context.maxValue; var areaColor = ColorUtil.clearColor32; var areaToColor = ColorUtil.clearColor32; @@ -211,13 +212,13 @@ namespace XCharts.Runtime var state = SerieHelper.GetSerieState(serie, serieData); var itemStyle = SerieHelper.GetItemStyle(serie, serieData, state); var value = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse); - var relativedValue = serieData.GetCurrData(1, dataChangeDuration, relativedAxis.inverse, yMinValue, yMaxValue, serie.animation.unscaledTime); + var relativedValue = serieData.GetCurrData(1, dataAddDuration, dataChangeDuration, relativedAxis.inverse, yMinValue, yMaxValue, serie.animation.unscaledTime); var borderWidth = relativedValue == 0 ? 0 : itemStyle.runtimeBorderWidth; var borderGap = relativedValue == 0 ? 0 : itemStyle.borderGap; var borderGapAndWidth = borderWidth + borderGap; var backgroundColor = itemStyle.backgroundColor; - if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting)) + if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting, interactDuration)) { SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme); serieData.interact.SetColor(ref interacting, areaColor, areaToColor); @@ -236,7 +237,6 @@ namespace XCharts.Runtime { barHig = AxisHelper.GetAxisValueLength(m_SerieGrid, relativedAxis, categoryWidth, relativedValue); } - float currHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, barHig); Vector3 plb, plt, prt, prb, top; UpdateRectPosition(m_SerieGrid, isY, relativedValue, pX, pY, gap, borderWidth, barWidth, currHig, diff --git a/Runtime/Serie/Bar/SimplifiedBar.cs b/Runtime/Serie/Bar/SimplifiedBar.cs index 0e9703f9..a99218cb 100644 --- a/Runtime/Serie/Bar/SimplifiedBar.cs +++ b/Runtime/Serie/Bar/SimplifiedBar.cs @@ -7,7 +7,8 @@ namespace XCharts.Runtime [SerieHandler(typeof(SimplifiedBarHandler), true)] [SerieConvert(typeof(SimplifiedLine), typeof(Bar))] [CoordOptions(typeof(GridCoord))] - [DefaultAnimation(AnimationType.LeftToRight)] + [DefaultAnimation(AnimationType.LeftToRight, false)] + [DefaultTooltip(Tooltip.Type.Shadow, Tooltip.Trigger.Axis)] [SerieComponent()] [SerieDataComponent()] [SerieDataExtraField()] diff --git a/Runtime/Serie/Bar/SimplifiedBarHandler.cs b/Runtime/Serie/Bar/SimplifiedBarHandler.cs index 508481fe..49833431 100644 --- a/Runtime/Serie/Bar/SimplifiedBarHandler.cs +++ b/Runtime/Serie/Bar/SimplifiedBarHandler.cs @@ -133,8 +133,10 @@ namespace XCharts.Runtime (serie.maxShow > showData.Count ? showData.Count : serie.maxShow) : showData.Count; - bool dataChanging = false; - float dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + var dataChanging = false; + var dataChangeDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); + var interactDuration = serie.animation.GetInteractionDuration(); double yMinValue = relativedAxis.context.minValue; double yMaxValue = relativedAxis.context.maxValue; @@ -161,10 +163,10 @@ namespace XCharts.Runtime var highlight = serieData.context.highlight || serie.highlight; var itemStyle = SerieHelper.GetItemStyle(serie, serieData); var value = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse); - var relativedValue = serieData.GetCurrData(1, dataChangeDuration, relativedAxis.inverse, yMinValue, yMaxValue, serie.animation.unscaledTime); + var relativedValue = serieData.GetCurrData(1, dataAddDuration, dataChangeDuration, relativedAxis.inverse, yMinValue, yMaxValue, serie.animation.unscaledTime); var borderWidth = relativedValue == 0 ? 0 : itemStyle.runtimeBorderWidth; - if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting)) + if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting, interactDuration)) { SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme); serieData.interact.SetColor(ref interacting, areaColor, areaToColor); @@ -216,7 +218,7 @@ namespace XCharts.Runtime else { if (axis.context.minMaxRange <= 0) pY = grid.context.y; - else pY = grid.context.y + (float) ((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.height - barWidth); + else pY = grid.context.y + (float)((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.height - barWidth); } pX = AxisHelper.GetAxisValuePosition(grid, relativedAxis, categoryWidth, 0); } @@ -229,7 +231,7 @@ namespace XCharts.Runtime else { if (axis.context.minMaxRange <= 0) pX = grid.context.x; - else pX = grid.context.x + (float) ((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.width - barWidth); + else pX = grid.context.x + (float)((value - axis.context.minValue) / axis.context.minMaxRange) * (grid.context.width - barWidth); } pY = AxisHelper.GetAxisValuePosition(grid, relativedAxis, categoryWidth, 0); } diff --git a/Runtime/Serie/Candlestick/Candlestick.cs b/Runtime/Serie/Candlestick/Candlestick.cs index 092ec99d..26583938 100644 --- a/Runtime/Serie/Candlestick/Candlestick.cs +++ b/Runtime/Serie/Candlestick/Candlestick.cs @@ -4,7 +4,8 @@ namespace XCharts.Runtime { [System.Serializable] [SerieHandler(typeof(CandlestickHandler), true)] - [DefaultAnimation(AnimationType.LeftToRight)] + [DefaultAnimation(AnimationType.LeftToRight, false)] + [DefaultTooltip(Tooltip.Type.Shadow, Tooltip.Trigger.Axis)] [SerieComponent()] [SerieDataComponent(typeof(ItemStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField()] diff --git a/Runtime/Serie/Candlestick/CandlestickHandler.cs b/Runtime/Serie/Candlestick/CandlestickHandler.cs index 9c315351..a262f509 100644 --- a/Runtime/Serie/Candlestick/CandlestickHandler.cs +++ b/Runtime/Serie/Candlestick/CandlestickHandler.cs @@ -99,7 +99,8 @@ namespace XCharts.Runtime showData.Count; bool dataChanging = false; - float dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + float dataChangeDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; double yMinValue = yAxis.context.minValue; double yMaxValue = yAxis.context.maxValue; @@ -119,10 +120,10 @@ namespace XCharts.Runtime var state = SerieHelper.GetSerieState(serie, serieData); var itemStyle = SerieHelper.GetItemStyle(serie, serieData, state); var startDataIndex = serieData.data.Count > 4 ? 1 : 0; - var open = serieData.GetCurrData(startDataIndex, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); - var close = serieData.GetCurrData(startDataIndex + 1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); - var lowest = serieData.GetCurrData(startDataIndex + 2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); - var heighest = serieData.GetCurrData(startDataIndex + 3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var open = serieData.GetCurrData(startDataIndex, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var close = serieData.GetCurrData(startDataIndex + 1, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var lowest = serieData.GetCurrData(startDataIndex + 2, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var heighest = serieData.GetCurrData(startDataIndex + 3, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); var isRise = yAxis.inverse ? close<open : close> open; var borderWidth = open == 0 ? 0f : (itemStyle.runtimeBorderWidth == 0 ? theme.serie.candlestickBorderWidth : diff --git a/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs b/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs index 003c72fe..911f6eb2 100644 --- a/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs +++ b/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs @@ -4,7 +4,8 @@ namespace XCharts.Runtime { [System.Serializable] [SerieHandler(typeof(SimplifiedCandlestickHandler), true)] - [DefaultAnimation(AnimationType.LeftToRight)] + [DefaultAnimation(AnimationType.LeftToRight, false)] + [DefaultTooltip(Tooltip.Type.Shadow, Tooltip.Trigger.Axis)] [SerieComponent()] [SerieDataComponent()] [SerieDataExtraField()] diff --git a/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs b/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs index b52d068b..a49f6c19 100644 --- a/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs +++ b/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs @@ -99,7 +99,8 @@ namespace XCharts.Runtime showData.Count; bool dataChanging = false; - float dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + float dataChangeDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; double yMinValue = yAxis.context.minValue; double yMaxValue = yAxis.context.maxValue; @@ -118,10 +119,10 @@ namespace XCharts.Runtime continue; } var startDataIndex = serieData.data.Count > 4 ? 1 : 0; - var open = serieData.GetCurrData(startDataIndex, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); - var close = serieData.GetCurrData(startDataIndex + 1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); - var lowest = serieData.GetCurrData(startDataIndex + 2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); - var heighest = serieData.GetCurrData(startDataIndex + 3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var open = serieData.GetCurrData(startDataIndex, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var close = serieData.GetCurrData(startDataIndex + 1, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var lowest = serieData.GetCurrData(startDataIndex + 2, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); + var heighest = serieData.GetCurrData(startDataIndex + 3, dataAddDuration, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue, unscaledTime); var isRise = yAxis.inverse ? close<open : close> open; var borderWidth = open == 0 ? 0f : (itemStyle.runtimeBorderWidth == 0 ? theme.serie.candlestickBorderWidth : diff --git a/Runtime/Serie/Heatmap/Heatmap.cs b/Runtime/Serie/Heatmap/Heatmap.cs index 6897e5ec..0f62e11f 100644 --- a/Runtime/Serie/Heatmap/Heatmap.cs +++ b/Runtime/Serie/Heatmap/Heatmap.cs @@ -22,7 +22,8 @@ namespace XCharts.Runtime [System.Serializable] [SerieHandler(typeof(HeatmapHandler), true)] - [DefaultAnimation(AnimationType.LeftToRight)] + [DefaultAnimation(AnimationType.LeftToRight, false)] + [DefaultTooltip(Tooltip.Type.None, Tooltip.Trigger.Axis)] [RequireChartComponent(typeof(VisualMap))] [CoordOptions(typeof(GridCoord), typeof(PolarCoord))] [SerieComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs index c2ed3ffc..95f6c932 100644 --- a/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs +++ b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs @@ -27,7 +27,7 @@ namespace XCharts.Runtime m_LastCheckContextFlag = needCheck; serie.context.pointerItemDataIndex = -1; serie.context.pointerEnter = false; - serie.interact.SetValue(ref needAnimation1, lineWidth, false); + serie.interact.SetValue(ref needAnimation1, lineWidth); foreach (var serieData in serie.data) { var symbol = SerieHelper.GetSerieSymbol(serie, serieData); @@ -53,11 +53,11 @@ namespace XCharts.Runtime if (m_LegendEnter) { serie.context.pointerEnter = true; - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, SerieState.Emphasis); serieData.context.highlight = true; serieData.interact.SetValue(ref needInteract, size); } diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.cs b/Runtime/Serie/Heatmap/HeatmapHandler.cs index 262a908a..2ff83ec0 100644 --- a/Runtime/Serie/Heatmap/HeatmapHandler.cs +++ b/Runtime/Serie/Heatmap/HeatmapHandler.cs @@ -190,10 +190,11 @@ namespace XCharts.Runtime YAxis yAxis; if (!chart.TryGetChartComponent<XAxis>(out xAxis, serie.xAxisIndex)) return; if (!chart.TryGetChartComponent<YAxis>(out yAxis, serie.yAxisIndex)) return; + var visualMap = chart.GetVisualMapOfSerie(serie); + if (visualMap == null) return; m_SerieGrid = chart.GetChartComponent<GridCoord>(xAxis.gridIndex); xAxis.boundaryGap = true; yAxis.boundaryGap = true; - var visualMap = chart.GetVisualMapOfSerie(serie); var emphasisStyle = serie.emphasisStyle; var xCount = AxisHelper.GetTotalSplitGridNum(xAxis); var yCount = AxisHelper.GetTotalSplitGridNum(yAxis); @@ -209,7 +210,8 @@ namespace XCharts.Runtime serie.animation.InitProgress(0, xCount); var animationIndex = serie.animation.GetCurrIndex(); - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + var dataChangeDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; var dataChanging = false; serie.containerIndex = m_SerieGrid.index; @@ -246,7 +248,7 @@ namespace XCharts.Runtime var symbol = SerieHelper.GetSerieSymbol(serie, serieData, state); var isRectSymbol = symbol.type == SymbolType.Rect; SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, serieData, chart.theme, state); - var value = serieData.GetCurrData(dimension, dataChangeDuration, yAxis.inverse, + var value = serieData.GetCurrData(dimension, dataAddDuration, dataChangeDuration, yAxis.inverse, yAxis.context.minValue, yAxis.context.maxValue, unscaledTime); if (serieData.IsDataChanged()) dataChanging = true; var pos = new Vector3(zeroX + (i + 0.5f) * xWidth, @@ -283,7 +285,7 @@ namespace XCharts.Runtime } else { - var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, defaultSymbolSize, state); + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, defaultSymbolSize, state); rectWid = symbolSize; rectHig = symbolSize; } @@ -297,7 +299,7 @@ namespace XCharts.Runtime } else { - var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, defaultSymbolSize, state); + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, defaultSymbolSize, state); var emptyColor = SerieHelper.GetItemBackgroundColor(serie, serieData, chart.theme, serie.context.colorIndex, state); serieData.context.rect = new Rect(pos.x - symbolSize / 2, pos.y - symbolSize / 2, symbolSize, symbolSize); chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, pos, @@ -397,7 +399,7 @@ namespace XCharts.Runtime } var state = SerieHelper.GetSerieState(serie, null, true); var symbol = SerieHelper.GetSerieSymbol(serie, null, state); - var symbolSize = SerieHelper.GetSysmbolSize(serie, null, chart.theme, defaultSymbolSize, state); + var symbolSize = SerieHelper.GetSysmbolSize(serie, null, defaultSymbolSize, state); var isRectSymbol = symbol.type == SymbolType.Rect; float symbolBorder = 0f; float[] cornerRadius = null; diff --git a/Runtime/Serie/Line/Line.cs b/Runtime/Serie/Line/Line.cs index 68176cd6..bbc2cc76 100644 --- a/Runtime/Serie/Line/Line.cs +++ b/Runtime/Serie/Line/Line.cs @@ -6,23 +6,11 @@ namespace XCharts.Runtime [SerieHandler(typeof(LineHandler), true)] [SerieConvert(typeof(Bar), typeof(Pie))] [CoordOptions(typeof(GridCoord), typeof(PolarCoord))] - [DefaultAnimation(AnimationType.LeftToRight)] - [SerieComponent( - typeof(LabelStyle), - typeof(EndLabelStyle), - typeof(LineArrow), - typeof(AreaStyle), - typeof(EmphasisStyle), - typeof(BlurStyle), - typeof(SelectStyle))] - [SerieDataComponent( - typeof(ItemStyle), - typeof(LabelStyle), - typeof(SerieSymbol), - typeof(EmphasisStyle), - typeof(BlurStyle), - typeof(SelectStyle))] + [DefaultAnimation(AnimationType.LeftToRight, false)] + [DefaultTooltip(Tooltip.Type.Line, Tooltip.Trigger.Axis)] [SerieDataExtraField("m_State", "m_Ignore")] + [SerieComponent(typeof(LabelStyle), typeof(EndLabelStyle), typeof(LineArrow), typeof(AreaStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] + [SerieDataComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(SerieSymbol), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] public class Line : Serie, INeedSerieContainer { public int containerIndex { get; internal set; } @@ -31,6 +19,7 @@ namespace XCharts.Runtime { var serie = chart.AddSerie<Line>(serieName); serie.symbol.show = true; + serie.animation.interaction.radius.value = 1.5f; for (int i = 0; i < 5; i++) { chart.AddData(serie.index, UnityEngine.Random.Range(10, 90)); diff --git a/Runtime/Serie/Line/LineHandler.GridCoord.cs b/Runtime/Serie/Line/LineHandler.GridCoord.cs index 07b56738..5694aa3b 100644 --- a/Runtime/Serie/Line/LineHandler.GridCoord.cs +++ b/Runtime/Serie/Line/LineHandler.GridCoord.cs @@ -61,11 +61,11 @@ namespace XCharts.Runtime if (m_LegendEnter) { serie.context.pointerEnter = true; - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, SerieState.Emphasis); serieData.context.highlight = true; serieData.interact.SetValue(ref needInteract, size); } @@ -73,14 +73,14 @@ namespace XCharts.Runtime else if (serie.context.isTriggerByAxis) { serie.context.pointerEnter = false; - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; var highlight = i == serie.context.pointerItemDataIndex; serieData.context.highlight = highlight; var state = SerieHelper.GetSerieState(serie, serieData, true); - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, state); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state); serieData.interact.SetValue(ref needInteract, size); if (highlight) { @@ -99,11 +99,11 @@ namespace XCharts.Runtime { var serieData = serie.data[i]; var dist = Vector3.Distance(chart.pointerPos, serieData.context.position); - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize); var highlight = dist <= size; serieData.context.highlight = highlight; var state = SerieHelper.GetSerieState(serie, serieData, true); - size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, state); + size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state); serieData.interact.SetValue(ref needInteract, size); if (highlight) { @@ -116,7 +116,7 @@ namespace XCharts.Runtime needInteract = true; } if (serie.context.pointerItemDataIndex >= 0) - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); else serie.interact.SetValue(ref needInteract, lineWidth); } @@ -144,6 +144,7 @@ namespace XCharts.Runtime var lineArrow = serie.lineArrow; var visualMap = chart.GetVisualMapOfSerie(serie); var isVisualMapGradient = VisualMapHelper.IsNeedLineGradient(visualMap); + var interactDuration = serie.animation.GetInteractionDuration(); Axis axis; Axis relativedAxis; @@ -176,9 +177,9 @@ namespace XCharts.Runtime continue; var symbolSize = 0f; - if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting)) + if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting, interactDuration)) { - symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, chart.theme.serie.lineSymbolSize, state); + symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme.serie.lineSymbolSize, state); serieData.interact.SetValue(ref interacting, symbolSize); symbolSize = serie.animation.GetSysmbolSize(symbolSize); } @@ -288,7 +289,7 @@ namespace XCharts.Runtime serie.sampleAverage : DataHelper.DataAverage(ref showData, serie.sampleType, serie.minShow, maxCount, rate); var dataChanging = false; - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + var dataChangeDuration = serie.animation.GetChangeDuration(); var unscaledTime = serie.animation.unscaledTime; var interacting = false; @@ -325,7 +326,7 @@ namespace XCharts.Runtime var np = Vector3.zero; var xValue = axis.IsCategory() ? realIndex : serieData.GetData(0, axis.inverse); var relativedValue = DataHelper.SampleValue(ref showData, serie.sampleType, rate, serie.minShow, - maxCount, totalAverage, i, dataChangeDuration, ref dataChanging, relativedAxis, unscaledTime); + maxCount, totalAverage, i, 0, dataChangeDuration, ref dataChanging, relativedAxis, unscaledTime); serieData.context.stackHeight = GetDataPoint(isY, axis, relativedAxis, m_SerieGrid, xValue, relativedValue, i, scaleWid, isStack, ref np); diff --git a/Runtime/Serie/Line/LineHandler.PolarCoord.cs b/Runtime/Serie/Line/LineHandler.PolarCoord.cs index 1c34e96a..e6e8b9cd 100644 --- a/Runtime/Serie/Line/LineHandler.PolarCoord.cs +++ b/Runtime/Serie/Line/LineHandler.PolarCoord.cs @@ -27,7 +27,7 @@ namespace XCharts.Runtime m_LastCheckContextFlag = needCheck; serie.context.pointerItemDataIndex = -1; serie.context.pointerEnter = false; - serie.interact.SetValue(ref needAnimation1, lineWidth, false); + serie.interact.SetValue(ref needAnimation1, lineWidth); foreach (var serieData in serie.data) { var symbol = SerieHelper.GetSerieSymbol(serie, serieData); @@ -53,11 +53,11 @@ namespace XCharts.Runtime if (m_LegendEnter) { serie.context.pointerEnter = true; - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, SerieState.Emphasis); serieData.context.highlight = true; serieData.interact.SetValue(ref needInteract, size); } @@ -269,7 +269,7 @@ namespace XCharts.Runtime if (!symbol.show || !symbol.ShowSymbol(i, count)) continue; - var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, chart.theme.serie.lineSymbolSize, state); + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme.serie.lineSymbolSize, state); SerieHelper.GetItemColor(out symbolColor, out symbolToColor, out symbolEmptyColor, serie, serieData, chart.theme, n); SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, null, chart.theme, state); diff --git a/Runtime/Serie/Line/LineHandler.cs b/Runtime/Serie/Line/LineHandler.cs index 6ff1865c..e06fa144 100644 --- a/Runtime/Serie/Line/LineHandler.cs +++ b/Runtime/Serie/Line/LineHandler.cs @@ -98,26 +98,26 @@ namespace XCharts.Runtime } } - public override int GetPointerItemDataIndex() - { - var symbolSize = SerieHelper.GetSysmbolSize(serie, null, chart.theme, chart.theme.serie.lineSymbolSize) * 1.5f; - var count = serie.context.dataPoints.Count; - for (int i = 0; i < count; i++) - { - var index = serie.context.dataIndexs[i]; - var serieData = serie.GetSerieData(index); - if (serieData == null) - continue; - if (serieData.context.isClip) - continue; + // public override int GetPointerItemDataIndex() + // { + // var symbolSize = SerieHelper.GetSysmbolSize(serie, null, chart.theme.serie.lineSymbolSize) * 1.5f; + // var count = serie.context.dataPoints.Count; + // for (int i = 0; i < count; i++) + // { + // var index = serie.context.dataIndexs[i]; + // var serieData = serie.GetSerieData(index); + // if (serieData == null) + // continue; + // if (serieData.context.isClip) + // continue; - var pos = serie.context.dataPoints[i]; - if (Vector2.Distance(pos, chart.pointerPos) < symbolSize) - { - return i; - } - } - return -1; - } + // var pos = serie.context.dataPoints[i]; + // if (Vector2.Distance(pos, chart.pointerPos) < symbolSize) + // { + // return i; + // } + // } + // return -1; + // } } } \ No newline at end of file diff --git a/Runtime/Serie/Line/LineHelper.cs b/Runtime/Serie/Line/LineHelper.cs index 4e99f640..d188a0d8 100644 --- a/Runtime/Serie/Line/LineHelper.cs +++ b/Runtime/Serie/Line/LineHelper.cs @@ -410,7 +410,7 @@ namespace XCharts.Runtime public static float GetLineWidth(ref bool interacting, Serie serie, float defaultWidth) { var lineWidth = 0f; - if (!serie.interact.TryGetValue(ref lineWidth, ref interacting)) + if (!serie.interact.TryGetValue(ref lineWidth, ref interacting, serie.animation.GetInteractionDuration())) { lineWidth = serie.lineStyle.GetWidth(defaultWidth); serie.interact.SetValue(ref interacting, lineWidth); diff --git a/Runtime/Serie/Line/SimplifiedLine.cs b/Runtime/Serie/Line/SimplifiedLine.cs index c1a3b041..0e278988 100644 --- a/Runtime/Serie/Line/SimplifiedLine.cs +++ b/Runtime/Serie/Line/SimplifiedLine.cs @@ -7,7 +7,8 @@ namespace XCharts.Runtime [SerieHandler(typeof(SimplifiedLineHandler), true)] [SerieConvert(typeof(SimplifiedBar), typeof(Line))] [CoordOptions(typeof(GridCoord))] - [DefaultAnimation(AnimationType.LeftToRight)] + [DefaultAnimation(AnimationType.LeftToRight, false)] + [DefaultTooltip(Tooltip.Type.Line, Tooltip.Trigger.Axis)] [SerieComponent(typeof(AreaStyle))] [SerieDataComponent()] [SerieDataExtraField()] diff --git a/Runtime/Serie/Line/SimplifiedLineHandler.cs b/Runtime/Serie/Line/SimplifiedLineHandler.cs index 2e84beea..4abe6af9 100644 --- a/Runtime/Serie/Line/SimplifiedLineHandler.cs +++ b/Runtime/Serie/Line/SimplifiedLineHandler.cs @@ -46,7 +46,7 @@ namespace XCharts.Runtime m_LastCheckContextFlag = needCheck; serie.context.pointerItemDataIndex = -1; serie.context.pointerEnter = false; - serie.interact.SetValue(ref needAnimation1, lineWidth, false); + serie.interact.SetValue(ref needAnimation1, lineWidth); foreach (var serieData in serie.data) { var symbol = SerieHelper.GetSerieSymbol(serie, serieData); @@ -66,18 +66,17 @@ namespace XCharts.Runtime } m_LastCheckContextFlag = needCheck; var themeSymbolSize = chart.theme.serie.lineSymbolSize; - var themeSymbolSelectedSize = chart.theme.serie.lineSymbolSelectedSize; lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); var needInteract = false; if (m_LegendEnter) { serie.context.pointerEnter = true; - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, SerieState.Emphasis); serieData.context.highlight = true; serieData.interact.SetValue(ref needInteract, size); } @@ -85,14 +84,14 @@ namespace XCharts.Runtime else if (serie.context.isTriggerByAxis) { serie.context.pointerEnter = true; - serie.interact.SetValue(ref needInteract, lineWidth, true, chart.theme.serie.selectedRate); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; var highlight = i == serie.context.pointerItemDataIndex; serieData.context.highlight = highlight; var state = SerieHelper.GetSerieState(serie, serieData, true); - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, state); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state); serieData.interact.SetValue(ref needInteract, size); if (highlight) { @@ -110,17 +109,17 @@ namespace XCharts.Runtime { var serieData = serie.data[i]; var dist = Vector3.Distance(chart.pointerPos, serieData.context.position); - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize); var highlight = dist <= size; serieData.context.highlight = highlight; var state = SerieHelper.GetSerieState(serie, serieData, true); - size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, state); + size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state); serieData.interact.SetValue(ref needInteract, size); if (highlight) { serie.context.pointerEnter = true; serie.context.pointerItemDataIndex = serieData.index; - serie.interact.SetValue(ref needInteract, lineWidth, true); + serie.interact.SetValue(ref needInteract, serie.animation.interaction.GetWidth(lineWidth)); } } if (lastIndex != serie.context.pointerItemDataIndex) @@ -172,7 +171,8 @@ namespace XCharts.Runtime serie.sampleAverage : DataHelper.DataAverage(ref showData, serie.sampleType, serie.minShow, maxCount, rate); var dataChanging = false; - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + var dataChangeDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; var interacting = false; @@ -200,7 +200,7 @@ namespace XCharts.Runtime var np = Vector3.zero; var xValue = axis.IsCategory() ? i : serieData.GetData(0, axis.inverse); var relativedValue = DataHelper.SampleValue(ref showData, serie.sampleType, rate, serie.minShow, - maxCount, totalAverage, i, dataChangeDuration, ref dataChanging, relativedAxis, unscaledTime); + maxCount, totalAverage, i, dataAddDuration, dataChangeDuration, ref dataChanging, relativedAxis, unscaledTime); serieData.context.stackHeight = GetDataPoint(isY, axis, relativedAxis, m_SerieGrid, xValue, relativedValue, i, scaleWid, false, ref np); diff --git a/Runtime/Serie/Pie/PieHandler.cs b/Runtime/Serie/Pie/PieHandler.cs index c568a1e6..2284d958 100644 --- a/Runtime/Serie/Pie/PieHandler.cs +++ b/Runtime/Serie/Pie/PieHandler.cs @@ -43,7 +43,33 @@ namespace XCharts.Runtime public override Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label) { var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); - return SerieLabelHelper.GetRealLabelPosition(serie, serieData, label, labelLine); + if (labelLine != null && labelLine.show && serieData.labelObject != null) + { + var currAngle = serieData.context.halfAngle - serie.context.startAngle; + var isRight = currAngle % 360 < 180; + var textOffset = serieData.labelObject.text.GetPreferredWidth() / 2; + return serieData.context.labelPosition + (isRight ? Vector3.right : Vector3.left) * textOffset; + } + else + { + return serieData.context.labelPosition; + } + } + + public override Vector3 GetSerieDataLabelOffset(SerieData serieData, LabelStyle label) + { + var offset = label.GetOffset(serie.context.insideRadius); + if (label.autoOffset) + { + var currAngle = serieData.context.halfAngle - serie.context.startAngle; + var isRight = currAngle % 360 < 180; + if (isRight) return offset; + else return new Vector3(-offset.x, offset.y, offset.z); + } + else + { + return offset; + } } public override Vector3 GetSerieDataTitlePosition(SerieData serieData, TitleStyle titleStyle) @@ -51,31 +77,6 @@ namespace XCharts.Runtime return serie.context.center; } - public override void OnLegendButtonClick(int index, string legendName, bool show) - { - if (!serie.IsLegendName(legendName)) - return; - LegendHelper.CheckDataShow(serie, legendName, show); - chart.UpdateLegendColor(legendName, show); - chart.RefreshPainter(serie); - } - - public override void OnLegendButtonEnter(int index, string legendName) - { - if (!serie.IsLegendName(legendName)) - return; - LegendHelper.CheckDataHighlighted(serie, legendName, true); - chart.RefreshPainter(serie); - } - - public override void OnLegendButtonExit(int index, string legendName) - { - if (!serie.IsLegendName(legendName)) - return; - LegendHelper.CheckDataHighlighted(serie, legendName, false); - chart.RefreshPainter(serie); - } - public override void OnPointerDown(PointerEventData eventData) { if (chart.pointerPos == Vector2.zero) return; @@ -101,25 +102,41 @@ namespace XCharts.Runtime public override void UpdateSerieContext() { - var needCheck = m_LegendEnter || (chart.isPointerInChart && PointerIsInPieSerie(serie, chart.pointerPos)); + var needCheck = m_LegendEnter || m_LegendExiting || m_ForceUpdateSerieContext || (chart.isPointerInChart && PointerIsInPieSerie(serie, chart.pointerPos)); var needInteract = false; + var interactEnable = serie.animation.enable && serie.animation.interaction.enable; Color32 color, toColor; if (!needCheck) { - if (m_LastCheckContextFlag != needCheck) + if (m_LastCheckContextFlag != needCheck || m_ForceUpdateSerieContext) { - m_LastCheckContextFlag = needCheck; serie.context.pointerItemDataIndex = -1; serie.context.pointerEnter = false; + bool isAllZeroValue1 = SerieHelper.IsAllZeroValue(serie, 1); + var zeroReplaceValue1 = isAllZeroValue1 ? 360 / serie.dataCount : 0; foreach (var serieData in serie.data) { - var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); - SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal); serieData.context.highlight = false; - serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); + if (interactEnable) + { + var value = isAllZeroValue1 ? zeroReplaceValue1 : serieData.GetCurrData(1, serie.animation); + var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); + SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal); + UpdateSerieDataRadius(serieData, value); + serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); + serieData.interact.SetPosition(ref needInteract, serieData.context.offsetCenter); + } } if (needInteract) + { chart.RefreshPainter(serie); + } + else + { + m_LastCheckContextFlag = needCheck; + m_LegendExiting = false; + chart.RefreshPainter(serie); + } } return; } @@ -128,25 +145,32 @@ namespace XCharts.Runtime var dataIndex = GetPiePosIndex(serie, chart.pointerPos); serie.context.pointerItemDataIndex = -1; serie.context.pointerEnter = dataIndex >= 0; + + bool isAllZeroValue = SerieHelper.IsAllZeroValue(serie, 1); + var zeroReplaceValue = isAllZeroValue ? 360 / serie.dataCount : 0; + for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; + var value = isAllZeroValue ? zeroReplaceValue : serieData.GetCurrData(1, serie.animation); + var state = SerieState.Normal; if (dataIndex == i || (m_LegendEnter && m_LegendEnterIndex == i)) { serie.context.pointerItemDataIndex = i; serieData.context.highlight = true; - - var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); - SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Emphasis); - var value = serieData.context.outsideRadius + chart.theme.serie.pieTooltipExtraRadius; - serieData.interact.SetValueAndColor(ref needInteract, value, color, toColor); + state = SerieState.Emphasis; } else { serieData.context.highlight = false; + } + if (interactEnable) + { + UpdateSerieDataRadius(serieData, value); var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); - SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal); + SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, state); serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); + serieData.interact.SetPosition(ref needInteract, serieData.context.offsetCenter); } } if (lastPointerItemDataIndex != serie.context.pointerItemDataIndex) @@ -165,8 +189,7 @@ namespace XCharts.Runtime serie.context.dataMax = serie.yMax; serie.context.startAngle = GetStartAngle(serie); var runtimePieDataTotal = serie.yTotal; - - SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight); + SerieHelper.UpdateCenter(serie, chart); float startDegree = serie.context.startAngle; float totalDegree = 0; float zeroReplaceValue = 0; @@ -176,8 +199,6 @@ namespace XCharts.Runtime if (sd.show && serie.pieRoseType == RoseType.Area) showdataCount++; sd.context.canShowLabel = false; } - float dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); - var unscaledTime = serie.animation.unscaledTime; bool isAllZeroValue = SerieHelper.IsAllZeroValue(serie, 1); var dataTotalFilterMinAngle = runtimePieDataTotal; if (isAllZeroValue) @@ -195,7 +216,7 @@ namespace XCharts.Runtime for (int n = 0; n < data.Count; n++) { var serieData = data[n]; - var value = isAllZeroValue ? zeroReplaceValue : serieData.GetCurrData(1, dataChangeDuration, unscaledTime); + var value = isAllZeroValue ? zeroReplaceValue : serieData.GetCurrData(1, serie.animation); serieData.context.startAngle = startDegree; serieData.context.toAngle = startDegree; serieData.context.halfAngle = startDegree; @@ -209,62 +230,74 @@ namespace XCharts.Runtime (float)(totalDegree * value / dataTotalFilterMinAngle); if (serie.minAngle > 0 && degree < serie.minAngle) degree = serie.minAngle; serieData.context.toAngle = startDegree + degree; - if (serieData.radius > 0) - serieData.context.outsideRadius = ChartHelper.GetActualValue(serieData.radius, Mathf.Min(chart.chartWidth, chart.chartHeight)); - else - serieData.context.outsideRadius = serie.pieRoseType > 0 ? - serie.context.insideRadius + (float)((serie.context.outsideRadius - serie.context.insideRadius) * value / serie.context.dataMax) : - serie.context.outsideRadius; - if (serieData.context.highlight) - { - serieData.context.outsideRadius += chart.theme.serie.pieTooltipExtraRadius; - } - var offset = 0f; - if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) - { - offset += chart.theme.serie.pieSelectedOffset; - } - if (serie.animation.CheckDetailBreak(serieData.context.toAngle)) - { - serieData.context.currentAngle = serie.animation.GetCurrDetail(); - } - else - { - serieData.context.currentAngle = serieData.context.toAngle; - } var halfDegree = (serieData.context.toAngle - startDegree) / 2; - var halfRadius = serie.context.insideRadius + (serieData.context.outsideRadius - serie.context.insideRadius) / 2; serieData.context.halfAngle = startDegree + halfDegree; serieData.context.angle = startDegree + halfDegree; - serieData.context.offsetCenter = serie.context.center; + serieData.context.currentAngle = serie.animation.CheckDetailBreak(serieData.context.toAngle) + ? serie.animation.GetCurrDetail() : serieData.context.toAngle; serieData.context.insideRadius = serie.context.insideRadius; - serieData.context.position = ChartHelper.GetPosition(serie.context.center, serieData.context.halfAngle, halfRadius); - if (offset > 0) - { - var currRad = serieData.context.halfAngle * Mathf.Deg2Rad; - var currSin = Mathf.Sin(currRad); - var currCos = Mathf.Cos(currRad); - serieData.context.offsetRadius = 0; - serieData.context.insideRadius -= serieData.context.offsetRadius; - serieData.context.outsideRadius -= serieData.context.offsetRadius; - if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) - { - serieData.context.offsetRadius += chart.theme.serie.pieSelectedOffset; - if (serieData.context.insideRadius > 0) - { - serieData.context.insideRadius += chart.theme.serie.pieSelectedOffset; - } - serieData.context.outsideRadius += chart.theme.serie.pieSelectedOffset; - } - serieData.context.offsetCenter = new Vector3( - serie.context.center.x + serieData.context.offsetRadius * currSin, - serie.context.center.y + serieData.context.offsetRadius * currCos); - } serieData.context.canShowLabel = serieData.context.currentAngle >= serieData.context.halfAngle; + UpdateSerieDataRadius(serieData, value); + UpdatePieLabelPosition(serie, serieData); startDegree = serieData.context.toAngle; - SerieLabelHelper.UpdatePieLabelPosition(serie, serieData); } - SerieLabelHelper.AvoidLabelOverlap(serie, chart.theme.common); + AvoidLabelOverlap(serie, chart.theme.common); + } + + private void UpdateSerieDataRadius(SerieData serieData, double value) + { + var minChartWidth = Mathf.Min(chart.chartWidth, chart.chartHeight); + var minRadius = serie.minRadius > 0 ? ChartHelper.GetActualValue(serie.minRadius, minChartWidth) : 0; + if (serieData.radius > 0) + { + serieData.context.outsideRadius = ChartHelper.GetActualValue(serieData.radius, minChartWidth); + } + else + { + var minInsideRadius = minRadius > 0 ? minRadius : serie.context.insideRadius; + serieData.context.outsideRadius = serie.pieRoseType > 0 ? + minInsideRadius + (float)((serie.context.outsideRadius - minInsideRadius) * value / serie.context.dataMax) : + serie.context.outsideRadius; + } + if (minRadius > 0 && serieData.context.outsideRadius < minRadius) + { + serieData.context.outsideRadius = minRadius; + } + var offset = 0f; + var interactOffset = serie.animation.interaction.GetOffset(serie.context.outsideRadius); + if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) + { + offset += interactOffset; + } + if (offset > 0) + { + serieData.context.outsideRadius += interactOffset; + var currRad = serieData.context.halfAngle * Mathf.Deg2Rad; + var currSin = Mathf.Sin(currRad); + var currCos = Mathf.Cos(currRad); + serieData.context.offsetRadius = 0; + if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) + { + serieData.context.offsetRadius += interactOffset; + if (serieData.context.insideRadius > 0) + { + serieData.context.insideRadius += interactOffset; + } + } + serieData.context.offsetCenter = new Vector3( + serie.context.center.x + serieData.context.offsetRadius * currSin, + serie.context.center.y + serieData.context.offsetRadius * currCos); + } + else + { + serieData.context.offsetCenter = serie.context.center; + } + if (serieData.context.highlight) + { + serieData.context.outsideRadius = serie.animation.GetInteractionRadius(serieData.context.outsideRadius); + } + var halfRadius = serie.context.insideRadius + (serieData.context.outsideRadius - serie.context.insideRadius) / 2; + serieData.context.position = ChartHelper.GetPosition(serie.context.center, serieData.context.halfAngle, halfRadius); } private double GetTotalAngle(Serie serie, double dataTotal, ref float totalAngle) @@ -310,6 +343,9 @@ namespace XCharts.Runtime var interacting = false; var color = ColorUtil.clearColor32; var toColor = ColorUtil.clearColor32; + var interactDuration = serie.animation.GetInteractionDuration(); + var interactEnable = serie.animation.enable && serie.animation.interaction.enable + && !serie.animation.IsFadeIn() && !serie.animation.IsFadeOut(); var data = serie.data; serie.animation.InitProgress(0, 360); for (int n = 0; n < data.Count; n++) @@ -326,38 +362,33 @@ namespace XCharts.Runtime var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); var outsideRadius = 0f; + var needOffset = (serie.pieClickOffset && (serieData.selected || serieData.context.selected)); + 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 insideRadius = serieData.context.insideRadius * progress; - //if (!serieData.interact.TryGetValueAndColor(ref outsideRadius, ref color, ref toColor, ref interacting)) + if (!interactEnable || !serieData.interact.TryGetValueAndColor( + ref outsideRadius, ref offsetCenter, ref color, ref toColor, ref interacting, interactDuration)) { SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex); outsideRadius = serieData.context.outsideRadius * progress; - serieData.interact.SetValueAndColor(ref interacting, outsideRadius, color, toColor); - } - - if (serie.pieClickOffset && (serieData.selected || serieData.context.selected)) - { - var drawEndDegree = serieData.context.currentAngle; - var needRoundCap = serie.roundCap && insideRadius > 0; - UGL.DrawDoughnut(vh, serieData.context.offsetCenter, insideRadius, - outsideRadius, color, toColor, Color.clear, serieData.context.startAngle, - drawEndDegree, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, - needRoundCap, true); - } - else - { - var drawEndDegree = serieData.context.currentAngle; - var needRoundCap = serie.roundCap && insideRadius > 0; - UGL.DrawDoughnut(vh, serie.context.center, insideRadius, - outsideRadius, color, toColor, Color.clear, serieData.context.startAngle, - drawEndDegree, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, - needRoundCap, true); - DrawPieCenter(vh, serie, itemStyle, insideRadius); + if (interactEnable) + { + serieData.interact.SetValueAndColor(ref interacting, outsideRadius, color, toColor); + serieData.interact.SetPosition(ref interacting, offsetCenter); + } } + var drawEndDegree = serieData.context.currentAngle; + var needRoundCap = serie.roundCap && insideRadius > 0; + UGL.DrawDoughnut(vh, offsetCenter, insideRadius, + outsideRadius, color, toColor, Color.clear, serieData.context.startAngle, + drawEndDegree, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, + needRoundCap, true); + DrawPieCenter(vh, serie, itemStyle, insideRadius); if (serie.animation.CheckDetailBreak(serieData.context.toAngle)) break; @@ -368,145 +399,125 @@ namespace XCharts.Runtime serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize)); chart.RefreshPainter(serie); } - if (dataChanging) + if (dataChanging || interacting) { chart.RefreshPainter(serie); } } - private bool IsAnyPieClickOffset() + private static void UpdatePieLabelPosition(Serie serie, SerieData serieData) { - foreach (var serie in chart.series) + if (serieData.labelObject == null) return; + var startAngle = serie.context.startAngle; + var currAngle = serieData.context.halfAngle; + var currRad = currAngle * Mathf.Deg2Rad; + var offsetRadius = serieData.context.offsetRadius; + var insideRadius = serieData.context.insideRadius; + var outsideRadius = serieData.context.outsideRadius; + var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); + var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); + var center = serieData.context.offsetCenter; + var interact = false; + serieData.interact.TryGetValueAndColor(ref outsideRadius, ref center, ref interact, serie.animation.GetInteractionDuration()); + var diffAngle = (currAngle - startAngle) % 360; + var isLeft = diffAngle > 180 || (diffAngle == 0 && serieData.context.startAngle > 0); + switch (serieLabel.position) { - if (serie is Pie && serie.pieClickOffset) - return true; + case LabelStyle.Position.Center: + serieData.context.labelPosition = serie.context.center; + break; + case LabelStyle.Position.Inside: + case LabelStyle.Position.Middle: + var labelRadius = offsetRadius + insideRadius + (outsideRadius - insideRadius) / 2 + serieLabel.distance; + var labelCenter = new Vector2(center.x + labelRadius * Mathf.Sin(currRad), + center.y + labelRadius * Mathf.Cos(currRad)); + UpdateLabelPosition(serie, serieData, labelLine, labelCenter, isLeft); + break; + default: + //LabelStyle.Position.Outside + var startPos = new Vector2(center.x + outsideRadius * Mathf.Sin(currRad), + center.y + outsideRadius * Mathf.Cos(currRad)); + UpdateLabelPosition(serie, serieData, labelLine, startPos, isLeft); + break; } - return false; } - private bool IsAnyPieDataHighlight() + private static void UpdateLabelPosition(Serie serie, SerieData serieData, LabelLine labelLine, Vector3 startPosition, bool isLeft) { - foreach (var serie in chart.series) + serieData.context.labelLinePosition = startPosition; + if (labelLine == null || !labelLine.show) { - if (serie is Pie) - { - foreach (var serieData in serie.data) - { - if (serieData.context.highlight) - return true; - } - } + serieData.context.labelPosition = startPosition; + return; } - return false; + var dire = isLeft ? Vector3.left : Vector3.right; + var rad = Mathf.Deg2Rad * serieData.context.halfAngle; + var lineLength1 = ChartHelper.GetActualValue(labelLine.lineLength1, serie.context.outsideRadius); + var lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius); + var pos1 = startPosition; + var pos2 = pos1 + new Vector3(Mathf.Sin(rad) * lineLength1, Mathf.Cos(rad) * lineLength1); + var pos5 = labelLine.lineType == LabelLine.LineType.HorizontalLine + ? pos1 + dire * (lineLength1 + lineLength2) + labelLine.GetEndSymbolOffset() + : pos2 + dire * lineLength2 + labelLine.GetEndSymbolOffset(); + if (labelLine.lineEndX != 0) + { + pos5.x = isLeft ? -Mathf.Abs(labelLine.lineEndX) : Mathf.Abs(labelLine.lineEndX); + } + serieData.context.labelLinePosition2 = pos2; + serieData.context.labelPosition = pos5; } - private void DrawPieLabelLine(VertexHelper vh, Serie serie, bool drawHightlight) + private void DrawPieLabelLine(VertexHelper vh, Serie serie, bool isTop) { foreach (var serieData in serie.data) { var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); - if (drawHightlight && !serieData.context.highlight) continue; - if (!drawHightlight && serieData.context.highlight) continue; + var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); if (SerieLabelHelper.CanShowLabel(serie, serieData, serieLabel, 1)) { int colorIndex = chart.m_LegendRealShowName.IndexOf(serieData.name); - Color color = chart.theme.GetColor(colorIndex); - DrawPieLabelLine(vh, serie, serieData, color); - } - } - } - - private void DrawPieLabelLine(VertexHelper vh, Serie serie, SerieData serieData, Color color) - { - var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); - var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); - if (serieLabel != null && serieLabel.show && - labelLine != null && labelLine.show && - (serieLabel.IsDefaultPosition(LabelStyle.Position.Outside))) - { - var insideRadius = serieData.context.insideRadius; - var outSideRadius = serieData.context.outsideRadius; - var center = serie.context.center; - var currAngle = serieData.context.halfAngle; - - if (!ChartHelper.IsClearColor(labelLine.lineColor)) - color = labelLine.lineColor; - else if (labelLine.lineType == LabelLine.LineType.HorizontalLine) - color *= color; - - float currSin = Mathf.Sin(currAngle * Mathf.Deg2Rad); - float currCos = Mathf.Cos(currAngle * Mathf.Deg2Rad); - var radius1 = labelLine.lineType == LabelLine.LineType.HorizontalLine ? - serie.context.outsideRadius : outSideRadius; - var radius3 = insideRadius + (outSideRadius - insideRadius) / 2; - if (radius1 < serie.context.insideRadius) radius1 = serie.context.insideRadius; - radius1 -= 0.1f; - var pos0 = new Vector3(center.x + radius3 * currSin, center.y + radius3 * currCos); - var pos1 = new Vector3(center.x + radius1 * currSin, center.y + radius1 * currCos); - var pos2 = serieData.context.labelPosition; - Vector3 pos4, pos6; - var horizontalLineCircleRadius = labelLine.lineWidth * 4f; - var lineCircleDiff = horizontalLineCircleRadius - 0.3f; - var startAngle = serie.context.startAngle; - if (currAngle < 90) - { - var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3; - r4 += labelLine.lineLength1 - lineCircleDiff; - pos6 = pos0 + Vector3.right * lineCircleDiff; - pos4 = pos6 + Vector3.right * r4; - } - else if (currAngle < 180) - { - var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos * radius3, 2)) - currSin * radius3; - r4 += labelLine.lineLength1 - lineCircleDiff; - pos6 = pos0 + Vector3.right * lineCircleDiff; - pos4 = pos6 + Vector3.right * r4; - } - else if (currAngle < 270) - { - var currSin1 = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad); - var currCos1 = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad); - var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos1 * radius3, 2)) - currSin1 * radius3; - r4 += labelLine.lineLength1 - lineCircleDiff; - pos6 = pos0 + Vector3.left * lineCircleDiff; - pos4 = pos6 + Vector3.left * r4; - } - else - { - var currSin1 = Mathf.Sin((360 - currAngle) * Mathf.Deg2Rad); - var currCos1 = Mathf.Cos((360 - currAngle) * Mathf.Deg2Rad); - var r4 = Mathf.Sqrt(radius1 * radius1 - Mathf.Pow(currCos1 * radius3, 2)) - currSin1 * radius3; - r4 += labelLine.lineLength1 - lineCircleDiff; - pos6 = pos0 + Vector3.left * lineCircleDiff; - pos4 = pos6 + Vector3.left * r4; - } - var diffAngle = (currAngle - startAngle) % 360; - var isLeft = diffAngle > 180 || (diffAngle == 0 && serieData.context.startAngle > 0); - var pos5X = isLeft ? pos2.x - labelLine.lineLength2 : pos2.x + labelLine.lineLength2; - var pos5 = new Vector3(pos5X, pos2.y); - var angle = Vector3.Angle(pos1 - center, pos2 - pos1); - if (angle > 15) - { - UGL.DrawLine(vh, pos1, pos5, labelLine.lineWidth, color); - } - else - { - switch (labelLine.lineType) + if (serieLabel != null && serieLabel.show && + labelLine != null && labelLine.show) { - case LabelLine.LineType.BrokenLine: - UGL.DrawLine(vh, pos1, pos2, pos5, labelLine.lineWidth, color); - break; - case LabelLine.LineType.Curves: - UGL.DrawCurves(vh, pos1, pos5, pos1, pos2, labelLine.lineWidth, color, - chart.settings.lineSmoothness); - break; - case LabelLine.LineType.HorizontalLine: - UGL.DrawCricle(vh, pos0, horizontalLineCircleRadius, color); - UGL.DrawLine(vh, pos6, pos4, labelLine.lineWidth, color); - break; + if (serieLabel.position == LabelStyle.Position.Inside || serieLabel.position == LabelStyle.Position.Middle) + { + if (!isTop) continue; + } + else + { + if (isTop && !labelLine.startSymbol.show) continue; + } + var color = ChartHelper.IsClearColor(labelLine.lineColor) ? + chart.theme.GetColor(colorIndex) : + labelLine.lineColor; + switch (labelLine.lineType) + { + case LabelLine.LineType.BrokenLine: + UGL.DrawLine(vh, serieData.context.labelLinePosition, serieData.context.labelLinePosition2, + serieData.context.labelPosition, labelLine.lineWidth, color); + break; + case LabelLine.LineType.Curves: + if (serieData.context.labelLinePosition2 == serieData.context.labelPosition) + { + UGL.DrawCurves(vh, serieData.context.labelLinePosition, serieData.context.labelPosition, + serieData.context.labelLinePosition, (serieData.context.labelLinePosition + serieData.context.labelPosition) * 0.6f, + labelLine.lineWidth, color, chart.settings.lineSmoothness); + } + else + { + UGL.DrawCurves(vh, serieData.context.labelLinePosition, serieData.context.labelPosition, + serieData.context.labelLinePosition, serieData.context.labelLinePosition2, + labelLine.lineWidth, color, chart.settings.lineSmoothness); + } + break; + case LabelLine.LineType.HorizontalLine: + UGL.DrawLine(vh, serieData.context.labelLinePosition, serieData.context.labelPosition, + labelLine.lineWidth, color); + break; + } + DrawLabelLineSymbol(vh, labelLine, serieData.context.labelLinePosition, serieData.context.labelPosition, color); } } - DrawLabelLineSymbol(vh, labelLine, pos1, pos5, color); } } @@ -516,7 +527,8 @@ namespace XCharts.Runtime return -1; var dist = Vector2.Distance(local, serie.context.center); - var maxRadius = serie.context.outsideRadius + 3 * chart.theme.serie.pieSelectedOffset; + var interactOffset = serie.animation.interaction.GetOffset(serie.context.outsideRadius); + var maxRadius = serie.context.outsideRadius + 2 * interactOffset; if (dist < serie.context.insideRadius || dist > maxRadius) return -1; @@ -577,5 +589,131 @@ namespace XCharts.Runtime } return toAngle; } + + private void AvoidLabelOverlap(Serie serie, ComponentTheme theme) + { + if (!serie.avoidLabelOverlap) return; + var lastCheckPos = Vector3.zero; + var lastX = 0f; + var data = serie.data; + var splitCount = 0; + for (int n = 0; n < data.Count; n++) + { + var serieData = data[n]; + if (serieData.context.labelPosition.x != 0 && serieData.context.labelPosition.x < serie.context.center.x) + { + splitCount = n; + break; + } + } + var limitX = float.MinValue; + for (int n = 0; n < splitCount; n++) + { + CheckSerieDataLabel(serie, data[n], splitCount, false, n == splitCount - 1, theme, ref lastCheckPos, ref lastX, ref limitX); + } + lastCheckPos = Vector3.zero; + limitX = float.MaxValue; + for (int n = data.Count - 1; n >= splitCount; n--) + { + CheckSerieDataLabel(serie, data[n], data.Count - splitCount, true, n == splitCount, theme, ref lastCheckPos, ref lastX, ref limitX); + } + } + + private void CheckSerieDataLabel(Serie serie, SerieData serieData, int total, bool isLeft, bool isLastOne, ComponentTheme theme, + ref Vector3 lastCheckPos, ref float lastX, ref float limitX) + { + if (!serieData.context.canShowLabel) + { + serieData.SetLabelActive(false); + return; + } + if (!serieData.show) return; + var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); + if (serieLabel == null) return; + if (!serieLabel.show) return; + var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); + var fontSize = serieData.labelObject.GetHeight(); + var lineLength1 = 0f; + var lineLength2 = 0f; + if (labelLine != null && labelLine.show) + { + lineLength1 = ChartHelper.GetActualValue(labelLine.lineLength1, serie.context.outsideRadius); + lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius); + } + if (lastCheckPos == Vector3.zero) + { + lastCheckPos = serieData.context.labelPosition; + } + else if (serieData.context.labelPosition.x != 0) + { + if (lastCheckPos.y - serieData.context.labelPosition.y < fontSize) + { + var labelRadius = serie.context.outsideRadius + lineLength1; + var y1 = lastCheckPos.y - fontSize; + var cy = serie.context.center.y; + var diff = Mathf.Abs(y1 - cy); + var diffX = labelRadius * labelRadius - diff * diff; + diffX = diffX <= 0 ? 0 : diffX; + var x1 = serie.context.center.x + Mathf.Sqrt(diffX) * (isLeft ? -1 : 1); + var newPos = new Vector3(x1, y1); + serieData.context.labelLinePosition2 = newPos; + if (isLeft) + { + if (x1 < limitX) + { + limitX = x1; + serieData.context.labelPosition = new Vector3(newPos.x - lineLength2, newPos.y); + lastX = serieData.context.labelPosition.x; + } + else + { + serieData.context.labelPosition = new Vector3(lastX, y1); + lastX += 2; + } + } + else + { + if (x1 > limitX) + { + limitX = x1; + serieData.context.labelPosition = new Vector3(newPos.x + lineLength2, newPos.y); + lastX = serieData.context.labelPosition.x; + } + else + { + serieData.context.labelPosition = new Vector3(lastX, y1); + lastX -= 2; + } + + } + if (labelLine != null && labelLine.show && labelLine.lineEndX != 0) + { + serieData.context.labelPosition.x = isLeft ? -Mathf.Abs(labelLine.lineEndX) : Mathf.Abs(labelLine.lineEndX); + } + if (!isLastOne && serieData.context.labelPosition.y < serieData.context.labelLinePosition.y) + { + serieData.context.labelLinePosition2 = serieData.context.labelPosition; + } + else + { + if (isLeft && serieData.context.labelLinePosition2.x > serieData.context.labelLinePosition.x) + { + serieData.context.labelLinePosition2.x = serieData.context.labelLinePosition.x; + } + else if (!isLeft && serieData.context.labelLinePosition2.x < serieData.context.labelLinePosition.x) + { + serieData.context.labelLinePosition2.x = serieData.context.labelLinePosition.x; + } + } + + } + else + { + lastX = serieData.context.labelPosition.x; + } + lastCheckPos = serieData.context.labelPosition; + UpdateLabelPosition(serieData, serieLabel); + } + } } } \ No newline at end of file diff --git a/Runtime/Serie/Radar/Radar.cs b/Runtime/Serie/Radar/Radar.cs index 626465e9..d7d2e3dc 100644 --- a/Runtime/Serie/Radar/Radar.cs +++ b/Runtime/Serie/Radar/Radar.cs @@ -30,7 +30,7 @@ namespace XCharts.Runtime public static Serie AddDefaultSerie(BaseChart chart, string serieName) { - chart.AddChartComponentWhenNoExist<RadarCoord>(); + chart.EnsureChartComponent<RadarCoord>(); var serie = chart.AddSerie<Radar>(serieName); serie.symbol.show = true; serie.symbol.type = SymbolType.Circle; diff --git a/Runtime/Serie/Radar/RadarHandler.cs b/Runtime/Serie/Radar/RadarHandler.cs index 87f11e8b..6f32edfb 100644 --- a/Runtime/Serie/Radar/RadarHandler.cs +++ b/Runtime/Serie/Radar/RadarHandler.cs @@ -127,7 +127,7 @@ namespace XCharts.Runtime if (m_LegendEnter) { serieData.context.highlight = true; - serieData.interact.SetValue(ref needInteract, symbolSize, serieData.context.highlight); + serieData.interact.SetValue(ref needInteract, serie.animation.interaction.GetRadius(symbolSize)); } else { @@ -164,7 +164,10 @@ namespace XCharts.Runtime } } } - serieData.interact.SetValue(ref needInteract, symbolSize, serieData.context.highlight); + if (serieData.context.highlight) + serieData.interact.SetValue(ref needInteract, serie.animation.interaction.GetRadius(symbolSize)); + else + serieData.interact.SetValue(ref needInteract, symbolSize); } } break; @@ -173,7 +176,7 @@ namespace XCharts.Runtime for (int i = 0; i < serie.data.Count; i++) { var serieData = serie.data[i]; - var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize); + var size = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize); if (Vector3.Distance(chart.pointerPos, serieData.context.position) < size * 2) { serie.context.pointerEnter = true; @@ -237,11 +240,10 @@ namespace XCharts.Runtime var rate = serie.animation.GetCurrRate(); var dataChanging = false; var interacting = false; - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); - var unscaledTime = serie.animation.unscaledTime; SerieHelper.GetAllMinMaxData(serie, m_RadarCoord.ceilRate); Color32 areaColor, areaToColor; var startAngle = m_RadarCoord.startAngle * Mathf.PI / 180; + var interactDuration = serie.animation.GetInteractionDuration(); for (int j = 0; j < serie.data.Count; j++) { var serieData = serie.data[j]; @@ -265,7 +267,7 @@ namespace XCharts.Runtime if (n >= serieData.data.Count) break; var min = m_RadarCoord.GetIndicatorMin(n); var max = m_RadarCoord.GetIndicatorMax(n); - var value = serieData.GetCurrData(n, dataChangeDuration, unscaledTime); + var value = serieData.GetCurrData(n, serie.animation); if (serieData.IsDataChanged()) dataChanging = true; if (max == 0) { @@ -333,9 +335,9 @@ namespace XCharts.Runtime { var point = serieData.context.dataPoints[m]; var symbolSize = 0f; - if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting)) + if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting, interactDuration)) { - symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, chart.theme.serie.lineSymbolSize, serieState); + symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme.serie.lineSymbolSize, serieState); serieData.interact.SetValue(ref interacting, symbolSize); symbolSize = serie.animation.GetSysmbolSize(symbolSize); } @@ -379,8 +381,6 @@ namespace XCharts.Runtime var rate = serie.animation.GetCurrRate(); var dataChanging = false; - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); - var unscaledTime = serie.animation.unscaledTime; var startIndex = GetStartShowIndex(serie); var endIndex = GetEndShowIndex(serie); var startAngle = m_RadarCoord.startAngle * Mathf.PI / 180; @@ -404,7 +404,7 @@ namespace XCharts.Runtime var index = serieData.index; var p = m_RadarCoord.context.center; var max = m_RadarCoord.GetIndicatorMax(index); - var value = serieData.GetCurrData(1, dataChangeDuration, unscaledTime); + var value = serieData.GetCurrData(1, serie.animation); if (serieData.IsDataChanged()) dataChanging = true; if (max == 0) { @@ -484,7 +484,7 @@ namespace XCharts.Runtime var serieData = serie.data[j]; if (!serieData.show) continue; var state = SerieHelper.GetSerieState(serie, serieData); - var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, chart.theme.serie.lineSymbolSize, state); + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme.serie.lineSymbolSize, state); var colorIndex = serie.colorByData ? serieData.index : serie.context.colorIndex; SerieHelper.GetItemColor(out symbolColor, out symbolToColor, out symbolEmptyColor, serie, serieData, chart.theme, colorIndex, state); SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, serieData, chart.theme, state); diff --git a/Runtime/Serie/Ring/RingHandler.cs b/Runtime/Serie/Ring/RingHandler.cs index f31021e9..9ca6ccc9 100644 --- a/Runtime/Serie/Ring/RingHandler.cs +++ b/Runtime/Serie/Ring/RingHandler.cs @@ -10,7 +10,6 @@ namespace XCharts.Runtime [UnityEngine.Scripting.Preserve] internal sealed class RingHandler : SerieHandler<Ring> { - public override int defaultDimension { get { return 0; } } public override void Update() @@ -100,7 +99,7 @@ namespace XCharts.Runtime param.color = color; param.marker = SerieHelper.GetItemMarker(serie, serieData, marker); param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter); - param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter);; + param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter); ; param.columns.Clear(); param.columns.Add(param.marker); @@ -110,59 +109,10 @@ namespace XCharts.Runtime paramList.Add(param); } - public override Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label) - { - var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); - var centerRadius = (serieData.context.outsideRadius + serieData.context.insideRadius) / 2; - var startAngle = serieData.context.startAngle; - var toAngle = serieData.context.toAngle; - switch (label.position) - { - case LabelStyle.Position.Bottom: - case LabelStyle.Position.Start: - var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius; - var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius; - var xDiff = serie.clockwise ? -label.distance : label.distance; - - if (labelLine != null && labelLine.show) - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px1, py1) + labelLine.GetStartSymbolOffset(); - serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine) + new Vector3(xDiff, 0); - } - else - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px1 + xDiff, py1); - serieData.context.labelPosition = serieData.context.labelLinePosition; - } - break; - case LabelStyle.Position.Top: - case LabelStyle.Position.End: - startAngle += serie.clockwise ? -label.distance : label.distance; - toAngle += serie.clockwise ? label.distance : -label.distance; - var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius; - var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius; - - if (labelLine != null && labelLine.show) - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2) + labelLine.GetStartSymbolOffset(); - serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine); - } - else - { - serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2); - serieData.context.labelPosition = serieData.context.labelLinePosition; - } - break; - default: //LabelStyle.Position.Center - serieData.context.labelLinePosition = serie.context.center + label.offset; - serieData.context.labelPosition = serieData.context.labelLinePosition; - break; - } - return serieData.context.labelPosition; - } - private Vector3 GetLabelLineEndPosition(Serie serie, SerieData serieData, LabelLine labelLine) { + if (labelLine == null || !labelLine.show) + return serieData.context.labelLinePosition; var isRight = !serie.clockwise; var dire = isRight ? Vector3.right : Vector3.left; var rad = Mathf.Deg2Rad * (isRight ? labelLine.lineAngle : 180 - labelLine.lineAngle); @@ -170,18 +120,22 @@ namespace XCharts.Runtime var lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius); var pos1 = serieData.context.labelLinePosition; var pos2 = pos1 + new Vector3(Mathf.Cos(rad) * lineLength1, Mathf.Sin(rad) * lineLength1); - var pos5 = pos2 + dire * lineLength2; - return pos5 + labelLine.GetEndSymbolOffset(); + var pos5 = labelLine.lineType == LabelLine.LineType.HorizontalLine + ? pos1 + dire * (lineLength1 + lineLength2) + labelLine.GetEndSymbolOffset() + : pos2 + dire * lineLength2 + labelLine.GetEndSymbolOffset(); + if (labelLine.lineEndX != 0) + { + pos5.x = labelLine.lineEndX; + } + return pos5; } public override void DrawSerie(VertexHelper vh) { if (!serie.show || serie.animation.HasFadeOut()) return; + UpdateRuntimeData(); var data = serie.data; serie.animation.InitProgress(serie.startAngle, serie.startAngle + 360); - SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight); - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); - var unscaledTime = serie.animation.unscaledTime; var ringWidth = serie.context.outsideRadius - serie.context.insideRadius; var dataChanging = false; for (int j = 0; j < data.Count; j++) @@ -189,32 +143,37 @@ namespace XCharts.Runtime var serieData = data[j]; if (!serieData.show) continue; if (serieData.IsDataChanged()) dataChanging = true; - var value = serieData.GetFirstData(unscaledTime, dataChangeDuration); + var outsideRadius = serie.context.outsideRadius - j * (ringWidth + serie.gap); + if (outsideRadius < 0) continue; + var value = serieData.GetCurrData(0, serie.animation, false, false); var max = serieData.GetLastData(); - var degree = (float) (360 * value / max); + var degree = (float)(360 * value / max); var startDegree = GetStartAngle(serie); var toDegree = GetToAngle(serie, degree); var itemStyle = SerieHelper.GetItemStyle(serie, serieData); var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); Color32 itemColor, itemToColor; SerieHelper.GetItemColor(out itemColor, out itemToColor, serie, serieData, chart.theme, colorIndex); - var outsideRadius = serie.context.outsideRadius - j * (ringWidth + serie.gap); + var insideRadius = outsideRadius - ringWidth; var borderWidth = itemStyle.borderWidth; var borderColor = itemStyle.borderColor; var roundCap = serie.roundCap && insideRadius > 0; - - serieData.context.startAngle = startDegree; - serieData.context.toAngle = toDegree; - serieData.context.insideRadius = insideRadius; - serieData.context.outsideRadius = serieData.radius > 0 ? serieData.radius : outsideRadius; DrawBackground(vh, serie, serieData, j, insideRadius, outsideRadius); UGL.DrawDoughnut(vh, serie.context.center, insideRadius, outsideRadius, itemColor, itemToColor, Color.clear, startDegree, toDegree, borderWidth, borderColor, 0, chart.settings.cicleSmoothness, roundCap, serie.clockwise); DrawCenter(vh, serie, serieData, insideRadius, j == data.Count - 1); + } + for (int j = 0; j < data.Count; j++) + { + var serieData = data[j]; + if (!serieData.show) continue; var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); + var colorIndex = chart.GetLegendRealShowNameIndex(serieData.legendName); + Color32 itemColor, itemToColor; + SerieHelper.GetItemColor(out itemColor, out itemToColor, serie, serieData, chart.theme, colorIndex); if (SerieLabelHelper.CanShowLabel(serie, serieData, serieLabel, 0)) { DrawRingLabelLine(vh, serie, serieData, itemColor); @@ -231,6 +190,32 @@ namespace XCharts.Runtime } } + private void UpdateRuntimeData() + { + var data = serie.data; + SerieHelper.UpdateCenter(serie, chart); + var ringWidth = serie.context.outsideRadius - serie.context.insideRadius; + for (int j = 0; j < data.Count; j++) + { + var serieData = data[j]; + if (!serieData.show) continue; + var outsideRadius = serie.context.outsideRadius - j * (ringWidth + serie.gap); + if (outsideRadius < 0) continue; + var value = serieData.GetCurrData(0, serie.animation, false, false); + var max = serieData.GetLastData(); + var degree = (float)(360 * value / max); + var startDegree = GetStartAngle(serie); + var toDegree = GetToAngle(serie, degree); + var insideRadius = outsideRadius - ringWidth; + serieData.context.startAngle = startDegree; + serieData.context.toAngle = toDegree; + serieData.context.insideRadius = insideRadius; + serieData.context.outsideRadius = serieData.radius > 0 ? serieData.radius : outsideRadius; + UpdateLabelPosition(serieData); + } + AvoidLabelOverlap(); + } + public override void OnLegendButtonClick(int index, string legendName, bool show) { if (!serie.IsLegendName(legendName)) @@ -372,6 +357,85 @@ namespace XCharts.Runtime return angle; } + private void UpdateLabelPosition(SerieData serieData) + { + if (serieData.labelObject == null) return; + var label = SerieHelper.GetSerieLabel(serie, serieData); + var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); + var centerRadius = (serieData.context.outsideRadius + serieData.context.insideRadius) / 2; + var startAngle = serieData.context.startAngle; + var toAngle = serieData.context.toAngle; + switch (label.position) + { + case LabelStyle.Position.Bottom: + case LabelStyle.Position.Start: + var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius; + var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius; + var xDiff = serie.clockwise ? -label.distance : label.distance; + + if (labelLine != null && labelLine.show) + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px1, py1) + labelLine.GetStartSymbolOffset(); + serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine) + new Vector3(xDiff, 0); + } + else + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px1 + xDiff, py1); + serieData.context.labelPosition = serieData.context.labelLinePosition; + } + break; + case LabelStyle.Position.Top: + case LabelStyle.Position.End: + case LabelStyle.Position.Outside: + startAngle += serie.clockwise ? -label.distance : label.distance; + toAngle += serie.clockwise ? label.distance : -label.distance; + var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius; + var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius; + + if (labelLine != null && labelLine.show) + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2) + labelLine.GetStartSymbolOffset(); + serieData.context.labelPosition = GetLabelLineEndPosition(serie, serieData, labelLine); + } + else + { + serieData.context.labelLinePosition = serie.context.center + new Vector3(px2, py2); + serieData.context.labelPosition = serieData.context.labelLinePosition; + } + break; + default: //LabelStyle.Position.Center + serieData.context.labelLinePosition = serie.context.center + label.offset; + serieData.context.labelPosition = serieData.context.labelLinePosition; + break; + } + } + + private void AvoidLabelOverlap() + { + if (!serie.avoidLabelOverlap) return; + serie.context.sortedData.Clear(); + foreach (var serieData in serie.data) + { + serie.context.sortedData.Add(serieData); + } + serie.context.sortedData.Sort(delegate (SerieData a, SerieData b) + { + if (a == null || b == null) return 0; + return a.context.labelPosition.y.CompareTo(b.context.labelPosition.y); + }); + var startY = serie.context.sortedData[0].context.labelPosition.y; + for (int i = 1; i < serie.context.sortedData.Count; i++) + { + var serieData = serie.context.sortedData[i]; + var fontSize = serieData.labelObject.GetHeight(); + if (serieData.context.labelPosition.y - startY < fontSize) + { + serieData.context.labelPosition.y = startY + fontSize; + } + startY = serieData.context.labelPosition.y; + } + } + private void DrawRingLabelLine(VertexHelper vh, Serie serie, SerieData serieData, Color32 defaltColor) { var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); @@ -383,14 +447,11 @@ namespace XCharts.Runtime ChartHelper.GetHighlightColor(defaltColor, 0.9f) : labelLine.lineColor; var isRight = !serie.clockwise; - var dire = isRight ? Vector3.right : Vector3.left; var rad = Mathf.Deg2Rad * (isRight ? labelLine.lineAngle : 180 - labelLine.lineAngle); var lineLength1 = ChartHelper.GetActualValue(labelLine.lineLength1, serie.context.outsideRadius); - var lineLength2 = ChartHelper.GetActualValue(labelLine.lineLength2, serie.context.outsideRadius); var pos1 = serieData.context.labelLinePosition; var pos2 = pos1 + new Vector3(Mathf.Cos(rad) * lineLength1, Mathf.Sin(rad) * lineLength1); - var pos5 = pos2 + dire * lineLength2 + labelLine.GetEndSymbolOffset(); - serieData.context.labelPosition = pos5; + var pos5 = serieData.context.labelPosition; switch (labelLine.lineType) { case LabelLine.LineType.BrokenLine: @@ -401,8 +462,6 @@ namespace XCharts.Runtime chart.settings.lineSmoothness, UGL.Direction.XAxis); break; case LabelLine.LineType.HorizontalLine: - pos5 = pos1 + dire * (lineLength1 + lineLength2); - serieData.context.labelPosition = pos5; UGL.DrawLine(vh, pos1, pos5, labelLine.lineWidth, color); break; } diff --git a/Runtime/Serie/Scatter/BaseScatterHandler.cs b/Runtime/Serie/Scatter/BaseScatterHandler.cs index 6be8113c..430f0bb0 100644 --- a/Runtime/Serie/Scatter/BaseScatterHandler.cs +++ b/Runtime/Serie/Scatter/BaseScatterHandler.cs @@ -77,12 +77,11 @@ namespace XCharts.Runtime serie.context.pointerItemDataIndex = -1; serie.context.pointerEnter = false; var themeSymbolSize = chart.theme.serie.scatterSymbolSize; - var themeSymbolSelectedSize = chart.theme.serie.scatterSymbolSelectedSize; var needInteract = false; for (int i = serie.dataCount - 1; i >= 0; i--) { var serieData = serie.data[i]; - var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize); + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize); if (m_LegendEnter || (!needHideAll && Vector3.Distance(serieData.context.position, chart.pointerPos) <= symbolSize)) { @@ -95,7 +94,7 @@ namespace XCharts.Runtime serieData.context.highlight = false; } var state = SerieHelper.GetSerieState(serie, serieData, true); - symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, state); + symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, themeSymbolSize, state); serieData.interact.SetValue(ref needInteract, symbolSize); } if (needInteract) @@ -133,7 +132,9 @@ namespace XCharts.Runtime serie.dataCount; serie.animation.InitProgress(0, 1); var rate = serie.animation.GetCurrRate(); - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + var dataChangeDuration = serie.animation.GetChangeDuration(); + var interactDuration = serie.animation.GetInteractionDuration(); + var isFadeOut = serie.animation.IsFadeOut(); var unscaledTime = serie.animation.unscaledTime; var dataChanging = false; var interacting = false; @@ -157,8 +158,8 @@ namespace XCharts.Runtime SerieHelper.GetItemColor(out color, out toColor, out emptyColor, serie, serieData, chart.theme, colorIndex, state); SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, serieData, chart.theme, state); - double xValue = serieData.GetCurrData(0, dataChangeDuration, unscaledTime, xAxis.inverse); - double yValue = serieData.GetCurrData(1, dataChangeDuration, unscaledTime, yAxis.inverse); + double xValue = serieData.GetCurrData(0, 0, isFadeOut ? 0 : dataChangeDuration, unscaledTime, xAxis.inverse); + double yValue = serieData.GetCurrData(1, 0, isFadeOut ? 0 : dataChangeDuration, unscaledTime, yAxis.inverse); if (serieData.IsDataChanged()) dataChanging = true; @@ -177,12 +178,15 @@ namespace XCharts.Runtime serieData.context.position = pos; var datas = serieData.data; var symbolSize = 0f; - if (!serieData.interact.TryGetValue(ref symbolSize, ref interacting)) + if (isFadeOut || !serieData.interact.TryGetValue(ref symbolSize, ref interacting, interactDuration)) { - symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, chart.theme.serie.scatterSymbolSize, state); - serieData.interact.SetValue(ref interacting, symbolSize); + symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme.serie.scatterSymbolSize, state); + if (!isFadeOut) + { + serieData.interact.SetValue(ref interacting, symbolSize, true); + serieData.interact.TryGetValue(ref symbolSize, ref interacting, interactDuration); + } } - symbolSize *= rate; if (isEffectScatter) @@ -198,7 +202,6 @@ namespace XCharts.Runtime } else { - if (symbolSize > 100) symbolSize = 100; chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, pos, color, toColor, emptyColor, borderColor, symbol.gap, cornerRadius); } @@ -237,7 +240,7 @@ namespace XCharts.Runtime serie.animation.InitProgress(0, 1); var rate = serie.animation.GetCurrRate(); - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + var dataChangeDuration = serie.animation.GetChangeDuration(); var unscaledTime = serie.animation.unscaledTime; var dataChanging = false; var dataList = serie.GetDataList(xDataZoom); @@ -264,7 +267,7 @@ namespace XCharts.Runtime dataChanging = true; var pos = Vector3.zero; - var xValue = serieData.GetCurrData(0, dataChangeDuration, unscaledTime, axis.inverse); + var xValue = serieData.GetCurrData(0, 0, dataChangeDuration, unscaledTime, axis.inverse); if (axis.orient == Orient.Horizonal) { @@ -283,7 +286,7 @@ namespace XCharts.Runtime serieData.context.position = pos; var datas = serieData.data; - var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, chart.theme.serie.scatterSymbolSize, state); + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme.serie.scatterSymbolSize, state); symbolSize *= rate; if (isEffectScatter) diff --git a/Runtime/Serie/Scatter/EffectScatter.cs b/Runtime/Serie/Scatter/EffectScatter.cs index ca10028e..0e3e89ae 100644 --- a/Runtime/Serie/Scatter/EffectScatter.cs +++ b/Runtime/Serie/Scatter/EffectScatter.cs @@ -5,6 +5,7 @@ namespace XCharts.Runtime [System.Serializable] [SerieHandler(typeof(EffectScatterHandler), true)] [CoordOptions(typeof(GridCoord), typeof(SingleAxisCoord))] + [DefaultTooltip(Tooltip.Type.None, Tooltip.Trigger.Item)] [SerieComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField("m_Radius")] diff --git a/Runtime/Serie/Scatter/Scatter.cs b/Runtime/Serie/Scatter/Scatter.cs index a6367539..bf64074f 100644 --- a/Runtime/Serie/Scatter/Scatter.cs +++ b/Runtime/Serie/Scatter/Scatter.cs @@ -5,6 +5,7 @@ namespace XCharts.Runtime [System.Serializable] [SerieHandler(typeof(ScatterHandler), true)] [CoordOptions(typeof(GridCoord), typeof(SingleAxisCoord))] + [DefaultTooltip(Tooltip.Type.None, Tooltip.Trigger.Item)] [SerieComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField("m_Radius")] diff --git a/Runtime/Serie/Serie.cs b/Runtime/Serie/Serie.cs index 2b73a87a..a2d5f6e4 100644 --- a/Runtime/Serie/Serie.cs +++ b/Runtime/Serie/Serie.cs @@ -246,6 +246,7 @@ namespace XCharts.Runtime [SerializeField] private int m_PolarIndex = 0; [SerializeField] private int m_SingleAxisIndex = 0; [SerializeField] private int m_ParallelIndex = 0; + [SerializeField][Since("v3.8.0")] private int m_GridIndex = -1; [SerializeField] protected int m_MinShow; [SerializeField] protected int m_MaxShow; [SerializeField] protected int m_MaxCache; @@ -279,6 +280,7 @@ namespace XCharts.Runtime [SerializeField] private float m_Gap; [SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.48f }; [SerializeField] private float[] m_Radius = new float[2] { 0, 0.28f }; + [SerializeField][Since("v3.8.0")] private float m_MinRadius = 0f; [SerializeField][Range(2, 10)] private int m_ShowDataDimension; [SerializeField] private bool m_ShowDataName; @@ -476,6 +478,15 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_ParallelIndex, value)) SetAllDirty(); } } /// <summary> + /// Index of layout component that serie uses. Default is -1 means not use layout, otherwise use the first layout component. + /// |所使用的 layout 组件的 index。 默认为-1不指定index, 当为大于或等于0时, 为第一个layout组件的第index个格子。 + /// </summary> + public int gridIndex + { + get { return m_GridIndex; } + set { if (PropertyUtil.SetStruct(ref m_GridIndex, value)) SetAllDirty(); } + } + /// <summary> /// The min number of data to show in chart. /// |系列所显示数据的最小索引 /// </summary> @@ -679,6 +690,15 @@ namespace XCharts.Runtime set { if (value != null && value.Length == 2) { m_Radius = value; SetVerticesDirty(); } } } /// <summary> + /// the min radius of chart. It can be used to limit the minimum radius of the rose chart. + /// |最小半径。可用于限制玫瑰图的最小半径。 + /// </summary> + public float minRadius + { + get { return m_MinRadius; } + set { if (PropertyUtil.SetStruct(ref m_MinRadius, value)) SetVerticesDirty(); } + } + /// <summary> /// 最小值。 /// </summary> public float min @@ -1031,6 +1051,12 @@ namespace XCharts.Runtime titleDirty = true; } + public override void SetVerticesDirty() + { + base.SetVerticesDirty(); + interactDirty = true; + } + private bool AnySerieDataVerticesDirty() { if (IsPerformanceMode()) @@ -1066,6 +1092,7 @@ namespace XCharts.Runtime public bool labelDirty { get; set; } public bool titleDirty { get; set; } public bool dataDirty { get; set; } + public bool interactDirty { get; set; } private void SetSerieNameDirty() { @@ -1176,12 +1203,13 @@ namespace XCharts.Runtime } else { - var duration = animation.GetUpdateAnimationDuration(); + var duration = animation.GetChangeDuration(); + var dataAddDuration = animation.GetAdditionDuration(); var unscaledTime = animation.unscaledTime; foreach (var sdata in data) { if (sdata.show && !IsIgnoreValue(sdata, sdata.data[1])) - total += sdata.GetCurrData(1, duration, unscaledTime); + total += sdata.GetCurrData(1, dataAddDuration, duration, unscaledTime); } } return total; @@ -1301,6 +1329,8 @@ namespace XCharts.Runtime m_Data.Insert(0, serieData); else m_Data.Add(serieData); + serieData.OnAdd(animation); + context.totalDataIndex++; SetVerticesDirty(); dataDirty = true; m_NeedUpdateFilterData = true; @@ -1444,7 +1474,8 @@ namespace XCharts.Runtime serieData.name = name; serieData.index = m_Data.Count; serieData.id = id; - serieData.data = new List<double>() { m_Data.Count, value }; + serieData.data.Add(m_Data.Count); + serieData.data.Add(value); AddChildData(parent, serieData); return serieData; } @@ -1455,7 +1486,7 @@ namespace XCharts.Runtime serieData.name = name; serieData.index = m_Data.Count; serieData.id = id; - serieData.data = new List<double>(value); + serieData.data.AddRange(value); AddChildData(parent, serieData); return serieData; } @@ -1535,7 +1566,7 @@ namespace XCharts.Runtime var serieData = GetDataList(dataZoom); if (index < serieData.Count) { - var value = serieData[index].GetCurrData(1, animation.GetUpdateAnimationDuration(), animation.unscaledTime); + var value = serieData[index].GetCurrData(1, 0, animation.GetChangeDuration(), animation.unscaledTime); if (showAsPositiveNumber) value = Math.Abs(value); return value; @@ -1697,7 +1728,7 @@ namespace XCharts.Runtime if (index >= 0 && index < m_Data.Count) { var animationOpen = animation.enable; - var animationDuration = animation.GetUpdateAnimationDuration(); + var animationDuration = animation.GetChangeDuration(); var unscaledTime = animation.unscaledTime; var flag = m_Data[index].UpdateData(dimension, value, animationOpen, unscaledTime, animationDuration); if (flag) @@ -1724,7 +1755,7 @@ namespace XCharts.Runtime { var serieData = m_Data[index]; var animationOpen = animation.enable; - var animationDuration = animation.GetUpdateAnimationDuration(); + var animationDuration = animation.GetChangeDuration(); var unscaledTime = animation.unscaledTime; for (int i = 0; i < values.Count; i++) serieData.UpdateData(i, values[i], animationOpen, unscaledTime, animationDuration); @@ -1907,6 +1938,7 @@ namespace XCharts.Runtime /// </summary> public void AnimationFadeIn() { + ResetInteract(); if (animation.enable) animation.FadeIn(); SetVerticesDirty(); } @@ -1916,6 +1948,7 @@ namespace XCharts.Runtime /// </summary> public void AnimationFadeOut() { + ResetInteract(); if (animation.enable) animation.FadeOut(); SetVerticesDirty(); } diff --git a/Runtime/Serie/SerieContext.cs b/Runtime/Serie/SerieContext.cs index 1f7c2348..fe642286 100644 --- a/Runtime/Serie/SerieContext.cs +++ b/Runtime/Serie/SerieContext.cs @@ -115,5 +115,9 @@ namespace XCharts.Runtime public List<PointInfo> drawPoints = new List<PointInfo>(); public SerieParams param = new SerieParams(); public ChartLabel titleObject { get; set; } + + public Tooltip.Type tooltipType; + public Tooltip.Trigger tooltipTrigger; + public int totalDataIndex; } } \ No newline at end of file diff --git a/Runtime/Serie/SerieData.cs b/Runtime/Serie/SerieData.cs index 2f448df8..d1ae84d0 100644 --- a/Runtime/Serie/SerieData.cs +++ b/Runtime/Serie/SerieData.cs @@ -152,6 +152,8 @@ namespace XCharts.Runtime private List<double> m_PreviousData = new List<double>(); private List<float> m_DataUpdateTime = new List<float>(); private List<bool> m_DataUpdateFlag = new List<bool>(); + private List<float> m_DataAddTime = new List<float>(); + private List<bool> m_DataAddFlag = new List<bool>(); private List<Vector2> m_PolygonPoints = new List<Vector2>(); public override bool vertsDirty @@ -222,6 +224,8 @@ namespace XCharts.Runtime m_PreviousData.Clear(); m_DataUpdateTime.Clear(); m_DataUpdateFlag.Clear(); + m_DataAddTime.Clear(); + m_DataAddFlag.Clear(); m_Labels.Clear(); m_LabelLines.Clear(); m_ItemStyles.Clear(); @@ -234,6 +238,30 @@ namespace XCharts.Runtime m_SelectStyles.Clear(); } + public void OnAdd(AnimationStyle animation, double startValue = 0) + { + if (!animation.enable) return; + if (!animation.context.enableSerieDataAddedAnimation) + { + animation.Addition(); + return; + } +#if UNITY_EDITOR + if (!Application.isPlaying) + return; +#endif + m_DataAddTime.Clear(); + m_DataAddFlag.Clear(); + if (animation.GetAdditionDuration() > 0) + { + for (int i = 0; i < m_Data.Count; i++) + { + m_DataAddTime.Add(animation.unscaledTime ? Time.unscaledTime : Time.time); + m_DataAddFlag.Add(true); + } + } + } + [Obsolete("GetOrAddComponent is obsolete. Use EnsureComponent instead.")] public T GetOrAddComponent<T>() where T : ChildComponent, ISerieDataComponent { @@ -469,7 +497,7 @@ namespace XCharts.Runtime public double GetFirstData(bool unscaledTime, float animationDuration = 500f) { - if (m_Data.Count > 0) return GetCurrData(0, animationDuration, unscaledTime); + if (m_Data.Count > 0) return GetCurrData(0, 0, animationDuration, unscaledTime); return 0; } @@ -479,62 +507,137 @@ namespace XCharts.Runtime return 0; } - public double GetCurrData(int index, float animationDuration = 500f, bool unscaledTime = false, bool inverse = false) + public double GetCurrData(int index, AnimationStyle animation, bool inverse = false, bool loop = false) { - return GetCurrData(index, animationDuration, inverse, 0, 0, unscaledTime); + if (animation == null || !animation.enable) + return GetData(index, inverse); + else + return GetCurrData(index, animation.GetAdditionDuration(), animation.GetChangeDuration(), + inverse, 0, 0, animation.unscaledTime, loop); } - public double GetCurrData(int index, float animationDuration, bool inverse, double min, double max, bool unscaledTime, bool loop = false) + public double GetCurrData(int index, AnimationStyle animation, bool inverse, double min, double max, bool loop = false) { - if (index < m_DataUpdateFlag.Count && m_DataUpdateFlag[index] && animationDuration > 0) + if (animation == null || !animation.enable) + return GetData(index, inverse); + else + return GetCurrData(index, animation.GetAdditionDuration(), animation.GetChangeDuration(), + inverse, min, max, animation.unscaledTime, loop); + } + + public double GetCurrData(int index, float dataAddDuration = 500f, float animationDuration = 500f, bool unscaledTime = false, bool inverse = false) + { + return GetCurrData(index, dataAddDuration, animationDuration, inverse, 0, 0, unscaledTime); + } + + public double GetCurrData(int index, float dataAddDuration, float animationDuration, bool inverse, double min, double max, bool unscaledTime, bool loop = false) + { + if (dataAddDuration > 0) { - var time = (unscaledTime ? Time.unscaledTime : Time.time) - m_DataUpdateTime[index]; + if (index < m_DataAddFlag.Count && m_DataAddFlag[index]) + { + var time = (unscaledTime ? Time.unscaledTime : Time.time) - m_DataAddTime[index]; + var total = dataAddDuration / 1000; + + var rate = time / total; + if (rate > 1) rate = 1; + if (rate < 1) + { + var prev = min > 0 ? min : 0; + var next = GetData(index); + var curr = MathUtil.Lerp(prev, next, rate); + curr = inverse ? -curr : curr; + return curr; + } + else + { + for (int i = 0; i < m_DataAddFlag.Count; i++) + m_DataAddFlag[i] = false; + return GetData(index, inverse); + } + } + } + if (animationDuration > 0) + { + if (index < m_DataUpdateFlag.Count && m_DataUpdateFlag[index]) + { + var time = (unscaledTime ? Time.unscaledTime : Time.time) - m_DataUpdateTime[index]; + var total = animationDuration / 1000; + + var rate = time / total; + if (rate > 1) rate = 1; + if (rate < 1) + { + CheckLastData(unscaledTime); + var prev = GetPreviousData(index); + var next = GetData(index); + if (loop && next <= min && prev != 0) + { + next = max; + } + var curr = MathUtil.Lerp(prev, next, rate); + if (min != 0 || max != 0) + { + if (inverse) + { + var temp = min; + min = -max; + max = -temp; + } + var pre = m_PreviousData[index]; + if (pre < min) + { + m_PreviousData[index] = min; + curr = min; + } + else if (pre > max) + { + m_PreviousData[index] = max; + curr = max; + } + } + curr = inverse ? -curr : curr; + return curr; + } + else + { + for (int i = 0; i < m_DataUpdateFlag.Count; i++) + m_DataUpdateFlag[i] = false; + return GetData(index, inverse); + } + } + else + { + return GetData(index, inverse); + } + } + return GetData(index, inverse); + } + + public double GetAddAnimationData(double min, double max, float animationDuration = 500f, bool unscaledTime = false) + { + if (animationDuration > 0 && m_DataAddFlag.Count > 0 && m_DataAddFlag[0]) + { + var time = (unscaledTime ? Time.unscaledTime : Time.time) - m_DataAddTime[0]; var total = animationDuration / 1000; var rate = time / total; if (rate > 1) rate = 1; if (rate < 1) { - CheckLastData(unscaledTime); - var prev = GetPreviousData(index); - var next = GetData(index); - if (loop) - { - if (next <= min && prev != 0) next = max; - } - var curr = MathUtil.Lerp(prev, next, rate); - if (min != 0 || max != 0) - { - if (inverse) - { - var temp = min; - min = -max; - max = -temp; - } - var pre = m_PreviousData[index]; - if (pre < min) - { - m_PreviousData[index] = min; - curr = min; - } - else if (pre > max) - { - m_PreviousData[index] = max; - curr = max; - } - } - curr = inverse ? -curr : curr; + var curr = MathUtil.Lerp(min, max, rate); return curr; } else { - m_DataUpdateFlag[index] = false; - return GetData(index, inverse); + for (int i = 0; i < m_DataAddFlag.Count; i++) + m_DataAddFlag[i] = false; + return max; } } else { - return GetData(index, inverse); + return max; } } @@ -600,8 +703,7 @@ namespace XCharts.Runtime if (dimension >= 0 && dimension < data.Count) { CheckLastData(unscaledTime); - m_PreviousData[dimension] = GetCurrData(dimension, animationDuration, unscaledTime); - //m_PreviousData[dimension] = data[dimension];; + m_PreviousData[dimension] = GetCurrData(dimension, 0, animationDuration, unscaledTime); m_DataUpdateTime[dimension] = (unscaledTime ? Time.unscaledTime : Time.time); m_DataUpdateFlag[dimension] = updateAnimation; data[dimension] = value; @@ -640,6 +742,8 @@ namespace XCharts.Runtime { for (int i = 0; i < m_DataUpdateFlag.Count; i++) if (m_DataUpdateFlag[i]) return true; + for (int i = 0; i < m_DataAddFlag.Count; i++) + if (m_DataAddFlag[i]) return true; return false; } diff --git a/Runtime/Serie/SerieDataContext.cs b/Runtime/Serie/SerieDataContext.cs index f549c9f9..685f541f 100644 --- a/Runtime/Serie/SerieDataContext.cs +++ b/Runtime/Serie/SerieDataContext.cs @@ -8,6 +8,7 @@ namespace XCharts.Runtime { public Vector3 labelPosition; public Vector3 labelLinePosition; + public Vector3 labelLinePosition2; /// <summary> /// 开始角度 /// </summary> diff --git a/Runtime/Serie/SerieHandler.cs b/Runtime/Serie/SerieHandler.cs index 4e67ca40..f2774cfb 100644 --- a/Runtime/Serie/SerieHandler.cs +++ b/Runtime/Serie/SerieHandler.cs @@ -15,7 +15,9 @@ namespace XCharts.Runtime public virtual void InitComponent() { } public virtual void RemoveComponent() { } public virtual void CheckComponent(StringBuilder sb) { } + public virtual void BeforeUpdate() { } public virtual void Update() { } + public virtual void AfterUpdate() { } public virtual void DrawBase(VertexHelper vh) { } public virtual void DrawSerie(VertexHelper vh) { } public virtual void DrawUpper(VertexHelper vh) { } @@ -31,12 +33,12 @@ namespace XCharts.Runtime public virtual void OnScroll(PointerEventData eventData) { } public virtual void RefreshLabelNextFrame() { } public virtual void RefreshLabelInternal() { } + public virtual void ForceUpdateSerieContext() { } public virtual void UpdateSerieContext() { } public virtual void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, string marker, string itemFormatter, string numericFormatter, string ignoreDataDefaultContent, - ref List<SerieParams> paramList, ref string title) - { } + ref List<SerieParams> paramList, ref string title) { } public virtual void OnLegendButtonClick(int index, string legendName, bool show) { } public virtual void OnLegendButtonEnter(int index, string legendName) { } public virtual void OnLegendButtonExit(int index, string legendName) { } @@ -58,22 +60,40 @@ namespace XCharts.Runtime protected bool m_RefreshLabel; protected bool m_LastCheckContextFlag = false; protected bool m_LegendEnter = false; + protected bool m_LegendExiting = false; + protected bool m_ForceUpdateSerieContext = false; protected int m_LegendEnterIndex; protected ChartLabel m_EndLabel; + private float[] m_LastRadius = new float[2] { 0, 0 }; + private float[] m_LastCenter = new float[2] { 0, 0 }; + private bool m_LastPointerEnter; + private int m_LastPointerDataIndex; + private int m_LastPointerDataDimension; + public T serie { get; internal set; } public GameObject labelObject { get { return m_SerieLabelRoot; } } internal override void SetSerie(Serie serie) { - this.serie = (T)serie; + this.serie = (T) serie; this.serie.context.param.serieType = typeof(T); m_NeedInitComponent = true; AnimationStyleHelper.UpdateSerieAnimation(serie); } + public override void BeforeUpdate() + { + m_LastPointerEnter = serie.context.pointerEnter; + m_LastPointerDataIndex = serie.context.pointerItemDataIndex; + m_LastPointerDataDimension = GetPointerItemDataDimension(); + serie.context.pointerEnter = false; + serie.context.pointerItemDataIndex = -1; + } + public override void Update() { + CheckConfigurationChanged(); if (m_NeedInitComponent) { m_NeedInitComponent = false; @@ -122,37 +142,75 @@ namespace XCharts.Runtime if (serie.vertsDirty) { chart.RefreshPainter(serie); - serie.ResetInteract(); serie.ClearVerticesDirty(); } + if (serie.interactDirty) + { + serie.interactDirty = false; + m_ForceUpdateSerieContext = true; + } + } + + public override void AfterUpdate() + { UpdateSerieContextInternal(); } + public override void ForceUpdateSerieContext() + { + m_ForceUpdateSerieContext = true; + } + + private void CheckConfigurationChanged() + { + if (m_LastRadius[0] != serie.radius[0] || m_LastRadius[1] != serie.radius[1]) + { + m_LastRadius[0] = serie.radius[0]; + m_LastRadius[1] = serie.radius[1]; + serie.SetVerticesDirty(); + } + if (m_LastCenter[0] != serie.center[0] || m_LastCenter[1] != serie.center[1]) + { + m_LastCenter[0] = serie.center[0]; + m_LastCenter[1] = serie.center[1]; + serie.SetVerticesDirty(); + } + } + private void UpdateSerieContextInternal() { - var lastEnter = serie.context.pointerEnter; - var lastDataIndex = serie.context.pointerItemDataIndex; UpdateSerieContext(); - if (lastEnter != serie.context.pointerEnter || lastDataIndex != serie.context.pointerItemDataIndex) + m_ForceUpdateSerieContext = false; + if (m_LastPointerEnter != serie.context.pointerEnter || m_LastPointerDataIndex != serie.context.pointerItemDataIndex) { if (chart.onSerieEnter != null || chart.onSerieExit != null || serie.onEnter != null || serie.onExit != null) { - var dataIndex = GetPointerItemDataIndex(); - var dimension = GetPointerItemDataDimension(); - var value = serie.GetData(dataIndex, dimension); - var data = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value); if (serie.context.pointerEnter) { - if (serie.onEnter != null) serie.onEnter(data); - if (chart.onSerieEnter != null) chart.onSerieEnter(data); + if ((serie.onExit != null || chart.onSerieExit != null) && m_LastPointerDataIndex >= 0) + { + var dataValue = serie.GetData(m_LastPointerDataIndex, m_LastPointerDataDimension); + var exitEventData = SerieEventDataPool.Get(chart.pointerPos, serie.index, m_LastPointerDataIndex, m_LastPointerDataDimension, dataValue); + if (serie.onExit != null) serie.onExit(exitEventData); + if (chart.onSerieExit != null) chart.onSerieExit(exitEventData); + SerieEventDataPool.Release(exitEventData); + } + var dataIndex = GetPointerItemDataIndex(); + var dimension = GetPointerItemDataDimension(); + var value = serie.GetData(dataIndex, dimension); + var enterEventData = SerieEventDataPool.Get(chart.pointerPos, serie.index, dataIndex, dimension, value); + if (serie.onEnter != null) serie.onEnter(enterEventData); + if (chart.onSerieEnter != null) chart.onSerieEnter(enterEventData); + SerieEventDataPool.Release(enterEventData); } - else + else if (m_LastPointerDataIndex >= 0) { - data.dataIndex = lastDataIndex; - if (serie.onExit != null) serie.onExit(data); - if (chart.onSerieExit != null) chart.onSerieExit(data); + var dataValue = serie.GetData(m_LastPointerDataIndex, m_LastPointerDataDimension); + var exitEventData = SerieEventDataPool.Get(chart.pointerPos, serie.index, m_LastPointerDataIndex, m_LastPointerDataDimension, dataValue); + if (serie.onExit != null) serie.onExit(exitEventData); + if (chart.onSerieExit != null) chart.onSerieExit(exitEventData); + SerieEventDataPool.Release(exitEventData); } - SerieEventDataPool.Release(data); } } } @@ -165,6 +223,7 @@ namespace XCharts.Runtime public override void InitComponent() { m_InitedLabel = false; + serie.context.totalDataIndex = serie.dataCount - 1; InitRoot(); InitSerieLabel(); InitSerieTitle(); @@ -195,7 +254,8 @@ namespace XCharts.Runtime { if (serie.colorByData && serie.IsSerieDataLegendName(legendName)) { - LegendHelper.CheckDataHighlighted(serie, legendName, true); + m_LegendEnterIndex = LegendHelper.CheckDataHighlighted(serie, legendName, true); + m_LegendEnter = true; chart.RefreshPainter(serie); } else if (serie.IsLegendName(legendName)) @@ -210,11 +270,14 @@ namespace XCharts.Runtime if (serie.colorByData && serie.IsSerieDataLegendName(legendName)) { LegendHelper.CheckDataHighlighted(serie, legendName, false); + m_LegendEnter = false; + m_LegendExiting = true; chart.RefreshPainter(serie); } else if (serie.IsLegendName(legendName)) { m_LegendEnter = false; + m_LegendExiting = true; chart.RefreshPainter(serie); } } @@ -247,7 +310,7 @@ namespace XCharts.Runtime m_SerieLabelRoot.hideFlags = chart.chartHideFlags; SerieLabelPool.ReleaseAll(m_SerieLabelRoot.transform); int count = 0; - SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight); + SerieHelper.UpdateCenter(serie, chart); for (int j = 0; j < serie.data.Count; j++) { var serieData = serie.data[j]; @@ -323,7 +386,7 @@ namespace XCharts.Runtime return; } InitRoot(); - var dataAutoColor = (Color)chart.GetLegendRealShowNameColor(serie.legendName); + var dataAutoColor = (Color) chart.GetLegendRealShowNameColor(serie.legendName); m_EndLabel = ChartHelper.AddChartLabel(s_SerieEndLabelObjectName, m_SerieRoot.transform, serie.endLabel, chart.theme.common, "", dataAutoColor, TextAnchor.MiddleLeft); m_EndLabel.SetActive(serie.endLabel.show); @@ -339,7 +402,7 @@ namespace XCharts.Runtime SerieLabelPool.ReleaseAll(serieTitleRoot.transform); ChartHelper.RemoveComponent<Text>(serieTitleRoot); - SerieHelper.UpdateCenter(serie, chart.chartPosition, chart.chartWidth, chart.chartHeight); + SerieHelper.UpdateCenter(serie, chart); if (serie.titleJustForSerie) { @@ -401,7 +464,8 @@ namespace XCharts.Runtime if (!m_InitedLabel) return; - var dataChangeDuration = serie.animation.GetUpdateAnimationDuration(); + var dataChangeDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; var needCheck = serie.context.dataIndexs.Count > 0; foreach (var serieData in serie.data) @@ -432,7 +496,7 @@ namespace XCharts.Runtime { if (i >= serieData.context.dataPoints.Count) continue; var labelObject = serieData.context.dataLabels[i]; - var value = serieData.GetCurrData(i, dataChangeDuration, unscaledTime); + var value = serieData.GetCurrData(i, dataAddDuration, dataChangeDuration, unscaledTime); var content = string.IsNullOrEmpty(currLabel.formatter) ? ChartCached.NumberToStr(value, currLabel.numericFormatter) : SerieLabelHelper.GetFormatterContent(serie, serieData, value, total, @@ -452,7 +516,7 @@ namespace XCharts.Runtime } else { - var value = serieData.GetCurrData(defaultDimension, dataChangeDuration, unscaledTime); + var value = serieData.GetCurrData(defaultDimension, dataAddDuration, dataChangeDuration, unscaledTime); var total = serie.GetDataTotal(defaultDimension, serieData); var color = chart.GetItemColor(serie, serieData); var content = string.IsNullOrEmpty(currLabel.formatter) ? @@ -499,7 +563,7 @@ namespace XCharts.Runtime m_EndLabel.isAnimationEnd = serie.animation.IsFinish(); } - private void UpdateLabelPosition(SerieData serieData, LabelStyle currLabel) + protected void UpdateLabelPosition(SerieData serieData, LabelStyle currLabel) { var labelPosition = GetSerieDataLabelPosition(serieData, currLabel); var offset = GetSerieDataLabelOffset(serieData, currLabel); @@ -535,7 +599,7 @@ namespace XCharts.Runtime var colorIndex = serie.colorByData ? serieData.index : serie.index; Color32 color, toColor; SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, colorIndex, SerieState.Normal, false); - return (Color)color; + return (Color) color; } protected void UpdateCoordSerieParams(ref List<SerieParams> paramList, ref string title, diff --git a/Runtime/Serie/SerieHelper.cs b/Runtime/Serie/SerieHelper.cs index b8bb2f9d..039aae40 100644 --- a/Runtime/Serie/SerieHelper.cs +++ b/Runtime/Serie/SerieHelper.cs @@ -213,9 +213,20 @@ namespace XCharts.Runtime /// </summary> /// <param name="chartWidth"></param> /// <param name="chartHeight"></param> - public static void UpdateCenter(Serie serie, Vector3 chartPosition, float chartWidth, float chartHeight) + public static void UpdateCenter(Serie serie, BaseChart chart) { if (serie.center.Length < 2) return; + var chartPosition = chart.chartPosition; + var chartWidth = chart.chartWidth; + var chartHeight = chart.chartHeight; + if (serie.gridIndex >= 0) + { + var layout = chart.GetChartComponent<GridLayout>(0); + if (layout != null) + { + layout.UpdateGridContext(serie.gridIndex, ref chartPosition, ref chartWidth, ref chartHeight); + } + } var centerX = serie.center[0] <= 1 ? chartWidth * serie.center[0] : serie.center[0]; var centerY = serie.center[1] <= 1 ? chartHeight * serie.center[1] : serie.center[1]; serie.context.center = chartPosition + new Vector3(centerX, centerY); @@ -436,14 +447,14 @@ namespace XCharts.Runtime public static ItemStyle GetItemStyle(Serie serie, SerieData serieData, SerieState state = SerieState.Auto) { if (state == SerieState.Auto) state = GetSerieState(serie, serieData); - if (state == SerieState.Normal) + var stateStyle = GetStateStyle(serie, serieData, state); + if (stateStyle == null || !stateStyle.show) { return serieData != null && serieData.itemStyle != null ? serieData.itemStyle : serie.itemStyle; } else { - var stateStyle = GetStateStyle(serie, serieData, state); - return stateStyle == null || !stateStyle.show ? serie.itemStyle : stateStyle.itemStyle; + return stateStyle.itemStyle; } } @@ -646,7 +657,7 @@ namespace XCharts.Runtime if (stateStyle == null) { var itemStyle = GetItemStyle(serie, serieData, SerieState.Normal); - border = itemStyle.borderWidth != 0 ? itemStyle.borderWidth : serie.lineStyle.GetWidth(theme.serie.lineWidth); + border = itemStyle.borderWidth != 0 ? itemStyle.borderWidth : serie.lineStyle.GetWidth(theme.serie.lineWidth) * 1.8f; cornerRadius = itemStyle.cornerRadius; GetColor(ref borderColor, itemStyle.borderColor, itemStyle.borderColor, 1, theme, -1); switch (state) @@ -667,14 +678,15 @@ namespace XCharts.Runtime else { var itemStyle = stateStyle.itemStyle; - border = itemStyle.borderWidth != 0 ? itemStyle.borderWidth : stateStyle.lineStyle.GetWidth(theme.serie.lineWidth); + border = itemStyle.borderWidth != 0 ? itemStyle.borderWidth : stateStyle.lineStyle.GetWidth(theme.serie.lineWidth) * 1.8f; cornerRadius = itemStyle.cornerRadius; GetColor(ref borderColor, stateStyle.itemStyle.borderColor, ColorUtil.clearColor32, 1, theme, -1); } } - public static float GetSysmbolSize(Serie serie, SerieData serieData, ThemeStyle theme, float defaultSize, SerieState state = SerieState.Auto) + public static float GetSysmbolSize(Serie serie, SerieData serieData, float defaultSize, SerieState state = SerieState.Auto, bool checkAnimation = false) { + if (serie == null) return defaultSize; if (state == SerieState.Auto) state = GetSerieState(serie, serieData); var stateStyle = GetStateStyle(serie, serieData, state); @@ -687,7 +699,7 @@ namespace XCharts.Runtime { case SerieState.Emphasis: case SerieState.Select: - size *= theme.serie.selectedRate; + size = serie.animation.interaction.GetRadius(size); break; default: break; @@ -698,6 +710,10 @@ namespace XCharts.Runtime var symbol = stateStyle.symbol; size = symbol.GetSize(serieData == null ? null : serieData.data, defaultSize); } + if (serieData != null && checkAnimation) + { + size = (float)serieData.GetAddAnimationData(0, size, serie.animation.GetAdditionDuration()); + } return size; } @@ -815,6 +831,10 @@ namespace XCharts.Runtime serie.m_FilterMinShow = dataZoom.minShowNum; serie.m_NeedUpdateFilterData = false; + if (ReferenceEquals(serie.m_FilterData, data)) + { + serie.m_FilterData = new List<SerieData>(); + } serie.m_FilterData.Clear(); foreach (var serieData in data) { diff --git a/Runtime/Serie/SeriesHelper.cs b/Runtime/Serie/SeriesHelper.cs index 85717ee3..074f2c50 100644 --- a/Runtime/Serie/SeriesHelper.cs +++ b/Runtime/Serie/SeriesHelper.cs @@ -294,7 +294,7 @@ namespace XCharts.Runtime for (int i = 0; i <= currSerie.index; i++) { var serie = series[i]; - if (serie.GetType() == currSerie.GetType() && ChartHelper.IsValueEqualsString(serie.stack, currSerie.stack)) + if (serie.show && serie.GetType() == currSerie.GetType() && ChartHelper.IsValueEqualsString(serie.stack, currSerie.stack)) { dataList.Add(serie.GetDataList(dataZoom)); } @@ -306,12 +306,12 @@ namespace XCharts.Runtime /// </summary> /// <param name="dataZoom"></param> /// <param name="axisIndex"></param> - /// <param name="minVaule"></param> + /// <param name="minValue"></param> /// <param name="maxValue"></param> public static void GetXMinMaxValue(BaseChart chart, int axisIndex, bool isValueAxis, - bool inverse, out double minVaule, out double maxValue, bool isPolar = false, bool filterByDataZoom = true) + bool inverse, out double minValue, out double maxValue, bool isPolar = false, bool filterByDataZoom = true) { - GetMinMaxValue(chart, axisIndex, isValueAxis, inverse, false, out minVaule, out maxValue, isPolar, filterByDataZoom); + GetMinMaxValue(chart, axisIndex, isValueAxis, inverse, false, out minValue, out maxValue, isPolar, filterByDataZoom); } /// <summary> @@ -319,19 +319,19 @@ namespace XCharts.Runtime /// </summary> /// <param name="dataZoom"></param> /// <param name="axisIndex"></param> - /// <param name="minVaule"></param> + /// <param name="minValue"></param> /// <param name="maxValue"></param> public static void GetYMinMaxValue(BaseChart chart, int axisIndex, bool isValueAxis, - bool inverse, out double minVaule, out double maxValue, bool isPolar = false, bool filterByDataZoom = true) + bool inverse, out double minValue, out double maxValue, bool isPolar = false, bool filterByDataZoom = true) { - GetMinMaxValue(chart, axisIndex, isValueAxis, inverse, true, out minVaule, out maxValue, isPolar, filterByDataZoom); + GetMinMaxValue(chart, axisIndex, isValueAxis, inverse, true, out minValue, out maxValue, isPolar, filterByDataZoom); } private static Dictionary<int, List<Serie>> _stackSeriesForMinMax = new Dictionary<int, List<Serie>>(); private static Dictionary<int, double> _serieTotalValueForMinMax = new Dictionary<int, double>(); private static DataZoom xDataZoom, yDataZoom; public static void GetMinMaxValue(BaseChart chart, int axisIndex, bool isValueAxis, - bool inverse, bool yValue, out double minVaule, out double maxValue, bool isPolar = false, + bool inverse, bool yValue, out double minValue, out double maxValue, bool isPolar = false, bool filterByDataZoom = true) { double min = double.MaxValue; @@ -346,7 +346,8 @@ namespace XCharts.Runtime if ((isPolar && serie.polarIndex != axisIndex) || (!isPolar && serie.yAxisIndex != axisIndex) || !serie.show) continue; - var updateDuration = serie.animation.enable ? serie.animation.dataChangeDuration : 0; + var updateDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); var unscaledTime = serie.animation.unscaledTime; if (isPercentStack && SeriesHelper.IsPercentStack<Bar>(series, serie.serieName)) { @@ -372,7 +373,7 @@ namespace XCharts.Runtime foreach (var data in showData) { var currData = performanceMode ? data.GetData(yValue ? 1 : 0, inverse) : - data.GetCurrData(yValue ? 1 : 0, updateDuration, unscaledTime, inverse); + data.GetCurrData(yValue ? 1 : 0, dataAddDuration, updateDuration, unscaledTime, inverse); if (!serie.IsIgnoreValue(data, currData)) { if (currData > max) max = currData; @@ -405,6 +406,9 @@ namespace XCharts.Runtime } else { + var updateDuration = serie.animation.GetChangeDuration(); + var dataAddDuration = serie.animation.GetAdditionDuration(); + var unscaledTime = serie.animation.unscaledTime; for (int j = 0; j < showData.Count; j++) { if (!_serieTotalValueForMinMax.ContainsKey(j)) @@ -416,9 +420,10 @@ namespace XCharts.Runtime } else { - currData = yValue ? showData[j].GetData(1) : showData[j].GetData(0); + //currData = yValue ? showData[j].GetData(1) : showData[j].GetData(0); + currData = showData[j].GetCurrData(yValue ? 1 : 0, dataAddDuration, updateDuration, unscaledTime, inverse); } - if (inverse) currData = -currData; + //if (inverse) currData = -currData; if (!serie.IsIgnoreValue(showData[j], currData)) _serieTotalValueForMinMax[j] = _serieTotalValueForMinMax[j] + currData; } @@ -437,12 +442,17 @@ namespace XCharts.Runtime } if (max == double.MinValue && min == double.MaxValue) { - minVaule = 0; + minValue = 0; maxValue = 0; } + else if (min == 0 && max == 0) + { + minValue = 0; + maxValue = 1; + } else { - minVaule = min; + minValue = min; maxValue = max; } } diff --git a/Runtime/Theme/SerieTheme.cs b/Runtime/Theme/SerieTheme.cs index c97a693d..e41f052a 100644 --- a/Runtime/Theme/SerieTheme.cs +++ b/Runtime/Theme/SerieTheme.cs @@ -9,9 +9,6 @@ namespace XCharts.Runtime [SerializeField] protected float m_LineWidth; [SerializeField] protected float m_LineSymbolSize; [SerializeField] protected float m_ScatterSymbolSize; - [SerializeField] protected float m_PieTooltipExtraRadius; - [SerializeField] protected float m_SelectedRate = 1.3f; - [SerializeField] protected float m_PieSelectedOffset; [SerializeField] protected Color32 m_CandlestickColor = new Color32(235, 84, 84, 255); [SerializeField] protected Color32 m_CandlestickColor0 = new Color32(71, 178, 98, 255); [SerializeField] protected float m_CandlestickBorderWidth = 1; @@ -37,11 +34,6 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_LineSymbolSize, value)) SetVerticesDirty(); } } /// <summary> - /// the selected symbol size of line serie. - /// |折线图Symbol在被选中状态时的大小。 - /// </summary> - public float lineSymbolSelectedSize { get { return lineSymbolSize * selectedRate; } } - /// <summary> /// the symbol size of scatter serie. /// |散点图的Symbol大小。 /// </summary> @@ -51,39 +43,6 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_ScatterSymbolSize, value)) SetVerticesDirty(); } } /// <summary> - /// the selected symbol size of scatter serie. - /// |散点图的Symbol在被选中状态时的大小。 - /// </summary> - public float scatterSymbolSelectedSize { get { return scatterSymbolSize * selectedRate; } } - /// <summary> - /// the rate of symbol size of line or scatter serie. - /// |折线图或散点图在被选中时的放大倍数。 - /// </summary> - public float selectedRate - { - get { return m_SelectedRate; } - set { if (PropertyUtil.SetStruct(ref m_SelectedRate, value)) SetVerticesDirty(); } - } - - /// <summary> - /// the extra radius of pie when actived by tooltip. - /// |饼图鼠标移到高亮时的额外半径 - /// </summary> - public float pieTooltipExtraRadius - { - get { return m_PieTooltipExtraRadius; } - set { if (PropertyUtil.SetStruct(ref m_PieTooltipExtraRadius, value < 0 ? 0f : value)) SetVerticesDirty(); } - } - /// <summary> - /// the center offset of pie if selected. - /// |饼图选中时的中心点偏移。 - /// </summary> - public float pieSelectedOffset - { - get { return m_PieSelectedOffset; } - set { if (PropertyUtil.SetStruct(ref m_PieSelectedOffset, value < 0 ? 0f : value)) SetVerticesDirty(); } - } - /// <summary> /// K线图阳线(涨)填充色 /// </summary> public Color32 candlestickColor @@ -130,9 +89,6 @@ namespace XCharts.Runtime m_LineWidth = theme.lineWidth; m_LineSymbolSize = theme.lineSymbolSize; m_ScatterSymbolSize = theme.scatterSymbolSize; - selectedRate = theme.selectedRate; - m_PieTooltipExtraRadius = theme.pieTooltipExtraRadius; - m_PieSelectedOffset = theme.pieSelectedOffset; m_CandlestickColor = theme.candlestickColor; m_CandlestickColor0 = theme.candlestickColor0; m_CandlestickBorderColor = theme.candlestickBorderColor; @@ -145,8 +101,6 @@ namespace XCharts.Runtime m_LineWidth = XCSettings.serieLineWidth; m_LineSymbolSize = XCSettings.serieLineSymbolSize; m_ScatterSymbolSize = XCSettings.serieScatterSymbolSize; - m_PieTooltipExtraRadius = XCSettings.pieTooltipExtraRadius; - m_PieSelectedOffset = XCSettings.pieSelectedOffset; m_CandlestickBorderWidth = XCSettings.serieCandlestickBorderWidth; switch (theme) { diff --git a/Runtime/XLog.meta b/Runtime/XLog.meta new file mode 100644 index 00000000..998fed38 --- /dev/null +++ b/Runtime/XLog.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8a4ed57531ebf43999c449f6aa58595c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/XLog/XLog.cs b/Runtime/XLog/XLog.cs new file mode 100644 index 00000000..3380aadc --- /dev/null +++ b/Runtime/XLog/XLog.cs @@ -0,0 +1,340 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using UnityEngine; + +namespace XCharts.Runtime +{ + /// <summary> + /// Log system. Used to output logs with date and log type, support output to file, support custom output log type. + /// |日志系统。用于输出带日期和日志类型的日志,支持输出到文件,支持自定义输出的日志类型。 + /// </summary> + public class XLog : MonoBehaviour + { + public const int ALL = 0; + public const int WARNING = 1; + public const int DEBUG = 2; + public const int INFO = 3; + public const int PROTO = 4; + public const int VITAL = 5; + public const int ERROR = 6; + public const int EXCEPTION = 7; + + private const int MAX_ERROR_LOG = 20; + + public static bool isReportBug = false; + public static bool isOutputLog = false; + public static bool isUploadLog = false; + public static bool isCloseOutLog = false; + + public static int errorCount = 0; + public static int exceptCount = 0; + public static int uploadTick = 20; + public static int reportTick = 10; + + private static bool initFileSuccess = false; + private static bool[] levelList = new bool[] { true, true, true, true, true, true, true, true }; + private static List<string> writeList = new List<string>(); + private static float uploadTime = 0; + private static float reportTime = 0; + + private string outpath; + private StreamWriter writer; + private string[] temp; + + public int logCount = 0; + public static List<string> errorList = new List<string>(); + private static object m_Lock = new object(); + + private static XLog m_Instance; + public static XLog Instance + { + get + { + // if (m_Instance == null) + // { + // GameObject go = new GameObject("XLog"); + // m_Instance = go.AddComponent<XLog>(); + // DontDestroyOnLoad(go); + // } + return m_Instance; + } + } + + void Awake() + { + if (m_Instance != null) + { + Destroy(gameObject); + return; + } + m_Instance = this; + InitLogFile(); + // Application.logMessageReceived += HandleLog; + Application.logMessageReceivedThreaded += HandleLog; + } + + void OnDestroy() + { + if (writer != null) + { + writer.Close(); + writer.Dispose(); + } + // Application.logMessageReceived -= HandleLog; + Application.logMessageReceivedThreaded -= HandleLog; + } + + void Update() + { + uploadTime += Time.deltaTime; + reportTime += Time.deltaTime; + lock (m_Lock) + { + if (writeList.Count > 0) + { + logCount = writeList.Count; + if (!initFileSuccess) + { + writeList.Clear(); + return; + } + try + { + temp = writeList.ToArray(); + int count = 0; + foreach (var str in temp) + { + count++; + writer.WriteLine(str); + writeList.Remove(str); + if (count > 10) break; + } + writer.Flush(); + } + catch (Exception e) + { + initFileSuccess = false; + //Application.logMessageReceived -= HandleLog; + Application.logMessageReceivedThreaded -= HandleLog; + UnityEngine.Debug.LogError("write outlog.txt error:" + e.Message); + } + } + } + } + + private void InitLogFile() + { + ClearAllLog(); + XLog.EnableLog(ALL); + if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) + { + XLog.ClearAllLog(); + XLog.EnableLog(VITAL); + XLog.EnableLog(ERROR); + XLog.isReportBug = true; + XLog.isUploadLog = true; + } + else + { + XLog.isUploadLog = false; + XLog.isReportBug = false; + } + outpath = GetLogOutputPath(); + try + { + if (File.Exists(outpath)) + { + File.Delete(outpath); + } + writer = new StreamWriter(outpath, false, Encoding.UTF8); + writer.WriteLine(GetNowTime() + "init file success!!"); + UnityEngine.Debug.Log(GetNowTime() + "init file success:" + outpath); + writer.Flush(); + initFileSuccess = true; + } + catch (Exception e) + { + initFileSuccess = false; + Application.logMessageReceived -= HandleLog; + UnityEngine.Debug.LogError("write outlog.txt error:" + e.Message); + } + } + + private static string GetLogOutputPath() + { +#if UNITY_EDITOR + string path = Application.dataPath + "/../outlog.txt"; +#else + string path = Application.persistentDataPath + "/outlog.txt"; + if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) + { + path = Application.persistentDataPath + "/outlog.txt"; + } + else + { + path = Application.dataPath + "/../outlog.txt"; + } +#endif + return path; + } + + private void HandleLog(string logString, string stackTrace, LogType type) + { + lock (m_Lock) + { + if (!initFileSuccess) return; + int index = logString.IndexOf("stack traceback"); + if (index > 0) + { + string log = logString.Substring(0, index); + string trace = logString.Substring(index, logString.Length - index); + logString = log; + stackTrace = trace; + } + + if (type == LogType.Log) + { + } + else if (type == LogType.Error) + { + if (logString.IndexOf("LUA ERROR") > 0 || logString.IndexOf("stack traceback") > 0) exceptCount++; + else errorCount++; + + writeList.Add(logString); + //writeList.Add(stackTrace + "\n"); + + if (errorList.Count >= MAX_ERROR_LOG) + { + errorList.RemoveAt(1); + } + + if (errorList.Count < MAX_ERROR_LOG) + { + errorList.Add(logString); + // errorList.Add(stackTrace + "\n"); + } + } + else if (type == LogType.Exception) + { + exceptCount++; + + writeList.Add(logString); + writeList.Add(stackTrace + "\n"); + + if (errorList.Count >= MAX_ERROR_LOG) + { + errorList.RemoveAt(1); + } + + if (errorList.Count < MAX_ERROR_LOG) + { + errorList.Add(logString); + errorList.Add(stackTrace + "\n"); + } + } + } + } + + public static void FlushLog() + { + var instance = XLog.Instance; + if (instance != null && instance.writer != null) + { + for (int i = 0; i < writeList.Count; i++) + { + instance.writer.WriteLine(writeList[i]); + } + instance.writer.Flush(); + writeList.Clear(); + } + } + + public static void EnableLog(int logType) + { + if (logType < 0 || logType >= levelList.Length) return; + levelList[logType] = true; + } + + public static void ClearAllLog() + { + for (int i = 0; i < levelList.Length; i++) + { + levelList[i] = false; + } + } + + public static bool CanLog(int level) + { + if (level < 0 || level >= levelList.Length) return false; + return levelList[level] || levelList[0]; + } + + public static void Log(string log) + { + Debug(log); + } + + public static void LogError(string log) + { + Error(log); + } + + public static void LogWarning(string log) + { + Warning(log); + } + + public static void Debug(string log) + { + if (!CanLog(DEBUG)) return; + UnityEngine.Debug.Log(GetNowTime() + "[DEBUG]\t" + log); + } + + public static void Vital(string log) + { + if (!CanLog(INFO)) return; + UnityEngine.Debug.Log(GetNowTime() + "[VITAL]\t" + log); + } + + public static void Info(string log) + { + if (!CanLog(INFO)) return; + UnityEngine.Debug.Log(GetNowTime() + "[INFO]\t" + log); + } + + public static void Proto(string log) + { + if (!CanLog(PROTO)) return; + UnityEngine.Debug.Log(GetNowTime() + "[PROTO]\t" + log); + } + + public static void Warning(string log) + { + if (!CanLog(WARNING)) return; + UnityEngine.Debug.LogWarning(GetNowTime() + "[WARN]\t" + log); + } + + public static void Error(string log) + { + if (!CanLog(ERROR)) return; + UnityEngine.Debug.LogError(GetNowTime() + "[ERROR]\t" + log); + } + + public static string GetNowTime(string formatter = null) + { + DateTime now = DateTime.Now; + if (formatter == null) + return now.ToString("[HH:mm:ss fff]", DateTimeFormatInfo.InvariantInfo); + else + return now.ToString(formatter, DateTimeFormatInfo.InvariantInfo); + } + + public static ulong GetTimestamp() + { + return (ulong)(DateTime.Now - new DateTime(190, 1, 1, 0, 0, 0, 0)).TotalSeconds; + } + } +} diff --git a/Runtime/XLog/XLog.cs.meta b/Runtime/XLog/XLog.cs.meta new file mode 100644 index 00000000..79a55607 --- /dev/null +++ b/Runtime/XLog/XLog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: baf125f6000464daeb59d4c183eed941 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/XUGL/UGL.cs b/Runtime/XUGL/UGL.cs index b35a9820..5e74590e 100644 --- a/Runtime/XUGL/UGL.cs +++ b/Runtime/XUGL/UGL.cs @@ -406,18 +406,39 @@ namespace XUGL if (dist < 0.1f) return; if (zebraWidth == 0) zebraWidth = 3 * width; if (zebraGap == 0) zebraGap = 3 * width; - var allSegment = Mathf.CeilToInt(maxDistance / (zebraWidth + zebraGap)); - var segment = Mathf.CeilToInt(dist / maxDistance * allSegment); + var segment = Mathf.CeilToInt(dist / (zebraWidth + zebraGap)) + 1; var dir = (endPoint - startPoint).normalized; var sp = startPoint; var np = Vector3.zero; var isGradient = !color.Equals(toColor); - zebraWidth = (maxDistance - zebraGap * (allSegment - 1)) / allSegment; - for (int i = 1; i <= segment; i++) + var currDist = 0f; + for (int i = 0; i <= segment; i++) { - np = sp + dir * zebraWidth; - DrawLine(vh, sp, np, width, isGradient ? Color32.Lerp(color, toColor, i * 1.0f / allSegment) : color); - sp = np + dir * zebraGap; + if (currDist + zebraWidth + zebraGap <= dist) + { + currDist += (zebraWidth + zebraGap); + np = sp + dir * zebraWidth; + DrawLine(vh, sp, np, width, isGradient ? Color32.Lerp(color, toColor, currDist / maxDistance) : color); + sp = np + dir * zebraGap; + } + else + { + if (currDist + zebraWidth <= dist) + { + currDist += zebraWidth; + np = sp + dir * zebraWidth; + DrawLine(vh, sp, np, width, isGradient ? Color32.Lerp(color, toColor, currDist / maxDistance) : color); + if (dist - currDist > 6) + { + DrawLine(vh, endPoint - dir * 2f, endPoint, width, isGradient ? Color32.Lerp(color, toColor, dist / maxDistance) : color); + } + } + else + { + DrawLine(vh, sp, endPoint, width, isGradient ? Color32.Lerp(color, toColor, dist / maxDistance) : color); + } + break; + } } } @@ -443,14 +464,50 @@ namespace XUGL /// <param name="toColor">渐变色2</param> public static void DrawDiamond(VertexHelper vh, Vector3 center, float size, Color32 color, Color32 toColor) { - var p1 = new Vector2(center.x - size, center.y); - var p2 = new Vector2(center.x, center.y + size); - var p3 = new Vector2(center.x + size, center.y); - var p4 = new Vector2(center.x, center.y - size); + DrawDiamond(vh, center, size, size, color, toColor); + } + + public static void DrawDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, Color32 color, Color32 toColor) + { + var p1 = new Vector2(center.x - xRadius, center.y); + var p2 = new Vector2(center.x, center.y + yRadius); + var p3 = new Vector2(center.x + xRadius, center.y); + var p4 = new Vector2(center.x, center.y - yRadius); DrawTriangle(vh, p4, p1, p2, color, color, toColor); DrawTriangle(vh, p3, p4, p2, color, color, toColor); } + public static void DrawEmptyDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, float tickness, Color32 color) + { + DrawEmptyDiamond(vh, center, xRadius, yRadius, tickness, color, s_ClearColor32); + } + + public static void DrawEmptyDiamond(VertexHelper vh, Vector3 center, float xRadius, float yRadius, float tickness, Color32 color, Color32 emptyColor) + { + var p1 = new Vector2(center.x - xRadius, center.y); + var p2 = new Vector2(center.x, center.y + yRadius); + var p3 = new Vector2(center.x + xRadius, center.y); + var p4 = new Vector2(center.x, center.y - yRadius); + + var xRadius1 = xRadius - tickness; + var yRadius1 = yRadius - tickness * 1.5f; + var ip1 = new Vector2(center.x - xRadius1, center.y); + var ip2 = new Vector2(center.x, center.y + yRadius1); + var ip3 = new Vector2(center.x + xRadius1, center.y); + var ip4 = new Vector2(center.x, center.y - yRadius1); + + if (!UGLHelper.IsClearColor(emptyColor)) + { + DrawQuadrilateral(vh, ip1, ip2, ip3, ip4, emptyColor); + } + + AddVertToVertexHelper(vh, p1, ip1, color, false); + AddVertToVertexHelper(vh, p2, ip2, color); + AddVertToVertexHelper(vh, p3, ip3, color); + AddVertToVertexHelper(vh, p4, ip4, color); + AddVertToVertexHelper(vh, p1, ip1, color); + } + /// <summary> /// Draw a square. 画正方形 /// </summary> @@ -1224,6 +1281,38 @@ namespace XUGL vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2); } + public static void DrawEmptyTriangle(VertexHelper vh, Vector3 pos, float size, float tickness, Color32 color) + { + DrawEmptyTriangle(vh, pos, size, tickness, color, s_ClearColor32); + } + + public static void DrawEmptyTriangle(VertexHelper vh, Vector3 pos, float size, float tickness, Color32 color, Color32 backgroundColor) + { + var cos30 = Mathf.Cos(30 * Mathf.PI / 180); + var sin30 = Mathf.Sin(30 * Mathf.PI / 180); + var x = size * cos30; + var y = size * sin30; + var outsideLeft = new Vector2(pos.x - x, pos.y - y); + var outsideTop = new Vector2(pos.x, pos.y + size); + var outsideRight = new Vector2(pos.x + x, pos.y - y); + + var size2 = size - tickness; + var x1 = size2 * cos30; + var y1 = size2 * sin30; + var insideLeft = new Vector2(pos.x - x1, pos.y - y1); + var insideTop = new Vector2(pos.x, pos.y + size2); + var insideRight = new Vector2(pos.x + x1, pos.y - y1); + + if (!UGLHelper.IsClearColor(backgroundColor)) + { + DrawTriangle(vh, insideLeft, insideTop, insideRight, backgroundColor, backgroundColor, backgroundColor); + } + AddVertToVertexHelper(vh, outsideLeft, insideLeft, color, false); + AddVertToVertexHelper(vh, outsideTop, insideTop, color); + AddVertToVertexHelper(vh, outsideRight, insideRight, color); + AddVertToVertexHelper(vh, outsideLeft, insideLeft, color); + } + public static void DrawCricle(VertexHelper vh, Vector3 center, float radius, Color32 color, float smoothness = 2f) { @@ -1327,7 +1416,7 @@ namespace XUGL if (gap > 0 && isCircle) gap = 0; radius -= borderWidth; smoothness = (smoothness < 0 ? 2f : smoothness); - int segments = (int) ((2 * Mathf.PI * radius) * (Mathf.Abs(toDegree - startDegree) / 360) / smoothness); + int segments = (int)((2 * Mathf.PI * radius) * (Mathf.Abs(toDegree - startDegree) / 360) / smoothness); if (segments < 1) segments = 1; float startAngle = startDegree * Mathf.Deg2Rad; float toAngle = toDegree * Mathf.Deg2Rad; @@ -1520,7 +1609,7 @@ namespace XUGL var needSpace = gap != 0; var diffAngle = Mathf.Abs(toDegree - startDegree) * Mathf.Deg2Rad; - int segments = (int) ((2 * Mathf.PI * outsideRadius) * (diffAngle * Mathf.Rad2Deg / 360) / smoothness); + int segments = (int)((2 * Mathf.PI * outsideRadius) * (diffAngle * Mathf.Rad2Deg / 360) / smoothness); if (segments < 1) segments = 1; float startAngle = startDegree * Mathf.Deg2Rad; float toAngle = toDegree * Mathf.Deg2Rad; @@ -1779,7 +1868,7 @@ namespace XUGL float lineWidth, Color32 lineColor, float smoothness, Direction dire = Direction.XAxis) { var dist = Vector3.Distance(sp, ep); - var segment = (int) (dist / (smoothness <= 0 ? 2f : smoothness)); + var segment = (int)(dist / (smoothness <= 0 ? 2f : smoothness)); UGLHelper.GetBezierList2(ref s_CurvesPosList, sp, ep, segment, cp1, cp2); DrawCurvesInternal(vh, s_CurvesPosList, lineWidth, lineColor, dire); } @@ -1801,15 +1890,15 @@ namespace XUGL bool closed = false) { var count = points.Count; - var size = (closed?count : count - 1); + var size = (closed ? count : count - 1); if (closed) dire = Direction.Random; for (int i = 0; i < size; i++) { var sp = points[i]; - var ep = closed?(i == size - 1 ? points[0] : points[i + 1]) : points[i + 1]; - var lsp = i > 0 ? points[i - 1] : (closed?points[count - 1] : sp); - var nep = i < points.Count - 2 ? points[i + 2] : (closed?points[(i + 2) % count] : ep); + var ep = closed ? (i == size - 1 ? points[0] : points[i + 1]) : points[i + 1]; + var lsp = i > 0 ? points[i - 1] : (closed ? points[count - 1] : sp); + var nep = i < points.Count - 2 ? points[i + 2] : (closed ? points[(i + 2) % count] : ep); var smoothness2 = smoothness; if (currProgress != float.NaN) { @@ -1966,5 +2055,40 @@ namespace XUGL vh.AddTriangle(cv, cv + i - 1, cv + i); } } + + /// <summary> + /// Draw plus sign. + /// |绘制加号 + /// </summary> + /// <param name="vh"></param> + /// <param name="center"></param> + /// <param name="radius"></param> + /// <param name="tickness"></param> + /// <param name="color"></param> + public static void DrawPlus(VertexHelper vh, Vector3 center, float radius, float tickness, Color32 color) + { + var xPos1 = new Vector3(center.x - radius, center.y); + var xPos2 = new Vector3(center.x + radius, center.y); + var yPos1 = new Vector3(center.x, center.y - radius); + var yPos2 = new Vector3(center.x, center.y + radius); + UGL.DrawLine(vh, xPos1, xPos2, tickness, color); + UGL.DrawLine(vh, yPos1, yPos2, tickness, color); + } + + /// <summary> + /// Draw minus sign. + /// |绘制减号 + /// </summary> + /// <param name="vh"></param> + /// <param name="center"></param> + /// <param name="radius"></param> + /// <param name="tickness"></param> + /// <param name="color"></param> + public static void DrawMinus(VertexHelper vh, Vector3 center, float radius, float tickness, Color32 color) + { + var xPos1 = new Vector3(center.x - radius, center.y); + var xPos2 = new Vector3(center.x + radius, center.y); + UGL.DrawLine(vh, xPos1, xPos2, tickness, color); + } } } \ No newline at end of file diff --git a/package.json b/package.json index 14c8d4b9..bc13bf59 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "com.monitor1394.xcharts", "displayName": "XCharts", - "version": "3.7.0", - "date": "20230601", - "checkdate": "20230601", + "version": "3.8.0", + "date": "20230903", + "checkdate": "20230903", "desc": "如果 XCharts 对您有帮助,希望您能在 Github 上点 Star 支持,非常感谢!", "unity": "2018.3", "description": "A charting and data visualization library for Unity.",