Skip to content

bizweekgraphics/swoopyarrows

Repository files navigation

swoopyarrows.js

Out of the crooked timber of JavaScript, no straight arrow was ever made.
— Immanuel Kant

Finally an open source project to match the scope of our ambition! A family of three path generators for making nice fun arrows. Use it more or less like d3.svg.line; the easiest thing is to just pass an array of two points, like [[0,0],[10,30]]. Each has x and y accessors and a couple other options.

Download, demo, demo source.

The only dependency is d3 v3. But it goes great with d3-jetpack! If you’re trying to annotate a bunch of things, you may also have more luck with Adam Pearce’s swoopyDrag.

Bring your own SVG markers. We typically use this simple arrowhead:

<marker id="arrowhead" viewBox="-10 -10 20 20" refX="0" refY="0" markerWidth="20" markerHeight="20" stroke-width="1" orient="auto"><polyline stroke-linejoin="bevel" points="-6.75,-6.75 0,0 -6.75,6.75"></polyline></marker>

swoopyArrow

Download. Connect points with circular arcs. The classic. Set angle to the angle the arrow should subtend, in radians, between 0 (basically straight) and Math.PI (a semicircle, 180º). It's not currently possible to subtend more than that.

var swoopy = swoopyArrow()
  .angle(Math.PI/4)
  .x(function(d) { return d[0]; })
  .y(function(d) { return d[1]; });

svg.append("path")
  .attr('marker-end', 'url(#arrowhead)')
  .datum([[100,200],[300,400]])
  .attr("d", swoopy);

loopyArrow

Download. Like a coiled telephone cord. Set the radius of the loop with radius; increase steps to add more coils — although it's only proportionate to the number of loops, not equal to, because I am bad at math and lazy.

var loopy = loopyArrow()
  .steps(30)
  .radius(20)
  .x(function(d) { return d[0]; })
  .y(function(d) { return d[1]; });

svg.append("path")
  .attr('marker-end', 'url(#arrowhead)')
  .datum([[400,600],[800,100]])
  .attr("d", loopy);

kookyArrow

Download. Follows a random path between two points. Increase steps to add more kinks; increase deviation to make the kinks deviate more from the path.

var kooky = kookyArrow()
  .steps(5)
  .deviation(100)
  .x(function(d) { return d[0]; })
  .y(function(d) { return d[1]; });

svg.append("path")
  .attr('marker-end', 'url(#arrowhead)')
  .datum([[1000,200],[700,600]])
  .attr("d", kooky);

For an idea of how you might use the x and y accessors — you could set them to get the offsetLeft and offsetTop of DOM elements, so you can just pass an array of two DOM elements and generate an arrow between them:

var swoopBetweenElements = swoopyArrow()
  .angle(Math.PI/4)
  .x(function(d) { return d.offsetLeft; })
  .y(function(d) { return d.offsetTop; });

svg.append("path")
  .attr('marker-end', 'url(#arrowhead)')
  .datum([document.querySelector('h1'), document.querySelector('h2')])
  .attr("d", swoopBetweenElements);

To-do

  • Handle passing in more than two points (go through all three? choose the closest two?)
  • Put together a bunch of Adobe Illustrator-style SVG markers
  • The whole thing should just be a d3-shape custom curve module
  • Add droopy catenaries

Swoopy arrows have been in use since Egyptian hieroglyphics. They belong to no one ↪↺↷⟲⤣⤥⤴⤵⤶⤷⤹⤳⤻⤿⤺
Jennifer Daniel, patron saint

Prior art