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> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现