g6/packages/site/docs/manual/customize/edgeExtension.en.md
Aaron e08c299a69
docs: update v5 site docs (#5162)
* docs: remove readme and navigation in site

* docs: remove v4 core concept docs

* docs: update history and lod plugin docs

* chore: update dumirc config

* docs: add api shape overview doc

* docs: update manual docs

* docs: update manual and tutorial docs

* chore: update dumirc

* docs: remove design sector

* docs: update docs meta data

* docs: update api docs
2023-11-20 09:50:36 +08:00

8.5 KiB

title order
Custom Edge 2

Example

import { Graph as BaseGraph, extend, Extensions } from '@antv/g6';

// Custom edge type, inherit an existing edge type or edge base class Extensions.BaseEdge
class CustomNode extends Extensions.LineEdge {
  // Override methods, see the following section for methods that can be overridden
}

const Graph = extend(BaseGraph, {
  // Register custom edge
  edges: {
    'custom-edge': CustomEdge,
  },
});

const graph = new Graph({
  // ... Other configurations
  edge: {
    type: 'custom-edge', // Use the registered edge
  },
});

Override methods

draw

:::info In most cases, there is no need to override the draw method. It is more common to override methods such as drawKeyShape and drawLabelShape, which will be introduced in the following section. :::

G5 5.0 removes the update and afterUpdate methods. Now you only need to override the draw method and the afterDraw method, and G6 will automatically update the shapes incrementally based on the updated attributes.

The draw method draws each part of the edge by calling methods such as this.drawKeyShape.

Refer to the draw method of the line-edge type edge for overriding.

afterDraw

The logic executed after the draw function is completed can also be used to draw more shapes. The return value is the same as the draw method. It is not implemented in the built-in edge types.

drawKeyShape

Draw the main shape (keyShape), which is required. For example, the main shape of a line edge is a straight line (line) and the head and tail arrows (arrow), and the main shape of a curved edge replaces the straight line with a curved path (path).

The following example overrides the drawKeyShape method to draw a straight edge:

public drawKeyShape(
  model: EdgeDisplayModel,
  sourcePoint: Point,
  targetPoint: Point,
  shapeMap: EdgeShapeMap,
) {
  const { keyShape: keyShapeStyle } = this.mergedStyles;
  const { startArrow, endArrow, ...others } = keyShapeStyle;
  const lineStyle = {
    ...others,
    x1: sourcePoint.x,
    y1: sourcePoint.y,
    z1: sourcePoint.z || 0,
    x2: targetPoint.x,
    y2: targetPoint.y,
    z2: targetPoint.z || 0,
    isBillboard: true,
  };
  // upsert arrow
  this.upsertArrow('start', startArrow, others, model, lineStyle);
  this.upsertArrow('end', endArrow, others, model, lineStyle);
  // upsert and return shape
  return this.upsertShape('line', 'keyShape', lineStyle, shapeMap, model);
}

If you want to draw a curve or polyline, you should calculate the path based on the control points in drawKeyShape. For example, the drawKeyShape method of the built-in quadratic-edge:

public drawKeyShape(
  model: EdgeDisplayModel,
  sourcePoint: Point,
  targetPoint: Point,
  shapeMap: EdgeShapeMap,
) {
  const { keyShape: keyShapeStyle } = this.mergedStyles as any;
  const { startArrow, endArrow, ...others } = keyShapeStyle;

  // Calculate control points based on arc position, arc, etc.
  const controlPoint = this.getControlPoints(
    sourcePoint,
    targetPoint,
    keyShapeStyle.curvePosition,
    keyShapeStyle.controlPoints,
    keyShapeStyle.curveOffset,
  )[0];
  const lineStyle = {
    ...others,
    path: [
      ['M', sourcePoint.x, sourcePoint.y],
      ['Q', controlPoint.x, controlPoint.y, targetPoint.x, targetPoint.y],
    ],
  };
  // upsert arrow
  this.upsertArrow('start', startArrow, others, model, lineStyle);
  this.upsertArrow('end', endArrow, others, model, lineStyle);
  // upsert and return shape
  return this.upsertShape('path', 'keyShape', lineStyle, shapeMap, model);
}

The this.getControlPoints can be overridden to customize the control point calculation logic, see getControlPoints.

drawHaloShape

Draw the main shape outline (haloShape), which is usually displayed in the selected and active states.

Refer to BaseEdge.drawHaloShape for overriding.

drawLabelShape

Draw the text shape (labelShape)

Refer to BaseEdge.drawLabelShape for overriding.

drawLabelBackgroundShape

Draw the background shape of the text shape (labelBackgroundShape)

Refer to BaseEdge.drawLabelBackgroundShape for overriding.

drawOtherShapes

Draw shapes other than the above parts, which can be completed in drawOtherShapes, such as drawing an extra circle:

public drawOtherShapes(
  model: EdgeDisplayModel,
  shapeMap: EdgeShapeMap,
) {
  return {
    extraShape: upsertShape(
      'circle',
      'other-circle-shape',
      {
        r: 4,
        fill: '#0f0',
        x: -20,
        y: 0,
      },
      shapeMap,
    ),
  };
}

Member properties and methods

BaseEdge and its subclasses provide some member properties and methods that can be used when customizing edges.

getControlPoints

Get the control points, usually used to calculate the path. For example, the control points of the polyline edge are the turning points, and the control points of the curved edge are the control points of the curve.

When inheriting Extensions.PolylineEdge, Extensions.QuadraticEdge, Extensions.CubicEdge, Extensions.CubicHorizontalEdge, Extensions.CubicVerticalEdge, you can override getControlPoints to modify the logic of the control points.

The getControlPoints type of Extensions.PolylineEdge is:

(
  /** Edge rendering data */
  model: EdgeDisplayModel,
  /** Edge start point */
  sourcePoint: Point,
  /** Edge end point */
  targetPoint: Point,
) =>
/** Calculated control points */
{
  x: number;
  y: number;
  z?: number;
}[]

The getControlPoints type of Extensions.QuadraticEdgeExtensions.CubicEdgeExtensions.CubicHorizontalEdgeExtensions.CubicVerticalEdge is:

(
  /** Edge start point */
  startPoint: Point,
  /** Edge end point */
  endPoint: Point,
  /** Percentage of the projection of the control point on the line connecting the two end points, ranging from 0 to 1 */
  percent: number,
  /** Control point configuration in data */
  controlPoints: Point[],
  /** Arc distance */
  offset: number,
) =>
/** Calculated control points */
{
  x: number;
  y: number;
  z?: number;
}[];

getPath

The member method of Extensions.PolylineEdge can only be overridden when inheriting it to implement a custom edge. Because the automatic path-finding algorithm of the polyline is more complicated, this function is extracted separately. Also because of the complexity of the algorithm, the performance of the polyline edge is slightly worse. If there is a certain rule for drawing the polyline edge, you can inherit the built-in polyline edge and customize the getPath method to override the automatic path-finding logic. The function type is:

(
  /** Edge rendering data */
  model: EdgeDisplayModel,
  /** Edge start point */
  points: Point[],
  /** Radius of the polyline turning point */
  radius: number,
  /** Edge end point */
  routeCfg?: RouterCfg,
  /** Whether to use the A* algorithm */
  auto?: boolean,
) =>
  /** Path */
  string;
RouterCfg
type RouterCfg = {
  name: 'orth' | 'er';
  /** Spacing between lines and points */
  offset?: number;
  /** Grid size */
  gridSize?: number;
  /** Maximum allowable rotation angle (radian) */
  maxAllowedDirectionChange?: number;
  /** Allowed edge directions */
  directions?: any[];
  /** Penalties */
  penalties?: {};
  /** Determine if use simple router for polyline when no obstacles */
  simple?: boolean;
  /** Function to calculate the distance between two points */
  distFunc?: (p1: PolyPoint, p2: PolyPoint) => number;
  /** Simplified function to find path */
  fallbackRoute?: (p1: PolyPoint, p2: PolyPoint, startNode?: Node, endNode?: Node, cfg?: RouterCfg) => PolyPoint[];
  /** Maximum loops */
  maximumLoops?: number;
  /**
   * Whether to automatically avoid other nodes (obstacles) on the path
   * Defaults to false.
   */
  enableObstacleAvoidance?: boolean;
};