最近一致在開發能源平台,平台中很多能耗數據都是通過使用微軟的chart控件進行圖形呈現的。考慮到要給用戶更為直觀的呈現效果,需要對原有控件的功能進行擴展。微軟chart控件沒有第三方樣chart樣式炫酷,但是勝在可定制性強,中文手冊詳細,很多效果能夠自己寫出來。
主要實現功能:1.最大值,最小值,平均值展示 2.鼠標移動到數據點繪制豎線,用tooltip的方式展示數據
最終呈現效果如圖:
解決方案:
(1)最大值,最小值,平均值呈現
之前在網上找了好久都沒有想要的效果,第三方控件往往都能直接設置。最開始我的解決方法是在ChartArea中添加單獨的series展示最值,但是呈現效果不佳:
在看了微軟的技術手冊后,發現可以在ChartArea中添加Stripline實現。以插入最大值線條為例,代碼如下:
//最大線條
double max = ammeter.Max();
StripLine stripMax = new StripLine(); stripMax.Text = string.Format("最大:{0:F}", max);//展示文本 stripMax.BackColor = Color.FromArgb(208, 109, 106);//背景色 stripMax.Interval = 0;//間隔 stripMax.IntervalOffset = max;//偏移量 stripMax.StripWidth = 0.001;//線寬 stripMax.ForeColor = Color.White;//前景色 stripMax.TextAlignment = StringAlignment.Near;//文本對齊方式 chartInfo.ChartAreas["ammeter"].AxisY.StripLines.Add(stripMax);//添加到ChartAreas中
(2)實現鼠標移動到數據點繪制豎線,用tooltip的方式展示數據
chart中可以對畫圖區域使用HitTest進行數據點檢測,之前的方案是在鼠標移動的過程中對當前鼠標的坐標區域(x為當前坐標,y為畫圖區域的高 )進行數據檢測,移動的過程中繪制跟隨鼠標的線條。實現后發現效果並不是很好,HitTest在數據點周圍的series都會判定為數據點,所以線條一直在繪制,而想要的效果鼠標移動的過程中僅在數據點時才繪制豎線。
要在數據點位置繪制線條需要獲得數據點的相對坐標,網上一直沒有找到解決辦法。起初通過x,y軸的偏移量,0點的坐標,繪圖區域的坐標可以實現相對坐標的獲取,但是發現這樣有時計算會有很大的偏差。同樣通過查找技術手冊后,發現微軟給了獲取x,y軸相對坐標的方法。
Point lastPoint = new Point();//上次點的坐標 ToolTip tp = new ToolTip();//tooltip展示條 //繪制豎線坐標 Point p1 = new Point(0, 0); Point p2 = new Point(0, 0); /// <summary> /// 鼠標移動事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void chartInfo_MouseMove(object sender, MouseEventArgs e) { this.Refresh();//刷新chart,使用clear會使chart上的圖形完全清空 Pen pen = new Pen(Color.Yellow); Graphics g = chartInfo.CreateGraphics(); string seriesInfo = ""; //tooltip文本 if (e.Location != lastPoint)//如果在上次點的位置不進行操作,此處操作會引發chart控件的refresh操作造成界面閃爍 { for (int y = 0; y <= chartInfo.Size.Height; y++)//線條范圍進行碰撞檢測 { HitTestResult result = chartInfo.HitTest(e.X, y); if (result.ChartElementType == ChartElementType.DataPoint) { foreach (DataPoint dpp in result.Series.Points)//數據點默認樣式 使用索引的方式修改偶爾會出現無法正常修改完 { dpp.MarkerStyle = MarkerStyle.Diamond; dpp.MarkerColor = Color.White; dpp.MarkerSize = 5; } int i = result.PointIndex; DataPoint dp = result.Series.Points[i]; dp.MarkerStyle = MarkerStyle.Star4;//捕獲到數據點的樣式 dp.MarkerColor = Color.Orange; dp.MarkerSize = 15; //獲取數據點的相對坐標 p1 = new Point((int)chartInfo.ChartAreas["ammeter"].AxisX.ValueToPixelPosition(dp.XValue), 0); p2 = new Point((int)chartInfo.ChartAreas["ammeter"].AxisX.ValueToPixelPosition(dp.XValue), chartInfo.Size.Height); seriesInfo = string.Format("分項:{0} 時間:{1} 能耗值:{2}", result.Series.LegendText, DateTime.FromOADate(dp.XValue), dp.YValues[0]); break; } } tp.AutoPopDelay = 5000;//展示tooltip tp.ShowAlways = false; tp.IsBalloon = true; tp.SetToolTip(chartInfo, seriesInfo); } lastPoint = e.Location;//記錄本次位置 g.DrawLine(pen, p1, p2);//繪制豎線 }
寫在最后
微軟技術手冊真香