optimize<Statistics>: only redraw chart when mouse hovered on a new sample box

This commit is contained in:
leo 2024-03-04 20:50:10 +08:00
parent ad9cf615ab
commit ade43ed988

View file

@ -42,7 +42,11 @@ namespace SourceGit.Views {
} }
static Chart() { static Chart() {
AffectsRender<Chart>(SamplesProperty); SamplesProperty.Changed.AddClassHandler<Chart>((c, e) => {
c._hitBoxes.Clear();
c._lastHitIdx = -1;
c.InvalidateVisual();
});
} }
public override void Render(DrawingContext context) { public override void Render(DrawingContext context) {
@ -75,6 +79,9 @@ namespace SourceGit.Views {
var width = Bounds.Width; var width = Bounds.Width;
var height = Bounds.Height; var height = Bounds.Height;
// Transparent background to block mouse move events.
context.DrawRectangle(Brushes.Transparent, null, new Rect(0, 0, Bounds.Width, Bounds.Height));
// Draw coordinate // Draw coordinate
var maxLabel = new FormattedText($"{maxV}", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 12.0, LineBrush); var maxLabel = new FormattedText($"{maxV}", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 12.0, LineBrush);
var horizonStart = maxLabel.Width + 8; var horizonStart = maxLabel.Width + 8;
@ -108,13 +115,14 @@ namespace SourceGit.Views {
} }
// Calculate hit boxes // Calculate hit boxes
var shapeWidth = Math.Min(32, stepX - 4); if (_hitBoxes.Count == 0) {
var hitboxes = new List<Rect>(); var shapeWidth = Math.Min(32, stepX - 4);
for (int i = 0; i < samples.Count; i++) { for (int i = 0; i < samples.Count; i++) {
var h = samples[i].Count * (height - labelHeight) / maxV; var h = samples[i].Count * (height - labelHeight) / maxV;
var x = horizonStart + 1 + stepX * i + (stepX - shapeWidth) * 0.5; var x = horizonStart + 1 + stepX * i + (stepX - shapeWidth) * 0.5;
var y = height - labelHeight - h; var y = height - labelHeight - h;
hitboxes.Add(new Rect(x, y, shapeWidth, h)); _hitBoxes.Add(new Rect(x, y, shapeWidth, h - 1));
}
} }
// Draw shapes // Draw shapes
@ -126,7 +134,7 @@ namespace SourceGit.Views {
typeface, typeface,
10.0, 10.0,
LineBrush); LineBrush);
var rect = hitboxes[i]; var rect = _hitBoxes[i];
var xLabel = rect.X - (hLabel.Width - rect.Width) * 0.5; var xLabel = rect.X - (hLabel.Width - rect.Width) * 0.5;
var yLabel = height - labelHeight + 4; var yLabel = height - labelHeight + 4;
@ -145,32 +153,45 @@ namespace SourceGit.Views {
} }
// Draw labels on hover // Draw labels on hover
for (int i = 0; i < samples.Count; i++) { if (_lastHitIdx >= 0 && _lastHitIdx < samples.Count) {
var rect = hitboxes[i]; var rect = _hitBoxes[_lastHitIdx];
if (rect.Contains(_mousePos)) { var tooltip = new FormattedText(
var tooltip = new FormattedText( $"{samples[_lastHitIdx].Count}",
$"{samples[i].Count}",
CultureInfo.CurrentCulture, CultureInfo.CurrentCulture,
FlowDirection.LeftToRight, FlowDirection.LeftToRight,
typeface, typeface,
12.0, 12.0,
LineBrush); LineBrush);
var tx = rect.X - (tooltip.Width - rect.Width) * 0.5; var tx = rect.X - (tooltip.Width - rect.Width) * 0.5;
var ty = rect.Y - tooltip.Height - 4; var ty = rect.Y - tooltip.Height - 4;
context.DrawText(tooltip, new Point(tx, ty)); context.DrawText(tooltip, new Point(tx, ty));
break;
}
} }
} }
protected override void OnPointerMoved(PointerEventArgs e) { protected override void OnPointerMoved(PointerEventArgs e) {
base.OnPointerMoved(e); base.OnPointerMoved(e);
_mousePos = e.GetPosition(this);
InvalidateVisual(); var p = e.GetPosition(this);
for (int i = 0; i < _hitBoxes.Count; i++) {
if (_hitBoxes[i].Contains(p)) {
if (_lastHitIdx != i) {
_lastHitIdx = i;
InvalidateVisual();
}
return;
}
}
if (_lastHitIdx != -1) {
_lastHitIdx = -1;
InvalidateVisual();
}
} }
private Point _mousePos = new Point(0, 0); private List<Rect> _hitBoxes = new List<Rect>();
private int _lastHitIdx = -1;
} }
public partial class Statistics : Window { public partial class Statistics : Window {