Skip to content

Commit 0bf3f3b

Browse files
manarutoswharden
andauthored
LabelStyle: Add underline support (ScottPlot#4893)
* Finalize underline text logic for both LTR and RTL. * Cookbook: underline recipe * Underline: do not draw when width is 0 * Update CHANGELOG.md --------- Co-authored-by: Scott W Harden <swharden@gmail.com>
1 parent 3da4cc9 commit 0bf3f3b

4 files changed

Lines changed: 102 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ _Not yet on NuGet..._
1919
* GitHub: Create a `devconainer.json` file to facilitate development in GitHub Codespaces (#5002) @oxygen-dioxide
2020
* Maui: Improve behavior for interactive plots when their user input processor is disabled (#4990, #4989) @Adam--
2121
* Fonts: Added new styling options for weight, slant, density, etc. (#5013, #4873) @aespitia @Christoph-Wagner
22+
* Labels: Added styling options for underline with customizable thickness and offset (#4893) @manaruto
2223

2324
## ScottPlot 5.0.55
2425
_Published on [NuGet](https://www.nuget.org/profiles/ScottPlot) on 2025-03-22_

src/ScottPlot5/ScottPlot5 Cookbook/Recipes/General/Styling.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,4 +421,28 @@ public override void Execute()
421421
myPlot.HideGrid();
422422
}
423423
}
424+
425+
public class SetFontUnderline : RecipeBase
426+
{
427+
public override string Name => "Set Label Underline";
428+
public override string Description => "Underlines may be added to label styles. " +
429+
"Underline thickness and offset may be customized as well.";
430+
431+
[Test]
432+
public override void Execute()
433+
{
434+
for (int i = 0; i < 5; i++)
435+
{
436+
var text = myPlot.Add.Text($"Underline {i}px", i / 5.0, i);
437+
text.LabelFontSize = 24;
438+
text.LabelFontColor = ScottPlot.Palette.Default.GetColor(i);
439+
text.LabelUnderline = true;
440+
text.LabelUnderlineWidth = i;
441+
text.LabelUnderlineOffset = 2 + i / 2;
442+
}
443+
444+
myPlot.Axes.SetLimits(-1, 5, -1, 4);
445+
myPlot.HideGrid();
446+
}
447+
}
424448
}

src/ScottPlot5/ScottPlot5/Primitives/LabelStyle.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public class LabelStyle
4848
public string FontName { get; set; } = Fonts.Default;
4949
public float FontSize { get; set; } = 12;
5050
public bool Bold { get; set; } = false;
51+
public bool Underline { get; set; } = false;
52+
private bool RenderUnderline => Underline & UnderlineWidth != 0;
53+
public double UnderlineWidth { get; set; } = 1;
54+
public double UnderlineOffset { get; set; } = 2;
5155

5256
/// <summary>
5357
/// Manually defined line height in pixels.
@@ -329,10 +333,45 @@ private void DrawText(SKCanvas canvas, MeasuredText measured, SKPaint paint, Pix
329333
if (LabelStyle.RTLSupport)
330334
{
331335
using (var shaper = new SKShaper(paint.Typeface))
336+
{
337+
float shapedWidth = shaper.Shape(lines[i], paint).Width;
332338
canvas.DrawShapedText(shaper, lines[i], xPx, yPx, paint);
339+
340+
if (RenderUnderline)
341+
{
342+
float underlineY = yPx + (float)UnderlineOffset;
343+
344+
using var underlinePaint = new SKPaint
345+
{
346+
Color = paint.Color,
347+
StrokeWidth = (float)UnderlineWidth,
348+
IsStroke = true,
349+
IsAntialias = paint.IsAntialias
350+
};
351+
352+
canvas.DrawLine(xPx, underlineY, xPx + shapedWidth, underlineY, underlinePaint);
353+
}
354+
}
333355
}
334356
else
357+
{
335358
canvas.DrawText(lines[i], xPx, yPx, paint);
359+
360+
if (RenderUnderline)
361+
{
362+
float underlineY = yPx + (float)UnderlineOffset;
363+
float textWidth = paint.MeasureText(lines[i]);
364+
365+
using var underlinePaint = new SKPaint
366+
{
367+
Color = paint.Color,
368+
StrokeWidth = (float)UnderlineWidth,
369+
IsStroke = true,
370+
IsAntialias = paint.IsAntialias
371+
};
372+
canvas.DrawLine(xPx, underlineY, xPx + textWidth, underlineY, underlinePaint);
373+
}
374+
}
336375
}
337376
}
338377
else
@@ -342,10 +381,45 @@ private void DrawText(SKCanvas canvas, MeasuredText measured, SKPaint paint, Pix
342381
if (LabelStyle.RTLSupport)
343382
{
344383
using (var shaper = new SKShaper(paint.Typeface))
384+
{
385+
float shapedWidth = shaper.Shape(Text, paint).Width;
345386
canvas.DrawShapedText(shaper, Text, xPx, yPx, paint);
387+
388+
if (RenderUnderline)
389+
{
390+
float underlineY = yPx + (float)UnderlineOffset;
391+
392+
using var underlinePaint = new SKPaint
393+
{
394+
Color = paint.Color,
395+
StrokeWidth = (float)UnderlineWidth,
396+
IsStroke = true,
397+
IsAntialias = paint.IsAntialias
398+
};
399+
400+
canvas.DrawLine(xPx, underlineY, xPx + shapedWidth, underlineY, underlinePaint);
401+
}
402+
}
346403
}
347404
else
405+
{
348406
canvas.DrawText(Text, xPx, yPx, paint);
407+
408+
if (RenderUnderline)
409+
{
410+
float underlineY = yPx + (float)UnderlineOffset;
411+
float textWidth = paint.MeasureText(Text);
412+
413+
using var underlinePaint = new SKPaint
414+
{
415+
Color = paint.Color,
416+
StrokeWidth = (float)UnderlineWidth,
417+
IsStroke = true,
418+
IsAntialias = paint.IsAntialias
419+
};
420+
canvas.DrawLine(xPx, underlineY, xPx + textWidth, underlineY, underlinePaint);
421+
}
422+
}
349423
}
350424
}
351425

src/ScottPlot5/ScottPlot5/Primitives/LabelStyleProperties.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ public abstract class LabelStyleProperties : IHasLabel
2323
public float? LabelLineSpacing { get => LabelStyle.LineSpacing; set => LabelStyle.LineSpacing = value; }
2424
public bool LabelItalic { get => LabelStyle.Italic; set => LabelStyle.Italic = value; }
2525
public bool LabelBold { get => LabelStyle.Bold; set => LabelStyle.Bold = value; }
26-
26+
public bool LabelUnderline { get => LabelStyle.Underline; set => LabelStyle.Underline = value; }
27+
public double LabelUnderlineWidth { get => LabelStyle.UnderlineWidth; set => LabelStyle.UnderlineWidth = value; }
28+
public double LabelUnderlineOffset { get => LabelStyle.UnderlineOffset; set => LabelStyle.UnderlineOffset = value; }
2729
public Color LabelFontColor { get => LabelStyle.ForeColor; set => LabelStyle.ForeColor = value; }
2830
public Color LabelBackgroundColor { get => LabelStyle.BackgroundColor; set => LabelStyle.BackgroundColor = value; }
2931
public float LabelBorderRadius { get => LabelStyle.BorderRadius; set => LabelStyle.BorderRadius = value; }

0 commit comments

Comments
 (0)