經常坐地鐵,卻不知道地鐵多少條線路?哪個站下車?今天就帶領大家熟悉並繪製深圳地鐵路線圖。 WPF在繪製矢量圖方面有非常強大的優勢,利用WPF可以繪製出各種矢量圖形,如線,圓,多邊形,矩形,及組合圖形。今天以繪製深圳地鐵路線圖為例,簡述WPF在圖形繪製方面的一些知識,僅供學習分享使用,如有不足之處,還 ...
經常坐地鐵,卻不知道地鐵多少條線路?哪個站下車?今天就帶領大家熟悉並繪製深圳地鐵路線圖。
WPF在繪製矢量圖方面有非常強大的優勢,利用WPF可以繪製出各種矢量圖形,如線,圓,多邊形,矩形,及組合圖形。今天以繪製深圳地鐵路線圖為例,簡述WPF在圖形繪製方面的一些知識,僅供學習分享使用,如有不足之處,還請指正。
WPF圖形概述
與傳統的.NET開發使用GDI+進行繪圖不同,WPF擁有自己的一套圖形API,繪圖為矢量圖。繪圖可以在任何一種佈局控制項中完成,wpf會根據容器計算相應坐標。最常用的是Canvas和Grid。基本圖形包括以下幾個,都是Shaper類的派生類。
- Line,直線段,可以設置Stroke
- Rectangle,有Stroke也有Fill
- Ellipse,橢圓,同上
- Polygon,多邊形。由多條直線線段圍成的閉合區域,同上。
- Polyline,折線,不閉合,由多條首尾相接的直線段組成
- Path,路徑,閉合。可以由若幹直線、圓弧、貝塞爾曲線(由線段與節點組成,節點是可拖動的支點,線段像可伸縮的皮筋)組成。很強大。
地鐵官網效果
首先打開深圳地鐵官網【https://www.szmc.net/map/】,可查看深圳地鐵的路線圖,如下所示:
獲取地鐵路線數據
通過對地鐵官網的網路介面接收數據分析,可以獲取地鐵數據的原始JSON文件,將原始JSON文件保存到本地,在程式中進行引用,如下所示:
構建地鐵數據模型
在得到shentie.json文件後,通過分析,構建模型類,如下所示:
1 namespace DemoSubway.Models 2 { 3 /// <summary> 4 /// 深圳地鐵模型 5 /// </summary> 6 public class ShenTie 7 { 8 [JsonProperty("s")] 9 public string? Name { get; set; } 10 11 [JsonProperty("i")] 12 public string? Index { get; set; } 13 14 [JsonProperty("l")] 15 public SubwayLine[]? SubwayLines { get; set; } 16 17 [JsonProperty("o")] 18 public string? Obj { get;set; } 19 } 20 21 public class SubwayLine 22 { 23 [JsonProperty("st")] 24 public St[]? Sites { get; set; } 25 26 [JsonProperty("ln")] 27 public string? LineNumber { get; set; } 28 29 [JsonProperty("su")] 30 public string? Su { get; set; } 31 32 [JsonProperty("kn")] 33 public string? KName { get; set; } 34 35 [JsonProperty("c")] 36 public string[]? Circles { get;set; } 37 38 [JsonProperty("lo")] 39 public string? Lo { get; set; } 40 41 [JsonProperty("lp")] 42 public string[]? LinePosition { get; set; } 43 44 [JsonProperty("ls")] 45 public string? Ls { get; set; } 46 47 [JsonProperty("cl")] 48 public string? Color { get; set; } 49 50 [JsonProperty("la")] 51 public string? La { get; set; } 52 53 [JsonProperty("x")] 54 public string? X { get; set; } 55 56 [JsonProperty("li")] 57 public string? Li { get; set; } 58 } 59 60 public class St 61 { 62 [JsonProperty("rs")] 63 public string? Rs { get; set; } 64 65 [JsonProperty("udpx")] 66 public string? Udpx { get; set; } 67 68 [JsonProperty("su")] 69 public string? Su { get; set; } 70 71 [JsonProperty("udsu")] 72 public string? Udsu { get; set;} 73 74 [JsonProperty("n")] 75 public string? Name { get; set;} 76 77 [JsonProperty("en")] 78 public string? En { get; set; } 79 80 [JsonProperty("sid")] 81 public string? Sid { get; set; } 82 83 [JsonProperty("p")] 84 public string? Position { get; set; } 85 86 [JsonProperty("r")] 87 public string? R { get; set; } 88 89 [JsonProperty("udsi")] 90 public string? Udsi { get; set; } 91 92 [JsonProperty("t")] 93 public string? T { get; set;} 94 95 [JsonProperty("si")] 96 public string? Si { get; set; } 97 98 [JsonProperty("sl")] 99 public string? Sl { get; set;} 100 101 [JsonProperty("udli")] 102 public string? Udli { get; set; } 103 104 [JsonProperty("poiid")] 105 public string? Poiid { get; set; } 106 107 [JsonProperty("lg")] 108 public string? Lg { get; set; } 109 110 [JsonProperty("sp")] 111 public string? Sp { get; set; } 112 } 113 }
解析數據源
通過反序列化,將shentie.json文件內容,載入到記憶體並實例化為ShenTie對象,在此需要用到第三方庫【Newtonsoft.Json】,如下所示:
繪製地鐵路線圖
地鐵路線圖在WPF主頁面顯示,用Grid作為容器【subwayBox】,如下所示:
1 <Window x:Class="DemoSubway.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:DemoSubway" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded"> 9 10 <Grid> 11 <Grid.RowDefinitions> 12 <RowDefinition Height="Auto"></RowDefinition> 13 <RowDefinition Height="*"></RowDefinition> 14 </Grid.RowDefinitions> 15 <StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center"> 16 <TextBlock x:Name="tbTitle" FontSize="30" HorizontalAlignment="Center"></TextBlock> 17 </StackPanel> 18 <Viewbox Stretch="Fill" Grid.Row="1"> 19 <Grid x:Name="subwayBox"> 20 21 </Grid> 22 </Viewbox> 23 </Grid> 24 </Window>
ShenTie對象創建成功後,就可以獲取路線數據,然後創建地鐵路線元素,如下所示:
1 private void Window_Loaded(object sender, RoutedEventArgs e) 2 { 3 string jsonFile = "shentie.json"; 4 JsonHelper jsonHelper = new JsonHelper(); 5 var shentie = jsonHelper.Deserialize<ShenTie>(jsonFile); 6 this.tbTitle.Text = shentie.Name; 7 List<string> lstSites = new List<string>(); 8 for(int i = 0; i < shentie.SubwayLines?.Length; i++) 9 { 10 var subwayLine= shentie.SubwayLines[i]; 11 if(subwayLine != null) 12 { 13 //地鐵線路 14 var color = ColorTranslator.FromHtml($"#{subwayLine.Color}");//線路顏色 15 var circles = subwayLine.Circles;//線路節點 16 Path line = new Path(); 17 PathFigureCollection lineFigures = new PathFigureCollection(); 18 PathFigure lineFigure = new PathFigure(); 19 lineFigure.IsClosed= false; 20 var start = circles?[0].Split(" ");//線路起始位置 21 lineFigure.StartPoint = new System.Windows.Point(int.Parse(start[0]), int.Parse(start[1])); 22 23 for (int j= 0;j< circles?.Length;j++) 24 { 25 var circle= circles[j].Split(" "); 26 LineSegment lineSegment = new LineSegment(new System.Windows.Point(int.Parse(circle[0]), int.Parse(circle[1])),true); 27 lineFigure.Segments.Add(lineSegment); 28 } 29 lineFigures.Add(lineFigure); 30 line.Data = new PathGeometry(lineFigures, FillRule.Nonzero, null); 31 line.Stroke = new SolidColorBrush(System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B)); 32 line.StrokeThickness = 4; 33 this.subwayBox.Children.Add(line); 34 //地鐵站點 35 for (int j = 0; j < subwayLine.Sites?.Length; j++) 36 { 37 var site = subwayLine.Sites[j]; 38 if (site != null) 39 { 40 41 //站點標識,圓圈 42 Path siteCirclePath = new Path(); 43 var sitePosition = site?.Position?.Split(" "); 44 EllipseGeometry ellipse = new EllipseGeometry(); 45 ellipse.Center = new System.Windows.Point(int.Parse(sitePosition[0]), int.Parse(sitePosition[1])); 46 ellipse.RadiusX = 4; 47 ellipse.RadiusY=4; 48 siteCirclePath.Data=ellipse; 49 siteCirclePath.Fill = Brushes.White; 50 siteCirclePath.Stroke = new SolidColorBrush(System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B)); 51 siteCirclePath.Cursor= Cursors.Hand; 52 siteCirclePath.Focusable = true; 53 siteCirclePath.Tag = site?.Name; 54 siteCirclePath.MouseDown += SiteCirclePath_MouseDown; 55 this.subwayBox.Children.Add(siteCirclePath); 56 //站點名字 57 if (lstSites.Contains(site?.Name)) 58 { 59 continue;//對於交匯站點,只繪製一次 60 } 61 //站點名稱 62 Path siteTextPath = new Path(); 63 FormattedText siteContent = new FormattedText(site?.Name,CultureInfo.CurrentCulture,FlowDirection.LeftToRight,new Typeface("Arial"),14,Brushes.Black, 1.25); 64 var x = int.Parse(sitePosition[0]); 65 var y = int.Parse(sitePosition[1]); 66 if (j + 1 < subwayLine.Sites?.Length) 67 { 68 //站點位置適當偏移 69 var next = subwayLine.Sites[j + 1]?.Position?.Split(" "); 70 var nextx = int.Parse(next[0]); 71 var nexty = int.Parse(next[1]); 72 if (x == nextx) 73 { 74 x = x + 6; 75 } 76 else if (y == nexty) 77 { 78 y = y + 6; 79 } 80 else 81 { 82 x = x + 1; 83 y = y + 1; 84 } 85 } 86 Geometry geometry = siteContent.BuildGeometry(new System.Windows.Point(x, y)); 87 siteTextPath.Data = geometry; 88 siteTextPath.Stroke = Brushes.Black; 89 siteTextPath.Focusable = true; 90 siteTextPath.Cursor = Cursors.Hand; 91 siteTextPath.MouseDown += SiteTextPath_MouseDown; 92 siteTextPath.Tag = site?.Name; 93 this.subwayBox.Children.Add(siteTextPath); 94 lstSites.Add(site?.Name); 95 } 96 } 97 98 var kName = subwayLine.KName;//線路名稱 99 var linePosition= subwayLine.LinePosition?[0].Split(" "); 100 if(kName != null) 101 { 102 Path lineNamePath = new Path(); 103 FormattedText lineNameText = new FormattedText(kName, CultureInfo.CurrentCulture,FlowDirection.LeftToRight,new Typeface("Arial"),16,Brushes.Black,1.25); 104 var lineX = int.Parse(linePosition[0]); 105 var lineY = int.Parse(linePosition[1]); 106 if (subwayLine.LineNumber == "1") 107 { 108 lineX = lineX - 10; 109 lineY = lineY + 20; 110 } 111 Geometry geometry = lineNameText.BuildGeometry(new System.Windows.Point(lineX, lineY)); 112 lineNamePath.Data=geometry; 113 lineNamePath.Stroke = new SolidColorBrush(System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B)); 114 this.subwayBox.Children.Add(lineNamePath); 115 } 116 } 117 } 118 }
效果展示
本示例效果圖如下所示:
在獲取的JSON文件中,有些屬性名都是簡寫,所以在編寫示例代碼過程中,對有些屬性的理解並不准確,需要不斷測試優化,繪製出的地鐵路線圖可能與實際存在稍微的差異,如站點名稱,路線名稱等內容的位置。
以上就是本篇文章的全部內容,旨在學習分享,傳播知識。
作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章