博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用Canvas进行绘制XY坐标系
阅读量:5985 次
发布时间:2019-06-20

本文共 23331 字,大约阅读时间需要 77 分钟。

原文:

首先来一发图

绘制XY的坐标主要是利用Canvas setLeft和setBottom功能(Canvas内置坐标的功能)

1.首先WPF中的坐标系都是从左到右,从上到下的 即左上角位置(0,0)点,所以XY的Canvas要以(RenderTransformOrigin="0,0",为中心点)进行270°旋转,然后平移<TranslateTransform Y="{Binding ActualHeight,ElementName=canvasInPath}"/>

就是如上所图的XY坐标(绿色的)Line

不旋转的图如下:

2.如果以XY的Canvas要以(RenderTransformOrigin="0.5,0.5",为中心点)旋转,如果Canvas是正方形,那么只需要旋转270可以了,如果是长方形那么就会出现如下图情况:

3.因为Canvas是旋转的,X和Y的网格线就是蓝色的线,就不在旋转的Canvas中进行画线了(注:在旋转后的Canvas再放置控件都要旋转才能正常)

跟Canvas同一个级别放置两个X和Y网格线的Canvas

Line和TextBlock如何画,看上面的测试代码,然后转换成Code,动态绘制出来。

4.如果按照Canvas 100X100的坐标系绘制出来的图像特别密集下图:

所以我对此做了一个原始坐标和实际绘制坐标进行相应的扩大倍数计算,

///         /// 宽度        ///         public double XWidth        {            get            {                return _xWidth;            }            set            {                _xWidth = value;                this.Width = value;                //预留100的line长度                  scaleNumX = (value - xyShorten) / scaleStandard / (xTotal/ scaleStandard);            }

当前宽度-预留线的长度/基础倍数/(标尺总值/基础倍数),假如当前宽度是x=700,预留100宽度,基础倍数100,x标尺总刻度是200

那么计算出的scaleNumX=(700-100)/100/(200/100)=3

同理计算出 scaleNumY=(500-100)/100/(100/100)=4  (y=500 预留100 基础倍数100 y标尺总刻度是100)

 

原始坐标 (20,90)=>真实绘制坐标(60,360) x*scaleNumX,y*scaleNumY 下图:

完整的xaml代码如下:

View Code

