Now that we have a canvas and can draw straight lines, let’s find out how to draw other basic shapes, as well as create a “toolbar” for the user so they can pick what kinds of shapes to draw.

Stars, fish, hearts, and buttons not included. Photo by Soraya Irving / Unsplash

The Sample Project

The sample project for this series is over on GitHub, and contains the complete codebase for the finished drawing canvas.

Initializing the Display Components

Before we can build more shape drawers, we first need a way to display the existing drawers in a “toolbar” so the user can select which one they want. We need a lot of pieces to make this work, so let’s get started building them.

The first thing we need is a class that represents each displayed option. We are calling these classes “display components” and we need a base one from which all specific components can inherit. This class will need some properties that allow us to set up things like the CSS classes and icon displayed, as well as set the Drawing Mode.

Here’s the annotated code for this base class, called DisplayComponent:

class DisplayComponent {
    drawingMode: DrawingMode; //Line, Rectangle, Oval, etc.
    target: string; //The selector for the HTML element 
                    //this Component will be rendered in
    hoverText: string; //The tooltip text
    svg: string; //The SVG for the component's icon
    cssClass: string; //CSS class for the FontAwesome 
                      //icon used by this display component
    childName: string; //Selector for the child element; 
                       //only used by text components.
    canvasDrawer: DrawingEditor;

    constructor(mode: DrawingMode, selector: string, parent: DrawingEditor, options: DisplayComponentOptions) {
        this.drawingMode = mode;
        this.target = selector; 
        this.cssClass = options.classNames;
        this.hoverText = options.altText;
        this.svg = options.svg;
        this.childName = options.childName;
        this.canvasDrawer = parent; 
        this.render();
        this.attachEvents();
    }

    //This method replaces the target HTML with the component's HTML.
    //The radio button is included to have Bootstrap use the correct styles.
    render() {
        const html = `<label id="${this.target.replace('#', '')}" class="btn btn-primary text-light " title="${this.hoverText}">
                        <input type="radio" name="options" autocomplete="off">
                        ${this.iconStr()}
                     </label>`;

        $(this.target).replaceWith(html);
    }

    private iconStr(): string {
        if (this.cssClass != null) {
            return `<i class="${this.cssClass}"></i>`;
        }
        else {
            return this.svg;
        }
    }

    //This method attaches the componentSelected event in DrawingEditor
    attachEvents() {
        const data = {
            mode: this.drawingMode,
            container: this.canvasDrawer,
            target: this.target
        };

        //When clicking the <label>, fire this event.
        $(this.target).click(data, function () {
            data.container.drawingMode = data.mode;
            data.container.componentSelected(data.target);
        });
    }

    selectedChanged(componentName: string) { }
}

class DisplayComponentOptions {
    altText: string;
    svg?: string;
    classNames?: string;
    childName?: string;
}

#fabricjs

Drawing with FabricJS and TypeScript Part 3: Basic Shapes
1.35 GEEK