Dou*_*ean 4 c# charts data-visualization winforms
使用图表控件System.Windows.Forms.DataVisualization.Charting.Chart,我正在制作一个散点图.
如何约束它以使X轴的刻度与Y轴的刻度相同?
简单地将控件本身设置为方形是不够的,因为它具有用于绘制和标记不相等的轴的内部边距.
我可以选择一个特定的大小并将其调整为方形,但它需要是正方形和可调整大小.
我在文档和属性浏览器中搜索了高低,但在resize事件中我找不到任何东西或想到任何方法.
这是一个很好的问题,但遗憾的是没有像锁定两个Axes或设置一个值的简单解决方案.
让我们从相关的玩家开始:
该Chart控制具有内部Size称为ClientSize,这是Chart.Size减去边框.两种尺寸都以像素为单位.
里面可能有一个或多个ChartAreas.每个都有一个Position类型ElementPosition.
每个内部ChartArea都是用于实际绘制点的区域; 它被称为InnerPlotPosition.
InnerPlotPosition属性定义图表区域元素中用于绘制数据的矩形; 它不包括刻度线,轴标签等.
用于此属性的坐标(0,0到100,100)与ChartArea对象相关,而不是与整个图表相关.
InnerPlotPosition属性可用于对齐多个图表区域.但是,如果一个图表区域有刻度线和轴标签而另一个没有,则它们的轴线不能对齐.
ChartArea.Position并ChartArea.InnerPlotPosition不仅包括位置,还包含区域的大小 ; 所有值都是外部区域的百分比,即ChartArea.InnerPlotPosition相对于ChartArea.Position和ChartArea.Position相对于Chart.ClientSize.所有百分比都来自0-100.因此,ChartArea包括Labels和Legends以及Axes和TickMarks..
我们想要的是找到制作InnerPlotArea正方形的方法,即具有相同的宽度和高度(以像素为单位).百分比不会做!
让我们从几个简单的计算开始; 如果这些是我们的数据..:
// we'll work with one ChartArea only..:
ChartArea ca = chart1.ChartAreas[0];
ElementPosition cap = ca.Position;
ElementPosition ipp = ca.InnerPlotPosition;
Run Code Online (Sandbox Code Playgroud)
..那么这些是两个区域的像素大小:
// 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));
Run Code Online (Sandbox Code Playgroud)
理想情况下,我们希望它InnerPlotArea是方形的; 因为不能很好地让较小的一面增长(否则图表会过度绘制),我们需要缩小较大的一面.所以新的像素大小InnerPlotArea是
int ippNewSide = Math.Min(IppSize.Width, IppSize.Height);
Run Code Online (Sandbox Code Playgroud)
接下来是什么?由于Chart.Size刚刚设定,我们不想搞砸它.我们也不应该捣乱ChartArea:它仍然需要空间来容纳Legend等等.
所以我们改变了InnerPlotArea.. 的大小:
首先创建一个类级变量来存储以下的原始值InnerPlotPosition:
ElementPosition ipp0 = null;
Run Code Online (Sandbox Code Playgroud)
我们需要它保持原始百分比,即边距,以便在计算新的百分比时使用它们.当我们调整图表时,当前的图表已经被更改/扭曲了..
然后我们创建一个函数来制作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);
}
Run Code Online (Sandbox Code Playgroud)
您可以在调整大小之后或期间调用该函数.
private void chart1_Resize(object sender, EventArgs e)
{
makeSquare(chart1);
}
Run Code Online (Sandbox Code Playgroud)
这个功能在起作用:
请注意绿色如何ChartArea保留足够的空间Labels以及Legend轴的自动缩放仍然有效.但是X轴标签现在不适合一行.还要注意ChartArea.BackColor 实际上是InnerPlotArea唯一的颜色!
请注意ipp0,在对ChartArea布局进行修改(例如放大或移动或移除Legends或更改大小或角度Labels等)之后,您可能必须刷新变量以反映更改的百分比.
当然你可以修改函数以传递任何其他比例来保持而不是将绘图区域保持为正方形.