完整的Code代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;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.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;namespace CoordinateXY{    ///     /// UserControlXY.xaml 的交互逻辑    ///     public partial class UserControlXY : UserControl    {        public UserControlXY()        {            InitializeComponent();            this.Loaded += UserControlXY_Loaded;        }        private void UserControlXY_Loaded(object sender, RoutedEventArgs e)        {            InitXRuler();            InitYRuler();        }        #region 变量        ///         /// 放大倍数 防止坐标尺子重叠        ///         private static double scaleNumX = 0;        ///         /// 放大倍数 防止坐标尺子重叠        ///         private static double scaleNumY = 0;        ///         /// 按照宽度和高度计算放大倍数        ///         private double scaleStandard = 50;        ///         /// x坐标尺度        ///         private double xTotal = 150;        ///         /// Y坐标尺度        ///         private double yTotal = 300;        ///         ///  刻度间隔 10刻度显示一个网格线        ///         private double scaleInterval = 10;        ///         /// 网格刻度线延长出来的长度值        /// 修改此长度看效果图        ///         private int xyLine = 0;        ///         /// xy坐标线长比网格绘制长度长多少        ///         private int xyShorten = 50;        ///         /// 文本距离xy坐标线的位置        ///         private int txtDis = 20;        ///         /// 宽度        ///         private double _xWidth;        ///         /// 高度        ///         private double _yHeight;        ///         /// 高度        ///         public double YHeight        {            get            {                return _yHeight;            }            set            {                _yHeight = value;                this.Height = value;                //预留100的line长度                  scaleNumY = (value - xyShorten) / scaleStandard / (yTotal / scaleStandard);            }        }        ///         /// 宽度        ///         public double XWidth        {            get            {                return _xWidth;            }            set            {                _xWidth = value;                this.Width = value;                //预留100的line长度                  scaleNumX = (value - xyShorten) / scaleStandard / (xTotal / scaleStandard);            }        }        #endregion        #region 方法        ///         /// 初始化X坐标尺        ///         private void InitXRuler()        {            canvasXRuler.Children.Clear();            var xtotal = xTotal + 1;            for (int i = 1; i < xtotal; i++)            {                if (i % scaleInterval != 0 && i + 1 != xtotal)                {                    continue;                }                Line xLine = new Line();                xLine.X1 = 1;                xLine.X2 = 0;                xLine.Y1 = 0;                xLine.Y2 = this.Height - xyShorten + xyLine;//柱状线图形高度;                xLine.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 255));//蓝色                xLine.StrokeThickness = 1;                xLine.IsHitTestVisible = false;                Canvas.SetLeft(xLine, i * scaleNumX);                Canvas.SetBottom(xLine, -xyLine);//延迟8长度刻度                TextBlock txtBlock = new TextBlock();                txtBlock.Text = (i).ToString();//文本内容                var typeface = new Typeface(txtBlock.FontFamily, txtBlock.FontStyle, txtBlock.FontWeight, txtBlock.FontStretch);                var width = Commons.Helper.TrimmingHelper.GetControlWidth(txtBlock.Text, typeface, txtBlock.FontSize);                Canvas.SetLeft(txtBlock, i * scaleNumX - width / 2);//计算文本宽度 使text内容center居中                Canvas.SetBottom(txtBlock, -txtDis);//刻度下方文本                canvasXRuler.Children.Add(xLine);                canvasXRuler.Children.Add(txtBlock);            }        }        ///         /// 初始化Y坐标尺        ///         private void InitYRuler()        {            canvasYRuler.Children.Clear();            var ytotal = yTotal + 1;            for (int i = 1; i < ytotal; i++)            {                if (i % scaleInterval != 0 && i + 1 != ytotal)                {                    continue;                }                Line yLine = new Line();                yLine.X1 = 1;                yLine.X2 = this.Width - xyShorten + xyLine;//柱状线图形长度;                yLine.Y1 = 0;                yLine.Y2 = 0;                yLine.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 255));//蓝色                yLine.StrokeThickness = 1;                yLine.IsHitTestVisible = false;                Canvas.SetLeft(yLine, -xyLine);//刻度值                Canvas.SetBottom(yLine, i * scaleNumY);                TextBlock txtBlock = new TextBlock();                txtBlock.Text = (i).ToString();//文本内容                Canvas.SetRight(txtBlock, this.Width + 8);                Canvas.SetBottom(txtBlock, i * scaleNumY - 8);//高度平移8文本内容上下对齐线                canvasXRuler.Children.Add(yLine);                canvasXRuler.Children.Add(txtBlock);            }        }        private static UserControlXY uControlXY;        ///         /// 创建点的位置        ///         ///         void InCanvasPoint(Point point)        {            var temp = CreatePointEllipse();            //temp.ToolTip = point.X / scaleNumX + "," + point.Y / scaleNumY;            temp.ToolTip = point.Y / scaleNumX + "," + point.X / scaleNumY + "  " + "(" + point.Y + "," + point.X + ")";            uControlXY.canvasLinePoint.Children.Add(temp);            Panel.SetZIndex(temp, 100);            Canvas.SetLeft(temp, point.X - temp.Height / 2);            Canvas.SetTop(temp, point.Y - temp.Width / 2);        }        ///         /// 创建Point        ///         void CreatePoint(List
itemList) { if (itemList != null && itemList.Count > 0) { for (int i = 0; i < itemList.Count; i++) { var startPoint = itemList[i]; var tmpPoint = ConvertPoint(startPoint); InCanvasPoint(tmpPoint); if (i + 1 == itemList.Count) { break; } var endPoint = itemList[i + 1]; var tmpEndPoint = ConvertPoint(endPoint); CreateLine(tmpPoint, tmpEndPoint); } } } ///
/// 创建连接的直线 /// ///
///
void CreateLine(Point startPoint, Point endPoint) { PathGeometry pg = new PathGeometry();//组合绘制的线段 Path pa = new Path();//绘制轨迹曲线的容器,用于显示 pa.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0)); pa.StrokeThickness = 1; PathFigure pf = new PathFigure(); pf.StartPoint = startPoint; LineSegment line = new LineSegment(); line.Point = endPoint; pf.Segments.Add(line); pg.Figures.Add(pf); pa.Data = pg; uControlXY.canvasLinePoint.Children.Add(pa); } ///
/// 创建弧线 /// void CreateArcLine(Tuple
data) { if (data == null) { return; } Point startPoint = ConvertPoint(data.Item1); Point endPoint = ConvertPoint(data.Item2); CreateLine(startPoint, endPoint); PathGeometry pg = new PathGeometry();//组合绘制的线段 Path pa = new Path();//绘制轨迹曲线的容器,用于显示 pa.ToolTip = data.Item1 + " " + data.Item2; //pa.Fill = new SolidColorBrush(Color.FromRgb(255, 0, 0)); pa.Stroke = new SolidColorBrush(Color.FromRgb(255, 0, 0)); pa.StrokeThickness = 1; PathFigure pf = new PathFigure(); pf.StartPoint = startPoint; ArcSegment line = new ArcSegment(); line.SweepDirection = SweepDirection.Clockwise;//顺时针弧 line.Point = endPoint; //半径 正弦定理a/sinA=2r r=a/2sinA 其中a指的是两个城市点之间的距离 角A指a边的对角 double sinA = Math.Sin(Math.PI * data.Item3 / 180.0); //计算距离 勾股定理 double x = startPoint.X - endPoint.X; double y = startPoint.Y - endPoint.Y; double aa = x * x + y * y; double l = Math.Sqrt(aa); double r = l / (sinA * 2); line.Size = new Size(r, r); pf.Segments.Add(line); pg.Figures.Add(pf); pa.Data = pg; uControlXY.canvasLinePoint.Children.Add(pa); } ///
/// 把坐标转换为绘画坐标 /// ///
///
Point ConvertPoint(Point point) { var tmpPoint = new Point(); tmpPoint.X = point.Y * scaleNumY; tmpPoint.Y = point.X * scaleNumX; return tmpPoint; } ///
/// 创建圆点 /// ///
Ellipse CreatePointEllipse() { Ellipse ell = new Ellipse(); ell.Stroke = new SolidColorBrush(Color.FromRgb(255, 0, 0)); ell.Fill = new SolidColorBrush(Color.FromRgb(255, 0, 0)); ell.Height = 8; ell.Width = 8; return ell; } public void Refresh(List
_itemsSource) { canvasLinePoint.Children.Clear(); CreatePoint(_itemsSource); InitXRuler(); InitYRuler(); } public void ClearLine() { this.canvasLinePoint.Children.Clear(); } #endregion #region Customer DependencyObject ///
/// 求两点之间的弧线 /// item1 开始坐标 item2 结束坐标 item3 弧度值 /// public Tuple
PointArc { get { return (Tuple
)GetValue(PointArcProperty); } set { SetValue(PointArcProperty, value); } } public List
ItemsSource { get { return (List
)GetValue(ItemsSourceProperty); } set { SetValue(ItemsSourceProperty, value); } } // Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc... public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(List
), typeof(UserControlXY), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChangedCallback))); public static void OnItemsSourceChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.NewValue != null) { uControlXY = d as UserControlXY; uControlXY.CreatePoint(e.NewValue as List
); } } // Using a DependencyProperty as the backing store for PointArc. This enables animation, styling, binding, etc... public static readonly DependencyProperty PointArcProperty = DependencyProperty.Register("PointArc", typeof(Tuple
), typeof(UserControlXY), new PropertyMetadata(null, new PropertyChangedCallback(OnPointArcChangedCallback))); public static void OnPointArcChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.NewValue != null) { uControlXY = d as UserControlXY; uControlXY.CreateArcLine(e.NewValue as Tuple
); } } #endregion }}
View Code

