Flutter: how to draw text along an arc

Kirill Bubochkin
Dec 12, 2019 · 4 min read
Image for post
Image for post

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

Image for post
Image for post

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:

Image for post
Image for post

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:

Image for post
Image for post

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:

Image for post
Image for post

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

Image for post
Image for post

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.

Kirill Bubochkin

Written by

Head of Applications @ Mews

MewsDevs

MewsDevs

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

Kirill Bubochkin

Written by

Head of Applications @ Mews

MewsDevs

MewsDevs

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

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

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