在 DataVisualization.Charting 中绘制轴并防止选择
Axis drawing over point and preventing selection in DataVisualization.Charting
我正在使用圆形标记来指示数据点的位置。当这些点绘制在一个轴上时,我不能 select 它们(使用 HitTest)...但是当它们被绘制在图表上的其他任何地方时我可以 select 它们。无法select 的点似乎在 轴下方绘制。如果我使标记变大,那么我可以通过单击圆的边缘 select 轴上的点。
有没有办法让标记绘制在轴的顶部(如果这是问题所在!)?
这真是个好问题。
这个问题确实存在我不知道一个简单的解决方案。
- 这是一种可能的解决方法:
当你发现你击中了Axis
或AxisLabel
或TickMark
时,你可以修改你测试的X
。计算位置镜像在轴和偏移的宽度,然后再次测试。
为此,您需要知道以像素为单位的轴位置及其宽度。
后者是axis.Linewidth
。对于前者使用轴函数ax.ValueToPixelPosition
。它采用 y 轴位置的 x 值。这将是 x 轴的最小值(如果已设置)或 0
或某个自动值,具体取决于您的数据。
这确实改善了这种情况,尽管我发现 TickMarks 仍然会阻碍,但不确定为什么。
如果鼠标点真的很近,用户会喜欢它,直到它们再次离开。您可以使用反向函数 PixelPositionToValue
和一些 Linq 来找到最近的点。
更新:
- 事实上,最后一个想法可以作为替代解决方法来实施。
这是一个函数示例,用于查找最近点,可能在 MouseMove
事件中,或者可能在 HitTest
击中轴或轴元素之后..:[=32= ]
DataPoint GetNearestPoint(Series s, ChartArea ca, Point pt)
{
int limit = s.MarkerSize * 4; // pick a suitable distance!
Axis ay = ca.AxisY;
Axis ax = ca.AxisX;
var mins = s.Points.Cast<DataPoint>().Select((x, index) =>
new
{
val = Math.Abs(pt.Y - (int)ay.ValueToPixelPosition(x.YValues[0]))
+ Math.Abs(pt.X - (int)ax.ValueToPixelPosition(x.XValue)),
ix = index
});
var min = mins.Where(x => x.val == mins.Min(v => v.val)).Select(x => x.ix).First();
if (mins.ElementAt(min).val > limit) return null;
else return s.Points[min];
}
这是我在创建 class 级别变量后调用它的方式:
DataPoint lastHit = null;
它会在光标足够近时为最近的点着色..:[=32=]
var nearest = GetNearestPoint(someSeries, someChart.ChartAreas[0], e.Location);
if (lastHit != null) lastHit.MarkerColor = someSeries.Color;
if (nearest != null)
{
lastHit = nearest;
nearest.MarkerColor = Color.Red;
}
扩大 MarkerSize
当然也很简单(至少除非你的 ChartType
是 Bubble
,就像我的一样 ;-)
- 另一种解决方法会相当混乱:您可以添加一个额外的 ChartArea 并将其完全 覆盖在原始图表上。您必须获得原件的
ElementPositions
及其 InnerPlotPosition
的 ElementPositions
,然后将它们用于叠加层。现在您可以将系列移动到第二个,上部 ChartArea
并关闭其 Axis
等。HitTest
现在应该可以按预期工作。但是每次调整大小都需要调整位置。
我正在使用圆形标记来指示数据点的位置。当这些点绘制在一个轴上时,我不能 select 它们(使用 HitTest)...但是当它们被绘制在图表上的其他任何地方时我可以 select 它们。无法select 的点似乎在 轴下方绘制。如果我使标记变大,那么我可以通过单击圆的边缘 select 轴上的点。
有没有办法让标记绘制在轴的顶部(如果这是问题所在!)?
这真是个好问题。
这个问题确实存在我不知道一个简单的解决方案。
- 这是一种可能的解决方法:
当你发现你击中了Axis
或AxisLabel
或TickMark
时,你可以修改你测试的X
。计算位置镜像在轴和偏移的宽度,然后再次测试。
为此,您需要知道以像素为单位的轴位置及其宽度。
后者是axis.Linewidth
。对于前者使用轴函数ax.ValueToPixelPosition
。它采用 y 轴位置的 x 值。这将是 x 轴的最小值(如果已设置)或 0
或某个自动值,具体取决于您的数据。
这确实改善了这种情况,尽管我发现 TickMarks 仍然会阻碍,但不确定为什么。
如果鼠标点真的很近,用户会喜欢它,直到它们再次离开。您可以使用反向函数 PixelPositionToValue
和一些 Linq 来找到最近的点。
更新:
- 事实上,最后一个想法可以作为替代解决方法来实施。
这是一个函数示例,用于查找最近点,可能在 MouseMove
事件中,或者可能在 HitTest
击中轴或轴元素之后..:[=32= ]
DataPoint GetNearestPoint(Series s, ChartArea ca, Point pt)
{
int limit = s.MarkerSize * 4; // pick a suitable distance!
Axis ay = ca.AxisY;
Axis ax = ca.AxisX;
var mins = s.Points.Cast<DataPoint>().Select((x, index) =>
new
{
val = Math.Abs(pt.Y - (int)ay.ValueToPixelPosition(x.YValues[0]))
+ Math.Abs(pt.X - (int)ax.ValueToPixelPosition(x.XValue)),
ix = index
});
var min = mins.Where(x => x.val == mins.Min(v => v.val)).Select(x => x.ix).First();
if (mins.ElementAt(min).val > limit) return null;
else return s.Points[min];
}
这是我在创建 class 级别变量后调用它的方式:
DataPoint lastHit = null;
它会在光标足够近时为最近的点着色..:[=32=]
var nearest = GetNearestPoint(someSeries, someChart.ChartAreas[0], e.Location);
if (lastHit != null) lastHit.MarkerColor = someSeries.Color;
if (nearest != null)
{
lastHit = nearest;
nearest.MarkerColor = Color.Red;
}
扩大 MarkerSize
当然也很简单(至少除非你的 ChartType
是 Bubble
,就像我的一样 ;-)
- 另一种解决方法会相当混乱:您可以添加一个额外的 ChartArea 并将其完全 覆盖在原始图表上。您必须获得原件的
ElementPositions
及其InnerPlotPosition
的ElementPositions
,然后将它们用于叠加层。现在您可以将系列移动到第二个,上部ChartArea
并关闭其Axis
等。HitTest
现在应该可以按预期工作。但是每次调整大小都需要调整位置。