WPF-自定义雷达图(一)

1、创建一下UserControl,名为“RadarChartControl”

前台:

<UserControl x:Class="WpfApplication4.RadarChartControl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Loaded="RadarChartControl_OnLoaded">
<Canvas x:Name="CanvasPanel" HorizontalAlignment="Center" VerticalAlignment="Center">
</Canvas>
</UserControl>

后台:

/// <summary>
/// RadarChartControl.xaml 的交互逻辑
/// </summary>
public partial class RadarChartControl : UserControl
{
public RadarChartControl()
{
InitializeComponent();
}
#region 属性
/// <summary>
/// 尺寸大小
/// 高宽大小一样
/// </summary>
public double Size
{
get { return (double) GetValue(SizeProperty); }
set { SetValue(SizeProperty,value);}
}

public static readonly DependencyProperty SizeProperty = DependencyProperty.Register("Size", typeof (double),
typeof (RadarChartControl), new PropertyMetadata(200.0));
/// <summary>
/// 标题
/// </summary>
public List<ArgumentModel> Arguments
{
get { return (List<ArgumentModel>)GetValue(ArgumentsProperty); }
set { SetValue(ArgumentsProperty,value);}
}

public static readonly DependencyProperty ArgumentsProperty = DependencyProperty.Register("Arguments", typeof(List<ArgumentModel>),
typeof(RadarChartControl), new PropertyMetadata(new List<ArgumentModel>()));
/// <summary>
/// 数据
/// </summary>
public List<ChartItem> Datas
{
get { return (List<ChartItem>)GetValue(DatasProperty); }
set { SetValue(DatasProperty, value); }
}

public static readonly DependencyProperty DatasProperty = DependencyProperty.Register("Datas", typeof(List<ChartItem>),
typeof(RadarChartControl), new PropertyMetadata(new List<ChartItem>()));
/// <summary>
/// 获取或设置线条颜色
/// </summary>
public Brush BorderBrush
{
get { return (Brush)GetValue(BorderBrushProperty); }
set { SetValue(BorderBrushProperty, value); }
}

public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register("BorderBrush", typeof(Brush),
typeof(RadarChartControl), new PropertyMetadata(Brushes.RoyalBlue));
/// <summary>
/// 连接点大小
/// </summary>
public int EllipseSize = 7;
/// <summary>
/// 控件大小
/// </summary>
public double TotalSize
{
get
{
double size = Size + 200;
return size;
}
}
/// <summary>
/// 面板
/// </summary>
public Canvas ChartCanvas=new Canvas();

//声明和注册路由事件
public static readonly RoutedEvent TitleClickRoutedEvent =
EventManager.RegisterRoutedEvent("TitleClick", RoutingStrategy.Bubble, typeof(EventHandler<RoutedEventArgs>), typeof(RadarChartControl));
//CLR事件包装
public event RoutedEventHandler TitleClick
{
add { this.AddHandler(TitleClickRoutedEvent, value); }
remove { this.RemoveHandler(TitleClickRoutedEvent, value); }
}
//激发路由事件,借用Click事件的激发方法
protected void OnClick(object sender, RoutedEventArgs e)
{
RoutedEventArgs args = new RoutedEventArgs(TitleClickRoutedEvent, e);
this.RaiseEvent(args);
}
#endregion

private void RadarChartControl_OnLoaded(object sender, RoutedEventArgs e)
{
if (!CheckData())
{
throw new Exception("RadarChart的数据之间不匹配!请重新配置!");
}
//获取最大数值
int maxData = Datas.Max(i => i.DataList.Max(o => o.Data));
//设置面板和背景
SetCanvasAndBackground(maxData);
//设置数据标题
SetDataTitle(Datas);
//获取半圈大小
double length = Size / 2 / maxData;
//连接点半径
int ellipseR = EllipseSize / 2;
foreach (var chartItem in Datas)
{
var color = chartItem.Color;

//俩个多边形,一个设置背景,一个设置边框
Polygon polygonArea = new Polygon() { Fill = color, Opacity = 0.2, StrokeThickness = 0 };
Polygon polygonBorder = new Polygon() { Fill = Brushes.Transparent, Stroke = color, StrokeThickness = 0.8 };

int index = 0;
foreach (var data in chartItem.DataList)
{
double currentAngle = Angle * index + 90;
double angle = (currentAngle / 360) * 2 * Math.PI;
var r = data.Data * length;
double x = Size / 2 + r * Math.Cos(angle);
double y = Size / 2 - r * Math.Sin(angle);
//多边形添加节点
var point = new Point()
{
X = x,
Y = y
};
polygonArea.Points.Add(point);
polygonBorder.Points.Add(point);
//设置节点Style
var ellipse = new Ellipse() { Width = EllipseSize, Height = EllipseSize, Fill = color };
Canvas.SetLeft(ellipse, x - ellipseR);
Canvas.SetTop(ellipse, y - ellipseR);
ChartCanvas.Children.Add(ellipse);

index++;
}
ChartCanvas.Children.Add(polygonArea);
ChartCanvas.Children.Add(polygonBorder);
}
//设置标题
SetArguments();
}
/// <summary>
/// 设置数据标题
/// </summary>
/// <param name="datas"></param>
private void SetDataTitle(List<ChartItem> datas)
{
RadarChartTitleList titleList=new RadarChartTitleList();
titleList.ItemSoure = datas;
double angle = Math.PI*0.25;
double x = TotalSize/2 + (TotalSize/2)*Math.Sin(angle);
Canvas.SetLeft(titleList,x);
Canvas.SetTop(titleList, x);
CanvasPanel.Children.Add(titleList);
}

/// <summary>
/// 设置标题
/// </summary>
private void SetArguments()
{
int index = 0;
foreach (var argument in Arguments)
{
var button = new ChartButton();
button.Content = argument.Name;
button.Icon = argument.IconSource;
button.MyButton.Click += OnClick;
//绘制XY
double currentAngle = Angle * index + 90;
double angle = (currentAngle / 360) * 2 * Math.PI;
var r = TotalSize / 2;
double x = r + r * Math.Cos(angle) - (button.Width / 2);
double y = r - r * Math.Sin(angle) - (button.Height / 2);

//添加按钮高度差异
y = y + Math.Sin(angle) * (button.Width / 2 - button.Height / 2);

Canvas.SetLeft(button, x );
Canvas.SetTop(button, y );

CanvasPanel.Children.Add(button);
index++;
}
}

/// <summary>
/// 检查数据
/// </summary>
/// <returns></returns>
private bool CheckData()
{
if (Datas==null)
{
return false;
}

foreach (var data in Datas)
{
bool result = !Datas.Any(i => i.DataList.Count != data.DataList.Count);
if (!result)
{
return false;
}
}
return true;
}

/// <summary>
/// 设置面板和背景
/// </summary>
/// <param name="maxIndex"></param>
private void SetCanvasAndBackground(int maxIndex)
{
CanvasPanel.Height = TotalSize;
CanvasPanel.Width = TotalSize;

//面板
ChartCanvas.Height = Size;
ChartCanvas.Width = Size;
double canvasX = (TotalSize - Size)/2;
Canvas.SetLeft(ChartCanvas, canvasX);
Canvas.SetTop(ChartCanvas, canvasX);
CanvasPanel.Children.Add(ChartCanvas);
//画圈和直线
var color = BorderBrush;
double length = Size/2/maxIndex;
for (int i = 0; i < maxIndex; i++)
{
double height = length*2*(i + 1);
double left = Size / 2 - length * (i + 1);
var ellipse = new Ellipse() { Stroke = color, StrokeThickness = 0.5, Height = height, Width = height };
Canvas.SetLeft(ellipse, left);
Canvas.SetTop(ellipse, left);

ChartCanvas.Children.Add(ellipse);
}
//暂时设定:4个标题时,画线
if (Arguments.Count == 4)
{
//竖向直线
Path verticalPath = new Path()
{
Stroke = color,
StrokeThickness = 0.2,
};
//添加数据
StreamGeometry geometry = new StreamGeometry();
geometry.FillRule = FillRule.Nonzero; //声前F0还是F1,现在是F1
using (StreamGeometryContext ctx = geometry.Open())
{

ctx.BeginFigure(new Point(Size / 2, 0), true, true);

ctx.LineTo(new Point(Size / 2, Size), true, false);

}
geometry.Freeze();
verticalPath.Data = geometry;
ChartCanvas.Children.Add(verticalPath);
//横向直线
Path horizontalPath = new Path()
{
Stroke = color,
StrokeThickness = 0.2,
};
//添加数据
geometry = new StreamGeometry();
geometry.FillRule = FillRule.Nonzero; //声前F0还是F1,现在是F1
using (StreamGeometryContext ctx = geometry.Open())
{

ctx.BeginFigure(new Point(0,Size / 2), true, true);

ctx.LineTo(new Point(Size,Size / 2), true, false);

}
geometry.Freeze();
horizontalPath.Data = geometry;
ChartCanvas.Children.Add(horizontalPath);
}
}
/// <summary>
/// 分隔角度
/// </summary>
private double Angle
{
get
{
int count=Arguments.Count;
double angle = 360/count;
return angle;
}
}
}
/// <summary>
/// 类标题
/// </summary>
public class ArgumentModel
{
public ImageSource IconSource { get; set; }
public string Name { get; set; }
}
/// <summary>
/// 单组数据
/// </summary>
public class ChartItem
{
public Brush Color { get; set; }
List<ChartData> dataList=new List<ChartData>();

public List<ChartData> DataList
{
get { return dataList; }
set { dataList = value; }
}

public object Name { get; set; }
}
/// <summary>
/// 数据
/// </summary>
public class ChartData
{
public string Name { get; set; }
public int Data { get; set; }
}

