After reading the first two tutorials, you should be able to create paths and some basic predefined shapes. You should also be able to simplify or flatten your paths as well as draw them on different layers and blend them together.
Even though we have come a long way, there is still one thing missing. Up to this point, there has been no interaction between our canvas and the user. It would be nice if we could give users the ability to interact with various paths or draw something on their own. This tutorial will cover all the basics of user interaction, starting with the tool
variable.
Tool and ToolEvent
There is a global tool
variable that only exists in scripts which contain handler functions to interact with either the mouse or the keyboard. This variable gives you access to properties like minDistance
, which is the minimum distance after which the mouse can again fire the onMouseDrag
event, since it was last fired. Similarly, the property maxDistance
allows you to specify a maximum distance after which the onMouseDrag
event needs to fire again.
Paper.js also has a ToolEvent
object. It is an extension of the event object and the only parameter that is passed to all mouse event handlers. It contains all the relevant information about these mouse events like:
-
type
, which tells you if the event ismouseup
,mousedown
,mousemove
ormousedrag
. -
point
, which gives you the position of the mouse when the event was fired. -
delta
, which gives you the distance between the current and last mouse position when the event was fired. -
count
, which gives you the number of times the mouse event was fired. -
item
, which gives you the item that was present at the location of the mouse event. If the item is part of agroup
orcompound
path then the topmost level ofgroup
orcompound
path is returned. -
lastPoint
, which gives the position of the mouse when the event was last fired. -
downPoint
, which gives you the position of the mouse in project co-ordinates when it was last clicked. -
middlePoint
, which gives you the point in the middle oflastPoint
andpoint
.
You should keep all of these in mind because they will be used frequently in most of your projects.
Mouse Interactions
Paper.js has various handler functions that are called automatically to handle different mouse events. The three mouse handler functions are listed below.
function onMouseDown(event) { // Do something console.log('Mouse pressed!'); } function onMouseDrag(event) { // Do something else console.log('Mouse dragged!'); } function onMouseUp(event) { // Do anything console.log('Mouse released!'); }
Let's create a basic demo based on the onMouseDown
and onMouseUp
handlers. Every time a user presses a mouse button, we will create a new Path
and mark that point as the beginning of our Path
.
Every time the user releases the mouse button, we will add a new point as the end of our Path
. This will create a straight line from the point where the mouse button was pressed to the point where it was released. Here is the code:
var aPath; function onMouseDown(event) { aPath = new Path(); aPath.strokeColor = 'purple'; aPath.strokeWidth = event.point.x/10; aPath.add(event.point); } function onMouseUp(event) { aPath.add(event.point); }
I have also set the strokeColor
to purple and strokeWidth
to one-tenth of the value of x co-ordinate using the event.point
property. If you try to draw some vertical lines in the gray area below, you will notice that all of them have a width directly proportional to their distance from the left side.
Now, let's create some circles using the onMouseDrag
event. Every time a drag event is fired, we will draw a circle with its center at the middle point of the last and current drag point. The radius of the circle will depend directly on the drag speed of the user.
To locate the center of our circle, we can use the middlePoint
property that we discussed in the previous section. To determine the radius of the circle, we can use the delta
property and divide the result by 2. Here is the code that we need:
tool.maxDistance = 50; tool.minDistance = 4; function onMouseDrag(event) { var circle = new Path.Circle({ center: event.middlePoint, radius: event.delta.length / 2 }); circle.fillColor = 'pink'; circle.strokeColor = 'black'; }
If the user were to drag the mouse too quickly or too slowly, the circles would become too big or too small.
This issue can be resolved by using the maxDistance
and minDistance
properties. If the user drags too quickly, the maxDistance
property will fire the drag event every 50 pixels. If the user's dragging speed is too slow, the minDistance
property will not be fired until the minimum distance threshold that we specified has been reached. You can test the code above by dragging your mouse in the gray area below:
Keyboard Interactions
The event
object has three properties that you can use for your interactions with the keyboard. The event.key
property will tell you which key was pressed, and the event.character
property will tell you the character that was generated on key press. To determine whether it was a keyup
or keydown
event, you can use the event.type
property.
Let's use these properties together to create tiny circles and move them around. Take a look at the code below:
var step = 10; var centerPoint = new Point(100, 100); function onKeyDown(event) { var circle = new Path.Circle(centerPoint, 3); circle.fillColor = 'pink'; circle.strokeColor = 'black'; if(event.key == 'a') { centerPoint -= new Point(step,0); } // Code for other keys }
We create a variable step
which will be used to determine the speed at which our circle moves around. The variable centerPoint
stores the location of the center of our circles. The onKeyDown
handler has the code to handle all keydown
events. This event is fired continuously as long as a key is being pressed.
This is the reason that new circles are created continuously. Based on the key pressed, we change the value of centerPoint
to move our newly created circle to a different location. You can see the code in action in the demo below:
Some keys, for instance the Shift key and Option key, don't directly produce a character when pressed. These keys are called modifier keys. The event
object has an event.modifiers
property which you can use to determine the modifier key which was pressed. Consider the code below:
var path; function onMouseDown(event) { path = new Path(); path.strokeColor = 'black'; path.strokeWidth = 2; path.add(event.point); } function onMouseDrag(event) { if(event.modifiers.shift) { path.lastSegment.point = event.point; path.simplify(); } else { path.add(event.point); } }
Whenever a user presses a mouse button, the onMouseDown
handler creates a new Path and adds a point to it. After you start dragging, the onMouseDrag
handler adds a new point to it on every drag event.
If you are dragging the mouse with the Shift key pressed, the handler detects it with the event.modifiers.shift
property. In that case, instead of adding a new point on each drag event, it just sets the co-ordinates of the last segment to the current location of the mouse pointer. It also simplifies the complete path that was drawn. You can drag your mouse in the gray area below to see how the path behaves when the Shift key is pressed.
If the Shift key does not seem to work, that's probably because the canvas does not have focus. In that case, you should first click inside the little white space below the canvas to give it focus.
Final Thoughts
The event handlers that we discussed today cover the most common interactivity scenarios. As is evident from the tutorial, it is not hard to manipulate the items in a canvas based on a user's actions. The best way to learn is by practicing. So I would like to suggest that you create your own demos combining everything that you have learned in the three tutorials up to this point.
If you have any questions regarding this tutorial, please let me know in the comments.
Comments