如何定位标签周围的标签?

我试图弄清楚如何计算一个圆圈周围文本标签的位置。 这比你在第一次阅读时可能会想到的稍微复杂一些。

我了解基础知识:

X = ptCenter.X + (dRadius * Math.Cos(dAngle * Math.PI / 180.0))
Y = ptCenter.Y + (dRadius * Math.Sin(dAngle * Math.PI / 180.0))

所以,这会给我在dAngle半径为dRadius的圆上的点。 当然,DrawText(任何种类,但我特别使用DrawingContext.DrawText,如果这对你的答案有任何不同)用给定的点作为文本的左上角绘制。

问题在于,这不是在文本上绘制文本的正确位置。 这是一个问题的例子:

https://support.office.com/en-us/article/Present-your-data-in-a-radar-chart-16e20279-eed4-43c2-9bf5-29ff9b10601d

Jan水平居中,从左下方画出2月,而Mar似乎是水平居中的四月,垂直居中等等。

标签没有以统一的方式定位在点周围。 它的种类取决于你的绘图的角度。

我需要绘制的标签数量可能会有所不同,因此硬编码技巧因素已不存在。 我需要绘制的角度也可能会有所不同,因此在那里也不会有任何欺骗因素。 所有这些都必须在飞行中计算。

类似于0,90,180,270是特殊情况,而其他情况似乎是以点为中心垂直居中,但是根据您所谈论的圆的哪一侧绘制在右侧或左侧?

我在正确的轨道上吗? 还是有一个“已知”的算法?

谢谢。


你需要的是将文本的中心定位在你计算的点上。 所以你需要在X方向上以半宽度移动点,在Y方向上按半高度移动。这将把标签定位在圆内。 喜欢这个:

public class CircleText : FrameworkElement {
    public string[] Labels
    {
        get { return (string[])GetValue(LabelsProperty); }
        set { SetValue(LabelsProperty, value); }
    }

    public static readonly DependencyProperty LabelsProperty =
        DependencyProperty.Register("Labels", typeof(string[]), typeof(CircleText), new PropertyMetadata(null, OnLabelsChanged));

    private static void OnLabelsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        ((CircleText) d).InvalidateVisual();
    }

    protected override void OnRender(DrawingContext drawingContext) {
        if (Labels == null || Labels.Length == 0)
            return;
        var centerX = this.ActualWidth / 2;
        var centerY = this.ActualHeight / 2;
        var rad = Math.Min(this.ActualWidth / 2, this.ActualHeight / 2);
        for (int i = 0; i < Labels.Length; i++) {
            var angle = 360 / (Labels.Length) * i;
            var x = centerX + rad * Math.Cos(angle * Math.PI / 180.0);
            var y = centerY + rad * Math.Sin(angle * Math.PI / 180.0);
            FormattedText text = new FormattedText(
                Labels[i],
                CultureInfo.GetCultureInfo("en-us"),
                FlowDirection.LeftToRight,
                new Typeface("Verdana"),
                12,
                Brushes.Black);
            x -= text.Width / 2;
            y -= text.Height / 2;
            drawingContext.DrawText(text, new Point(x, y));
        }

    }
}

如果您想为您的点绘制线条,并且希望标签位于这些线条之外 - 则需要根据已计算的cos和sin值来移动标签。 这会将标签定位在“外部”,如下所示:

protected override void OnRender(DrawingContext drawingContext) {
        if (Labels == null || Labels.Length == 0)
            return;
        var centerX = this.ActualWidth / 2;
        var centerY = this.ActualHeight / 2;
        var rad = Math.Min(this.ActualWidth / 2, this.ActualHeight / 2);
        for (int i = 0; i < Labels.Length; i++) {
            var angle = 360 / (Labels.Length) * i;
            var xshift = Math.Cos(angle * Math.PI / 180.0);
            var yshift = Math.Sin(angle * Math.PI / 180.0);
            var x = centerX + rad * xshift;
            var y = centerY + rad * yshift;
            drawingContext.DrawLine(new Pen(Brushes.Black, 1), new Point(centerX, centerY), new Point(x,y));
            FormattedText text = new FormattedText(
                Labels[i],
                CultureInfo.GetCultureInfo("en-us"),
                FlowDirection.LeftToRight,
                new Typeface("Verdana"),
                12,
                Brushes.Black);
            x -= (1 - xshift) * text.Width / 2;
            y -= (1 - yshift) * text.Height / 2;                
            drawingContext.DrawText(text, new Point(x, y));
        }            
    }

当然,上述工作适用于任何数量的标签。


你是对的,问题并不像看起来那么简单。 在用铅笔和纸张坐下后,我认为问题可以通过简单的步骤分解:

在这里输入图像描述

  • 确定您的圆圈和所需边距的尺寸(图片上:蓝色虚线圆圈)。
  • 确定标签文本的大小(在图像上:标签周围的黑框)。
  • 确定应触及蓝色虚线圆圈的(黑色)标签文字框上的点。 对于每个维度(X,Y)分别:
  • 如果文本标签的中心点距离坐标轴的标签大小的一半(在图像上:在橙色双线内 - 请参见圆圈上方的标签),那么您的点位于标签文本框的边缘
  • 否则,该点位于标签文本框的拐角处。
  • 从圆圈中间移动标签,使其黑框在步骤3中确定的点处接触蓝色虚线。 (在图像上:从圆心到标签中心的红线)
  • 根据与圆圈接触的点,确定标签的左上角点,并在结果位置绘制标签。
  • 对不起,这里没有公式,我需要更多时间来撰写它们。 但是我想告诉你,这里的定位标签比两行代码中的sin()cos()简单得多。

    链接地址: http://www.djcxy.com/p/53309.html

    上一篇: How to position labels around circle?

    下一篇: Setting MIME Types in IIS