为 mschart 创建缩放图片框

To create a zoom picturebox for mschart

我想为 mschart 创建一个像 PictureBox Zoom 中那样的缩放图片框。当我将鼠标悬停在图表上时,图片框应该显示缩放视图,这样我就可以 select 一个合适的点。这会发生在 winforms C#.net 中吗?

这是一个解决方案,可以满足 op 的要求:创建一个 PictureBox,显示 Chartzoomed 部分,它将作为一个整体移动在图表中移动。

看起来不错,但仍然需要移动那些未缩放的微小像素..

这是如何完成和设置的:

必要时必须重新设置 PictureBox zoomPBox;设置它需要进行一些 测量 并创建 Chart 的屏幕截图。为此,图表暂时放大,然后重置为原始大小。

注意:每当图表以任何其他方式调整大小或更改时,都必须再次调用设置例程。

PictureBox zoomPBox 设置为 SizeMode Normal 并且 嵌套 Panel 中。在设置中,我们放大 zoomPBox 以容纳整个 BitmapPanel zoomPanelAutoScroll = false 以避免滚动条。

一个并发症是图表控件的自动调整大小。放大时,内容会放大,但例如none 的字体是。这导致正常绘图区域和缩放绘图区域之间 不同的纵横比 。为了保持运动同步,我们不能这样做。因此,我们不仅要 剪掉 没有 LegendTitleAxes 的实际内部绘图区域,而且还要 [=64] =]将其拉伸至与未缩放绘图区域相同的纵横比..

结果如下:

MouseMove的代码没那么复杂..:[=​​38=]

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的像素大小; (MSChart 中的 ElementPosition 在相应容器区域的 百分比 中包含 LocationSize。)我使用我发布的功能之前,例如.

另一个解决方案是使用图表控件作为缩放视图。当鼠标移到原始图表上时,您可以查看以红色标记的数据点。如下所示:

代码如下:

private void chart1_MouseMove(object sender, MouseEventArgs e)
    {
        Point mousePoint = new Point(e.X, e.Y);
        double mouse_Xvalue = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X);
        double mouse_Yvalue = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Y);

        DataPoint Prev_DataPoint = chart1.Series[0].Points.Select(x => x)
                                        .Where(x => x.XValue >= mouse_Xvalue)
                                        .DefaultIfEmpty(chart1.Series[0].Points.First()).First();

        DataPoint Next_DataPoint = chart1.Series[0].Points.Select(x => x)
                              .Where(x => x.XValue <= mouse_Xvalue)
                               .DefaultIfEmpty(chart1.Series[0].Points.Last()).Last();

        double diff_prev = Math.Abs(Prev_DataPoint.XValue - mouse_Xvalue);
        double diff_next = Math.Abs(Next_DataPoint.XValue - mouse_Xvalue);

        int zoffset = 15;
        int setindexX = diff_prev < diff_next ?
                          chart1.Series[0].Points.IndexOf(Prev_DataPoint)
                        : chart1.Series[0].Points.IndexOf(Next_DataPoint);

        int setXmin = (setindexX - zoffset) >= 0 ? (setindexX - zoffset)
                        : 0;
        int setXmax = (setindexX + zoffset) < chart1.Series[0].Points.Count
                      ? (setindexX + zoffset)
                        : chart1.Series[0].Points.Count - 1;

        if (zoomchart.Series.Count > 0)
            zoomchart.Series.Clear();

        Series series = new Series();
        Series series2 = new Series();
        series.Points.Clear();
        series2.Points.Clear();

        for (int i = setXmin; i <= setXmax; i++)
            series.Points.AddXY(chart1.Series[0].Points[i].XValue,
                                chart1.Series[0].Points[i].YValues[0]);
        series.Color = chart1.Series[0].Color;
        series.ChartType = SeriesChartType.Line;

        series2.Points.AddXY(chart1.Series[0].Points[setindexX].XValue,
                             chart1.Series[0].Points[setindexX].YValues[0]);
        series2.Color = Color.Red;
        series2.ChartType = SeriesChartType.Point;
        series2.Points[0].Label = series2.Points[0].XValue.ToString("F2") + ", "
                                + series2.Points[0].YValues[0].ToString("F2");


        zoomchart.Series.Add(series);
        zoomchart.Series.Add(series2);
        zoomchart.Invalidate();

        zoomchart.ChartAreas[0].AxisX.Minimum = series.Points[0].XValue;
        zoomchart.ChartAreas[0].AxisX.Maximum = series.Points.FindMaxByValue("X").XValue;
        zoomchart.ChartAreas[0].AxisY.Minimum = series.Points.FindMinByValue().YValues[0];
        zoomchart.ChartAreas[0].AxisY.Maximum = series.Points.FindMaxByValue().YValues[0];

    }