How to Add Arrowheads to One End of a Vector in Figma

How to Add Arrowheads to One End of a Vector in Figma

I came upon a problem the other day. I was working on a graphic showing the increases in the amount of protected land in every country in the world over the last 15 years or so. I wanted to represent each increase with an arrow - 180 arrows in all. I exported my plotted data in an SVG from Flourish, but there was a problem - all the arrows had become simple lines.

Figma does have a setting for arrowheads, but when you apply it the arrowheads go on both ends of a line - which is almost never what you want. I wanted all my lines to have just one arrowhead, on the right hand side.

To accomplish this normally for a single arrow, I would select individual vertices within the arrow and then pick the cap I wanted. But doing this for 180 arrows would have been immensely tedious. I needed a new way.

I appealed for help on Twitter, and a got a handful of replies recommending plugins that use components. But all my attempts failed - the component instances retained the length of the master component.

Then I found Scripter - a plugin created by Rasmus Andersson that lets you interact with the Figma API from within Figma. It's like custom-writing your own miniature plugins. You can grab it from here.

After some trial and error, I was able to use my rudimentary Javascript knowledge to put together a script that did the job. Here it is, in case you're stumbling across this blog post with the exact same problem.

/* This plugin adds arrowheads to vectors */
/* Created by Duncan Geere, Jan 2020 */

for (const selection of figma.currentPage.selection) { 
  const node = selection as VectorNode

  /* make a copy of the original node */
  let copy = JSON.parse(JSON.stringify(node.vectorNetwork))
  /* if it has a strokeCap property, change */
  if ("strokeCap" in copy.vertices[copy.vertices.length-1]) {
    copy.vertices[copy.vertices.length-1].strokeCap = "ARROW_EQUILATERAL"
    copy.vertices[0].strokeCap = "NONE"

  /* assign the copy back to the original */
  node.vectorNetwork = copy

Updated 16 June 2020 - Jordi Dosne recommended some tweaks to the script which I've added here. Thanks Jordi!

Updated 19 August 2020 - Christopher Harris suggested an improvement to get this code to work with vectors that have multiple vertices. Thanks Christopher!

There are a few things to bear in mind with this. First, it only works on nodes with type VECTOR, not those with type LINE. I'm assured it's possible to convert LINEs to VECTORs pretty easily, but I haven't yet figured that out.

Second, you're only going to get a filled arrow. If you want a line arrow, change the strokeCap property to "ARROW_LINES" instead. See here for more details.

Third, it puts the cap on the end of the line. If you want it on the start instead, you'll need to flip around the lines inside the if statement.

With that in mind, run it by hitting the play button in the bottom right of the Scripter window. Et voila - arrowheads on one side only:

Thanks to plugin author Rasmus Andersson for helping me debug this script over Twitter!