WindowsForms中的约束宽高比DataVisualization图表 [英] Constrain aspect ratio in WindowsForms DataVisualization Chart
问题描述
使用 System.Windows.Forms.DataVisualization.Charting.Chart
中的图表控制,我正在制作散点图。
如何约束它,使X轴的比例与Y轴的比例相同?
只需将控件本身设置为
我可以选择一个特定的大小,并将其调整为正方形,但是它的方向是不够的,因为它有内部边距用于绘制和标注不相等的轴。它需要是正方形和可调整大小。
我在文档和属性浏览器中搜索高低,但我找不到任何东西或想
这是一个很好的问题,但不幸的是,没有一个简单的解决方案,如锁定两个 Axes
或设置一个值。
让我们先看看相关的玩家:
-
图表
控制有一个内部Size
调用ClientSize
,这是Chart.Size
减去边框。这两种尺寸都以像素为单位。 -
内部可能有一个或多个
压缩一点:$ b $ b
再次变成方形:
请注意绿色
ChartArea
如何为标签
和图例
以及轴的自动缩放是如何工作的。但是X轴标签现在不适合一行。还要注意ChartArea.BackColor
实际上是InnerPlotArea
的颜色! / p>
请注意,在修改
之后,您可能需要刷新变量
布局,如放大或移动或移除ipp0
c $ c> ChartAreaLegends
或更改标签的大小或角度
等。
当然你可以修改函数以任何其他比例传递,而不是保持绘图区域的方形。
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 innerSize
calledClientSize
, which is theChart.Size
minus the borders. Both sizes are measured in pixels.Inside there may be one or more
ChartAreas
. Each has aPosition
which is of typeElementPosition
.Inside each
ChartArea
the is an area which is used for the actual drawing of the points; it is calledInnerPlotPosition
.
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
andChartArea.InnerPlotPosition
contain not just the location but also the size of the areas; all values are in percent of the outer area, ieChartArea.InnerPlotPosition
is relative to theChartArea.Position
andChartArea.Position
is relative to theChart.ClientSize
. All percentages go from0-100
.
So the
ChartArea
includesLabels
andLegends
as well asAxes
andTickMarks
..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 theInnerPlotArea
isint 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 theChartArea
: It still needs space to hold theLegend
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 theLabels
and theLegend
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 theChartArea.BackColor
actually is the color of theInnerPlotArea
only!Note that you may have to refresh the variable
ipp0
to reflect the changed percentages, after making modification to theChartArea
layout like enlarging or moving or removingLegends
or changing the size or angle ofLabels
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屋!