Forum Libraries, Components, and Plugins

Rotate Text in SkiaSharp independent of Canvas (sort of....)

Iain1986Iain1986 Member ✭✭

Hi

I'm wondering if anyone else has done similar to this and could share their approach to achieve this affect before I lose too much time chasing my tail!

I've got a Skia Canvas, Xamarin Native (not Forms) and I'm actually using the excellent SkiaScene plugin to handle gestures. All is working great.

Imagine a diagram in the Skia Canvas that you can pinch zoom, two finger rotation, drag around etc. Simple Nodes and Edges. This is all working fine. I'm scaling the nodes and edges paint too so the lines remain uniform as you zoom in and out. All looks good!

Anyway - I rendering text at midpoints of the lines, but obvious this text can go upside down/any angle as you use two fingers to rotate.

What I'm aiming for is to always have the text centered on the midpoint (working) and have it always render flat left to right (not working).

I know I can rotate the canvas back to 0/identity rotation to ensure text is flat, but then the positions go out of sync due to undoing any rotation/zoom/etc from the gestures.

Any thoughts? Do I have to work out the midpoints in the current canvas Matrix, and then work out where they would be in the Identity matrix setup, reset the canvas to that then draw the text at those locations...so they end up being rotated back to their correct spot (super hard to explain).

Or....is there a way to render a Paint with a custom matrix to be applied to that alone, so I can just apply an extra rotation on top of what's there to the text alone?

Best Answer

  • Iain1986Iain1986 ✭✭
    Accepted Answer

    Solved it.

    In case anyone else wants to do something similar.

    // Grab a copy of the current canvas Matrix for text rendering.
    SKMatrix textMatrix = SKMatrix.MakeIdentity();
    canvas.Concat(ref textMatrix);

    // Rotate this by the amount the canvas has rotated as we're about to reverse that back
    // this will ensure the locations are correct
    SKMatrix rotation = SKMatrix.MakeRotation(angleInRadians);
    SKMatrix.PreConcat(ref textMatrix, rotation);

    // Undo the canvas rotation so text is aligned correctly.
    canvas.RotateRadians(-angleInRadians);

    ...

    // Project the point you want to draw text at onto the Text matrix that contains all the original transforms
    // and draw at that point
    var projected_point = textMatrix.MapPoint(text_x, text_y);
    canvas.DrawText(text, projected_point, _textPaint);

    // Restore canvas back to its previous state before this (original rotation/scale/translation etc)
    canvas.Restore();

Answers

  • Iain1986Iain1986 Member ✭✭

    My thoughts....

    I have a canvas with whatever Matrix has been built from all the Pan, Zoom and Rotations. This is drawing the diagram fine.

    I know the points on the diagram and the edges - I'm drawing them fine...

    If I get the midpoints of all these in terms of their position in the canvas.

    Then reset the rotation back to 0 so the text is flat.

    Then take the previous midpoint from the original Matrix, project that onto the new Matrix with 0 rotation, and draw the text at that position? - not sure if I'm barking up the wrong tree here, or there's a much easier way to do this...

  • Iain1986Iain1986 Member ✭✭
    Accepted Answer

    Solved it.

    In case anyone else wants to do something similar.

    // Grab a copy of the current canvas Matrix for text rendering.
    SKMatrix textMatrix = SKMatrix.MakeIdentity();
    canvas.Concat(ref textMatrix);

    // Rotate this by the amount the canvas has rotated as we're about to reverse that back
    // this will ensure the locations are correct
    SKMatrix rotation = SKMatrix.MakeRotation(angleInRadians);
    SKMatrix.PreConcat(ref textMatrix, rotation);

    // Undo the canvas rotation so text is aligned correctly.
    canvas.RotateRadians(-angleInRadians);

    ...

    // Project the point you want to draw text at onto the Text matrix that contains all the original transforms
    // and draw at that point
    var projected_point = textMatrix.MapPoint(text_x, text_y);
    canvas.DrawText(text, projected_point, _textPaint);

    // Restore canvas back to its previous state before this (original rotation/scale/translation etc)
    canvas.Restore();

Sign In or Register to comment.