diff --git a/Documentation~/zh/changelog.md b/Documentation~/zh/changelog.md
index 533dd576..4634ea0d 100644
--- a/Documentation~/zh/changelog.md
+++ b/Documentation~/zh/changelog.md
@@ -80,6 +80,7 @@ slug: /changelog
## master
+* (2025.10.30) 优化`Candlestick`对时间轴的支持
* (2025.10.30) 增加`Scatter`的`ignore`支持设置忽略数据
* (2025.10.24) 优化`Sankey`的线条绘制排序
* (2025.10.22) 增加`Pie`的`pieType`支持实心饼图和线框柄图 (#349)
diff --git a/Runtime/Component/Axis/Axis.cs b/Runtime/Component/Axis/Axis.cs
index 915a9d4f..527e6917 100644
--- a/Runtime/Component/Axis/Axis.cs
+++ b/Runtime/Component/Axis/Axis.cs
@@ -485,6 +485,7 @@ namespace XCharts.Runtime
context.maxValue = 0;
context.destMinValue = 0;
context.destMaxValue = 0;
+ context.labelValueList.Clear();
}
public Axis Clone()
diff --git a/Runtime/Component/Axis/AxisHandler.cs b/Runtime/Component/Axis/AxisHandler.cs
index 1b576b95..d1d4432c 100644
--- a/Runtime/Component/Axis/AxisHandler.cs
+++ b/Runtime/Component/Axis/AxisHandler.cs
@@ -364,7 +364,7 @@ namespace XCharts
{
var lastCount = axis.context.labelValueList.Count;
axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList,
- axis.context.minValue, axis.context.maxValue, axis.splitNumber);
+ axis.context.minValue, axis.context.maxValue, axis.splitNumber, axis.ceilRate);
if (axis.context.labelValueList.Count != lastCount)
axis.SetAllDirty();
diff --git a/Runtime/Internal/BaseChart.cs b/Runtime/Internal/BaseChart.cs
index 3c8caab6..9b325278 100644
--- a/Runtime/Internal/BaseChart.cs
+++ b/Runtime/Internal/BaseChart.cs
@@ -204,7 +204,7 @@ namespace XCharts.Runtime
protected override void OnValidate()
{
base.OnValidate();
- foreach (var handler in m_SerieHandlers) handler.ForceUpdateSerieContext();
+ ResetChartStatus();
}
#endif
diff --git a/Runtime/Serie/Candlestick/CandlestickHandler.cs b/Runtime/Serie/Candlestick/CandlestickHandler.cs
index b72be4de..b17cc585 100644
--- a/Runtime/Serie/Candlestick/CandlestickHandler.cs
+++ b/Runtime/Serie/Candlestick/CandlestickHandler.cs
@@ -157,13 +157,13 @@ namespace XCharts.Runtime
(itemStyle.borderWidth == 0 ? theme.serie.candlestickBorderWidth :
itemStyle.borderWidth);
if (serieData.IsDataChanged()) dataChanging = true;
- float pX = grid.context.x + i * categoryWidth;
+ float pX = xAxis.IsCategory() ? grid.context.x + i * categoryWidth : AxisHelper.GetAxisValuePosition(grid, xAxis, categoryWidth, serieData.GetData(0));
float zeroY = grid.context.y + yAxis.context.offset;
if (!xAxis.boundaryGap) pX -= categoryWidth / 2;
float pY = zeroY;
var barHig = 0f;
double valueTotal = yMaxValue - yMinValue;
- var minCut = (yMinValue > 0 ? yMinValue : 0);
+ var minCut = yMinValue > 0 ? yMinValue : 0;
if (valueTotal != 0)
{
barHig = (float)((close - open) / valueTotal * grid.context.height);
diff --git a/Runtime/Serie/SerieData.cs b/Runtime/Serie/SerieData.cs
index d6104093..fc01844d 100644
--- a/Runtime/Serie/SerieData.cs
+++ b/Runtime/Serie/SerieData.cs
@@ -645,11 +645,12 @@ namespace XCharts.Runtime
/// the maxinum value.
/// ||最大值。
///
- public double GetMaxData(bool inverse = false)
+ public double GetMaxData(bool inverse = false, int startDimensionIndex = 0)
{
if (m_Data.Count == 0) return 0;
var temp = double.MinValue;
- for (int i = 0; i < m_Data.Count; i++)
+ if (startDimensionIndex < 0) startDimensionIndex = 0;
+ for (int i = startDimensionIndex; i < m_Data.Count; i++)
{
var value = GetData(i, inverse);
if (value > temp) temp = value;
@@ -661,11 +662,12 @@ namespace XCharts.Runtime
/// the mininum value.
/// ||最小值。
///
- public double GetMinData(bool inverse = false)
+ public double GetMinData(bool inverse = false, int startDimensionIndex = 0)
{
if (m_Data.Count == 0) return 0;
var temp = double.MaxValue;
- for (int i = 0; i < m_Data.Count; i++)
+ if (startDimensionIndex < 0) startDimensionIndex = 0;
+ for (int i = startDimensionIndex; i < m_Data.Count; i++)
{
var value = GetData(i, inverse);
if (value < temp) temp = value;
diff --git a/Runtime/Serie/SeriesHelper.cs b/Runtime/Serie/SeriesHelper.cs
index ed6a0ab7..84837696 100644
--- a/Runtime/Serie/SeriesHelper.cs
+++ b/Runtime/Serie/SeriesHelper.cs
@@ -384,7 +384,7 @@ namespace XCharts.Runtime
else
{
var showData = serie.GetDataList(filterByDataZoom ? chart.GetXDataZoomOfSerie(serie) : null);
- if (serie is Candlestick || serie is SimplifiedCandlestick)
+ if (dimension > 0 && (serie is Candlestick || serie is SimplifiedCandlestick))
{
foreach (var data in showData)
{
@@ -441,9 +441,9 @@ namespace XCharts.Runtime
if (!_serieTotalValueForMinMax.ContainsKey(j))
_serieTotalValueForMinMax[j] = 0;
double currData = 0;
- if (serie is Candlestick)
+ if (serie is Candlestick || serie is SimplifiedCandlestick)
{
- currData = showData[j].GetMaxData(false);
+ currData = showData[j].GetMaxData(false, dimension);
}
else
{
diff --git a/Runtime/Utilities/DateTimeUtil.cs b/Runtime/Utilities/DateTimeUtil.cs
index 26a064c7..33936825 100644
--- a/Runtime/Utilities/DateTimeUtil.cs
+++ b/Runtime/Utilities/DateTimeUtil.cs
@@ -83,15 +83,16 @@ namespace XCharts.Runtime
}
}
- public static DateTime GetDateTime(double timestamp, bool local = true)
+ public static DateTime GetDateTime(double timestamp, bool local = false)
{
- return local ? k_LocalDateTime1970.AddSeconds(timestamp) : k_DateTime1970.AddSeconds(timestamp);
+ var dateTime = local ? k_LocalDateTime1970.AddSeconds(timestamp) : k_DateTime1970.AddSeconds(timestamp);
+ return dateTime;
}
- public static string GetDefaultDateTimeString(double timestamp, double range = 0)
+ public static string GetDefaultDateTimeString(double timestamp, double range = 0, bool local = false)
{
var dateString = String.Empty;
- var dateTime = GetDateTime(timestamp);
+ var dateTime = GetDateTime(timestamp, local);
if (range <= 0 || range >= DateTimeUtil.ONE_DAY)
{
dateString = dateTime.ToString("yyyy-MM-dd");
@@ -144,7 +145,7 @@ namespace XCharts.Runtime
///
///
///
- internal static float UpdateTimeAxisDateTimeList(List list, double minTimestamp, double maxTimestamp, int splitNumber)
+ internal static float UpdateTimeAxisDateTimeList(List list, double minTimestamp, double maxTimestamp, int splitNumber, double ceilRate)
{
var range = maxTimestamp - minTimestamp;
if (range <= 0)
@@ -152,61 +153,15 @@ namespace XCharts.Runtime
list.Clear();
return 0;
}
- var dtMin = DateTimeUtil.GetDateTime(minTimestamp);
- var dtMax = DateTimeUtil.GetDateTime(maxTimestamp);
- int tick = 0;
- if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER)
+ var dtMin = GetDateTime(minTimestamp);
+ var dtMax = GetDateTime(maxTimestamp);
+ int tick;
+ if (ceilRate != 0)
{
- var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_YEAR) : (int)Math.Max(range / (splitNumber * ONE_YEAR), 1);
- var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp));
- dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
- while (dtStart > dtMin)
- {
- dtStart = dtStart.AddYears(-num);
- }
- if (dtStart < dtMin)
- {
- dtStart = dtStart.AddYears(num);
- }
- tick = num * 365 * 24 * 3600;
- list.Clear();
- while (dtStart.Ticks < dtMax.Ticks)
- {
- list.Add(DateTimeUtil.GetTimestamp(dtStart));
- dtStart = dtStart.AddYears(num);
- }
- }
- else if (range >= ONE_MONTH * MIN_TIME_SPLIT_NUMBER)
- {
- var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_MONTH) : (int)Math.Max(range / (splitNumber * ONE_MONTH), 1);
- var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp));
- dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
- while (dtStart > dtMin)
- {
- dtStart = dtStart.AddMonths(-num);
- }
- if (dtStart < dtMin)
- {
- dtStart = dtStart.AddMonths(num);
- }
- tick = num * 30 * 24 * 3600;
- list.Clear();
- while (dtStart.Ticks < dtMax.Ticks)
- {
- list.Add(DateTimeUtil.GetTimestamp(dtStart));
- dtStart = dtStart.AddMonths(num);
- }
- }
- else
- {
- int tickSecond;
- if (range >= ONE_DAY * MIN_TIME_SPLIT_NUMBER) tickSecond = ONE_DAY;
- else if (range >= ONE_HOUR * MIN_TIME_SPLIT_NUMBER) tickSecond = ONE_HOUR;
- else if (range >= ONE_MINUTE * MIN_TIME_SPLIT_NUMBER) tickSecond = ONE_MINUTE;
- else tickSecond = ONE_SECOND;
- tick = GetTickSecond(range, splitNumber, tickSecond);
- var let = minTimestamp % tick;
- var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tick;
+ var tickSecond = (int)ceilRate;
+ tick = GetTickSecond(range, 0, tickSecond);
+ var let = minTimestamp % tickSecond;
+ var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tickSecond;
var startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp);
while (startTimestamp > minTimestamp)
{
@@ -219,6 +174,85 @@ namespace XCharts.Runtime
list.Clear();
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
}
+ else
+ {
+ if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER)
+ {
+ var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_YEAR) : (int)Math.Max(range / (splitNumber * ONE_YEAR), 1);
+ var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp));
+ dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
+ while (dtStart > dtMin)
+ {
+ dtStart = dtStart.AddYears(-num);
+ }
+ if (dtStart < dtMin)
+ {
+ dtStart = dtStart.AddYears(num);
+ }
+ tick = num * 365 * 24 * 3600;
+ list.Clear();
+ while (dtStart.Ticks < dtMax.Ticks)
+ {
+ list.Add(DateTimeUtil.GetTimestamp(dtStart));
+ dtStart = dtStart.AddYears(num);
+ }
+ }
+ else if (range >= ONE_MONTH * MIN_TIME_SPLIT_NUMBER)
+ {
+ var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_MONTH) : (int)Math.Max(range / (splitNumber * ONE_MONTH), 1);
+ var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp));
+ dtStart = new DateTime(dtStart.Year, dtStart.Month, 1);
+ while (dtStart > dtMin)
+ {
+ dtStart = dtStart.AddMonths(-num);
+ }
+ if (dtStart < dtMin)
+ {
+ dtStart = dtStart.AddMonths(num);
+ }
+ tick = num * 30 * 24 * 3600;
+ list.Clear();
+ while (dtStart.Ticks < dtMax.Ticks)
+ {
+ list.Add(DateTimeUtil.GetTimestamp(dtStart));
+ dtStart = dtStart.AddMonths(num);
+ }
+ }
+ else
+ {
+ int tickSecond;
+ if (range >= ONE_DAY * MIN_TIME_SPLIT_NUMBER)
+ {
+ tickSecond = ONE_DAY;
+ }
+ else if (range >= ONE_HOUR * MIN_TIME_SPLIT_NUMBER)
+ {
+ tickSecond = ONE_HOUR;
+ }
+ else if (range >= ONE_MINUTE * MIN_TIME_SPLIT_NUMBER)
+ {
+ tickSecond = ONE_MINUTE;
+ }
+ else
+ {
+ tickSecond = ONE_SECOND;
+ }
+ tick = GetTickSecond(range, splitNumber, tickSecond);
+ var let = minTimestamp % tickSecond;
+ var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tickSecond;
+ var startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp);
+ while (startTimestamp > minTimestamp)
+ {
+ startTimestamp -= tick;
+ }
+ if (startTimestamp < minTimestamp)
+ {
+ startTimestamp += tick;
+ }
+ list.Clear();
+ AddTickTimestamp(list, startTimestamp, maxTimestamp, tick);
+ }
+ }
return tick;
}