时间: 2024-11-07 12:12:45

WPF-自定义雷达图(一)的相关文章

WPF 自定义雷达图(二)

2.然后自定义一下标题按钮,命名为“ChartButton” 前台: <UserControl x:Class="WpfApplication4.ChartButton" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="

WPF 自定义雷达图(四)

4.最后,引用即可,案例如下: <wpfApplication4:RadarChartControl x:Name="RadarChartControl" HorizontalAlignment="Center" VerticalAlignment="Center" TitleClick="RadarChartControl_OnTitleClick"> <wpfApplication4:RadarChart

WPF 自定义雷达图

3.最后定义数据标题显示列表 前台: <UserControl x:Class="WpfApplication4.RadarChartTitleList" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://s

在Unity中使用uGUI绘制自定义图形(饼状图 雷达图)

饼状图或者是雷达图是根据属性自动生成的自定义图形.这里展示了如何使用uGUI完成这一功能. 先附上我制作雷达图的控件的代码  UIPropWidget.cs using UnityEngine; using System.Collections.Generic; using UnityEngine.UI; /* * * 2 6 * * 3 7 * * 0 1 5 4 * * * 2 6位为属性0 3为属性1 0为属性2 4为属性3 7为属性4 */ public class UIPropWidg

WPF DevExpress 设置雷达图Radar样式

  DevExpress中定义的ChartControl很不错,很多项目直接使用这种控件. 本节讲述雷达图的样式设置 <Grid> <Grid.Resources> <DataTemplate x:Key="LabelItemDataTemplate" DataType="dxc:SeriesLabelItem"> <Border CornerRadius="8" Padding="8,1&qu

