在 WindowsForms DataVisualization Chart 中限制纵横比 [英] Constrain aspect ratio in WindowsForms DataVisualization Chart

查看:22
本文介绍了在 WindowsForms DataVisualization Chart 中限制纵横比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 System.Windows.Forms.DataVisualization.Charting.Chart 中的图表控件,我正在制作散点图.

如何约束它,使 X 轴的刻度与 Y 轴的刻度相同?

简单地将控件本身设置为正方形是不够的,因为它具有用于绘制和标记不相等轴的内部边距.

我可以选择一个特定的尺寸并将其调整为方形,但它需要既方形又可调整大小.

我在文档和属性浏览器中搜索了高低,但在调整大小事件中找不到任何内容或想出任何方法.

解决方案

这是一个很好的问题,但不幸的是,没有像锁定两个 Axes 或设置一个值这样的简单解决方案..

让我们先看看相关的玩家:

  • Chart 控件有一个名为 ClientSize 的内部 Size,也就是 Chart.Size减去边界.两种尺寸均以像素为单位.

  • 里面可能有一个或多个

    有点挤:

    然后再次正方形:

    注意绿色 ChartArea 如何为 LabelsLegend 保留足够的空间,以及坐标轴的自动缩放仍然有效.但是 X 轴标签现在不适合在一行中.还要注意 ChartArea.BackColor 实际上InnerPlotArea 的颜色!

    请注意,在对 ChartArea 布局进行修改(例如放大或移动或删除 Legends)后,您可能需要刷新变量 ipp0 以反映更改的百分比 或改变 Labels 等的大小或角度.

    当然,您可以修改函数以传入任何其他比例以保持而不是将绘图区域保持为正方形..

    Using the charting control from System.Windows.Forms.DataVisualization.Charting.Chart, I am making a scatter plot.

    How can I constrain it so that the scale of the X axis is the same as the scale of the Y axis?

    Simply setting the control itself to be square is insufficient, because it has internal margins for drawing and labeling the axes which are not equal.

    I could pick a specific size and tweak it to be square, but it needs to be both square and resizable.

    I've searched high and low in the documentation and in the property browser, but I can't find anything or think of any ways to do it in the resize event.

    解决方案

    This is a good question but unfortunately there is no simple solution like locking the two Axes or setting one value..

    Let's start by looking at the relevant players:

    • The Chart control has an inner Size called ClientSize, which is the Chart.Size minus the borders. Both sizes are measured in pixels.

    • Inside there may be one or more ChartAreas. Each has a Position which is of type ElementPosition.

    • Inside each ChartArea the is an area which is used for the actual drawing of the points; it is called InnerPlotPosition.

    The InnerPlotPosition property defines the rectangle within a chart area element that is used for plotting data; it excludes tick marks, axis labels, and so forth.

    The coordinates used for this property (0,0 to 100,100) are related to the ChartArea object, and not to the entire Chart.

    The InnerPlotPosition property can be used to align multiple chart areas. However, if one chart area has tick marks and axis labels and another one does not, their axis lines cannot be aligned.

    • Both ChartArea.Position and ChartArea.InnerPlotPosition contain not just the location but also the size of the areas; all values are in percent of the outer area, ie ChartArea.InnerPlotPosition is relative to the ChartArea.Position and ChartArea.Position is relative to the Chart.ClientSize. All percentages go from 0-100.

    So the ChartArea includes Labels and Legends as well as Axes and TickMarks..

    What we want is to find a way to make the InnerPlotArea square, i.e. have the same width and height in pixels. The percentages won't do!

    Let's start with a few simple calculations; if these are the data we have..:

        // we'll work with one ChartArea only..:
        ChartArea ca = chart1.ChartAreas[0];
        ElementPosition cap = ca.Position;
        ElementPosition ipp = ca.InnerPlotPosition;
    

    .. then these are the pixel sizes of the two areas:

        // chartarea pixel size:
        Size CaSize = new Size( (int)( cap.Width * chart1.ClientSize.Width / 100f), 
                                (int)( cap.Height * chart1.ClientSize.Height / 100f));
    
        // InnerPlotArea pixel size:
       Size IppSize = new Size((int)(ipp.Width * CaSize.Width / 100f),
                                (int)(ipp.Height * CaSize.Height / 100f));
    

    Ideally we would like the InnerPlotArea to be square; since can't very well let the smaller side grow (or else the chart would overdraw,) we need to shrink the larger one. So the new pixel size of the InnerPlotArea is

    int ippNewSide = Math.Min(IppSize.Width, IppSize.Height);
    

    What next? Since the Chart.Size has just been set, we don't want to mess with it. Nor should we mess with the ChartArea: It still needs space to hold the Legend etc..

    So we change the size of the InnerPlotArea..:

    First create a class level variable to store the original values of the InnerPlotPosition :

       ElementPosition ipp0 = null;
    

    We will need it to keep the original percentages, i.e. the margins in order to use them when calculating the new ones. When we adapt the chart the then current ones will already have been changed/distorted..

    Then we create a function to make the InnerPlotArea square, which wraps it all up:

    void makeSquare(Chart chart)
    {
        ChartArea ca = chart.ChartAreas[0];
    
        // store the original value:
        if (ipp0 == null) ipp0 = ca.InnerPlotPosition;
    
        // get the current chart area :
        ElementPosition cap = ca.Position;
    
        // get both area sizes in pixels:
        Size CaSize = new Size( (int)( cap.Width * chart1.ClientSize.Width / 100f), 
                                (int)( cap.Height * chart1.ClientSize.Height / 100f));
    
        Size IppSize = new Size((int)(ipp0.Width * CaSize.Width / 100f),
                                (int)(ipp0.Height * CaSize.Height / 100f));
    
        // we need to use the smaller side:
        int ippNewSide = Math.Min(IppSize.Width, IppSize.Height);
    
        // calculate the scaling factors
        float px = ipp0.Width / IppSize.Width * ippNewSide;
        float py = ipp0.Height / IppSize.Height * ippNewSide;
    
        // use one or the other:
        if (IppSize.Width  < IppSize.Height)
            ca.InnerPlotPosition = new ElementPosition(ipp0.X, ipp0.Y, ipp0.Width, py);
        else 
            ca.InnerPlotPosition = new ElementPosition(ipp0.X, ipp0.Y, px, ipp0.Height);
    
    }
    

    You would call the function after or during resizing.

    private void chart1_Resize(object sender, EventArgs e)
    {
        makeSquare(chart1);
    }
    

    Here the function is at work:

    The original size:

    Squeezed a little:

    And made square again:

    Note how the green ChartArea reserves enough space for the Labels and the Legend and how the automatic scaling for the axes still works.. But the X-Axis labels now don't fit in one row. Also note how the ChartArea.BackColor actually is the color of the InnerPlotArea only!

    Note that you may have to refresh the variable ipp0 to reflect the changed percentages, after making modification to the ChartArea layout like enlarging or moving or removing Legends or changing the size or angle of Labels etc..

    Of course you can modify the function to pass in any other ratio to keep instead of keeping the plot area a square..

    这篇关于在 WindowsForms DataVisualization Chart 中限制纵横比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