diff --git a/packages/g6/__tests__/demo/static/index.ts b/packages/g6/__tests__/demo/static/index.ts index a19f3112bc8..955561f1138 100644 --- a/packages/g6/__tests__/demo/static/index.ts +++ b/packages/g6/__tests__/demo/static/index.ts @@ -7,6 +7,7 @@ export * from './edge-polyline'; export * from './edge-quadratic'; export * from './layered-canvas'; export * from './node-circle'; +export * from './node-rect'; export * from './node-star'; export * from './shape-badge'; export * from './shape-icon'; diff --git a/packages/g6/__tests__/demo/static/node-rect.ts b/packages/g6/__tests__/demo/static/node-rect.ts new file mode 100644 index 00000000000..0095ccb06ca --- /dev/null +++ b/packages/g6/__tests__/demo/static/node-rect.ts @@ -0,0 +1,73 @@ +import { Rect } from '../../../src/elements/nodes'; +import type { StaticTestCase } from '../types'; + +export const nodeRect: StaticTestCase = async (context) => { + const { canvas } = context; + + const c1 = new Rect({ + style: { + // key + x: 100, + y: 100, + fill: 'green', + size: [80, 80], + }, + }); + + const c2 = new Rect({ + style: { + // key + x: 300, + y: 100, + fill: 'red', + size: [80], + // label + labelText: 'rect node', + labelFontSize: 14, + labelFill: 'pink', + labelPosition: 'bottom', + // badge + badgeOptions: [ + { text: 'A', position: 'right-top', backgroundFill: 'grey', fill: 'white', fontSize: 10, padding: [1, 4] }, + { text: 'Important', position: 'right', backgroundFill: 'blue', fill: 'white', fontSize: 10 }, + { text: 'Notice', position: 'left-bottom', backgroundFill: 'red', fill: 'white', fontSize: 10 }, + ], + // anchor + anchorOptions: [ + { position: [0, 0.5], r: 2, stroke: 'black', lineWidth: 1, zIndex: 2 }, + { position: [1, 0.5], r: 2, stroke: 'yellow', lineWidth: 2, zIndex: 2 }, + { position: [0.5, 0], r: 2, stroke: 'green', lineWidth: 1, zIndex: 2 }, + { position: [0.5, 1], r: 2, stroke: 'grey', lineWidth: 1, zIndex: 2 }, + ], + // icon + iconSrc: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg', + iconWidth: 32, + iconHeight: 32, + // halo + haloOpacity: 0.4, + haloStroke: 'grey', + haloLineWidth: 12, + haloPointerEvents: 'none', + }, + }); + + const c3 = new Rect({ + style: { + // key + x: 100, + y: 300, + fill: 'pink', + size: 80, + // icon + iconText: 'Y', + iconFontSize: 32, + iconFill: 'black', + }, + }); + + await canvas.init(); + + canvas.appendChild(c1); + canvas.appendChild(c2); + canvas.appendChild(c3); +}; diff --git a/packages/g6/__tests__/integration/snapshots/static/node-rect.svg b/packages/g6/__tests__/integration/snapshots/static/node-rect.svg new file mode 100644 index 00000000000..0732e1de881 --- /dev/null +++ b/packages/g6/__tests__/integration/snapshots/static/node-rect.svg @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rect node + + + + + + + + + + + + + + + + + + + A + + + + + + + + + + + + Important + + + + + + + + + + + + Notice + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Y + + + + + + + \ No newline at end of file diff --git a/packages/g6/src/elements/nodes/index.ts b/packages/g6/src/elements/nodes/index.ts index 830584c8496..df3bf02a416 100644 --- a/packages/g6/src/elements/nodes/index.ts +++ b/packages/g6/src/elements/nodes/index.ts @@ -1,7 +1,9 @@ export { BaseNode } from './base-node'; export { Circle } from './circle'; +export { Rect } from './rect'; export { Star } from './star'; export type { BaseNodeStyleProps } from './base-node'; export type { CircleStyleProps } from './circle'; +export type { RectStyleProps } from './rect'; export type { StarStyleProps } from './star'; diff --git a/packages/g6/src/elements/nodes/rect.ts b/packages/g6/src/elements/nodes/rect.ts new file mode 100644 index 00000000000..feded58336b --- /dev/null +++ b/packages/g6/src/elements/nodes/rect.ts @@ -0,0 +1,49 @@ +import { Path as GPath } from '@antv/g'; +import { getRectPath } from '../../utils/element'; +import { subStyleProps } from '../../utils/prefix'; +import { BaseNode } from './base-node'; + +import type { DisplayObjectConfig, PathStyleProps as GPathStyleProps, Group } from '@antv/g'; +import type { BaseNodeStyleProps } from './base-node'; + +type KeyShapeStyleProps = GPathStyleProps & { + size: number[] | number; +}; + +export type RectStyleProps = BaseNodeStyleProps; + +type ParsedRectStyleProps = Required; + +type RectOptions = DisplayObjectConfig; + +/** + * Draw Rect based on BaseNode, override drawKeyShape. + */ +export class Rect extends BaseNode { + constructor(options: RectOptions) { + super(options); + } + + protected getKeyStyle(attributes: ParsedRectStyleProps): KeyShapeStyleProps { + const keyStyle = super.getKeyStyle(attributes); + const { size } = keyStyle; + const d = getRectPath(size); + return { ...keyStyle, d }; + } + + protected getHaloStyle(attributes: ParsedRectStyleProps): KeyShapeStyleProps { + const haloStyle = subStyleProps(this.getGraphicStyle(attributes), 'halo') as Partial; + const keyStyle = this.getKeyStyle(attributes); + + return { + ...keyStyle, + ...haloStyle, + } as KeyShapeStyleProps; + } + + protected drawKeyShape(attributes: ParsedRectStyleProps, container: Group): GPath { + return this.upsert('key', GPath, this.getKeyStyle(attributes), container) as GPath; + } + + connectedCallback() {} +} diff --git a/packages/g6/src/utils/element.ts b/packages/g6/src/utils/element.ts index fe362876e13..91166914dd8 100644 --- a/packages/g6/src/utils/element.ts +++ b/packages/g6/src/utils/element.ts @@ -1,6 +1,6 @@ import type { AABB, TextStyleProps } from '@antv/g'; import type { PathArray } from '@antv/util'; -import { get, isString } from '@antv/util'; +import { get, isArray, isString } from '@antv/util'; import type { Point } from '../types'; import type { AnchorPosition, LabelPosition, RelativePosition, StarAnchorPosition } from '../types/node'; @@ -120,3 +120,20 @@ export function getStarAnchors(outerR: number, innerR: number): Record) { return get(anchors, position.toLocaleLowerCase(), anchors['default']); } + +/** + * Get Rect PathArray. + * @param size - width or height + * @returns The PathArray for G + */ +export function getRectPath(size: number[] | number): PathArray { + const [width = 40, height = width] = (isArray(size) ? size : [size, size]) as [number, number]; + + return [ + ['M', width / 2, -height / 2], + ['L', width / 2, height / 2], + ['L', -width / 2, height / 2], + ['L', -width / 2, -height / 2], + ['Z'], + ]; +}