Play with node-canvas and build something useful
Tags: typescript, canvas, node, calendar
Published: 2020-01-12 19:33:15

I've always had a passion for design, but in the past I've always created all my work with tools like CorelDraw (it used to be great!), Affinity Designer or even just PowerPoint or Keynote.

Only recently I stumbled upon **generative art**, and it fascinated me directly. For this I started working with `canvas` and had first works generated. I'm far from being satisfied enough, so I haven't posted any (except my Twitter header).

When last year came to an end I wanted to get a new wall calendar. During my search I was totally convinced by the concept of [dot calendars](https://www.dot-on.de/en), but I couldn't find a provider that a) offers different color schemes and b) sets predefined markers. So I decided to build my own Dot Calendar and have it printed by myself.

Again, I wanted to start with a vector graphics program. I added the first circles, started thinking about where to add text, which colors to use and so on. Finally I came to the conclusion that there are too many parameters that I cannot and do not want to define from the beginning. It didn't take long until I had the idea to generate the calendar as the first project with canvas. If I choose a programmatic solution, I can change all possible parameters afterwards and simply let the calendar be generated again.

## Canvas is not the problem, it's math!

For developers the configurability of things is quite natural. And I wanted to leave different configurations open. Not many elements are needed with a Dot Calender: Circles and text. That's it.

So to start, set up a node project and install canvas:

```bash
npm install canvas --save
```

To draw a circle you use `arc`:

```bash
ctx.beginPath();
ctx.strokeStyle = this.properties.dots.dotStrikeColor;
ctx.lineWidth = this.properties.dots.dotLineWidth;
ctx.fillStyle = this.getFillColor(dotFlag);
ctx.arc(x, y, radius, 0, Math.PI * 2, true);
ctx.stroke();
ctx.fill();
ctx.closePath();
```

Adding a text is also very easy with `fillText()`.

The art of this lies in mathematics:

- Number of circles per month
- Radius of the circles depending on the base area
- Basically distances (between circles, between texts, ...)

And there are some more configurations to consider. This is not about higher mathematics either, but the model has to be assembled nevertheless. To determine the `x` and `y` coordinates of the circles I used for example the following formula:

```bash
const x =
     startX +
     (month * textDistance +
       month * columns * (radius * 2 + distanceBetweenCirclesX) +
       column * (radius * 2 + distanceBetweenCirclesX));
const y = startY + day * (radius * 2 + distanceBetweenCirclesY);
```

With the help of configuration files most of the parameters I need can be adjusted. I am quite proud of the results :)

Here you can find examples with different color schemes and different numbers of columns per month:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/cevmo63swv6714iy3xsj.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/hof4gaa5qeocymsab52h.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ixf9iap9s4sjcc3nwexy.png)

The whole project can be found [here](https://github.com/urbanisierung/dot-calendar).

I still have a few ideas in my head that I would like to implement, but for now it has served its purpose. And I built my first useful project with `canvas` ;)