How to Create an HTML Canvas Editor with Clojure and FabricJS
In this chapter, we will integrate FabricJS with our app and create an HTML canvas-based editor.
Graphics Editor#
Editing graphics on the web requires working with the canvas
element. Fabric is a popular canvas library that we are going to use. We'll create an editor component to show at the /graphics/:graphicId
route.
By the end of this chapter, we'll have an editor with a canvas and options to add elements like shapes and text:

The big idea is to develop the editor
component like a controlled component, for example, an input. This way, we can pass the initial value of the canvas to the editor and add an on-change handler, and keep the editor mostly pure:

Install dependencies#
We'll need the fabric
and file-saver
package to build our editor:
yarn add fabric file-saver
fabric
provides a pragmatic wrapper to HTML5 Canvas and file-saver
helps in downloading files, which will be helpful for exporting our graphics.
Editor component#
Fabric works by hijacking an existing canvas node and elevating it to a fabric.Canvas
object. This enables Fabric's rich API. It lets us add and remove objects like text, SVG, and images. It also lets us serialize and de-serialize the canvas.
We will create an editor component in app.components.editor
.
Set up editor namespace#
Here's the ns
setup. We have imported all the required dependencies for the sake of convenience, but feel free to add more as and when you need them:
(ns app.components.editor
(:require [reagent.core :as r]
["fabric" :refer (fabric)]
["file-saver" :refer (saveAs)]
["@blueprintjs/core" :refer (Colors Button Intent InputGroup)]))
Accessing fabric classes#
fabric
exposes a variety of classes that we'll need to initialize objects. The ES6 syntax for importing with fabric
is:
import {fabric} from "fabric";
const c = new fabric.Canvas(args)
The equivalent CLJS would be:
(ns
[:require "fabric" :refer (fabric)])
(def c (new (aget fabric "Canvas") args))
We also need to ensure that all args
passed to fabric
are native JS objects and not CLJS data structures - ie be prepared to call clj->js
excessively. Data shape is a common source of bugs while dealing with native JS libraries.
Canvas component#
To be able to work with fabric
, we need a canvas
element in the DOM. Once the canvas element exists, we need to initialize the fabric.Canvas
class. We also need to clean up when the canvas is unmounted.
This page is a preview of Tinycanva: Clojure for React Developers