为mschart创建缩放图片框

时间:2018-11-26 06:02:40

标签: c# .net picturebox mschart

我想为PictureBox Zoom创建一个用于mschart的缩放图片框。当我将鼠标悬停在图表上时,图片框应显示缩放视图,以便我可以选择适当的点。可以在winforms C#.net中发生这种情况吗?

2 个答案:

答案 0 :(得分:1)

以下是一种解决方案,可以按照用户要求进行:创建一个PictureBox,其中显示Chart zoomed 部分,该部分将随着图表的移动而移动。

看起来不错,但仍然需要在这些微小的未缩放像素之间移动。

这是完成和设置的方法:

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

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

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

一个并发症是Chart控件执行的自动调整大小。放大时,内容会放大,但例如没有一种字体。这将导致法线和缩放图区域之间的不同的长宽比。为了使运动保持同步,我们无法做到这一点。因此,我们不仅要从缩放的屏幕截图中切出没有LegendTitleAxes的实际内部绘图区域,而且还要拉伸 strong>与未缩放的绘图区域具有相同的长宽比。

这是结果:

enter image description here

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在相应容器区域的百分比中包括LocationSize。)我使用之前发布的函数,例如here

答案 1 :(得分:1)

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

这是代码:

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];

    }