This is the seventh day of my participation in the First Challenge 2022

I am the front-end watermelon brother, today teach you how to develop a graphics editor.

Although it is a graphic editor, it is also classified as an editor, and the idea of developing a text editor is in many places common. If you do text editor development, you can also check it out.

An editor is a complex project composed of multiple functional modules. Module decoupling is very important for extensible and maintainable editor code.

The biggest work in editor development is in interaction, basically around left mouse button events, with keyboard shortcuts.

Computational graphics is involved, but it’s mostly simple, like determining whether two rectangles intersect. Advanced computer graphics knowledge involves less, mainly advanced functions will be used, usually I will find a third-party library to achieve.

So, it’s possible to develop a graphic editor without much knowledge, but it takes time.

Let’s start with a few important modules of the editor.

Coordinate module

When it comes to graphical interfaces, coordinates are a must.

The canvas can be scaled and dragged, and the coordinates on the real screen are not the coordinates on the editor canvas, so a layer of transformation is required.

An editor may also have multiple coordinate systems.

The canvas module

Drag and drop of the canvas, and zoom.

Drag and drop, you can modify the top left corner of the canvas coordinates, or use transform Translate.

As for scaling, there’s a lot to consider:

  • When zooming with the mouse, consider the position of the cursor as the zoom center for zooming.

  • Consider how small you can shrink and how large you can zoom in.

  • Whether to center the canvas when it is smaller than the container.

  • Whether the scaling process is to set a fixed scale, or to let the user scale at will with decimal numbers.

  • One click zoom ratio of 100% or adaptive window logic.

History module

An editor without undo redo, no matter how powerful, is a work in progress.

History is usually implemented as a design-mode command pattern, which abstracts operations into command classes. Command instances created during operations are maintained in undo and redo stacks.

When writing interactive logic, be careful not to generate multiple commands for procedural operations.

For example, do not generate multiple move commands to place in the history of the movement element before the mouse release, otherwise undo unfriendly.

For text editors, don’t generate an action command every time you type a word. Instead, set a time for how long it took for the command to be generated and placed in history without input.

Tool module

The unique functionality of the editor is embodied in the tools module, and the other modules are the infrastructure.

What are the tools modules? The most basic are:

  • Select the Move Tool. The selection tools can be complicated: select directly, select, shift more or less, select already selected elements (move)
  • Drawing tool. Rectangles, circles, Bezier curves, etc.
  • Drag the Canvas tool. Because it’s a high frequency operation. In addition, some editors support right – and – drag, or space bar and left – mouse drag.

There are many tool classes, so how do you manage them?

We need a toolManager class that implements the same things as the Vue Router and React Router, except that instead of changing the route, we switch tools by clicking the tool button and invoking the API. When switching, the corresponding registered tool module will be mounted.

Each tool module, like the React component, needs to support mounting, destroying, and so on.

Some temporary shortcut event methods need to be registered at mount time, and event method destruction is done at destroy time.

Of course, this is a more interactive editor, so we need to implement mouseDown, mouseover and other interfaces.

The tool class should pay attention to the extensibility, it is best to make the form of plug-in, so that others can customize their own development of the tool class.

The layer module

When something becomes complex, it becomes important to manage it, and grouping is one solution.

So many editors support layers. Of course, if the editor is simple enough, it can not support.

What about layers? It’s like sheets of transparent paper stacked together, and we look down from the top. Then we drew on separate pieces of paper, with the opaque content at the top blocking out the same area below. We can also hide or move any of these layers to create the “picture” we want.

If we don’t have layers and all of our content is on one piece of paper, we lose a lot of possibilities, and basically you can’t tweak it, you have to redraw it.

The layer module needs to support basic functions:

  • Show hidden
  • Locked (unable to operate. Of course, there are also advanced immobile, transparent pixel lock, can be considered)
  • Select (go to layer)
  • rename
  • delete

There are also some higher-level and higher-frequency functions: merge down and create layer masks.

Other modules

  • Shortcuts. There are global shortcut keys and local shortcut keys of tools. I seehotkey-jsThis keyboard shortcut library seems pretty good.
  • Ruler module. Fixed ruler on top and left side of canvas, can be aligned.
  • Element relative position auxiliary line display
  • .

Technology selection

Because there are so many modules, some major changes and even major refactorings will be made to support new functionality. So weak-typed JavaScript is better, you have to TypeScript.

For portability, it is recommended that the editor be divided into core, which provides the underlying capabilities, and UI, which provides the interactive capabilities.

This makes it easier to migrate to Vue, React, and other frameworks. For example, VSCode’s core Editor has been removed as the Monaco Editor, which is the default Editor when LeetCode brushes.

So maybe you should consider Monorepo’s multi-project development strategy? But I haven’t tried.

The graphics editor mainly includes:

  • Dom element: SVG or div. Such as DRAwio, Boxy SVG, Baidu brain map.
  • Canvas: Such as various online collaboration forms, Figma

Considering the web page rendering lag caused by too many elements, Canvas can optimize the rendering and support scenes with a large amount of data. You can look at the online tables of various manufacturers, all made of Canvas, because it is the only way to support tens of thousands of rows of tables.

Canvas is the dominant graphics editor, but it can also be cumbersome to develop: it’s hard to debug, and you may need to write your own rendering engine.

Required knowledge

Because editors are complex, the architecture has to be good or it can’t be maintained. To do this, you need to learn design patterns.

In addition, you need to learn some simple computer graphics knowledge, such as graphic collision detection, color filling algorithm and so on. When you run into a problem during development, do the research. Some complex graphics knowledge, may need to find a third party graphics library to help you solve it.

Canvas or SVG API learning, depending on what underlying technology you use.

A demo

By the way, I have a half-finished SVG editor project. Welcome star.

Github.com/F-star/svg-…

It’s in a semi-abandoned state, so let’s see how it works.

At the end

Here are some of my shallow insights into developing an editor that I hope will help you. If you have an editor related question, drop me a comment and I’ll consider it as the subject of my next article.

If you think it is helpful, I hope you can give me a thumbs up, so that I can be motivated to update the editor related articles.