WPF 云图

/// <summary>
/// 颜色温度对应表
/// </summary>
public class ColorTable
{
    public int Value { get; set; }
    public int R { get; set; }
    public int G { get; set; }
    public int B { get; set; }
    public double Alpha { get; set; }
 
    public ColorTable()
    {
        Value = R = G = B = 0;
        Alpha = 255;
    }
 
    public ColorTable(int value, int r, int g, int b, double alpha = 255)
    {
        Value = value;
        R = r;
        G = g;
        B = b;
        Alpha = alpha;
    }
}

  

/// <summary>
/// 温湿度结构
/// </summary>
public class HumiTemp
{
    public HumiTemp()
    {
        X = 0;
        Y = 0;
        MgrObjId = "";
        Id = "";
        Value = 0;
    }
    public HumiTemp(double x, double y, string mgrobjid, string id, double value = 0)
    {
        X = x;
        Y = y;
        MgrObjId = mgrobjid;
        Id = id;
        Value = value;
    }
    public double X { get; set; }
    public double Y { get; set; }
    /// <summary>
    /// 管理对象ID
    /// </summary>
    public string MgrObjId { get; set; }
    /// <summary>
    /// 属性ID
    /// </summary>
    public string Id { get; set; }
    /// <summary>
    /// 外部传入值
    /// </summary>
    public double Value { get; set; }
}

  

/// <summary>
/// CloudChart.xaml 的交互逻辑
/// </summary>
public partial class CloudChart : UserControl
{
    private static readonly DependencyProperty ColorListProperty = DependencyProperty.Register("ColorList", typeof(List<ColorTable>), typeof(CloudChart), new PropertyMetadata(new List<ColorTable>()));
    private static readonly DependencyProperty HTListProperty = DependencyProperty.Register("HTList", typeof(List<HumiTemp>), typeof(CloudChart), new PropertyMetadata(new List<HumiTemp>()));
    private static readonly DependencyProperty CabWidthProperty = DependencyProperty.Register("CabWidth", typeof(double), typeof(CloudChart), new PropertyMetadata(double.NaN));
    private static readonly DependencyProperty CabHeightProperty = DependencyProperty.Register("CabHeight", typeof(double), typeof(CloudChart), new PropertyMetadata(double.NaN));
 
    public CloudChart()
    {
        InitializeComponent();
        //SetValue(HTListProperty, new List<HumiTemp>());
        //SetValue(ColorListProperty, new List<ColorTable>());
        HTList = new List<HumiTemp>();
        ColorList = new List<ColorTable>();
    }
 
    private bool isRealTimeValue;
 
    /// <summary>
    /// 是否是实时值
    /// </summary>
    public bool IsRealTimeValue
    {
        get { return isRealTimeValue; }
        set { isRealTimeValue = value; }
    }
 
    /// <summary>
    /// 配置信息
    /// </summary>
    public List<HumiTemp> HTList
    {
       set { SetValue(HTListProperty, value); }
        get { return (List<HumiTemp>)GetValue(HTListProperty); }
    }
 
    /// <summary>
    /// 颜色表
    /// </summary>
    public List<ColorTable> ColorList
    {
       set { SetValue(ColorListProperty, value); }
        get { return (List<ColorTable>)GetValue(ColorListProperty); }
    }
 
    /// <summary>
    /// 机柜宽度
    /// </summary>
    public double CabWidth
    {
        set { SetValue(CabWidthProperty, value); }
        get { return (double)GetValue(CabWidthProperty); }
    }
 
    /// <summary>
    /// 机柜高度
    /// </summary>
    public double CabHeight
    {
        set { SetValue(CabHeightProperty, value); }
        get { return (double)GetValue(CabHeightProperty); }
    }
 
    /// <summary>
    /// 计算每个点的实时值
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="list"></param>
    /// <returns></returns>
    private double GetPointRealTimeValue(double x, double y, List<HumiTemp> list)
    {
        double R = 0, S = 0;
        foreach (var ht in list)
        {
            double temp = GetRealTimeValue(ht);
            if (x == ht.X && y == ht.Y)
                return temp;
            //计算系数
            double ratio = 1 / ((x - ht.X) * (x - ht.X) + (y - ht.Y) * (y - ht.Y));
            S += ratio * temp;
            R += ratio;
        }
        return S / R;
    }
 
    /// <summary>
    /// 读取实时值
    /// </summary>
    /// <param name="ht"></param>
    /// <returns></returns>
    private double GetRealTimeValue(HumiTemp ht)
    {
        double value;
        if (double.TryParse(WcfClient.Instance.GetData(ht.MgrObjId, ht.Id), out value))
            return value;
        return double.NaN;
    }
 
