实例介绍
【实例简介】
【实例截图】
【核心代码】
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace LikeEchartsMap { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } //所有的动画 都在这个方法里 AddPointToStoryboard #region 成员变量 /// <summary> /// 跑动的点里的Path的Data /// </summary> private string m_PointData; /// <summary> /// 点的运动速度 单位距离/秒 /// </summary> private double m_Speed; /// <summary> /// 运动轨迹弧线的正弦角度 /// </summary> private double m_Angle; /// <summary> /// 数据源 /// </summary> private List<MapItem> m_Source; /// <summary> /// 故事版 /// </summary> private Storyboard m_Sb = new Storyboard(); #endregion #region 事件 #region loaded /// <summary> /// loaded /// </summary> private void Window_Loaded(object sender, RoutedEventArgs e) { //参数设置部分 m_PointData = "M244.5,98.5 L273.25,93.75 C278.03113,96.916667 277.52785,100.08333 273.25,103.25 z"; m_Speed = 50; m_Angle = 15; MakeData(); InitRadioButton(); AddAnimation(m_Source[0]); } #endregion #region RadioButton点击 /// <summary> /// RadioButton点击 /// </summary> void rbtn_Click(object sender, RoutedEventArgs e) { RadioButton rbtn = (RadioButton)sender; if (rbtn.IsChecked == true) { foreach (MapItem item in m_Source) { if ((string)rbtn.Content == item.From.ToString()) { AddAnimation(item); return; } } } } #endregion #endregion #region 方法 #region 做数据 /// <summary> /// 做数据 /// </summary> private void MakeData() { Random rd = new Random(); List<MapItem> list = new List<MapItem>(); List<MapToItem> toList = new List<MapToItem>(); toList.Add(new MapToItem() { To = ProvincialCapital.成都, Diameter = rd.Next(10, 51) }); toList.Add(new MapToItem() { To = ProvincialCapital.西宁, Diameter = rd.Next(10, 51) }); toList.Add(new MapToItem() { To = ProvincialCapital.哈尔滨, Diameter = rd.Next(10, 51) }); toList.Add(new MapToItem() { To = ProvincialCapital.海口, Diameter = rd.Next(10, 51), Tip = "美丽的大海" }); toList.Add(new MapToItem() { To = ProvincialCapital.呼和浩特, Diameter = rd.Next(10, 51) }); toList.Add(new MapToItem() { To = ProvincialCapital.重庆, Diameter = 50, Tip = "山鸡大神在这" }); toList.Add(new MapToItem() { To = ProvincialCapital.台北, Diameter = rd.Next(10, 51) }); toList.Add(new MapToItem() { To = ProvincialCapital.乌鲁木齐, Diameter = rd.Next(10, 51) }); toList.Add(new MapToItem() { To = ProvincialCapital.广州, Diameter = rd.Next(10, 51) }); toList.Add(new MapToItem() { To = ProvincialCapital.上海, Diameter = 50, Tip = "雷叔的地盘!" }); list.Add(new MapItem() { From = ProvincialCapital.北京, To = toList }); list.Add(new MapItem() { From = ProvincialCapital.西安, To = toList }); list.Add(new MapItem() { From = ProvincialCapital.拉萨, To = toList }); m_Source = list; } #endregion #region 加载菜单RadioButton /// <summary> /// 加载RadioButton /// </summary> private void InitRadioButton() { Random rd = new Random(); for (int i = 0; i < m_Source.Count; i ) { byte r = (byte)rd.Next(0, 256); byte g = (byte)rd.Next(0, 256); byte b = (byte)rd.Next(0, 256); RadioButton rbtn = new RadioButton(); rbtn.Content = m_Source[i].From.ToString(); rbtn.Margin = new Thickness(0, 20, 0, 0); rbtn.Background = new SolidColorBrush(Color.FromArgb(200, r, g, b)); rbtn.BorderBrush = new SolidColorBrush(Color.FromArgb(255, r, g, b)); if (i == 0) rbtn.IsChecked = true; else rbtn.IsChecked = false; rbtn.Click = rbtn_Click; spnl_Radio.Children.Add(rbtn); } } #endregion #region 添加控件和动画到容器 /// <summary> /// 添加控件和动画到容器 /// </summary> /// <param name="item">数据项</param> private void AddAnimation(MapItem item) { grid_Animation.Children.Clear(); m_Sb.Children.Clear(); Random rd = new Random(); foreach (MapToItem toItem in item.To) { if (item.From == toItem.To) continue; //颜色 byte[] rgb = new byte[] { (byte)rd.Next(0, 255), (byte)rd.Next(0, 255), (byte)rd.Next(0, 255) }; //运动轨迹 double l = 0; Path particlePath = GetParticlePath(item.From, toItem, rgb, out l); grid_Animation.Children.Add(particlePath); // 跑动的点 Grid grid = GetRunPoint(rgb); //到达城市的圆 Ellipse ell = GetToEllipse(toItem, rgb); AddPointToStoryboard(grid, ell, m_Sb, particlePath, l, item.From, toItem); grid_Animation.Children.Add(grid); grid_Animation.Children.Add(ell); m_Sb.Begin(this); } } #endregion #region 获取省会,直辖市,特别行政区的坐标 /// <summary> /// 获取省会,直辖市,特别行政区的坐标 /// </summary> /// <param name="pc">城市</param> /// <returns>Point(Left,Top)</returns> private Point GetProvincialCapitalPoint(ProvincialCapital city) { Point point = new Point(0, 0); switch (city) { case ProvincialCapital.北京: point.X = 625.71145; point.Y = 265.20515; break; case ProvincialCapital.天津: point.X = 646.648895; point.Y = 277.719215; break; case ProvincialCapital.上海: point.X = 730.844; point.Y = 425.208; break; case ProvincialCapital.重庆: point.X = 487.123; point.Y = 469.796; break; case ProvincialCapital.石家庄: point.X = 605.527; point.Y = 300.853; break; case ProvincialCapital.太原: point.X = 575.685; point.Y = 310.961; break; case ProvincialCapital.沈阳: point.X = 725.375; point.Y = 214.217; break; case ProvincialCapital.长春: point.X = 742.702; point.Y = 173.786; break; case ProvincialCapital.哈尔滨: point.X = 751.847; point.Y = 137.687; break; case ProvincialCapital.南京: point.X = 691.682; point.Y = 418.295; break; case ProvincialCapital.杭州: point.X = 706.603; point.Y = 446.211; break; case ProvincialCapital.合肥: point.X = 661.841; point.Y = 418.295; break; case ProvincialCapital.福州: point.X = 706.603; point.Y = 528.516; break; case ProvincialCapital.南昌: point.X = 646.439; point.Y = 486.16; break; case ProvincialCapital.济南: point.X = 648.845; point.Y = 327.807; break; case ProvincialCapital.郑州: point.X = 596.382; point.Y = 371.126; break; case ProvincialCapital.武汉: point.X = 617.078; point.Y = 451.506; break; case ProvincialCapital.长沙: point.X = 593.975; point.Y = 497.231; break; case ProvincialCapital.广州: point.X = 611.303; point.Y = 592.531; break; case ProvincialCapital.海口: point.X = 553.545; point.Y = 663.766; break; case ProvincialCapital.成都: point.X = 445.73; point.Y = 453.912; break; case ProvincialCapital.贵阳: point.X = 492.417; point.Y = 533.811; break; case ProvincialCapital.昆明: point.X = 420.22; point.Y = 563.171; break; case ProvincialCapital.西安: point.X = 522.259; point.Y = 384.121; break; case ProvincialCapital.兰州: point.X = 442.842; point.Y = 354.28; break; case ProvincialCapital.西宁: point.X = 408.668; point.Y = 340.321; break; case ProvincialCapital.拉萨: point.X = 235.394; point.Y = 452.949; break; case ProvincialCapital.南宁: point.X = 520.815; point.Y = 605.046; break; case ProvincialCapital.呼和浩特: point.X = 557.877; point.Y = 255.128; break; case ProvincialCapital.银川: point.X = 479.422; point.Y = 299.891; break; case ProvincialCapital.乌鲁木齐: point.X = 220.474; point.Y = 179.562; break; case ProvincialCapital.香港: point.X = 623.817; point.Y = 611.784; break; case ProvincialCapital.澳门: point.X = 600.714; point.Y = 615.634; break; case ProvincialCapital.台北: point.X = 747.515; point.Y = 545.844; break; } return point; } #endregion #region 获取运动轨迹 /// <summary> /// 获取运动轨迹 /// </summary> /// <param name="from">来自</param> /// <param name="toItem">去</param> /// <param name="rgb">颜色:r,g,b</param> /// <param name="l">两点间的直线距离</param> /// <returns>Path</returns> private Path GetParticlePath(ProvincialCapital from, MapToItem toItem, byte[] rgb, out double l) { Point startPoint = GetProvincialCapitalPoint(from); Point endPoint = GetProvincialCapitalPoint(toItem.To); Path path = new Path(); Style style = (Style)FindResource("ParticlePathStyle"); path.Style = style; PathGeometry pg = new PathGeometry(); PathFigure pf = new PathFigure(); pf.StartPoint = startPoint; ArcSegment arc = new ArcSegment(); arc.SweepDirection = SweepDirection.Clockwise;//顺时针弧 arc.Point = endPoint; //半径 正弦定理a/sinA=2r r=a/2sinA 其中a指的是两个城市点之间的距离 角A指a边的对角 double sinA = Math.Sin(Math.PI * m_Angle / 180.0); //计算距离 勾股定理 double x = startPoint.X - endPoint.X; double y = startPoint.Y - endPoint.Y; double aa = x * x y * y; l = Math.Sqrt(aa); double r = l / (sinA * 2); arc.Size = new Size(r, r); pf.Segments.Add(arc); pg.Figures.Add(pf); path.Data = pg; path.Stroke = new SolidColorBrush(Color.FromArgb(255, rgb[0], rgb[1], rgb[2])); path.Stretch = Stretch.None; path.ToolTip = string.Format("{0}=>{1}", from.ToString(), toItem.To.ToString()); return path; } #endregion #region 获取跑动的点 /// <summary> /// 获取跑动的点 /// </summary> /// <param name="rgb">颜色:r,g,b</param> /// <returns>Grid</returns> private Grid GetRunPoint(byte[] rgb) { //一个Grid里包含一个椭圆 一个Path 椭圆做阴影 //Grid Grid grid = new Grid(); grid.IsHitTestVisible = false;//不参与命中测试 grid.HorizontalAlignment = HorizontalAlignment.Left; grid.VerticalAlignment = VerticalAlignment.Top; grid.Width = 40; grid.Height = 15; grid.RenderTransformOrigin = new Point(0.5, 0.5); //Ellipse Ellipse ell = new Ellipse(); ell.Width = 40; ell.Height = 15; ell.Fill = new SolidColorBrush(Color.FromArgb(255, rgb[0], rgb[1], rgb[2])); RadialGradientBrush rgbrush = new RadialGradientBrush(); rgbrush.GradientOrigin = new Point(0.8, 0.5); rgbrush.GradientStops.Add(new GradientStop(Color.FromArgb(255, 0, 0, 0), 0)); rgbrush.GradientStops.Add(new GradientStop(Color.FromArgb(22, 0, 0, 0), 1)); ell.OpacityMask = rgbrush; grid.Children.Add(ell); //Path Path path = new Path(); path.Data = Geometry.Parse(m_PointData); path.Width = 30; path.Height = 4; LinearGradientBrush lgb = new LinearGradientBrush(); lgb.StartPoint = new Point(0, 0); lgb.EndPoint = new Point(1, 0); lgb.GradientStops.Add(new GradientStop(Color.FromArgb(88, rgb[0], rgb[1], rgb[2]), 0)); lgb.GradientStops.Add(new GradientStop(Color.FromArgb(255, 255, 255, 255), 1)); path.Fill = lgb; path.Stretch = Stretch.Fill; grid.Children.Add(path); return grid; } #endregion #region 获取到达城市的圆 /// <summary> /// 获取到达城市的圆 /// </summary> /// <param name="toItem">数据项</param> /// <param name="rgb">颜色</param> /// <returns>Ellipse</returns> private Ellipse GetToEllipse(MapToItem toItem, byte[] rgb) { Ellipse ell = new Ellipse(); ell.HorizontalAlignment = HorizontalAlignment.Left; ell.VerticalAlignment = VerticalAlignment.Top; ell.Width = toItem.Diameter; ell.Height = toItem.Diameter; ell.Fill = new SolidColorBrush(Color.FromArgb(255, rgb[0], rgb[1], rgb[2])); Point toPos = GetProvincialCapitalPoint(toItem.To); TranslateTransform ttf = new TranslateTransform(toPos.X - ell.Width / 2, toPos.Y - ell.Height / 2);//定位到城市所在的点 ell.RenderTransform = ttf; ell.ToolTip = string.Format("{0} {1}", toItem.To.ToString(), toItem.Tip); ell.Opacity = 0; return ell; } #endregion #region 将点加入到动画故事版 /// <summary> /// 将点加入到动画故事版 /// </summary> /// <param name="runPoint">运动的点</param> /// <param name="toEll">达到城市的圆</param> /// <param name="sb">故事版</param> /// <param name="particlePath">运动轨迹</param> /// <param name="l">运动轨迹的直线距离</param> /// <param name="from">来自</param> /// <param name="toItem">去</param> private void AddPointToStoryboard(Grid runPoint, Ellipse toEll, Storyboard sb, Path particlePath, double l, ProvincialCapital from, MapToItem toItem) { double pointTime = l / m_Speed;//点运动所需的时间 double particleTime = pointTime / 2;//轨迹呈现所需时间(跑的比点快两倍) //生成为控件注册名称的guid string name = Guid.NewGuid().ToString().Replace("-", ""); #region 运动的点 TransformGroup tfg = new TransformGroup(); MatrixTransform mtf = new MatrixTransform(); tfg.Children.Add(mtf); TranslateTransform ttf = new TranslateTransform(-runPoint.Width / 2, -runPoint.Height / 2);//纠正最上角沿path运动到中心沿path运动 tfg.Children.Add(ttf); runPoint.RenderTransform = tfg; this.RegisterName("m" name, mtf); MatrixAnimationUsingPath maup = new MatrixAnimationUsingPath(); maup.PathGeometry = particlePath.Data.GetFlattenedPathGeometry(); maup.Duration = new Duration(TimeSpan.FromSeconds(pointTime)); maup.RepeatBehavior = RepeatBehavior.Forever; maup.AutoReverse = false; maup.IsOffsetCumulative = false; maup.DoesRotateWithTangent = true;//沿切线旋转 Storyboard.SetTargetName(maup, "m" name); Storyboard.SetTargetProperty(maup, new PropertyPath(MatrixTransform.MatrixProperty)); sb.Children.Add(maup); #endregion #region 达到城市的圆 this.RegisterName("ell" name, toEll); //轨迹到达圆时 圆呈现 DoubleAnimation ellda = new DoubleAnimation(); ellda.From = 0.2;//此处值设置0-1会有不同的呈现效果 ellda.To = 1; ellda.Duration = new Duration(TimeSpan.FromSeconds(particleTime)); ellda.BeginTime = TimeSpan.FromSeconds(particleTime);//推迟动画开始时间 等轨迹连接到圆时 开始播放圆的呈现动画 ellda.FillBehavior = FillBehavior.HoldEnd; Storyboard.SetTargetName(ellda, "ell" name); Storyboard.SetTargetProperty(ellda, new PropertyPath(Ellipse.OpacityProperty)); sb.Children.Add(ellda); //圆呈放射状 RadialGradientBrush rgBrush = new RadialGradientBrush(); GradientStop gStop0 = new GradientStop(Color.FromArgb(255, 0, 0, 0), 0); //此为控制点 color的a值设为0 off值走0-1 透明部分向外放射 初始设为255是为了初始化效果 开始不呈放射状 等跑动的点运动到城市的圆后 color的a值才设为0开始呈现放射动画 GradientStop gStopT = new GradientStop(Color.FromArgb(255, 0, 0, 0), 0); GradientStop gStop1 = new GradientStop(Color.FromArgb(255, 0, 0, 0), 1); rgBrush.GradientStops.Add(gStop0); rgBrush.GradientStops.Add(gStopT); rgBrush.GradientStops.Add(gStop1); toEll.OpacityMask = rgBrush; this.RegisterName("e" name, gStopT); //跑动的点达到城市的圆时 控制点由不透明变为透明 color的a值设为0 动画时间为0 ColorAnimation ca = new ColorAnimation(); ca.To = Color.FromArgb(0, 0, 0, 0); ca.Duration = new Duration(TimeSpan.FromSeconds(0)); ca.BeginTime = TimeSpan.FromSeconds(pointTime); ca.FillBehavior = FillBehavior.HoldEnd; Storyboard.SetTargetName(ca, "e" name); Storyboard.SetTargetProperty(ca, new PropertyPath(GradientStop.ColorProperty)); sb.Children.Add(ca); //点达到城市的圆时 呈现放射状动画 控制点的off值走0-1 透明部分向外放射 DoubleAnimation eda = new DoubleAnimation(); eda.To = 1; eda.Duration = new Duration(TimeSpan.FromSeconds(2)); eda.RepeatBehavior = RepeatBehavior.Forever; eda.BeginTime = TimeSpan.FromSeconds(particleTime); Storyboard.SetTargetName(eda, "e" name); Storyboard.SetTargetProperty(eda, new PropertyPath(GradientStop.OffsetProperty)); sb.Children.Add(eda); #endregion #region 运动轨迹 //找到渐变的起点和终点 Point startPoint = GetProvincialCapitalPoint(from); Point endPoint = GetProvincialCapitalPoint(toItem.To); Point start = new Point(0, 0); Point end = new Point(1, 1); if (startPoint.X > endPoint.X) { start.X = 1; end.X = 0; } if (startPoint.Y > endPoint.Y) { start.Y = 1; end.Y = 0; } LinearGradientBrush lgBrush = new LinearGradientBrush(); lgBrush.StartPoint = start; lgBrush.EndPoint = end; GradientStop lgStop0 = new GradientStop(Color.FromArgb(255, 0, 0, 0), 0); GradientStop lgStop1 = new GradientStop(Color.FromArgb(0, 0, 0, 0), 0); lgBrush.GradientStops.Add(lgStop0); lgBrush.GradientStops.Add(lgStop1); particlePath.OpacityMask = lgBrush; this.RegisterName("p0" name, lgStop0); this.RegisterName("p1" name, lgStop1); //运动轨迹呈现 DoubleAnimation pda0 = new DoubleAnimation(); pda0.To = 1; pda0.Duration = new Duration(TimeSpan.FromSeconds(particleTime)); pda0.FillBehavior = FillBehavior.HoldEnd; Storyboard.SetTargetName(pda0, "p0" name); Storyboard.SetTargetProperty(pda0, new PropertyPath(GradientStop.OffsetProperty)); sb.Children.Add(pda0); DoubleAnimation pda1 = new DoubleAnimation(); //pda1.From = 0.5; //此处解开注释 值设为0-1 会有不同的轨迹呈现效果 pda1.To = 1; pda1.Duration = new Duration(TimeSpan.FromSeconds(particleTime)); pda1.FillBehavior = FillBehavior.HoldEnd; Storyboard.SetTargetName(pda1, "p1" name); Storyboard.SetTargetProperty(pda1, new PropertyPath(GradientStop.OffsetProperty)); sb.Children.Add(pda1); #endregion } #endregion #endregion } /// <summary> /// 省会,直辖市,特别行政区 /// </summary> public enum ProvincialCapital { 北京, 天津, 上海, 重庆, 石家庄, 太原, 沈阳, 长春, 哈尔滨, 南京, 杭州, 合肥, 福州, 南昌, 济南, 郑州, 武汉, 长沙, 广州, 海口, 成都, 贵阳, 昆明, 西安, 兰州, 西宁, 拉萨, 南宁, 呼和浩特, 银川, 乌鲁木齐, 香港, 澳门, 台北 } /// <summary> /// 地图数据项 /// </summary> public class MapItem { /// <summary> /// 出发城市 /// </summary> public ProvincialCapital From { get; set; } /// <summary> /// 到达城市 /// </summary> public List<MapToItem> To { get; set; } } /// <summary> /// 地图到达城市数据项 /// </summary> public class MapToItem { /// <summary> /// 到达城市 /// </summary> public ProvincialCapital To { get; set; } /// <summary> /// 到达城市圆点的直径 /// </summary> public double Diameter { get; set; } /// <summary> /// 提示的值 /// </summary> public string Tip { get; set; } } }
好例子网口号:伸出你的我的手 — 分享!
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论