refactor: adjust element type definition (#5865)

* refactor: remove Position and Points type

* refactor(elements): adjust elements type define
This commit is contained in:
Aaron 2024-06-14 09:19:43 +08:00 committed by GitHub
parent e91d473ebd
commit e0b4e44358
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 161 additions and 96 deletions

View File

@ -1,5 +1,5 @@
import { Path } from '@antv/g';
import type { IPointerEvent, Points } from '../types';
import type { IPointerEvent, Point } from '../types';
import { pointsToPath } from '../utils/path';
import type { BrushSelectOptions } from './brush-select';
import { BrushSelect, getCursorPoint } from './brush-select';
@ -21,7 +21,7 @@ export interface LassoSelectOptions extends BrushSelectOptions {}
* <en/> Select a group of elements with an irregular polygon.
*/
export class LassoSelect extends BrushSelect {
private points?: Points;
private points?: Point[];
private pathShape?: Path;
/**

View File

@ -4,7 +4,7 @@ import type { BaseShapeStyleProps } from './shapes';
import { BaseShape } from './shapes';
export abstract class BaseElement<T extends BaseShapeStyleProps> extends BaseShape<T> {
public get parsedAttributes() {
protected get parsedAttributes() {
return this.attributes as Required<T>;
}
@ -25,28 +25,4 @@ export abstract class BaseElement<T extends BaseShapeStyleProps> extends BaseSha
return animation;
}
/**
* <zh/>
*
* <en/> Called after the element is created and the entrance animation is completed
* @override
*/
public onCreate() {}
/**
* <zh/>
*
* <en/> Called after the element is updated and the transition animation is completed
* @override
*/
public onUpdate() {}
/**
* <zh/> 退
*
* <en/> Called after the element completes the exit animation and is destroyed
* @override
*/
public onDestroy() {}
}

View File

@ -3,10 +3,11 @@ import { isFunction } from '@antv/util';
import { COMBO_KEY } from '../../constants';
import type {
CollapsedMarkerStyleProps,
Combo,
ID,
NodeLikeData,
Padding,
Position,
Point,
Prefix,
STDSize,
Size,
@ -83,7 +84,10 @@ export interface BaseComboStyleProps
*
* <en/> When customizing a combo, it is recommended to use this class as the base class. In this way, users only need to focus on the logic of drawing keyShape
*/
export abstract class BaseCombo<S extends BaseComboStyleProps = BaseComboStyleProps> extends BaseNode<S> {
export abstract class BaseCombo<S extends BaseComboStyleProps = BaseComboStyleProps>
extends BaseNode<S>
implements Combo
{
public type = 'combo';
static defaultStyleProps: Partial<BaseComboStyleProps> = {
@ -184,7 +188,7 @@ export abstract class BaseCombo<S extends BaseComboStyleProps = BaseComboStylePr
return ancestors.length;
}
public getComboPosition(attributes: Required<S>): Position {
public getComboPosition(attributes: Required<S>): Point {
const { x = 0, y = 0, collapsed, context, childrenData = [] } = attributes;
if (childrenData.length === 0) return [+x, +y, 0];
@ -195,7 +199,7 @@ export abstract class BaseCombo<S extends BaseComboStyleProps = BaseComboStylePr
if (descendants.length > 0) {
// combo 被收起,返回平均中心位置 / combo is collapsed, return the average center position
const totalPosition = descendants.reduce((acc, datum) => add(acc, positionOf(datum)), [0, 0, 0] as Position);
const totalPosition = descendants.reduce((acc, datum) => add(acc, positionOf(datum)), [0, 0, 0] as Point);
return divide(totalPosition, descendants.length);
}
// empty combo

View File

@ -4,6 +4,7 @@ import type { PathArray } from '@antv/util';
import { isFunction, pick } from '@antv/util';
import type {
BaseElementStyleProps,
Edge,
EdgeArrowStyleProps,
EdgeBadgeStyleProps,
EdgeKey,
@ -170,7 +171,7 @@ type ParsedBaseEdgeStyleProps = Required<BaseEdgeStyleProps>;
*
* <en/> Base class of the edge
*/
export abstract class BaseEdge extends BaseElement<BaseEdgeStyleProps> {
export abstract class BaseEdge extends BaseElement<BaseEdgeStyleProps> implements Edge {
public type = 'edge';
static defaultStyleProps: Partial<BaseEdgeStyleProps> = {

View File

@ -5,6 +5,7 @@ import type { NodeData } from '../../spec';
import type {
BaseElementStyleProps,
ID,
Node,
NodeBadgeStyleProps,
NodeLabelStyleProps,
NodePortStyleProps,
@ -185,7 +186,10 @@ export interface BaseNodeStyleProps
*
* <en/> Design document: https://www.yuque.com/antv/g6/gl1iof1xpzg6ed98
*/
export abstract class BaseNode<S extends BaseNodeStyleProps = BaseNodeStyleProps> extends BaseElement<S> {
export abstract class BaseNode<S extends BaseNodeStyleProps = BaseNodeStyleProps>
extends BaseElement<S>
implements Node
{
public type = 'node';
static defaultStyleProps: Partial<BaseNodeStyleProps> = {

View File

@ -201,6 +201,8 @@ export type {
EdgeLabelStyleProps,
Element,
ElementDatum,
ElementHooks,
ElementMethods,
ElementType,
FitViewOptions,
IAnimateEvent,

View File

@ -14,12 +14,11 @@ import type {
PartialEdgeData,
PartialGraphData,
PartialNodeLikeData,
Position,
Point,
State,
} from '../types';
import type { EdgeDirection } from '../types/edge';
import type { ElementType } from '../types/element';
import type { Point } from '../types/point';
import { cloneElementData, mergeElementsData } from '../utils/data';
import { arrayDiff } from '../utils/diff';
import { toG6Data, toGraphlibData } from '../utils/graphlib';
@ -563,25 +562,25 @@ export class DataController {
model.mergeNodeData(id, value);
}
public getElementPosition(id: ID): Position {
public getElementPosition(id: ID): Point {
const datum = this.getElementDataById(id) as NodeLikeData;
return positionOf(datum);
}
public translateNodeBy(id: ID, offset: Position) {
public translateNodeBy(id: ID, offset: Point) {
const curr = this.getElementPosition(id);
const position = add(curr, [...offset, 0].slice(0, 3) as Point);
this.translateNodeTo(id, position);
}
public translateNodeTo(id: ID, position: Position) {
public translateNodeTo(id: ID, position: Point) {
const [x = 0, y = 0, z = 0] = position;
this.preventUpdateNodeLikeHierarchy(() => {
this.updateNodeData([{ id, style: { x, y, z } }]);
});
}
public translateComboBy(id: ID, offset: Position) {
public translateComboBy(id: ID, offset: Point) {
const [dx = 0, dy = 0, dz = 0] = offset;
if ([dx, dy, dz].some(isNaN) || [dx, dy, dz].every((o) => o === 0)) return;
const combo = this.getComboData([id])[0];
@ -608,7 +607,7 @@ export class DataController {
);
}
public translateComboTo(id: ID, position: Position) {
public translateComboTo(id: ID, position: Point) {
if (position.some(isNaN)) return;
const [tx = 0, ty = 0, tz = 0] = position;
const combo = this.getComboData([id])?.[0];

View File

@ -389,7 +389,7 @@ export class ElementController {
{
after: () => {
this.emit(new ElementLifeCycleEvent(GraphEvent.AFTER_ELEMENT_CREATE, elementType, datum), context);
element.onCreate();
element.onCreate?.();
},
},
);
@ -457,7 +457,7 @@ export class ElementController {
if (stage === 'collapse') updateStyle(element, style);
if (exactStage === 'hide') updateStyle(element, { visibility: getCachedStyle(element, 'visibility') });
this.emit(new ElementLifeCycleEvent(GraphEvent.AFTER_ELEMENT_UPDATE, elementType, datum), context);
element.onUpdate();
element.onUpdate?.();
},
},
);
@ -496,7 +496,7 @@ export class ElementController {
after: () => {
this.clearElement(id);
element.destroy();
element.onDestroy();
element.onDestroy?.();
this.emit(new ElementLifeCycleEvent(GraphEvent.AFTER_ELEMENT_DESTROY, elementType, datum), context);
},
},

View File

@ -36,7 +36,6 @@ import type {
PartialGraphData,
PartialNodeLikeData,
Point,
Position,
State,
Vector2,
ViewportAnimationEffectTiming,
@ -1184,7 +1183,7 @@ export class Graph extends EventEmitter {
* @param animation - <zh/> | <en/> whether to enable animation
* @apiCategory element
*/
public async translateElementBy(id: ID, offset: Position, animation?: boolean): Promise<void>;
public async translateElementBy(id: ID, offset: Point, animation?: boolean): Promise<void>;
/**
* <zh/>
*
@ -1193,15 +1192,15 @@ export class Graph extends EventEmitter {
* @param animation - <zh/> | <en/> whether to enable animation
* @apiCategory element
*/
public async translateElementBy(offsets: Record<ID, Position>, animation?: boolean): Promise<void>;
public async translateElementBy(offsets: Record<ID, Point>, animation?: boolean): Promise<void>;
public async translateElementBy(
args1: ID | Record<ID, Position>,
args2?: Position | boolean,
args1: ID | Record<ID, Point>,
args2?: Point | boolean,
args3: boolean = true,
): Promise<void> {
const [config, animation] = isObject(args1)
? [args1, (args2 as boolean) ?? true]
: [{ [args1 as ID]: args2 as Position }, args3];
: [{ [args1 as ID]: args2 as Point }, args3];
Object.entries(config).forEach(([id, offset]) => this.context.model.translateNodeBy(id, offset));
await this.context.element!.draw({ animation })?.finished;
@ -1216,7 +1215,7 @@ export class Graph extends EventEmitter {
* @param animation - <zh/> | <en/> whether to enable animation
* @apiCategory element
*/
public async translateElementTo(id: ID, position: Position, animation?: boolean): Promise<void>;
public async translateElementTo(id: ID, position: Point, animation?: boolean): Promise<void>;
/**
* <zh/>
*
@ -1225,15 +1224,15 @@ export class Graph extends EventEmitter {
* @param animation - <zh/> | <en/> whether to enable animation
* @apiCategory element
*/
public async translateElementTo(positions: Record<ID, Position>, animation?: boolean): Promise<void>;
public async translateElementTo(positions: Record<ID, Point>, animation?: boolean): Promise<void>;
public async translateElementTo(
args1: ID | Record<ID, Position>,
args2?: boolean | Position,
args1: ID | Record<ID, Point>,
args2?: boolean | Point,
args3: boolean = true,
): Promise<void> {
const [config, animation] = isObject(args1)
? [args1, (args2 as boolean) ?? true]
: [{ [args1 as ID]: args2 as Position }, args3];
: [{ [args1 as ID]: args2 as Point }, args3];
Object.entries(config).forEach(([id, position]) => this.context.model.translateNodeTo(id, position));
await this.context.element!.draw({ animation })?.finished;
@ -1247,7 +1246,7 @@ export class Graph extends EventEmitter {
* @returns <zh/> | <en/> element position
* @apiCategory element
*/
public getElementPosition(id: ID): Position {
public getElementPosition(id: ID): Point {
return this.context.model.getElementPosition(id);
}

View File

@ -1,25 +1,120 @@
import type { BaseStyleProps } from '@antv/g';
import type { BaseCombo } from '../elements/combos';
import type { BaseEdge } from '../elements/edges';
import type { BaseNode } from '../elements/nodes';
import type { BaseStyleProps, DisplayObject } from '@antv/g';
import type { RuntimeContext } from '../runtime/types';
import type { ComboOptions, EdgeOptions, NodeOptions } from '../spec';
import type { Point, Port } from '../types';
/**
* <zh/>
*
* <en/> Node type
*/
export interface Node extends DisplayObject, ElementHooks, ElementMethods {
/**
* <zh/>
*
* <en/> Get the ports
*/
getPorts(): Record<string, Port>;
/**
* <zh/>
*
* <en/> Get the center position of the node
*/
getCenter(): Point;
/**
* <zh/>
*
* <en/> Get the intersection point
* @param point - <zh/> | <en/> external position
* @returns <zh/> | <en/> intersection point
* @description
* <zh/>
*
* <en/> Given an external position, return the intersection point of the edge between the current node and the position and the node
*/
getIntersectPoint(point: Point): Point;
}
/**
* <zh/>
*
* <en/> Edge type
*/
export interface Edge extends DisplayObject, ElementHooks, ElementMethods {}
/**
* <zh/>
*
* <en/> Combo type
*/
export interface Combo extends Node {
/**
* <zh/>
*
* <en/> Get the position of the combo
* @param attributes - <zh/> | <en/> combo attributes
*/
getComboPosition(attributes: Record<string, unknown>): Point;
}
export type Element = Node | Edge | Combo;
export type ElementType = 'node' | 'edge' | 'combo';
export type ElementOptions = NodeOptions | EdgeOptions | ComboOptions;
export type Node = BaseNode<any>;
export type Edge = BaseEdge;
export type Combo = BaseCombo<any>;
export type Element = Node | Edge | Combo;
export interface BaseElementStyleProps extends BaseStyleProps {
/**
* @internal
*/
context?: RuntimeContext;
}
/**
* <zh/>
*
* <en/> Element methods
*/
export interface ElementMethods {
/**
* <zh/>
*
* <en/> Get the subgraph in the current element
* @param shapeID - <zh/> ID | <en/> Subgraph ID
* @returns <zh/> | <en/> Subgraph
*/
getShape<T extends DisplayObject = DisplayObject>(shapeID: string): T;
}
/**
* <zh/>
*
* <en/> Element hooks
*/
export interface ElementHooks {
/**
* <zh/>
*
* <en/> Called after the element is created and the entrance animation is completed
* @override
*/
onCreate?: () => void;
/**
* <zh/>
*
* <en/> Called after the element is updated and the transition animation is completed
* @override
*/
onUpdate?: () => void;
/**
* <zh/> 退
*
* <en/> Called after the element completes the exit animation and is destroyed
* @override
*/
onDestroy?: () => void;
}

View File

@ -16,7 +16,6 @@ export type * from './node';
export type * from './padding';
export type * from './placement';
export type * from './point';
export type * from './position';
export type * from './prefix';
export type * from './size';
export type * from './state';

View File

@ -1,2 +1 @@
export type Point = [number, number] | [number, number, number] | Float32Array;
export type Points = Point[];

View File

@ -1,3 +0,0 @@
import type { Point } from './point';
export type Position = Point;

View File

@ -1,17 +1,7 @@
import type { AABB, DisplayObject, TextStyleProps } from '@antv/g';
import { get, isString, set } from '@antv/util';
import { BaseCombo, BaseEdge, BaseNode } from '../elements';
import type {
Combo,
Edge,
Element,
Node,
NodePortStyleProps,
Placement,
Point,
Position,
TriangleDirection,
} from '../types';
import type { Combo, Edge, Element, Node, NodePortStyleProps, Placement, Point, TriangleDirection } from '../types';
import type { NodeLabelStyleProps, Port } from '../types/node';
import { getBBoxHeight, getBBoxWidth } from './bbox';
import { isPoint } from './is';
@ -148,7 +138,7 @@ export function isSimplePort(portStyle: NodePortStyleProps): boolean {
* @param port - <zh/> | <en/> Port
* @returns <zh/> | <en/> Port Position
*/
export function getPortPosition(port: Port): Position {
export function getPortPosition(port: Port): Point {
return isPoint(port) ? port : port.getPosition();
}
@ -212,7 +202,7 @@ export function findPort(node: Node, oppositeNode: Node, portKey?: string, oppos
* @param portKey
* @returns <zh/> | <en/> Connection Point
*/
function findConnectionPoints(node: Node, portKey?: string): Position[] {
function findConnectionPoints(node: Node, portKey?: string): Point[] {
const allPortsMap = getAllPorts(node);
if (portKey) return [getPortPosition(allPortsMap[portKey])];
const oppositePorts = Object.values(allPortsMap);

View File

@ -1,15 +1,15 @@
import type { PathArray, PathCommand } from '@antv/util';
import type { Point, Points } from '../types';
import type { Point } from '../types';
/**
* <zh/> points path
*
* <en/> points transfrom path.
* <en/> points transform path.
* @param points Point[]
* @param isClose boolean
* @returns path string[][]
*/
export function pointsToPath(points: Points, isClose = true): PathArray {
export function pointsToPath(points: Point[], isClose = true): PathArray {
const path = [];
points.forEach((point, index) => {

View File

@ -1,5 +1,5 @@
import type { AABB } from '@antv/g';
import type { Anchor, NodeLikeData, Placement, Points, Position, RelativePlacement } from '../types';
import type { Anchor, NodeLikeData, Placement, Point, RelativePlacement } from '../types';
import { parseAnchor } from './anchor';
import { parsePlacement } from './placement';
@ -10,7 +10,7 @@ import { parsePlacement } from './placement';
* @param datum - <zh/> / combo | <en/> data of node/combo
* @returns - <zh/> | <en/> position
*/
export function positionOf(datum: NodeLikeData): Position {
export function positionOf(datum: NodeLikeData): Point {
const { x = 0, y = 0, z = 0 } = datum.style || {};
return [+x, +y, +z];
}
@ -20,10 +20,10 @@ export function positionOf(datum: NodeLikeData): Position {
*
* <en/> Get position by relative placement
* @param bbox - <zh/> | <en/> element bounding box
* @param placement - <zh/> | <en/> Position relative to element
* @param placement - <zh/> | <en/> Point relative to element
* @returns - <zh/> | <en/> position
*/
export function getXYByRelativePlacement(bbox: AABB, placement: RelativePlacement): Position {
export function getXYByRelativePlacement(bbox: AABB, placement: RelativePlacement): Point {
const [x, y] = placement;
const { min, max } = bbox;
return [min[0] + x * (max[0] - min[0]), min[1] + y * (max[1] - min[1])];
@ -34,10 +34,10 @@ export function getXYByRelativePlacement(bbox: AABB, placement: RelativePlacemen
*
* <en/> Get position by placement
* @param bbox - <zh/> | <en/> element bounding box
* @param placement - <zh/> | <en/> Position relative to element
* @param placement - <zh/> | <en/> Point relative to element
* @returns - <zh/> | <en/> position
*/
export function getXYByPlacement(bbox: AABB, placement: Placement = 'center'): Position {
export function getXYByPlacement(bbox: AABB, placement: Placement = 'center'): Point {
const relativePlacement = parsePlacement(placement);
return getXYByRelativePlacement(bbox, relativePlacement);
}
@ -50,7 +50,7 @@ export function getXYByPlacement(bbox: AABB, placement: Placement = 'center'): P
* @param anchor - <zh/> | <en/> Anchor
* @returns - <zh/> | <en/> position
*/
export function getXYByAnchor(bbox: AABB, anchor: Anchor): Position {
export function getXYByAnchor(bbox: AABB, anchor: Anchor): Point {
const parsedAnchor = parseAnchor(anchor);
return getXYByRelativePlacement(bbox, parsedAnchor as RelativePlacement);
}
@ -62,7 +62,7 @@ export function getXYByAnchor(bbox: AABB, anchor: Anchor): Position {
* @param points Points
* @returns `{ left: number; right: number; top: number; bottom: number }`
*/
export const getPositionByRectPoints = (points: Points) => {
export const getPositionByRectPoints = (points: Point[]) => {
const [p1, p2] = points;
return {
left: Math.min(p1[0], p2[0]),