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.
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>
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);
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);
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);
- 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