Drawing With Robot.js

Drawing With Robot.js

How to manipulate mouse movements with JavaScript
Ferenc AlmasiLast updated 2021 November 11 • Read time 7 min read
Get your weekly dose of webtips
  • twitter
  • facebook
JavaScript

Lately, I’ve been experimenting with RobotJS, the desktop automation library which can be used for manipulating mouse and keyboard inputs. You can use it to automate tedious tasks that require repetitive user input in desktop applications that don’t have an API you can interact with. And what better way to demonstrate its power than to use it for drawing geometries. Namely the following:

the seed of life
The seed of life

Setting up the Project

First, we’re going to need a canvas. To avoid writing a drawing app just to try out RobotJS, I’m going to use Sketch Toy, but anything else should work just fine where you can use your mouse to draw.

Next, we will need to take care of the dependencies. Luckily, only RobotJS will be needed. Run npm i robotjs to get it installed.

Copied to clipboard!
{
    "name": "drawing-robot",
    "version": "1.0.0",
    "scripts": {
        "draw": "node draw.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "robotjs": "0.6.0"
    }
}
package.json

I have also added a draw script, so we can run the file with npm run draw.

Next, we will need to set up some variables. We want to draw into the middle of the canvas and to do that, we will need to get an anchor to the top left corner so we have a reference point.

This can be simply done by moving the cursor there and requesting the mouse position with RobotJS. Add the following two lines to draw.js:

Copied to clipboard!
const robot = require('robotjs');

console.log(robot.getMousePos());
draw.js

Then move your mouse to the top left corner of Sketch Toy and run the file. You’ll get back the x and y coordinates of the mouse. This will be our anchor point.

the location of the anchor point

For me, its 196 for x and 121 for y. Yours will be different based on the resolution of your screen as well as how far you are scrolled down into the browser. We will also need the width and height of the canvas, this can be gathered pretty easily from DevTools:

the width and height of the canvas

Add these values as variables into draw.js. Alongside with them, we can also define the radius for the outer and inner circle as well as the starting positions:

Copied to clipboard! Playground
const outerRadius = 200;
const innerRadius = 100;

const canvas = { width: 960, height: 580 };
const anchor = { x: 196, y: 121 }

const startX = anchor.x + (canvas.width / 2);
const startY = anchor.y + (canvas.height / 2) - (outerRadius / 2);
draw.js

To get the middle, we start from the anchor and get half of the width and height. To start drawing in the middle, we will also need to subtract half of the radius from y.

With everything in place, we can start drawing the first circles.


Drawing the Seed of Life

Since we are going to draw multiple circles (exactly 8), I’ve outsourced the drawing code into a separate function. This will take the radius as an argument and will draw a circle starting at the mouse position:

Copied to clipboard! Playground
const drawCircle = radius => {
    const mousePos = robot.getMousePos();

    for (let i = 0; i <= Math.PI * 2; i += 0.01) {
        // Convert polar coordinates to cartesian
        const x = mousePos.x + (radius * Math.cos(i));
        const y = mousePos.y + (radius * Math.sin(i));
        
        robot.dragMouse(x, y);
    }
};
draw.js

To keep the mouse button pressed down, all we need to do is call robot.dragMouse with the passed x and y positions. In order to call this function 8 times, I’ve created a circles array with the x, y position of the circles as well as their radius:

Copied to clipboard!
const circles = [
    { x: startX, y: startY, radius: outerRadius },
    { x: startX, y: startY, radius: innerRadius }
];
draw.js

Then we can loop through them using a forEach:

Copied to clipboard! Playground
robot.setMouseDelay(2);

circles.forEach(circle => {
    robot.moveMouse(circle.x, circle.y);
    robot.mouseToggle('down');

    drawCircle(circle.radius);

    robot.mouseToggle('up');
});
draw.js

To speed things up, you can use setMouseDelay with the number of milliseconds passed. This means that 2 milliseconds will pass between each mouse event. By default, it is set to 10.

Then for each circle, we can move the mouse into position, and press down the left mouse button using mouseToggle. We also need to release it at the end to avoid drawing unnecessary lines between circles. If we run the function now, we will get the first two circles drawn onto the screen. 🎉

drawing two circles

We need to do this 6 more times. Getting the top and bottom middle circles are going to be relatively easy. We keep the x position and we just have to +/- the radius for the y position:

position for the two new circles

We can extend the circles array with the following two new lines:

Copied to clipboard!
 const circles = [
     { x: startX, y: startY, radius: outerRadius },
     { x: startX, y: startY, radius: innerRadius },
+    { x: startX, y: startY - innerRadius, radius: innerRadius },
+    { x: startX, y: startY + innerRadius, radius: innerRadius }
 ];
draw.diff

The remaining four will be drawn on each intersection of the three circles.

The center points of the remaining circles
Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScriptinfo Remove ads

Getting the Intersection

To get the intersection of two circles, I’ve turned to stackoverflow where I found a neat function for retrieving the intersections. I’ve pulled this function into draw.js and renamed the arguments so it expects two circle object:

Copied to clipboard!
const getIntersection = (circle1, circle2) => { ... }
draw.js

To avoid calling the function more than it’s needed, we need to store the result in a variable. This also means that it’s best to store each circle object in separate variables as well:

Copied to clipboard! Playground
let intersection;

const outerCircle  = { x: startX, y: startY, radius: outerRadius };
const innerCircle  = { x: startX, y: startY, radius: innerRadius };
const topCircle    = { x: startX, y: startY - innerRadius, radius: innerRadius };
const bottomCircle = { x: startX, y: startY + innerRadius, radius: innerRadius };

intersection = getIntersection(innerCircle, topCircle);

const topLeftCircle =  { x: intersection[0], y: intersection[2], radius: innerRadius };
const topRightCircle = { x: intersection[1], y: intersection[2], radius: innerRadius };
draw.js

We start with the four circles we had initially, then we get the intersecting points of the middle and top one. We can use the returned values as our new x and y position. The same needs to be done for the bottom two:

Copied to clipboard!
intersection = getIntersection(innerCircle, bottomCircle);

const bottomLeftCircle =  { x: intersection[0], y: intersection[2], radius: innerRadius };
const bottomRightCircle = { x: intersection[1], y: intersection[2], radius: innerRadius };
draw.js

With every variable in place, we can rewrite our circles array in the following way:

Copied to clipboard! Playground
const circles = [
    outerCircle,
    innerCircle,
    topCircle,
    bottomCircle,
    topLeftCircle,
    topRightCircle,
    bottomLeftCircle,
    bottomRightCircle
];
draw.js

And finally, after running the script one more time, here is the end result:

drawing the seed of life with robotjs

Summary

This pretty much sums up mouse movements in RobotJS. The official documentation is well written, I highly recommend diving into it if you would like to find out more. I have the whole project hosted on GitHub if you would like to tweak around with the final result. You can reach it at the link above.

Now your next task is to extend this example and draw the flower of life. Thank you for reading through, happy drawing!

  • twitter
  • facebook
JavaScript
Did you find this page helpful?
📚 More Webtips
Mentoring

Rocket Launch Your Career

Speed up your learning progress with our mentorship program. Join as a mentee to unlock the full potential of Webtips and get a personalized learning experience by experts to master the following frontend technologies:

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.