Recently, I have been learning knowledge related to visualization. In addition to theoretical knowledge, I also need to learn more about the most commonly used visualization tools in actual business, such as Bizcharts and G2, which Bizcharts depends on. But when it comes to the core layer, I still need to return to G drawing engine. G graphics engine is also the foundation on which G2 and G6 depend, and it also exposes many apis from G engine. Therefore, familiarity with G is very helpful for mastering other visualization libraries.

G Source code interpretation

I learn here is G 3.5-PREPARE version source code, is also the 3.0 version of G first use TS build version, easy to read. The following is the UML diagram of the main classes in the source code I built. You can find that there are many inheritance relationships used in the source code, and the relationships are relatively clear.

Interpretation of core usage

Element Element

The first is Element. As can be seen from the UML diagram above, The Element class is the common parent class of Shape, Canvas, and Group. From here, we can actually conclude that Element in the document is a virtual concept. Shape, Group, and their corresponding subclasses Line, Rect, Canvas, etc., are all elements, and their properties and methods can be called on an instance of the above class.

The Container vessel

The concept of Container is not described in detail in the documentation, but the source code is easy to find that the TS interface of a Container is defined as follows:

export interface IContainer extends IElement {
Copy the code

Obviously, a Container is an Element in essence. However, a Container is an abstract description. There are two types of elements that belong to the Container type

  • The Canvas instance, which is the outermost Canvas Container object built with new Canvas (), belongs to Container

    export interface ICanvas extends IContainer { … }

  • The addGroup () method returns an object of type Group whose Ts interface is defined as follows

    Export interface IGroup extends IElement, IContainer {/** * is an entity group, * @return {Boolean} Is an entity group */ isEntityGroup(): Boolean; }

As you can see, an object of type Group belongs to a Container and is also an Element.

Canvas Canvas

Canvas, the concept is easy to understand, namely the Canvas class in the picture above. In actual development, creating an instance of Canvas class is also the first step for drawing. Meanwhile, the Canvas method will decide whether to use Canvas or SVG for drawing according to the configuration of render property.

export type Renderer = 'canvas' | 'svg';
Copy the code

Each time a separate chart is created, a separate Canvas instance is created

const chart = new Canvas({
  container: 'container',
  width: 600,
  height: 500,
Copy the code

Group Graph grouping

Group is the Group class in the UML diagram above, and as you can see, Group is also of type Element. Then the Ts interface of the Group object is defined as follows:

Export interface IGroup extends IElement, IContainer {/** * is an entity group, * @return {Boolean} Is an entity group */ isEntityGroup(): Boolean; }Copy the code

As you can see, the Group object inherits the type definitions of Elemnt and Container, so the use of Group in the document is straightforward. Let’s just use the attributes and methods of Element and Container.

In addition, we define a method called isEntityGroup, which is simple to implement. This method will return true in SVG mode, since in SVG, an entity label is used to wrap a group, and false in Canvas mode. Because Canvas has no actual concept of grouping graphics.

In G2, the most direct use of groups is when initializing a chart, creating a total of three groups and then superimposing them to form the final chart

{parent: null, canvas, // create 3 group layers for views. backgroundGroup: Canvas. AddGroup ({zIndex:}), // Canvas. AddGroup ({zIndex:}), // Canvas. Group_z_index.mid}), foregroundGroup: Canvas.addGroup ({zIndex: Group_z_index. FORE}), // the container in front of the chart padding, appendPadding, visible, options, limitInPlot, theme, syncViewPadding,});Copy the code

When registerShape is used to register a custom graph in G2, the addGroup method is also used to add a new Group on an existing Container, add the graph to the new Group, and return the new Group for overlay.

// registerShape('point', 'pointer', {draw(CFG, container) {const group = container.addGroup({}); Const center = this.parsePoint({x: 0, y: 0}); AddShape ('line', {attrs: {x1: center.x, y1: center.y, x2: cfg.x, y2: cfg.y, stroke: cfg.color, lineWidth: 5, lineCap: 'round', }, }); Group. AddShape ('circle', {attrs: {x: center.x, y: center.y, r: 9.75, stroke: cfg.color, lineWidth: 4.5, fill: '#fff', }, }); return group; }});Copy the code

Shape graphics

Shape (G) : Shape (G) : Shape (G) : Shape (G) : Shape (G)


group.addShape('circle', { attrs: { x: 300, y: 200, r: 100, fill: '#1890FF', stroke: '#F04864', lineWidth: 4, radius: 8,}});Copy the code