Hit testing against our axis-aligned rectangles is easy. Is the point left of the left edge? Right of the right edge, above the top, or below the bottom? If you answered yes to any of these questions then it's a miss; otherwise, it's a hit.
Our lines are more difficult. We want to score hits within a certain distance of the line so we need to turn the line into a box. If the line is straight then we test against a polygon (a potentially rotated rectangle). Trickier but not bad. Curved lines? Those are hard.
...but not for us. We're using an HTML canvas here—and the canvas 2D rendering context has a function called "isPointInPath". We can use it to test a point against any Path2D. developer.mozilla.org/en-US/docs/Web…
Here's how we'll do it. Our arrow here is defined as an arc, or a segment of a circle between a two angles. The library will calculate the circle for us, along with the start and end angles.
But we want to create a "curved box". To do this, we need to draw two new arcs: one using circle with a slightly smaller radius, and another with a slightly larger radius. Those give us the inner and outer edges of our curved box.
Now we can just connect the lines (or close the shape) and there we go: we have a path that we can hit test against using isPointInPath.
The code itself looks something like this. Get the pointer position, get the arrow, use the arrow to create the path, and then use our canvas context to test whether the point is in the path.
The browser is doing our work for us for free—and in C++ too! If we weren't using canvas to render, we could still do this work with an off-screen canvas, where we'd use an un-mounted canvas just for this kind of calculation. developer.mozilla.org/en-US/docs/Web…
Arrows! 🏹
• • •
Missing some Tweet in this thread? You can try to
force a refresh
Experiment with adjustable arrows. The whole point of my arrows library was to avoid this kind of thing—and let the algorithm "guess" the best arc for an arrow, based on its distance—but this is useful too. 🏹🧵
For comparison, here's the same arrangements (almost) with the guessing algorithm in action.
The library has always supported two options: "bow" defines the minimum arc and "stretch" adds more arc to short arrows. The first GIF is essentially a UI to set the bow of arrows with no stretch. The second GIF is a set of arrows that all have the same non-zero bow and stretch.
pro level docs for @createwithplay featuring theme-aware embedded videos 👀
This is of course a png / mp4 hamburger, with device frames laid over the video. We can record videos from our device and slap them into a Screenshot component.
I like how responsive it is, even to device height. (There's some liberal use of CSS functions.)
Added a layers list and more design functions (align, stretch, distribute). The layers list is using a virtual list (react window via @brian_d_vaughn) so it can keep up with the high number of nodes, too.
Another little feature I would love to see in more design tools: stretch to fill bounding box. The need doesn't come up too often, but it's tedious to set when it does.
Today I found a ten year old micro-app by @evanwallace with a great arrow-drawing algorithm. I worked through the code and adapted it for perfect-arrows. Really beautiful arrows! Playground here: 2vu07.csb.app
And here's the original source: madebyevan.com/fsm/ . In this app, you can adjust the arc of an arrow by clicking and dragging. I like that! But the goal with perfect is to calculate that automatically, too. Points can also be padded out here.
These arrows are using arc segments rather than quadratic curves, which is how I've been doing things so far. I really this might just be the better way. Intersection points are much easier with circles, though I imagine the algorithm will hold up with other shapes too.
Pinch zooming to the pointer on an infinite canvas. We're having to offset the camera as we change the zoom, and that offset amount was... not intuitive.
With this kind of thing, it's useful to think in terms of separate "screen space" and "document space" coordinates. These are usually very different: a pointer at x=100 y=100 on the screen could be anywhere in the document, depending on how the document is scrolled or zoomed.
The goal here is to *preserve* that document coordinate as the user zooms in or out. So as we zoom, we need to scoot the document over so that the user's pointer is still pointing at the same place in the document.
It's Friday! Let's get wild 🙆♂️ and learn about finding intersections between line segments and boxes with rounded corners.
This is a lot like finding the points where a line segment intersects a rectangle—it's just that the rectangle has rounded corners, or a "corner radius".
Let's start with a regular rectangle. To find its intersections, we test each of its sides—or "segments"—separately. There are lots of ways to do that. Here's one: gist.github.com/steveruizok/9f…