WPF 自定义 写实风 雷达图控件

WPF 自定义 写实风 雷达图控件

控件主要使用Transform实现控件的旋转绘制
先来张图Look Look。。。
在这里插入图片描述
XAMl:

  <UserControl.Resources>
        <Style TargetType="Line">
            <Setter Property="Stroke" Value="#AB72D458"/>
            <Setter Property="X1" Value="0"/>
            <Setter Property="Y1" Value="0"/>
            <Setter Property="X2" Value="1"/>
            <Setter Property="Y1" Value="0"/>
            <Setter Property="Stretch" Value="Fill"/>
            <Setter Property="StrokeThickness" Value="1"/>
            <Setter Property="RenderTransformOrigin" Value="0.5,0.05"/>
        </Style>
    </UserControl.Resources>

    <Grid Margin="8" x:Name="RadarGrid" Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}">
        <Ellipse Margin="-8" StrokeThickness="8">
            <Ellipse.Stroke>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#777777"/>
                    <GradientStop Color="White" Offset="1"/>
                </LinearGradientBrush>
            </Ellipse.Stroke>
            <Ellipse.Effect>
                <DropShadowEffect ShadowDepth="4" BlurRadius="20" Direction="-90" Color="#B6B4B4"/>
            </Ellipse.Effect>
        </Ellipse>

        <!--#region 底图 -->
        <Ellipse>
            <Ellipse.Fill>
                <RadialGradientBrush>
                    <GradientStop Color="#FF02AE03"/>
                    <GradientStop Color="#FF034300" Offset="0.904"/>
                </RadialGradientBrush>
            </Ellipse.Fill>
        </Ellipse>
        <!--#endregion-->

        <!--#region 扫描线 -->

        <!--<Grid RenderTransformOrigin="0.5,0.5">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.Triggers>
                <EventTrigger RoutedEvent="Loaded">
                    <BeginStoryboard>
                        <Storyboard RepeatBehavior="Forever">
                            <DoubleAnimation Storyboard.TargetName="ScanEllipse" Duration="0:0:2"
                                             Storyboard.TargetProperty="Angle" From="0" To="360"/>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Grid.Triggers>
            <Grid.RenderTransform>
                <RotateTransform x:Name="ScanEllipse"/>
            </Grid.RenderTransform>
            <Line X1="0" Y1="0" X2="1" Y2="0" StrokeThickness="4" StrokeDashCap="Round" StrokeDashArray="{x:Null}" Stretch="Fill">
                <Line.Stroke>
                    <LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
                        <GradientStop Color="#FFC5FFB6" Offset="0.008"/>
                        <GradientStop Color="Transparent" Offset="1"/>
                    </LinearGradientBrush>
                </Line.Stroke>
                <Line.Effect>
                    <BlurEffect/>
                </Line.Effect>
            </Line>
        </Grid>-->

        <!--#endregion-->

        <Line/>
        <Line>
            <Line.RenderTransform>
                <RotateTransform Angle="30"/>
            </Line.RenderTransform>
        </Line>

        <Line>
            <Line.RenderTransform>
                <RotateTransform Angle="60"/>
            </Line.RenderTransform>
        </Line>
        <Line>
            <Line.RenderTransform>
                <RotateTransform Angle="90"/>
            </Line.RenderTransform>
        </Line>
        <Line>
            <Line.RenderTransform>
                <RotateTransform Angle="120"/>
            </Line.RenderTransform>
        </Line>
        <Line>
            <Line.RenderTransform>
                <RotateTransform Angle="150"/>
            </Line.RenderTransform>
        </Line>

        <Ellipse Stroke="#FF0C6703" StrokeThickness="2"/>
        <Ellipse Stroke="#E4A0F424" Margin="50"/>
        <Ellipse Stroke="#C3A0F424" Margin="100"/>
        <Ellipse Stroke="#9EA0F424" Margin="150"/>
        <Ellipse Stroke="#AEA0F424" Margin="200"/>
        <Ellipse Fill="#AEA0F424" Width="10" Height="10"/>

        <Grid x:Name="dataGrid"/>
        <!--<TextBlock Text="10" VerticalAlignment="Center" Foreground="{StaticResource MahApps.Brushes.ThemeBackground}" Margin="0" />
        <TextBlock Text="8" VerticalAlignment="Center" Foreground="{StaticResource MahApps.Brushes.ThemeBackground}" Margin="48" />
        <TextBlock Text="6" VerticalAlignment="Center" Foreground="{StaticResource MahApps.Brushes.ThemeBackground}" Margin="98" />
        <TextBlock Text="4" VerticalAlignment="Center" Foreground="{StaticResource MahApps.Brushes.ThemeBackground}" Margin="148"/>
        <TextBlock Text="2" VerticalAlignment="Center" Foreground="{StaticResource MahApps.Brushes.ThemeBackground}" Margin="198"/>-->
    </Grid>