    /// <summary>
    /// 根据外部传入值计算每个点的值
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="list"></param>
    /// <returns></returns>
    private double GetPointOutsideValue(double x, double y, List<HumiTemp> list)
    {
        double R = 0, S = 0;
        foreach (var ht in list)
        {
            double temp = GetOutsideValue(ht);
            if (x == ht.X && y == ht.Y)
                return temp;
            //计算系数
            double ratio = 1 / ((x - ht.X) * (x - ht.X) + (y - ht.Y) * (y - ht.Y));
            S += ratio * temp;
            R += ratio;
        }
        return S / R;
    }
 
    /// <summary>
    /// 读取外部传入值
    /// </summary>
    /// <param name="ht"></param>
    /// <returns></returns>
    private double GetOutsideValue(HumiTemp ht)
    {
        return ht.Value;
    }
 
    /// <summary>
    /// 温度(值)转换成颜色值
    /// </summary>
    /// <param name="temperature"></param>
    /// <returns></returns>
    private Color ValueToColor(double temperature, List<ColorTable> colorList)
    {
        int Tlength = colorList.Count;
        if (Tlength == 0)
            return Colors.Red;
        int i;
        for (i = 0; i < Tlength; i++)
        {
            if (colorList[i].Value > temperature)
                break;
        }
        if (i == 0)
            return Color.FromRgb((byte)(colorList[0].R), (byte)(colorList[0].G), (byte)(colorList[0].B));
        else if (i == Tlength)
            return Color.FromRgb((byte)(colorList[i - 1].R), (byte)(colorList[i - 1].G), (byte)(colorList[i - 1].B));
 
        double ratio = (temperature - colorList[i - 1].Value) / (colorList[i].Value - colorList[i - 1].Value);
        int rSpan = colorList[i].R - colorList[i - 1].R;
        int gSpan = colorList[i].G - colorList[i - 1].G;
        int bSpan = colorList[i].B - colorList[i - 1].B;
        double r = (colorList[i - 1].R + rSpan * ratio);
        double g = (colorList[i - 1].G + gSpan * ratio);
        double b = (colorList[i - 1].B + bSpan * ratio);
        return Color.FromRgb((byte)r, (byte)g, (byte)b);
    }
 
 
    /// <summary>
    /// 更新界面
    /// </summary>
    public void Update()
    {
        Show();
    }
 
    /// <summary>
    /// 获取坐标点的值
    /// </summary>
    private double GetData(double x, double y, List<HumiTemp> list)
    {
        double ret = 0;
        if (IsRealTimeValue == true)
        {
            ret = GetPointRealTimeValue(x, y, list);
        }
        else
        {
            ret = GetPointOutsideValue(x, y, list);
        }
        return ret;
    }
 
    /// <summary>
    /// 控件初始化
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        if (CabHeight > 0 && CabWidth > 0)
        {
            double d1 = Height / CabHeight;
            double d2 = Width / CabWidth;
            //取得控件和真实机柜的比例尺
            double scale = d1 > d2 ? d2 : d1;
            img.Height = scale * CabHeight;
            img.Width = scale * CabWidth;
        }
        InitColorTable();
    }
 
    /// <summary>
    /// 初始化颜色表
    /// </summary>
    public void InitColorTable()
    {
        colorStack.Children.Clear();
        ValueStack.Children.Clear();
        foreach (ColorTable item in ColorList)
        {
            Rectangle rect = new Rectangle();
            rect.Width = 25;
            rect.Height = 25;
            rect.Fill = new SolidColorBrush(Color.FromRgb((byte)item.R, (byte)item.G, (byte)item.B));
            colorStack.Children.Add(rect);
            Label lb = new Label();
            lb.Width = 25;
            lb.Height = 25;
            lb.Content = item.Value;
            ValueStack.Children.Add(lb);
        }
    }
 
    /// <summary>
    /// 显示云图
    /// </summary>
    private void Show()
    {
        if (double.IsNaN(img.Width) || img.Width == 0 || double.IsNaN(img.Height) || img.Height == 0)
        {
            UserControl_Loaded(this, new RoutedEventArgs());
        }
        //防止用户并未初始化
        if (!double.IsNaN(img.Width) && !double.IsNaN(img.Height))
        {
            // Create the bitmap, with the dimensions of the image placeholder.
            WriteableBitmap wb = new WriteableBitmap((int)img.Width, (int)img.Height, 96, 96, PixelFormats.Bgra32, null);
            // Define the update square (which is as big as the entire image).
            Int32Rect rect = new Int32Rect(0, 0, (int)img.Width, (int)img.Height);
            byte[] pixels = new byte[(int)img.Width * (int)img.Height * wb.Format.BitsPerPixel / 8];
            for (int y = 0; y < wb.PixelHeight; y++)
            {
                for (int x = 0; x < wb.PixelWidth; x++)
                {
                    int alpha = 255;
                    int red = 0;
                    int green = 0;
                    int blue = 0;
 
                    double value = GetData(x, y, HTList);
                    Color c = ValueToColor(value,ColorList);
                    red = c.R;
                    green = c.G;
                    blue = c.B;
 
                    int pixelOffset = (x + (wb.PixelHeight - y - 1) * wb.PixelWidth) * wb.Format.BitsPerPixel / 8;
                    pixels[pixelOffset] = (byte)blue;
                    pixels[pixelOffset + 1] = (byte)green;
                    pixels[pixelOffset + 2] = (byte)red;
                    pixels[pixelOffset + 3] = (byte)alpha;
                }
 
                int stride = (wb.PixelWidth * wb.Format.BitsPerPixel) / 8;
                wb.WritePixels(rect, pixels, stride, 0);
            }
            // Show the bitmap in an Image element.
            img.Source = wb;
        }
    }
}

 

