图元
介绍
VRender有很多图元,但是它们的使用方法都差不多,因为他们都继承自Graphic类,它们都有几乎相同的属性和方法,只 是接受的参数不同。下图所示为图元的继承关系图。

- 首先他们都继承自
Node,所以所有图元都有树的结构。 - 然后他们都继承自
Graphic,所以他们都有图元的基础属性和方法比如x、y、fill等。 Graphic分化出了基本的图元类型比如Text、Rect、Arc等,也有一个特殊的类型Group,Group可以包含其他的图元,Group也可以作为一个图元添加到另一个Group图元中。- 创建实例章节中介绍的
Stage和Layer就继承自Group,同时VRender中的组件类型( 组件是带有逻辑的特殊组合图元)也继承自Group,组件内容可以参考组件章节。 - VRender中基于基础的组件类型实现了各种各样的组件,比如
poptip、axis、label等等。
图元的创建代码如下:
import { Rect, createRect, Text, createText } from '@visactor/vrender'; const rectAttribute = { x: 100, y: 100, width: 100, height: 100, fill: 'red' } const rect1 = new Rect(rectAttribute); const rect2 = createRect(rectAttribute); const textAttribute = { x: 100, y: 100, text: 'hello world', fill:'red' } const text1 = new Text(textAttribute); const text2 = createText(textAttribute); // ...其他图元
树结构(Node)
图元都继承自Node,所以都有树的结构,图元也提供了一些方法用于操作树结构。树结构是基于链表实现的,但提供了forEachChildren方法用于遍历树结构,insertBefore,insertAfter,insertInto,appendChild,removeChild,removeAllChild等方法用于操作树结构。
interface INode extends Releaseable, IEventElement {
_prev?: INode;
_next?: INode;
_uid: number;
id?: number | string;
name?: string;
type?: string;
// 父元素
parent: INode | null;
// 子元素数量(包含自己)
count: number;
// 子元素数量(不包含自己)
childrenCount: number;
// 第一个子元素
firstChild: INode | null;
// 最后一个子元素
lastChild: INode | null;
// 获取所有子元素
getChildren: () => INode[];
// 获取在idx位置的子元素
getChildAt: (idx: number) => INode | null;
// getChildAt语法糖
at: (idx: number) => INode | null;
// 向前插入
insertBefore: (newNode: INode, referenceNode: INode) => INode | null;
// 向后插入
insertAfter: (newNode: INode, referenceNode: INode) => INode | null;
// 插入到idx位置
insertInto: (ele: INode, idx: number) => INode | null;
// 遍历子元素
forEachChildren: (cb: (n: INode, i: number) => void | boolean, reverse?: boolean) => void;
// 遍历子元素,异步
forEachChildrenAsync: (cb: (n: INode, i: number) => Promise<void | boolean> | void | boolean, reverse?: boolean) => Promise<void>;
// 添加到最后一个子元素
appendChild: (node: INode, highPerformance?: boolean) => INode | null;
// appendChild语法糖
add: (node: INode, highPerformance?: boolean) => INode | null;
// 删除自己
delete: () => void;
// 删除子节点
removeChild: (node: INode, highPerformance?: boolean) => INode | null;
// 删除所有子节点
removeAllChild: (deep?: boolean) => void;
// 判断是否是node的子节点
isChildOf: (node: INode) => boolean;
// 判断是否是node的父节点
isParentOf: (node: INode) => boolean;
// 判断是否是node的后代节点
isDescendantsOf: (node: INode) => boolean;
// 判断是否是node的祖先节点
isAncestorsOf: (node: INode) => boolean;
// 触发事件
dispatchEvent: (event: Event) => boolean;
// 返回的是一个布尔值,来表示传入的节点是否为该节点的后代节点。
containNode: (node: INode) => boolean;
// 设置该节点的所有后代节点某个属性
setAllDescendantsProps: (propsName: string, propsValue: any) => any;
// 根据自定义逻辑查找元素,返回单一图形元素
find: (callback: (node: INode, index: number) => boolean, deep: boolean) => INode | null;
// 根据自定义逻辑查找元素,返回匹配的元素集合
findAll: (callback: (node: INode, index: number) => boolean, deep: boolean) => INode[];
// 通过用户设置的 id 查找对应的图形元素
getElementById: (id: string | number) => INode | null;
// getElementById语法糖
findChildById: (id: string | number) => INode | null;
// 通过用户设置的 uid 查找对应的图形元素
findChildByUid: (uid: number) => INode | null;
// 通过用户设置的 name 查找对应的图形元素
getElementsByName: (name: string) => INode[];
// getElementsByName语法糖
findChildrenByName: (name: string) => INode[];
// 通过用户设置的 type 查找对应的图形元素
getElementsByType: (type: string) => INode[];
}
图元结构(Graphic)
通过树结构,我们可以构建一个场景树了,但是我们还需要一些属性来描述图元的一些属性,比如位置、大小、颜色等等,所以Graphic基类来描述图元的一些属性。所有图元同样可以使用
interface IGraphic<T extends Partial<IGraphicAttribute> = Partial<IGraphicAttribute>>
extends INode,
IAnimateTarget {
// 图元类型
type?: GraphicType;
// 图元类型(数字类型)
numberType?: number;
// 绑定到的stage
stage?: IStage;
// 绑定到的layer
layer?: ILayer;
// 影子节点
shadowRoot?: IShadowRoot;
// 是否合法
valid: boolean;
// 是否是容器节点(继承自Group)
isContainer?: boolean;
// 是否是3d模式(是否应用3d视角)
in3dMode?: boolean;
// 属性参数
attribute: Partial<T>;
/** 用于实现morph动画场景,转换成bezier曲线渲染 */
pathProxy?: ICustomPath2D | ((attrs: T) => ICustomPath2D);
// 获取state图形属性的方法
stateProxy?: (stateName: string, targetStates?: string[]) => Partial<T>;
/* 状态相关方法 */
toggleState: (stateName: string, hasAnimation?: boolean) => void;
removeState: (stateName: string, hasAnimation?: boolean) => void;
clearStates: (hasAnimation?: boolean) => void;
useStates: (states: string[], hasAnimation?: boolean) => void;
addState: (stateName: string, keepCurrentStates?: boolean, hasAnimation?: boolean) => void;
hasState: (stateName?: string) => boolean;
getState: (stateName: string) => Partial<T>;
// 属性更新前回调
onBeforeAttributeUpdate?: (
val: any,
attributes: Partial<T>,
key: null | string | string[],
context?: ISetAttributeContext
) => T | undefined;
readonly AABBBounds: IAABBBounds; // 用于获取当前节点的AABB包围盒
readonly OBBBounds: IOBBBounds; // 获取OBB包围盒,旋转防重叠需要用
readonly globalAABBBounds: IAABBBounds; // 全局AABB包围盒
readonly transMatrix: IMatrix; // 变换矩阵,动态计算
readonly globalTransMatrix: IMatrix; // 变换矩阵,动态计算
/**
* 是否包含某个点(点需要是全局坐标系)
*/
containsPoint: (x: number, y: number, mode?: IContainPointMode, picker?: IPickerService) => boolean;
// 设置是2d模式还是3d模式
setMode: (mode: '3d' | '2d') => void;
// 是否合法
isValid: () => boolean;
// 基于当前transform的变换,字面意思,普通用户尽量别用,拿捏不住的~
translate: (x: number, y: number) => this;
translateTo: (x: number, y: number) => this;
scale: (scaleX: number, scaleY: number, scaleCenter?: IPointLike) => this;
scaleTo: (scaleX: number, scaleY: number) => this;
rotate: (angle: number, rotateCenter?: IPointLike) => this;
rotateTo: (angle: number) => this;
skewTo: (b: number, c: number) => this;
// 设置Tag,默认不用调用
addUpdateBoundTag: () => void;
addUpdateShapeAndBoundsTag: () => void;
addUpdateLayoutTag: () => void;
addUpdatePositionTag: () => void;
addUpdateGlobalPositionTag: () => void;
// 供render处理shape缓存tag
shouldUpdateShape: () => boolean;
clearUpdateShapeTag: () => void;
shouldUpdateAABBBounds: () => boolean;
shouldSelfChangeUpdateAABBBounds: () => boolean;
shouldUpdateGlobalMatrix: () => boolean;
// 设置属性
setAttributes: (params: Partial<T>, forceUpdateTag?: boolean, context?: ISetAttributeContext) => void;
// 设置单个属性
setAttribute: (key: string, value: any, forceUpdateTag?: boolean, context?: ISetAttributeContext) => void;
// 添加影子节点
attachShadow: () => IShadowRoot;
// 卸载影子节点
detachShadow: () => void;
// 导出JSON配置
toJson: () => IGraphicJson;
/** 创建pathProxy */
createPathProxy: (path?: string) => void;
/** 将图形转换成CustomPath2D */
toCustomPath?: () => ICustomPath2D;
// 克隆对象
clone: () => IGraphic;
// 停止动画
stopAnimates: (stopChildren?: boolean) => void;
// 获取不用走动画的属性
getNoWorkAnimateAttr: () => Record<string, number>;
// 获取主题
getGraphicTheme: () => T;
}
这里涉及到的配置很多,但我们最常用的主要是
attribute:图元的属性setAttributes:设置属性对象AABBBounds:获取AABB包围盒transMatrix:获取变换矩阵type:图元类型
attribute
图元属性有很多,具体可以参考配置文档,几乎图元的所有配置都在这个对象中。包括位置、颜色、样式等等。接下来我们来详细讲解一下这些通用的配置。其中特殊的配置还需要参考配置文档中具体的图元类型
位置变换配置
首先位置变换配置都是通用的:
type ITransform = {
x: number;
y: number;
z: number;
dx: number;
dy: number;
dz: number;
scrollX: number;
scrollY: number;
scaleX: number;
scaleY: number;
scaleZ: number;
angle: number; // 旋转角度
alpha: number; // x轴的转角
beta: number; // y轴的转角
scaleCenter: [number | string, number | string]; // 缩放中心
anchor: [number | string, number | string]; // 基于AABB的锚点位置,用于简单的定位某些path
anchor3d: [number | string, number | string, number] | [number | string, number | string]; // 3d的锚点位置
postMatrix: IMatrix; // 后处理矩阵,会在最后乘以之前的变换矩阵
}