From fdcefb48f66d2c67cb4f93046802145f6583e0f4 Mon Sep 17 00:00:00 2001 From: monitor1394 Date: Tue, 9 Jun 2026 22:32:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96`DataZoom`=E7=9A=84=E7=BC=A9?= =?UTF-8?q?=E6=94=BE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Runtime/Component/DataZoom/DataZoomHandler.cs | 84 +++++++++---------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/Runtime/Component/DataZoom/DataZoomHandler.cs b/Runtime/Component/DataZoom/DataZoomHandler.cs index e98db669..aa68252d 100644 --- a/Runtime/Component/DataZoom/DataZoomHandler.cs +++ b/Runtime/Component/DataZoom/DataZoomHandler.cs @@ -429,60 +429,58 @@ namespace XCharts.Runtime private void ScaleDataZoom(DataZoom dataZoom, float delta, GridCoord grid = null, Vector2? mousePos = null) { if (grid == null) grid = chart.GetGridOfDataZoom(dataZoom); - var range = dataZoom.orient == Orient.Horizonal ? grid.context.width : grid.context.height; - var deltaPercent = Mathf.Abs(delta / range * 100); - float start, end; + var gridRange = dataZoom.orient == Orient.Horizonal ? grid.context.width : grid.context.height; + var currentRange = dataZoom.end - dataZoom.start; + if (delta > 0 && currentRange <= 0) return; - // Calculate the anchor ratio within the current [start, end] range based on mouse position. - // This ensures the data point under the cursor stays fixed while zooming. - float centerRatio = 0.5f; - if (mousePos.HasValue) + // Mouse position as a fraction [0,1] within the grid. + // The grid always maps the current [start,end] window onto its full pixel width, + // so this fraction directly equals the mouse's relative position inside the data window. + float fraction = 0.5f; + if (mousePos.HasValue && gridRange > 0) { - float mousePercent; - if (dataZoom.orient == Orient.Horizonal) - mousePercent = grid.context.width > 0 - ? (mousePos.Value.x - grid.context.x) / grid.context.width * 100 - : 50f; - else - mousePercent = grid.context.height > 0 - ? (mousePos.Value.y - grid.context.y) / grid.context.height * 100 - : 50f; + float raw = dataZoom.orient == Orient.Horizonal + ? (mousePos.Value.x - grid.context.x) / gridRange + : (mousePos.Value.y - grid.context.y) / gridRange; - var currentRange = dataZoom.end - dataZoom.start; - if (currentRange > 0) + bool isInverse = false; + if (dataZoom.orient == Orient.Horizonal && dataZoom.xAxisIndexs.Count > 0) { - // mousePercent is always grid-relative (0=left edge, 100=right edge). - // When DataZoom shows [start, end], the grid spans exactly that window, - // so the anchor fraction is simply mousePercent/100. - // For inverse axes the data runs right→left, so flip the fraction. - bool isInverse = false; - if (dataZoom.orient == Orient.Horizonal && dataZoom.xAxisIndexs.Count > 0) - { - var xAxis = chart.GetChartComponent(dataZoom.xAxisIndexs[0]); - isInverse = xAxis != null && xAxis.inverse; - } - else if (dataZoom.orient == Orient.Vertical && dataZoom.yAxisIndexs.Count > 0) - { - var yAxis = chart.GetChartComponent(dataZoom.yAxisIndexs[0]); - isInverse = yAxis != null && yAxis.inverse; - } - centerRatio = isInverse - ? 1f - mousePercent / 100f - : mousePercent / 100f; + var xAxis = chart.GetChartComponent(dataZoom.xAxisIndexs[0]); + isInverse = xAxis != null && xAxis.inverse; } + else if (dataZoom.orient == Orient.Vertical && dataZoom.yAxisIndexs.Count > 0) + { + var yAxis = chart.GetChartComponent(dataZoom.yAxisIndexs[0]); + isInverse = yAxis != null && yAxis.inverse; + } + fraction = Mathf.Clamp01(isInverse ? 1f - raw : raw); } - if (delta > 0) + // The data-space anchor (0~100) under the mouse — must stay at the same fraction after zoom. + var anchorPercent = dataZoom.start + fraction * currentRange; + + // New range: proportional to current range for consistent zoom feel at any zoom level. + var deltaPercent = Mathf.Abs(delta / gridRange * currentRange); + var newRange = delta > 0 ? currentRange - deltaPercent : currentRange + deltaPercent; + + // Place the new window so that anchorPercent stays under the mouse. + var start = anchorPercent - fraction * newRange; + var end = anchorPercent + (1f - fraction) * newRange; + + // If the window goes out of [0,100], slide it to the boundary while keeping its size, + // so the zoom always feels consistent and the window never shrinks on one side only. + if (start < 0f) { - if (dataZoom.end <= dataZoom.start) return; - start = dataZoom.start + deltaPercent * centerRatio; - end = dataZoom.end - deltaPercent * (1 - centerRatio); + end = Mathf.Min(100f, newRange); + start = 0f; } - else + else if (end > 100f) { - start = dataZoom.start - deltaPercent * centerRatio; - end = dataZoom.end + deltaPercent * (1 - centerRatio); + start = Mathf.Max(0f, 100f - newRange); + end = 100f; } + UpdateDataZoomRange(dataZoom, start, end, grid); }