在WindowsForms DataVisualization Chart中限制宽高比

时间:2016-03-25 14:17:29

标签: c# winforms charts data-visualization

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

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

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

我可以选择一个特定尺寸并将其调整为正方形,但它必须是正方形且可调整大小。

我在文档和属性浏览器中搜索过高低,但我无法在resize事件中找到任何内容或想出任何方法。

1 个答案:

答案 0 :(得分:5)

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

让我们先来看看相关的球员:

  • Chart控件的内部Size名为ClientSizeChart.Size减去边框。两种尺寸均以像素为单位进行测量。

  • 里面可能有一个或多个ChartAreas。每个都有一个Position,类型为ElementPosition

  • 在每个ChartArea内,是一个用于实际绘制点的区域;它被称为InnerPlotPosition

  

InnerPlotPosition属性定义图表中的矩形   用于绘制数据的area元素;它不包括刻度线,   轴标签,等等。

     

此属性使用的坐标(0,0到100,100)与   ChartArea对象,而不是整个Chart。

     

InnerPlotPosition属性可用于对齐多个图表   区域。但是,如果一个图表区域有刻度线和轴标签   另一个没有,他们的轴线不能对齐。

  • ChartArea.PositionChartArea.InnerPlotPosition不仅包含位置,还包含 区域的尺寸;所有值都在外部区域的百分比,即ChartArea.InnerPlotPosition相对于ChartArea.PositionChartArea.Position相对于Chart.ClientSize。所有百分比均来自0-100

因此ChartArea包括LabelsLegends以及AxesTickMarks ..

我们想要的是找到一种方法来制作InnerPlotArea方形,即具有相同的宽度和高度(以像素为单位)。百分比不会这样做!

让我们从几个简单的计算开始;如果这些是我们的数据..:

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

..然后这些是两个区域的像素大小:

    // 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));

理想情况下,我们希望InnerPlotArea为正方形;因为不能很好地让较小的一面增长(否则图表会过度绘制),我们需要缩小较大的一面。因此InnerPlotArea的新像素大小为

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

下一步是什么?由于Chart.Size刚刚设定,我们不想搞砸它。我们也不应该混淆ChartArea:它仍然需要空间来容纳Legend等。

因此我们更改了InnerPlotArea ..:

的大小

首先创建一个类级变量来存储InnerPlotPosition的原始值:

   ElementPosition ipp0 = null;

我们需要它保持原始百分比,即边距,以便在计算新的百分比时使用它们。当我们调整图表时,当前的图表已经被更改/扭曲..

然后我们创建一个函数来制作InnerPlotArea正方形,它将它全部包装起来:

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

}

您可以在调整大小后或调整大小期间调用该函数。

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

这里的功能正在发挥作用:

原始尺寸: original

挤了一下: scaled

再次成为正方形: square

请注意绿色ChartArea如何为LabelsLegend保留足够的空间,以及轴的自动缩放如何仍然有效..但X轴标签现在不适用t适合一排。另请注意ChartArea.BackColor 实际的颜色仅为InnerPlotArea的颜色!

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

当然你可以修改函数以传递任何其他比率来保持而不是将绘图区域保持为正方形..