-
Notifications
You must be signed in to change notification settings - Fork 61
Expand file tree
/
Copy pathMetricsDiagram.cs
More file actions
131 lines (117 loc) · 5.1 KB
/
MetricsDiagram.cs
File metadata and controls
131 lines (117 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.Drawing.Processing;
namespace SixLabors.Samples.Fonts;
/// <summary>
/// Provides shared drawing helpers for metrics visualizer samples.
/// </summary>
internal static class MetricsDiagram
{
private const float MeasurementLineWidth = 2;
private const float ExtensionLineLength = 44;
/// <summary>
/// Draws a horizontal measurement with centered arrowheads and a label.
/// </summary>
public static void DrawHorizontalMeasurement(
DrawingCanvas canvas,
Font labelFont,
string label,
float start,
float end,
float y,
PointF labelAnchor,
HorizontalAlignment horizontalAlignment,
VerticalAlignment verticalAlignment)
{
Pen measurementPen = Pens.Solid(Color.Black, MeasurementLineWidth);
Pen guidePen = new PatternPen(Color.Gray, 1, [4, 4]);
canvas.DrawLine(measurementPen, new PointF(start, y), new PointF(end, y));
canvas.DrawLine(guidePen, new PointF(start, y - (ExtensionLineLength * .5F)), new PointF(start, y + (ExtensionLineLength * .5F)));
canvas.DrawLine(guidePen, new PointF(end, y - (ExtensionLineLength * .5F)), new PointF(end, y + (ExtensionLineLength * .5F)));
DrawArrowHead(canvas, new PointF(start, y), new PointF(1, 0));
DrawArrowHead(canvas, new PointF(end, y), new PointF(-1, 0));
DrawLabel(canvas, labelFont, label, labelAnchor, Color.Black, horizontalAlignment, verticalAlignment);
}
/// <summary>
/// Draws a vertical measurement with centered arrowheads and a label.
/// </summary>
public static void DrawVerticalMeasurement(
DrawingCanvas canvas,
Font labelFont,
string label,
float start,
float end,
float x,
PointF labelAnchor,
HorizontalAlignment horizontalAlignment,
VerticalAlignment verticalAlignment)
{
Pen measurementPen = Pens.Solid(Color.Black, MeasurementLineWidth);
Pen guidePen = new PatternPen(Color.Gray, 1, [4, 4]);
canvas.DrawLine(measurementPen, new PointF(x, start), new PointF(x, end));
canvas.DrawLine(guidePen, new PointF(x - (ExtensionLineLength * .5F), start), new PointF(x + (ExtensionLineLength * .5F), start));
canvas.DrawLine(guidePen, new PointF(x - (ExtensionLineLength * .5F), end), new PointF(x + (ExtensionLineLength * .5F), end));
DrawArrowHead(canvas, new PointF(x, start), new PointF(0, 1));
DrawArrowHead(canvas, new PointF(x, end), new PointF(0, -1));
DrawLabel(canvas, labelFont, label, labelAnchor, Color.Black, horizontalAlignment, verticalAlignment);
}
/// <summary>
/// Draws a text label.
/// </summary>
public static void DrawLabel(DrawingCanvas canvas, Font labelFont, string label, PointF origin, Color color)
=> canvas.DrawText(
new RichTextOptions(labelFont) { Origin = origin },
label,
Brushes.Solid(color),
pen: null);
/// <summary>
/// Draws a text label positioned relative to an anchor point.
/// </summary>
public static void DrawLabel(
DrawingCanvas canvas,
Font labelFont,
string label,
PointF anchor,
Color color,
HorizontalAlignment horizontalAlignment,
VerticalAlignment verticalAlignment)
{
FontRectangle labelBounds = TextMeasurer.MeasureAdvance(label, new TextOptions(labelFont));
PointF origin = new(
AlignHorizontal(anchor.X, labelBounds.Width, horizontalAlignment),
AlignVertical(anchor.Y, labelBounds.Height, verticalAlignment));
DrawLabel(canvas, labelFont, label, origin, color);
}
private static void DrawArrowHead(DrawingCanvas canvas, PointF endPoint, PointF direction)
{
const float length = 12;
const float halfWidth = 5;
const float lineOffset = .5F;
PointF tip = direction.X == 0
? new PointF(endPoint.X + lineOffset, endPoint.Y)
: new PointF(endPoint.X, endPoint.Y + lineOffset);
canvas.Fill(Brushes.Solid(Color.Black), new Polygon(
[
tip,
new PointF(tip.X + (direction.X * length) - (direction.Y * halfWidth), tip.Y + (direction.Y * length) + (direction.X * halfWidth)),
new PointF(tip.X + (direction.X * length) + (direction.Y * halfWidth), tip.Y + (direction.Y * length) - (direction.X * halfWidth)),
]));
}
private static float AlignHorizontal(float x, float width, HorizontalAlignment alignment)
=> alignment switch
{
HorizontalAlignment.Center => x - (width * .5F),
HorizontalAlignment.Right => x - width,
_ => x,
};
private static float AlignVertical(float y, float height, VerticalAlignment alignment)
=> alignment switch
{
VerticalAlignment.Center => y - (height * .5F),
VerticalAlignment.Bottom => y - height,
_ => y,
};
}