diff --git a/CHANGELOG.md b/CHANGELOG.md index 80b5664e..65efedbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ ## master +* (2022.07.29) 增加`Axis`为`Time`时间轴时,支持次刻度和次分割线 * (2022.07.28) 优化`Radar`雷达图效果 * (2022.07.28) 增加`Serie`的`colorBy`参数配置取色策略 * (2022.07.27) 增加`StateStyle`的`Symbol`用于配置状态下的标记样式 diff --git a/Runtime/Component/Axis/AxisHandler.cs b/Runtime/Component/Axis/AxisHandler.cs index 8831dab5..50e9b3ac 100644 --- a/Runtime/Component/Axis/AxisHandler.cs +++ b/Runtime/Component/Axis/AxisHandler.cs @@ -205,8 +205,8 @@ namespace XCharts if (axis.IsTime()) { var lastCount = axis.context.labelValueList.Count; - DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList, (int) axis.context.minValue, - (int) axis.context.maxValue, axis.splitNumber); + axis.context.tickValue = DateTimeUtil.UpdateTimeAxisDateTimeList(axis.context.labelValueList, + (int) axis.context.minValue, (int) axis.context.maxValue, axis.splitNumber); if (axis.context.labelValueList.Count != lastCount) axis.SetAllDirty(); @@ -565,13 +565,15 @@ namespace XCharts var tickWidth = axis.axisTick.GetWidth(theme.tickWidth); var tickColor = axis.axisTick.GetColor(theme.tickColor); var current = orient == Orient.Horizonal ? startX : startY; - var lastTickX = 0f; - var lastTickY = 0f; + var maxAxisXY = current + axisLength; + var lastTickX = current; + var lastTickY = current; var minorTickSplitNumber = axis.minorTick.splitNumber <= 0 ? 5 : axis.minorTick.splitNumber; var minorTickDistance = axis.GetValueLength(axis.context.tickValue / minorTickSplitNumber, axisLength); var minorTickColor = axis.minorTick.GetColor(theme.tickColor); var minorTickWidth = axis.minorTick.GetWidth(theme.tickWidth); var minorTickLength = axis.minorTick.GetLength(theme.tickLength * 0.6f); + var minorStartIndex = axis.IsTime() ? 0 : 1; for (int i = 0; i < size; i++) { var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, i + 1, dataZoom); @@ -606,9 +608,9 @@ namespace XCharts } if (!hideTick) UGL.DrawLine(vh, new Vector3(pX, sY), new Vector3(pX, eY), tickWidth, tickColor); - if (axis.minorTick.show && i > 0 && minorTickDistance > 0) + if (axis.minorTick.show && i >= minorStartIndex && minorTickDistance > 0) { - if (lastTickX <= axis.context.zeroX || (i == 1 && pX > axis.context.zeroX)) + if (lastTickX <= axis.context.zeroX || (i == minorStartIndex && pX > axis.context.zeroX)) { var tickTotal = pX - minorTickDistance; while (tickTotal > lastTickX) @@ -626,6 +628,15 @@ namespace XCharts tickTotal += minorTickDistance; } } + if (i == size - 1) + { + var tickTotal = pX + minorTickDistance; + while (tickTotal < maxAxisXY) + { + UGL.DrawLine(vh, new Vector3(tickTotal, sY), new Vector3(tickTotal, mY), minorTickWidth, minorTickColor); + tickTotal += minorTickDistance; + } + } } lastTickX = pX; } @@ -656,9 +667,9 @@ namespace XCharts } if (!hideTick) UGL.DrawLine(vh, new Vector3(sX, pY), new Vector3(eX, pY), tickWidth, tickColor); - if (axis.minorTick.show && i > 0 && minorTickDistance > 0) + if (axis.minorTick.show && i >= minorStartIndex && minorTickDistance > 0) { - if (lastTickY <= axis.context.zeroY || (i == 1 && pY > axis.context.zeroY)) + if (lastTickY <= axis.context.zeroY || (i == minorStartIndex && pY > axis.context.zeroY)) { var tickTotal = pY - minorTickDistance; while (tickTotal > lastTickY) @@ -678,6 +689,15 @@ namespace XCharts tickTotal += minorTickDistance; } } + if (i == size - 1) + { + var tickTotal = pY + minorTickDistance; + while (tickTotal < maxAxisXY) + { + UGL.DrawLine(vh, new Vector3(sX, tickTotal), new Vector3(mX, tickTotal), minorTickWidth, minorTickColor); + tickTotal += minorTickDistance; + } + } } lastTickY = pY; } @@ -751,10 +771,8 @@ namespace XCharts size += 1; } - var current = orient == Orient.Horizonal ? - startX : - startY; - + var current = orient == Orient.Horizonal ? startX : startY; + var maxAxisXY = current + axisLength; var lastSplitX = 0f; var lastSplitY = 0f; var minorTickSplitNumber = axis.minorTick.splitNumber <= 0 ? 5 : axis.minorTick.splitNumber; @@ -762,6 +780,7 @@ namespace XCharts var minorSplitLineColor = axis.minorSplitLine.GetColor(theme.minorSplitLineColor); var minorLineWidth = axis.minorSplitLine.GetWidth(theme.lineWidth); var minorLineType = axis.minorSplitLine.GetType(theme.splitLineType); + var minorStartIndex = axis.IsTime() ? 0 : 1; for (int i = 0; i < size; i++) { var scaleWidth = AxisHelper.GetScaleWidth(axis, axisLength, axis.IsTime() ? i : i + 1, dataZoom); @@ -789,7 +808,6 @@ namespace XCharts new Vector2(startX, current + scaleWidth), axis.splitArea.GetColor(i, theme)); } - } if (axis.splitLine.show) { @@ -806,9 +824,9 @@ namespace XCharts new Vector3(current, startY + splitLength), lineColor); } - if (axis.minorSplitLine.show && i > 0 && minorTickDistance > 0) + if (axis.minorSplitLine.show && i >= minorStartIndex && minorTickDistance > 0) { - if (lastSplitX <= axis.context.zeroX || (i == 1 && current > axis.context.zeroX)) + if (lastSplitX <= axis.context.zeroX || (i == minorStartIndex && current > axis.context.zeroX)) { var tickTotal = current - minorTickDistance; var count = 0; @@ -840,6 +858,22 @@ namespace XCharts tickTotal += minorTickDistance; } } + if (i == size - 1) + { + var tickTotal = current + minorTickDistance; + var count = 0; + while (tickTotal < maxAxisXY && count < minorTickSplitNumber - 1) + { + ChartDrawer.DrawLineStyle(vh, + minorLineType, + minorLineWidth, + new Vector3(tickTotal, startY), + new Vector3(tickTotal, startY + splitLength), + minorSplitLineColor); + count++; + tickTotal += minorTickDistance; + } + } } lastSplitX = current; } @@ -854,9 +888,9 @@ namespace XCharts new Vector3(startX + splitLength, current), lineColor); } - if (axis.minorSplitLine.show && i > 0 && minorTickDistance > 0) + if (axis.minorSplitLine.show && i >= minorStartIndex && minorTickDistance > 0) { - if (lastSplitY <= axis.context.zeroY || (i == 1 && current > axis.context.zeroY)) + if (lastSplitY <= axis.context.zeroY || (i == minorStartIndex && current > axis.context.zeroY)) { var tickTotal = current - minorTickDistance; var count = 0; @@ -888,6 +922,22 @@ namespace XCharts tickTotal += minorTickDistance; } } + if (i == size - 1) + { + var tickTotal = current + minorTickDistance; + var count = 0; + while (tickTotal < maxAxisXY && count < minorTickSplitNumber - 1) + { + ChartDrawer.DrawLineStyle(vh, + minorLineType, + minorLineWidth, + new Vector3(startX, tickTotal), + new Vector3(startX + splitLength, tickTotal), + minorSplitLineColor); + count++; + tickTotal += minorTickDistance; + } + } } lastSplitY = current; } diff --git a/Runtime/Utilities/DateTimeUtil.cs b/Runtime/Utilities/DateTimeUtil.cs index 361218f2..cf97f145 100644 --- a/Runtime/Utilities/DateTimeUtil.cs +++ b/Runtime/Utilities/DateTimeUtil.cs @@ -80,18 +80,20 @@ namespace XCharts.Runtime /// /// /// - internal static void UpdateTimeAxisDateTimeList(List list, int minTimestamp, int maxTimestamp, int splitNumber) + internal static float UpdateTimeAxisDateTimeList(List list, int minTimestamp, int maxTimestamp, int splitNumber) { list.Clear(); var range = maxTimestamp - minTimestamp; - if (range <= 0) return; + if (range <= 0) return 0; if (splitNumber <= 0) splitNumber = 1; var dtMin = DateTimeUtil.GetDateTime(minTimestamp); var dtMax = DateTimeUtil.GetDateTime(maxTimestamp); + int tick = 0; if (range >= ONE_YEAR * MIN_TIME_SPLIT_NUMBER) { var num = Math.Max(range / (splitNumber * ONE_YEAR), 1); var dtStart = new DateTime(dtMin.Year + 1, 1, 1); + tick = num * 365 * 24 * 3600; while (dtStart.Ticks < dtMax.Ticks) { list.Add(DateTimeUtil.GetTimestamp(dtStart)); @@ -102,6 +104,7 @@ namespace XCharts.Runtime { var num = Math.Max(range / (splitNumber * ONE_MONTH), 1); var dtStart = new DateTime(dtMin.Year, dtMin.Month, 1).AddMonths(1); + tick = num * 30 * 24 * 3600; while (dtStart.Ticks < dtMax.Ticks) { list.Add(DateTimeUtil.GetTimestamp(dtStart)); @@ -110,28 +113,29 @@ namespace XCharts.Runtime } else if (range >= ONE_DAY * MIN_TIME_SPLIT_NUMBER) { - var tick = GetTickSecond(range, splitNumber, ONE_DAY); + tick = GetTickSecond(range, splitNumber, ONE_DAY); var startTimestamp = (minTimestamp - minTimestamp % tick) + tick; AddTickTimestamp(list, startTimestamp, maxTimestamp, tick); } else if (range >= ONE_HOUR * MIN_TIME_SPLIT_NUMBER) { - var tick = GetTickSecond(range, splitNumber, ONE_HOUR); + tick = GetTickSecond(range, splitNumber, ONE_HOUR); var startTimestamp = (minTimestamp - minTimestamp % tick) + tick; AddTickTimestamp(list, startTimestamp, maxTimestamp, tick); } else if (range >= ONE_MINUTE * MIN_TIME_SPLIT_NUMBER) { - var tick = GetTickSecond(range, splitNumber, ONE_MINUTE); + tick = GetTickSecond(range, splitNumber, ONE_MINUTE); var startTimestamp = (minTimestamp - minTimestamp % tick) + tick; AddTickTimestamp(list, startTimestamp, maxTimestamp, tick); } else { - var tick = GetTickSecond(range, splitNumber, ONE_SECOND); + tick = GetTickSecond(range, splitNumber, ONE_SECOND); var startTimestamp = (minTimestamp - minTimestamp % tick) + tick; AddTickTimestamp(list, startTimestamp, maxTimestamp, tick); } + return tick; } private static int GetTickSecond(int range, int splitNumber, int tickSecond)