Skip to content

Commit 598ba6b

Browse files
committed
Add support for multi-line text to SkiaRenderContext (#1538)
1 parent 68f7dbb commit 598ba6b

File tree

5 files changed

+73
-26
lines changed

5 files changed

+73
-26
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ All notable changes to this project will be documented in this file.
2626
- WindowsForms ExampleBrowser can display transposed versions of examples (#1535)
2727
- Example for Issue #1545 showing the use of different line endings
2828
- Support for unix line endings in OxyPlot.ImageSharp, OxyPlot.Svg, and OxyPlot.Pdf (#1545)
29+
- Multi-Line Text support to SkiaRenderContext (#1538)
2930

3031
### Changed
3132
- Legends model (#644)

Source/Examples/ExampleLibrary/Examples/RenderingCapabilities.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,32 @@ public static PlotModel DrawTextAlignmentRotation()
262262
return model;
263263
}
264264

265+
/// <summary>
266+
/// Shows multi-line alignment capabilities for the DrawText method.
267+
/// </summary>
268+
/// <returns>A plot model.</returns>
269+
[Example("DrawText - Multi-line Alignment/Rotation")]
270+
public static PlotModel DrawMultilineTextAlignmentRotation()
271+
{
272+
var model = new PlotModel();
273+
model.Annotations.Add(new DelegateAnnotation(rc =>
274+
{
275+
for (var ha = HorizontalAlignment.Left; ha <= HorizontalAlignment.Right; ha++)
276+
{
277+
for (var va = VerticalAlignment.Top; va <= VerticalAlignment.Bottom; va++)
278+
{
279+
var origin = new ScreenPoint(((int)ha + 2) * 170, ((int)va + 2) * 170);
280+
rc.FillCircle(origin, 3, OxyColors.Blue, EdgeRenderingMode.Adaptive);
281+
for (var rotation = 0; rotation < 360; rotation += 90)
282+
{
283+
rc.DrawText(origin, $"R{rotation:000}\n{ha}\n{va}", OxyColors.Black, fontSize: 20d, rotation: rotation, horizontalAlignment: ha, verticalAlignment: va);
284+
}
285+
}
286+
}
287+
}));
288+
return model;
289+
}
290+
265291
/// <summary>
266292
/// Shows color capabilities for the DrawText method.
267293
/// </summary>

Source/OxyPlot.SkiaSharp.Tests/OxyPlot.SkiaSharp.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<Copyright>OxyPlot contributors</Copyright>
88
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
99
<Platforms>AnyCPU;x86;x64</Platforms>
10+
<LangVersion>8</LangVersion>
1011
</PropertyGroup>
1112
<PropertyGroup Condition="'$(TargetFramework)|$(Platform)'=='net461|AnyCPU'">
1213
<PlatformTarget>x86</PlatformTarget>

Source/OxyPlot.SkiaSharp.Tests/SvgExporterTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace OxyPlot.SkiaSharp.Tests
88
{
9+
using ExampleLibrary;
910
using NUnit.Framework;
1011
using OxyPlot.SkiaSharp;
1112
using System.IO;
@@ -24,6 +25,15 @@ public void Export_SomeExamplesInExampleLibrary_CheckThatAllFilesExist()
2425
ExportTest.Export_FirstExampleOfEachExampleGroup_CheckThatAllFilesExist(exporter, directory, ".svg");
2526
}
2627

28+
[Test]
29+
public void TestMultilineAlignment()
30+
{
31+
var exporter = new SvgExporter { Width = 1000, Height = 750 };
32+
var model = RenderingCapabilities.DrawMultilineTextAlignmentRotation();
33+
using var stream = File.Create(Path.Combine(this.outputDirectory, "Multiline-Alignment.svg"));
34+
exporter.Export(model, stream);
35+
}
36+
2737
[OneTimeSetUp]
2838
public void Setup()
2939
{

Source/OxyPlot.SkiaSharp/SkiaRenderContext.cs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -354,44 +354,51 @@ public void DrawText(
354354
var x = this.Convert(p.X);
355355
var y = this.Convert(p.Y);
356356

357-
var metrics = paint.FontMetrics;
357+
var lines = StringHelper.SplitLines(text);
358+
var lineHeight = paint.GetFontMetrics(out var metrics);
359+
358360
var deltaY = verticalAlignment switch
359361
{
360362
VerticalAlignment.Top => -metrics.Ascent,
361-
VerticalAlignment.Middle => -(metrics.Ascent + metrics.Descent) / 2,
362-
VerticalAlignment.Bottom => -metrics.Descent,
363+
VerticalAlignment.Middle => -(metrics.Ascent + metrics.Descent + lineHeight * (lines.Length - 1)) / 2,
364+
VerticalAlignment.Bottom => -metrics.Descent - lineHeight * (lines.Length - 1),
363365
_ => throw new ArgumentOutOfRangeException(nameof(verticalAlignment))
364366
};
365367

366368
using var _ = new SKAutoCanvasRestore(this.SkCanvas);
367369
this.SkCanvas.Translate(x, y);
368370
this.SkCanvas.RotateDegrees((float)rotation);
369371

370-
if (this.UseTextShaping)
372+
foreach (var line in lines)
371373
{
372-
var width = this.MeasureText(text, shaper, paint);
373-
var deltaX = horizontalAlignment switch
374+
if (this.UseTextShaping)
374375
{
375-
HorizontalAlignment.Left => 0,
376-
HorizontalAlignment.Center => -width / 2,
377-
HorizontalAlignment.Right => -width,
378-
_ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
379-
};
380-
381-
this.paint.TextAlign = SKTextAlign.Left;
382-
this.SkCanvas.DrawShapedText(shaper, text, deltaX, deltaY, paint);
383-
}
384-
else
385-
{
386-
paint.TextAlign = horizontalAlignment switch
376+
var width = this.MeasureText(line, shaper, paint);
377+
var deltaX = horizontalAlignment switch
378+
{
379+
HorizontalAlignment.Left => 0,
380+
HorizontalAlignment.Center => -width / 2,
381+
HorizontalAlignment.Right => -width,
382+
_ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
383+
};
384+
385+
this.paint.TextAlign = SKTextAlign.Left;
386+
this.SkCanvas.DrawShapedText(shaper, line, deltaX, deltaY, paint);
387+
}
388+
else
387389
{
388-
HorizontalAlignment.Left => SKTextAlign.Left,
389-
HorizontalAlignment.Center => SKTextAlign.Center,
390-
HorizontalAlignment.Right => SKTextAlign.Right,
391-
_ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
392-
};
390+
paint.TextAlign = horizontalAlignment switch
391+
{
392+
HorizontalAlignment.Left => SKTextAlign.Left,
393+
HorizontalAlignment.Center => SKTextAlign.Center,
394+
HorizontalAlignment.Right => SKTextAlign.Right,
395+
_ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment))
396+
};
393397

394-
this.SkCanvas.DrawText(text, 0, deltaY, paint);
398+
this.SkCanvas.DrawText(line, 0, deltaY, paint);
399+
}
400+
401+
deltaY += lineHeight;
395402
}
396403
}
397404

@@ -403,9 +410,11 @@ public OxySize MeasureText(string text, string fontFamily = null, double fontSiz
403410
return new OxySize(0, 0);
404411
}
405412

413+
var lines = StringHelper.SplitLines(text);
406414
var paint = this.GetTextPaint(fontFamily, fontSize, fontWeight, out var shaper);
407-
var width = this.MeasureText(text, shaper, paint);
408-
var height = paint.GetFontMetrics(out _);
415+
var height = paint.GetFontMetrics(out _) * lines.Length;
416+
var width = lines.Max(line => this.MeasureText(line, shaper, paint));
417+
409418
return new OxySize(this.ConvertBack(width), this.ConvertBack(height));
410419
}
411420

0 commit comments

Comments
 (0)