<UserControl x:Class="MobileHT.CloudChart"
             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"  Loaded="UserControl_Loaded"  d:DesignHeight="600" d:DesignWidth="400" Width="400" Height="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="26"></RowDefinition>
            <RowDefinition Height="26"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Image Grid.Row="3" Name="img" IsHitTestVisible="False" Margin="2" ></Image>
        <StackPanel  Name="colorStack" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="0" Margin="2">
        </StackPanel>
        <StackPanel Name="ValueStack"  Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="1" Margin="2">
        </StackPanel>
    </Grid>
</UserControl>

  

  

 

获取数据有使用外部DLL,可参考以上代码,做任何值的云图。(上述为温度云图或者湿度云图)

 

效果图:

效果图配置代码:

<my:CloudChart x:Name="cloud2" Height="300" Width="200"  CabHeight="300" CabWidth="200" IsRealTimeValue="False" Margin="365,85,53,294">
    <my:CloudChart.HTList>
        <my:HumiTemp Id="0" MgrObjId="0" />
        <my:HumiTemp Id="1" MgrObjId="1" X="20" Y="30"  Value="19"/>
        <my:HumiTemp Id="2" MgrObjId="2"  X="30" Y="60" Value="20"/>
        <my:HumiTemp Id="3" MgrObjId="3" X="40" Y="90" Value="21"/>
        <my:HumiTemp Id="4" MgrObjId="4"  X="50" Y="100" Value="22"/>
        <my:HumiTemp Id="5" MgrObjId="5"  X="60" Y="110" Value="27"/>
        <my:HumiTemp Id="6" MgrObjId="6"  X="80" Y="120" Value="24"/>
        <my:HumiTemp Id="7" MgrObjId="7"  X="100" Y="130" Value="25"/>
        <my:HumiTemp Id="8" MgrObjId="8" X="120" Y="150" Value="26"/>
        <my:HumiTemp Id="9" MgrObjId="9"  X="140" Y="160" Value="28"/>
        <my:HumiTemp Id="9" MgrObjId="9"  X="160" Y="200" Value="30"/>
        <my:HumiTemp Id="9" MgrObjId="9"  X="180" Y="230" Value="33"/>
        <my:HumiTemp Id="9" MgrObjId="9"  X="270" Y="200" Value="35"/>
    </my:CloudChart.HTList>
    <my:CloudChart.ColorList>
        <my:ColorTable Value="19" R="0" G="0" B="255" Alpha="255"></my:ColorTable>
        <my:ColorTable Value="22" R="100" G="149" B="237" Alpha="255"></my:ColorTable>
        <my:ColorTable Value="25" R="100" G="100" B="220" Alpha="255"></my:ColorTable>
        <my:ColorTable Value="28" R="127" G="0" B="212" Alpha="255"></my:ColorTable>
        <my:ColorTable Value="30" R="173" G="255" B="47" Alpha="255"></my:ColorTable>
        <my:ColorTable Value="32" R="255" G="165" B="0" Alpha="255"></my:ColorTable>
        <my:ColorTable Value="35" R="255" G="69" B="0" Alpha="255"></my:ColorTable>
    </my:CloudChart.ColorList>
</my:CloudChart>

  

posted @   三叶草╮  阅读(766)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示