WPF 雷达图

雷达图逻辑同玫瑰图差不多,不同的地方在于绘制雷达网络,也就是蜘蛛网这样的底图. 界面代码 <UserControl x:Class="Painter.RadarControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc=&qu

WPF自定义路由事件

一 概要 本文通过实例演示WPF自定义路由事件的使用,进而探讨了路由事件与普通的CLR事件的区别(注:"普通的CLR事件"这个说法可能不太专业,但是,我暂时也找不到什么更好的称呼,就这么着吧,呵呵.)(扩展阅读:例说.NET事件的使用). 二 实例演示与说明 1 新建DetailReportEventArgs类,该类派生自RoutedEventArgs类,RoutedEventArgs类包含与路由事件相关的状态信息和事件数据.DetailReportEventArgs类中定义了属性Ev

javascript雷达图/星形图/极坐标图Radar &amp; Polar chart介绍

Radar & Polar chart 控件为软件开发人员提供了雷达图/星形图/极坐标图,它以轴上的同一个点为起点,绘制出三个或更多的变量. 具体功能: 任意多的轴 动态或静态 简单.堆积.100%堆积的图表 网格线能转换为圆环 在轴之间进行填充 以自定义范围值填充 跨平台 导出为图像 可通过JavaScript进行控制 可直接通过HTML文件进行设置和数据交换 自定义图像和Flash(动态)背景 无限的标签 可旋转的标签 可使用预设频率重新加载数据 格式任何气球文本 Amcharts可以从简单

Android自定义控件 芝麻信用分雷达图

本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. 1.介绍 首先看下支付宝上芝麻信用分的效果图: 2.思路 确定雷达图中心点坐标 绘制多边形及连接线 根据维度值绘制覆盖区域 绘制分数 绘制每个维度的标题文字和图标 3.实现 获取布局的中心坐标 在onSizeChanged(int w, int h, int oldw, int oldh)方法里面,根据View的长宽,计算出雷达图的半径(这里取布局宽高最小值的四分之一,可以自定义),获取整个布局的中心坐标.

手动撸个Android雷达图(蜘蛛网图)RadarView

公司产品需要一个雷达图来展示各维度的比重,网上找了一波,学到不少,直接自己上手来撸一记 无图言虚空 简单分析一波,确定雷达图正几边形的--正五边形 int count=5,分为几个层数--4 层 int layerCount=4     @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);         drawPolygon(canvas);//画边         drawLin