MewsDevs
Published in

MewsDevs

Flutter: how to draw text along an arc

For one of our side projects (highly experimental and written in Flutter for Web, by the way) I needed to implement something like this:

The code is actually the same for mobile and web, so, for the sake of simplicity (and because they look nicer), I’ll share screenshots from the mobile app.

The problem is that Flutter doesn’t support drawing text along a custom path (and it doesn’t look like it will, at least not in the near future). So I decided to implement the functionality on my own. Drawing text along any custom path would be quite complex, but luckily I only had to implement text along an arc. I’d like to share with you one way to do that.

For this implementation, your first geometry course should be more than enough (though, shame on me, I’ve realised that I’ve forgot almost all of mine). It won’t be the best possible implementation, but for our use case it will be good enough.

Let’s start with defining the interface of our widget (let it be ArcText):

startAngle is the initial angle where the text will start, and radius is the arc's radius - the text will be drawn along its side. We can use it like this:

For the text rendering we’ll be using CustomPainter. This is where the magic happens:

Before starting to implement the _Painter class let's think about how it will work:

The idea here is that we will draw each letter on top of a chord. The radius of the circle the cord belongs to is our defined radius. d - the chord's length - equals the letter's width. That means that after drawing each letter we can rotate the canvas to a specified angle and move it to a distance d along the x axis. It's easier to transform the canvas than to calculate new coordinates.

Let’s start implementing the _Painter class:

For rendering we will need: the radius, the text itself, the text style (so that we can get a width of each letter) and the initial angle. The shouldRepaint method defines whether the paint method needs to be called and, in the simplest case (when we don't have any complex calculations there), it can always return true.

Now we can continue implementing paint:

In this code snippet we’re moving the canvas so that circle radius is in the center of a container, drawing the circle (it’s just a helper, we’ll remove it later), and moving the canvas again to a -radius along the y axis - later it will be easy to move and rotate it. We should get the following picture:

Let’s add text rendering:

As I said, the idea is rather simple: with each letter drawn we’re rotating the canvas to a calculated angle, so that the chord of the current letter is parallel to the x axis; then we draw the letter and move the canvas along the x axis to a distance equal to the letter width.

We can use our knowledge of geometry to find a chord’s angle and the new angle to rotate the canvas.

A chord’s length can be found from the following equation:

d = 2r * sin(⍺ / 2)

So it can be transformed like this to find the chord’s central angle:

⍺ = 2 * arcsin(d / 2r)

The angle to rotate the canvas can be found with this simple formula:

𝛥 = (⍺ + β) / 2

is the central angle of the previous chord, β is the central angle of the current chord.

Now it looks like this:

Now we can remove the helper circle and take the initial angle into account:

That’s all! Here’s the final source code:

By the way, it’s also available as a Flutter package here.

Originally published at https://developers.mews.com on December 12, 2019.

--

--

--

Insights and opinions on engineering in general, React, Flutter, functional programming, engineering leadership, and much more. Follow to join our community.

Recommended from Medium

Jenkins Pipeline — triggerRemoteJob fails in script only

HUFFMAN ENCODING

What is Big O notation? And why we need it?

How to Effectively Manage Problems in Your Support Center

How to Effectively Manage Problems in Your Support Center

CSS Overview — New Experimental Feature in Google Chrome

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Kirill Bubochkin

Kirill Bubochkin

Head of Applications @ Mews

More from Medium

Why No One Can Get Flutter State, Lack Of Architecture

Dart Functors, Applicatives, And Monads In Pictures

How to setup dart-define for keys and secrets on Android and iOS in Flutter apps

How to debug code dependencies on VS code

Searching a bug