diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f0bc2cc..9885877d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ # 更新日志 [master](#master) +[v3.3.0](#v3.3.0) [v3.2.0](#v3.2.0) [v3.1.0](#v3.1.0) [v3.0.1](#v3.0.1) @@ -58,6 +59,54 @@ ## master +## v3.3.0 + +### 版本要点 + +* 优化图表细节,支持更多功能 +* 增加大量的Demo示例 +* 完善文档,修复若干问题 +* 新增PolarChart对Bar、Heatmap的支持 +* 新增HeatmapChart热力图类型 +* 完善Tooltip显示 + +### 日志详情 + +* (2022.09.26) 优化`Axis`在类目轴时的默认分割段数 +* (2022.09.25) 修复`API`文档中部分接口没有导出的问题 +* (2022.09.24) 优化`FunnelChart` +* (2022.09.23) 优化`ParallelChart` +* (2022.09.22) 增加`SaveAsImage()`接口保存图表到图片 +* (2022.09.21) 修复`InsertSerie()`接口不刷新图表的问题 +* (2022.09.21) 优化`PolarChart`对`Line`热力图的支持 +* (2022.09.20) 增加`PolarChart`对`Heatmap`热力图的支持 +* (2022.09.19) 增加`PolarChart`对多柱图和堆叠柱图的支持 +* (2022.09.16) 增加`PolarChart`对`Bar`柱图的支持 +* (2022.09.14) 增加`PolarCoord`可通过`radius`设置环形极坐标的支持 +* (2022.09.09) 修复`Editor`下编辑参数部分组件可能不会实时刷新的问题 +* (2022.09.08) 增加`RingChart`可设置`LabelLine`引导线的支持 +* (2022.09.06) 增加`SerieSymbol`的`minSize`和`maxSize`参数设置最大最小尺寸的支持 +* (2022.09.06) 增加`AxisSplitLine`的`showStartLine`和`showEndLine`参数设置是否显示首位分割线的支持 +* (2022.09.06) 增加`Heatmap`通过`symbol`设置不同的图案的支持 +* (2022.09.05) 增加`Heatmap`的`heatmapType`支持设置`Data`和`Count`两种不同映射方式的热力图 +* (2022.09.05) 优化`Tooltip`在热力图为数值轴时的指示 +* (2022.09.02) 增加`onPointerEnterPie`回调支持 +* (2022.09.02) 优化`HeatmapChart` +* (2022.08.30) 优化`RadarChart` +* (2022.08.30) 修复`DataZoom`在某些情况下计算范围不准确的问题 (#221) +* (2022.08.29) 优化`BarChart`在数据过密时的默认表现 +* (2022.08.29) 优化`YAxis`在开启`DataZoom`时的最大最小值计算 +* (2022.08.29) 优化`CandlestickChart`大量数据绘制 +* (2022.08.28) 修复`LineChart`在堆叠和自定义Y轴范围的情况下显示不正常的问题 +* (2022.08.26) 增加`Legend`新图标类型`Candlestick` +* (2022.08.26) 优化`CandlestickChart`表现,调整相关的`AddData()`接口参数 +* (2022.08.26) 增加`Tooltip`的`position`参数支持设置移动平台不同的显示位置 +* (2022.08.26) 删除`Tooltip`的`fixedXEnable`和`fixedYEnable`参数 +* (2022.08.25) 优化`EmphasisStyle`对`label`的支持 +* (2022.08.25) 增加`formatter`对`{d3}`指定维度数据百分比的支持 +* (2022.08.24) 修复`ScatterChart`的`label`不刷新的问题 +* (2022.08.24) 修复`MarkLine`的`label`某些情况下显示异常的问题 + ## v3.2.0 ### 版本要点 diff --git a/Documentation/CHANGELOG.md b/Documentation/CHANGELOG.md index 8e94df40..e20f04a6 100644 --- a/Documentation/CHANGELOG.md +++ b/Documentation/CHANGELOG.md @@ -2,6 +2,7 @@ # 更新日志 [master](#master) +[v3.3.0](#v3.3.0) [v3.2.0](#v3.2.0) [v3.1.0](#v3.1.0) [v3.0.1](#v3.0.1) @@ -58,6 +59,54 @@ ## master +## v3.3.0 + +### Main points + +* Optimized chart details to support more functions +* Add lots of Demo examples +* Improved documentation and fixed several issues +* Added PolarChart support for Bar and Heatmap +* Added a HeatmapChart type +* Improved Tooltip display + +### Log details + +* (2022.09.26) Optimizes the default number of segments for `Axis` at the category Axis +* (2022.09.25) Fixed the problem that some interfaces in the `API` document were not exported +* (2022.09.24) optimize `FunnelChart` +* (2022.09.23) Optimizes `ParallelChart` +* (2022.09.22) Added `SaveAsImage()` interface to save charts to images +* (2022.09.21) Fixed an issue where the `InsertSerie()` interface did not refresh the graph +* (2022.09.21) Optimized `PolarChart` for `Line` thermal map support +* (2022.09.20) Added `PolarChart` support for `Heatmap` +* (2022.09.19) Added `PolarChart` support for multi-bar graphs and stacked bar graphs +* (2022.09.16) Added `PolarChart` support for `Bar` histogram +* (2022.09.14) Added support for `PolarCoord` to set ring polar coordinates via `Radius` +* (2022.09.09) Fixed an issue where some components of edit parameters in `Editor` might not refresh in real time +* (2022.09.08) Added support for `RingChart` settable `LabelLine` bootline +* (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) Optimizes `Tooltip` when indicating numerical axis in thermograph +* (2022.09.02) Added `onPointerEnterPie` callback support +* (2022.09.02) Optimize the HeatmapChart ` +* (2022.08.30) optimizes` RadarChart ` +* (2022.08.30) Fixed `DataZoom` calculation range inaccuracies in some cases (#221) +* (2022.08.29) optimizes the default behavior of `BarChart` when data is too dense +* (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) 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 +* (2022.08.25) EmphasisStyle `EmphasisStyle` has emphasised the support for `label` +* (2022.08.25) Added support for `formatter` for `{d3}` specified percentage of dimension data +* (2022.08.24) fixed the `label` of the `ScatterChart` not refreshing +* (2022.08.24) fixed abnormal display of `label` of `MarkLine` in some cases + ## v3.2.0 ### Main points diff --git a/Documentation/XChartsAPI-EN.md b/Documentation/XChartsAPI-EN.md index f09576c8..dc8d9f4f 100644 --- a/Documentation/XChartsAPI-EN.md +++ b/Documentation/XChartsAPI-EN.md @@ -130,12 +130,14 @@ Inherits or Implemented: [MainComponentHandler](#MainComponentHandler) | `GetAxisValueDistance()` |public static float GetAxisValueDistance(GridCoord grid, Axis axis, float scaleWidth, double value)
获得数值value在坐标轴上相对起点的距离 | | `GetAxisValueLength()` |public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value)
获得数值value在坐标轴上对应的长度 | | `GetAxisValuePosition()` |public static float GetAxisValuePosition(GridCoord grid, Axis axis, float scaleWidth, double value)
获得数值value在坐标轴上的坐标位置 | +| `GetAxisValueSplitIndex()` |public static int GetAxisValueSplitIndex(Axis axis, double value, int totalSplitNumber = -1)
获得数值value在坐标轴上对应的split索引 | | `GetAxisXOrY()` |public static float GetAxisXOrY(GridCoord grid, Axis axis, Axis relativedAxis)
| | `GetDataWidth()` |public static float GetDataWidth(Axis axis, float coordinateWidth, int dataCount, DataZoom dataZoom)
获得一个类目数据在坐标系中代表的宽度 | | `GetEachWidth()` |public static float GetEachWidth(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
| | `GetScaleNumber()` |public static int GetScaleNumber(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
获得分割线条数 | | `GetScaleWidth()` |public static float GetScaleWidth(Axis axis, float coordinateWidth, int index, DataZoom dataZoom = null)
获得分割段宽度 | | `GetSplitNumber()` |public static int GetSplitNumber(Axis axis, float coordinateWid, DataZoom dataZoom)
获得分割段数 | +| `GetTotalSplitGridNum()` |public static int GetTotalSplitGridNum(Axis axis)
获得分割网格个数,包含次刻度 | | `GetXAxisXOrY()` |public static float GetXAxisXOrY(GridCoord grid, Axis xAxis, Axis relativedAxis)
| | `GetYAxisXOrY()` |public static float GetYAxisXOrY(GridCoord grid, Axis yAxis, Axis relativedAxis)
| | `NeedShowSplit()` |public static bool NeedShowSplit(Axis axis)
| @@ -151,16 +153,19 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver |public method|description| |--|--| | `AddChartComponent()` |public MainComponent AddChartComponent(Type type)
| +| `AddChartComponent()` |public T AddChartComponent() where T : MainComponent
| +| `AddChartComponentWhenNoExist()` |public T AddChartComponentWhenNoExist() where T : MainComponent
| | `AddData()` |public SerieData AddData(int serieIndex, DateTime time, double yValue, string dataName = null, string dataId = null)
Add a (time,y) data to serie. | | `AddData()` |public SerieData AddData(int serieIndex, double data, string dataName = null, string dataId = null)
Add a data to serie. | -| `AddData()` |public SerieData AddData(int serieIndex, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| +| `AddData()` |public SerieData AddData(int serieIndex, double indexOrTimestamp, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| | `AddData()` |public SerieData AddData(int serieIndex, double xValue, double yValue, string dataName = null, string dataId = null)
Add a (x,y) data to serie. | | `AddData()` |public SerieData AddData(int serieIndex, List multidimensionalData, string dataName = null, string dataId = null)
Add an arbitray dimension data to serie,such as (x,y,z,...). | | `AddData()` |public SerieData AddData(string serieName, DateTime time, double yValue, string dataName = null, string dataId = null)
Add a (time,y) data to serie. | | `AddData()` |public SerieData AddData(string serieName, double data, string dataName = null, string dataId = null)
Add a data to serie. | -| `AddData()` |public SerieData AddData(string serieName, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| +| `AddData()` |public SerieData AddData(string serieName, double indexOrTimestamp, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| | `AddData()` |public SerieData AddData(string serieName, double xValue, double yValue, string dataName = null, string dataId = null)
Add a (x,y) data to serie. | | `AddData()` |public SerieData AddData(string serieName, List multidimensionalData, string dataName = null, string dataId = null)
Add an arbitray dimension data to serie,such as (x,y,z,...). | +| `AddSerie()` |public T AddSerie(string serieName = null, bool show = true, bool addToHead = false) where T : Serie
| | `AddXAxisData()` |public void AddXAxisData(string category, int xAxisIndex = 0)
Add a category data to xAxis. | | `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. | @@ -173,17 +178,22 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `AnimationResume()` |public void AnimationResume()
Stop play animation. | | `CanAddChartComponent()` |public bool CanAddChartComponent(Type type)
| | `CanAddSerie()` |public bool CanAddSerie(Type type)
| +| `CanAddSerie()` |public bool CanAddSerie() where T : Serie
| | `CanMultipleComponent()` |public bool CanMultipleComponent(Type type)
| | `ClampInChart()` |public void ClampInChart(ref Vector3 pos)
| | `ClampInGrid()` |public Vector3 ClampInGrid(GridCoord grid, Vector3 pos)
| | `ClearData()` |public virtual void ClearData()
Clear all components and series data. Note: serie only empties the data and does not remove serie. | | `ClickLegendButton()` |public void ClickLegendButton(int legendIndex, string legendName, bool show)
点击图例按钮 | | `CovertSerie()` |public bool CovertSerie(Serie serie, Type type)
| +| `CovertSerie()` |public bool CovertSerie(Serie serie) where T : Serie
| | `CovertXYAxis()` |public void CovertXYAxis(int index)
转换X轴和Y轴的配置 | | `GenerateDefaultSerieName()` |public string GenerateDefaultSerieName()
| | `GetAllSerieDataCount()` |public int GetAllSerieDataCount()
| | `GetChartBackgroundColor()` |public Color32 GetChartBackgroundColor()
| +| `GetChartComponent()` |public T GetChartComponent(int index = 0) where T : MainComponent
| | `GetChartComponentNum()` |public int GetChartComponentNum(Type type)
| +| `GetChartComponentNum()` |public int GetChartComponentNum() where T : MainComponent
| +| `GetChartComponents()` |public List GetChartComponents() where T : MainComponent
| | `GetData()` |public double GetData(int serieIndex, int dataIndex, int dimension = 1)
| | `GetData()` |public double GetData(string serieName, int dataIndex, int dimension = 1)
| | `GetDataZoomOfAxis()` |public DataZoom GetDataZoomOfAxis(Axis axis)
| @@ -195,20 +205,32 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `GetItemColor()` |public Color32 GetItemColor(Serie serie, SerieData serieData, int colorIndex)
| | `GetLegendRealShowNameColor()` |public Color32 GetLegendRealShowNameColor(string name)
| | `GetLegendRealShowNameIndex()` |public int GetLegendRealShowNameIndex(string name)
| +| `GetOrAddChartComponent()` |public T GetOrAddChartComponent() where T : MainComponent
| | `GetPainter()` |public Painter GetPainter(int index)
| | `GetSerie()` |public Serie GetSerie(int serieIndex)
| | `GetSerie()` |public Serie GetSerie(string serieName)
| +| `GetSerie()` |public T GetSerie() where T : Serie
| +| `GetSerie()` |public T GetSerie(int serieIndex) where T : Serie
| +| `GetSerieBarGap()` |public float GetSerieBarGap() where T : Serie
| +| `GetSerieBarRealCount()` |public int GetSerieBarRealCount() where T : Serie
| +| `GetSerieIndexIfStack()` |public int GetSerieIndexIfStack(Serie currSerie) where T : Serie
| +| `GetSerieSameStackTotalValue()` |public double GetSerieSameStackTotalValue(string stack, int dataIndex) where T : Serie
| | `GetSeriesMinMaxValue()` |public virtual void GetSeriesMinMaxValue(Axis axis, int axisIndex, out double tempMinValue, out double tempMaxValue)
| +| `GetSerieTotalGap()` |public float GetSerieTotalGap(float categoryWidth, float gap, int index) where T : Serie
| +| `GetSerieTotalWidth()` |public float GetSerieTotalWidth(float categoryWidth, float gap, int realBarCount) where T : Serie
| | `GetTitlePosition()` |public Vector3 GetTitlePosition(Title title)
| | `GetVisualMapOfSerie()` |public VisualMap GetVisualMapOfSerie(Serie serie)
| +| `GetXDataZoomOfSerie()` |public DataZoom GetXDataZoomOfSerie(Serie serie)
| | `GetXLerpColor()` |public Color32 GetXLerpColor(Color32 areaColor, Color32 areaToColor, Vector3 pos, GridCoord grid)
| | `GetYLerpColor()` |public Color32 GetYLerpColor(Color32 areaColor, Color32 areaToColor, Vector3 pos, GridCoord grid)
| | `HasChartComponent()` |public bool HasChartComponent(Type type)
| | `HasChartComponent()` |public bool HasChartComponent()
| | `HasSerie()` |public bool HasSerie(Type type)
| +| `HasSerie()` |public bool HasSerie() where T : Serie
| | `Init()` |public void Init(bool defaultChart = true)
| -| `InitAxisRuntimeData()` |public virtual void InitAxisRuntimeData(Axis axis)
| +| `InitAxisRuntimeData()` |public virtual void InitAxisRuntimeData(Axis axis) { }
| | `InsertSerie()` |public void InsertSerie(Serie serie, int index = -1, bool addToHead = false)
| +| `InsertSerie()` |public T InsertSerie(int index, string serieName = null, bool show = true) where T : Serie
| | `Internal_CheckAnimation()` |public void Internal_CheckAnimation()
| | `IsActiveByLegend()` |public virtual bool IsActiveByLegend(string legendName)
Whether serie is activated. | | `IsAllAxisCategory()` |public bool IsAllAxisCategory()
纯类目轴。 | @@ -239,6 +261,7 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `RefreshChart()` |public void RefreshChart(int serieIndex)
Redraw chart serie in next frame. | | `RefreshChart()` |public void RefreshChart(Serie serie)
Redraw chart serie in next frame. | | `RefreshDataZoom()` |public void RefreshDataZoom()
在下一帧刷新DataZoom | +| `RefreshGraph()` |public override void RefreshGraph()
| | `RefreshPainter()` |public void RefreshPainter(int index)
| | `RefreshPainter()` |public void RefreshPainter(Serie serie)
| | `RefreshTopPainter()` |public void RefreshTopPainter()
| @@ -255,8 +278,10 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `RemoveSerie()` |public void RemoveSerie(int serieIndex)
| | `RemoveSerie()` |public void RemoveSerie(Serie serie)
| | `RemoveSerie()` |public void RemoveSerie(string serieName)
| +| `RemoveSerie()` |public void RemoveSerie() where T : Serie
| | `ReplaceSerie()` |public bool ReplaceSerie(Serie oldSerie, Serie newSerie)
| | `ResetDataIndex()` |public bool ResetDataIndex(int serieIndex)
重置serie的数据项索引。避免数据项索引异常。 | +| `SaveAsImage()` |public void SaveAsImage(string imageType = "png", string savePath = "")
保存图表为图片。 | | `SetBasePainterMaterial()` |public void SetBasePainterMaterial(Material material)
设置Base Painter的材质球 | | `SetMaxCache()` |public void SetMaxCache(int maxCache)
设置可缓存的最大数据量。当数据量超过该值时,会自动删除第一个值再加入最新值。 | | `SetPainterActive()` |public void SetPainterActive(int index, bool flag)
| @@ -267,6 +292,8 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `SetTopPainterMaterial()` |public void SetTopPainterMaterial(Material material)
设置Top Painter的材质球 | | `SetUpperPainterMaterial()` |public void SetUpperPainterMaterial(Material material)
设置Upper Painter的材质球 | | `TryAddChartComponent()` |public bool TryAddChartComponent(Type type)
| +| `TryAddChartComponent()` |public bool TryAddChartComponent() where T : MainComponent
| +| `TryAddChartComponent()` |public bool TryAddChartComponent(out T component) where T : MainComponent
| | `TryGetChartComponent()` |public bool TryGetChartComponent(out T component, int index = 0)
| | `UdpateXAxisIcon()` |public void UdpateXAxisIcon(int index, Sprite icon, int xAxisIndex = 0)
Update xAxis icon. | | `UpdateData()` |public bool UpdateData(int serieIndex, int dataIndex, double value)
Update serie data by serie index. | @@ -302,7 +329,7 @@ Inherits or Implemented: [MaskableGraphic](#MaskableGraphic),[IPointerDownHandle | `OnScroll()` |public virtual void OnScroll(PointerEventData eventData)
| | `RebuildChartObject()` |public void RebuildChartObject()
移除并重新创建所有图表的Object。 | | `RefreshAllComponent()` |public void RefreshAllComponent()
| -| `RefreshGraph()` |public void RefreshGraph()
Redraw graph in next frame. | +| `RefreshGraph()` |public virtual void RefreshGraph()
Redraw graph in next frame. | | `ScreenPointToChartPoint()` |public bool ScreenPointToChartPoint(Vector2 screenPoint, out Vector2 chartPoint)
| | `SetPainterDirty()` |public void SetPainterDirty()
重新初始化Painter | | `SetSize()` |public virtual void SetSize(float width, float height)
设置图形的宽高(在非stretch pivot下才有效,其他情况需要自己调整RectTransform) | @@ -354,6 +381,8 @@ Inherits or Implemented: [BaseChart](#BaseChart) | `GetMaxLogValue()` |public static double GetMaxLogValue(double value, float logBase, bool isLogBaseE, out int splitNumber)
| | `GetMinDivisibleValue()` |public static double GetMinDivisibleValue(double min, double ceilRate)
| | `GetMinLogValue()` |public static double GetMinLogValue(double value, float logBase, bool isLogBaseE, out int splitNumber)
| +| `GetOrAddComponent()` |public static T GetOrAddComponent(GameObject gameObject) where T : Component
| +| `GetOrAddComponent()` |public static T GetOrAddComponent(Transform transform) where T : Component
| | `GetPointList()` |public static void GetPointList(ref List posList, Vector3 sp, Vector3 ep, float k = 30f)
| | `GetPos()` |public static Vector3 GetPos(Vector3 center, float radius, float angle, bool isDegree = false)
| | `GetPosition()` |public static Vector3 GetPosition(Vector3 center, float angle, float radius)
| @@ -380,6 +409,7 @@ Inherits or Implemented: [BaseChart](#BaseChart) | `ParseStringFromString()` |public static List ParseStringFromString(string jsonData)
| | `RemoveComponent()` |public static void RemoveComponent(GameObject gameObject)
| | `RotateRound()` |public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
| +| `SaveAsImage()` |public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png", string path = "")
| | `SetActive()` |public static void SetActive(GameObject gameObject, bool active)
| | `SetActive()` |public static void SetActive(Image image, bool active)
| | `SetActive()` |public static void SetActive(Text text, bool active)
| @@ -458,6 +488,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| +| `Contains()` |public bool Contains() where T : CoordSystem
| | `CoordOptionsAttribute()` |public CoordOptionsAttribute(Type coord)
| | `CoordOptionsAttribute()` |public CoordOptionsAttribute(Type coord, Type coord2)
| | `CoordOptionsAttribute()` |public CoordOptionsAttribute(Type coord, Type coord2, Type coord3)
| @@ -472,6 +503,7 @@ Inherits or Implemented: [MainComponentContext](#MainComponentContext) |public method|description| |--|--| | `UpdateDataZoomRuntimeStartEndValue()` |public static void UpdateDataZoomRuntimeStartEndValue(DataZoom dataZoom, Serie serie)
| +| `UpdateDataZoomRuntimeStartEndValue()` |public static void UpdateDataZoomRuntimeStartEndValue(BaseChart chart) where T : Serie
| ## `DateTimeUtil` @@ -615,6 +647,26 @@ Inherits or Implemented: [ListFor](#ListFor) ## `MainComponentHandler` +|public method|description| +|--|--| +| `CheckComponent()` |public virtual void CheckComponent(StringBuilder sb) { }
| +| `DrawBase()` |public virtual void DrawBase(VertexHelper vh) { }
| +| `DrawTop()` |public virtual void DrawTop(VertexHelper vh) { }
| +| `DrawUpper()` |public virtual void DrawUpper(VertexHelper vh) { }
| +| `InitComponent()` |public virtual void InitComponent() { }
| +| `OnBeginDrag()` |public virtual void OnBeginDrag(PointerEventData eventData) { }
| +| `OnDrag()` |public virtual void OnDrag(PointerEventData eventData) { }
| +| `OnEndDrag()` |public virtual void OnEndDrag(PointerEventData eventData) { }
| +| `OnPointerClick()` |public virtual void OnPointerClick(PointerEventData eventData) { }
| +| `OnPointerDown()` |public virtual void OnPointerDown(PointerEventData eventData) { }
| +| `OnPointerEnter()` |public virtual void OnPointerEnter(PointerEventData eventData) { }
| +| `OnPointerExit()` |public virtual void OnPointerExit(PointerEventData eventData) { }
| +| `OnPointerUp()` |public virtual void OnPointerUp(PointerEventData eventData) { }
| +| `OnScroll()` |public virtual void OnScroll(PointerEventData eventData) { }
| +| `OnSerieDataUpdate()` |public virtual void OnSerieDataUpdate(int serieIndex) { }
| +| `RemoveComponent()` |public virtual void RemoveComponent() { }
| +| `Update()` |public virtual void Update() { }
| + ## `MainComponentHandler` Inherits or Implemented: [MainComponentHandler](#MainComponentHandler) @@ -679,8 +731,10 @@ Inherits or Implemented: [BaseChart](#BaseChart) |public method|description| |--|--| +| `SetClass()` |public static bool SetClass(ref T currentValue, T newValue, bool notNull = false) where T : class
| | `SetColor()` |public static bool SetColor(ref Color currentValue, Color newValue)
| | `SetColor()` |public static bool SetColor(ref Color32 currentValue, Color32 newValue)
| +| `SetStruct()` |public static bool SetStruct(ref T currentValue, T newValue) where T : struct
| ## `RadarChart` @@ -722,6 +776,8 @@ Inherits or Implemented: [BaseChart](#BaseChart) | `GetAllAssemblyTypes()` |public static IEnumerable GetAllAssemblyTypes()
| | `GetAllTypesDerivedFrom()` |public static IEnumerable GetAllTypesDerivedFrom(Type type)
| | `GetAllTypesDerivedFrom()` |public static IEnumerable GetAllTypesDerivedFrom()
| +| `GetAttribute()` |public static T GetAttribute(this MemberInfo type, bool check = true) where T : Attribute
| +| `GetAttribute()` |public static T GetAttribute(this Type type, bool check = true) where T : Attribute
| | `HasSubclass()` |public static bool HasSubclass(Type type)
| ## `ScatterChart` @@ -737,6 +793,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| | `Contains()` |public bool Contains(Type type)
| +| `Contains()` |public bool Contains() where T : Serie
| | `SerieConvertAttribute()` |public SerieConvertAttribute(Type serie)
| | `SerieConvertAttribute()` |public SerieConvertAttribute(Type serie, Type serie2)
| | `SerieConvertAttribute()` |public SerieConvertAttribute(Type serie, Type serie2, Type serie3)
| @@ -755,6 +812,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| | `Contains()` |public bool Contains(Type type)
| +| `Contains()` |public bool Contains() where T : ISerieExtraComponent
| | `SerieDataExtraComponentAttribute()` |public SerieDataExtraComponentAttribute()
| | `SerieDataExtraComponentAttribute()` |public SerieDataExtraComponentAttribute(Type type1)
| | `SerieDataExtraComponentAttribute()` |public SerieDataExtraComponentAttribute(Type type1, Type type2)
| @@ -787,6 +845,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| | `Contains()` |public bool Contains(Type type)
| +| `Contains()` |public bool Contains() where T : ISerieExtraComponent
| | `SerieExtraComponentAttribute()` |public SerieExtraComponentAttribute()
| | `SerieExtraComponentAttribute()` |public SerieExtraComponentAttribute(Type type1)
| | `SerieExtraComponentAttribute()` |public SerieExtraComponentAttribute(Type type1, Type type2)
| @@ -798,6 +857,31 @@ Inherits or Implemented: [Attribute](#Attribute) ## `SerieHandler` +|public method|description| +|--|--| +| `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) { }
| +| `InitComponent()` |public virtual void InitComponent() { }
| +| `OnBeginDrag()` |public virtual void OnBeginDrag(PointerEventData eventData) { }
| +| `OnDrag()` |public virtual void OnDrag(PointerEventData eventData) { }
| +| `OnEndDrag()` |public virtual void OnEndDrag(PointerEventData eventData) { }
| +| `OnLegendButtonClick()` |public virtual void OnLegendButtonClick(int index, string legendName, bool show) { }
| +| `OnLegendButtonEnter()` |public virtual void OnLegendButtonEnter(int index, string legendName) { }
| +| `OnLegendButtonExit()` |public virtual void OnLegendButtonExit(int index, string legendName) { }
| +| `OnPointerClick()` |public virtual void OnPointerClick(PointerEventData eventData) { }
| +| `OnPointerDown()` |public virtual void OnPointerDown(PointerEventData eventData) { }
| +| `OnPointerEnter()` |public virtual void OnPointerEnter(PointerEventData eventData) { }
| +| `OnPointerExit()` |public virtual void OnPointerExit(PointerEventData eventData) { }
| +| `OnPointerUp()` |public virtual void OnPointerUp(PointerEventData eventData) { }
| +| `OnScroll()` |public virtual void OnScroll(PointerEventData eventData) { }
| +| `RefreshLabelInternal()` |public virtual void RefreshLabelInternal() { }
| +| `RefreshLabelNextFrame()` |public virtual void RefreshLabelNextFrame() { }
| +| `RemoveComponent()` |public virtual void RemoveComponent() { }
| +| `Update()` |public virtual void Update() { }
| + ## `SerieHandler` Inherits or Implemented: [SerieHandler where T](#SerieHandler where T),[Serie](#Serie) @@ -831,6 +915,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| +| `CloneSerie()` |public static T CloneSerie(Serie serie) where T : Serie
| | `CopySerie()` |public static void CopySerie(Serie oldSerie, Serie newSerie)
| | `GetAllMinMaxData()` |public static void GetAllMinMaxData(Serie serie, double ceilRate = 0, DataZoom dataZoom = null)
| | `GetAreaStyle()` |public static AreaStyle GetAreaStyle(Serie serie, SerieData serieData)
| @@ -900,7 +985,10 @@ Inherits or Implemented: [Attribute](#Attribute) | `GetStackSeries()` |public static void GetStackSeries(List series, ref Dictionary> stackSeries)
获得堆叠系列列表 | | `IsAnyClipSerie()` |public static bool IsAnyClipSerie(List series)
是否有需裁剪的serie。 | | `IsLegalLegendName()` |public static bool IsLegalLegendName(string name)
| +| `IsPercentStack()` |public static bool IsPercentStack(List series) where T : Serie
是否时百分比堆叠 | +| `IsPercentStack()` |public static bool IsPercentStack(List series, string stackName) where T : Serie
是否时百分比堆叠 | | `IsStack()` |public static bool IsStack(List series)
是否由数据堆叠 | +| `IsStack()` |public static bool IsStack(List series, string stackName) where T : Serie
是否堆叠 | | `UpdateSerieNameList()` |public static void UpdateSerieNameList(BaseChart chart, ref List serieNameList)
获得所有系列名,不包含空名字。 | | `UpdateStackDataList()` |public static void UpdateStackDataList(List series, Serie currSerie, DataZoom dataZoom, List> dataList)
| @@ -1038,7 +1126,7 @@ Inherits or Implemented: [MainComponentContext](#MainComponentContext) |public method|description| |--|--| | `AutoSetLineMinMax()` |public static void AutoSetLineMinMax(VisualMap visualMap, Serie serie, bool isY, Axis axis, Axis relativedAxis)
| -| `GetDimension()` |public static int GetDimension(VisualMap visualMap, int serieDataCount)
| +| `GetDimension()` |public static int GetDimension(VisualMap visualMap, int defaultDimension)
| | `IsNeedAreaGradient()` |public static bool IsNeedAreaGradient(VisualMap visualMap)
| | `IsNeedGradient()` |public static bool IsNeedGradient(VisualMap visualMap)
| | `IsNeedLineGradient()` |public static bool IsNeedLineGradient(VisualMap visualMap)
| diff --git a/Documentation/XChartsAPI-ZH.md b/Documentation/XChartsAPI-ZH.md index e2994473..d4b73194 100644 --- a/Documentation/XChartsAPI-ZH.md +++ b/Documentation/XChartsAPI-ZH.md @@ -130,12 +130,14 @@ Inherits or Implemented: [MainComponentHandler](#MainComponentHandler) | `GetAxisValueDistance()` |public static float GetAxisValueDistance(GridCoord grid, Axis axis, float scaleWidth, double value)
获得数值value在坐标轴上相对起点的距离 | | `GetAxisValueLength()` |public static float GetAxisValueLength(GridCoord grid, Axis axis, float scaleWidth, double value)
获得数值value在坐标轴上对应的长度 | | `GetAxisValuePosition()` |public static float GetAxisValuePosition(GridCoord grid, Axis axis, float scaleWidth, double value)
获得数值value在坐标轴上的坐标位置 | +| `GetAxisValueSplitIndex()` |public static int GetAxisValueSplitIndex(Axis axis, double value, int totalSplitNumber = -1)
获得数值value在坐标轴上对应的split索引 | | `GetAxisXOrY()` |public static float GetAxisXOrY(GridCoord grid, Axis axis, Axis relativedAxis)
| | `GetDataWidth()` |public static float GetDataWidth(Axis axis, float coordinateWidth, int dataCount, DataZoom dataZoom)
获得一个类目数据在坐标系中代表的宽度 | | `GetEachWidth()` |public static float GetEachWidth(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
| | `GetScaleNumber()` |public static int GetScaleNumber(Axis axis, float coordinateWidth, DataZoom dataZoom = null)
获得分割线条数 | | `GetScaleWidth()` |public static float GetScaleWidth(Axis axis, float coordinateWidth, int index, DataZoom dataZoom = null)
获得分割段宽度 | | `GetSplitNumber()` |public static int GetSplitNumber(Axis axis, float coordinateWid, DataZoom dataZoom)
获得分割段数 | +| `GetTotalSplitGridNum()` |public static int GetTotalSplitGridNum(Axis axis)
获得分割网格个数,包含次刻度 | | `GetXAxisXOrY()` |public static float GetXAxisXOrY(GridCoord grid, Axis xAxis, Axis relativedAxis)
| | `GetYAxisXOrY()` |public static float GetYAxisXOrY(GridCoord grid, Axis yAxis, Axis relativedAxis)
| | `NeedShowSplit()` |public static bool NeedShowSplit(Axis axis)
| @@ -151,16 +153,19 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver |public method|description| |--|--| | `AddChartComponent()` |public MainComponent AddChartComponent(Type type)
| +| `AddChartComponent()` |public T AddChartComponent() where T : MainComponent
| +| `AddChartComponentWhenNoExist()` |public T AddChartComponentWhenNoExist() where T : MainComponent
| | `AddData()` |public SerieData AddData(int serieIndex, DateTime time, double yValue, string dataName = null, string dataId = null)
添加(time,y)数据到指定的系列中。 | | `AddData()` |public SerieData AddData(int serieIndex, double data, string dataName = null, string dataId = null)
添加一个数据到指定的系列中。 | -| `AddData()` |public SerieData AddData(int serieIndex, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| +| `AddData()` |public SerieData AddData(int serieIndex, double indexOrTimestamp, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| | `AddData()` |public SerieData AddData(int serieIndex, double xValue, double yValue, string dataName = null, string dataId = null)
添加(x,y)数据到指定系列中。 | | `AddData()` |public SerieData AddData(int serieIndex, List multidimensionalData, string dataName = null, string dataId = null)
添加多维数据(x,y,z...)到指定的系列中。 | | `AddData()` |public SerieData AddData(string serieName, DateTime time, double yValue, string dataName = null, string dataId = null)
添加(time,y)数据到指定的系列中。 | | `AddData()` |public SerieData AddData(string serieName, double data, string dataName = null, string dataId = null)
If serieName doesn't exist in legend,will be add to legend. | -| `AddData()` |public SerieData AddData(string serieName, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| +| `AddData()` |public SerieData AddData(string serieName, double indexOrTimestamp, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null)
| | `AddData()` |public SerieData AddData(string serieName, double xValue, double yValue, string dataName = null, string dataId = null)
添加(x,y)数据到指定系列中。 | | `AddData()` |public SerieData AddData(string serieName, List multidimensionalData, string dataName = null, string dataId = null)
添加多维数据(x,y,z...)到指定的系列中。 | +| `AddSerie()` |public T AddSerie(string serieName = null, bool show = true, bool addToHead = false) where T : Serie
| | `AddXAxisData()` |public void AddXAxisData(string category, int xAxisIndex = 0)
添加一个类目数据到指定的x轴。 | | `AddXAxisIcon()` |public void AddXAxisIcon(Sprite icon, int xAxisIndex = 0)
添加一个图标到指定的x轴。 | | `AddYAxisData()` |public void AddYAxisData(string category, int yAxisIndex = 0)
添加一个类目数据到指定的y轴。 | @@ -173,17 +178,22 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `AnimationResume()` |public void AnimationResume()
继续动画。 | | `CanAddChartComponent()` |public bool CanAddChartComponent(Type type)
| | `CanAddSerie()` |public bool CanAddSerie(Type type)
| +| `CanAddSerie()` |public bool CanAddSerie() where T : Serie
| | `CanMultipleComponent()` |public bool CanMultipleComponent(Type type)
| | `ClampInChart()` |public void ClampInChart(ref Vector3 pos)
| | `ClampInGrid()` |public Vector3 ClampInGrid(GridCoord grid, Vector3 pos)
| | `ClearData()` |public virtual void ClearData()
清空所有组件和Serie的数据。注意:Serie只是清空数据,不会移除Serie。 | | `ClickLegendButton()` |public void ClickLegendButton(int legendIndex, string legendName, bool show)
点击图例按钮 | | `CovertSerie()` |public bool CovertSerie(Serie serie, Type type)
| +| `CovertSerie()` |public bool CovertSerie(Serie serie) where T : Serie
| | `CovertXYAxis()` |public void CovertXYAxis(int index)
转换X轴和Y轴的配置 | | `GenerateDefaultSerieName()` |public string GenerateDefaultSerieName()
| | `GetAllSerieDataCount()` |public int GetAllSerieDataCount()
| | `GetChartBackgroundColor()` |public Color32 GetChartBackgroundColor()
| +| `GetChartComponent()` |public T GetChartComponent(int index = 0) where T : MainComponent
| | `GetChartComponentNum()` |public int GetChartComponentNum(Type type)
| +| `GetChartComponentNum()` |public int GetChartComponentNum() where T : MainComponent
| +| `GetChartComponents()` |public List GetChartComponents() where T : MainComponent
| | `GetData()` |public double GetData(int serieIndex, int dataIndex, int dimension = 1)
| | `GetData()` |public double GetData(string serieName, int dataIndex, int dimension = 1)
| | `GetDataZoomOfAxis()` |public DataZoom GetDataZoomOfAxis(Axis axis)
| @@ -195,20 +205,32 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `GetItemColor()` |public Color32 GetItemColor(Serie serie, SerieData serieData, int colorIndex)
| | `GetLegendRealShowNameColor()` |public Color32 GetLegendRealShowNameColor(string name)
| | `GetLegendRealShowNameIndex()` |public int GetLegendRealShowNameIndex(string name)
| +| `GetOrAddChartComponent()` |public T GetOrAddChartComponent() where T : MainComponent
| | `GetPainter()` |public Painter GetPainter(int index)
| | `GetSerie()` |public Serie GetSerie(int serieIndex)
| | `GetSerie()` |public Serie GetSerie(string serieName)
| +| `GetSerie()` |public T GetSerie() where T : Serie
| +| `GetSerie()` |public T GetSerie(int serieIndex) where T : Serie
| +| `GetSerieBarGap()` |public float GetSerieBarGap() where T : Serie
| +| `GetSerieBarRealCount()` |public int GetSerieBarRealCount() where T : Serie
| +| `GetSerieIndexIfStack()` |public int GetSerieIndexIfStack(Serie currSerie) where T : Serie
| +| `GetSerieSameStackTotalValue()` |public double GetSerieSameStackTotalValue(string stack, int dataIndex) where T : Serie
| | `GetSeriesMinMaxValue()` |public virtual void GetSeriesMinMaxValue(Axis axis, int axisIndex, out double tempMinValue, out double tempMaxValue)
| +| `GetSerieTotalGap()` |public float GetSerieTotalGap(float categoryWidth, float gap, int index) where T : Serie
| +| `GetSerieTotalWidth()` |public float GetSerieTotalWidth(float categoryWidth, float gap, int realBarCount) where T : Serie
| | `GetTitlePosition()` |public Vector3 GetTitlePosition(Title title)
| | `GetVisualMapOfSerie()` |public VisualMap GetVisualMapOfSerie(Serie serie)
| +| `GetXDataZoomOfSerie()` |public DataZoom GetXDataZoomOfSerie(Serie serie)
| | `GetXLerpColor()` |public Color32 GetXLerpColor(Color32 areaColor, Color32 areaToColor, Vector3 pos, GridCoord grid)
| | `GetYLerpColor()` |public Color32 GetYLerpColor(Color32 areaColor, Color32 areaToColor, Vector3 pos, GridCoord grid)
| | `HasChartComponent()` |public bool HasChartComponent(Type type)
| | `HasChartComponent()` |public bool HasChartComponent()
| | `HasSerie()` |public bool HasSerie(Type type)
| +| `HasSerie()` |public bool HasSerie() where T : Serie
| | `Init()` |public void Init(bool defaultChart = true)
| -| `InitAxisRuntimeData()` |public virtual void InitAxisRuntimeData(Axis axis)
| +| `InitAxisRuntimeData()` |public virtual void InitAxisRuntimeData(Axis axis) { }
| | `InsertSerie()` |public void InsertSerie(Serie serie, int index = -1, bool addToHead = false)
| +| `InsertSerie()` |public T InsertSerie(int index, string serieName = null, bool show = true) where T : Serie
| | `Internal_CheckAnimation()` |public void Internal_CheckAnimation()
| | `IsActiveByLegend()` |public virtual bool IsActiveByLegend(string legendName)
获得指定图例名字的系列是否显示。 | | `IsAllAxisCategory()` |public bool IsAllAxisCategory()
纯类目轴。 | @@ -239,6 +261,7 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `RefreshChart()` |public void RefreshChart(int serieIndex)
在下一帧刷新图表的指定serie。 | | `RefreshChart()` |public void RefreshChart(Serie serie)
在下一帧刷新图表的指定serie。 | | `RefreshDataZoom()` |public void RefreshDataZoom()
在下一帧刷新DataZoom | +| `RefreshGraph()` |public override void RefreshGraph()
| | `RefreshPainter()` |public void RefreshPainter(int index)
| | `RefreshPainter()` |public void RefreshPainter(Serie serie)
| | `RefreshTopPainter()` |public void RefreshTopPainter()
| @@ -255,8 +278,10 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `RemoveSerie()` |public void RemoveSerie(int serieIndex)
| | `RemoveSerie()` |public void RemoveSerie(Serie serie)
| | `RemoveSerie()` |public void RemoveSerie(string serieName)
| +| `RemoveSerie()` |public void RemoveSerie() where T : Serie
| | `ReplaceSerie()` |public bool ReplaceSerie(Serie oldSerie, Serie newSerie)
| | `ResetDataIndex()` |public bool ResetDataIndex(int serieIndex)
重置serie的数据项索引。避免数据项索引异常。 | +| `SaveAsImage()` |public void SaveAsImage(string imageType = "png", string savePath = "")
保存图表为图片。 | | `SetBasePainterMaterial()` |public void SetBasePainterMaterial(Material material)
设置Base Painter的材质球 | | `SetMaxCache()` |public void SetMaxCache(int maxCache)
设置可缓存的最大数据量。当数据量超过该值时,会自动删除第一个值再加入最新值。 | | `SetPainterActive()` |public void SetPainterActive(int index, bool flag)
| @@ -267,6 +292,8 @@ Inherits or Implemented: [BaseGraph](#BaseGraph),[ISerializationCallbackReceiver | `SetTopPainterMaterial()` |public void SetTopPainterMaterial(Material material)
设置Top Painter的材质球 | | `SetUpperPainterMaterial()` |public void SetUpperPainterMaterial(Material material)
设置Upper Painter的材质球 | | `TryAddChartComponent()` |public bool TryAddChartComponent(Type type)
| +| `TryAddChartComponent()` |public bool TryAddChartComponent() where T : MainComponent
| +| `TryAddChartComponent()` |public bool TryAddChartComponent(out T component) where T : MainComponent
| | `TryGetChartComponent()` |public bool TryGetChartComponent(out T component, int index = 0)
| | `UdpateXAxisIcon()` |public void UdpateXAxisIcon(int index, Sprite icon, int xAxisIndex = 0)
更新X轴图标。 | | `UpdateData()` |public bool UpdateData(int serieIndex, int dataIndex, double value)
更新指定系列中的指定索引数据。 | @@ -302,7 +329,7 @@ Inherits or Implemented: [MaskableGraphic](#MaskableGraphic),[IPointerDownHandle | `OnScroll()` |public virtual void OnScroll(PointerEventData eventData)
| | `RebuildChartObject()` |public void RebuildChartObject()
移除并重新创建所有图表的Object。 | | `RefreshAllComponent()` |public void RefreshAllComponent()
| -| `RefreshGraph()` |public void RefreshGraph()
在下一帧刷新图形。 | +| `RefreshGraph()` |public virtual void RefreshGraph()
在下一帧刷新图形。 | | `ScreenPointToChartPoint()` |public bool ScreenPointToChartPoint(Vector2 screenPoint, out Vector2 chartPoint)
| | `SetPainterDirty()` |public void SetPainterDirty()
重新初始化Painter | | `SetSize()` |public virtual void SetSize(float width, float height)
设置图形的宽高(在非stretch pivot下才有效,其他情况需要自己调整RectTransform) | @@ -354,6 +381,8 @@ Inherits or Implemented: [BaseChart](#BaseChart) | `GetMaxLogValue()` |public static double GetMaxLogValue(double value, float logBase, bool isLogBaseE, out int splitNumber)
| | `GetMinDivisibleValue()` |public static double GetMinDivisibleValue(double min, double ceilRate)
| | `GetMinLogValue()` |public static double GetMinLogValue(double value, float logBase, bool isLogBaseE, out int splitNumber)
| +| `GetOrAddComponent()` |public static T GetOrAddComponent(GameObject gameObject) where T : Component
| +| `GetOrAddComponent()` |public static T GetOrAddComponent(Transform transform) where T : Component
| | `GetPointList()` |public static void GetPointList(ref List posList, Vector3 sp, Vector3 ep, float k = 30f)
| | `GetPos()` |public static Vector3 GetPos(Vector3 center, float radius, float angle, bool isDegree = false)
| | `GetPosition()` |public static Vector3 GetPosition(Vector3 center, float angle, float radius)
| @@ -380,6 +409,7 @@ Inherits or Implemented: [BaseChart](#BaseChart) | `ParseStringFromString()` |public static List ParseStringFromString(string jsonData)
| | `RemoveComponent()` |public static void RemoveComponent(GameObject gameObject)
| | `RotateRound()` |public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
| +| `SaveAsImage()` |public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png", string path = "")
| | `SetActive()` |public static void SetActive(GameObject gameObject, bool active)
| | `SetActive()` |public static void SetActive(Image image, bool active)
| | `SetActive()` |public static void SetActive(Text text, bool active)
| @@ -458,6 +488,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| +| `Contains()` |public bool Contains() where T : CoordSystem
| | `CoordOptionsAttribute()` |public CoordOptionsAttribute(Type coord)
| | `CoordOptionsAttribute()` |public CoordOptionsAttribute(Type coord, Type coord2)
| | `CoordOptionsAttribute()` |public CoordOptionsAttribute(Type coord, Type coord2, Type coord3)
| @@ -472,6 +503,7 @@ Inherits or Implemented: [MainComponentContext](#MainComponentContext) |public method|description| |--|--| | `UpdateDataZoomRuntimeStartEndValue()` |public static void UpdateDataZoomRuntimeStartEndValue(DataZoom dataZoom, Serie serie)
| +| `UpdateDataZoomRuntimeStartEndValue()` |public static void UpdateDataZoomRuntimeStartEndValue(BaseChart chart) where T : Serie
| ## `DateTimeUtil` @@ -615,6 +647,26 @@ Inherits or Implemented: [ListFor](#ListFor) ## `MainComponentHandler` +|public method|description| +|--|--| +| `CheckComponent()` |public virtual void CheckComponent(StringBuilder sb) { }
| +| `DrawBase()` |public virtual void DrawBase(VertexHelper vh) { }
| +| `DrawTop()` |public virtual void DrawTop(VertexHelper vh) { }
| +| `DrawUpper()` |public virtual void DrawUpper(VertexHelper vh) { }
| +| `InitComponent()` |public virtual void InitComponent() { }
| +| `OnBeginDrag()` |public virtual void OnBeginDrag(PointerEventData eventData) { }
| +| `OnDrag()` |public virtual void OnDrag(PointerEventData eventData) { }
| +| `OnEndDrag()` |public virtual void OnEndDrag(PointerEventData eventData) { }
| +| `OnPointerClick()` |public virtual void OnPointerClick(PointerEventData eventData) { }
| +| `OnPointerDown()` |public virtual void OnPointerDown(PointerEventData eventData) { }
| +| `OnPointerEnter()` |public virtual void OnPointerEnter(PointerEventData eventData) { }
| +| `OnPointerExit()` |public virtual void OnPointerExit(PointerEventData eventData) { }
| +| `OnPointerUp()` |public virtual void OnPointerUp(PointerEventData eventData) { }
| +| `OnScroll()` |public virtual void OnScroll(PointerEventData eventData) { }
| +| `OnSerieDataUpdate()` |public virtual void OnSerieDataUpdate(int serieIndex) { }
| +| `RemoveComponent()` |public virtual void RemoveComponent() { }
| +| `Update()` |public virtual void Update() { }
| + ## `MainComponentHandler` Inherits or Implemented: [MainComponentHandler](#MainComponentHandler) @@ -679,8 +731,10 @@ Inherits or Implemented: [BaseChart](#BaseChart) |public method|description| |--|--| +| `SetClass()` |public static bool SetClass(ref T currentValue, T newValue, bool notNull = false) where T : class
| | `SetColor()` |public static bool SetColor(ref Color currentValue, Color newValue)
| | `SetColor()` |public static bool SetColor(ref Color32 currentValue, Color32 newValue)
| +| `SetStruct()` |public static bool SetStruct(ref T currentValue, T newValue) where T : struct
| ## `RadarChart` @@ -722,6 +776,8 @@ Inherits or Implemented: [BaseChart](#BaseChart) | `GetAllAssemblyTypes()` |public static IEnumerable GetAllAssemblyTypes()
| | `GetAllTypesDerivedFrom()` |public static IEnumerable GetAllTypesDerivedFrom(Type type)
| | `GetAllTypesDerivedFrom()` |public static IEnumerable GetAllTypesDerivedFrom()
| +| `GetAttribute()` |public static T GetAttribute(this MemberInfo type, bool check = true) where T : Attribute
| +| `GetAttribute()` |public static T GetAttribute(this Type type, bool check = true) where T : Attribute
| | `HasSubclass()` |public static bool HasSubclass(Type type)
| ## `ScatterChart` @@ -737,6 +793,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| | `Contains()` |public bool Contains(Type type)
| +| `Contains()` |public bool Contains() where T : Serie
| | `SerieConvertAttribute()` |public SerieConvertAttribute(Type serie)
| | `SerieConvertAttribute()` |public SerieConvertAttribute(Type serie, Type serie2)
| | `SerieConvertAttribute()` |public SerieConvertAttribute(Type serie, Type serie2, Type serie3)
| @@ -755,6 +812,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| | `Contains()` |public bool Contains(Type type)
| +| `Contains()` |public bool Contains() where T : ISerieExtraComponent
| | `SerieDataExtraComponentAttribute()` |public SerieDataExtraComponentAttribute()
| | `SerieDataExtraComponentAttribute()` |public SerieDataExtraComponentAttribute(Type type1)
| | `SerieDataExtraComponentAttribute()` |public SerieDataExtraComponentAttribute(Type type1, Type type2)
| @@ -787,6 +845,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| | `Contains()` |public bool Contains(Type type)
| +| `Contains()` |public bool Contains() where T : ISerieExtraComponent
| | `SerieExtraComponentAttribute()` |public SerieExtraComponentAttribute()
| | `SerieExtraComponentAttribute()` |public SerieExtraComponentAttribute(Type type1)
| | `SerieExtraComponentAttribute()` |public SerieExtraComponentAttribute(Type type1, Type type2)
| @@ -798,6 +857,31 @@ Inherits or Implemented: [Attribute](#Attribute) ## `SerieHandler` +|public method|description| +|--|--| +| `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) { }
| +| `InitComponent()` |public virtual void InitComponent() { }
| +| `OnBeginDrag()` |public virtual void OnBeginDrag(PointerEventData eventData) { }
| +| `OnDrag()` |public virtual void OnDrag(PointerEventData eventData) { }
| +| `OnEndDrag()` |public virtual void OnEndDrag(PointerEventData eventData) { }
| +| `OnLegendButtonClick()` |public virtual void OnLegendButtonClick(int index, string legendName, bool show) { }
| +| `OnLegendButtonEnter()` |public virtual void OnLegendButtonEnter(int index, string legendName) { }
| +| `OnLegendButtonExit()` |public virtual void OnLegendButtonExit(int index, string legendName) { }
| +| `OnPointerClick()` |public virtual void OnPointerClick(PointerEventData eventData) { }
| +| `OnPointerDown()` |public virtual void OnPointerDown(PointerEventData eventData) { }
| +| `OnPointerEnter()` |public virtual void OnPointerEnter(PointerEventData eventData) { }
| +| `OnPointerExit()` |public virtual void OnPointerExit(PointerEventData eventData) { }
| +| `OnPointerUp()` |public virtual void OnPointerUp(PointerEventData eventData) { }
| +| `OnScroll()` |public virtual void OnScroll(PointerEventData eventData) { }
| +| `RefreshLabelInternal()` |public virtual void RefreshLabelInternal() { }
| +| `RefreshLabelNextFrame()` |public virtual void RefreshLabelNextFrame() { }
| +| `RemoveComponent()` |public virtual void RemoveComponent() { }
| +| `Update()` |public virtual void Update() { }
| + ## `SerieHandler` Inherits or Implemented: [SerieHandler where T](#SerieHandler where T),[Serie](#Serie) @@ -831,6 +915,7 @@ Inherits or Implemented: [Attribute](#Attribute) |public method|description| |--|--| +| `CloneSerie()` |public static T CloneSerie(Serie serie) where T : Serie
| | `CopySerie()` |public static void CopySerie(Serie oldSerie, Serie newSerie)
| | `GetAllMinMaxData()` |public static void GetAllMinMaxData(Serie serie, double ceilRate = 0, DataZoom dataZoom = null)
| | `GetAreaStyle()` |public static AreaStyle GetAreaStyle(Serie serie, SerieData serieData)
| @@ -900,7 +985,10 @@ Inherits or Implemented: [Attribute](#Attribute) | `GetStackSeries()` |public static void GetStackSeries(List series, ref Dictionary> stackSeries)
获得堆叠系列列表 | | `IsAnyClipSerie()` |public static bool IsAnyClipSerie(List series)
是否有需裁剪的serie。 | | `IsLegalLegendName()` |public static bool IsLegalLegendName(string name)
| +| `IsPercentStack()` |public static bool IsPercentStack(List series) where T : Serie
是否时百分比堆叠 | +| `IsPercentStack()` |public static bool IsPercentStack(List series, string stackName) where T : Serie
是否时百分比堆叠 | | `IsStack()` |public static bool IsStack(List series)
是否由数据堆叠 | +| `IsStack()` |public static bool IsStack(List series, string stackName) where T : Serie
是否堆叠 | | `UpdateSerieNameList()` |public static void UpdateSerieNameList(BaseChart chart, ref List serieNameList)
获得所有系列名,不包含空名字。 | | `UpdateStackDataList()` |public static void UpdateStackDataList(List series, Serie currSerie, DataZoom dataZoom, List> dataList)
| @@ -1038,7 +1126,7 @@ Inherits or Implemented: [MainComponentContext](#MainComponentContext) |public method|description| |--|--| | `AutoSetLineMinMax()` |public static void AutoSetLineMinMax(VisualMap visualMap, Serie serie, bool isY, Axis axis, Axis relativedAxis)
| -| `GetDimension()` |public static int GetDimension(VisualMap visualMap, int serieDataCount)
| +| `GetDimension()` |public static int GetDimension(VisualMap visualMap, int defaultDimension)
| | `IsNeedAreaGradient()` |public static bool IsNeedAreaGradient(VisualMap visualMap)
| | `IsNeedGradient()` |public static bool IsNeedGradient(VisualMap visualMap)
| | `IsNeedLineGradient()` |public static bool IsNeedLineGradient(VisualMap visualMap)
| diff --git a/Documentation/XChartsConfiguration-EN.md b/Documentation/XChartsConfiguration-EN.md index ed930332..d43693a8 100644 --- a/Documentation/XChartsConfiguration-EN.md +++ b/Documentation/XChartsConfiguration-EN.md @@ -357,6 +357,8 @@ Split line of axis in grid area. |`interval`|||Interval of Axis splitLine. |`distance`|||The distance between the split line and axis line. |`autoColor`|||auto color. +|`showStartLine`|true|v3.3.0|Whether to show the first split line. +|`showEndLine`|true|v3.3.0|Whether to show the last split line. ## `AxisTheme` @@ -628,6 +630,9 @@ Grid component. Inherits or Implemented: [Serie](#Serie),[INeedSerieContainer](#INeedSerieContainer) +|field|default|since|comment| +|--|--|--|--| +|`heatmapType`||3.3.0|The mapping type of heatmap.
`HeatmapType`:
- `Data`: Data mapping type.By default, the second dimension data is used as the color map.
- `Count`: Number mapping type.The number of occurrences of a statistic in a divided grid, as a color map.
| ## `IconStyle` @@ -781,7 +786,7 @@ Legend component.The legend component shows different sets of tags, colors, and |field|default|since|comment| |--|--|--|--| |`show`|true||Whether to show legend component. -|`iconType`|||Type of legend.
`Legend.Type`:
- `Auto`: 自动匹配。
- `Custom`: 自定义图标。
- `EmptyCircle`: 空心圆。
- `Circle`: 圆形。
- `Rect`: 正方形。可通过Setting的legendIconCornerRadius参数调整圆角。
- `Triangle`: 三角形。
- `Diamond`: 菱形。
| +|`iconType`|||Type of legend.
`Legend.Type`:
- `Auto`: 自动匹配。
- `Custom`: 自定义图标。
- `EmptyCircle`: 空心圆。
- `Circle`: 圆形。
- `Rect`: 正方形。可通过Setting的legendIconCornerRadius参数调整圆角。
- `Triangle`: 三角形。
- `Diamond`: 菱形。
- `Candlestick`: 烛台(可用于K线图)。
| |`selectedMode`|||Selected mode of legend, which controls whether series can be toggled displaying by clicking legends.
`Legend.SelectedMode`:
- `Multiple`: 多选。
- `Single`: 单选。
- `None`: 无法选择。
| |`orient`|||Specify whether the layout of legend component is horizontal or vertical.
`Orient`:
- `Horizonal`: 水平
- `Vertical`: 垂直
| |`location`|||The location of legend. [Location](#Location)| @@ -1004,7 +1009,7 @@ Polar coordinate can be used in scatter and line chart. Every polar coordinate h |--|--|--|--| |`show`|true||Whether to show the polor component. |`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`|0.35f||the radius of polar. +|`radius`|||the radius of polar. |`backgroundColor`|||Background color of polar, which is transparent by default. ## `Radar` @@ -1169,6 +1174,8 @@ Inherits or Implemented: [SymbolStyle](#SymbolStyle),[ISerieDataComponent](#ISer |`interval`|||the interval of show symbol. |`forceShowLast`|false||whether to show the last symbol. |`repeat`|false||图形是否重复。 +|`minSize`|0f|v3.3.0|Minimum symbol size. +|`maxSize`|0f|v3.3.0|Maximum symbol size. ## `SerieTheme` @@ -1422,6 +1429,7 @@ Tooltip component. |`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.
| +|`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. |`marker`|||the marker of serie. @@ -1441,10 +1449,8 @@ Tooltip component. |`backgroundType`|||The background type of tooltip. |`backgroundColor`|||The background color of tooltip. |`borderWidth`|2f||the width of tooltip border. -|`fixedXEnable`|false||enable fixedX. |`fixedX`|0f||the x positionn of fixedX. -|`fixedYEnable`|false||enable fixedY. -|`fixedY`|0f||the y position of fixedY. +|`fixedY`|0.7f||the y position of fixedY. |`titleHeight`|25f||height of title text. |`itemHeight`|25f||height of content text. |`borderColor`|Color32(230, 230, 230, 255)||the color of tooltip border. @@ -1480,7 +1486,7 @@ VisualMap component. Mapping data to visual elements such as colors. |`selectedMode`|||the selected mode for Piecewise visualMap.
`VisualMap.SelectedMode`:
- `Multiple`: 多选。
- `Single`: 单选。
| |`serieIndex`|0||the serie index of visualMap. |`min`|0||范围最小值 -|`max`|100||范围最大值 +|`max`|0||范围最大值 |`range`|||Specifies the position of the numeric value corresponding to the handle. Range should be within the range of [min,max]. |`text`|||Text on both ends. |`textGap`|||The distance between the two text bodies. diff --git a/Documentation/XChartsConfiguration-ZH.md b/Documentation/XChartsConfiguration-ZH.md index fbeed47d..af9a78cd 100644 --- a/Documentation/XChartsConfiguration-ZH.md +++ b/Documentation/XChartsConfiguration-ZH.md @@ -357,6 +357,8 @@ Inherits or Implemented: [BaseLine](#BaseLine) |`interval`|||坐标轴分隔线的显示间隔。 |`distance`|||刻度线与轴线的距离。 |`autoColor`|||自动设置颜色。 +|`showStartLine`|true|v3.3.0|是否显示第一条分割线。 +|`showEndLine`|true|v3.3.0|是否显示最后一条分割线。 ## `AxisTheme` @@ -628,6 +630,9 @@ Drawing grid in rectangular coordinate. Line chart, bar chart, and scatter chart Inherits or Implemented: [Serie](#Serie),[INeedSerieContainer](#INeedSerieContainer) +|field|default|since|comment| +|--|--|--|--| +|`heatmapType`||3.3.0|热力图类型。通过颜色映射划分。
`HeatmapType`:
- `Data`: 数据映射型。默认用第2维数据作为颜色映射。要求数据至少有3个维度数据。
- `Count`: 个数映射型。统计数据在划分的格子中出现的次数,作为颜色映射。要求数据至少有2个维度数据。
| ## `IconStyle` @@ -781,7 +786,7 @@ Inherits or Implemented: [MainComponent](#MainComponent),[IPropertyChanged](#IPr |field|default|since|comment| |--|--|--|--| |`show`|true||是否显示图例组件。 -|`iconType`|||图例类型。
`Legend.Type`:
- `Auto`: 自动匹配。
- `Custom`: 自定义图标。
- `EmptyCircle`: 空心圆。
- `Circle`: 圆形。
- `Rect`: 正方形。可通过Setting的legendIconCornerRadius参数调整圆角。
- `Triangle`: 三角形。
- `Diamond`: 菱形。
| +|`iconType`|||图例类型。
`Legend.Type`:
- `Auto`: 自动匹配。
- `Custom`: 自定义图标。
- `EmptyCircle`: 空心圆。
- `Circle`: 圆形。
- `Rect`: 正方形。可通过Setting的legendIconCornerRadius参数调整圆角。
- `Triangle`: 三角形。
- `Diamond`: 菱形。
- `Candlestick`: 烛台(可用于K线图)。
| |`selectedMode`|||选择模式。控制是否可以通过点击图例改变系列的显示状态。默认开启图例选择,可以设成 None 关闭。
`Legend.SelectedMode`:
- `Multiple`: 多选。
- `Single`: 单选。
- `None`: 无法选择。
| |`orient`|||布局方式是横还是竖。
`Orient`:
- `Horizonal`: 水平
- `Vertical`: 垂直
| |`location`|||图例显示的位置。 [Location](#Location)| @@ -1004,7 +1009,7 @@ Inherits or Implemented: [CoordSystem](#CoordSystem),[ISerieContainer](#ISerieCo |--|--|--|--| |`show`|true||是否显示极坐标。 |`center`|||极坐标的中心点。数组的第一项是横坐标,第二项是纵坐标。 当值为0-1之间时表示百分比,设置成百分比时第一项是相对于容器宽度,第二项是相对于容器高度。 -|`radius`|0.35f||极坐标的半径。 +|`radius`|||半径。radius[0]表示内径,radius[1]表示外径。 |`backgroundColor`|||极坐标的背景色,默认透明。 ## `Radar` @@ -1169,6 +1174,8 @@ Inherits or Implemented: [SymbolStyle](#SymbolStyle),[ISerieDataComponent](#ISer |`interval`|||显示图形标记的间隔。0表示显示所有标签,1表示隔一个隔显示一个标签,以此类推。 |`forceShowLast`|false||是否强制显示最后一个图形标记。 |`repeat`|false||图形是否重复。 +|`minSize`|0f|v3.3.0|图形最小尺寸。只在sizeType为SymbolSizeType.FromData时有效。 +|`maxSize`|0f|v3.3.0|图形最大尺寸。只在sizeType为SymbolSizeType.FromData时有效。 ## `SerieTheme` @@ -1422,6 +1429,7 @@ Inherits or Implemented: [MainComponent](#MainComponent) |`show`|true||是否显示提示框组件。 |`type`|||提示框指示器类型。
`Tooltip.Type`:
- `Line`: 直线指示器
- `Shadow`: 阴影指示器
- `None`: 无指示器
- `Corss`: 十字准星指示器。坐标轴显示Label和交叉线。
| |`trigger`|||触发类型。
`Tooltip.Trigger`:
- `Item`: 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
- `Axis`: 坐标轴触发,主要在柱状图,折线图等会使用类目轴的图表中使用。
- `None`: 什么都不触发。
| +|`position`||v3.3.0|显示位置类型。
`Tooltip.Position`:
- `Auto`: 自适应。移动平台靠顶部显示,非移动平台跟随鼠标位置。
- `Custom`: 自定义。完全自定义显示位置(x,y)。
- `FixedX`: 只固定坐标X。Y跟随鼠标位置。
- `FixedY`:
| |`itemFormatter`|||提示框单个serie或数据项内容的字符串模版格式器。支持用 \n 换行。用 |`titleFormatter`|||提示框标题内容的字符串模版格式器。支持用 \n 换行。可以单独设置占位符{i}表示忽略不显示title。 模板变量有{.}、{a}、{b}、{c}、{d}、{e}、{f}、{g}。
{.}为当前所指示或index为0的serie的对应颜色的圆点。
{a}为当前所指示或index为0的serie的系列名name。
{b}为当前所指示或index为0的serie的数据项serieData的name,或者类目值(如折线图的X轴)。
{c}为当前所指示或index为0的serie的y维(dimesion为1)的数值。
{d}为当前所指示或index为0的serie的y维(dimesion为1)百分比值,注意不带%号。
{e}为当前所指示或index为0的serie的数据项serieData的name。
{f}为数据总和。
{g}为数据总个数。
{.1}表示指定index为1的serie对应颜色的圆点。
{a1}、{b1}、{c1}中的1表示指定index为1的serie。
{c1:2}表示索引为1的serie的当前指示数据项的第3个数据(一个数据项有多个数据,index为2表示第3个数据)。
{c1:2-2}表示索引为1的serie的第3个数据项的第3个数据(也就是要指定第几个数据项时必须要指定第几个数据)。
{d1:2:f2}表示单独指定了数值的格式化字符串为f2(不指定时用numericFormatter)。
{d:0.##} 表示单独指定了数值的格式化字符串为 0.## (用于百分比,保留2位有效数同时又能避免使用 f2 而出现的类似于"100.00%"的情况 )。
示例:"{a}:{c}"、"{a1}:{c1:f1}"、"{a1}:{c1:0:f1}"、"{a1}:{c1:1-1:f1}" |`marker`|||serie的符号标志。 @@ -1441,10 +1449,8 @@ Inherits or Implemented: [MainComponent](#MainComponent) |`backgroundType`|||提示框的背景图片显示类型。 |`backgroundColor`|||提示框的背景颜色。 |`borderWidth`|2f||边框线宽。 -|`fixedXEnable`|false||是否固定X位置。 |`fixedX`|0f||固定X位置的坐标。 -|`fixedYEnable`|false||是否固定Y位置。 -|`fixedY`|0f||固定Y位置的坐标。 +|`fixedY`|0.7f||固定Y位置的坐标。 |`titleHeight`|25f||标题文本的高。 |`itemHeight`|25f||数据项文本的高。 |`borderColor`|Color32(230, 230, 230, 255)||边框颜色。 @@ -1480,7 +1486,7 @@ Inherits or Implemented: [MainComponent](#MainComponent) |`selectedMode`|||选择模式。
`VisualMap.SelectedMode`:
- `Multiple`: 多选。
- `Single`: 单选。
| |`serieIndex`|0||影响的serie索引。 |`min`|0||范围最小值 -|`max`|100||范围最大值 +|`max`|0||范围最大值 |`range`|||指定手柄对应数值的位置。range 应在[min,max]范围内。 |`text`|||两端的文本,如 ['High', 'Low']。 |`textGap`|||两端文字主体之间的距离,单位为px。 diff --git a/Documentation/XChartsTutorial01-EN.md b/Documentation/XChartsTutorial01-EN.md index 216e3e89..e4013745 100644 --- a/Documentation/XChartsTutorial01-EN.md +++ b/Documentation/XChartsTutorial01-EN.md @@ -11,7 +11,7 @@ XCharts可通过以下任意一种方式导入到项目: - 直接将XCharts源码到项目 - 下载好XCharts源码后,直接将XCharts目录拷贝到Unity项目工程的Assets目录下。 + 下载好XCharts源码后,直接将XCharts目录拷贝到Unity项目工程的Assets目录或Packages目录下,编译通过后即可使用。 - 通过`Assets/Import Package`导入XCharts @@ -50,7 +50,7 @@ XCharts可通过以下任意一种方式导入到项目: ## 添加Serie组件 -Serie只自带了几个常见的组件,其他组件按需额外添加。比如,需要给折线图区域填充颜色,可单独给`Serie`添加`AreaStyle`组件: +Serie只自带了几个常见的组件,其他组件要根据需求额外添加,不同的Serie支持不同的额外组件。比如,需要给折线图区域填充颜色,可单独给`Serie`添加`AreaStyle`组件: ![op_addseriecomponent](res/op_addseriecomponent.png) ![linechart3](res/linechart3.png) @@ -80,7 +80,7 @@ Serie只自带了几个常见的组件,其他组件按需额外添加。比如 2. 如果`Serie`的`ItemStyle`配置有非`0000`颜色值,则优先用这个颜色值。 3. 否则颜色值取自主题`Theme`的`Color Palette`。 -通常颜色值为0000时表示用主题默认颜色,配置为0或null时表示用主题默认配置。 +通常配置的颜色值为0000时表示用主题默认颜色;配置参数的值为0或null时表示用主题默认配置。 ## 用代码添加折线图 @@ -94,6 +94,7 @@ if (chart == null) chart.Init(); } ``` +用代码生成的Chart需要调用一次Init()。 调整大小: @@ -170,7 +171,7 @@ for (int i = 0; i < 10; i++) XCharts内部有自动刷新机制,但也是在一定条件下。如果自己调用了内部组件的接口,碰到组件没有刷新,确实找不到原因的话,可以用以下两个接口强制刷新: -1. `chart.RefreshAllComponent()`:刷新图表组件,会重新初始化所有组件,不建议频繁待用。 +1. `chart.RefreshAllComponent()`:刷新图表组件,会重新初始化所有组件,不建议频繁使用。 2. `chart.RefreshChart()`:刷新图表绘制,只刷新绘制部分,不会刷新组件文本,位置等部分。 ## 使用TextMeshPro diff --git a/Editor/Charts/BaseChartEditor.cs b/Editor/Charts/BaseChartEditor.cs index 617d12ef..fc9f39d7 100644 --- a/Editor/Charts/BaseChartEditor.cs +++ b/Editor/Charts/BaseChartEditor.cs @@ -16,6 +16,7 @@ namespace XCharts.Editor public static readonly GUIContent btnAddComponent = new GUIContent("Add Main Component", ""); public static readonly GUIContent btnCovertXYAxis = new GUIContent("Covert XY Axis", ""); public static readonly GUIContent btnRebuildChartObject = new GUIContent("Rebuild Chart Object", ""); + public static readonly GUIContent btnSaveAsImage = new GUIContent("Save As Image", ""); public static readonly GUIContent btnCheckWarning = new GUIContent("Check Warning", ""); public static readonly GUIContent btnHideWarning = new GUIContent("Hide Warning", ""); } @@ -279,6 +280,10 @@ namespace XCharts.Editor { m_Chart.RebuildChartObject(); } + if (GUILayout.Button(Styles.btnSaveAsImage)) + { + m_Chart.SaveAsImage(); + } if (m_CheckWarning) { EditorGUILayout.BeginHorizontal(); diff --git a/Editor/ChildComponents/LineDrawer.cs b/Editor/ChildComponents/LineDrawer.cs index 002d520c..f3519bb1 100644 --- a/Editor/ChildComponents/LineDrawer.cs +++ b/Editor/ChildComponents/LineDrawer.cs @@ -44,6 +44,8 @@ namespace XCharts.Editor PropertyField(prop, "m_Interval"); PropertyField(prop, "m_Distance"); PropertyField(prop, "m_AutoColor"); + PropertyField(prop, "m_ShowStartLine"); + PropertyField(prop, "m_ShowEndLine"); } } diff --git a/Editor/ChildComponents/SerieSymbolDrawer.cs b/Editor/ChildComponents/SerieSymbolDrawer.cs index 23639c5b..31a132e4 100644 --- a/Editor/ChildComponents/SerieSymbolDrawer.cs +++ b/Editor/ChildComponents/SerieSymbolDrawer.cs @@ -35,6 +35,8 @@ namespace XCharts.Editor case SymbolSizeType.FromData: PropertyField(prop, "m_DataIndex"); PropertyField(prop, "m_DataScale"); + PropertyField(prop, "m_MinSize"); + PropertyField(prop, "m_MaxSize"); break; case SymbolSizeType.Function: break; diff --git a/Editor/ChildComponents/SymbolStyleDrawer.cs b/Editor/ChildComponents/SymbolStyleDrawer.cs index d30ac905..1ae59e29 100644 --- a/Editor/ChildComponents/SymbolStyleDrawer.cs +++ b/Editor/ChildComponents/SymbolStyleDrawer.cs @@ -23,11 +23,11 @@ namespace XCharts.Editor PropertyField(prop, "m_ImageType"); PropertyField(prop, "m_Width"); PropertyField(prop, "m_Height"); - // PropertyField(prop, "m_Offset"); } PropertyField(prop, "m_Color"); PropertyField(prop, "m_Size"); PropertyField(prop, "m_Gap"); + PropertyField(prop, "m_Offset"); --EditorGUI.indentLevel; } } diff --git a/Editor/MainComponents/PolarCoordEditor.cs b/Editor/MainComponents/PolarCoordEditor.cs index 8d359e74..28d867a6 100644 --- a/Editor/MainComponents/PolarCoordEditor.cs +++ b/Editor/MainComponents/PolarCoordEditor.cs @@ -10,7 +10,7 @@ namespace XCharts.Editor { ++EditorGUI.indentLevel; PropertyTwoFiled("m_Center"); - PropertyField("m_Radius"); + PropertyTwoFiled("m_Radius"); PropertyField("m_BackgroundColor"); --EditorGUI.indentLevel; } diff --git a/Editor/MainComponents/TooltipEditor.cs b/Editor/MainComponents/TooltipEditor.cs index af7b4344..c657d8fe 100644 --- a/Editor/MainComponents/TooltipEditor.cs +++ b/Editor/MainComponents/TooltipEditor.cs @@ -11,6 +11,10 @@ namespace XCharts.Editor ++EditorGUI.indentLevel; PropertyField("m_Type"); PropertyField("m_Trigger"); + PropertyField("m_Position"); + PropertyField("m_FixedX"); + PropertyField("m_FixedY"); + PropertyField("m_Offset"); PropertyField("m_ShowContent"); PropertyField("m_AlwayShowContent"); PropertyField("m_TitleFormatter"); @@ -33,11 +37,6 @@ namespace XCharts.Editor PropertyField("m_MinWidth"); PropertyField("m_MinHeight"); PropertyField("m_IgnoreDataDefaultContent"); - PropertyField("m_Offset"); - PropertyField("m_FixedXEnable"); - PropertyField("m_FixedX"); - PropertyField("m_FixedYEnable"); - PropertyField("m_FixedY"); }); PropertyField("m_LineStyle"); PropertyField("m_IndicatorLabelStyle"); diff --git a/Editor/Series/BarEditor.cs b/Editor/Series/BarEditor.cs index beb6ecea..1a078531 100644 --- a/Editor/Series/BarEditor.cs +++ b/Editor/Series/BarEditor.cs @@ -19,13 +19,20 @@ namespace XCharts.Editor PropertyField("m_YAxisIndex"); } PropertyField("m_BarType"); - PropertyField("m_BarPercentStack"); PropertyField("m_BarWidth"); PropertyField("m_BarGap"); - if (serie.barType == BarType.Zebra) + if (serie.IsUseCoord()) { - PropertyField("m_BarZebraWidth"); - PropertyField("m_BarZebraGap"); + PropertyField("m_RoundCap"); + } + else + { + PropertyField("m_BarPercentStack"); + if (serie.barType == BarType.Zebra) + { + PropertyField("m_BarZebraWidth"); + PropertyField("m_BarZebraGap"); + } } PropertyField("m_Clip"); PropertyFiledMore(() => diff --git a/Editor/Series/CandlestickEditor.cs b/Editor/Series/CandlestickEditor.cs index ff77a8db..06fff6ff 100644 --- a/Editor/Series/CandlestickEditor.cs +++ b/Editor/Series/CandlestickEditor.cs @@ -7,6 +7,7 @@ namespace XCharts.Editor { public override void OnCustomInspectorGUI() { + PropertyField("m_ColorBy"); PropertyField("m_XAxisIndex"); PropertyField("m_YAxisIndex"); PropertyFieldLimitMin("m_MinShow", 0); diff --git a/Editor/Series/HeatmapEditor.cs b/Editor/Series/HeatmapEditor.cs index 739952ba..c4eaa9cb 100644 --- a/Editor/Series/HeatmapEditor.cs +++ b/Editor/Series/HeatmapEditor.cs @@ -7,9 +7,20 @@ namespace XCharts.Editor { public override void OnCustomInspectorGUI() { + if (serie.IsUseCoord()) + { + PropertyField("m_PolarIndex"); + } + else + { + PropertyField("m_XAxisIndex"); + PropertyField("m_YAxisIndex"); + } + PropertyField("m_HeatmapType"); PropertyField("m_Ignore"); PropertyField("m_IgnoreValue"); + PropertyField("m_Symbol"); PropertyField("m_ItemStyle"); PropertyField("m_Animation"); } diff --git a/Editor/Series/ParallelEditor.cs b/Editor/Series/ParallelEditor.cs index c0d7b2c5..c29aff68 100644 --- a/Editor/Series/ParallelEditor.cs +++ b/Editor/Series/ParallelEditor.cs @@ -7,6 +7,7 @@ namespace XCharts.Editor { public override void OnCustomInspectorGUI() { + PropertyField("m_ColorBy"); PropertyField("m_ParallelIndex"); PropertyField("m_LineType"); PropertyField("m_LineStyle"); diff --git a/Examples/Example90_Candlestick.cs b/Examples/Example90_Candlestick.cs index 895e305d..7218b6b9 100644 --- a/Examples/Example90_Candlestick.cs +++ b/Examples/Example90_Candlestick.cs @@ -61,7 +61,7 @@ namespace XCharts.Example var heighest = boxVals[3]; chart.AddXAxisData(i.ToString()); - chart.AddData(0, open, close, lowest, heighest); + chart.AddData(0, i, open, close, lowest, heighest); } } } diff --git a/Examples/Example_Test.cs b/Examples/Example_Test.cs index f105bc79..e51b0ac9 100644 --- a/Examples/Example_Test.cs +++ b/Examples/Example_Test.cs @@ -51,15 +51,9 @@ namespace XCharts.Example void AddData() { - chart.ClearData(); - int count = Random.Range(5, 100); - for (int i = 0; i < count; i++) - { - chart.AddXAxisData("x" + i); - if (Random.Range(1, 3) == 2) - chart.AddData(0, Random.Range(-110, 200)); - else - chart.AddData(0, Random.Range(-100, 100)); + var serie = chart.InsertSerie(0); + for(int i=0;i<5;i++){ + chart.AddData(serie.index, Random.Range(10,90)); } } } diff --git a/Plugins.meta b/Plugins.meta new file mode 100644 index 00000000..a60003bb --- /dev/null +++ b/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6558d1464a47441d18df18c4a403b2f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/Download.jslib b/Plugins/Download.jslib new file mode 100644 index 00000000..cc5b8886 --- /dev/null +++ b/Plugins/Download.jslib @@ -0,0 +1,24 @@ +mergeInto(LibraryManager.library, { + Download: function (str, fn) { + var msg = UTF8ToString(str); + var fname = UTF8ToString(fn); + function fixBinary(bin) { + var length = bin.length; + var buf = new ArrayBuffer(length); + var arr = new Uint8Array(buf); + for (var i = 0; i < length; i++) { + arr[i] = bin.charCodeAt(i); + } + return buf; + } + var binary = fixBinary(atob(msg)); + var data = new Blob([binary]); + var link = document.createElement('a'); + link.download = fname; + link.href = URL.createObjectURL(data); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +}); + diff --git a/Plugins/Download.jslib.meta b/Plugins/Download.jslib.meta new file mode 100644 index 00000000..c2c8647a --- /dev/null +++ b/Plugins/Download.jslib.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 821b9cd60f13648a396c76481da2191c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + isOverridable: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Facebook: WebGL + second: + enabled: 1 + settings: {} + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index 22371843..747b61ed 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ 更多教程请看:[XCharts教程:5分钟上手教程](Documentation/XChartsTutorial01-ZH.md) -首次使用,建议认真看一遍教程。 +首次使用,建议先认真看一遍教程。 ## FAQ @@ -125,11 +125,15 @@ 答:`XCharts`使用`MIT`协议,可以免费使用。也可以订阅`VIP`享受更多增值服务。 2. `XCharts`支持代码动态添加和修改数据吗?支持从`Excel`或数据库中获取数据吗? - 答:支持代码动态添加和修改数据,但数据需要自己解析或获取,再调用`XCharts`的接口添加到`XCharts`。 + 答:`XCharts`提供了各种数据操作的接口,支持代码动态添加和修改数据,但数据需要自己解析或获取,再调用`XCharts`的接口添加到`XCharts`。 3. 这个插件除了用在`Unity`,还能用在其他平台(如`Winform`或`WPF`)吗? 答:目前只支持在`Unity`平台使用。理论上任何支持`UGUI`的`Unity`版本都能运行`XCharts`。 +4. 锯齿怎么解决?支持多大量级的数据? + 答:`XCharts`是基于`UGUI`实现的,所以`UGUI`中碰到的问题,在`XCharts`中也会存在。比如锯齿问题,比如`Mesh`顶点数超`65535`的问题。这两个问题的解决可参考`问答16`和`问答27`。 + 由于`Mesh`的`65535`顶点数的限制,目前`XCharts`的单条`Line`大概支持`2万`左右的数据量,当然开采样可以支持更多数据,但可能会更消耗CPU。 + ## Licenses [MIT License](LICENSE.md) diff --git a/Runtime/Chart/HeatmapChart.cs b/Runtime/Chart/HeatmapChart.cs index 421ae09e..f1df5f11 100644 --- a/Runtime/Chart/HeatmapChart.cs +++ b/Runtime/Chart/HeatmapChart.cs @@ -36,9 +36,7 @@ namespace XCharts.Runtime Heatmap.AddDefaultSerie(this, GenerateDefaultSerieName()); var visualMap = GetOrAddChartComponent(); - visualMap.max = 10; - visualMap.range[0] = 0f; - visualMap.range[1] = 10f; + visualMap.autoMinMax = true; visualMap.orient = Orient.Vertical; visualMap.calculable = true; visualMap.location.align = Location.Align.BottomLeft; @@ -71,10 +69,7 @@ namespace XCharts.Runtime { for (int j = 0; j < ySplitNumber; j++) { - var value = 0f; - var rate = Random.Range(0, 101); - if (rate > 70) value = Random.Range(8f, 10f); - else value = Random.Range(1f, 8f); + var value = Random.Range(0, 150); var list = new List { i, j, value }; AddData(0, list); } diff --git a/Runtime/Component/Axis/AngleAxis/AngleAxis.cs b/Runtime/Component/Axis/AngleAxis/AngleAxis.cs index 46909d73..51436a3c 100644 --- a/Runtime/Component/Axis/AngleAxis/AngleAxis.cs +++ b/Runtime/Component/Axis/AngleAxis/AngleAxis.cs @@ -29,6 +29,11 @@ namespace XCharts.Runtime return (value + context.startAngle + 360) % 360; } + public float GetValueAngle(double value) + { + return (float) (value + context.startAngle + 360) % 360; + } + public override void SetDefaultValue() { m_Show = true; diff --git a/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs b/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs index b57b5a4d..5ac345e7 100644 --- a/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs +++ b/Runtime/Component/Axis/AngleAxis/AngleAxisHandler.cs @@ -29,7 +29,7 @@ namespace XCharts.Runtime if (axis.IsCategory() || !axis.show) return; double tempMinValue = 0; double tempMaxValue = 0; - SeriesHelper.GetYMinMaxValue(chart.series, null, axis.polarIndex, true, axis.inverse, out tempMinValue, + SeriesHelper.GetYMinMaxValue(chart, axis.polarIndex, true, axis.inverse, out tempMinValue, out tempMaxValue, true); AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true); if (tempMinValue != axis.context.minValue || tempMaxValue != axis.context.maxValue) @@ -61,7 +61,7 @@ namespace XCharts.Runtime var polar = chart.GetChartComponent(axis.polarIndex); if (polar == null) return; PolarHelper.UpdatePolarCenter(polar, chart.chartPosition, chart.chartWidth, chart.chartHeight); - var radius = polar.context.radius; + var radius = polar.context.outsideRadius; axis.context.labelObjectList.Clear(); axis.context.startAngle = 90 - axis.startAngle; @@ -103,7 +103,7 @@ namespace XCharts.Runtime private void DrawAngleAxis(VertexHelper vh, AngleAxis angleAxis) { var polar = chart.GetChartComponent(angleAxis.polarIndex); - var radius = polar.context.radius; + var radius = polar.context.outsideRadius; var cenPos = polar.context.center; var total = 360; var size = AxisHelper.GetScaleNumber(angleAxis, total, null); @@ -116,11 +116,15 @@ namespace XCharts.Runtime for (int i = 1; i < size; i++) { var scaleWidth = AxisHelper.GetScaleWidth(angleAxis, total, i); - var pos = ChartHelper.GetPos(cenPos, radius, currAngle, true); + var pos1 = ChartHelper.GetPos(cenPos, polar.context.insideRadius, currAngle, true); + var pos2 = ChartHelper.GetPos(cenPos, polar.context.outsideRadius, currAngle, true); if (angleAxis.show && angleAxis.splitLine.show) { - var lineWidth = angleAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth); - UGL.DrawLine(vh, cenPos, pos, lineWidth, splitLineColor); + if (angleAxis.splitLine.NeedShow(i - 1, size - 1)) + { + var lineWidth = angleAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth); + UGL.DrawLine(vh, pos1, pos2, lineWidth, splitLineColor); + } } if (angleAxis.show && angleAxis.axisTick.show) { @@ -130,7 +134,7 @@ namespace XCharts.Runtime { var tickY = radius + tickLength; var tickPos = ChartHelper.GetPos(cenPos, tickY, currAngle, true); - UGL.DrawLine(vh, pos, tickPos, tickWidth, tickColor); + UGL.DrawLine(vh, pos2, tickPos, tickWidth, tickColor); } } currAngle += scaleWidth; @@ -139,7 +143,13 @@ namespace XCharts.Runtime { var lineWidth = angleAxis.axisLine.GetWidth(chart.theme.axis.lineWidth); var outsideRaidus = radius + lineWidth * 2; - UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, lineColor, Color.clear); + UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, lineColor, ColorUtil.clearColor32); + if (polar.context.insideRadius > 0) + { + radius = polar.context.insideRadius; + outsideRaidus = radius + lineWidth * 2; + UGL.DrawDoughnut(vh, cenPos, radius, outsideRaidus, lineColor, ColorUtil.clearColor32); + } } } @@ -158,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.radius + 25); + axis.context.pointerLabelPosition = polar.context.center + new Vector3(dir.x, dir.y) * (polar.context.outsideRadius + 25); } } } \ No newline at end of file diff --git a/Runtime/Component/Axis/Axis.cs b/Runtime/Component/Axis/Axis.cs index 46bbb8e5..1a988b1f 100644 --- a/Runtime/Component/Axis/Axis.cs +++ b/Runtime/Component/Axis/Axis.cs @@ -719,6 +719,8 @@ namespace XCharts.Runtime } } + + /// /// 获得指定区域缩放的类目数据列表 /// diff --git a/Runtime/Component/Axis/AxisContext.cs b/Runtime/Component/Axis/AxisContext.cs index 5a50c1e4..fcc5a768 100644 --- a/Runtime/Component/Axis/AxisContext.cs +++ b/Runtime/Component/Axis/AxisContext.cs @@ -92,13 +92,13 @@ namespace XCharts.Runtime if (dataZoom.context.invert) { - end = Mathf.CeilToInt(data.Count * dataZoom.end / 100); + end = Mathf.RoundToInt(data.Count * dataZoom.end / 100); start = end - range; if (start < 0) start = 0; } else { - start = Mathf.FloorToInt(data.Count * dataZoom.start / 100); + start = Mathf.RoundToInt(data.Count * dataZoom.start / 100); end = start + range; if (end > data.Count) end = data.Count; } @@ -122,8 +122,8 @@ namespace XCharts.Runtime else range = dataZoom.minShowNum; } - if (range > data.Count - start - 1) - start = data.Count - range - 1; + if (range > data.Count - start) + start = data.Count - range; if (start >= 0) { dataZoomStartIndex = start; diff --git a/Runtime/Component/Axis/AxisHandler.cs b/Runtime/Component/Axis/AxisHandler.cs index 0a86e596..22863c28 100644 --- a/Runtime/Component/Axis/AxisHandler.cs +++ b/Runtime/Component/Axis/AxisHandler.cs @@ -368,10 +368,6 @@ namespace XCharts ((inside && axis.IsLeft()) || (!inside && axis.IsRight()) ? TextAnchor.MiddleLeft : TextAnchor.MiddleRight); - - if (axis.IsCategory() && axis.boundaryGap) - splitNumber -= 1; - for (int i = 0; i < splitNumber; i++) { var labelWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom); @@ -817,11 +813,11 @@ namespace XCharts } if (axis.splitLine.show) { - if (axis.splitLine.NeedShow(i)) + if (axis.splitLine.NeedShow(i, size)) { if (orient == Orient.Horizonal) { - if (relativedAxis == null || !MathUtil.Approximately(current, relativedAxis.context.x)) + if (relativedAxis == null || !relativedAxis.axisLine.show || !MathUtil.Approximately(current, relativedAxis.context.x)) { ChartDrawer.DrawLineStyle(vh, lineType, @@ -885,7 +881,7 @@ namespace XCharts } else { - if (relativedAxis == null || !MathUtil.Approximately(current, relativedAxis.context.y)) + if (relativedAxis == null || !relativedAxis.axisLine.show || !MathUtil.Approximately(current, relativedAxis.context.y)) { ChartDrawer.DrawLineStyle(vh, lineType, diff --git a/Runtime/Component/Axis/AxisHelper.cs b/Runtime/Component/Axis/AxisHelper.cs index e24be302..7171e826 100644 --- a/Runtime/Component/Axis/AxisHelper.cs +++ b/Runtime/Component/Axis/AxisHelper.cs @@ -19,6 +19,22 @@ namespace XCharts.Runtime return 0; } + /// + /// 获得分割网格个数,包含次刻度 + /// + /// + /// + public static int GetTotalSplitGridNum(Axis axis) + { + if (axis.IsCategory()) + return axis.data.Count; + else + { + var splitNum = axis.splitNumber <= 0 ? GetSplitNumber(axis, 0, null) : axis.splitNumber; + return splitNum * axis.minorTick.splitNumber; + } + } + /// /// 获得分割段数 /// @@ -48,15 +64,10 @@ namespace XCharts.Runtime if (axis.splitNumber <= 0) { - if (dataCount <= 10) return dataCount; - else - { - for (int i = 4; i < 6; i++) - { - if (dataCount % i == 0) return i; - } - return 5; - } + var eachWid = coordinateWid / dataCount; + if (eachWid > 80) return dataCount; + var tick = Mathf.CeilToInt(80 / eachWid); + return (int) (dataCount / tick); } else { @@ -180,7 +191,8 @@ namespace XCharts.Runtime } else { - if (axis.boundaryGap && coordinateWidth / dataCount > 5) + var diff = newIndex - dataCount; + if (axis.boundaryGap && ((diff > 0 && diff / rate < 0.4f) || dataCount >= axis.data.Count)) return string.Empty; else return axis.axisLabel.GetFormatterContent(dataCount - 1, showData[dataCount - 1]); @@ -212,10 +224,7 @@ namespace XCharts.Runtime } else { - if (dataCount < splitNum) scaleNum = splitNum; - else scaleNum = dataCount > 2 && dataCount % splitNum == 0 ? - splitNum : - splitNum + 1; + scaleNum = splitNum + 1; } return scaleNum; } @@ -519,6 +528,34 @@ namespace XCharts.Runtime return GetAxisPositionInternal(grid, axis, scaleWidth, value, false, true); } + /// + /// 获得数值value在坐标轴上对应的split索引 + /// + /// + /// + /// + public static int GetAxisValueSplitIndex(Axis axis, double value, int totalSplitNumber = -1) + { + if (axis.IsCategory()) + { + return (int) value; + } + else + { + if (value == axis.context.minValue) + return 0; + else + { + if (totalSplitNumber == -1) + totalSplitNumber = GetTotalSplitGridNum(axis); + if (axis.minMaxType == Axis.AxisMinMaxType.Custom) + return Mathf.CeilToInt(((float) ((value - axis.min) / axis.max) * totalSplitNumber) - 1); + else + return Mathf.CeilToInt(((float) ((value - axis.context.minValue) / axis.context.minMaxRange) * totalSplitNumber) - 1); + } + } + } + private static float GetAxisPositionInternal(GridCoord grid, Axis axis, float scaleWidth, double value, bool includeGridXY, bool realLength) { var isY = axis is YAxis; @@ -589,9 +626,5 @@ namespace XCharts.Runtime startX += relativedAxis.context.offset; return startX; } - - public static void UpdateAxisOffset(){ - - } } } \ No newline at end of file diff --git a/Runtime/Component/Axis/AxisSplitLine.cs b/Runtime/Component/Axis/AxisSplitLine.cs index 8e345272..a9785e3c 100644 --- a/Runtime/Component/Axis/AxisSplitLine.cs +++ b/Runtime/Component/Axis/AxisSplitLine.cs @@ -13,6 +13,8 @@ namespace XCharts.Runtime [SerializeField] private int m_Interval; [SerializeField] private float m_Distance; [SerializeField] private bool m_AutoColor; + [SerializeField][Since("v3.3.0")] private bool m_ShowStartLine = true; + [SerializeField][Since("v3.3.0")] private bool m_ShowEndLine = true; /// /// The distance between the split line and axis line. @@ -33,6 +35,24 @@ namespace XCharts.Runtime get { return m_Interval; } set { if (PropertyUtil.SetStruct(ref m_Interval, value)) SetVerticesDirty(); } } + /// + /// Whether to show the first split line. + /// |是否显示第一条分割线。 + /// + public bool showStartLine + { + get { return m_ShowStartLine; } + set { if (PropertyUtil.SetStruct(ref m_ShowStartLine, value)) SetVerticesDirty(); } + } + /// + /// Whether to show the last split line. + /// |是否显示最后一条分割线。 + /// + public bool showEndLine + { + get { return m_ShowEndLine; } + set { if (PropertyUtil.SetStruct(ref m_ShowEndLine, value)) SetVerticesDirty(); } + } public override bool vertsDirty { get { return m_VertsDirty || m_LineStyle.anyDirty; } } public override void ClearVerticesDirty() @@ -56,6 +76,8 @@ namespace XCharts.Runtime var axisSplitLine = new AxisSplitLine(); axisSplitLine.show = show; axisSplitLine.interval = interval; + axisSplitLine.showStartLine = showStartLine; + axisSplitLine.showEndLine = showEndLine; axisSplitLine.lineStyle = lineStyle.Clone(); return axisSplitLine; } @@ -64,11 +86,17 @@ namespace XCharts.Runtime { base.Copy(splitLine); interval = splitLine.interval; + showStartLine = splitLine.showStartLine; + showEndLine = splitLine.showEndLine; } - internal bool NeedShow(int index) + internal bool NeedShow(int index, int total) { - return show && (interval == 0 || index % (interval + 1) == 0); + if (!show) return false; + if (interval != 0 && index % (interval + 1) != 0) return false; + if (!showStartLine && index == 0) return false; + if (!showEndLine && index == total - 1) return false; + return true; } } } \ No newline at end of file diff --git a/Runtime/Component/Axis/ParallelAxis/ParallelAxis.cs b/Runtime/Component/Axis/ParallelAxis/ParallelAxis.cs index 18f86050..7fac3ab5 100644 --- a/Runtime/Component/Axis/ParallelAxis/ParallelAxis.cs +++ b/Runtime/Component/Axis/ParallelAxis/ParallelAxis.cs @@ -23,6 +23,7 @@ namespace XCharts.Runtime splitLine.show = false; splitLine.lineStyle.type = LineStyle.Type.None; axisLabel.textLimit.enable = true; + axisName.labelStyle.offset = new Vector3(0, 25, 0); } } diff --git a/Runtime/Component/Axis/ParallelAxis/ParallelAxisHander.cs b/Runtime/Component/Axis/ParallelAxis/ParallelAxisHander.cs index 0ae6185c..f1e8d57a 100644 --- a/Runtime/Component/Axis/ParallelAxis/ParallelAxisHander.cs +++ b/Runtime/Component/Axis/ParallelAxis/ParallelAxisHander.cs @@ -160,7 +160,7 @@ namespace XCharts.Runtime internal override float GetAxisLineXOrY() { - return component.context.y; + return component.context.x; } } } \ No newline at end of file diff --git a/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs b/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs index 4e295923..60382f55 100644 --- a/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs +++ b/Runtime/Component/Axis/RadiusAxis/RadiusAxisHandler.cs @@ -50,7 +50,7 @@ namespace XCharts.Runtime if (axis.IsCategory() || !axis.show) return; double tempMinValue = 0; double tempMaxValue = 0; - SeriesHelper.GetXMinMaxValue(chart.series, null, axis.polarIndex, true, axis.inverse, out tempMinValue, + SeriesHelper.GetXMinMaxValue(chart, axis.polarIndex, true, axis.inverse, out tempMinValue, out tempMaxValue, true); AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true); if (tempMinValue != axis.context.minValue || tempMaxValue != axis.context.maxValue) @@ -74,7 +74,9 @@ namespace XCharts.Runtime if (axis.context.labelObjectList.Count <= 0) InitRadiusAxis(axis); else + { axis.UpdateLabelText(polar.context.radius, null, false); + } } private void InitRadiusAxis(RadiusAxis axis) @@ -89,7 +91,7 @@ namespace XCharts.Runtime PolarHelper.UpdatePolarCenter(polar, chart.chartPosition, chart.chartWidth, chart.chartHeight); axis.context.labelObjectList.Clear(); - var radius = polar.context.radius; + var radius = polar.context.outsideRadius - polar.context.insideRadius; var objName = component.GetType().Name + axis.index; var axisObj = ChartHelper.AddObject(objName, chart.transform, chart.chartMinAnchor, chart.chartMaxAnchor, chart.chartPivot, chart.chartSizeDelta); @@ -99,7 +101,7 @@ namespace XCharts.Runtime ChartHelper.HideAllObject(axisObj); var textStyle = axis.axisLabel.textStyle; var splitNumber = AxisHelper.GetScaleNumber(axis, radius, null); - var totalWidth = 0f; + var totalWidth = polar.context.insideRadius; var txtHig = textStyle.GetFontSize(chart.theme.axis) + 2; for (int i = 0; i < splitNumber; i++) { @@ -133,6 +135,10 @@ namespace XCharts.Runtime var tickLength = axis.axisTick.GetLength(chart.theme.axis.tickLength); var tickVector = ChartHelper.GetVertialDire(dire) * (tickLength + axis.axisLabel.distance); + if (axis.IsCategory()) + { + totalWidth += polar.context.radius / axis.data.Count / 2; + } return ChartHelper.GetPos(cenPos, totalWidth, startAngle, true) + tickVector; } @@ -150,20 +156,23 @@ namespace XCharts.Runtime var radius = polar.context.radius; var cenPos = polar.context.center; var size = AxisHelper.GetScaleNumber(radiusAxis, radius, null); - var totalWidth = 0f; + var totalWidth = polar.context.insideRadius; var dire = ChartHelper.GetDire(startAngle, true).normalized; var tickWidth = radiusAxis.axisTick.GetWidth(chart.theme.axis.tickWidth); var tickLength = radiusAxis.axisTick.GetLength(chart.theme.axis.tickLength); var tickVetor = ChartHelper.GetVertialDire(dire) * tickLength; - for (int i = 0; i <= size; i++) + for (int i = 0; i < size; i++) { - var scaleWidth = AxisHelper.GetScaleWidth(radiusAxis, radius, i); + var scaleWidth = AxisHelper.GetScaleWidth(radiusAxis, radius, i + 1); var pos = ChartHelper.GetPos(cenPos, totalWidth + tickWidth, startAngle, true); if (radiusAxis.show && radiusAxis.splitLine.show) { - var outsideRaidus = totalWidth + radiusAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth) * 2; - var splitLineColor = radiusAxis.splitLine.GetColor(chart.theme.axis.splitLineColor); - UGL.DrawDoughnut(vh, cenPos, totalWidth, outsideRaidus, splitLineColor, Color.clear); + if (CanDrawSplitLine(angleAxis, i, size) && radiusAxis.splitLine.NeedShow(i, size)) + { + var outsideRaidus = totalWidth + radiusAxis.splitLine.GetWidth(chart.theme.axis.splitLineWidth) * 2; + var splitLineColor = radiusAxis.splitLine.GetColor(chart.theme.axis.splitLineColor); + UGL.DrawDoughnut(vh, cenPos, totalWidth, outsideRaidus, splitLineColor, Color.clear); + } } if (radiusAxis.show && radiusAxis.axisTick.show) { @@ -178,11 +187,23 @@ namespace XCharts.Runtime } if (radiusAxis.show && radiusAxis.axisLine.show) { - var lineStartPos = polar.context.center - dire * tickWidth; - var lineEndPos = polar.context.center + dire * (radius + tickWidth); + var lineStartPos = polar.context.center + dire * polar.context.insideRadius; + var lineEndPos = polar.context.center + dire * (polar.context.outsideRadius + 2 * tickWidth); var lineWidth = radiusAxis.axisLine.GetWidth(chart.theme.axis.lineWidth); UGL.DrawLine(vh, lineStartPos, lineEndPos, lineWidth, chart.theme.axis.lineColor); } } + + private bool CanDrawSplitLine(AngleAxis angleAxis, int i, int size) + { + if (angleAxis.axisLine.show) + { + return i != size - 1 && i != 0; + } + else + { + return true; + } + } } } \ No newline at end of file diff --git a/Runtime/Component/Child/SerieSymbl.cs b/Runtime/Component/Child/SerieSymbl.cs index 7cdc1013..c31c5bd5 100644 --- a/Runtime/Component/Child/SerieSymbl.cs +++ b/Runtime/Component/Child/SerieSymbl.cs @@ -41,6 +41,8 @@ namespace XCharts.Runtime [SerializeField] private int m_Interval; [SerializeField] private bool m_ForceShowLast = false; [SerializeField] private bool m_Repeat = false; + [SerializeField][Since("v3.3.0")] private float m_MinSize = 0f; + [SerializeField][Since("v3.3.0")] private float m_MaxSize = 0f; public override void Reset() { @@ -53,6 +55,8 @@ namespace XCharts.Runtime m_Interval = 0; m_ForceShowLast = false; m_Repeat = false; + m_MinSize = 0f; + m_MaxSize = 0f; } /// @@ -126,6 +130,25 @@ namespace XCharts.Runtime get { return m_Repeat; } set { if (PropertyUtil.SetStruct(ref m_Repeat, value)) SetAllDirty(); } } + /// + /// Minimum symbol size. + /// |图形最小尺寸。只在sizeType为SymbolSizeType.FromData时有效。 + /// + public float minSize + { + get { return m_MinSize; } + set { if (PropertyUtil.SetStruct(ref m_MinSize, value)) SetVerticesDirty(); } + } + /// + /// Maximum symbol size. + /// |图形最大尺寸。只在sizeType为SymbolSizeType.FromData时有效。 + /// + public float maxSize + { + get { return m_MaxSize; } + set { if (PropertyUtil.SetStruct(ref m_MaxSize, value)) SetVerticesDirty(); } + } + /// /// 根据指定的sizeType获得标记的大小 /// @@ -140,7 +163,10 @@ namespace XCharts.Runtime case SymbolSizeType.FromData: if (data != null && dataIndex >= 0 && dataIndex < data.Count) { - return (float) data[dataIndex] * m_DataScale; + var value = (float) data[dataIndex] * m_DataScale; + if (m_MinSize != 0 && value < m_MinSize) value = m_MinSize; + if (m_MaxSize != 0 && value > m_MaxSize) value = m_MaxSize; + return value; } else { diff --git a/Runtime/Component/DataZoom/DataZoomHandler.cs b/Runtime/Component/DataZoom/DataZoomHandler.cs index aa9e7644..be6854ad 100644 --- a/Runtime/Component/DataZoom/DataZoomHandler.cs +++ b/Runtime/Component/DataZoom/DataZoomHandler.cs @@ -464,7 +464,7 @@ namespace XCharts.Runtime Vector3 np = Vector3.zero; double minValue = 0; double maxValue = 0; - SeriesHelper.GetYMinMaxValue(chart.series, null, 0, chart.IsAllAxisValue(), axis.inverse, out minValue, out maxValue); + SeriesHelper.GetYMinMaxValue(chart, 0, chart.IsAllAxisValue(), axis.inverse, out minValue, out maxValue, false, false); AxisHelper.AdjustMinMaxValue(axis, ref minValue, ref maxValue, true); int rate = 1; @@ -553,7 +553,7 @@ namespace XCharts.Runtime Vector3 np = Vector3.zero; double minValue = 0; double maxValue = 0; - SeriesHelper.GetYMinMaxValue(chart.series, null, 0, chart.IsAllAxisValue(), axis.inverse, out minValue, out maxValue); + SeriesHelper.GetYMinMaxValue(chart, 0, chart.IsAllAxisValue(), axis.inverse, out minValue, out maxValue); AxisHelper.AdjustMinMaxValue(axis, ref minValue, ref maxValue, true); int rate = 1; diff --git a/Runtime/Component/Label/LabelLine.cs b/Runtime/Component/Label/LabelLine.cs index a0b1c2c6..d092af18 100644 --- a/Runtime/Component/Label/LabelLine.cs +++ b/Runtime/Component/Label/LabelLine.cs @@ -141,5 +141,15 @@ namespace XCharts.Runtime get { return m_EndSymbol; } set { if (PropertyUtil.SetClass(ref m_EndSymbol, value)) SetVerticesDirty(); } } + + public Vector3 GetStartSymbolOffset() + { + 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; + } } } \ No newline at end of file diff --git a/Runtime/Component/Legend/Legend.cs b/Runtime/Component/Legend/Legend.cs index df3e5b46..9b8e53b4 100644 --- a/Runtime/Component/Legend/Legend.cs +++ b/Runtime/Component/Legend/Legend.cs @@ -43,6 +43,10 @@ namespace XCharts.Runtime /// 菱形。 /// Diamond, + /// + /// 烛台(可用于K线图)。 + /// + Candlestick, } /// /// Selected mode of legend, which controls whether series can be toggled displaying by clicking legends. diff --git a/Runtime/Component/Legend/LegendHandler.cs b/Runtime/Component/Legend/LegendHandler.cs index 724d5d06..52951bd8 100644 --- a/Runtime/Component/Legend/LegendHandler.cs +++ b/Runtime/Component/Legend/LegendHandler.cs @@ -196,31 +196,38 @@ namespace XCharts.Runtime if (legend.iconType == Legend.Type.Auto) { var serie = chart.GetSerie(item.legendName); - if (serie != null && serie is Line) + if (serie != null) { - var sp = new Vector3(rect.center.x - rect.width / 2, rect.center.y); - var ep = new Vector3(rect.center.x + rect.width / 2, rect.center.y); - UGL.DrawLine(vh, sp, ep, chart.settings.legendIconLineWidth, color); - if (!serie.symbol.show) continue; - switch (serie.symbol.type) + if (serie is Line || serie is SimplifiedLine) { - case SymbolType.None: - continue; - case SymbolType.Circle: - iconType = Legend.Type.Circle; - break; - case SymbolType.Diamond: - iconType = Legend.Type.Diamond; - break; - case SymbolType.EmptyCircle: - iconType = Legend.Type.EmptyCircle; - break; - case SymbolType.Rect: - iconType = Legend.Type.Rect; - break; - case SymbolType.Triangle: - iconType = Legend.Type.Triangle; - break; + var sp = new Vector3(rect.center.x - rect.width / 2, rect.center.y); + var ep = new Vector3(rect.center.x + rect.width / 2, rect.center.y); + UGL.DrawLine(vh, sp, ep, chart.settings.legendIconLineWidth, color); + if (!serie.symbol.show) continue; + switch (serie.symbol.type) + { + case SymbolType.None: + continue; + case SymbolType.Circle: + iconType = Legend.Type.Circle; + break; + case SymbolType.Diamond: + iconType = Legend.Type.Diamond; + break; + case SymbolType.EmptyCircle: + iconType = Legend.Type.EmptyCircle; + break; + case SymbolType.Rect: + iconType = Legend.Type.Rect; + break; + case SymbolType.Triangle: + iconType = Legend.Type.Triangle; + break; + } + } + else + { + iconType = Legend.Type.Rect; } } else @@ -249,6 +256,12 @@ namespace XCharts.Runtime case Legend.Type.Triangle: UGL.DrawTriangle(vh, rect.center, 1.2f * radius, color); break; + case Legend.Type.Candlestick: + UGL.DrawRoundRectangle(vh, rect.center, rect.width / 2, rect.height / 2, color, color, + 0, null, false, 0.5f); + UGL.DrawLine(vh, new Vector3(rect.center.x, rect.center.y - rect.height / 2), + new Vector3(rect.center.x, rect.center.y + rect.height / 2), 1, color); + break; } } } diff --git a/Runtime/Component/Mark/MarkLineHandler.cs b/Runtime/Component/Mark/MarkLineHandler.cs index 55d211df..6ac01410 100644 --- a/Runtime/Component/Mark/MarkLineHandler.cs +++ b/Runtime/Component/Mark/MarkLineHandler.cs @@ -35,8 +35,9 @@ namespace XCharts.Runtime { if (data.runtimeLabel != null) { - data.runtimeLabel.SetActive(data.label.show); - data.runtimeLabel.SetPosition(MarkLineHelper.GetLabelPosition(data)); + var pos = MarkLineHelper.GetLabelPosition(data); + data.runtimeLabel.SetActive(data.label.show && pos != Vector3.zero); + data.runtimeLabel.SetPosition(pos); data.runtimeLabel.SetText(MarkLineHelper.GetFormatterContent(serie, data)); } } @@ -76,10 +77,10 @@ namespace XCharts.Runtime 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); - label.SetPosition(MarkLineHelper.GetLabelPosition(data)); + label.SetActive(data.label.show && pos != Vector3.zero); + label.SetPosition(pos); data.runtimeLabel = label; }; data.refreshComponent(); @@ -202,8 +203,7 @@ namespace XCharts.Runtime for (int i = 0; i < markLine.data.Count; i++) { var data = markLine.data[i]; - // data.index = i; - data.index = markLine.index; + data.index = i; if (data.group == 0) continue; if (!m_TempGroupData.ContainsKey(data.group)) { diff --git a/Runtime/Component/Mark/MarkLineHelper.cs b/Runtime/Component/Mark/MarkLineHelper.cs index 55304ff4..4a1c5dcd 100644 --- a/Runtime/Component/Mark/MarkLineHelper.cs +++ b/Runtime/Component/Mark/MarkLineHelper.cs @@ -34,13 +34,16 @@ namespace XCharts.Runtime switch (data.label.position) { case LabelStyle.Position.Start: + if (data.runtimeStartPosition == Vector3.zero) return Vector3.zero; if (horizontal) return data.runtimeStartPosition + data.label.offset + labelWidth / 2 * Vector3.left; else return data.runtimeStartPosition + data.label.offset + labelHeight / 2 * Vector3.down; case LabelStyle.Position.Middle: + if (data.runtimeCurrentEndPosition == Vector3.zero) return Vector3.zero; var center = (data.runtimeStartPosition + data.runtimeCurrentEndPosition) / 2; if (horizontal) return center + data.label.offset + labelHeight / 2 * Vector3.up; else return center + data.label.offset + labelWidth / 2 * Vector3.right; default: + if (data.runtimeCurrentEndPosition == Vector3.zero) return Vector3.zero; if (horizontal) return data.runtimeCurrentEndPosition + data.label.offset + labelWidth / 2 * Vector3.right; else return data.runtimeCurrentEndPosition + data.label.offset + labelHeight / 2 * Vector3.up; } diff --git a/Runtime/Component/Radar/RadarCoord.cs b/Runtime/Component/Radar/RadarCoord.cs index 5b0cb039..0af7d4be 100644 --- a/Runtime/Component/Radar/RadarCoord.cs +++ b/Runtime/Component/Radar/RadarCoord.cs @@ -385,7 +385,7 @@ namespace XCharts.Runtime SetAllDirty(); } - public RadarCoord.Indicator AddIndicator(string name, float min, float max) + public RadarCoord.Indicator AddIndicator(string name, double min, double max) { var indicator = new RadarCoord.Indicator(); indicator.name = name; @@ -396,7 +396,14 @@ namespace XCharts.Runtime return indicator; } - public bool UpdateIndicator(int indicatorIndex, string name, float min, float max) + [Since("v3.3.0")] + public void AddIndicatorList(List nameList, double min = 0, double max = 0) + { + foreach (var name in nameList) + AddIndicator(name, min, max); + } + + public bool UpdateIndicator(int indicatorIndex, string name, double min, double max) { var indicator = GetIndicator(indicatorIndex); if (indicator == null) return false; diff --git a/Runtime/Component/Radar/RadarCoordHandler.cs b/Runtime/Component/Radar/RadarCoordHandler.cs index 4c72ccb8..add4ada8 100644 --- a/Runtime/Component/Radar/RadarCoordHandler.cs +++ b/Runtime/Component/Radar/RadarCoordHandler.cs @@ -17,6 +17,7 @@ namespace XCharts.Runtime public override void Update() { + base.Update(); if (!chart.isPointerInChart) { component.context.isPointerEnter = false; @@ -87,6 +88,7 @@ namespace XCharts.Runtime var lineType = radar.axisLine.GetType(chart.theme.axis.lineType); var splitLineColor = radar.splitLine.GetColor(chart.theme.axis.splitLineColor); var splitLineWidth = radar.splitLine.GetWidth(chart.theme.axis.splitLineWidth); + splitLineWidth *= 2f; for (int i = 0; i < radar.splitNumber; i++) { var color = radar.splitArea.GetColor(i, chart.theme.axis); @@ -146,7 +148,7 @@ namespace XCharts.Runtime { UGL.DrawQuadrilateral(vh, p1, p2, p3, p4, color); } - if (radar.splitLine.NeedShow(i)) + if (radar.splitLine.NeedShow(i, radar.splitNumber)) { ChartDrawer.DrawLineStyle(vh, splitLineType, splitLineWidth, p2, p3, splitLineColor); } diff --git a/Runtime/Component/Tooltip/Tooltip.cs b/Runtime/Component/Tooltip/Tooltip.cs index 418c679a..b882e057 100644 --- a/Runtime/Component/Tooltip/Tooltip.cs +++ b/Runtime/Component/Tooltip/Tooltip.cs @@ -42,6 +42,10 @@ namespace XCharts.Runtime Corss } + /// + /// Trigger strategy. + /// |触发类型。 + /// public enum Trigger { /// @@ -60,10 +64,37 @@ namespace XCharts.Runtime /// None } + /// + /// Position type. + /// |坐标类型。 + /// + public enum Position + { + /// + /// Auto. The mobile platform is displayed at the top, and the non-mobile platform follows the mouse position. + /// |自适应。移动平台靠顶部显示,非移动平台跟随鼠标位置。 + /// + Auto, + /// + /// Custom. Fully customize display position (x,y). + /// |自定义。完全自定义显示位置(x,y)。 + /// + Custom, + /// + /// Just fix the coordinate X. Y follows the mouse position. + /// |只固定坐标X。Y跟随鼠标位置。 + /// + FixedX, + /// + /// Just fix the coordinate Y. X follows the mouse position. + /// |只固定坐标Y。X跟随鼠标位置。 + FixedY + } [SerializeField] private bool m_Show = true; [SerializeField] private Type m_Type; [SerializeField] private Trigger m_Trigger = Trigger.Item; + [SerializeField][Since("v3.3.0")] private Position m_Position = Position.Auto; [SerializeField] private string m_ItemFormatter; [SerializeField] private string m_TitleFormatter; [SerializeField] private string m_Marker = "●"; @@ -83,10 +114,8 @@ namespace XCharts.Runtime [SerializeField] private Image.Type m_BackgroundType = Image.Type.Simple; [SerializeField] private Color m_BackgroundColor; [SerializeField] private float m_BorderWidth = 2f; - [SerializeField] private bool m_FixedXEnable = false; [SerializeField] private float m_FixedX = 0f; - [SerializeField] private bool m_FixedYEnable = false; - [SerializeField] private float m_FixedY = 0f; + [SerializeField] private float m_FixedY = 0.7f; [SerializeField] private float m_TitleHeight = 25f; [SerializeField] private float m_ItemHeight = 25f; [SerializeField] private Color32 m_BorderColor = new Color32(230, 230, 230, 255); @@ -136,6 +165,15 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_Trigger, value)) SetAllDirty(); } } /// + /// Type of position. + /// |显示位置类型。 + /// + public Position position + { + get { return m_Position; } + set { if (PropertyUtil.SetStruct(ref m_Position, value)) SetAllDirty(); } + } + /// /// 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. @@ -189,6 +227,7 @@ namespace XCharts.Runtime /// {g}为当前所指示的serie的数据总个数。
/// {c0}表示当前数据项维度为0的数据。
/// {c1}表示当前数据项维度为1的数据。
+ /// {d3}表示维度3的数据的百分比。它的分母是默认维度(一般是1维度)数据。
/// |表示多个列的分隔。
/// 示例:"{i}", "{.}|{a}|{c}", "{.}|{b}|{c2:f2}" ///
@@ -303,15 +342,6 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetColor(ref m_BorderColor, value)) SetVerticesDirty(); } } /// - /// enable fixedX. - /// |是否固定X位置。 - /// - public bool fixedXEnable - { - get { return m_FixedXEnable; } - set { if (PropertyUtil.SetStruct(ref m_FixedXEnable, value)) SetVerticesDirty(); } - } - /// /// the x positionn of fixedX. /// |固定X位置的坐标。 /// @@ -321,15 +351,6 @@ namespace XCharts.Runtime set { if (PropertyUtil.SetStruct(ref m_FixedX, value)) SetVerticesDirty(); } } /// - /// enable fixedY. - /// |是否固定Y位置。 - /// - public bool fixedYEnable - { - get { return m_FixedYEnable; } - set { if (PropertyUtil.SetStruct(ref m_FixedYEnable, value)) SetVerticesDirty(); } - } - /// /// the y position of fixedY. /// |固定Y位置的坐标。 /// @@ -467,12 +488,29 @@ namespace XCharts.Runtime /// 更新文本框位置 ///
/// - public void UpdateContentPos(Vector2 pos) + public void UpdateContentPos(Vector2 pos, float width, float height) { if (view != null) { - if (fixedXEnable) pos.x = fixedX; - if (fixedYEnable) pos.y = fixedY; + switch (m_Position) + { + case Position.Auto: +#if UNITY_ANDROID || UNITY_IOS + if (m_FixedY == 0) pos.y = ChartHelper.GetActualValue(0.7f, height); + else pos.y = ChartHelper.GetActualValue(m_FixedY, height); +#endif + break; + case Position.Custom: + pos.x = ChartHelper.GetActualValue(m_FixedX, width); + pos.y = ChartHelper.GetActualValue(m_FixedY, height); + break; + case Position.FixedX: + pos.x = ChartHelper.GetActualValue(m_FixedX, width); + break; + case Position.FixedY: + pos.y = ChartHelper.GetActualValue(m_FixedY, height); + break; + } view.UpdatePosition(pos); } } diff --git a/Runtime/Component/Tooltip/TooltipHandler.cs b/Runtime/Component/Tooltip/TooltipHandler.cs index a03205a6..1572b9f2 100644 --- a/Runtime/Component/Tooltip/TooltipHandler.cs +++ b/Runtime/Component/Tooltip/TooltipHandler.cs @@ -241,7 +241,11 @@ namespace XCharts.Runtime private void UpdateAxisPointerDataIndex(Serie serie, XAxis xAxis, YAxis yAxis, GridCoord grid, bool isTriggerAxis) { serie.context.pointerAxisDataIndexs.Clear(); - if (yAxis.IsCategory()) + if (serie is Heatmap) + { + GetSerieDataByXYAxis(serie, xAxis, yAxis); + } + else if (yAxis.IsCategory()) { if (isTriggerAxis) { @@ -277,6 +281,32 @@ namespace XCharts.Runtime } } + private void GetSerieDataByXYAxis(Serie serie, Axis xAxis, Axis yAxis) + { + var xAxisIndex = AxisHelper.GetAxisValueSplitIndex(xAxis, xAxis.context.pointerValue); + var yAxisIndex = AxisHelper.GetAxisValueSplitIndex(yAxis, yAxis.context.pointerValue); + serie.context.pointerItemDataIndex = -1; + if (serie is Heatmap) + { + var heatmap = serie as Heatmap; + if (heatmap.heatmapType == HeatmapType.Count) + { + serie.context.pointerItemDataIndex = HeatmapHandler.GetGridKey(xAxisIndex, yAxisIndex); + return; + } + } + foreach (var serieData in serie.data) + { + var x = AxisHelper.GetAxisValueSplitIndex(xAxis, serieData.GetData(0)); + var y = AxisHelper.GetAxisValueSplitIndex(yAxis, serieData.GetData(1)); + if (xAxisIndex == x && y == yAxisIndex) + { + serie.context.pointerItemDataIndex = serieData.index; + break; + } + } + } + private void GetSerieDataIndexByAxis(Serie serie, Axis axis, GridCoord grid, int dimension = 0) { var currValue = 0d; @@ -418,7 +448,7 @@ namespace XCharts.Runtime { var serie = series[i]; serie.context.isTriggerByAxis = isTriggerByAxis; - if (isTriggerByAxis && dataIndex >= 0) + if (isTriggerByAxis && dataIndex >= 0 && serie.context.pointerItemDataIndex < 0) serie.context.pointerItemDataIndex = dataIndex; serie.handler.UpdateTooltipSerieParams(dataIndex, showCategory, category, tooltip.marker, tooltip.itemFormatter, tooltip.numericFormatter, @@ -616,11 +646,11 @@ namespace XCharts.Runtime var lineType = tooltip.lineStyle.GetType(theme.tooltip.lineType); var lineWidth = tooltip.lineStyle.GetWidth(theme.tooltip.lineWidth); var cenPos = m_Polar.context.center; - var radius = m_Polar.context.radius; - var sp = m_Polar.context.center; + var radius = m_Polar.context.outsideRadius; var tooltipAngle = m_AngleAxis.GetValueAngle(tooltip.context.angle); - var ep = ChartHelper.GetPos(sp, radius, tooltipAngle, true); + 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) { diff --git a/Runtime/Component/Tooltip/TooltipHelper.cs b/Runtime/Component/Tooltip/TooltipHelper.cs index f0dd53d6..8f9d729d 100644 --- a/Runtime/Component/Tooltip/TooltipHelper.cs +++ b/Runtime/Component/Tooltip/TooltipHelper.cs @@ -77,7 +77,7 @@ namespace XCharts.Runtime } if (pos.y > chartRect.y + chartRect.height) pos.y = chartRect.y + chartRect.height; - tooltip.UpdateContentPos(pos); + tooltip.UpdateContentPos(pos, chartRect.width / 2, chartRect.height / 2); } public static string GetItemNumericFormatter(Tooltip tooltip, Serie serie, SerieData serieData) diff --git a/Runtime/Component/VisualMap/VisualMap.cs b/Runtime/Component/VisualMap/VisualMap.cs index 165aa809..69a0a786 100644 --- a/Runtime/Component/VisualMap/VisualMap.cs +++ b/Runtime/Component/VisualMap/VisualMap.cs @@ -81,9 +81,9 @@ namespace XCharts.Runtime [SerializeField] private SelectedMode m_SelectedMode = SelectedMode.Multiple; [SerializeField] private int m_SerieIndex = 0; [SerializeField] private double m_Min = 0; - [SerializeField] private double m_Max = 100; + [SerializeField] private double m_Max = 0; - [SerializeField] private double[] m_Range = new double[2] { 0, 100 }; + [SerializeField] private double[] m_Range = new double[2] { 0, 0 }; [SerializeField] private string[] m_Text = new string[2] { "", "" }; [SerializeField] private float[] m_TextGap = new float[2] { 10f, 10f }; [SerializeField] private int m_SplitNumber = 5; @@ -364,7 +364,8 @@ namespace XCharts.Runtime { get { - if (m_Range[0] < min || m_Range[0] > max) return min; + if (m_Range[0] == 0 && m_Range[1] == 0) return min; + else if (m_Range[0] < min || m_Range[0] > max) return min; else return m_Range[0]; } set @@ -377,6 +378,7 @@ namespace XCharts.Runtime { get { + if (m_Range[0] == 0 && m_Range[1] == 0) return max; if (m_Range[1] >= m_Range[0] && m_Range[1] < max) return m_Range[1]; else return max; } diff --git a/Runtime/Component/VisualMap/VisualMapContext.cs b/Runtime/Component/VisualMap/VisualMapContext.cs index 730b537d..afba42a2 100644 --- a/Runtime/Component/VisualMap/VisualMapContext.cs +++ b/Runtime/Component/VisualMap/VisualMapContext.cs @@ -12,6 +12,8 @@ namespace XCharts.Runtime public double pointerValue { get; set; } public bool minDrag { get; internal set; } public bool maxDrag { get; internal set; } + public double min { get; set; } + public double max { get; set; } internal List inRangeColors = new List(); diff --git a/Runtime/Component/VisualMap/VisualMapHelper.cs b/Runtime/Component/VisualMap/VisualMapHelper.cs index 6351dea4..406b2bf5 100644 --- a/Runtime/Component/VisualMap/VisualMapHelper.cs +++ b/Runtime/Component/VisualMap/VisualMapHelper.cs @@ -177,15 +177,13 @@ namespace XCharts.Runtime return true; } - public static int GetDimension(VisualMap visualMap, int serieDataCount) + public static int GetDimension(VisualMap visualMap, int defaultDimension) { - var dimension = visualMap != null && visualMap.dimension >= 0 ? - visualMap.dimension : serieDataCount - 1; + if (visualMap == null || !visualMap.show) + return defaultDimension; - if (dimension > serieDataCount - 1) - dimension = serieDataCount - 1; - - return dimension; + return visualMap != null && visualMap.dimension >= 0 ? + visualMap.dimension : defaultDimension; } } } \ No newline at end of file diff --git a/Runtime/Coord/Polar/PolarCoord.cs b/Runtime/Coord/Polar/PolarCoord.cs index b251c932..a68ea39c 100644 --- a/Runtime/Coord/Polar/PolarCoord.cs +++ b/Runtime/Coord/Polar/PolarCoord.cs @@ -14,7 +14,7 @@ namespace XCharts.Runtime { [SerializeField] private bool m_Show = true; [SerializeField] private float[] m_Center = new float[2] { 0.5f, 0.45f }; - [SerializeField] private float m_Radius = 0.35f; + [SerializeField] private float[] m_Radius = new float[2] { 0, 0.35f }; [SerializeField] private Color m_BackgroundColor; public PolarCoordContext context = new PolarCoordContext(); @@ -41,12 +41,12 @@ namespace XCharts.Runtime } /// /// the radius of polar. - /// |极坐标的半径。 + /// |半径。radius[0]表示内径,radius[1]表示外径。 /// - public float radius + public float[] radius { get { return m_Radius; } - set { if (PropertyUtil.SetStruct(ref m_Radius, value)) SetAllDirty(); } + set { if (value != null && value.Length == 2) { m_Radius = value; SetAllDirty(); } } } /// /// Background color of polar, which is transparent by default. @@ -65,7 +65,8 @@ namespace XCharts.Runtime public bool Contains(Vector3 pos) { - return Vector3.Distance(pos, context.center) < context.radius; + var dist = Vector3.Distance(pos, context.center); + return dist >= context.insideRadius && dist <= context.outsideRadius; } } } \ No newline at end of file diff --git a/Runtime/Coord/Polar/PolarCoordContext.cs b/Runtime/Coord/Polar/PolarCoordContext.cs index 035c2ca9..f2909b6f 100644 --- a/Runtime/Coord/Polar/PolarCoordContext.cs +++ b/Runtime/Coord/Polar/PolarCoordContext.cs @@ -10,11 +10,17 @@ namespace XCharts.Runtime /// |极坐标在容器中的具体中心点。 /// public Vector3 center; + public float radius; /// /// the true radius of polar. - /// |极坐标的运行时实际半径。 + /// |极坐标的运行时实际内半径。 /// - public float radius; + public float insideRadius; + /// + /// the true radius of polar. + /// |极坐标的运行时实际外半径。 + /// + public float outsideRadius; public bool isPointerEnter; } } \ No newline at end of file diff --git a/Runtime/Coord/Polar/PolarCoordHandler.cs b/Runtime/Coord/Polar/PolarCoordHandler.cs index 7c176a87..182c8be7 100644 --- a/Runtime/Coord/Polar/PolarCoordHandler.cs +++ b/Runtime/Coord/Polar/PolarCoordHandler.cs @@ -10,6 +10,7 @@ namespace XCharts.Runtime { public override void Update() { + base.Update(); PolarHelper.UpdatePolarCenter(component, chart.chartPosition, chart.chartWidth, chart.chartHeight); if (chart.isPointerInChart) @@ -26,9 +27,22 @@ namespace XCharts.Runtime private void DrawPolar(VertexHelper vh, PolarCoord polar) { PolarHelper.UpdatePolarCenter(polar, chart.chartPosition, chart.chartWidth, chart.chartHeight); - if (!ChartHelper.IsClearColor(polar.backgroundColor)) + if (polar.show && !ChartHelper.IsClearColor(polar.backgroundColor)) { - UGL.DrawCricle(vh, polar.context.center, polar.context.radius, polar.backgroundColor); + if (polar.context.insideRadius > 0) + { + UGL.DrawDoughnut(vh, polar.context.center, + polar.context.insideRadius, + polar.context.outsideRadius, + polar.backgroundColor, + ColorUtil.clearColor32); + } + else + { + UGL.DrawCricle(vh, polar.context.center, + polar.context.outsideRadius, + polar.backgroundColor); + } } } } diff --git a/Runtime/Coord/Polar/PolarHelper.cs b/Runtime/Coord/Polar/PolarHelper.cs index fa51a52a..f80f5216 100644 --- a/Runtime/Coord/Polar/PolarHelper.cs +++ b/Runtime/Coord/Polar/PolarHelper.cs @@ -9,19 +9,33 @@ namespace XCharts.Runtime if (polar.center.Length < 2) return; var centerX = polar.center[0] <= 1 ? chartWidth * polar.center[0] : polar.center[0]; var centerY = polar.center[1] <= 1 ? chartHeight * polar.center[1] : polar.center[1]; + var minWidth = Mathf.Min(chartWidth, chartHeight); + polar.context.center = chartPosition + new Vector3(centerX, centerY); - if (polar.radius <= 0) + polar.context.insideRadius = polar.context.outsideRadius = 0; + if (polar.radius.Length >= 2) { - polar.context.radius = 0; + polar.context.insideRadius = ChartHelper.GetActualValue(polar.radius[0], minWidth, 1); + polar.context.outsideRadius = ChartHelper.GetActualValue(polar.radius[1], minWidth, 1); } - else if (polar.radius <= 1) + else if (polar.radius.Length >= 1) { - polar.context.radius = Mathf.Min(chartWidth, chartHeight) * polar.radius; - } - else - { - polar.context.radius = polar.radius; + polar.context.outsideRadius = ChartHelper.GetActualValue(polar.radius[0], minWidth, 1); } + polar.context.radius = polar.context.outsideRadius - polar.context.insideRadius; + } + + public static Vector3 UpdatePolarAngleAndPos(PolarCoord polar, AngleAxis angleAxis, RadiusAxis radiusAxis, SerieData serieData) + { + var value = serieData.GetData(0); + var angle = angleAxis.GetValueAngle(serieData.GetData(1)); + var radius = polar.context.insideRadius + radiusAxis.GetValueLength(value, polar.context.radius); + + angle = (angle + 360) % 360; + serieData.context.angle = angle; + serieData.context.position = ChartHelper.GetPos(polar.context.center, radius, angle, true); + + return serieData.context.position; } } } \ No newline at end of file diff --git a/Runtime/Helper/FormatterHelper.cs b/Runtime/Helper/FormatterHelper.cs index 6cb3a659..02ddaea8 100644 --- a/Runtime/Helper/FormatterHelper.cs +++ b/Runtime/Helper/FormatterHelper.cs @@ -205,7 +205,9 @@ namespace XCharts.Runtime } else if (p == 'd' || p == 'D') { - var rate = total == 0 ? 0 : value / total * 100; + var rate = pIndex >= 0 && serieData != null ? + (value == 0 ? 0 : serieData.GetData(pIndex) / value * 100) : + (total == 0 ? 0 : value / total * 100); content = content.Replace(old, ChartCached.NumberToStr(rate, numericFormatter)); } else if (p == 'c' || p == 'C') diff --git a/Runtime/Internal/BaseChart.API.cs b/Runtime/Internal/BaseChart.API.cs index c0034efb..68c279cc 100644 --- a/Runtime/Internal/BaseChart.API.cs +++ b/Runtime/Internal/BaseChart.API.cs @@ -96,11 +96,17 @@ namespace XCharts.Runtime ///
public CustomDrawGaugePointerFunction customDrawGaugePointerFunction { set { m_CustomDrawGaugePointerFunction = value; } get { return m_CustomDrawGaugePointerFunction; } } /// - /// the callback function of click pie area. + /// the callback function of pointer click pie area. /// |点击饼图区域回调。参数:PointerEventData,SerieIndex,SerieDataIndex /// public Action onPointerClickPie { set { m_OnPointerClickPie = value; m_ForceOpenRaycastTarget = true; } get { return m_OnPointerClickPie; } } /// + /// the callback function of pointer enter pie area. + /// |鼠标进入和离开饼图区域回调,SerieDataIndex为-1时表示离开。参数:PointerEventData,SerieIndex,SerieDataIndex + /// + [Since("v3.3.0")] + public Action onPointerEnterPie { set { m_OnPointerEnterPie = value; m_ForceOpenRaycastTarget = true; } get { return m_OnPointerEnterPie; } } + /// /// the callback function of click bar. /// |点击柱形图柱条回调。参数:eventData, dataIndex /// @@ -151,6 +157,11 @@ namespace XCharts.Runtime if (m_PainterTop) m_PainterTop.Refresh(); } + public override void RefreshGraph() + { + RefreshChart(); + } + /// /// Redraw chart serie in next frame. /// |在下一帧刷新图表的指定serie。 @@ -577,5 +588,15 @@ namespace XCharts.Runtime SerieHelper.GetItemColor(out color, out toColor, serie, null, m_Theme); return color; } + + /// + /// 保存图表为图片。 + /// + /// type of image: png, jpg, exr + /// save path + public void SaveAsImage(string imageType = "png", string savePath = "") + { + StartCoroutine(SaveAsImageSync(imageType, savePath)); + } } } \ No newline at end of file diff --git a/Runtime/Internal/BaseChart.Component.cs b/Runtime/Internal/BaseChart.Component.cs index 8e19c4d5..b989f2d9 100644 --- a/Runtime/Internal/BaseChart.Component.cs +++ b/Runtime/Internal/BaseChart.Component.cs @@ -349,6 +349,22 @@ namespace XCharts.Runtime } } + public DataZoom GetXDataZoomOfSerie(Serie serie) + { + if (serie == null) return null; + foreach (var component in m_Components) + { + if (component is DataZoom) + { + var dataZoom = component as DataZoom; + if (!dataZoom.enable) continue; + if (dataZoom.IsContainsXAxis(serie.xAxisIndex)) + return dataZoom; + } + } + return null; + } + /// /// reutrn true when all the show axis is `Value` type. /// |纯数值坐标轴(数值轴或对数轴)。 @@ -427,6 +443,12 @@ namespace XCharts.Runtime internal bool GetSerieGridCoordAxis(Serie serie, out Axis axis, out Axis relativedAxis) { var yAxis = GetChartComponent(serie.yAxisIndex); + if (yAxis == null) + { + axis = null; + relativedAxis = null; + return false; + } var isY = yAxis.IsCategory(); if (isY) { diff --git a/Runtime/Internal/BaseChart.Custom.cs b/Runtime/Internal/BaseChart.Custom.cs index cbd04dad..f9c110fb 100644 --- a/Runtime/Internal/BaseChart.Custom.cs +++ b/Runtime/Internal/BaseChart.Custom.cs @@ -6,8 +6,7 @@ namespace XCharts.Runtime { public partial class BaseChart { - public virtual void InitAxisRuntimeData(Axis axis) - { } + public virtual void InitAxisRuntimeData(Axis axis) { } public virtual void GetSeriesMinMaxValue(Axis axis, int axisIndex, out double tempMinValue, out double tempMaxValue) { @@ -15,16 +14,16 @@ namespace XCharts.Runtime { if (axis is XAxis) { - SeriesHelper.GetXMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue); + SeriesHelper.GetXMinMaxValue(this, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue); } else { - SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue); + SeriesHelper.GetYMinMaxValue(this, axisIndex, true, axis.inverse, out tempMinValue, out tempMaxValue); } } else { - SeriesHelper.GetYMinMaxValue(m_Series, null, axisIndex, false, axis.inverse, out tempMinValue, out tempMaxValue); + SeriesHelper.GetYMinMaxValue(this, axisIndex, false, axis.inverse, out tempMinValue, out tempMaxValue); } AxisHelper.AdjustMinMaxValue(axis, ref tempMinValue, ref tempMaxValue, true); } diff --git a/Runtime/Internal/BaseChart.Serie.cs b/Runtime/Internal/BaseChart.Serie.cs index 4b0a3cec..48f753ce 100644 --- a/Runtime/Internal/BaseChart.Serie.cs +++ b/Runtime/Internal/BaseChart.Serie.cs @@ -19,7 +19,9 @@ namespace XCharts.Runtime public T InsertSerie(int index, string serieName = null, bool show = true) where T : Serie { if (!CanAddSerie()) return null; - return InsertSerie(index, typeof(T), serieName, show) as T; + var serie = InsertSerie(index, typeof(T), serieName, show) as T; + InitSerieHandlers(); + return serie; } public void InsertSerie(Serie serie, int index = -1, bool addToHead = false) @@ -377,23 +379,23 @@ namespace XCharts.Runtime return AddData(serieIndex, xValue, yValue, dataName, dataId); } - public SerieData AddData(int serieIndex, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null) + public SerieData AddData(int serieIndex, double indexOrTimestamp, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null) { var serie = GetSerie(serieIndex); if (serie != null) { - var serieData = serie.AddData(open, close, lowest, heighest, dataName, dataId); + var serieData = serie.AddData(indexOrTimestamp, open, close, lowest, heighest, dataName, dataId); RefreshPainter(serie.painter); return serieData; } return null; } - public SerieData AddData(string serieName, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null) + public SerieData AddData(string serieName, double indexOrTimestamp, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null) { var serie = GetSerie(serieName); if (serie != null) { - var serieData = serie.AddData(open, close, lowest, heighest, dataName, dataId); + var serieData = serie.AddData(indexOrTimestamp, open, close, lowest, heighest, dataName, dataId); RefreshPainter(serie.painter); return serieData; } @@ -966,6 +968,11 @@ namespace XCharts.Runtime serie.symbol.show = true; serie.symbol.type = SymbolType.EmptyCircle; } + else if (type == typeof(Heatmap)) + { + serie.symbol.show = true; + serie.symbol.type = SymbolType.Rect; + } else { serie.symbol.show = false; diff --git a/Runtime/Internal/BaseChart.cs b/Runtime/Internal/BaseChart.cs index fdbf414e..f9ea93c1 100644 --- a/Runtime/Internal/BaseChart.cs +++ b/Runtime/Internal/BaseChart.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEngine; @@ -86,6 +87,7 @@ namespace XCharts.Runtime protected Action m_OnDrawSerieBefore; protected Action m_OnDrawSerieAfter; protected Action m_OnPointerClickPie; + protected Action m_OnPointerEnterPie; protected Action m_OnPointerClickBar; protected Action m_OnAxisPointerValueChanged; protected Action m_OnLegendClick; @@ -578,23 +580,25 @@ namespace XCharts.Runtime serie.context.dataIndexs.Clear(); serie.context.dataIgnores.Clear(); serie.animation.context.isAllItemAnimationEnd = true; - if (!serie.context.pointerEnter) - serie.ResetInteract(); - - if (m_OnDrawSerieBefore != null) + if (serie.show && !serie.animation.HasFadeOut()) { - m_OnDrawSerieBefore.Invoke(vh, serie); - } - DrawPainterSerie(vh, serie); - if (i >= 0 && i < m_SerieHandlers.Count) - { - var handler = m_SerieHandlers[i]; - handler.DrawSerie(vh); - handler.RefreshLabelNextFrame(); - } - if (m_OnDrawSerieAfter != null) - { - m_OnDrawSerieAfter(vh, serie); + if (!serie.context.pointerEnter) + serie.ResetInteract(); + if (m_OnDrawSerieBefore != null) + { + m_OnDrawSerieBefore.Invoke(vh, serie); + } + DrawPainterSerie(vh, serie); + if (i >= 0 && i < m_SerieHandlers.Count) + { + var handler = m_SerieHandlers[i]; + handler.DrawSerie(vh); + handler.RefreshLabelNextFrame(); + } + if (m_OnDrawSerieAfter != null) + { + m_OnDrawSerieAfter(vh, serie); + } } serie.context.vertCount = vh.currentVertCount; } @@ -738,5 +742,11 @@ namespace XCharts.Runtime InitComponentHandlers(); InitSerieHandlers(); } + + private IEnumerator SaveAsImageSync(string imageType, string path) + { + yield return new WaitForEndOfFrame(); + ChartHelper.SaveAsImage(rectTransform, canvas, imageType, path); + } } } \ No newline at end of file diff --git a/Runtime/Internal/BaseGraph.API.cs b/Runtime/Internal/BaseGraph.API.cs index a9290229..f2c9c945 100644 --- a/Runtime/Internal/BaseGraph.API.cs +++ b/Runtime/Internal/BaseGraph.API.cs @@ -120,7 +120,7 @@ namespace XCharts.Runtime /// Redraw graph in next frame. /// |在下一帧刷新图形。 /// - public void RefreshGraph() + public virtual void RefreshGraph() { m_RefreshChart = true; } diff --git a/Runtime/Internal/BaseGraph.cs b/Runtime/Internal/BaseGraph.cs index 28b212dc..f5e52e10 100644 --- a/Runtime/Internal/BaseGraph.cs +++ b/Runtime/Internal/BaseGraph.cs @@ -80,9 +80,9 @@ namespace XCharts.Runtime if (m_IsOnValidate) { m_IsOnValidate = false; - m_RefreshChart = true; CheckTextMeshPro(); InitComponent(); + RefreshGraph(); } else { diff --git a/Runtime/Internal/Utilities/ChartHelper.cs b/Runtime/Internal/Utilities/ChartHelper.cs index be19f64a..d1c5f7a9 100644 --- a/Runtime/Internal/Utilities/ChartHelper.cs +++ b/Runtime/Internal/Utilities/ChartHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using UnityEngine; @@ -896,5 +897,63 @@ namespace XCharts.Runtime if (valueOrRate >= -maxRate && valueOrRate <= maxRate) return valueOrRate * total; else return valueOrRate; } + + [DllImport("__Internal")] + private static extern void Download(string base64str, string fileName); + + public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png", string path = "") + { + var cam = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera; + var pos = RectTransformUtility.WorldToScreenPoint(cam, rectTransform.position); + var width = rectTransform.rect.width * canvas.scaleFactor; + var height = rectTransform.rect.height * canvas.scaleFactor; + var posX = pos.x + rectTransform.rect.xMin * canvas.scaleFactor; + var posY = pos.y + rectTransform.rect.yMin * canvas.scaleFactor; + var rect = new Rect(posX, posY, width, height); + var tex = new Texture2D((int) width, (int) height, TextureFormat.RGBA32, false); + tex.ReadPixels(rect, 0, 0); + tex.Apply(); + byte[] bytes; + switch (imageType) + { + case "png": + bytes = tex.EncodeToPNG(); + break; + case "jpg": + bytes = tex.EncodeToJPG(); + break; + case "exr": + bytes = tex.EncodeToEXR(); + break; + default: + Debug.LogError("SaveAsImage ERROR: not support image type:" + imageType); + return null; + } + var fileName = rectTransform.name + "." + imageType; +#if UNITY_WEBGL + string base64str = Convert.ToBase64String(bytes); + Download(base64str, fileName); + Debug.Log("SaveAsImage: download by brower:" + fileName); + return tex; +#else + if (string.IsNullOrEmpty(path)) + { + var dir = Application.persistentDataPath + "/SavedImage"; +#if UNITY_EDITOR + dir = Application.dataPath + "/../SavedImage"; +#else + dir = Application.persistentDataPath + "/SavedImage"; +#endif + if (!System.IO.Directory.Exists(dir)) + { + System.IO.Directory.CreateDirectory(dir); + } + path = dir + "/" + fileName; + } + System.IO.File.WriteAllBytes(path, bytes); + Debug.Log("SaveAsImage:" + path); + return tex; +#endif + } } } \ No newline at end of file diff --git a/Runtime/Internal/XChartsMgr.cs b/Runtime/Internal/XChartsMgr.cs index a9d29535..ad454b56 100644 --- a/Runtime/Internal/XChartsMgr.cs +++ b/Runtime/Internal/XChartsMgr.cs @@ -20,8 +20,8 @@ namespace XCharts.Runtime [ExecuteInEditMode] public static class XChartsMgr { - public static readonly string version = "3.2.0"; - public static readonly int versionDate = 20220815; + public static readonly string version = "3.3.0"; + public static readonly int versionDate = 20220928; public static string fullVersion { get { return version + "-" + versionDate; } } internal static List chartList = new List(); diff --git a/Runtime/Serie/Bar/Bar.cs b/Runtime/Serie/Bar/Bar.cs index c02e83cb..bd3c1031 100644 --- a/Runtime/Serie/Bar/Bar.cs +++ b/Runtime/Serie/Bar/Bar.cs @@ -3,7 +3,7 @@ namespace XCharts.Runtime [System.Serializable] [SerieHandler(typeof(BarHandler), true)] [SerieConvert(typeof(Line), typeof(Pie))] - [RequireChartComponent(typeof(GridCoord))] + [CoordOptions(typeof(GridCoord), typeof(PolarCoord))] [DefaultAnimation(AnimationType.BottomToTop)] [SerieExtraComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] diff --git a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs new file mode 100644 index 00000000..f2c860ec --- /dev/null +++ b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs @@ -0,0 +1,213 @@ +using UnityEngine; +using UnityEngine.UI; +using XUGL; + +namespace XCharts.Runtime +{ + /// + /// For polar coord + /// + internal sealed partial class BarHandler + { + private PolarCoord m_SeriePolar; + + private void UpdateSeriePolarContext() + { + if (m_SeriePolar == null) + return; + + var needCheck = (chart.isPointerInChart && m_SeriePolar.IsPointerEnter()) || m_LegendEnter; + var lineWidth = 0f; + if (!needCheck) + { + if (m_LastCheckContextFlag != needCheck) + { + var needAnimation1 = false; + lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); + m_LastCheckContextFlag = needCheck; + serie.context.pointerItemDataIndex = -1; + serie.context.pointerEnter = false; + serie.interact.SetValue(ref needAnimation1, lineWidth, false); + foreach (var serieData in serie.data) + { + var symbol = SerieHelper.GetSerieSymbol(serie, serieData); + var symbolSize = symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize); + serieData.context.highlight = false; + serieData.interact.SetValue(ref needAnimation1, symbolSize); + } + if (needAnimation1) + { + if (SeriesHelper.IsStack(chart.series)) + chart.RefreshTopPainter(); + else + chart.RefreshPainter(serie); + } + } + return; + } + m_LastCheckContextFlag = needCheck; + var themeSymbolSize = chart.theme.serie.lineSymbolSize; + 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); + for (int i = 0; i < serie.dataCount; i++) + { + var serieData = serie.data[i]; + var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + serieData.context.highlight = true; + serieData.interact.SetValue(ref needInteract, size); + } + } + else + { + serie.context.pointerItemDataIndex = -1; + serie.context.pointerEnter = false; + var dir = chart.pointerPos - new Vector2(m_SeriePolar.context.center.x, m_SeriePolar.context.center.y); + var pointerAngle = ChartHelper.GetAngle360(Vector2.up, dir); + var pointerRadius = Vector2.Distance(chart.pointerPos, m_SeriePolar.context.center); + Color32 color, toColor; + for (int i = 0; i < serie.dataCount; i++) + { + var serieData = serie.data[i]; + if (pointerAngle >= serieData.context.startAngle && + pointerAngle < serieData.context.toAngle && + pointerRadius >= serieData.context.insideRadius && + pointerRadius < serieData.context.outsideRadius) + { + serie.context.pointerItemDataIndex = i; + serie.context.pointerEnter = true; + serieData.context.highlight = true; + } + else + { + serieData.context.highlight = false; + } + var state = SerieHelper.GetSerieState(serie, serieData, true); + SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, state); + serieData.interact.SetColor(ref needInteract, color, toColor); + } + } + if (needInteract) + { + if (SeriesHelper.IsStack(chart.series)) + chart.RefreshTopPainter(); + else + chart.RefreshPainter(serie); + } + } + + private void DrawPolarBar(VertexHelper vh, Serie serie) + { + var datas = serie.data; + if (datas.Count <= 0) + return; + + m_SeriePolar = chart.GetChartComponent(serie.polarIndex); + if (m_SeriePolar == null) + return; + + var m_AngleAxis = ComponentHelper.GetAngleAxis(chart.components, m_SeriePolar.index); + var m_RadiusAxis = ComponentHelper.GetRadiusAxis(chart.components, m_SeriePolar.index); + if (m_AngleAxis == null || m_RadiusAxis == null) + return; + + var startAngle = m_AngleAxis.context.startAngle; + var currDetailProgress = 0f; + var totalDetailProgress = datas.Count; + + serie.animation.InitProgress(currDetailProgress, totalDetailProgress); + + var isStack = SeriesHelper.IsStack(chart.series, serie.stack); + if (isStack) + SeriesHelper.UpdateStackDataList(chart.series, serie, null, m_StackSerieData); + + var barCount = chart.GetSerieBarRealCount(); + var categoryWidth = m_AngleAxis.IsCategory() ? + AxisHelper.GetDataWidth(m_AngleAxis, 360, datas.Count, null) : + AxisHelper.GetDataWidth(m_RadiusAxis, m_SeriePolar.context.radius, datas.Count, null); + var barGap = chart.GetSerieBarGap(); + var totalBarWidth = chart.GetSerieTotalWidth(categoryWidth, barGap, barCount); + var barWidth = serie.GetBarWidth(categoryWidth, barCount); + var offset = (categoryWidth - totalBarWidth) * 0.5f; + var serieReadIndex = chart.GetSerieIndexIfStack(serie); + float gap = serie.barGap == -1 ? offset : offset + chart.GetSerieTotalGap(categoryWidth, barGap, serieReadIndex); + + var areaColor = ColorUtil.clearColor32; + var areaToColor = ColorUtil.clearColor32; + var interacting = false; + + float start, end; + float inside, outside; + double radiusValue, angleValue; + for (int i = 0; i < datas.Count; i++) + { + if (serie.animation.CheckDetailBreak(i)) + break; + var serieData = datas[i]; + var itemStyle = SerieHelper.GetItemStyle(serie, serieData); + var borderWidth = itemStyle.borderWidth; + var borderColor = itemStyle.borderColor; + + radiusValue = serieData.GetData(0); + angleValue = serieData.GetData(1); + if (m_AngleAxis.IsCategory()) + { + start = (float) (startAngle + categoryWidth * angleValue + gap); + end = start + barWidth; + inside = m_SeriePolar.context.insideRadius; + if (isStack) + { + for (int n = 0; n < m_StackSerieData.Count - 1; n++) + inside += m_StackSerieData[n][i].context.stackHeight; + } + outside = inside + m_RadiusAxis.GetValueLength(radiusValue, m_SeriePolar.context.radius); + serieData.context.stackHeight = outside - inside; + } + else + { + start = startAngle; + if (isStack) + { + for (int n = 0; n < m_StackSerieData.Count - 1; n++) + start += m_StackSerieData[n][i].context.stackHeight; + } + end = start + m_AngleAxis.GetValueLength(angleValue, 360); + serieData.context.stackHeight = end - start; + inside = m_SeriePolar.context.insideRadius + categoryWidth * (float) radiusValue + gap; + outside = inside + barWidth; + } + serieData.context.startAngle = start; + serieData.context.toAngle = end; + serieData.context.halfAngle = (start + end) / 2; + + if (!serieData.interact.TryGetColor(ref areaColor, ref areaToColor, ref interacting)) + { + SerieHelper.GetItemColor(out areaColor, out areaToColor, serie, serieData, chart.theme); + serieData.interact.SetColor(ref interacting, areaColor, areaToColor); + } + + var needRoundCap = serie.roundCap && inside > 0; + + serieData.context.insideRadius = inside; + serieData.context.outsideRadius = outside; + serieData.context.areaCenter = m_SeriePolar.context.center; + serieData.context.position = ChartHelper.GetPosition(m_SeriePolar.context.center, (start + end) / 2, (inside + outside) / 2); + + UGL.DrawDoughnut(vh, m_SeriePolar.context.center, inside, outside, areaColor, areaToColor, + ColorUtil.clearColor32, start, end, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, + needRoundCap, true); + } + + if (!serie.animation.IsFinish()) + { + serie.animation.CheckProgress(totalDetailProgress); + serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize)); + chart.RefreshChart(); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Serie/Bar/BarHandler.PolarCoord.cs.meta b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs.meta new file mode 100644 index 00000000..30d890fb --- /dev/null +++ b/Runtime/Serie/Bar/BarHandler.PolarCoord.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 152848d4f7ed84b0491d277fd55b64ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Serie/Bar/BarHandler.cs b/Runtime/Serie/Bar/BarHandler.cs index 5b4558ff..c3c70c0f 100644 --- a/Runtime/Serie/Bar/BarHandler.cs +++ b/Runtime/Serie/Bar/BarHandler.cs @@ -7,7 +7,7 @@ using XUGL; namespace XCharts.Runtime { [UnityEngine.Scripting.Preserve] - internal sealed class BarHandler : SerieHandler + internal sealed partial class BarHandler : SerieHandler { List> m_StackSerieData = new List>(); private GridCoord m_SerieGrid; @@ -16,7 +16,10 @@ namespace XCharts.Runtime public override void Update() { base.Update(); - UpdateSerieContext(); + if (serie.IsUseCoord()) + UpdateSerieGridContext(); + else if (serie.IsUseCoord()) + UpdateSeriePolarContext(); } public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, @@ -29,21 +32,49 @@ namespace XCharts.Runtime public override void DrawSerie(VertexHelper vh) { - DrawBarSerie(vh, serie, serie.context.colorIndex); + if (serie.IsUseCoord()) + { + DrawPolarBar(vh, serie); + } + else if (serie.IsUseCoord()) + { + DrawBarSerie(vh, serie); + } } public override Vector3 GetSerieDataLabelPosition(SerieData serieData, LabelStyle label) { - switch (label.position) + if (serie.IsUseCoord()) { - case LabelStyle.Position.Bottom: - var center = serieData.context.rect.center; - return new Vector3(center.x, center.y - serieData.context.rect.height / 2); - case LabelStyle.Position.Center: - case LabelStyle.Position.Inside: - return serieData.context.rect.center; - default: - return serieData.context.position; + switch (label.position) + { + case LabelStyle.Position.Bottom: + var center = serieData.context.areaCenter; + var angle = serieData.context.halfAngle; + var radius = serieData.context.insideRadius; + return ChartHelper.GetPosition(center, angle, radius); + case LabelStyle.Position.Top: + center = serieData.context.areaCenter; + angle = serieData.context.halfAngle; + radius = serieData.context.outsideRadius; + return ChartHelper.GetPosition(center, angle, radius); + default: + return serieData.context.position; + } + } + else + { + switch (label.position) + { + case LabelStyle.Position.Bottom: + var center = serieData.context.rect.center; + return new Vector3(center.x, center.y - serieData.context.rect.height / 2); + case LabelStyle.Position.Center: + case LabelStyle.Position.Inside: + return serieData.context.rect.center; + default: + return serieData.context.position; + } } } @@ -57,7 +88,7 @@ namespace XCharts.Runtime } } - private void UpdateSerieContext() + private void UpdateSerieGridContext() { if (m_SerieGrid == null) return; @@ -119,7 +150,7 @@ namespace XCharts.Runtime } } - private void DrawBarSerie(VertexHelper vh, Bar serie, int colorIndex) + private void DrawBarSerie(VertexHelper vh, Bar serie) { if (!serie.show || serie.animation.HasFadeOut()) return; @@ -127,14 +158,15 @@ namespace XCharts.Runtime Axis axis; Axis relativedAxis; var isY = chart.GetSerieGridCoordAxis(serie, out axis, out relativedAxis); - m_SerieGrid = chart.GetChartComponent(axis.gridIndex); - if (axis == null) return; if (relativedAxis == null) return; + + m_SerieGrid = chart.GetChartComponent(axis.gridIndex); if (m_SerieGrid == null) return; + var dataZoom = chart.GetDataZoomOfAxis(axis); var showData = serie.GetDataList(dataZoom); diff --git a/Runtime/Serie/Candlestick/Candlestick.cs b/Runtime/Serie/Candlestick/Candlestick.cs index 16da2b14..08ff439c 100644 --- a/Runtime/Serie/Candlestick/Candlestick.cs +++ b/Runtime/Serie/Candlestick/Candlestick.cs @@ -22,7 +22,7 @@ namespace XCharts.Runtime var close = Random.Range(40, 90); var lowest = Random.Range(0, 50); var heighest = Random.Range(50, 100); - chart.AddData(serie.index, open, close, lowest, heighest); + chart.AddData(serie.index, i, open, close, lowest, heighest); } return serie; } diff --git a/Runtime/Serie/Candlestick/CandlestickHandler.cs b/Runtime/Serie/Candlestick/CandlestickHandler.cs index dcbf690c..ab401a92 100644 --- a/Runtime/Serie/Candlestick/CandlestickHandler.cs +++ b/Runtime/Serie/Candlestick/CandlestickHandler.cs @@ -54,7 +54,7 @@ namespace XCharts.Runtime param.columns.Add(string.Empty); paramList.Add(param); - for (int i = 0; i < 4; i++) + for (int i = 1; i < 5; i++) { param = new SerieParams(); param.serieName = serie.serieName; @@ -71,7 +71,7 @@ namespace XCharts.Runtime param.columns.Clear(); param.columns.Add(param.marker); - param.columns.Add(XCSettings.lang.GetCandlestickDimensionName(i)); + param.columns.Add(XCSettings.lang.GetCandlestickDimensionName(i-1)); param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter)); paramList.Add(param); @@ -105,10 +105,11 @@ namespace XCharts.Runtime var isYAxis = false; serie.containerIndex = grid.index; serie.containterInstanceId = grid.instanceId; + var intensive = grid.context.width / (maxCount - serie.minShow) < 0.6f; for (int i = serie.minShow; i < maxCount; i++) { var serieData = showData[i]; - if (serie.IsIgnoreValue(serieData)) + if (!serieData.show || serie.IsIgnoreValue(serieData)) { serie.context.dataPoints.Add(Vector3.zero); serie.context.dataIndexs.Add(serieData.index); @@ -116,10 +117,11 @@ namespace XCharts.Runtime } var state = SerieHelper.GetSerieState(serie, serieData); var itemStyle = SerieHelper.GetItemStyle(serie, serieData, state); - var open = serieData.GetCurrData(0, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); - var close = serieData.GetCurrData(1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); - var lowest = serieData.GetCurrData(2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); - var heighest = serieData.GetCurrData(3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var startDataIndex = serieData.data.Count > 4 ? 1 : 0; + var open = serieData.GetCurrData(startDataIndex, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var close = serieData.GetCurrData(startDataIndex + 1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var lowest = serieData.GetCurrData(startDataIndex + 2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var heighest = serieData.GetCurrData(startDataIndex + 3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); var isRise = yAxis.inverse ? close open; var borderWidth = open == 0 ? 0f : (itemStyle.runtimeBorderWidth == 0 ? theme.serie.candlestickBorderWidth : @@ -169,37 +171,44 @@ namespace XCharts.Runtime var heighPos = new Vector3(center.x, zeroY + (float) ((heighest - minCut) / valueTotal * grid.context.height)); var openCenterPos = new Vector3(center.x, prb.y); var closeCenterPos = new Vector3(center.x, prt.y); - if (barWidth > 2f * borderWidth) + if (intensive) { - if (itemWidth > 0 && itemHeight > 0) + UGL.DrawLine(vh, lowPos, heighPos, borderWidth, borderColor); + } + else + { + if (barWidth > 2f * borderWidth) { - if (itemStyle.IsNeedCorner()) + if (itemWidth > 0 && itemHeight > 0) { - UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaColor, 0, + if (itemStyle.IsNeedCorner()) + { + UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaColor, 0, + itemStyle.cornerRadius, isYAxis, 0.5f); + } + else + { + chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor, + serie.clip, grid); + } + UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0, itemStyle.cornerRadius, isYAxis, 0.5f); } - else - { - chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor, - serie.clip, grid); - } - UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0, - itemStyle.cornerRadius, isYAxis, 0.5f); } - } - else - { - UGL.DrawLine(vh, openCenterPos, closeCenterPos, Mathf.Max(borderWidth, barWidth / 2), borderColor); - } - if (isRise) - { - UGL.DrawLine(vh, openCenterPos, lowPos, borderWidth, borderColor); - UGL.DrawLine(vh, closeCenterPos, heighPos, borderWidth, borderColor); - } - else - { - UGL.DrawLine(vh, closeCenterPos, lowPos, borderWidth, borderColor); - UGL.DrawLine(vh, openCenterPos, heighPos, borderWidth, borderColor); + else + { + UGL.DrawLine(vh, openCenterPos, closeCenterPos, Mathf.Max(borderWidth, barWidth / 2), borderColor); + } + if (isRise) + { + UGL.DrawLine(vh, openCenterPos, lowPos, borderWidth, borderColor); + UGL.DrawLine(vh, closeCenterPos, heighPos, borderWidth, borderColor); + } + else + { + UGL.DrawLine(vh, closeCenterPos, lowPos, borderWidth, borderColor); + UGL.DrawLine(vh, openCenterPos, heighPos, borderWidth, borderColor); + } } } if (!serie.animation.IsFinish()) diff --git a/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs b/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs index 820b00a5..4a8ca1a2 100644 --- a/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs +++ b/Runtime/Serie/Candlestick/SimplifiedCandlestick.cs @@ -25,7 +25,7 @@ namespace XCharts.Runtime var close = lastValue + Random.Range(-5, 10); var lowest = lastValue + Random.Range(-15, -10); var heighest = lastValue + Random.Range(10, 20); - chart.AddData(serie.index, open, close, lowest, heighest); + chart.AddData(serie.index, i, open, close, lowest, heighest); } return serie; } diff --git a/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs b/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs index 8266c6be..7362e142 100644 --- a/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs +++ b/Runtime/Serie/Candlestick/SimplifiedCandlestickHandler.cs @@ -54,7 +54,7 @@ namespace XCharts.Runtime param.columns.Add(string.Empty); paramList.Add(param); - for (int i = 0; i < 4; i++) + for (int i = 1; i < 5; i++) { param = new SerieParams(); param.serieName = serie.serieName; @@ -71,7 +71,7 @@ namespace XCharts.Runtime param.columns.Clear(); param.columns.Add(param.marker); - param.columns.Add(XCSettings.lang.GetCandlestickDimensionName(i)); + param.columns.Add(XCSettings.lang.GetCandlestickDimensionName(i - 1)); param.columns.Add(ChartCached.NumberToStr(param.value, param.numericFormatter)); paramList.Add(param); @@ -106,20 +106,21 @@ namespace XCharts.Runtime var itemStyle = serie.itemStyle; serie.containerIndex = grid.index; serie.containterInstanceId = grid.instanceId; - + var intensive = grid.context.width / (maxCount - serie.minShow) < 0.6f; for (int i = serie.minShow; i < maxCount; i++) { var serieData = showData[i]; - if (serie.IsIgnoreValue(serieData)) + if (!serieData.show || serie.IsIgnoreValue(serieData)) { serie.context.dataPoints.Add(Vector3.zero); serie.context.dataIndexs.Add(serieData.index); continue; } - var open = serieData.GetCurrData(0, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); - var close = serieData.GetCurrData(1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); - var lowest = serieData.GetCurrData(2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); - var heighest = serieData.GetCurrData(3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var startDataIndex = serieData.data.Count > 4 ? 1 : 0; + var open = serieData.GetCurrData(startDataIndex, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var close = serieData.GetCurrData(startDataIndex + 1, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var lowest = serieData.GetCurrData(startDataIndex + 2, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); + var heighest = serieData.GetCurrData(startDataIndex + 3, dataChangeDuration, yAxis.inverse, yMinValue, yMaxValue); var isRise = yAxis.inverse ? close open; var borderWidth = open == 0 ? 0f : (itemStyle.runtimeBorderWidth == 0 ? theme.serie.candlestickBorderWidth : @@ -169,39 +170,45 @@ namespace XCharts.Runtime var heighPos = new Vector3(center.x, zeroY + (float) ((heighest - minCut) / valueTotal * grid.context.height)); var openCenterPos = new Vector3(center.x, prb.y); var closeCenterPos = new Vector3(center.x, prt.y); - if (barWidth > 2f * borderWidth) + if (intensive) { - if (itemWidth > 0 && itemHeight > 0) - { - if (itemStyle.IsNeedCorner()) - { - UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaColor, 0, - itemStyle.cornerRadius, isYAxis, 0.5f); - } - else - { - chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor, - serie.clip, grid); - } - UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0, - itemStyle.cornerRadius, isYAxis, 0.5f); - } - if (isRise) - { - UGL.DrawLine(vh, openCenterPos, lowPos, borderWidth, borderColor); - UGL.DrawLine(vh, closeCenterPos, heighPos, borderWidth, borderColor); - } - else - { - UGL.DrawLine(vh, closeCenterPos, lowPos, borderWidth, borderColor); - UGL.DrawLine(vh, openCenterPos, heighPos, borderWidth, borderColor); - } + UGL.DrawLine(vh, lowPos, heighPos, borderWidth, borderColor); } else { - UGL.DrawLine(vh, openCenterPos, closeCenterPos, Mathf.Max(borderWidth, barWidth / 2), borderColor); + if (barWidth > 2f * borderWidth) + { + if (itemWidth > 0 && itemHeight > 0) + { + if (itemStyle.IsNeedCorner()) + { + UGL.DrawRoundRectangle(vh, center, itemWidth, itemHeight, areaColor, areaColor, 0, + itemStyle.cornerRadius, isYAxis, 0.5f); + } + else + { + chart.DrawClipPolygon(vh, ref prb, ref plb, ref plt, ref prt, areaColor, areaColor, + serie.clip, grid); + } + UGL.DrawBorder(vh, center, itemWidth, itemHeight, 2 * borderWidth, borderColor, 0, + itemStyle.cornerRadius, isYAxis, 0.5f); + } + if (isRise) + { + UGL.DrawLine(vh, openCenterPos, lowPos, borderWidth, borderColor); + UGL.DrawLine(vh, closeCenterPos, heighPos, borderWidth, borderColor); + } + else + { + UGL.DrawLine(vh, closeCenterPos, lowPos, borderWidth, borderColor); + UGL.DrawLine(vh, openCenterPos, heighPos, borderWidth, borderColor); + } + } + else + { + UGL.DrawLine(vh, openCenterPos, closeCenterPos, Mathf.Max(borderWidth, barWidth / 2), borderColor); + } } - } if (!serie.animation.IsFinish()) { diff --git a/Runtime/Serie/Heatmap/Heatmap.cs b/Runtime/Serie/Heatmap/Heatmap.cs index ea1ccd72..91b79855 100644 --- a/Runtime/Serie/Heatmap/Heatmap.cs +++ b/Runtime/Serie/Heatmap/Heatmap.cs @@ -2,29 +2,54 @@ using UnityEngine; namespace XCharts.Runtime { + /// + /// The mapping type of heatmap. + /// |热力图类型。通过颜色映射划分。 + /// + public enum HeatmapType + { + /// + /// Data mapping type.By default, the second dimension data is used as the color map. + /// |数据映射型。默认用第2维数据作为颜色映射。要求数据至少有3个维度数据。 + /// + Data, + /// + /// Number mapping type.The number of occurrences of a statistic in a divided grid, as a color map. + /// |个数映射型。统计数据在划分的格子中出现的次数,作为颜色映射。要求数据至少有2个维度数据。 + /// + Count + } + [System.Serializable] [SerieHandler(typeof(HeatmapHandler), true)] [DefaultAnimation(AnimationType.LeftToRight)] [RequireChartComponent(typeof(VisualMap))] + [CoordOptions(typeof(GridCoord), typeof(PolarCoord))] [SerieExtraComponent(typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField()] public class Heatmap : Serie, INeedSerieContainer { + [SerializeField][Since("3.3.0")] private HeatmapType m_HeatmapType = HeatmapType.Data; + + /// + /// The mapping type of heatmap. + /// |热力图类型。通过颜色映射划分。 + /// + public HeatmapType heatmapType + { + get { return m_HeatmapType; } + set { if (PropertyUtil.SetStruct(ref m_HeatmapType, value)) { SetVerticesDirty(); } } + } public int containerIndex { get; internal set; } public int containterInstanceId { get; internal set; } + public static Serie AddDefaultSerie(BaseChart chart, string serieName) { var serie = chart.AddSerie(serieName); serie.itemStyle.show = true; serie.itemStyle.borderWidth = 1; serie.itemStyle.borderColor = Color.clear; - - var emphasis = serie.AddExtraComponent(); - emphasis.show = true; - emphasis.itemStyle.show = true; - emphasis.itemStyle.borderWidth = 1; - emphasis.itemStyle.borderColor = Color.black; return serie; } } diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs new file mode 100644 index 00000000..c2ed3ffc --- /dev/null +++ b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs @@ -0,0 +1,202 @@ +using UnityEngine; +using UnityEngine.UI; +using XUGL; + +namespace XCharts.Runtime +{ + /// + /// For polar coord + /// + internal sealed partial class HeatmapHandler + { + private PolarCoord m_SeriePolar; + + private void UpdateSeriePolarContext() + { + if (m_SeriePolar == null) + return; + + var needCheck = (chart.isPointerInChart && m_SeriePolar.IsPointerEnter()) || m_LegendEnter; + var lineWidth = 0f; + if (!needCheck) + { + if (m_LastCheckContextFlag != needCheck) + { + var needAnimation1 = false; + lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); + m_LastCheckContextFlag = needCheck; + serie.context.pointerItemDataIndex = -1; + serie.context.pointerEnter = false; + serie.interact.SetValue(ref needAnimation1, lineWidth, false); + foreach (var serieData in serie.data) + { + var symbol = SerieHelper.GetSerieSymbol(serie, serieData); + var symbolSize = symbol.GetSize(serieData.data, chart.theme.serie.lineSymbolSize); + serieData.context.highlight = false; + serieData.interact.SetValue(ref needAnimation1, symbolSize); + } + if (needAnimation1) + { + if (SeriesHelper.IsStack(chart.series)) + chart.RefreshTopPainter(); + else + chart.RefreshPainter(serie); + } + } + return; + } + m_LastCheckContextFlag = needCheck; + var themeSymbolSize = chart.theme.serie.lineSymbolSize; + 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); + for (int i = 0; i < serie.dataCount; i++) + { + var serieData = serie.data[i]; + var size = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, themeSymbolSize, SerieState.Emphasis); + serieData.context.highlight = true; + serieData.interact.SetValue(ref needInteract, size); + } + } + else + { + serie.context.pointerItemDataIndex = -1; + serie.context.pointerEnter = false; + var dir = chart.pointerPos - new Vector2(m_SeriePolar.context.center.x, m_SeriePolar.context.center.y); + var pointerAngle = ChartHelper.GetAngle360(Vector2.up, dir); + var pointerRadius = Vector2.Distance(chart.pointerPos, m_SeriePolar.context.center); + Color32 color, toColor; + for (int i = 0; i < serie.dataCount; i++) + { + var serieData = serie.data[i]; + if (pointerAngle >= serieData.context.startAngle && + pointerAngle < serieData.context.toAngle && + pointerRadius >= serieData.context.insideRadius && + pointerRadius < serieData.context.outsideRadius) + { + serie.context.pointerItemDataIndex = i; + serie.context.pointerEnter = true; + serieData.context.highlight = true; + } + else + { + serieData.context.highlight = false; + } + var state = SerieHelper.GetSerieState(serie, serieData, true); + SerieHelper.GetItemColor(out color, out toColor, serie, serieData, chart.theme, state); + serieData.interact.SetColor(ref needInteract, color, toColor); + } + } + if (needInteract) + { + if (SeriesHelper.IsStack(chart.series)) + chart.RefreshTopPainter(); + else + chart.RefreshPainter(serie); + } + } + + private void DrawPolarHeatmap(VertexHelper vh, Serie serie) + { + var datas = serie.data; + if (datas.Count <= 0) + return; + + m_SeriePolar = chart.GetChartComponent(serie.polarIndex); + if (m_SeriePolar == null) + return; + + var m_AngleAxis = ComponentHelper.GetAngleAxis(chart.components, m_SeriePolar.index); + var m_RadiusAxis = ComponentHelper.GetRadiusAxis(chart.components, m_SeriePolar.index); + if (m_AngleAxis == null || m_RadiusAxis == null) + return; + var visualMap = chart.GetVisualMapOfSerie(serie); + + var startAngle = m_AngleAxis.context.startAngle; + var currDetailProgress = 0f; + var totalDetailProgress = datas.Count; + + var xCount = AxisHelper.GetTotalSplitGridNum(m_RadiusAxis); + var yCount = AxisHelper.GetTotalSplitGridNum(m_AngleAxis); + var xWidth = m_SeriePolar.context.radius / xCount; + var yWidth = 360 / yCount; + + serie.animation.InitProgress(currDetailProgress, totalDetailProgress); + + var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension); + if (visualMap.autoMinMax) + { + double maxValue, minValue; + SerieHelper.GetMinMaxData(serie, dimension, out minValue, out maxValue); + VisualMapHelper.SetMinMax(visualMap, minValue, maxValue); + } + var rangeMin = visualMap.rangeMin; + var rangeMax = visualMap.rangeMax; + var color = chart.theme.GetColor(serie.index); + + float start, end; + float inside, outside; + double value, radiusValue, angleValue; + for (int i = 0; i < datas.Count; i++) + { + if (serie.animation.CheckDetailBreak(i)) + break; + var serieData = datas[i]; + var itemStyle = SerieHelper.GetItemStyle(serie, serieData); + var borderWidth = itemStyle.borderWidth; + var borderColor = itemStyle.borderColor; + + radiusValue = serieData.GetData(0); + angleValue = serieData.GetData(1); + value = serieData.GetData(2); + + var xIndex = AxisHelper.GetAxisValueSplitIndex(m_RadiusAxis, radiusValue, xCount); + var yIndex = AxisHelper.GetAxisValueSplitIndex(m_AngleAxis, angleValue, yCount); + + start = startAngle + yIndex * yWidth; + end = start + yWidth; + + inside = m_SeriePolar.context.insideRadius + xIndex * xWidth; + outside = inside + xWidth; + + serieData.context.startAngle = start; + serieData.context.toAngle = end; + serieData.context.halfAngle = (start + end) / 2; + serieData.context.insideRadius = inside; + serieData.context.outsideRadius = outside; + + if ((value < rangeMin && rangeMin != visualMap.min) || + (value > rangeMax && rangeMax != visualMap.max)) + { + continue; + } + if (!visualMap.IsInSelectedValue(value)) continue; + color = visualMap.GetColor(value); + if (serieData.context.highlight) + color = ChartHelper.GetHighlightColor(color); + + var needRoundCap = serie.roundCap && inside > 0; + + serieData.context.insideRadius = inside; + serieData.context.outsideRadius = outside; + serieData.context.areaCenter = m_SeriePolar.context.center; + serieData.context.position = ChartHelper.GetPosition(m_SeriePolar.context.center, (start + end) / 2, (inside + outside) / 2); + + UGL.DrawDoughnut(vh, m_SeriePolar.context.center, inside, outside, color, color, + ColorUtil.clearColor32, start, end, borderWidth, borderColor, serie.gap / 2, chart.settings.cicleSmoothness, + needRoundCap, true); + } + + if (!serie.animation.IsFinish()) + { + serie.animation.CheckProgress(totalDetailProgress); + serie.animation.CheckSymbol(serie.symbol.GetSize(null, chart.theme.serie.lineSymbolSize)); + chart.RefreshChart(); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs.meta b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs.meta new file mode 100644 index 00000000..e9f8a398 --- /dev/null +++ b/Runtime/Serie/Heatmap/HeatmapHandler.PolarCoord.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: baaa1d070b88a4b9bb7d1eed341041e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Serie/Heatmap/HeatmapHandler.cs b/Runtime/Serie/Heatmap/HeatmapHandler.cs index 806908b2..b3bf9ba4 100644 --- a/Runtime/Serie/Heatmap/HeatmapHandler.cs +++ b/Runtime/Serie/Heatmap/HeatmapHandler.cs @@ -6,21 +6,48 @@ using XUGL; namespace XCharts.Runtime { [UnityEngine.Scripting.Preserve] - internal sealed class HeatmapHandler : SerieHandler + internal sealed partial class HeatmapHandler : SerieHandler { private GridCoord m_SerieGrid; + private Dictionary m_CountDict = new Dictionary(); public override int defaultDimension { get { return 2; } } + public static int GetGridKey(int x, int y) + { + return x * 100000 + y; + } + + public static void GetGridXYByKey(int key, out int x, out int y) + { + x = key / 100000; + y = key % 100000; + } + public override void Update() { base.Update(); - UpdateSerieContext(); + if (serie.IsUseCoord()) + UpdateSerieContext(); + else if (serie.IsUseCoord()) + UpdateSeriePolarContext(); } public override void DrawSerie(VertexHelper vh) { - DrawHeatmapSerie(vh, serie); + if (serie.heatmapType == HeatmapType.Count) + DrawCountHeatmapSerie(vh, serie); + else + { + if (serie.IsUseCoord()) + { + DrawPolarHeatmap(vh, serie); + } + else if (serie.IsUseCoord()) + { + DrawDataHeatmapSerie(vh, serie); + } + } } public override void UpdateTooltipSerieParams(int dataIndex, bool showCategory, string category, @@ -28,39 +55,70 @@ namespace XCharts.Runtime ref List paramList, ref string title) { dataIndex = serie.context.pointerItemDataIndex; - if (dataIndex < 0) - return; - - var serieData = serie.GetSerieData(dataIndex); - if (serieData == null) - return; - - if (string.IsNullOrEmpty(category)) + if (serie.heatmapType == HeatmapType.Count) { - var xAxis = chart.GetChartComponent(serie.xAxisIndex); - if (xAxis != null) - category = xAxis.GetData((int) serieData.GetData(0)); + int value; + if (!m_CountDict.TryGetValue(dataIndex, out value)) return; + var visualMap = chart.GetVisualMapOfSerie(serie); + var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension); + + title = serie.serieName; + + var param = serie.context.param; + param.serieName = serie.serieName; + param.serieIndex = serie.index; + param.dimension = dimension; + param.dataCount = serie.dataCount; + param.serieData = null; + param.color = visualMap.GetColor(value); + param.marker = SerieHelper.GetItemMarker(serie, null, marker); + param.itemFormatter = SerieHelper.GetItemFormatter(serie, null, itemFormatter); + param.numericFormatter = SerieHelper.GetNumericFormatter(serie, null, numericFormatter); + param.columns.Clear(); + + param.columns.Add(param.marker); + param.columns.Add("count"); + param.columns.Add(ChartCached.NumberToStr(value, param.numericFormatter)); + + paramList.Add(param); } + else + { + if (dataIndex < 0) + return; - title = serie.serieName; + var serieData = serie.GetSerieData(dataIndex); + if (serieData == null) + return; + var visualMap = chart.GetVisualMapOfSerie(serie); + var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension); - var param = serie.context.param; - param.serieName = serie.serieName; - param.serieIndex = serie.index; - param.dimension = defaultDimension; - param.dataCount = serie.dataCount; - param.serieData = serieData; - param.color = serieData.context.color; - param.marker = SerieHelper.GetItemMarker(serie, serieData, marker); - param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter); - param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter); - param.columns.Clear(); + if (string.IsNullOrEmpty(category)) + { + var xAxis = chart.GetChartComponent(serie.xAxisIndex); + if (xAxis != null) + category = xAxis.GetData((int) serieData.GetData(0)); + } + title = serie.serieName; - param.columns.Add(param.marker); - param.columns.Add(category); - param.columns.Add(ChartCached.NumberToStr(serieData.GetData(defaultDimension), param.numericFormatter)); + var param = serie.context.param; + param.serieName = serie.serieName; + param.serieIndex = serie.index; + param.dimension = dimension; + param.dataCount = serie.dataCount; + param.serieData = serieData; + param.color = serieData.context.color; + param.marker = SerieHelper.GetItemMarker(serie, serieData, marker); + param.itemFormatter = SerieHelper.GetItemFormatter(serie, serieData, itemFormatter); + param.numericFormatter = SerieHelper.GetNumericFormatter(serie, serieData, numericFormatter); + param.columns.Clear(); - paramList.Add(param); + param.columns.Add(param.marker); + param.columns.Add(category); + param.columns.Add(ChartCached.NumberToStr(serieData.GetData(dimension), param.numericFormatter)); + + paramList.Add(param); + } } private void UpdateSerieContext() @@ -85,6 +143,8 @@ namespace XCharts.Runtime } return; } + if (serie.heatmapType == HeatmapType.Count) + return; m_LastCheckContextFlag = needCheck; if (m_LegendEnter) { @@ -119,9 +179,9 @@ namespace XCharts.Runtime } } - private void DrawHeatmapSerie(VertexHelper vh, Heatmap serie) + private void DrawDataHeatmapSerie(VertexHelper vh, Heatmap serie) { - if (serie.animation.HasFadeOut()) return; + if (!serie.show || serie.animation.HasFadeOut()) return; XAxis xAxis; YAxis yAxis; if (!chart.TryGetChartComponent(out xAxis, serie.xAxisIndex)) return; @@ -131,29 +191,17 @@ namespace XCharts.Runtime yAxis.boundaryGap = true; var visualMap = chart.GetVisualMapOfSerie(serie); var emphasisStyle = serie.emphasisStyle; - var xCount = xAxis.data.Count; - var yCount = yAxis.data.Count; + var xCount = AxisHelper.GetTotalSplitGridNum(xAxis); + var yCount = AxisHelper.GetTotalSplitGridNum(yAxis); var xWidth = m_SerieGrid.context.width / xCount; var yWidth = m_SerieGrid.context.height / yCount; var zeroX = m_SerieGrid.context.x; var zeroY = m_SerieGrid.context.y; - var rangeMin = visualMap.rangeMin; - var rangeMax = visualMap.rangeMax; - var color = chart.theme.GetColor(serie.index); var borderWidth = serie.itemStyle.show ? serie.itemStyle.borderWidth : 0; - var rectWid = xWidth - 2 * borderWidth; - var rectHig = yWidth - 2 * borderWidth; - - var borderColor = serie.itemStyle.opacity > 0 ? - serie.itemStyle.borderColor : - ChartConst.clearColor32; - borderColor.a = (byte) (borderColor.a * serie.itemStyle.opacity); - - var borderToColor = serie.itemStyle.opacity > 0 ? - serie.itemStyle.borderToColor : - ChartConst.clearColor32; - borderToColor.a = (byte) (borderToColor.a * serie.itemStyle.opacity); + var splitWid = xWidth - 2 * borderWidth; + var splitHig = yWidth - 2 * borderWidth; + var defaultSymbolSize = Mathf.Min(splitWid, splitHig) * 0.25f; serie.animation.InitProgress(0, xCount); var animationIndex = serie.animation.GetCurrIndex(); @@ -161,30 +209,48 @@ namespace XCharts.Runtime var dataChanging = false; serie.containerIndex = m_SerieGrid.index; serie.containterInstanceId = m_SerieGrid.instanceId; + + var dimension = VisualMapHelper.GetDimension(visualMap, defaultDimension); + if (visualMap.autoMinMax) + { + double maxValue, minValue; + SerieHelper.GetMinMaxData(serie, dimension, out minValue, out maxValue); + VisualMapHelper.SetMinMax(visualMap, minValue, maxValue); + } + var rangeMin = visualMap.rangeMin; + var rangeMax = visualMap.rangeMax; + var color = chart.theme.GetColor(serie.index); + float symbolBorder = 0f; + float[] cornerRadius = null; + Color32 borderColor; for (int n = 0; n < serie.dataCount; n++) { var serieData = serie.data[n]; - var i = (int) serieData.GetData(0); - var j = (int) serieData.GetData(1); - var dimension = VisualMapHelper.GetDimension(visualMap, serieData.data.Count); + var xValue = serieData.GetData(0); + var yValue = serieData.GetData(1); + var i = AxisHelper.GetAxisValueSplitIndex(xAxis, xValue, xCount); + var j = AxisHelper.GetAxisValueSplitIndex(yAxis, yValue, yCount); + if (serie.IsIgnoreValue(serieData, dimension)) { serie.context.dataPoints.Add(Vector3.zero); serie.context.dataIndexs.Add(serieData.index); continue; } + var state = SerieHelper.GetSerieState(serie, serieData, true); + 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, yAxis.context.minValue, yAxis.context.maxValue); if (serieData.IsDataChanged()) dataChanging = true; - var pos = new Vector3(zeroX + (i + (xAxis.boundaryGap ? 0.5f : 0)) * xWidth, - zeroY + (j + (yAxis.boundaryGap ? 0.5f : 0)) * yWidth); + var pos = new Vector3(zeroX + (i + 0.5f) * xWidth, + zeroY + (j + 0.5f) * yWidth); serie.context.dataPoints.Add(pos); serie.context.dataIndexs.Add(serieData.index); serieData.context.position = pos; - serieData.context.canShowLabel = false; - serieData.context.rect = new Rect(pos.x - rectWid / 2, pos.y - rectHig / 2, rectWid, rectHig); - if (value == 0) continue; + if ((value < rangeMin && rangeMin != visualMap.min) || (value > rangeMax && rangeMax != visualMap.max)) { @@ -201,14 +267,196 @@ namespace XCharts.Runtime var highlight = (serieData.context.highlight) || visualMap.context.pointerIndex > 0; - - //UGL.DrawRectangle(vh, pos, rectWid / 2, rectHig / 2, color); - UGL.DrawRectangle(vh, serieData.context.rect, color); - - if (borderWidth > 0 && !ChartHelper.IsClearColor(borderColor)) + var rectWid = 0f; + var rectHig = 0f; + if (isRectSymbol) { - UGL.DrawBorder(vh, pos, rectWid, rectHig, borderWidth, borderColor, borderToColor); + if (symbol.size == 0 && symbol.sizeType == SymbolSizeType.Custom) + { + rectWid = splitWid; + rectHig = splitHig; + } + else + { + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, defaultSymbolSize, state); + rectWid = symbolSize; + rectHig = symbolSize; + } + serieData.context.rect = new Rect(pos.x - rectWid / 2, pos.y - rectHig / 2, rectWid, rectHig); + UGL.DrawRectangle(vh, serieData.context.rect, color); + + if (borderWidth > 0 && !ChartHelper.IsClearColor(borderColor)) + { + UGL.DrawBorder(vh, pos, rectWid, rectHig, borderWidth, borderColor, borderColor); + } } + else + { + var symbolSize = SerieHelper.GetSysmbolSize(serie, serieData, chart.theme, 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, + color, color, emptyColor, borderColor, symbol.gap, cornerRadius); + } + + if (visualMap.hoverLink && highlight && emphasisStyle != null && + emphasisStyle.itemStyle.borderWidth > 0) + { + var emphasisItemStyle = emphasisStyle.itemStyle; + var emphasisBorderWidth = emphasisItemStyle.borderWidth; + var emphasisBorderColor = emphasisItemStyle.opacity > 0 ? + emphasisItemStyle.borderColor : ChartConst.clearColor32; + var emphasisBorderToColor = emphasisItemStyle.opacity > 0 ? + emphasisItemStyle.borderToColor : ChartConst.clearColor32; + UGL.DrawBorder(vh, pos, rectWid, rectHig, emphasisBorderWidth, emphasisBorderColor, + emphasisBorderToColor); + } + + } + if (!serie.animation.IsFinish()) + { + serie.animation.CheckProgress(xCount); + chart.RefreshPainter(serie); + } + if (dataChanging) + { + chart.RefreshPainter(serie); + } + } + + private void DrawCountHeatmapSerie(VertexHelper vh, Heatmap serie) + { + if (!serie.show || serie.animation.HasFadeOut()) return; + XAxis xAxis; + YAxis yAxis; + if (!chart.TryGetChartComponent(out xAxis, serie.xAxisIndex)) return; + if (!chart.TryGetChartComponent(out yAxis, serie.yAxisIndex)) return; + m_SerieGrid = chart.GetChartComponent(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); + var xWidth = m_SerieGrid.context.width / xCount; + var yWidth = m_SerieGrid.context.height / yCount; + + var zeroX = m_SerieGrid.context.x; + var zeroY = m_SerieGrid.context.y; + var borderWidth = serie.itemStyle.show ? serie.itemStyle.borderWidth : 0; + var splitWid = xWidth - 2 * borderWidth; + var splitHig = yWidth - 2 * borderWidth; + var defaultSymbolSize = Mathf.Min(splitWid, splitHig) * 0.25f; + + serie.animation.InitProgress(0, xCount); + var animationIndex = serie.animation.GetCurrIndex(); + var dataChanging = false; + serie.containerIndex = m_SerieGrid.index; + serie.containterInstanceId = m_SerieGrid.instanceId; + + m_CountDict.Clear(); + double minCount = 0, maxCount = 0; + foreach (var serieData in serie.data) + { + var xValue = serieData.GetData(0); + var yValue = serieData.GetData(1); + var i = AxisHelper.GetAxisValueSplitIndex(xAxis, xValue, xCount); + var j = AxisHelper.GetAxisValueSplitIndex(yAxis, yValue, yCount); + var key = GetGridKey(i, j); + var count = 0; + + if (!m_CountDict.TryGetValue(key, out count)) + count = 1; + else + count++; + if (count > maxCount) + maxCount = count; + m_CountDict[key] = count; + } + + if (visualMap.autoMinMax) + { + VisualMapHelper.SetMinMax(visualMap, minCount, maxCount); + } + var rangeMin = visualMap.rangeMin; + var rangeMax = visualMap.rangeMax; + + int highlightX = -1; + int highlightY = -1; + if (serie.context.pointerItemDataIndex > 0) + { + if (m_CountDict.ContainsKey(serie.context.pointerItemDataIndex)) + { + GetGridXYByKey(serie.context.pointerItemDataIndex, out highlightX, out highlightY); + } + } + 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 isRectSymbol = symbol.type == SymbolType.Rect; + float symbolBorder = 0f; + float[] cornerRadius = null; + Color32 color, toColor, emptyColor, borderColor; + SerieHelper.GetItemColor(out color, out toColor, out emptyColor, serie, null, chart.theme, serie.context.colorIndex, state); + SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, null, chart.theme, state); + foreach (var kv in m_CountDict) + { + int i, j; + GetGridXYByKey(kv.Key, out i, out j); + var value = kv.Value; + + if (serie.IsIgnoreValue(value)) + { + continue; + } + + if ((value < rangeMin && rangeMin != visualMap.min) || + (value > rangeMax && rangeMax != visualMap.max)) + { + continue; + } + if (!visualMap.IsInSelectedValue(value)) + continue; + if (animationIndex >= 0 && i > animationIndex) + continue; + + var highlight = i == highlightX && j == highlightY; + + color = visualMap.GetColor(value); + if (highlight) + color = ChartHelper.GetHighlightColor(color); + + var pos = new Vector3(zeroX + (i + 0.5f) * xWidth, + zeroY + (j + 0.5f) * yWidth); + + var rectWid = 0f; + var rectHig = 0f; + if (isRectSymbol) + { + if (symbol.size == 0 && symbol.sizeType == SymbolSizeType.Custom) + { + rectWid = splitWid; + rectHig = splitHig; + } + else + { + rectWid = symbolSize; + rectHig = symbolSize; + } + var rect = new Rect(pos.x - rectWid / 2, pos.y - rectHig / 2, rectWid, rectHig); + UGL.DrawRectangle(vh, rect, color); + + if (borderWidth > 0 && !ChartHelper.IsClearColor(borderColor)) + { + UGL.DrawBorder(vh, pos, rectWid, rectHig, borderWidth, borderColor, borderColor); + } + } + else + { + chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, pos, + color, color, emptyColor, borderColor, symbol.gap, cornerRadius); + } + if (visualMap.hoverLink && highlight && emphasisStyle != null && emphasisStyle.itemStyle.borderWidth > 0) { diff --git a/Runtime/Serie/Line/LineHandler.GridCoord.cs b/Runtime/Serie/Line/LineHandler.GridCoord.cs index c3760d1c..d5364dc5 100644 --- a/Runtime/Serie/Line/LineHandler.GridCoord.cs +++ b/Runtime/Serie/Line/LineHandler.GridCoord.cs @@ -185,7 +185,7 @@ namespace XCharts.Runtime float symbolBorder = 0f; float[] cornerRadius = null; Color32 symbolColor, symbolToColor, symbolEmptyColor, borderColor; - SerieHelper.GetItemColor(out symbolColor, out symbolToColor, out symbolEmptyColor, serie, serieData, theme, serie.index); + SerieHelper.GetItemColor(out symbolColor, out symbolToColor, out symbolEmptyColor, serie, serieData, theme, serie.context.colorIndex); SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, null, chart.theme, state); if (isVisualMapGradient) { @@ -213,7 +213,7 @@ namespace XCharts.Runtime if (serie.context.dataPoints.Count < 2) return; - var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.index); + var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.context.colorIndex); var startPos = Vector3.zero; var arrowPos = Vector3.zero; var lineArrow = serie.lineArrow.arrow; @@ -248,8 +248,6 @@ namespace XCharts.Runtime private void DrawLineSerie(VertexHelper vh, Line serie) { - if (!serie.show) - return; if (serie.animation.HasFadeOut()) return; @@ -372,14 +370,12 @@ namespace XCharts.Runtime float xPos, yPos; var gridXY = isY ? grid.context.x : grid.context.y; var valueHig = 0f; + valueHig = AxisHelper.GetAxisValueDistance(grid, relativedAxis, scaleWid, yValue); + valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig); if (isY) { - valueHig = AxisHelper.GetAxisValueDistance(grid, relativedAxis, scaleWid, yValue); - valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig); - xPos = gridXY + valueHig; yPos = AxisHelper.GetAxisValuePosition(grid, axis, scaleWid, xValue); - if (isStack) { for (int n = 0; n < m_StackSerieData.Count - 1; n++) @@ -388,13 +384,8 @@ namespace XCharts.Runtime } else { - - valueHig = AxisHelper.GetAxisValueDistance(grid, relativedAxis, scaleWid, yValue); - valueHig = AnimationStyleHelper.CheckDataAnimation(chart, serie, i, valueHig); - yPos = gridXY + valueHig; xPos = AxisHelper.GetAxisValuePosition(grid, axis, scaleWid, xValue); - if (isStack) { for (int n = 0; n < m_StackSerieData.Count - 1; n++) @@ -402,7 +393,7 @@ namespace XCharts.Runtime } } np = new Vector3(xPos, yPos); - return valueHig; + return AxisHelper.GetAxisValueLength(grid, relativedAxis, scaleWid, yValue); } } } \ No newline at end of file diff --git a/Runtime/Serie/Line/LineHandler.PolarCoord.cs b/Runtime/Serie/Line/LineHandler.PolarCoord.cs index 9b1c5ae9..1c34e96a 100644 --- a/Runtime/Serie/Line/LineHandler.PolarCoord.cs +++ b/Runtime/Serie/Line/LineHandler.PolarCoord.cs @@ -111,14 +111,10 @@ namespace XCharts.Runtime return; var startAngle = m_AngleAxis.startAngle; - var radius = m_SeriePolar.context.radius; - - var min = m_RadiusAxis.context.minValue; - var max = m_RadiusAxis.context.maxValue; var firstSerieData = datas[0]; - var lp = GetPolarPos(m_SeriePolar, m_AngleAxis, firstSerieData, min, max, radius); + var lp = PolarHelper.UpdatePolarAngleAndPos(m_SeriePolar, m_AngleAxis, m_RadiusAxis, firstSerieData); var cp = Vector3.zero; - var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.index); + var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.context.colorIndex); var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); var currDetailProgress = 0f; var totalDetailProgress = datas.Count; @@ -134,53 +130,69 @@ namespace XCharts.Runtime var clp = Vector3.zero; var crp = Vector3.zero; bool bitp = true, bibp = true; - for (int i = 1; i < datas.Count; i++) + if (datas.Count <= 2) { - if (serie.animation.CheckDetailBreak(i)) - break; - - var serieData = datas[i]; - - cp = GetPolarPos(m_SeriePolar, m_AngleAxis, datas[i], min, max, radius); - var np = i == datas.Count - 1 ? cp : - GetPolarPos(m_SeriePolar, m_AngleAxis, datas[i + 1], min, max, radius); - - UGLHelper.GetLinePoints(lp, cp, np, lineWidth, - ref ltp, ref lbp, - ref ntp, ref nbp, - ref itp, ref ibp, - ref clp, ref crp, - ref bitp, ref bibp, i); - - if (i == 1) + for (int i = 0; i < datas.Count; i++) { - UGL.AddVertToVertexHelper(vh, ltp, lbp, lineColor, false); + var serieData = datas[i]; + cp = PolarHelper.UpdatePolarAngleAndPos(m_SeriePolar, m_AngleAxis, m_RadiusAxis, datas[i]); + serieData.context.position = cp; + serie.context.dataPoints.Add(cp); } - - if (bitp == bibp) + UGL.DrawLine(vh, serie.context.dataPoints, lineWidth, lineColor, false, false); + } + else + { + for (int i = 1; i < datas.Count; i++) { - if (bitp) - UGL.AddVertToVertexHelper(vh, itp, ibp, lineColor, true); + if (serie.animation.CheckDetailBreak(i)) + break; + + var serieData = datas[i]; + cp = PolarHelper.UpdatePolarAngleAndPos(m_SeriePolar, m_AngleAxis, m_RadiusAxis, datas[i]); + serieData.context.position = cp; + serie.context.dataPoints.Add(cp); + + var np = i == datas.Count - 1 ? cp : + PolarHelper.UpdatePolarAngleAndPos(m_SeriePolar, m_AngleAxis, m_RadiusAxis, datas[i + 1]); + + UGLHelper.GetLinePoints(lp, cp, np, lineWidth, + ref ltp, ref lbp, + ref ntp, ref nbp, + ref itp, ref ibp, + ref clp, ref crp, + ref bitp, ref bibp, i); + + if (i == 1) + { + UGL.AddVertToVertexHelper(vh, ltp, lbp, lineColor, false); + } + + if (bitp == bibp) + { + if (bitp) + UGL.AddVertToVertexHelper(vh, itp, ibp, lineColor, true); + else + { + UGL.AddVertToVertexHelper(vh, ltp, clp, lineColor, true); + UGL.AddVertToVertexHelper(vh, ltp, crp, lineColor, true); + } + } else { - UGL.AddVertToVertexHelper(vh, ltp, clp, lineColor, true); - UGL.AddVertToVertexHelper(vh, ltp, crp, lineColor, true); + if (bitp) + { + UGL.AddVertToVertexHelper(vh, itp, clp, lineColor, true); + UGL.AddVertToVertexHelper(vh, itp, crp, lineColor, true); + } + else if (bibp) + { + UGL.AddVertToVertexHelper(vh, clp, ibp, lineColor, true); + UGL.AddVertToVertexHelper(vh, crp, ibp, lineColor, true); + } } + lp = cp; } - else - { - if (bitp) - { - UGL.AddVertToVertexHelper(vh, itp, clp, lineColor, true); - UGL.AddVertToVertexHelper(vh, itp, crp, lineColor, true); - } - else if (bibp) - { - UGL.AddVertToVertexHelper(vh, clp, ibp, lineColor, true); - UGL.AddVertToVertexHelper(vh, crp, ibp, lineColor, true); - } - } - lp = cp; } if (!serie.animation.IsFinish()) @@ -191,6 +203,46 @@ namespace XCharts.Runtime } } + private void DrawPolarLineArrow(VertexHelper vh, Serie serie) + { + if (!serie.show || serie.lineArrow == null || !serie.lineArrow.show) + return; + + if (serie.context.dataPoints.Count < 2) + return; + + var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.context.colorIndex); + var startPos = Vector3.zero; + var arrowPos = Vector3.zero; + var lineArrow = serie.lineArrow.arrow; + var dataPoints = serie.context.dataPoints; + switch (serie.lineArrow.position) + { + case LineArrow.Position.End: + if (dataPoints.Count < 3) + { + startPos = dataPoints[dataPoints.Count - 2]; + arrowPos = dataPoints[dataPoints.Count - 1]; + } + else + { + startPos = dataPoints[dataPoints.Count - 3]; + arrowPos = dataPoints[dataPoints.Count - 2]; + } + UGL.DrawArrow(vh, startPos, arrowPos, lineArrow.width, lineArrow.height, + lineArrow.offset, lineArrow.dent, lineArrow.GetColor(lineColor)); + + break; + + case LineArrow.Position.Start: + startPos = dataPoints[1]; + arrowPos = dataPoints[0]; + UGL.DrawArrow(vh, startPos, arrowPos, lineArrow.width, lineArrow.height, + lineArrow.offset, lineArrow.dent, lineArrow.GetColor(lineColor)); + break; + } + } + private void DrawPolarLineSymbol(VertexHelper vh) { for (int n = 0; n < chart.series.Count; n++) @@ -227,29 +279,5 @@ namespace XCharts.Runtime } } } - - private Vector3 GetPolarPos(PolarCoord m_Polar, AngleAxis m_AngleAxis, SerieData serieData, double min, - double max, float polarRadius) - { - var angle = 0f; - - if (!m_AngleAxis.clockwise) - { - angle = m_AngleAxis.GetValueAngle((float) serieData.GetData(1)); - } - else - { - angle = m_AngleAxis.GetValueAngle((float) serieData.GetData(1)); - } - - var value = serieData.GetData(0); - var radius = (float) ((value - min) / (max - min) * polarRadius); - - angle = (angle + 360) % 360; - serieData.context.angle = angle; - serieData.context.position = ChartHelper.GetPos(m_Polar.context.center, radius, angle, true); - - return serieData.context.position; - } } } \ No newline at end of file diff --git a/Runtime/Serie/Line/LineHandler.cs b/Runtime/Serie/Line/LineHandler.cs index 9d9efa1a..10a5c5be 100644 --- a/Runtime/Serie/Line/LineHandler.cs +++ b/Runtime/Serie/Line/LineHandler.cs @@ -35,6 +35,7 @@ namespace XCharts.Runtime { DrawPolarLine(vh, serie); DrawPolarLineSymbol(vh); + DrawPolarLineArrow(vh, serie); } else if (serie.IsUseCoord()) { diff --git a/Runtime/Serie/Parallel/Parallel.cs b/Runtime/Serie/Parallel/Parallel.cs index 721f9f91..09b65279 100644 --- a/Runtime/Serie/Parallel/Parallel.cs +++ b/Runtime/Serie/Parallel/Parallel.cs @@ -6,7 +6,8 @@ namespace XCharts.Runtime [System.Serializable] [SerieHandler(typeof(ParallelHandler), true)] [RequireChartComponent(typeof(ParallelCoord))] - [SerieDataExtraComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] + [SerieExtraComponent(typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] + [SerieDataExtraComponent(typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField()] public class Parallel : Serie, INeedSerieContainer { diff --git a/Runtime/Serie/Parallel/ParallelHandler.cs b/Runtime/Serie/Parallel/ParallelHandler.cs index c126f576..26a5be3b 100644 --- a/Runtime/Serie/Parallel/ParallelHandler.cs +++ b/Runtime/Serie/Parallel/ParallelHandler.cs @@ -8,8 +8,6 @@ namespace XCharts.Runtime [UnityEngine.Scripting.Preserve] internal sealed class ParallelHandler : SerieHandler { - private List m_Points = new List(); - public override void Update() { base.Update(); @@ -38,7 +36,7 @@ namespace XCharts.Runtime var animationIndex = serie.animation.GetCurrIndex(); var isHorizonal = parallel.orient == Orient.Horizonal; - var lineColor = SerieHelper.GetLineColor(serie, null, chart.theme, serie.context.colorIndex); + var lineWidth = serie.lineStyle.GetWidth(chart.theme.serie.lineWidth); float currDetailProgress = !isHorizonal ? @@ -58,9 +56,11 @@ namespace XCharts.Runtime var isSmooth = serie.lineType == LineType.Smooth; foreach (var serieData in serie.data) { - m_Points.Clear(); var count = Mathf.Min(axisCount, serieData.data.Count); var lp = Vector3.zero; + var colorIndex = serie.colorByData?serieData.index : serie.context.colorIndex; + var lineColor = SerieHelper.GetLineColor(serie, serieData, chart.theme, colorIndex); + serieData.context.dataPoints.Clear(); for (int i = 0; i < count; i++) { if (animationIndex >= 0 && i > animationIndex) continue; @@ -69,11 +69,11 @@ namespace XCharts.Runtime { if (isSmooth) { - m_Points.Add(pos); + serieData.context.dataPoints.Add(pos); } else if (pos.x <= currProgress) { - m_Points.Add(pos); + serieData.context.dataPoints.Add(pos); } else { @@ -82,9 +82,9 @@ namespace XCharts.Runtime var intersectionPos = Vector3.zero; if (UGLHelper.GetIntersection(lp, pos, currProgressStart, currProgressEnd, ref intersectionPos)) - m_Points.Add(intersectionPos); + serieData.context.dataPoints.Add(intersectionPos); else - m_Points.Add(pos); + serieData.context.dataPoints.Add(pos); break; } } @@ -92,11 +92,11 @@ namespace XCharts.Runtime { if (isSmooth) { - m_Points.Add(pos); + serieData.context.dataPoints.Add(pos); } else if (pos.y <= currProgress) { - m_Points.Add(pos); + serieData.context.dataPoints.Add(pos); } else { @@ -105,21 +105,21 @@ namespace XCharts.Runtime var intersectionPos = Vector3.zero; if (UGLHelper.GetIntersection(lp, pos, currProgressStart, currProgressEnd, ref intersectionPos)) - m_Points.Add(intersectionPos); + serieData.context.dataPoints.Add(intersectionPos); else - m_Points.Add(pos); + serieData.context.dataPoints.Add(pos); break; } } lp = pos; } if (isSmooth) - UGL.DrawCurves(vh, m_Points, lineWidth, lineColor, + UGL.DrawCurves(vh, serieData.context.dataPoints, lineWidth, lineColor, chart.settings.lineSmoothStyle, chart.settings.lineSmoothness, UGL.Direction.XAxis, currProgress, isHorizonal); else - UGL.DrawLine(vh, m_Points, lineWidth, lineColor, isSmooth); + UGL.DrawLine(vh, serieData.context.dataPoints, lineWidth, lineColor, isSmooth); } if (!serie.animation.IsFinish()) { diff --git a/Runtime/Serie/Pie/PieHandler.cs b/Runtime/Serie/Pie/PieHandler.cs index 966ebe01..3be3b1c9 100644 --- a/Runtime/Serie/Pie/PieHandler.cs +++ b/Runtime/Serie/Pie/PieHandler.cs @@ -123,6 +123,10 @@ namespace XCharts.Runtime serieData.context.highlight = false; serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); } + if (chart.onPointerEnterPie != null) + { + chart.onPointerEnterPie(serie.index, serie.context.pointerItemDataIndex); + } if (needInteract) { chart.RefreshPainter(serie); @@ -131,8 +135,9 @@ namespace XCharts.Runtime return; } m_LastCheckContextFlag = needCheck; - serie.context.pointerItemDataIndex = -1; + var lastPointerItemDataIndex = serie.context.pointerItemDataIndex; var dataIndex = GetPiePosIndex(serie, chart.pointerPos); + serie.context.pointerItemDataIndex = -1; for (int i = 0; i < serie.dataCount; i++) { var serieData = serie.data[i]; @@ -154,6 +159,14 @@ namespace XCharts.Runtime serieData.interact.SetValueAndColor(ref needInteract, serieData.context.outsideRadius, color, toColor); } } + if (lastPointerItemDataIndex != serie.context.pointerItemDataIndex) + { + needInteract = true; + if (chart.onPointerEnterPie != null) + { + chart.onPointerEnterPie(serie.index, serie.context.pointerItemDataIndex); + } + } if (needInteract) { chart.RefreshPainter(serie); diff --git a/Runtime/Serie/Radar/Radar.cs b/Runtime/Serie/Radar/Radar.cs index 924669e4..4aa23261 100644 --- a/Runtime/Serie/Radar/Radar.cs +++ b/Runtime/Serie/Radar/Radar.cs @@ -25,7 +25,7 @@ namespace XCharts.Runtime public int containerIndex { get; internal set; } public int containterInstanceId { get; internal set; } - public override SerieColorBy defaultColorBy { get { return radarType == RadarType.Multiple?SerieColorBy.Serie : SerieColorBy.Data; } } + public override SerieColorBy defaultColorBy { get { return radarType == RadarType.Multiple?SerieColorBy.Data : SerieColorBy.Serie; } } public override bool multiDimensionLabel { get { return radarType == RadarType.Multiple; } } public static Serie AddDefaultSerie(BaseChart chart, string serieName) diff --git a/Runtime/Serie/Radar/RadarHandler.cs b/Runtime/Serie/Radar/RadarHandler.cs index c01e80bf..73ad790f 100644 --- a/Runtime/Serie/Radar/RadarHandler.cs +++ b/Runtime/Serie/Radar/RadarHandler.cs @@ -320,7 +320,6 @@ namespace XCharts.Runtime serieData.interact.SetValue(ref interacting, symbolSize); symbolSize = serie.animation.GetSysmbolSize(symbolSize); } - colorIndex = serie.colorByData ? m : colorIndex; SerieHelper.GetItemColor(out symbolColor, out symbolToColor, out symbolEmptyColor, serie, serieData, chart.theme, colorIndex, serieState); SerieHelper.GetSymbolInfo(out borderColor, out symbolBorder, out cornerRadius, serie, serieData, chart.theme, serieState); chart.DrawSymbol(vh, symbol.type, symbolSize, symbolBorder, point, symbolColor, diff --git a/Runtime/Serie/Ring/Ring.cs b/Runtime/Serie/Ring/Ring.cs index 658bd596..6610cdd2 100644 --- a/Runtime/Serie/Ring/Ring.cs +++ b/Runtime/Serie/Ring/Ring.cs @@ -4,8 +4,8 @@ namespace XCharts.Runtime { [System.Serializable] [SerieHandler(typeof(RingHandler), true)] - [SerieExtraComponent(typeof(LabelStyle), typeof(TitleStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] - [SerieDataExtraComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(TitleStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] + [SerieExtraComponent(typeof(LabelStyle), typeof(LabelLine), typeof(TitleStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] + [SerieDataExtraComponent(typeof(ItemStyle), typeof(LabelStyle), typeof(LabelLine), typeof(TitleStyle), typeof(EmphasisStyle), typeof(BlurStyle), typeof(SelectStyle))] [SerieDataExtraField()] public class Ring : Serie { diff --git a/Runtime/Serie/Ring/RingHandler.cs b/Runtime/Serie/Ring/RingHandler.cs index c4a87e25..c90a7db3 100644 --- a/Runtime/Serie/Ring/RingHandler.cs +++ b/Runtime/Serie/Ring/RingHandler.cs @@ -113,6 +113,7 @@ namespace XCharts.Runtime 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; @@ -123,7 +124,17 @@ namespace XCharts.Runtime var px1 = Mathf.Sin(startAngle * Mathf.Deg2Rad) * centerRadius; var py1 = Mathf.Cos(startAngle * Mathf.Deg2Rad) * centerRadius; var xDiff = serie.clockwise ? -label.distance : label.distance; - serieData.context.labelPosition = serie.context.center + new Vector3(px1 + xDiff, py1); + + 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: @@ -131,15 +142,39 @@ namespace XCharts.Runtime toAngle += serie.clockwise ? label.distance : -label.distance; var px2 = Mathf.Sin(toAngle * Mathf.Deg2Rad) * centerRadius; var py2 = Mathf.Cos(toAngle * Mathf.Deg2Rad) * centerRadius; - serieData.context.labelPosition = serie.context.center + new Vector3(px2, py2); + + 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.labelPosition = serie.context.center + label.offset; + 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) + { + 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; + return pos5 + labelLine.GetEndSymbolOffset(); + } + public override void DrawSerie(VertexHelper vh) { if (!serie.show || serie.animation.HasFadeOut()) return; @@ -169,8 +204,8 @@ namespace XCharts.Runtime var borderColor = itemStyle.borderColor; var roundCap = serie.roundCap && insideRadius > 0; - serieData.context.startAngle = serie.clockwise ? startDegree : toDegree; - serieData.context.toAngle = serie.clockwise ? toDegree : startDegree; + serieData.context.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); @@ -178,6 +213,12 @@ namespace XCharts.Runtime Color.clear, startDegree, toDegree, borderWidth, borderColor, 0, chart.settings.cicleSmoothness, roundCap, serie.clockwise); DrawCenter(vh, serie, serieData, insideRadius, j == data.Count - 1); + + var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); + if (SerieLabelHelper.CanShowLabel(serie, serieData, serieLabel, 0)) + { + DrawRingLabelLine(vh, serie, serieData, itemColor); + } } if (!serie.animation.IsFinish()) { @@ -304,8 +345,7 @@ namespace XCharts.Runtime var serieData = serie.data[i]; if (dist >= serieData.context.insideRadius && dist <= serieData.context.outsideRadius && - angle >= serieData.context.startAngle && - angle <= serieData.context.toAngle) + IsInAngle(serieData, angle, serie.clockwise)) { return i; } @@ -313,6 +353,14 @@ namespace XCharts.Runtime return -1; } + private bool IsInAngle(SerieData serieData, float angle, bool clockwise) + { + if (clockwise) + return angle >= serieData.context.startAngle && angle <= serieData.context.toAngle; + else + return angle >= serieData.context.toAngle && angle <= serieData.context.startAngle; + } + private float VectorAngle(Vector2 from, Vector2 to) { float angle; @@ -323,5 +371,57 @@ namespace XCharts.Runtime angle = (angle + 360) % 360; return angle; } + + private void DrawRingLabelLine(VertexHelper vh, Serie serie, SerieData serieData, Color32 defaltColor) + { + var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); + var labelLine = SerieHelper.GetSerieLabelLine(serie, serieData); + if (serieLabel != null && serieLabel.show && + labelLine != null && labelLine.show) + { + var color = ChartHelper.IsClearColor(labelLine.lineColor) ? + 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; + switch (labelLine.lineType) + { + case LabelLine.LineType.BrokenLine: + UGL.DrawLine(vh, pos1, pos2, pos5, labelLine.lineWidth, color); + break; + case LabelLine.LineType.Curves: + UGL.DrawCurves(vh, pos1, pos5, pos1, pos2, labelLine.lineWidth, color, + chart.settings.lineSmoothness, 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; + } + if (labelLine.startSymbol != null && labelLine.startSymbol.show) + { + DrawSymbol(vh, labelLine.startSymbol, pos1, color); + } + if (labelLine.endSymbol != null && labelLine.endSymbol.show) + { + DrawSymbol(vh, labelLine.endSymbol, pos5, color); + } + } + } + + private void DrawSymbol(VertexHelper vh, SymbolStyle symbol, Vector3 pos, Color32 defaultColor) + { + var color = symbol.GetColor(defaultColor); + chart.DrawSymbol(vh, symbol.type, symbol.size, 1, pos, + color, color, ColorUtil.clearColor32, color, symbol.gap, null); + } } } \ No newline at end of file diff --git a/Runtime/Serie/Scatter/BaseScatterHandler.cs b/Runtime/Serie/Scatter/BaseScatterHandler.cs index 0d9be98f..8d8f0220 100644 --- a/Runtime/Serie/Scatter/BaseScatterHandler.cs +++ b/Runtime/Serie/Scatter/BaseScatterHandler.cs @@ -12,6 +12,7 @@ namespace XCharts.Runtime public override void Update() { + base.Update(); UpdateSerieContext(); } diff --git a/Runtime/Serie/Serie.cs b/Runtime/Serie/Serie.cs index 151e9fb9..c5e193ad 100644 --- a/Runtime/Serie/Serie.cs +++ b/Runtime/Serie/Serie.cs @@ -1296,11 +1296,12 @@ namespace XCharts.Runtime /// /// the unique id of data /// - public SerieData AddData(double open, double close, double lowest, double heighest, string dataName = null, string dataId = null) + public SerieData AddData(double indexOrTimestamp, double open, double close, double lowest, double heighest, string dataName = null, string dataId = null) { CheckMaxCache(); var serieData = SerieDataPool.Get(); serieData.data.Clear(); + serieData.data.Add(indexOrTimestamp); serieData.data.Add(open); serieData.data.Add(close); serieData.data.Add(lowest); @@ -1309,7 +1310,7 @@ namespace XCharts.Runtime serieData.index = m_Data.Count; serieData.id = dataId; AddSerieData(serieData); - m_ShowDataDimension = 4; + m_ShowDataDimension = 5; SetVerticesDirty(); CheckDataName(dataName); labelDirty = true; @@ -1683,6 +1684,7 @@ namespace XCharts.Runtime public float GetBarWidth(float categoryWidth, int barCount = 0) { + if (categoryWidth < 2) return categoryWidth; if (m_BarWidth == 0) { var width = ChartHelper.GetActualValue(0.6f, categoryWidth); diff --git a/Runtime/Serie/SerieData.cs b/Runtime/Serie/SerieData.cs index bd43a936..0b0e10bd 100644 --- a/Runtime/Serie/SerieData.cs +++ b/Runtime/Serie/SerieData.cs @@ -478,6 +478,23 @@ namespace XCharts.Runtime return temp; } + public void GetMinMaxData(int startDimensionIndex, bool inverse, out double min, out double max) + { + if (m_Data.Count == 0) + { + min = 0; + max = 0; + } + min = double.MaxValue; + max = double.MinValue; + for (int i = startDimensionIndex; i < m_Data.Count; i++) + { + var value = GetData(i, inverse); + if (value < min) min = value; + if (value > max) max = value; + } + } + public double GetTotalData() { var total = 0d; diff --git a/Runtime/Serie/SerieDataContext.cs b/Runtime/Serie/SerieDataContext.cs index d2bdf499..f549c9f9 100644 --- a/Runtime/Serie/SerieDataContext.cs +++ b/Runtime/Serie/SerieDataContext.cs @@ -7,6 +7,7 @@ namespace XCharts.Runtime public class SerieDataContext { public Vector3 labelPosition; + public Vector3 labelLinePosition; /// /// 开始角度 /// diff --git a/Runtime/Serie/SerieHandler.cs b/Runtime/Serie/SerieHandler.cs index 520fe7c6..0b8a53fb 100644 --- a/Runtime/Serie/SerieHandler.cs +++ b/Runtime/Serie/SerieHandler.cs @@ -239,7 +239,7 @@ namespace XCharts.Runtime if (count == -1) count = serie.dataCount; var serieLabel = SerieHelper.GetSerieLabel(serie, serieData); - if (serieLabel == null || !serieLabel.show) + if (serieLabel == null) { return false; } @@ -401,7 +401,7 @@ namespace XCharts.Runtime SerieLabelHelper.GetFormatterContent(serie, serieData, value, total, currLabel, color); var offset = GetSerieDataLabelOffset(serieData, currLabel); - labelObject.SetActive(!isIgnore); + labelObject.SetActive(currLabel.show && !isIgnore); labelObject.SetText(content); labelObject.SetPosition(serieData.context.dataPoints[i] + offset); labelObject.UpdateIcon(currLabel.icon); @@ -422,7 +422,7 @@ namespace XCharts.Runtime ChartCached.NumberToStr(value, currLabel.numericFormatter) : SerieLabelHelper.GetFormatterContent(serie, serieData, value, total, currLabel, color); - serieData.SetLabelActive(!isIgnore); + serieData.SetLabelActive(currLabel.show && !isIgnore); serieData.labelObject.UpdateIcon(currLabel.icon); serieData.labelObject.SetText(content); UpdateLabelPosition(serieData, currLabel); @@ -448,7 +448,7 @@ namespace XCharts.Runtime var endLabelStyle = serie.endLabel; if (endLabelStyle == null) return; - var dataCount = serie.context.drawPoints.Count; + var dataCount = serie.context.dataPoints.Count; var active = endLabelStyle.show && dataCount > 0; m_EndLabel.SetActive(active); if (active) diff --git a/Runtime/Serie/SerieHelper.cs b/Runtime/Serie/SerieHelper.cs index ea5cff22..3e4e52c5 100644 --- a/Runtime/Serie/SerieHelper.cs +++ b/Runtime/Serie/SerieHelper.cs @@ -144,6 +144,11 @@ namespace XCharts.Runtime } } } + if (min == double.MaxValue && max == double.MinValue) + { + min = 0; + max = 0; + } } /// @@ -180,6 +185,11 @@ namespace XCharts.Runtime } } } + if (min == double.MaxValue && max == double.MinValue) + { + min = 0; + max = 0; + } } /// @@ -433,7 +443,7 @@ namespace XCharts.Runtime else { var stateStyle = GetStateStyle(serie, serieData, state); - return stateStyle == null?serie.itemStyle : stateStyle.itemStyle; + return stateStyle == null || !stateStyle.show ? serie.itemStyle : stateStyle.itemStyle; } } @@ -447,7 +457,7 @@ namespace XCharts.Runtime else { var stateStyle = GetStateStyle(serie, serieData, state); - return stateStyle == null?serie.label : stateStyle.label; + return stateStyle == null || !stateStyle.show ? serie.label : stateStyle.label; } } @@ -461,7 +471,7 @@ namespace XCharts.Runtime else { var stateStyle = GetStateStyle(serie, serieData, state); - return stateStyle == null?serie.labelLine : stateStyle.labelLine; + return stateStyle == null || !stateStyle.show ? serie.labelLine : stateStyle.labelLine; } } @@ -475,7 +485,7 @@ namespace XCharts.Runtime else { var stateStyle = GetStateStyle(serie, serieData, state); - return stateStyle == null?serie.symbol : stateStyle.symbol; + return stateStyle == null || !stateStyle.show ? serie.symbol : stateStyle.symbol; } } @@ -533,7 +543,7 @@ namespace XCharts.Runtime Serie serie, SerieData serieData, ThemeStyle theme, int index) { bool fill; - return GetAreaColor(out color, out toColor, out fill,serie, serieData, theme, index); + return GetAreaColor(out color, out toColor, out fill, serie, serieData, theme, index); } public static bool GetAreaColor(out Color32 color, out Color32 toColor, out bool innerFill, @@ -669,7 +679,7 @@ namespace XCharts.Runtime if (stateStyle == null) { var symbol = GetSerieSymbol(serie, serieData, SerieState.Normal); - size = symbol.GetSize(serieData.data, defaultSize); + size = symbol.GetSize(serieData == null? null : serieData.data, defaultSize); switch (state) { case SerieState.Emphasis: @@ -683,7 +693,7 @@ namespace XCharts.Runtime else { var symbol = stateStyle.symbol; - size = symbol.GetSize(serieData.data, defaultSize); + size = symbol.GetSize(serieData == null? null : serieData.data, defaultSize); } return size; } @@ -821,13 +831,13 @@ namespace XCharts.Runtime int start = 0, end = 0; if (dataZoom.context.invert) { - end = Mathf.CeilToInt(data.Count * dataZoom.end / 100); + end = Mathf.RoundToInt(data.Count * dataZoom.end / 100); start = end - range; if (start < 0) start = 0; } else { - start = Mathf.FloorToInt(data.Count * dataZoom.start / 100); + start = Mathf.RoundToInt(data.Count * dataZoom.start / 100); end = start + range; if (end > data.Count) end = data.Count; } @@ -845,8 +855,8 @@ namespace XCharts.Runtime if (dataZoom.minShowNum > data.Count) range = data.Count; else range = dataZoom.minShowNum; } - if (range > data.Count - start - 1) - start = data.Count - range - 1; + if (range > data.Count - start) + start = data.Count - range; if (start >= 0) { serie.context.dataZoomStartIndex = start; diff --git a/Runtime/Serie/SeriesHelper.cs b/Runtime/Serie/SeriesHelper.cs index a4fd0e6e..d3e9c244 100644 --- a/Runtime/Serie/SeriesHelper.cs +++ b/Runtime/Serie/SeriesHelper.cs @@ -300,10 +300,10 @@ namespace XCharts.Runtime /// /// /// - public static void GetXMinMaxValue(List series, DataZoom dataZoom, int axisIndex, bool isValueAxis, - bool inverse, out double minVaule, out double maxValue, bool isPolar = false) + public static void GetXMinMaxValue(BaseChart chart, int axisIndex, bool isValueAxis, + bool inverse, out double minVaule, out double maxValue, bool isPolar = false, bool filterByDataZoom = true) { - GetMinMaxValue(series, dataZoom, axisIndex, isValueAxis, inverse, false, out minVaule, out maxValue, isPolar); + GetMinMaxValue(chart, axisIndex, isValueAxis, inverse, false, out minVaule, out maxValue, isPolar, filterByDataZoom); } /// @@ -313,21 +313,24 @@ namespace XCharts.Runtime /// /// /// - public static void GetYMinMaxValue(List series, DataZoom dataZoom, int axisIndex, bool isValueAxis, - bool inverse, out double minVaule, out double maxValue, bool isPolar = false) + public static void GetYMinMaxValue(BaseChart chart, int axisIndex, bool isValueAxis, + bool inverse, out double minVaule, out double maxValue, bool isPolar = false, bool filterByDataZoom = true) { - GetMinMaxValue(series, dataZoom, axisIndex, isValueAxis, inverse, true, out minVaule, out maxValue, isPolar); + GetMinMaxValue(chart, axisIndex, isValueAxis, inverse, true, out minVaule, out maxValue, isPolar, filterByDataZoom); } private static Dictionary> _stackSeriesForMinMax = new Dictionary>(); private static Dictionary _serieTotalValueForMinMax = new Dictionary(); - public static void GetMinMaxValue(List series, DataZoom dataZoom, int axisIndex, bool isValueAxis, - bool inverse, bool yValue, out double minVaule, out double maxValue, bool isPolar = false) + 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 filterByDataZoom = true) { double min = double.MaxValue; double max = double.MinValue; + var series = chart.series; var isPercentStack = SeriesHelper.IsPercentStack(series); - if (!SeriesHelper.IsStack(series) || (isValueAxis && !yValue)) + if (!SeriesHelper.IsStack(series)) { for (int i = 0; i < series.Count; i++) { @@ -343,21 +346,24 @@ namespace XCharts.Runtime } else { - var showData = serie.GetDataList(dataZoom); - foreach (var data in showData) + var showData = serie.GetDataList(filterByDataZoom?chart.GetXDataZoomOfSerie(serie) : null); + if (serie is Candlestick || serie is SimplifiedCandlestick) { - - if (serie is Candlestick) + foreach (var data in showData) { - var dataMin = data.GetMinData(inverse); - var dataMax = data.GetMaxData(inverse); + double dataMin, dataMax; + data.GetMinMaxData(1, inverse, out dataMin, out dataMax); if (dataMax > max) max = dataMax; if (dataMin < min) min = dataMin; } - else + } + else + { + var performanceMode = serie.IsPerformanceMode(); + foreach (var data in showData) { - //var currData = data.GetData(yValue ? 1 : 0, inverse); - var currData = data.GetCurrData(yValue ? 1 : 0, updateDuration, inverse); + var currData = performanceMode? data.GetData(yValue?1 : 0, inverse): + data.GetCurrData(yValue ? 1 : 0, updateDuration, inverse); if (!serie.IsIgnoreValue(currData)) { if (currData > max) max = currData; @@ -380,7 +386,7 @@ namespace XCharts.Runtime if ((isPolar && serie.polarIndex != axisIndex) || (!isPolar && serie.yAxisIndex != axisIndex) || !serie.show) continue; - var showData = serie.GetDataList(dataZoom); + var showData = serie.GetDataList(filterByDataZoom?chart.GetXDataZoomOfSerie(serie) : null); if (SeriesHelper.IsPercentStack(series, serie.stack)) { for (int j = 0; j < showData.Count; j++) diff --git a/package.json b/package.json index b484585f..6ad69cde 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "com.monitor1394.xcharts", "displayName": "XCharts", - "version": "3.2.0", - "date": "20220815", - "checkdate": "20220815", + "version": "3.3.0", + "date": "20220928", + "checkdate": "20220928", "desc": "如果 XCharts 对您有帮助,希望您能在 Github 上点 Star 支持,非常感谢!", "unity": "2018.3", "description": "A charting and data visualization library for Unity.",