帮助类

/***********************************************************************   * Copyright(c) 2016-2050 ligl* CLR 版本: 4.0.30319.42000   * 文 件 名:TrimmingHelper   * 创 建 人:ligl   * 创建日期:2016/7/14 21:05:16   * 修 改 人:ligl   * 修改日期:   * 备注描述:************************************************************************/using System;using System.Collections.Generic;using System.ComponentModel;using System.Linq;using System.Text;using System.Windows.Media;namespace Commons.Helper{    ///     /// 计算长度是否超出文本宽度的帮助类    ///     public class TrimmingHelper    {        ///         ///         ///         /// 原始文本        /// 省略文本符号        /// 追加省略号后面的文本,source+endNoTrimSource总体长度计算省略号        /// 文本长度        /// 字体类        /// 字体大小        /// True标示截取了文本        /// 
public static string Trim(string source, string suffix, string endNoTrimSource, double width, Typeface face, double fontsize, ref bool ShowTip) { if (face != null) { //real display max width. double realWidth = width; //try to get GlyphTypeface. GlyphTypeface glyphTypeface; face.TryGetGlyphTypeface(out glyphTypeface); if (glyphTypeface != null) { //calculate end string 's display width. if (!string.IsNullOrEmpty(endNoTrimSource)) { double notrimWidth = 0; foreach (char c in endNoTrimSource) { ushort w; glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w); notrimWidth += glyphTypeface.AdvanceWidths[w] * fontsize; } realWidth = width - notrimWidth; } //calculate source 's screen width double sourceWidth = 0; if (!string.IsNullOrEmpty(source)) { foreach (char c in source) { ushort w; glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w); sourceWidth += glyphTypeface.AdvanceWidths[w] * fontsize; } } //don't need to trim. if (sourceWidth <= realWidth) return source + endNoTrimSource; //calculate suffix's display width double suffixWidth = 0; if (!string.IsNullOrEmpty(suffix)) { foreach (char c in suffix) { ushort w; glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w); suffixWidth += glyphTypeface.AdvanceWidths[w] * fontsize; } } realWidth = realWidth - suffixWidth; if (realWidth > 0) { sourceWidth = 0; string trimStr = string.Empty; foreach (char c in source) { ushort w; glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w); double cWidth = glyphTypeface.AdvanceWidths[w] * fontsize; if ((sourceWidth + cWidth) > realWidth) { ShowTip = true; return trimStr + suffix + endNoTrimSource; } trimStr += c; sourceWidth += cWidth; } } else { ShowTip = true; if (width > suffixWidth) return suffix; else return "..."; } } } ShowTip = false; return source + endNoTrimSource; } /// /// 获取文本内容宽度的方法 /// /// /// /// ///
public static double GetControlWidth(string source, Typeface face, double fontsize) { double realWidth = 0; if (face != null) { //try to get GlyphTypeface. GlyphTypeface glyphTypeface; face.TryGetGlyphTypeface(out glyphTypeface); if (glyphTypeface != null) { //calculate source 's screen width if (!string.IsNullOrEmpty(source)) { foreach (char c in source) { ushort w; glyphTypeface.CharacterToGlyphMap.TryGetValue(c, out w); realWidth += glyphTypeface.AdvanceWidths[w] * fontsize; } } } } return realWidth; } }}
View Code

 使用方式:

Xaml

View Code

Code

using System;using System.Collections.Generic;using System.Linq;using System.Text;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.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;using System.ComponentModel;namespace CoordinateXY{    ///     /// UserControlShow.xaml 的交互逻辑    ///     public partial class UserControlShow : UserControl    {        ViewMode vModel = new ViewMode();        public UserControlShow()        {            InitializeComponent();            this.DataContext = vModel;        }        private void BtnRefresh_Click(object sender, RoutedEventArgs e)        {            //uControlXY.Width = uControlXY.Width * 1.1;            //uControlXY.Height = uControlXY.Height * 1.1;            var txt = txtboxWH.Text.Trim();            string[] whs = txt.Split(',');            if (whs.Length != 2)            {                return;            }            double w;            double h;            double.TryParse(whs[0], out w);            double.TryParse(whs[1], out h);            if (w != 0 && h != 0)            {                this.uControlXY.XWidth = w;                this.uControlXY.YHeight = h;                this.uControlXY.Refresh(vModel.XyList);            }        }        private void BtnArc_Click(object sender, RoutedEventArgs e)        {            var spoints = txtboxArcSpoint.Text.Trim().Split(',');            if (spoints.Length != 2)            {                return;            }            Point startPoint = new Point();            double sX;            double sY;            double.TryParse(spoints[0], out sX);            double.TryParse(spoints[1], out sY);            startPoint.X = sX;            startPoint.Y = sY;            var epoints = txtboxArcEpoint.Text.Trim().Split(',');            if (epoints.Length != 2)            {                return;            }            Point endPoint = new Point();            double eX;            double eY;            double.TryParse(epoints[0], out eX);            double.TryParse(epoints[1], out eY);            endPoint.X = eX;            endPoint.Y = eY;            var angletxt = txtboxAngle.Text.Trim();            double angle;            double.TryParse(angletxt, out angle);            vModel.ArcData = new Tuple
(startPoint, endPoint, angle); } private void BtnClear_Click(object sender, RoutedEventArgs e) { uControlXY.ClearLine(); } } public class ViewMode : INotifyPropertyChanged { public ViewMode() { _xyList = new List
(); XyList.Add(new Point(10, 10)); XyList.Add(new Point(40, 50)); XyList.Add(new Point(30, 40)); XyList.Add(new Point(90, 10)); XyList.Add(new Point(20, 90)); XyList.Add(new Point(45.5, 73.2)); XyList.Add(new Point(140, 235)); _arcData = new Tuple
(new Point(50, 50), new Point(80, 90), 60); } private Tuple
_arcData; private List
_xyList; public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, e); } } public List
XyList { get { return _xyList; } set { _xyList = value; OnPropertyChanged(new PropertyChangedEventArgs("XyList")); } } ///
/// 弧线构成数据 /// public Tuple
ArcData { get { return _arcData; } set { _arcData = value; OnPropertyChanged(new PropertyChangedEventArgs("ArcData")); } } }}
View Code

 

转载地址:http://cuylx.baihongyu.com/

你可能感兴趣的文章
Linux expect自动登录ssh,ftp
查看>>
NET面试问题集
查看>>
设计模式学习(十) 外观模式
查看>>
sql中的视图
查看>>
mysql定时任务
查看>>
TCP
查看>>
[USACO06NOV] Corn Fields
查看>>
链表操作
查看>>
七、PyQT5控件——QSlider,QSpinBox
查看>>
C# 的时间戳转换
查看>>
总结一下三个io复用函数
查看>>
java第10次作业
查看>>
NuGet学习笔记——初识NuGet及快速安装使用
查看>>
spring配置hibernate映射文件
查看>>
hive四种排序
查看>>
各种开放平台接口
查看>>
SQL Server 调优系列基础篇 - 并行运算总结(一)
查看>>
url编码
查看>>
PHP基础(谈一谈Session&Cookie)
查看>>
硅谷行记二:走进百度美国研发中心
查看>>