WindowsForms中的约束宽高比DataVisualization图表 [英] Constrain aspect ratio in WindowsForms DataVisualization Chart

查看:247
本文介绍了WindowsForms中的约束宽高比DataVisualization图表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



如何约束它,使X轴的比例与Y轴的比例相同?



只需将控件本身设置为



我可以选择一个特定的大小,并将其调整为正方形,但是它的方向是不够的,因为它有内部边距用于绘制和标注不相等的轴。它需要是正方形和可调整大小。



我在文档和属性浏览器中搜索高低,但我找不到任何东西或想

解决方案

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



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




  • 图表控制有一个内部 Size 调用 ClientSize ,这是 Chart.Size 减去边框。这两种尺寸都以像素为单位。


  • 内部可能有一个或多个



    压缩一点:$ b​​ $ b



    再次变成方形:



    请注意绿色 ChartArea 如何为标签图例以及轴的自动缩放是如何工作的。但是X轴标签现在不适合一行。还要注意 ChartArea.BackColor 实际上 InnerPlotArea 的颜色! / p>

    请注意,在修改之后,您可能需要刷新变量 ipp0 c $ c> ChartArea 布局,如放大或移动或移除 Legends 或更改标签的大小或角度等。



    当然你可以修改函数以任何其他比例传递,而不是保持绘图区域的方形。


    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图表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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