C#:

  /// <summary>
    /// RadarChart.xaml 的交互逻辑
    /// </summary>
    public partial class RadarChart : UserControl
    {
        public RadarChart()
        {
            InitializeComponent();
        }
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            Refresh();
        }

        public ObservableCollection<RadarData> RadarDatas
        {
            get { return (ObservableCollection<RadarData>)GetValue(RadarDatasProperty); }
            set { SetValue(RadarDatasProperty, value); }
        }
        public static readonly DependencyProperty RadarDatasProperty =
            DependencyProperty.Register("RadarDatas", typeof(ObservableCollection<RadarData>), typeof(RadarChart), new PropertyMetadata(null, OnDataChanged));

        private static void OnDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sen = (d as RadarChart);
            if (sen.RadarDatas != null)
            {
                sen.RadarDatas.CollectionChanged += (s, er) => sen.Refresh();
            }
        }

        private const double maxDistance = 10;
        private void Refresh()
        {
            dataGrid.Children.Clear();
            if (RadarDatas == null)
            {
                return;
            }
            Point center = new Point(RadarGrid.ActualHeight / 2, RadarGrid.ActualWidth / 2);
            foreach (var item in RadarDatas)
            {
                if (item.Distance > maxDistance)
                {
                    continue;
                }

                ContentControl contentControl = new ContentControl() { Width = 30, Height = 30 };
                double locat = 0;
                if (item.Distance != 0)
                {
                    locat = item.Distance / maxDistance * (RadarGrid.ActualHeight + contentControl.Width) / 2 - (contentControl.Width / 2);
                }

                // 图形化的显示内容
                item.Content.HorizontalAlignment = HorizontalAlignment.Center;
                item.Content.VerticalAlignment = VerticalAlignment.Center;
                contentControl.Content = item.Content;
                TranslateTransform translate = new TranslateTransform() { Y = -locat };
                contentControl.RenderTransform = translate;
                contentControl.Foreground = Brushes.White;

                // 显示当前距离的文本
                TextBlock textBlock = new TextBlock() { Text = item.Distance.ToString("f1")};
                textBlock.VerticalAlignment = VerticalAlignment.Bottom;
                textBlock.FontSize = 14d;
                textBlock.HorizontalAlignment = HorizontalAlignment.Center;
                TranslateTransform translateText = new TranslateTransform() { Y = -locat / 2 };
                RotateTransform rotateText = new RotateTransform(-item.Angle);
                TransformGroup group = new TransformGroup();
                group.Children.Add(rotateText);
                group.Children.Add(translateText);
                textBlock.RenderTransform = group;
                textBlock.Foreground = Brushes.White;

                // 划线
                Line line = new Line() { X1 = 0, Y1 = 0, X2 = 0, Y2 = 1, Width = 0d,Height=0d};
                var lineHeight = item.Distance / maxDistance * (RadarGrid.ActualHeight + contentControl.Width) / 2 - (contentControl.Width / 2);
                if (lineHeight > contentControl.Width)
                {
                    line.Height = item.Distance / maxDistance * (RadarGrid.ActualHeight + contentControl.Width) / 2 - (contentControl.Width / 2);
                    line.Width = item.Distance / maxDistance * (RadarGrid.ActualHeight + contentControl.Width) / 2;
                }

                line.Stroke = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#9EBE0E19"));
                line.StrokeThickness = 3;
                line.VerticalAlignment = VerticalAlignment.Bottom;
                line.HorizontalAlignment = HorizontalAlignment.Center;
                Grid lineGrid = new Grid();
                lineGrid.RowDefinitions.Add(new RowDefinition());
                lineGrid.RowDefinitions.Add(new RowDefinition());

                lineGrid.Children.Add(line);
                lineGrid.Children.Add(textBlock);


                Grid grid = new Grid();
                RotateTransform rotate = new RotateTransform() { Angle = item.Angle };
                grid.RenderTransformOrigin = new Point(0.5, 0.5);
                grid.RenderTransform = rotate;

                grid.Children.Add(contentControl);
                grid.Children.Add(lineGrid);

                dataGrid.Children.Add(grid);
            }
        }
    }

    public class RadarData
    {
        public double Angle { get; set; }

        public double Distance { get; set; }

        public FrameworkElement Content { get; set; }
    }

测试使用数据:

  double testdis = 10;
        double testdis1 = 0;
        double testdis2 = 5;
        /// <summary>
        /// 测试雷达图
        /// </summary>
        void TestRadar()
        {
            testdis = testdis <= 1 ? 10 : testdis;
            testdis1 = testdis1 >= 9 ? 0 : testdis1;
            testdis2 = testdis2 >= 9 ? 0 : testdis2;
            RadarTestData.Clear();
            testdis -= 0.02;

            RadarData data = new RadarData()
            {
                Angle = -30,
                Distance = testdis,
                Content = new PackIconMaterial() { Width = 30, Foreground = Brushes.Red, Height = 30, Kind = PackIconMaterialKind.Run },
            };
            RadarTestData.Add(data);


            testdis1 += 0.02;
            RadarData data1 = new RadarData()
            {
                Angle = 120,
                Distance = testdis1,
                Content = new PackIconMaterial() { Width = 20, Foreground = Brushes.Red, Height = 20, Kind = PackIconMaterialKind.Archive },
            };
            RadarTestData.Add(data1);

            testdis2 += 0.02;
            RadarData data2 = new RadarData()
            {
                Angle = 45,
                Distance = testdis2,
                Content = new PackIconMaterial() { Width = 20, Foreground = Brushes.Red, Height = 20, Kind = PackIconMaterialKind.AlarmLight },
            };
            RadarTestData.Add(data2);
        }
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知名君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值