C#Charting控件中X轴和Y轴的ScaleView联动问题

在Charting控件中,由于数据较多,在X轴上通过ScaleView设置只显示一部分数据,同时Y轴上的数据跨度也很大,导致显示部分数据在Y轴向上看不出区别,有没有简便高... 在Charting控件中,由于数据较多,在X轴上通过ScaleView设置只显示一部分数据,同时Y轴上的数据跨度也很大,导致显示部分数据在Y轴向上看不出区别,有没有简便高效的方法可以让Y轴根据X轴选择显示的数据在Y轴向上的值来进行缩放,使显示数据的值Y轴向上也能尽量填满图表区域,望大神解答 展开
 我来答
makosharp
2014-10-10 · TA获得超过676个赞
知道小有建树答主
回答量:188
采纳率:100%
帮助的人:270万
展开全部

  可以看出你需要的是在X轴使用缩放视图时自动根据显示区域内数据点的Y值范围对Y轴也进行缩放。

  这里需要着重考虑几个问题。

  1. X轴缩放后我们需要找出X值在此区域的数据点,才能计算出这些数据点的Y值的最大值和最小值。

  2. 进行Y轴缩放时应该加入一个微调值,避免出现最小Y值触碰视图区域底部和最大Y值触碰视图区域顶部。

  3. 进入缩放视图后,如果用户在X轴上进行了滚动操作,应该根据设置决定是否立刻对Y轴缩放视图进行重新计算。

  这里的核心代码并不多,下面列出:

        

        private void ZoomInternal(double xStart, double xEnd, Series singleSeries)
        {
            ChartArea area = this.ChartAreas[singleSeries.ChartArea];
            //放大X轴为start到end区间的部分图表
            area.AxisX.ScaleView.Zoom(xStart, xEnd);
            if (viewZoomAutoLinkage)
            {
                //计算此视图上所有point的Y值(每个点可能有多个Y值),得到X值在范围内的所有点的所有Y值
                //这里的points是List<double[]>结构
                var points = (from p in singleSeries.Points
                              where p.XValue <= xEnd && p.XValue >= xStart
                              select p.YValues).ToList();
                //展开所有Y值得到最小和最大值。这里我们使用Lambda完成嵌套的Min计算
                //对每一个Y值集合计算最小值作为该集合的比较值,然后抽取所有集合中的最小值
                if (points.Any())
                {
                    double yStart = points.Min<double[]>(yValues => yValues.Min());
                    double yEnd = points.Max<double[]>(yValues => yValues.Max());
                    //放大Y轴到yStart,yEnd范围
                    area.AxisY.ScaleView.Zoom(yStart-viewZoomYFix, yEnd+viewZoomYFix);
                }
            }
        }


因为你提及的这个问题可能我项目中也会用到,这里顺手继承了一下Chart控件,解决了上面列出的三个问题。下面是一个自定义Chart控件的源码。请直接使用或修改。使用时请先设置其两个自定义的公有属性bool ViewZoomAutoLinkage和double ViewZoomYFix。


using System;
using System.Linq;
using System.Windows.Forms.DataVisualization.Charting;
namespace Utils
{
    public partial class MyChart : Chart
    {
        private bool viewZoomAutoLinkage = false;
        //是否使用联动缩放
        public bool ViewZoomAutoLinkage
        {
            get { return viewZoomAutoLinkage; }
            set { viewZoomAutoLinkage = value; }
        }
        private double viewZoomYFix;
        //联动缩放Y轴时对最大Y和最小Y的修正。修正为YMax+Fix和YMin-Fix。
        //为确保放大后的YMax和YMix不会触及区域顶端/底端,请使用合适的Fix值适当扩大Y轴视图范围
        //例:Y轴间隔为2,使用Fix=1较为合适。
        public double ViewZoomYFix
        {
            get { return viewZoomYFix; }
            set { viewZoomYFix = value; }
        }
        public MyChart()
        {
            this.AxisViewChanged += new EventHandler<ViewEventArgs>(LinkageZoom);
        }
        private void ZoomInternal(double xStart, double xEnd, Series singleSeries)
        {
            ChartArea area = this.ChartAreas[singleSeries.ChartArea];
            //放大X轴为start到end区间的部分图表
            area.AxisX.ScaleView.Zoom(xStart, xEnd);
            if (viewZoomAutoLinkage)
            {
                //计算此视图上所有point的Y值(每个点可能有多个Y值),得到X值在范围内的所有点的所有Y值
                //这里的points是List<double[]>结构
                var points = (from p in singleSeries.Points
                              where p.XValue <= xEnd && p.XValue >= xStart
                              select p.YValues).ToList();
                //展开所有Y值得到最小和最大值。这里我们使用Lambda完成嵌套的Min计算
                //对每一个Y值集合计算最小值作为该集合的比较值,然后抽取所有集合中的最小值
                if (points.Any())
                {
                    double yStart = points.Min<double[]>(yValues => yValues.Min());
                    double yEnd = points.Max<double[]>(yValues => yValues.Max());
                    //放大Y轴到yStart,yEnd范围
                    area.AxisY.ScaleView.Zoom(yStart-viewZoomYFix, yEnd+viewZoomYFix);
                }
            }
        }
        //唯一个公有方法,对指定范围的X轴区域进行缩放。关联属性会决定是否同时缩放Y轴。使用默认的series参数会对所有序列进行操作,否则只缩放指定的序列。
        public void Zoom(double xStart, double xEnd, Series series = null)
        {
            if (series == null)
                foreach (Series s in this.Series)
                    ZoomInternal(xStart, xEnd, s);
            else if (this.Series.Contains(series))
                ZoomInternal(xStart, xEnd, series);
            else
                throw new Exception("This chart DO NOT contains parameter-specificed series.");
        }
        private void LinkageZoom(object sender, ViewEventArgs vea)
        {
            //如果滚动了X滚动条,应重新计算Y值范围并进行Y放大.这里不考虑第二条X轴(X2)
            if (viewZoomAutoLinkage && vea.Axis.AxisName == AxisName.X)
            {
                double xStart = vea.ChartArea.AxisX.ScaleView.ViewMinimum;
                double xEnd = vea.ChartArea.AxisX.ScaleView.ViewMaximum;
                xStart = vea.NewPosition;
                xEnd = vea.NewPosition + vea.NewSize;
                //找出哪些序列绑定了事件参数中的轴所在的Area
                var sList = this.Series.Where(s => s.ChartArea == vea.ChartArea.Name);
                if (sList.Any())
                    foreach (var s in sList)
                        Zoom(xStart, xEnd, s);
            }
        }
    }
}


使用时:

myChart1.ViewZoomAutoLinkage = true;

myChart1.ViewZoomYFix = 1;

myChart1.Zoom(3,5,myChart1.Series[0]);

使用效果:

这里添加了一系列数据点,风格等属性使用了默认。

原始数据图:

应用X轴3~5缩放视图后:

拖动X滚动条后:


最后是附件,编译过的用户控件链接库。使用时直接项目引用然后在工具箱里找就好。

注意自己编译的话,请新建-用户控件,复制代码,修改命名空间。用户控件的MyChart.Designer.cs文件请删除编译错误的一行(Chart不支持AutoScale属性),敬请注意。



推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式