Чтобы создать зум-картинку для mschart - PullRequest
0 голосов
/ 26 ноября 2018

Я хочу создать зум в картинке, как в PictureBox Zoom для mschart.Когда я наводю указатель мыши на график, в окне рисунка должен отображаться зум, чтобы я мог выбрать подходящую точку.Может ли это случиться в winforms C # .net?

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Другое решение заключается в использовании элемента управления диаграммой в качестве масштаба.Вы можете просмотреть точку данных, отмеченную красным, когда мышь перемещается над исходной диаграммой.Как показано ниже: 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];

    }
0 голосов
/ 28 ноября 2018

Вот решение, которое выполняет то, о чем просила опера: Создайте PictureBox, который показывает увеличенную часть Chart, которая будет перемещаться при перемещении по диаграмме.

Выглядит хорошо, но все равно придется перемещаться по этим крошечным не увеличенным пикселям ..

Вот как это делается и настраивается:

При необходимости PictureBox zoomPBoxдолжен быть настроен снова;настройка включает в себя несколько измерений и создание скриншота Chart.Для этого диаграмма временно увеличивается , а затем сбрасывается до исходного размера.

Примечание : Всякий раз, когда диаграмма изменяется или изменяется любым другим способом, процедура установки должнавызываться снова.

PictureBox zoomPBox установлен на SizeMode Normal и вложен в Panel.В настройках мы увеличиваем zoomPBox, чтобы вместить все Bitmap.Panel zoomPanel имеет AutoScroll = false, чтобы избежать полос прокрутки.

Одна сложность - это автоматическое определение размера , которое делает элемент управления Chart.При его увеличении содержимое увеличивается, но, например, ни один из шрифтов не увеличивается.Это приводит к различным соотношениям сторон между нормалью и увеличенной областью графика.Чтобы синхронизировать движение, у нас не может быть этого.Поэтому мы не только хотим вырезать фактическую внутреннюю область графика без Legend, Title или Axes из увеличенного скриншота, но также растянуть до такого же соотношения сторонкак необъятная область сюжета ..

Вот результат:

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();
}

Как видите, I Invalidate the 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 в процентах соответствующей области контейнера.) Я использую функции, которые я разместил ранее, например, здесь .

...