【WPF】坐标系

大小可变的坐标系…

绘制坐标轴和刻度

WPF的坐标系是从左上角为原点,向右的方向为x轴,向下的方向为y轴,所以使用canvas容器布局需要进行旋转,将坐标系旋转为正常的笛卡尔坐标系…
因为要动态的修改大小,所以刻度和刻度线就不可以都画在xaml里…

/// <summary>
/// 绘制坐标轴和刻度
/// </summary>
private void DrawAxisAndText()
{
    for (int i = 0; i < 10; ++i)
    {
        //左右两条线xaml里面画
        if (i != 0 || i != 9)
        {
            //坐标线
            Line lineX = new Line()
            {
                Stroke = new SolidColorBrush(Colors.White),
                StrokeDashArray = new DoubleCollection(6),
                StrokeThickness = 1,
            };
            Canvas.SetZIndex(lineX, 0);
            Line lineY = new Line()
            {
                Stroke = new SolidColorBrush(Colors.White),
                StrokeDashArray = new DoubleCollection(6),
                StrokeThickness = 1,
            };
            Canvas.SetZIndex(lineY, 0);
            lineX.X1 = (double)((decimal)CanvasInPath.Width / 10) * i;
            lineX.X2 = (double)((decimal)CanvasInPath.Width / 10) * i;
            lineX.Y1 = 0;
            lineX.Y2 = CanvasInPath.Height;

            lineY.X1 = 0;
            lineY.X2 = CanvasInPath.Width;
            lineY.Y1 = (double)((decimal)CanvasInPath.Height / 10) * i;
            lineY.Y2 = (double)((decimal)CanvasInPath.Height / 10) * i;
            CanvasInPath.Children.Add(lineX);
            CanvasInPath.Children.Add(lineY);
        }

        //刻度
        if (i < 9)
        {
            TextBlock xblock = new TextBlock();
            xblock.Foreground = new SolidColorBrush(Colors.White);
            xblock.FontSize = 10;
            TranslateTransform translateTransform = new TranslateTransform(0, xblock.ActualHeight);
            ScaleTransform scaleTransform = new ScaleTransform();
            scaleTransform.ScaleY = -1;
            TransformGroup transformGroup = new TransformGroup();
            transformGroup.Children.Add(translateTransform);
            transformGroup.Children.Add(scaleTransform);
            xblock.RenderTransform = transformGroup;

            xblock.Text = (i + 1) * 10 + "%";
            Canvas.SetLeft(xblock, TransFromX((i + 1) * 10));
            Canvas.SetTop(xblock, 15);
            CanvasInPath.Children.Add(xblock);
            Canvas.SetZIndex(xblock, 1);

            TextBlock yblock = new TextBlock();
            yblock.Foreground = new SolidColorBrush(Colors.White);
            yblock.FontSize = 10;
            translateTransform = new TranslateTransform(0, yblock.ActualHeight);
            scaleTransform = new ScaleTransform();
            scaleTransform.ScaleY = -1;
            transformGroup = new TransformGroup();
            transformGroup.Children.Add(translateTransform);
            transformGroup.Children.Add(scaleTransform);
            yblock.RenderTransform = transformGroup;

            yblock.Text = (i + 1) * 10 + "%";
            Canvas.SetLeft(yblock, 5);
            Canvas.SetTop(yblock, TransFromY((i + 1.5) * 10));
            CanvasInPath.Children.Add(yblock);
            Canvas.SetZIndex(yblock, 1);
        }
    }
}

把整个画布的宽和高分成十份,均匀的画线,然后在线的中间画上刻度…

效果图

在这里插入图片描述

坐标转换

输入小球对应的刻度,转换为canvas容器里对应的坐标,也就是leftproperty和topproperty,另外left和top属性设置的位置是小球的左下角,想设置为小球正中心需要减去小球的长度的1/2

/// <summary>
/// 转换Canvas坐标
/// </summary>
/// <param value="坐标轴的刻度"></param>
/// <returns></returns>
private double TransFromX(double value)
{
    return (double)(((decimal)value / 10) * (decimal)(CanvasInPath.Width) / 10 - (decimal)XOffset);
}
private double TransFromY(double value)
{
    return (double)(((decimal)value / 10) * (decimal)(CanvasInPath.Height) / 10 - (decimal)YOffset);
}

如果需要DataGrid实时显示小球的位置,需要将小球的对应的刻度更新到ViewModel,所以还需要根据小球对象获取小球对应的刻度

/// <summary>
/// 获取小球的坐标轴刻度
/// </summary>
/// <param dot="小球对象"></param>
/// <returns></returns>
private double[] GetValueOfAxis(Ellipse dot)
{
    double x1 = (double)((decimal)(Canvas.GetLeft(dot) + XOffset) / (decimal)(CanvasInPath.Width / 100));
    double y1 = (double)((decimal)(Canvas.GetTop(dot) + YOffset) / (decimal)(CanvasInPath.Height / 100));
    return new double[2] { x1, y1 };
}

根据上面的方法,封装一个设置小球位置的函数,这里小球我直接用的Ellipse,正确做法应该是做成一个单独的控件,以后要想改小球的大小和颜色只需要改动小球控件

/// <summary>
/// 设置点的位置
/// </summary>
/// <param dot="小球对象"></param>
/// <param x="x轴刻度"></param>
/// <param y="y轴刻度"></param>
private void SetDotPosition(Ellipse dot, double x, double y)
{
    double xpoint = TransFromX(x);
    double ypoint = TransFromY(y);
    Canvas.SetLeft(dot, xpoint);
    Canvas.SetTop(dot, ypoint);
}

然后加上小球的拖动,更新线段的位置,就实现了小球在坐标系里的移动,然后实现窗口大小改变,坐标轴更新,小球位置更新,线段更新即可

改变窗口大小

①保存改变之前小球对应的刻度(位置)
②canvas内所有元素移除
③canvas的大小根据改变后的窗口大小重新赋值,坐标轴最大值也根据窗口大小赋值
④canvas加入小球和线段
⑤画坐标系,根据保存的刻度设置小球位置,更新线段

/// <summary>
/// 尺寸改变,重绘
/// </summary>
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (this.Width != 500 || this.Height != 600)
    {
        double[] dot1value = GetValueOfAxis(DutyCycleCurveDot1);
        double[] dot2value = GetValueOfAxis(DutyCycleCurveDot2);

        CanvasInPath.Children.Clear();
        CanvasInPath.Height = this.ActualHeight - 100;
        CanvasInPath.Width = this.ActualWidth;
        MaxCoordinateAxisX = this.ActualWidth;
        MaxCoordinateAxisY = this.ActualHeight - 100;
        CanvasInPath.Children.Add(DutyCycleCurveDot1);
        CanvasInPath.Children.Add(DutyCycleCurveDot2);
        CanvasInPath.Children.Add(DutyCycleLineList[0]);
        CanvasInPath.Children.Add(DutyCycleLineList[1]);
        CanvasInPath.Children.Add(DutyCycleLineList[2]);
        DrawAxisAndText();
        SetDotPosition(DutyCycleCurveDot1, dot1value[0], dot1value[1]);
        SetDotPosition(DutyCycleCurveDot2, dot2value[0], dot2value[1]);
        UpdateLineAndDot(DutyCycleDotList, DutyCycleLineList);
    }
}

效果演示

在这里插入图片描述

展开阅读全文
©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值