Creating the Custom Image Dropdown

Drawing is an inherently visual endeavor, and due to this Chris felt that we needed an appropriately visual selector for the colors, line styles, and fills. Hence he created something he termed an Image Dropdown, a class which shows you little images instead of text for each selectable object, and can be used for multiple types of selections.

But before we can use it, we have to make it. And we need some basic stuff to start. Basic stuff like a class to represent each option in the Image Dropdown...

class ImageOption {
display: string;
value: any;
text: string;
}

...a class to represent the options we need to select to render the image dropdown itself...

But now we come to the most difficult portion of this implementation: the attachEvents() method.

attachEvents() Method

Whenever an element in the Image Dropdown is clicked, we need to ensure that the next objects which will be drawn in the canvas are drawn with the selected line color, fill color, or style. Plus, the item that has been selected must appear in the "viewable" portion of the display, just like in a standard drop down.

With that in mind, let's see the annotated code for the attachEvents() method.

Most of this code probably doesn't make much sense yet, but I promise it will.

We have now fully written our reusable ImageDropdown class! Time to implement a few instances of it.

Line Color and Fill Color

We can demonstrate how to use our new ImageDropdown class by implementing a way for the user to select the line color and fill color for the lines, shapes, and text they want to draw.

We're making a couple assumptions about this element:

There will only be a certain number of colors available. The user won't pick from a color wheel (though this would be an excellent improvement if you, dear reader, want to make a pull request for it) AND

The same set of colors will be available for lines and fill color.

Let's build a reusable display component that will make use of ImageDropdown and let the users choose colors! Here's the code for our component.

NOTE: In the above code and in many other places throughout this series, you may see constructors that have readonly parameters. In TypeScript, this is the same as instantiating a property for the class that contains that constructor, and so we don't need to define a property. I did not know this before starting this series, and I can see how it's a useful feature to have. See the docs for more info.

Just like our earlier display components, we need to modify the base DrawingEditor class and the Razor Page markup and script to wire up the new ColorChooserComponent. But this time, there's some extra changes that also need to be made.

In DrawingEditor, because it is that class which is aware of the brush currently being used to draw objects, we need to modify that brush whenever a new fill color or line color is selected. This is in addition to adding the new line/fill components to the addComponents() method, like we did for the other ones. Here's the changes to DrawingEditor for both of these:

GIF Time 1!

Now we can finally run the app, and use our new line color and fill color pickers! Here's a GIF that shows these features in action:

But wait, we're not done yet! Now let's see how to change the line styles and width.

Line Styles

Our requirements for this project specified that we needed a way to change the line "style" of the shapes. That is, we needed to allow the user to draw dotted, dashed, or solid lines. So, let's build a component to do this!

In FabricJS, there is a class called BaseBrush, which represents the brush being used at any given time to draw objects. BaseBrush contains two properties we will need to use: strokeLineCap and strokeDashArray.

strokeLineCap sets the line ending of the line being drawn; in our case, we only use the value "round".

strokeDashArray sets the properties of the dashes being drawn as part of a line. This allows us to set the size of the dashes. Our requirements specify that we need both dotted and dashed lines, so we will use strokeDashArray to create each of these.

GIF Time 2!

Guess what? It's GIF time again! Let's see how the new LineTypeComponent looks:

Woohoo! Almost there! There's only one thing left we need to do, and that's to create a component which allows the user to choose the thickness of the line being drawn.

Line Thickness

Given that you, dear reader, have probably seen this pattern many times by this point, I'm going to give you the short version of implementing this component. First, we need the new component class, LineThicknessComponent: