|
经常坐地铁,却不知道地铁多少条线路?哪个站下车?今天就带领大家熟悉并绘制深圳地铁路线图。
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文件后,通过分析,构建模型类,如下所示:
解析数据源
通过反序列化,将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文件中,有些属性名都是简写,所以在编写示例代码过程中,对有些属性的理解并不准确,需要不断测试优化,绘制出的地铁路线图可能与实际存在稍微的差异,如站点名称,路线名称等内容的位置。
以上就是本篇文章的全部内容,旨在学习分享,传播知识。
来源:https://www.cnblogs.com/hsiang/archive/2023/06/01/17447750.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|