WPF雷达图
驚鏵 人气:0前言
有小伙伴提出需要实现雷达图。
由于在WPF中没有现成的雷达图控件,所以我们自己实现一个。
PS:有更好的方式欢迎推荐。
实现代码
一、创建 RadarChart.cs 菜单继承 Control代码如下
RadarChart.cs实现思路如下
1、RadarArray :存放展示集合 。
2、重写OnRender 。
3、根据三角函数和圆的半径计算出圆上的N个点绘制成多边形GetPolygonPoint()。
4、在绘制多边形的时候因为需要多个大小不一的多边形,则需要多次调用GetPolygonPoint()方法,最外层绘制150,中间层100,中心点层 50。
5、DrawPoints() 方法增加了一个bool参数isDrawText是否绘制Text文本,因为最外侧需要绘制文本。
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; namespace WPFDevelopers.Controls { public class RadarChart:Control { public ObservableCollection<RadarModel> RadarArray { get { return (ObservableCollection<RadarModel>)GetValue(RadarArrayProperty); } set { SetValue(RadarArrayProperty, value); } } public static readonly DependencyProperty RadarArrayProperty = DependencyProperty.Register("RadarArray", typeof(ObservableCollection<RadarModel>), typeof(RadarChart), new PropertyMetadata(null)); static RadarChart() { DefaultStyleKeyProperty.OverrideMetadata(typeof(RadarChart), new FrameworkPropertyMetadata(typeof(RadarChart))); } protected override void OnRender(DrawingContext drawingContext) { DrawPoints(150, drawingContext,true); DrawPoints(100, drawingContext); DrawPoints(50, drawingContext); var myPen = new Pen { Thickness = 4, Brush = Brushes.DodgerBlue }; myPen.Freeze(); StreamGeometry streamGeometry = new StreamGeometry(); using (StreamGeometryContext geometryContext = streamGeometry.Open()) { var h = this.ActualHeight / 2; var w = this.ActualWidth / 2; PointCollection points = new PointCollection(); foreach (var item in RadarArray) { var ss = new Point((item.PointValue.X - w) / 100 * item.ValueMax + w,(item.PointValue.Y - h) / 100 * item.ValueMax + h); points.Add(ss); } geometryContext.BeginFigure(points[points.Count - 1], true, true); geometryContext.PolyLineTo(points, true, true); } streamGeometry.Freeze(); SolidColorBrush rectBrush = new SolidColorBrush(Colors.LightSkyBlue); rectBrush.Opacity = 0.5; drawingContext.DrawGeometry(rectBrush, myPen, streamGeometry); } void DrawPoints(int circleRadius, DrawingContext drawingContext,bool isDrawText = false) { var myPen = new Pen { Thickness = 2, Brush = Brushes.Gainsboro }; myPen.Freeze(); StreamGeometry streamGeometry = new StreamGeometry(); using (StreamGeometryContext geometryContext = streamGeometry.Open()) { var h = this.ActualHeight / 2; var w = this.ActualWidth / 2; PointCollection points = null; if (isDrawText) points = GetPolygonPoint(new Point(w, h), circleRadius, RadarArray.Count, drawingContext); else points = GetPolygonPoint(new Point(w, h), circleRadius, RadarArray.Count); geometryContext.BeginFigure(points[points.Count - 1], true, true); geometryContext.PolyLineTo(points, true, true); } streamGeometry.Freeze(); drawingContext.DrawGeometry(null, myPen, streamGeometry); } private PointCollection GetPolygonPoint(Point center, double r, int polygonBound, DrawingContext drawingContext = null) { double g = 18; double perangle = 360 / polygonBound; double pi = Math.PI; List<Point> values = new List<Point>(); for (int i = 0; i < polygonBound; i++) { Point p2 = new Point(r * Math.Cos(g * pi / 180) + center.X, r * Math.Sin(g * pi / 180) + center.Y); if(drawingContext != null) { FormattedText formattedText = new FormattedText( RadarArray[i].Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Thin, FontStretches.Normal), 20.001D, Brushes.Black) { MaxLineCount = 1, TextAlignment = TextAlignment.Justify, Trimming = TextTrimming.CharacterEllipsis }; RadarArray[i].PointValue = p2; if (p2.Y > center.Y && p2.X < center.X) drawingContext.DrawText(formattedText, new Point(p2.X - formattedText.Width - 5, p2.Y - formattedText.Height / 2)); else if (p2.Y < center.Y && p2.X > center.X) drawingContext.DrawText(formattedText, new Point(p2.X, p2.Y - formattedText.Height)); else if (p2.Y < center.Y && p2.X < center.X) drawingContext.DrawText(formattedText, new Point(p2.X - formattedText.Width - 5, p2.Y - formattedText.Height)); else if (p2.Y < center.Y && p2.X == center.X) drawingContext.DrawText(formattedText, new Point(p2.X - formattedText.Width, p2.Y - formattedText.Height)); else drawingContext.DrawText(formattedText, new Point(p2.X, p2.Y)); } values.Add(p2); g += perangle; } PointCollection pcollect = new PointCollection(values); return pcollect; } } }
二、创建RadarChartExample.xaml代码如下
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.RadarChartExample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews" xmlns:wpfdev="https://github.com/yanjinhuagood/WPFDevelopers" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid Background="Gainsboro" > <Border Background="White" Width="500" Height="500"> <Grid Margin="20,10"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="40"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="40"/> <RowDefinition/> </Grid.RowDefinitions> <WrapPanel> <Rectangle Width="6" Height="26" Fill="Black"/> <TextBlock Text="能力图" FontWeight="Black" FontSize="24" Padding="10,0"/> </WrapPanel> <wpfdev:RadarChart Grid.Column="0" Grid.Row="1" RadarArray="{Binding RadarModels,RelativeSource={RelativeSource AncestorType=local:RadarChartExample}}"/> </Grid> </Border> </Grid> </UserControl>
三、创建RadarChartExample.xaml.cs代码如下
ReadrChartExample.cs 思路如下
1、ValueMax 需要注意最小值0,最大值100。
using System.Collections.Generic; using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; using WPFDevelopers.Controls; namespace WPFDevelopers.Samples.ExampleViews { /// <summary> /// RadarChartExample.xaml 的交互逻辑 /// </summary> public partial class RadarChartExample : UserControl { public ObservableCollection<RadarModel> RadarModels { get { return (ObservableCollection<RadarModel>)GetValue(RadarModelsProperty); } set { SetValue(RadarModelsProperty, value); } } public static readonly DependencyProperty RadarModelsProperty = DependencyProperty.Register("RadarModels", typeof(ObservableCollection<RadarModel>), typeof(RadarChartExample), new PropertyMetadata(null)); List<ObservableCollection<RadarModel>> collectionList = new List<ObservableCollection<RadarModel>>(); public RadarChartExample() { InitializeComponent(); RadarModels = new ObservableCollection<RadarModel>(); var collection1 = new ObservableCollection<RadarModel>(); collection1.Add(new RadarModel { Text = "击杀", ValueMax = 95}); collection1.Add(new RadarModel { Text = "生存", ValueMax = 80 }); collection1.Add(new RadarModel { Text = "助攻", ValueMax = 70 }); collection1.Add(new RadarModel { Text = "物理", ValueMax = 80 }); collection1.Add(new RadarModel { Text = "魔法", ValueMax = 90 }); collection1.Add(new RadarModel { Text = "防御", ValueMax = 87 }); collection1.Add(new RadarModel { Text = "金钱", ValueMax = 59 }); var collection2 = new ObservableCollection<RadarModel>(); collection2.Add(new RadarModel { Text = "击杀", ValueMax = 59 }); collection2.Add(new RadarModel { Text = "生存", ValueMax = 80 }); collection2.Add(new RadarModel { Text = "助攻", ValueMax = 90 }); collection2.Add(new RadarModel { Text = "物理", ValueMax = 70 }); collection2.Add(new RadarModel { Text = "魔法", ValueMax = 80 }); collection2.Add(new RadarModel { Text = "防御", ValueMax = 90 }); collection2.Add(new RadarModel { Text = "金钱", ValueMax = 66 }); collectionList.AddRange(new[] { collection1, collection2 }); RadarModels = collectionList[0]; } bool isRefresh = false; private void Button_Click(object sender, RoutedEventArgs e) { if (!isRefresh) RadarModels = collectionList[1]; else RadarModels = collectionList[0]; isRefresh = !isRefresh; } } }
效果预览
数据来源于英雄联盟用户
数据1《屈越》
数据2《方拯》
加载全部内容