How we implemented SVG Arrows in React: Final touches (3/3)
In the previous part of this series, we played with Bezier curves. We showed how we represent them in SVG, how we calculate Control points, and how we adjust the size of the canvas.
If you want to skip ahead, you can go directly to our code on CodeSandbox or Github.
We’ll now look at a few final touches. The most important one is something that makes an arrow an arrow: The arrowhead.
For the arrowhead, we will use a simple
path component, where a polyline similar to the arrow will be drawn. We do not have to deal with the rotation of the arrow, because in our case, the arrow always points to the right.
It’s important to move the arrow to the correct position so that it is always drawn at the End point coordinate. This coordinate will still need to be adjusted so that the line always ends in the center of the arrow.
Rendering of the circle at the Start point of the arrow is easy:
When we style the arrow a bit, it looks pretty good at first glance:
But there is still at least one case that we have not solved — when the line is straight and the Start point is on the right and the End point is on the left. In such cases, the arrow is misplaced, because the arrowhead of the arrow on the right side crosses the line, and the whole thing looks weird:
However, the line should look right in this case:
This situation occurs when the delta Y (ΔY) is too small, while at the same time
[first point X coordinate] > [last point X coordinate]. Under these conditions, all we need to do is move the Control points a little up or down.
The arrow should behave continuously. This means that if we move the Start point or the End point, the way the arrow is drawn should not change in such a way that the curve of the arrow suddenly skips if we exceed a value.
We need to find a feature that suits us. We have defined that if ΔY <200, we will slowly begin to solve the Y coordinate correction at the Control points. The correction will be highest if ΔY == 0 (a state where the Start point and the End point have the same Y coordinate).
When we then implement this function to correct the Y coordinates at the Control points, we ensure that for delta <200, the Control points move vertically and continuously according to the following function:
At the same time, we need to slightly modify the function for calculating theControl points to take this adjustment into account:
At this point, the arrow is rendering better, although it’s still not perfect:
Initially, we tried to address this situation by dynamically moving the Control points, but we found that we would ideally need to add more Control points (to have more than a cubic Bezier curve). However, this complicates the whole arrow again, so in the end, we decided to solve this situation, according to Occam’s razor, in the simplest way that occurred to us. We made a straight line right next to the arrowhead:
Now everything looks as it should:
You can display the Control points and a bounding box to the curve in a fairly simple way. The curve then looks something like this:
The bounding box is highlighted with a red dotted rectangle
One of the things we dealt with a lot is the interaction of the arrow. Fortunately, the SVG path component easily solves this problem, because functions such as
onClick can be hooked on it. In our case, the line at the arrow is only
1px thick, which makes it an element that is very difficult to hit.
That’s why we’ve added another duplicate SVG
path component, which differs in only two ways — it’s thicker and transparent.
This allows us to create a layer for interactions with a thickness of
10px, which is far easier to hover over than the original
There is still plenty of room for improvement, but it’s far beyond the scope of this series, and for our use case, this solution is just fine.
We tried to cover the whole process of implementing SVG arrows, including the caveats, edge cases, and hacks we used.
We hope we will be able to save you some time during the implementation of your custom arrows. If you have any comments or suggestions for how we can improve, we will be happy to read them all!
The whole implementation of SVG arrows in React is available on CodeSandbox or Github.
Interested in joining our growing team? Well, we’re hiring across the board! Check out our careers page for the latest vacancies.