WPF实现雷达图(仿英雄联盟)

  • A+
所属分类:.NET技术
摘要

WPF 开发者QQ群 : 340500857  | 微信群 -> 进入公众号主页 加入组织

WPF开发者QQ群: 340500857  | 微信群 -> 进入公众号主页 加入组织

前言

    有小伙伴提出需要实现雷达图。 

WPF实现雷达图(仿英雄联盟)

 

 

由于在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《方拯

WPF实现雷达图(仿英雄联盟)

 

更多教程欢迎关注微信公众号:加微信群限时

WPF实现雷达图(仿英雄联盟)

WPF开发者QQ群: 340500857 

blogs: https://www.cnblogs.com/yanjinhua

源码Github:https://github.com/yanjinhuagood/WPFDevelopers.git

gitee:https://gitee.com/yanjinhua/WPFDevelopers.git