这是一个满足操作要求的解决方案:创建一个PictureBox,显示Chart 的放大部分,该部分将随着图表的移动而移动。
看起来不错,但仍然需要穿过那些微小的未缩放像素..
这是如何完成和设置的:
必要时必须重新设置PictureBox zoomPBox;设置它需要进行一些测量并创建Chart 的屏幕截图。为此,图表暂时放大,然后重置为原始大小。
注意:每当图表调整大小或以任何其他方式更改时,必须再次调用设置例程。
PictureBox zoomPBox 设置为 SizeMode Normal,并嵌套在 Panel 中。在设置中,我们放大zoomPBox 以容纳整个Bitmap。 Panel zoomPanel 有 AutoScroll = false 以避免滚动条。
一个复杂性是图表控件的自动调整大小。放大时,内容会放大,但例如没有任何字体。这会导致正常和缩放绘图区域之间的不同的纵横比。为了保持运动同步,我们不能这样做。因此,我们不仅要从放大的屏幕截图中切出没有Legend、Title或Axes的实际内部绘图区域,还要将其拉伸到相同的位置纵横比作为未缩放的绘图区域..
结果如下:
MouseMove 的代码就没有这么复杂了..:
private void chart_MouseMove(object sender, MouseEventArgs e)
{
if (zoomPBox.Image == null) return;
Rectangle ri = Rectangle.Round(
InnerPlotPositionClientRectangle(chart, chart.ChartAreas[0]));
Size szi = zoomPBox.Image.Size;
Size szp = zoomPanel.ClientSize;
Point cp = new Point( e.X - ri.X , e.Y - ri.Y );
float zx = 1f * szi.Width / ri.Width;
float zy = 1f * szi.Height / ri.Height; // should be the same
int x = round( szp.Width / 2 - cp.X * zx );
int y = round( szp.Height / 2 - cp.Y * zy );
zoomPBox.Location = new Point(x, y); // now we move the pBox into position
zoomPBox.Invalidate();
}
如你所见,我 Invalidate PictureBox;即允许它在自身上绘制十字线以便更好地控制;这是Paint 事件:
private void zoomPBox_Paint(object sender, PaintEventArgs e)
{
Size sz = zoomPanel.ClientSize;
int x = sz.Width / 2 - zoomPBox.Left;
int y = sz.Height / 2 - zoomPBox.Top;
e.Graphics.DrawLine(Pens.LightGray, 0, y, zoomPBox.Width, y);
e.Graphics.DrawLine(Pens.LightGray, x, 0, x, zoomPBox.Height);
}
现在开始设置例程:
void setupZoomBox(Chart chart, PictureBox pbox, float zoom)
{
ChartArea ca = chart.ChartAreas[0];
Size sz = chart.ClientSize;
Size szi = new Size(round(sz.Width * zoom), round(sz.Height * zoom));
Bitmap bmp2 = null;
chart.Refresh();
// original plot area
Rectangle pao = Rectangle.Round(InnerPlotPositionClientRectangle(chart, ca));
float ro = 1f * (pao.Width+2) / (pao.Height+2); // original aspect ratio
chart.ClientSize = szi;
chart.Refresh(); // enforce immediate layout
// zoomed plot area
Rectangle paz = Rectangle.Round(InnerPlotPositionClientRectangle(chart, ca));
float rz = 1f * paz.Width / paz.Height; // zoomed aspect ratio
// target rectangle, same aspect ratio as unzoomed area
int th = paz.Height;
int tw = round(paz.Height * ro );
// if (ro > rz)
//tw = round(th * ro); //else th = round(tw / ro);
Rectangle tgtR = new Rectangle(0, 0, tw, th);
// bitmap to hold only the zoomed inner plot area
bmp2 = new Bitmap(tgtR.Width, tgtR.Height);
// source area: Only the inner plot area plus 1 line of axis pixels:
Rectangle srcR = Rectangle.Round(
new RectangleF(paz.X - 1, paz.Y - 1, paz.Width + 2, paz.Height + 2));
// bitmap to hold the whole zoomed chart:
using (Bitmap bmp = new Bitmap(szi.Width, szi.Height))
{
Rectangle drawR = new Rectangle(0, 0, szi.Width, szi.Height);
chart.DrawToBitmap(bmp, drawR); // screenshot
using (Graphics g = Graphics.FromImage(bmp2)) // crop stretched
g.DrawImage(bmp, tgtR, srcR, GraphicsUnit.Pixel);
}
chart.ClientSize = sz; // reset chart
// you should dispose of the old Image if there is one before setting the new one!!
pbox.Image = bmp2;
pbox.ClientSize = bmp2.Size;
}
在某些地方,我需要获取所谓的InnerPlotPosition 的像素大小; (ElementPosition 中的 MSChart 包括 Location 和 Size 在相应容器区域的百分比中。)我使用我之前发布的功能,例如here.