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


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

    前言

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

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

     

     

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

    微信群人数太多扫码进不来了,请添加个人微信邀请你(请标注理由)。(yanjinhuawechat)或(W_Feng_aiQ)

    WPF开发者QQ群: 340500857 

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

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

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

  • 相关阅读:
    Ubuntu环境下NFS服务器搭建
    Node.js+koa2
    linux rhel7下安装python
    数据结构之链表
    0416. Partition Equal Subset Sum (M)
    0395. Longest Substring with At Least K Repeating Characters (M)
    1015. Smallest Integer Divisible by K (M)
    0227. Basic Calculator II (M)
    0337. House Robber III (M)
    0804. Unique Morse Code Words (E)
  • 原文地址:https://www.cnblogs.com/yanjinhua/p/15450989.html
Copyright © 2020-2023  润新知