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《方拯》

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

WPF开发者QQ群: 340500857

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

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

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

WPF实现雷达图(仿英雄联盟)的更多相关文章

  1. WPF 自定义雷达图

    自定义雷达图表如下: Git下载地址:https://github.com/Kybs0/RadarChartControl 1.创建UserControl,名为“RadarChartControl” ...

  2. Android仿掌上英雄联盟首页,实现折叠效果

    概述 仿掌上英雄联盟首页的demo 详细 代码下载:http://www.demodashi.com/demo/10695.html 首页大概分为几个部分 状态栏 标题栏 轮播图 切换的Tab 资讯列 ...

  3. C# WPF从RIOT API获取数据(RIOT代表作品《英雄联盟》)

    微信公众号:Dotnet9,网站:Dotnet9,问题或建议:请网站留言, 如果对您有所帮助:欢迎赞赏. C# WPF从RIOT API获取数据(RIOT代表作品<英雄联盟>) 阅读导航 ...

  4. WPF DevExpress 设置雷达图Radar样式

      DevExpress中定义的ChartControl很不错,很多项目直接使用这种控件. 本节讲述雷达图的样式设置 <Grid> <Grid.Resources> <D ...

  5. WPF系列教程——(一)仿TIM QQ界面 - 简书

    原文:WPF系列教程--(一)仿TIM QQ界面 - 简书 TIM QQ 我们先来看一下TIM QQ长什么样,整体可以将界面分为三个部分 TIM QQ 1. 准备 阅读本文假设你已经有XAML布局的基 ...

  6. Emgu-WPF 激光雷达研究-绘制雷达图

    原文:Emgu-WPF 激光雷达研究-绘制雷达图 硬件:Hokuyo URG04LX 环境:VS2017- win10- 64  Emgu_3.2.0.2682 语言:C#  WPF   数据解析参考 ...

  7. Wayos网吧路由英雄联盟频繁掉线解决办法

    英雄联盟某些机器瞬间ping值飙升,然后一直掉线重连!研究好久,解决了,经验与大家分享 第一步,在路由器地址后加qos_ext.htm进入qos参数设置页面(如果出现不了设置界面请更新固件).比如:h ...

  8. 用Python爬取英雄联盟(lol)全部皮肤

    小三:"怎么了小二?一副无精打采的样子!" 小二:"唉!别提了,还不是最近又接触了一个叫英雄联盟的游戏,游戏中很多皮肤都需要花钱买,但是我钱不够呀..." 小三 ...

  9. python爬虫——《英雄联盟》英雄及皮肤图片

    还记得那些年一起网吧开黑通宵的日子吗?<英雄联盟>绝对是大学时期的风靡游戏,即使毕业多年的大学同学相聚,难免不怀念一番当时一起玩<英雄联盟>的日子. 今天就给大家分享一下英雄及 ...

随机推荐

  1. MybatisPlus(一)——

    MybatisPlus https://www.cnblogs.com/JohanChan/p/14982870.html

  2. Python - 面向对象编程 - __call__()

    __call()__ 的作用 使得类实例对象可以像普通函数那样被调用 实际栗子 from typing import Callable class PoloBlog: def __init__(sel ...

  3. 路由懒加载---Vue Router

    一.什么是懒加载? 懒加载也就是延迟加载或者按需加载,即在需要的时候进行加载. 二.为什么在Vue路由中使用懒加载? 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常 ...

  4. Math.round真的是四舍五入吗?我不这么认为

    public static long round(double a) 返回最接近参数的 long.结果将舍入为整数:加上 1/2,对结果调用 floor 并将所得结果强制转换为 long 类型.换句话 ...

  5. 图论---DFS

    图论---DFS 1. 图的遍历 在理解DFS算法之前,我们首先需要对什么是遍历进行了解,遍历的概念就是:从某一个点出发(一般是首或尾),依次将数据结构中的每一个数据访问且只访问一遍. 2. DFS简 ...

  6. [CSP-J2020] 优秀的拆分

    [CSP-J2020] 优秀的拆分 难度:普及- 题目描述 一般来说,一个正整数可以拆分成若干个正整数的和. 例如,1=1,10=1+2+3+4 等.对于正整数 n 的一种特定拆分,我们称它为&quo ...

  7. Django学习day15BBS项目开发3.0

    每日测验 """ 今日考题 1.django admin作用及用法 2.media配置如何实现,基于该配置能够做到什么以及需要注意什么 3.阐述博客园为何支持用户自定义个 ...

  8. git实战-linux定时监控github更新状态(二)

    系列文章 git介绍-常用操作(一)✓ git实战-linux定时监控github更新状态(二)✓ 本文主要内容 如何查看github的本地仓库和远程仓库的同步情况 linux服务器定时监控githu ...

  9. 性能再提升70%?大咖前瞻带你揭开.NET6的神秘面纱!

    本月初微软官宣.NET 6 的RC1即将在11月正式发布,这意味着.NET6正式版跟我们见面的时间又近了一步.在之前的.NET6预览版本中,微软加入了大量新功能特性,而在最终版本中将不再额外加入新的内 ...

  10. hashCode 和 equals 的区别

    今天记录一下hashCode的知识,以前都没有怎么接触过的,感觉还是很陌生,专门去学习了一下 首先我最大的问题就是hashCode究竟是干什么 的,现在也一知半解了吧, 哈希值是一个对象的地址值,是一 ...