I'm trying to build a freehand pencil tool in HTML5 Canvas (using Paper.js as the Canvas wrapper).
I'd like to allow the user to draw straight lines (when Shift is pressed down for example) while drawing. This straight line should "snap", ideally, to an 8-directional snapping "radius".
I've tried a very simple solution where I snap the mouse point to a near rounded point. This works somehow fine but it's not exactly a snap-to-angle tool, it's more like a snap to an invisible grid kind-of-tool.
mousedrag: function(event) {
var snapped = {x: snap(event.point.x), y: snap(event.point.y)};
// add "snapped" drag point
path.add(snapped.x, snapped.y);
}
// convert a number to a rounded snap
function snap(x, div) {
return Math.round(x/div)*div;
};
Here's an interactive Sketch of what I'm currently doing (holding Shift snaps to a grid, releasing resumes regular freehand drawing)
Can anyone give me an indication on how to proceed for snapping to an angle instead of a grid?
Although I'm using Canvas/Paper.js, I understand that the solution to the problem is independent of the rendering tech I'm using, so any JS-based solution (either SVG or Canvas, wrapper or without) should give me some good foundations on how to proceed.
I'm having a feeling that the solution might involve Math.atan()
or something along those lines, instead of my solution where I snap to a rounded Math.round
point.
If you juste change one or two lines in your code, you get something which might be close to what you want:
// ...
function onMouseDrag(event) {
// if shift is down we transform the mousepoint
// to a "snapped point", else add the mousepoint as it is.
if(shiftDown)
{
var snapPoint = new Point(snap(event.point.x), snap(event.point.y));
myPath.lastSegment.point = snapPoint;
}
else
{
var snapPoint = event.point;
myPath.add(snapPoint);
}
}
// ...
You can easily modify this to snap the angle instead of the position.
function onMouseDrag(event) {
// if shift is down we transform the mousepoint
// to a "snapped point", else add the mousepoint as it is.
if(shiftDown)
{
var vector = event.point - myPath.lastSegment.previous.point;
vector.angle = Math.round(vector.angle/angleSnap)*angleSnap;
myPath.lastSegment.point = myPath.lastSegment.previous.point + vector;
}
else
{
var snapPoint = event.point;
myPath.add(snapPoint);
}
}