一、概要
解决问题--ChartControl不等距x轴显示
二、CS代码
用过ChartControl的开发者们应该都知道,ChartControl中设置x轴间距间隔都是固定的数值。
比如(间隔1000)数值为:
0 1000 2000 3000 4000
1 <dxc:AxisY2D.WholeRange> 2 <dxc:Range 3 MaxValue="0" 4 MinValue="4000" 5 SideMarginsValue="0" /> 6 </dxc:AxisY2D.WholeRange>
但是,当ChartControl中的某一条数值很小例如值为3,如果不转换的话几乎在控件中看不到用户体验非常不好,解决方案就是实现不等距x轴来显示。
间隔数值可以按照自己的想法来,本文章的数值为:
0 10 100 1000 4000
如果数值设置为不等距,当ChartControl中的某一条数值很小例如值为3的时候,这时候3的数值就可以在0到10这个区间完美显示如图【图a-1】
理想是美好的,那么问题来了,控件实际的间距是固定值1000 而显示间距是0到10这时候怎么转换有人会想0到10的这个域中的值乘以100不就可以满足情况了吗。
是的,这样做可以。但是这个做法非常不科学,因为后面的三个域中的值倍数就不能这么算了。
这时候怎么解决呢?需要用到高中的数学知识分段函数。
公式如下:
附加值:(总长度*当前段数 / 段数) 第一段附加值为0
((实际值 - 域下限) / (域上限 - 域下限))*(总长度 / 段数)+ 附加值
到这里为止,可能只能大概知道这个公式是个什么情况,但是还是不知道具体为什么要这么算。我们接下来在代码中深入了解。
三、xaml代码
1.修改ChartControl x轴的显示数值(转换)
1 <local:UpAndDownLabelConverter x:Key="xconv" />
1 <DataTemplate x:Key="AxisYLabelTemplate"> 2 <ContentPresenter Content="{Binding Path=Content, Converter={StaticResource xconv}}" /> 3 </DataTemplate>
<dxc:AxisY2D.Label> <dxc:AxisLabel ElementTemplate="{StaticResource AxisYLabelTemplate}" Visibility="Visible" Visible="True"> <dxc:Axis2D.ResolveOverlappingOptions> <dxc:AxisLabelResolveOverlappingOptions AllowHide="False" /> </dxc:Axis2D.ResolveOverlappingOptions> </dxc:AxisLabel> </dxc:AxisY2D.Label>
四、算法
/// <summary> /// 推算出显示值 /// </summary> /// <param name="xValue">X轴数值</param> /// <param name="minRange">域下限</param> /// <param name="maxRange">域上限</param> /// <param name="totalLength">总长度</param> /// <param name="period">分了几段</param> /// <returns></returns> private static double RangeCalculate(double xValue, double minRange, double maxRange,double totalLength = 4000.0,int period = 4) { //实际值 需要转化的实际值 //域上限 0-10 ,10为上限 //域下限 0-10 ,0为下限 //总长度=X轴的上限。例:0 10 100 1000 4000,4000为总长度 //段数:分了几段 例:0-10,10-100,100-1000,1000-4000 分为4段 //当前段数:0-10 第1段 , 10-100 第2段 , 100-1000第3段 ,1000-4000第4段 //段附加值:(总长度 * 当前段数 / 段数) ps:第一段,段附加值为0。附加值是为了值平均 //分段函数公式:((实际值 - 域下限) / (域上限 - 域下限))*(总长度 / 段数)+ 段附加值 double x = 0.0; if (0 < xValue && xValue <= 10) { x = ((xValue - minRange) / (maxRange - minRange)) * (totalLength / period) + 0; } if (10 < xValue && xValue <= 100) { x = ((xValue - minRange) / (maxRange - minRange)) * (totalLength / period) + (totalLength * 1 / period); } if (100 < xValue && xValue <= 1000) { x = ((xValue - minRange) / (maxRange - minRange)) * (totalLength / period) + (totalLength * 2 / period); } if (1000 < xValue && xValue <= 4000) { x = ((xValue - minRange) / (maxRange - minRange)) * (totalLength / period) + (totalLength * 3 / period); } return x; }
五、Convert
1 public class NotEquidistantLabelConverter : IValueConverter 2 { 3 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 4 { 5 int target = 0; 6 7 int.TryParse(value.ToString(), out target); 8 9 if (target <= 10) 10 return 0; 11 else if (target <= 1000) 12 return 10; 13 else if (target <= 2000) 14 return 100; 15 else if (target <= 3000) 16 return 1000; 17 else if (target <= 4000) 18 return 4000; 19 return string.Empty; 20 } 21 22 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 23 { 24 throw new NotImplementedException(); 25 } 26 }
- E-Mail:zhuzhen723723@outlook.com
- QQ: 580749909(个人群)
- Blog: https://www.cnblogs.com/justzhuzhu/
- Git: https://github.com/JusterZhu
- 微信公众号