优化Candlestick对时间轴的支持

This commit is contained in:
monitor1394
2025-10-30 22:48:36 +08:00
parent 0499126e55
commit 2cb82526bc
8 changed files with 108 additions and 70 deletions

View File

@@ -80,6 +80,7 @@ slug: /changelog
## master ## master
* (2025.10.30) 优化`Candlestick`对时间轴的支持
* (2025.10.30) 增加`Scatter``ignore`支持设置忽略数据 * (2025.10.30) 增加`Scatter``ignore`支持设置忽略数据
* (2025.10.24) 优化`Sankey`的线条绘制排序 * (2025.10.24) 优化`Sankey`的线条绘制排序
* (2025.10.22) 增加`Pie``pieType`支持实心饼图和线框柄图 (#349) * (2025.10.22) 增加`Pie``pieType`支持实心饼图和线框柄图 (#349)

View File

@@ -485,6 +485,7 @@ namespace XCharts.Runtime
context.maxValue = 0; context.maxValue = 0;
context.destMinValue = 0; context.destMinValue = 0;
context.destMaxValue = 0; context.destMaxValue = 0;
context.labelValueList.Clear();
} }
public Axis Clone() public Axis Clone()

View File

@@ -364,7 +364,7 @@ namespace XCharts
{ {
var lastCount = axis.context.labelValueList.Count; var lastCount = axis.context.labelValueList.Count;
axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList, axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList,
axis.context.minValue, axis.context.maxValue, axis.splitNumber); axis.context.minValue, axis.context.maxValue, axis.splitNumber, axis.ceilRate);
if (axis.context.labelValueList.Count != lastCount) if (axis.context.labelValueList.Count != lastCount)
axis.SetAllDirty(); axis.SetAllDirty();

View File

@@ -204,7 +204,7 @@ namespace XCharts.Runtime
protected override void OnValidate() protected override void OnValidate()
{ {
base.OnValidate(); base.OnValidate();
foreach (var handler in m_SerieHandlers) handler.ForceUpdateSerieContext(); ResetChartStatus();
} }
#endif #endif

View File

@@ -157,13 +157,13 @@ namespace XCharts.Runtime
(itemStyle.borderWidth == 0 ? theme.serie.candlestickBorderWidth : (itemStyle.borderWidth == 0 ? theme.serie.candlestickBorderWidth :
itemStyle.borderWidth); itemStyle.borderWidth);
if (serieData.IsDataChanged()) dataChanging = true; if (serieData.IsDataChanged()) dataChanging = true;
float pX = grid.context.x + i * categoryWidth; float pX = xAxis.IsCategory() ? grid.context.x + i * categoryWidth : AxisHelper.GetAxisValuePosition(grid, xAxis, categoryWidth, serieData.GetData(0));
float zeroY = grid.context.y + yAxis.context.offset; float zeroY = grid.context.y + yAxis.context.offset;
if (!xAxis.boundaryGap) pX -= categoryWidth / 2; if (!xAxis.boundaryGap) pX -= categoryWidth / 2;
float pY = zeroY; float pY = zeroY;
var barHig = 0f; var barHig = 0f;
double valueTotal = yMaxValue - yMinValue; double valueTotal = yMaxValue - yMinValue;
var minCut = (yMinValue > 0 ? yMinValue : 0); var minCut = yMinValue > 0 ? yMinValue : 0;
if (valueTotal != 0) if (valueTotal != 0)
{ {
barHig = (float)((close - open) / valueTotal * grid.context.height); barHig = (float)((close - open) / valueTotal * grid.context.height);

View File

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

View File

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

View File

@@ -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 dateString = String.Empty;
var dateTime = GetDateTime(timestamp); var dateTime = GetDateTime(timestamp, local);
if (range <= 0 || range >= DateTimeUtil.ONE_DAY) if (range <= 0 || range >= DateTimeUtil.ONE_DAY)
{ {
dateString = dateTime.ToString("yyyy-MM-dd"); dateString = dateTime.ToString("yyyy-MM-dd");
@@ -144,7 +145,7 @@ namespace XCharts.Runtime
/// <param name="minTimestamp"></param> /// <param name="minTimestamp"></param>
/// <param name="maxTimestamp"></param> /// <param name="maxTimestamp"></param>
/// <param name="splitNumber"></param> /// <param name="splitNumber"></param>
internal static float UpdateTimeAxisDateTimeList(List<double> list, double minTimestamp, double maxTimestamp, int splitNumber) internal static float UpdateTimeAxisDateTimeList(List<double> list, double minTimestamp, double maxTimestamp, int splitNumber, double ceilRate)
{ {
var range = maxTimestamp - minTimestamp; var range = maxTimestamp - minTimestamp;
if (range <= 0) if (range <= 0)
@@ -152,61 +153,15 @@ namespace XCharts.Runtime
list.Clear(); list.Clear();
return 0; return 0;
} }
var dtMin = DateTimeUtil.GetDateTime(minTimestamp); var dtMin = GetDateTime(minTimestamp);
var dtMax = DateTimeUtil.GetDateTime(maxTimestamp); var dtMax = GetDateTime(maxTimestamp);
int tick = 0; int tick;
if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER) if (ceilRate != 0)
{ {
var num = splitNumber <= 0 ? GetSplitNumber(range, ONE_YEAR) : (int)Math.Max(range / (splitNumber * ONE_YEAR), 1); var tickSecond = (int)ceilRate;
var dtStart = GetDateTime(GetFirstMaxValue(list, minTimestamp)); tick = GetTickSecond(range, 0, tickSecond);
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1); var let = minTimestamp % tickSecond;
while (dtStart > dtMin) var defaultTimestamp = let == 0 ? minTimestamp : minTimestamp - let + tickSecond;
{
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 startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp); var startTimestamp = (int)GetFirstMaxValue(list, minTimestamp, defaultTimestamp);
while (startTimestamp > minTimestamp) while (startTimestamp > minTimestamp)
{ {
@@ -219,6 +174,85 @@ namespace XCharts.Runtime
list.Clear(); list.Clear();
AddTickTimestamp(list, startTimestamp, maxTimestamp, tick); 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; return tick;
} }