Skip to content

Commit 7bc6cea

Browse files
committed
fix: prevent leftmost x-axis label from being clipped in Statistics chart
1 parent 6a32ba1 commit 7bc6cea

1 file changed

Lines changed: 69 additions & 57 deletions

File tree

src/Views/Chart.cs

Lines changed: 69 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public override void Render(DrawingContext context)
6868
var hasUserSamples = samples.HasSpecialUser;
6969

7070
var labelPen = new Pen(new SolidColorBrush(Colors.Gray, 0.4), .5);
71+
var tickPen = new Pen(Brushes.Gray);
7172
var labelTypeface = new Typeface(LabelFontFamily);
7273
var corner = new CornerRadius(2, 2, 0, 0);
7374
var sampleBrush = SampleBrush;
@@ -103,78 +104,89 @@ public override void Render(DrawingContext context)
103104
var sampleW = hasUserSamples ? Math.Min(step * 0.5 - 2.5, 14.0) : Math.Min(step - 3, 28.0);
104105
var maxSampleH = h - 24.0;
105106
var maxLabelEndX = w - 4.0;
107+
var labelsToDraw = new List<(FormattedText Text, Point Position, Point TickStart, Point TickEnd)>();
106108

107-
using var clip = context.PushClip(new Rect(leftMargin, 0, w - leftMargin, h));
108-
do
109+
using (context.PushClip(new Rect(leftMargin, 0, w - leftMargin, h)))
109110
{
110-
var (label, total, user) = samples.GetSample(time);
111-
112-
if (x - step <= w && total > 0)
111+
do
113112
{
114-
if (hasUserSamples)
115-
{
116-
var startX = x - step * 0.5 - 1 - sampleW;
117-
var startY = maxSampleH * (1.0 - total * 1.0 / maxValue);
118-
var rect = new Rect(startX, startY, sampleW, maxSampleH - startY);
113+
var (label, total, user) = samples.GetSample(time);
119114

120-
using (context.PushOpacity(0.2))
115+
if (x - step <= w && total > 0)
116+
{
117+
if (hasUserSamples)
121118
{
122-
context.DrawRectangle(sampleBrush, null, new RoundedRect(rect, corner));
119+
var startX = x - step * 0.5 - 1 - sampleW;
120+
var startY = maxSampleH * (1.0 - total * 1.0 / maxValue);
121+
var rect = new Rect(startX, startY, sampleW, maxSampleH - startY);
122+
123+
using (context.PushOpacity(0.2))
124+
{
125+
context.DrawRectangle(sampleBrush, null, new RoundedRect(rect, corner));
126+
}
127+
128+
if (user > 0)
129+
{
130+
var userStartX = startX + sampleW + 2;
131+
var userStartY = maxSampleH * (1.0 - user * 1.0 / maxValue);
132+
var userRect = new Rect(userStartX, userStartY, sampleW, maxSampleH - userStartY);
133+
context.DrawRectangle(sampleBrush, null, new RoundedRect(userRect, corner));
134+
}
135+
136+
var hitRect = new Rect(startX, startY, sampleW * 2 + 2, maxSampleH - startY);
137+
_hitBoxes.Add(new(hitRect, new(label, true, total, user)));
123138
}
124-
125-
if (user > 0)
139+
else
126140
{
127-
var userStartX = startX + sampleW + 2;
128-
var userStartY = maxSampleH * (1.0 - user * 1.0 / maxValue);
129-
var userRect = new Rect(userStartX, userStartY, sampleW, maxSampleH - userStartY);
130-
context.DrawRectangle(sampleBrush, null, new RoundedRect(userRect, corner));
131-
}
141+
var startX = x - step * 0.5 - sampleW * 0.5;
142+
var startY = maxSampleH * (1.0 - total * 1.0 / maxValue);
143+
var rect = new Rect(startX, startY, sampleW, maxSampleH - startY);
132144

133-
var hitRect = new Rect(startX, startY, sampleW * 2 + 2, maxSampleH - startY);
134-
_hitBoxes.Add(new(hitRect, new(label, true, total, user)));
135-
}
136-
else
137-
{
138-
var startX = x - step * 0.5 - sampleW * 0.5;
139-
var startY = maxSampleH * (1.0 - total * 1.0 / maxValue);
140-
var rect = new Rect(startX, startY, sampleW, maxSampleH - startY);
141-
142-
context.DrawRectangle(sampleBrush, null, new RoundedRect(rect, corner));
143-
_hitBoxes.Add(new(rect, new(label, false, total, 0)));
145+
context.DrawRectangle(sampleBrush, null, new RoundedRect(rect, corner));
146+
_hitBoxes.Add(new(rect, new(label, false, total, 0)));
147+
}
144148
}
145-
}
146149

147-
if (x <= w)
148-
{
149-
var formattedLabel = new FormattedText(
150-
label,
151-
CultureInfo.CurrentCulture,
152-
FlowDirection.LeftToRight,
153-
labelTypeface,
154-
11,
155-
Brushes.Gray);
156-
157-
var labelCenterX = x - step * 0.5;
158-
var labelEndX = labelCenterX + formattedLabel.Width * 0.5;
159-
if (labelEndX <= maxLabelEndX)
150+
if (x <= w)
160151
{
161-
var labelStartX = labelCenterX - formattedLabel.Width * 0.5;
162-
var labelStartY = h - formattedLabel.Height - 2.0;
163-
context.DrawLine(new Pen(Brushes.Gray), new Point(labelCenterX, maxSampleH + 4), new Point(labelCenterX, maxSampleH));
164-
context.DrawText(formattedLabel, new Point(labelStartX, labelStartY));
165-
maxLabelEndX = labelStartX - 16.0;
152+
var formattedLabel = new FormattedText(
153+
label,
154+
CultureInfo.CurrentCulture,
155+
FlowDirection.LeftToRight,
156+
labelTypeface,
157+
11,
158+
Brushes.Gray);
159+
160+
var labelCenterX = x - step * 0.5;
161+
var labelEndX = labelCenterX + formattedLabel.Width * 0.5;
162+
if (labelEndX <= maxLabelEndX)
163+
{
164+
var labelStartX = labelCenterX - formattedLabel.Width * 0.5;
165+
var labelStartY = h - formattedLabel.Height - 2.0;
166+
labelsToDraw.Add((formattedLabel,
167+
new Point(labelStartX, labelStartY),
168+
new Point(labelCenterX, maxSampleH + 4),
169+
new Point(labelCenterX, maxSampleH)));
170+
maxLabelEndX = labelStartX - 16.0;
171+
}
166172
}
167-
}
168173

169-
if (x <= leftMargin)
170-
break;
174+
if (x <= leftMargin)
175+
break;
176+
177+
x -= step;
171178

172-
x -= step;
179+
time = samples.NextSampleTime(time);
180+
if (time < minTime)
181+
break;
182+
} while (true);
183+
}
173184

174-
time = samples.NextSampleTime(time);
175-
if (time < minTime)
176-
break;
177-
} while (true);
185+
foreach (var (text, position, tickStart, tickEnd) in labelsToDraw)
186+
{
187+
context.DrawLine(tickPen, tickStart, tickEnd);
188+
context.DrawText(text, position);
189+
}
178190
}
179191

180192
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)

0 commit comments

Comments
 (0)