在悬停时突出显示 winforms MS 图表线
Highlight winforms MS Chart line on hover
我正在尝试将 MS Chart 与自定义控件结合使用。我的目的是:
- 鼠标悬停在该段上时,仅突出显示连接两个相邻点的线段
- 找到这两个相邻点的索引(我需要它才能通过同时移动两个点来拖动那条线)
插图种类:
现在,我可以使用 中描述的方法检测图表上一条线上的悬停。但我一直在寻找索引或至少是这两点的坐标。
所以最初的想法是通过x找到最近的点(假设所有的系列都有x值确实在稳步增加)然后计算y值。但我对此做了一些改进,并增加了对完全垂直线的支持。所以这是我捕获所需行的代码:
private static GrippedLine? LineHitTest(Series series, double xPos, double yPos, Axis xAxis, Axis yAxis)
{
double xPixelPos = xAxis.PixelPositionToValue(xPos);
double yPixelPos = yAxis.PixelPositionToValue(yPos);
DataPoint[] neighbors = new DataPoint[2];
neighbors[0] = series.Points.Last(x => x.XValue <= xPixelPos);
neighbors[1] = series.Points.First(x => x.XValue >= xPixelPos);
DataPoint[] verticalMates;
foreach (DataPoint neighbor in neighbors)
{
if (Math.Abs(neighbor.XValue - xPixelPos) < LINE_GRIP_REGION)
{
verticalMates = series.Points.FindAllByValue(neighbor.XValue, "X").ToArray();
if (verticalMates.Length > 1)
{
if (verticalMates.Length > 2)
{
if (verticalMates[0].YValues[0] < verticalMates[verticalMates.Length - 1].YValues[0])
{
neighbors[0] = verticalMates.LastOrDefault(y => y.YValues[0] < yPixelPos);
neighbors[1] = verticalMates.FirstOrDefault(y => y.YValues[0] >= yPixelPos);
}
else
{
neighbors[0] = verticalMates.LastOrDefault(y => y.YValues[0] > yPixelPos);
neighbors[1] = verticalMates.FirstOrDefault(y => y.YValues[0] <= yPixelPos);
}
}
else
{
neighbors[0] = verticalMates[0];
neighbors[1] = verticalMates[1];
}
break;
}
}
}
double x0 = xAxis.ValueToPixelPosition(neighbors[0].XValue);
double y0 = yAxis.ValueToPixelPosition(neighbors[0].YValues[0]);
double x1 = xAxis.ValueToPixelPosition(neighbors[1].XValue);
double y1 = yAxis.ValueToPixelPosition(neighbors[1].YValues[0]);
double Yinterpolated = y0 + (y1 - y0) * (xPos - x0) / (x1 - x0);
int[] linePoints = new int[2];
// if mouse Y position is near the calculated OR the line is vertical
if (Math.Abs(Yinterpolated - yPos) < LINE_GRIP_REGION || neighbors[0].XValue == neighbors[1].XValue)
{
linePoints[0] = series.Points.IndexOf(neighbors[0]);
linePoints[1] = series.Points.IndexOf(neighbors[1]);
}
else
{
return null;
}
return new GrippedLine()
{
startLinePointIndex = linePoints[0],
endLinePointIndex = linePoints[1],
x0Correction = neighbors[0].XValue - xPixelPos,
y0Correction = neighbors[0].YValues[0] - yPixelPos,
x1Correction = neighbors[1].XValue - xPixelPos,
y1Correction = neighbors[1].YValues[0] - yPixelPos
};
}
我正在尝试将 MS Chart 与自定义控件结合使用。我的目的是:
- 鼠标悬停在该段上时,仅突出显示连接两个相邻点的线段
- 找到这两个相邻点的索引(我需要它才能通过同时移动两个点来拖动那条线)
插图种类:
现在,我可以使用
所以最初
private static GrippedLine? LineHitTest(Series series, double xPos, double yPos, Axis xAxis, Axis yAxis)
{
double xPixelPos = xAxis.PixelPositionToValue(xPos);
double yPixelPos = yAxis.PixelPositionToValue(yPos);
DataPoint[] neighbors = new DataPoint[2];
neighbors[0] = series.Points.Last(x => x.XValue <= xPixelPos);
neighbors[1] = series.Points.First(x => x.XValue >= xPixelPos);
DataPoint[] verticalMates;
foreach (DataPoint neighbor in neighbors)
{
if (Math.Abs(neighbor.XValue - xPixelPos) < LINE_GRIP_REGION)
{
verticalMates = series.Points.FindAllByValue(neighbor.XValue, "X").ToArray();
if (verticalMates.Length > 1)
{
if (verticalMates.Length > 2)
{
if (verticalMates[0].YValues[0] < verticalMates[verticalMates.Length - 1].YValues[0])
{
neighbors[0] = verticalMates.LastOrDefault(y => y.YValues[0] < yPixelPos);
neighbors[1] = verticalMates.FirstOrDefault(y => y.YValues[0] >= yPixelPos);
}
else
{
neighbors[0] = verticalMates.LastOrDefault(y => y.YValues[0] > yPixelPos);
neighbors[1] = verticalMates.FirstOrDefault(y => y.YValues[0] <= yPixelPos);
}
}
else
{
neighbors[0] = verticalMates[0];
neighbors[1] = verticalMates[1];
}
break;
}
}
}
double x0 = xAxis.ValueToPixelPosition(neighbors[0].XValue);
double y0 = yAxis.ValueToPixelPosition(neighbors[0].YValues[0]);
double x1 = xAxis.ValueToPixelPosition(neighbors[1].XValue);
double y1 = yAxis.ValueToPixelPosition(neighbors[1].YValues[0]);
double Yinterpolated = y0 + (y1 - y0) * (xPos - x0) / (x1 - x0);
int[] linePoints = new int[2];
// if mouse Y position is near the calculated OR the line is vertical
if (Math.Abs(Yinterpolated - yPos) < LINE_GRIP_REGION || neighbors[0].XValue == neighbors[1].XValue)
{
linePoints[0] = series.Points.IndexOf(neighbors[0]);
linePoints[1] = series.Points.IndexOf(neighbors[1]);
}
else
{
return null;
}
return new GrippedLine()
{
startLinePointIndex = linePoints[0],
endLinePointIndex = linePoints[1],
x0Correction = neighbors[0].XValue - xPixelPos,
y0Correction = neighbors[0].YValues[0] - yPixelPos,
x1Correction = neighbors[1].XValue - xPixelPos,
y1Correction = neighbors[1].YValues[0] - yPixelPos
};
}