diff --git a/packages/g6/__tests__/demo/case/combo-circle.ts b/packages/g6/__tests__/demo/case/combo.ts similarity index 60% rename from packages/g6/__tests__/demo/case/combo-circle.ts rename to packages/g6/__tests__/demo/case/combo.ts index 5094934bd9d..ef4c2307f8c 100644 --- a/packages/g6/__tests__/demo/case/combo-circle.ts +++ b/packages/g6/__tests__/demo/case/combo.ts @@ -1,10 +1,10 @@ import { Graph } from '@/src'; import type { STDTestCase } from '../types'; -export const comboCircle: STDTestCase = async (context) => { +export const combo: STDTestCase = async (context) => { const data = { nodes: [ - { id: 'node-1', data: {}, style: { parentId: 'combo-2', x: 100, y: 100 } }, + { id: 'node-1', data: {}, style: { parentId: 'combo-2', x: 120, y: 100 } }, { id: 'node-2', data: {}, style: { parentId: 'combo-1', x: 300, y: 200 } }, { id: 'node-3', data: {}, style: { parentId: 'combo-1', x: 200, y: 300 } }, ], @@ -15,7 +15,7 @@ export const comboCircle: STDTestCase = async (context) => { combos: [ { id: 'combo-1', - style: { parentId: 'combo-2' }, + style: { type: 'rect', parentId: 'combo-2' }, }, { id: 'combo-2', @@ -36,8 +36,8 @@ export const comboCircle: STDTestCase = async (context) => { }, combo: { style: { - padding: 0, labelText: (d: any) => d.id, + lineDash: 0, collapsedLineDash: [5, 5], }, }, @@ -45,14 +45,56 @@ export const comboCircle: STDTestCase = async (context) => { await graph.render(); - const COLLAPSED_ORIGIN = ['top', 'bottom', 'left', 'right', 'center']; + const COMBO_TYPE = ['circle', 'rect']; + const COLLAPSED_ORIGIN = [ + 'top', + 'bottom', + 'left', + 'right', + 'center', + 'top-left', + 'top-right', + 'bottom-left', + 'bottom-right', + ]; const COLLAPSED_MARKER_TYPE = ['child-count', 'descendant-count', 'node-count']; - comboCircle.form = (panel) => { + combo.form = (panel) => { const config = { + combo2Type: 'circle', collapsedOrigin: 'top', collapsedMarker: true, collapsedMarkerType: 'child-count', + collapseCombo1: () => { + graph.updateComboData((data) => [ + ...data, + { + id: 'combo-1', + style: { + collapsed: true, + collapsedOrigin: config.collapsedOrigin, + collapsedMarker: config.collapsedMarker, + collapsedMarkerType: config.collapsedMarkerType, + }, + }, + ]); + graph.render(); + }, + expandCombo1: () => { + graph.updateComboData((data) => [ + ...data, + { + id: 'combo-1', + style: { + collapsed: false, + collapsedOrigin: config.collapsedOrigin, + collapsedMarker: config.collapsedMarker, + collapsedMarkerType: config.collapsedMarkerType, + }, + }, + ]); + graph.render(); + }, collapseCombo2: () => { graph.updateComboData((data) => [ ...data, @@ -86,6 +128,15 @@ export const comboCircle: STDTestCase = async (context) => { }; return [ + panel.add(config, 'combo2Type', COMBO_TYPE).onChange((type: string) => { + config.combo2Type = type; + const combo2Data = graph.getComboData('combo-2'); + graph.updateComboData((data) => [ + ...data, + { ...combo2Data, style: { ...combo2Data.style, type: config.combo2Type } }, + ]); + graph.render(); + }), panel.add(config, 'collapsedOrigin', COLLAPSED_ORIGIN).onChange((collapsedOrigin: string) => { config.collapsedOrigin = collapsedOrigin; }), @@ -95,6 +146,8 @@ export const comboCircle: STDTestCase = async (context) => { panel.add(config, 'collapsedMarkerType', COLLAPSED_MARKER_TYPE).onChange((collapsedMarkerType: string) => { config.collapsedMarkerType = collapsedMarkerType; }), + panel.add(config, 'collapseCombo1'), + panel.add(config, 'expandCombo1'), panel.add(config, 'collapseCombo2'), panel.add(config, 'expandCombo2'), ]; diff --git a/packages/g6/__tests__/demo/case/index.ts b/packages/g6/__tests__/demo/case/index.ts index d44c2d5fa4d..a5a51a1bcac 100644 --- a/packages/g6/__tests__/demo/case/index.ts +++ b/packages/g6/__tests__/demo/case/index.ts @@ -1,5 +1,5 @@ export * from './behavior-drag-canvas'; export * from './behavior-zoom-canvas'; -export * from './combo-circle'; +export * from './combo'; export * from './common-graph'; export * from './viewport-fit'; diff --git a/packages/g6/__tests__/integration/snapshots/static/graph-element.svg b/packages/g6/__tests__/integration/snapshots/static/graph-element.svg index 2a66c4ac274..3586e45cdc0 100644 --- a/packages/g6/__tests__/integration/snapshots/static/graph-element.svg +++ b/packages/g6/__tests__/integration/snapshots/static/graph-element.svg @@ -18,6 +18,7 @@ transform="translate(-36.76955262170047,-36.76955262170047)" cx="36.76955262170047" cy="36.76955262170047" + stroke-dasharray="0,0" stroke-width="1" stroke="rgba(153,173,209,1)" r="36.76955262170047" diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo.svg b/packages/g6/__tests__/snapshots/elements/combo/combo.svg index 39ec1d65047..899e893434d 100644 --- a/packages/g6/__tests__/snapshots/elements/combo/combo.svg +++ b/packages/g6/__tests__/snapshots/elements/combo/combo.svg @@ -10,24 +10,21 @@ - + - + - - + - + @@ -168,7 +166,7 @@ - + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo__collapse_bottom.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_bottomLeft.svg similarity index 93% rename from packages/g6/__tests__/snapshots/elements/combo/combo__collapse_bottom.svg rename to packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_bottomLeft.svg index 461316e53b7..8ae2e859195 100644 --- a/packages/g6/__tests__/snapshots/elements/combo/combo__collapse_bottom.svg +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_bottomLeft.svg @@ -13,7 +13,7 @@ @@ -62,18 +62,19 @@ transform="matrix(1,0,0,1,250.440002,261.500000)" > - - + - + @@ -169,7 +170,7 @@ - + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_center.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_center.svg new file mode 100644 index 00000000000..c965e1cbffb --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_center.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_left.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_left.svg new file mode 100644 index 00000000000..f3435d4260b --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_left.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_right.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_right.svg new file mode 100644 index 00000000000..b23136c2fec --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_right.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo__collapse_left.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_top.svg similarity index 93% rename from packages/g6/__tests__/snapshots/elements/combo/combo__collapse_left.svg rename to packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_top.svg index 43a7f54f9fe..15c86793a74 100644 --- a/packages/g6/__tests__/snapshots/elements/combo/combo__collapse_left.svg +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_circle__collapse_top.svg @@ -13,7 +13,7 @@ @@ -62,18 +62,19 @@ transform="matrix(1,0,0,1,250.440002,261.500000)" > - - + - + @@ -169,7 +170,7 @@ - + @@ -62,18 +62,19 @@ transform="matrix(1,0,0,1,250.440002,261.500000)" > - - + - + @@ -169,7 +170,7 @@ - + @@ -62,18 +62,19 @@ transform="matrix(1,0,0,1,250.440002,261.500000)" > - - + - + @@ -169,7 +170,7 @@ - + @@ -77,18 +77,19 @@ transform="matrix(1,0,0,1,250.440002,261.500000)" > - - + - + @@ -184,7 +185,7 @@ - + @@ -77,18 +77,19 @@ transform="matrix(1,0,0,1,250.440002,261.500000)" > - - + - + @@ -184,7 +185,7 @@ - + @@ -77,18 +77,19 @@ transform="matrix(1,0,0,1,250.440002,261.500000)" > - - + - + @@ -184,7 +185,7 @@ - + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_bottomLeft.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_bottomLeft.svg new file mode 100644 index 00000000000..b83db996422 --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_bottomLeft.svg @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_bottomRight.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_bottomRight.svg new file mode 100644 index 00000000000..8121a836a01 --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_bottomRight.svg @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_center.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_center.svg new file mode 100644 index 00000000000..7031d57f72e --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_center.svg @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_left.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_left.svg new file mode 100644 index 00000000000..96f2682200d --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_left.svg @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_right.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_right.svg new file mode 100644 index 00000000000..7f7124a3d4b --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_right.svg @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_top.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_top.svg new file mode 100644 index 00000000000..89b8dbf1632 --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_top.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_topLeft.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_topLeft.svg new file mode 100644 index 00000000000..aacaa014109 --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_topLeft.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_topRight.svg b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_topRight.svg new file mode 100644 index 00000000000..762adb26165 --- /dev/null +++ b/packages/g6/__tests__/snapshots/elements/combo/combo_rect__collapse_topRight.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + combo-2 + + + + + + + + + + + + + + + combo-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + node-1 + + + + + + + + + + + + + + + node-2 + + + + + + + + + + + + + + + node-3 + + + + + + + + \ No newline at end of file diff --git a/packages/g6/__tests__/snapshots/runtime/element/element.svg b/packages/g6/__tests__/snapshots/runtime/element/element.svg index 2a66c4ac274..3586e45cdc0 100644 --- a/packages/g6/__tests__/snapshots/runtime/element/element.svg +++ b/packages/g6/__tests__/snapshots/runtime/element/element.svg @@ -18,6 +18,7 @@ transform="translate(-36.76955262170047,-36.76955262170047)" cx="36.76955262170047" cy="36.76955262170047" + stroke-dasharray="0,0" stroke-width="1" stroke="rgba(153,173,209,1)" r="36.76955262170047" diff --git a/packages/g6/__tests__/unit/elements/combo.spec.ts b/packages/g6/__tests__/unit/elements/combo.spec.ts index fafc6555c00..97f5c0b962c 100644 --- a/packages/g6/__tests__/unit/elements/combo.spec.ts +++ b/packages/g6/__tests__/unit/elements/combo.spec.ts @@ -1,19 +1,19 @@ import { type Graph } from '@/src'; -import { comboCircle } from '@@/demo/case'; +import { combo } from '@@/demo/case'; import { createDemoGraph } from '@@/utils'; describe('combo', () => { let graph: Graph; beforeAll(async () => { - graph = await createDemoGraph(comboCircle, { animation: false }); + graph = await createDemoGraph(combo, { animation: false }); }); it('default status', async () => { await expect(graph.getCanvas()).toMatchSnapshot(__filename); }); - it('collapse combo', async () => { + it('collapse circle combo', async () => { const expandCombo = () => { graph.updateComboData((data) => [ ...data, @@ -41,15 +41,87 @@ describe('combo', () => { graph.render(); }; collapseCombo('top'); - await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}__collapse_top'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_top'); expandCombo(); collapseCombo('right'); - await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}__collapse_right'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_right'); collapseCombo('left'); - await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}__collapse_left'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_left'); expandCombo(); collapseCombo('bottom'); - await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}__collapse_bottom'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_bottom'); + expandCombo(); + collapseCombo('center'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_center'); + expandCombo(); + collapseCombo('top-left'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_topLeft'); + expandCombo(); + collapseCombo('top-right'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_topRight'); + expandCombo(); + collapseCombo('bottom-left'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_bottomLeft'); + expandCombo(); + collapseCombo('bottom-right'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__collapse_bottomRight'); + expandCombo(); + }); + + it('collapse rect combo', async () => { + const expandCombo = () => { + graph.updateComboData((data) => [ + ...data, + { + id: 'combo-1', + style: { + type: 'rect', + collapsed: false, + }, + }, + ]); + graph.render(); + }; + const collapseCombo = (collapsedOrigin: string) => { + graph.updateComboData((data) => [ + ...data, + { + id: 'combo-1', + style: { + type: 'rect', + collapsed: true, + collapsedOrigin, + collapsedMarker: false, + }, + }, + ]); + graph.render(); + }; + collapseCombo('top'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_top'); + expandCombo(); + collapseCombo('right'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_right'); + collapseCombo('left'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_left'); + expandCombo(); + collapseCombo('bottom'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_bottom'); + expandCombo(); + collapseCombo('center'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_center'); + expandCombo(); + collapseCombo('top-left'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_topLeft'); + expandCombo(); + collapseCombo('top-right'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_topRight'); + expandCombo(); + collapseCombo('bottom-left'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_bottomLeft'); + expandCombo(); + collapseCombo('bottom-right'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_rect__collapse_bottomRight'); expandCombo(); }); @@ -82,12 +154,12 @@ describe('combo', () => { graph.render(); }; collapseCombo('child-count'); - await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}__marker_childCount'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__marker_childCount'); expandCombo(); collapseCombo('descendant-count'); - await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}__marker_descendantCount'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__marker_descendantCount'); expandCombo(); collapseCombo('node-count'); - await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}__marker_nodeCount'); + await expect(graph.getCanvas()).toMatchSnapshot(__filename, '{name}_circle__marker_nodeCount'); }); }); diff --git a/packages/g6/__tests__/unit/registry.spec.ts b/packages/g6/__tests__/unit/registry.spec.ts index d9f4f08f771..c471753c196 100644 --- a/packages/g6/__tests__/unit/registry.spec.ts +++ b/packages/g6/__tests__/unit/registry.spec.ts @@ -16,6 +16,7 @@ import { import { getExtension, getExtensions, register } from '@/src/registry'; import { dark, light } from '@/src/themes'; import { pick } from '@antv/util'; +import { RectCombo } from '../../src/elements/combos/rect'; describe('registry', () => { it('registerBuiltInPlugins', () => { @@ -37,6 +38,7 @@ describe('registry', () => { }); expect(getExtensions('combo')).toEqual({ circle: CircleCombo, + rect: RectCombo, }); expect(getExtensions('theme')).toEqual({ dark, diff --git a/packages/g6/__tests__/unit/utils/combo.spec.ts b/packages/g6/__tests__/unit/utils/combo.spec.ts index bd82db3e514..7a77d72e708 100644 --- a/packages/g6/__tests__/unit/utils/combo.spec.ts +++ b/packages/g6/__tests__/unit/utils/combo.spec.ts @@ -1,19 +1,23 @@ import { Circle, CircleCombo } from '@/src/elements'; import { - calculateCollapsedOrigin, getCollapsedMarkerText, getDescendantCount, + getRectCollapsedOrigin, getXYByCollapsedOrigin, } from '@/src/utils/combo'; describe('combo', () => { - it('calculateCollapsedOrigin', () => { - expect(calculateCollapsedOrigin('top', [100, 100], [200, 200])).toEqual([0.5, 0.25]); - expect(calculateCollapsedOrigin('bottom', [100, 100], [200, 200])).toEqual([0.5, 0.75]); - expect(calculateCollapsedOrigin('left', [100, 100], [200, 200])).toEqual([0.25, 0.5]); - expect(calculateCollapsedOrigin('right', [100, 100], [200, 200])).toEqual([0.75, 0.5]); - expect(calculateCollapsedOrigin('center', [100, 100], [200, 200])).toEqual([0.5, 0.5]); - expect(calculateCollapsedOrigin([0.5, 0.5], [100, 100], [200, 200])).toEqual([0.5, 0.5]); + it('getRectCollapsedOrigin', () => { + expect(getRectCollapsedOrigin('top', [100, 100], [200, 200])).toEqual([0.5, 0.25]); + expect(getRectCollapsedOrigin('bottom', [100, 100], [200, 200])).toEqual([0.5, 0.75]); + expect(getRectCollapsedOrigin('left', [100, 100], [200, 200])).toEqual([0.25, 0.5]); + expect(getRectCollapsedOrigin('right', [100, 100], [200, 200])).toEqual([0.75, 0.5]); + expect(getRectCollapsedOrigin('center', [100, 100], [200, 200])).toEqual([0.5, 0.5]); + expect(getRectCollapsedOrigin('top-left', [100, 100], [200, 200])).toEqual([0.25, 0.25]); + expect(getRectCollapsedOrigin('top-right', [100, 100], [200, 200])).toEqual([0.75, 0.25]); + expect(getRectCollapsedOrigin('bottom-left', [100, 100], [200, 200])).toEqual([0.25, 0.75]); + expect(getRectCollapsedOrigin('bottom-right', [100, 100], [200, 200])).toEqual([0.75, 0.75]); + expect(getRectCollapsedOrigin([0.5, 0.5], [100, 100], [200, 200])).toEqual([0.5, 0.5]); }); it('getXYByCollapsedOrigin', () => { diff --git a/packages/g6/src/elements/combos/base-combo.ts b/packages/g6/src/elements/combos/base-combo.ts index e40c6c37997..bb01daf6b38 100644 --- a/packages/g6/src/elements/combos/base-combo.ts +++ b/packages/g6/src/elements/combos/base-combo.ts @@ -1,7 +1,7 @@ import type { AABB, BaseStyleProps, DisplayObject, DisplayObjectConfig, Group } from '@antv/g'; import { deepMix, isEmpty } from '@antv/util'; import type { BaseComboProps, Position, PrefixObject, STDSize } from '../../types'; -import { getCombinedBBox, getExpandedBBox } from '../../utils/bbox'; +import { getBBoxHeight, getBBoxWidth, getElementsBBox, getExpandedBBox } from '../../utils/bbox'; import { getCollapsedMarkerText, getXYByCollapsedOrigin } from '../../utils/combo'; import { getXYByPosition } from '../../utils/element'; import { subStyleProps } from '../../utils/prefix'; @@ -30,17 +30,17 @@ export abstract class BaseCombo) { super(deepMix({}, { style: BaseCombo.defaultStyleProps }, options)); @@ -52,24 +52,20 @@ export abstract class BaseCombo, container: Group): DisplayObject | undefined; protected calculatePosition(attributes: Required): Position { - const { x: comboX, y: comboY, collapsed, collapsedOrigin } = attributes; + const { x: comboX, y: comboY, collapsed } = attributes; + if (!isEmpty(comboX) && !isEmpty(comboY)) return [comboX, comboY, 0] as Position; - const contentBBox = this.getContentBBox(attributes); - let position: Position = contentBBox.center; - const computedExpandedSize = this.getExpandedKeySize(attributes); - const computedCollapsedSize = this.getCollapsedKeySize(attributes); - - if (collapsed) { - position = getXYByCollapsedOrigin( - collapsedOrigin!, - contentBBox.center, - computedCollapsedSize, - computedExpandedSize, - ); - } + return !collapsed ? this.getContentBBox(attributes).center : this.getCollapsedOriginPosition(attributes); + } - return position; + protected getCollapsedOriginPosition(attributes: Required): Position { + return getXYByCollapsedOrigin( + attributes.collapsedOrigin, + this.getContentBBox(attributes).center, + this.getCollapsedKeySize(attributes), + this.getExpandedKeySize(attributes), + ); } protected getKeySize(attributes: Required): STDSize { @@ -82,17 +78,24 @@ export abstract class BaseCombo): STDSize; + protected getCollapsedKeySize(attributes: Required): STDSize { + return parseSize(attributes.collapsedSize); + } - protected abstract getExpandedKeySize(attributes: Required): STDSize; + protected getExpandedKeySize(attributes: Required): STDSize { + if (!isEmpty(attributes.size)) return parseSize(attributes.size); + + const contentBBox = this.getContentBBox(attributes); + return [getBBoxWidth(contentBBox), getBBoxHeight(contentBBox), 0]; + } protected getContentBBox(attributes: Required): AABB { - const { children = [], padding } = attributes; - let childrenBBox = getCombinedBBox(children.map((child) => child.getBounds())); - if (padding) { - childrenBBox = getExpandedBBox(childrenBBox, padding); - } - return childrenBBox; + const { children, padding } = attributes; + const childrenBBox = getElementsBBox(children!); + + if (!padding) return childrenBBox; + + return getExpandedBBox(childrenBBox, padding); } protected drawCollapsedMarkerShape(attributes: Required, container: Group): void { diff --git a/packages/g6/src/elements/combos/circle.ts b/packages/g6/src/elements/combos/circle.ts index 22b07bdbb5a..c62f86ee95c 100644 --- a/packages/g6/src/elements/combos/circle.ts +++ b/packages/g6/src/elements/combos/circle.ts @@ -1,7 +1,9 @@ import type { DisplayObjectConfig, CircleStyleProps as GCircleStyleProps } from '@antv/g'; import { Circle as GCircle, Group } from '@antv/g'; -import type { STDSize } from '../../types'; +import { isEmpty } from '@antv/util'; +import type { Position, STDSize } from '../../types'; import { getBBoxHeight, getBBoxWidth } from '../../utils/bbox'; +import { getCircleCollapsedOrigin, getXYByCollapsedOrigin } from '../../utils/combo'; import { subStyleProps } from '../../utils/prefix'; import { parseSize } from '../../utils/size'; import type { BaseComboStyleProps, ParsedBaseComboStyleProps } from './base-combo'; @@ -41,11 +43,25 @@ export class CircleCombo extends BaseCombo { } protected getExpandedKeySize(attributes: ParsedCircleComboStyleProps): STDSize { - const [expandedWidth, expandedHeight] = parseSize(attributes.size); + if (!isEmpty(attributes.size)) { + const [expandedWidth, expandedHeight] = parseSize(attributes.size); + const expandedR = Math.sqrt(expandedWidth ** 2 + expandedHeight ** 2) / 2; + return [expandedR * 2, expandedR * 2, 0]; + } const contentBBox = this.getContentBBox(attributes); - const width = expandedWidth || getBBoxWidth(contentBBox); - const height = expandedHeight || getBBoxHeight(contentBBox); + const width = getBBoxWidth(contentBBox); + const height = getBBoxHeight(contentBBox); const expandedR = Math.sqrt(width ** 2 + height ** 2) / 2; return [expandedR * 2, expandedR * 2, 0]; } + + protected getCollapsedOriginPosition(attributes: ParsedBaseComboStyleProps): Position { + return getXYByCollapsedOrigin( + attributes.collapsedOrigin, + this.getContentBBox(attributes).center, + this.getCollapsedKeySize(attributes), + this.getExpandedKeySize(attributes), + getCircleCollapsedOrigin, + ); + } } diff --git a/packages/g6/src/elements/combos/rect.ts b/packages/g6/src/elements/combos/rect.ts new file mode 100644 index 00000000000..5d5e9c64964 --- /dev/null +++ b/packages/g6/src/elements/combos/rect.ts @@ -0,0 +1,40 @@ +import type { DisplayObjectConfig, RectStyleProps as GRectStyleProps } from '@antv/g'; +import { Rect as GRect, Group } from '@antv/g'; +import { deepMix } from '@antv/util'; +import { subStyleProps } from '../../utils/prefix'; +import type { BaseComboStyleProps, ParsedBaseComboStyleProps } from './base-combo'; +import { BaseCombo } from './base-combo'; + +type KeyStyleProps = GRectStyleProps; +export type RectComboStyleProps = BaseComboStyleProps; +type ParsedRectComboStyleProps = ParsedBaseComboStyleProps; +type RectComboOptions = DisplayObjectConfig; + +export class RectCombo extends BaseCombo { + static defaultStyleProps: RectComboStyleProps = { + size: [100, 30], + anchor: [0.5, 0.5], + }; + + constructor(options: RectComboOptions) { + super(deepMix({}, { style: RectCombo.defaultStyleProps }, options)); + } + + protected drawKeyShape(attributes: ParsedRectComboStyleProps, container: Group): GRect | undefined { + return this.upsert('key', GRect, this.getKeyStyle(attributes), container); + } + + protected getKeyStyle(attributes: ParsedRectComboStyleProps): GRectStyleProps { + const { collapsed } = attributes; + const keyStyle = super.getKeyStyle(attributes); + const collapsedStyle = subStyleProps(keyStyle, 'collapsed'); + + const [width, height] = this.getKeySize(attributes); + return { + ...keyStyle, + ...(collapsed && collapsedStyle), + width, + height, + }; + } +} diff --git a/packages/g6/src/registry/build-in.ts b/packages/g6/src/registry/build-in.ts index 59754aab000..e11b2343f04 100644 --- a/packages/g6/src/registry/build-in.ts +++ b/packages/g6/src/registry/build-in.ts @@ -15,6 +15,7 @@ import { Star, Triangle, } from '../elements'; +import { RectCombo } from '../elements/combos/rect'; import { CircularLayout, ComboCombinedLayout, @@ -52,6 +53,7 @@ export const BUILT_IN_EXTENSIONS: ExtensionRegistry = { }, combo: { circle: CircleCombo, + rect: RectCombo, }, edge: { cubic: Cubic, diff --git a/packages/g6/src/runtime/element.ts b/packages/g6/src/runtime/element.ts index 135ee873bb0..0e7787fac97 100644 --- a/packages/g6/src/runtime/element.ts +++ b/packages/g6/src/runtime/element.ts @@ -174,9 +174,9 @@ export class ElementController { const datum = this.getElementData(elementType, [id])?.[0]; if (!datum) return {}; - // `data.style` 中一些样式例如 parentId, type 并非直接给元素使用,因此需要过滤掉这些字段 + // `data.style` 中一些样式例如 parentId 并非直接给元素使用,因此需要过滤掉这些字段 // Some styles in `data.style`, such as parentId, type, are not directly used by the element, so these fields need to be filtered out - const { parentId, type, states, ...style } = datum.style || {}; + const { parentId, states, ...style } = datum.style || {}; return style; } @@ -574,7 +574,6 @@ export class ElementController { const currentShape = this.getElement(id); if (currentShape) return () => null; const renderData = this.getElementComputedStyle(elementType, id); - // get shape constructor const shapeType = this.getShapeType(elementType, renderData); const Ctor = getExtension(elementType, shapeType); @@ -739,7 +738,11 @@ export class ElementController { const originalShapeType = this.shapeTypeMap[id]; const modifiedShapeType = this.getShapeType(elementType, this.getElementComputedStyle(elementType, id)); if (originalShapeType && originalShapeType !== modifiedShapeType) { - this.destroyElement(datum, context); + // this.destroyElement(datum, context); + const element = this.elementMap[id]; + this.clearElement(id); + element.destroy(); + this.createElement(elementType, datum, context); } } diff --git a/packages/g6/src/themes/dark.ts b/packages/g6/src/themes/dark.ts index fefc487e3b3..78596495f67 100644 --- a/packages/g6/src/themes/dark.ts +++ b/packages/g6/src/themes/dark.ts @@ -146,6 +146,7 @@ export const dark: Theme = { labelFill: '#000', labelFontSize: 12, labelMaxLines: 1, + lineDash: 0, lineWidth: 1, padding: 10, size: 0, diff --git a/packages/g6/src/themes/light.ts b/packages/g6/src/themes/light.ts index da5ee8f4a05..4d728bc2d2e 100644 --- a/packages/g6/src/themes/light.ts +++ b/packages/g6/src/themes/light.ts @@ -145,6 +145,7 @@ export const light: Theme = { labelFill: '#000', labelFontSize: 12, labelMaxLines: 1, + lineDash: 0, lineWidth: 1, padding: 10, size: 0, diff --git a/packages/g6/src/types/element.ts b/packages/g6/src/types/element.ts index 16c6f96e012..fc52f6aa423 100644 --- a/packages/g6/src/types/element.ts +++ b/packages/g6/src/types/element.ts @@ -106,10 +106,20 @@ export type BaseComboProps = { */ collapsedSize?: Size; /** - * Combo 收起后的原点 + * Combo 收起时的原点 * The origin of combo when collapsed */ - collapsedOrigin?: string | [number, number]; + collapsedOrigin?: + | 'center' + | 'top' + | 'bottom' + | 'left' + | 'right' + | 'top-left' + | 'top-right' + | 'bottom-left' + | 'bottom-right' + | [number, number]; /** * Combo 的子元素,可以是节点或者 Combo * The children of combo, which can be nodes or combos diff --git a/packages/g6/src/utils/combo.ts b/packages/g6/src/utils/combo.ts index fa1fd474c55..e8bc0fd5fe1 100644 --- a/packages/g6/src/utils/combo.ts +++ b/packages/g6/src/utils/combo.ts @@ -1,54 +1,97 @@ import { AABB } from '@antv/g'; import type { CollapsedMarkerStyleProps } from '../elements/combos/base-combo'; -import type { Combo, Node, Point, Position, Size } from '../types'; +import type { BaseComboProps, Combo, Node, Point, Position, Size } from '../types'; +import type { STDAnchor } from '../types/anchor'; import { getXYByAnchor } from './anchor'; import { isNode } from './element'; import { parseSize } from './size'; /** - * 计算 Combo 收起后原点的相对位置 + * 获取矩形 Combo 收起时原点的相对位置 * - * Calculate the relative position of the origin after the Combo is collapsed + * Get the relative position of the origin when Rect Combo is collapsed * @param collapsedOrigin - 收起时的原点 | origin when collapsed - * @param collapsedSize - 折叠尺寸 | folding size + * @param collapsedSize - 收起尺寸 | collapsed size * @param expandedSize - 展开尺寸 | expanded size - * @returns 折叠后的原点 | origin after folding + * @returns 收起时的原点 | origin when collapsed */ -export function calculateCollapsedOrigin( - collapsedOrigin: string | [number, number], +export function getRectCollapsedOrigin( + collapsedOrigin: BaseComboProps['collapsedOrigin'], collapsedSize: Size, expandedSize: Size, ): Position { if (Array.isArray(collapsedOrigin)) return collapsedOrigin; const [expandedWidth, expandedHeight] = parseSize(expandedSize); const [collapsedWidth, collapsedHeight] = parseSize(collapsedSize); - const map: Record = { + const map: Record = { top: [0.5, collapsedHeight / 2 / expandedHeight], bottom: [0.5, 1 - collapsedHeight / 2 / expandedHeight], left: [collapsedWidth / 2 / expandedWidth, 0.5], right: [1 - collapsedWidth / 2 / expandedWidth, 0.5], center: [0.5, 0.5], + 'top-left': [collapsedWidth / 2 / expandedWidth, collapsedHeight / 2 / expandedHeight], + 'top-right': [1 - collapsedWidth / 2 / expandedWidth, collapsedHeight / 2 / expandedHeight], + 'bottom-left': [collapsedWidth / 2 / expandedWidth, 1 - collapsedHeight / 2 / expandedHeight], + 'bottom-right': [1 - collapsedWidth / 2 / expandedWidth, 1 - collapsedHeight / 2 / expandedHeight], + }; + return map[collapsedOrigin as string] || map.center; +} + +/** + * 获取圆形 Combo 收起时原点的相对位置 + * + * Get the relative position of the origin when Circle Combo is collapsed + * @param collapsedOrigin - 收起时的原点 | origin when collapsed + * @param collapsedSize - 收起尺寸 | collapsed size + * @param expandedSize - 展开尺寸 | expanded size + * @returns 收起时的原点 | origin when collapsed + */ +export function getCircleCollapsedOrigin( + collapsedOrigin: BaseComboProps['collapsedOrigin'], + collapsedSize: Size, + expandedSize: Size, +): Position { + if (Array.isArray(collapsedOrigin)) return collapsedOrigin; + const expandedR = parseSize(expandedSize)[0] / 2; + const collapsedR = parseSize(collapsedSize)[0] / 2; + // 收起时原点到中心的正交距离 + const dist = (expandedR - collapsedR) / Math.sqrt(2); + const map: Record = { + top: [0.5, collapsedR / (2 * expandedR)], + bottom: [0.5, 1 - collapsedR / (2 * expandedR)], + left: [collapsedR / (2 * expandedR), 0.5], + right: [1 - collapsedR / (2 * expandedR), 0.5], + 'top-left': [0.5 - dist / (2 * expandedR), 0.5 - dist / (2 * expandedR)], + 'top-right': [0.5 + dist / (2 * expandedR), 0.5 - dist / (2 * expandedR)], + 'bottom-left': [0.5 - dist / (2 * expandedR), 0.5 + dist / (2 * expandedR)], + 'bottom-right': [0.5 + dist / (2 * expandedR), 0.5 + dist / (2 * expandedR)], }; - return map[collapsedOrigin] || map.center; + return map[collapsedOrigin as string] || [0.5, 0.5]; } /** - * 计算 Combo 收起后原点的实际位置 + * 计算 Combo 收起时原点的实际位置 * * Calculate the actual position of the origin after the Combo is collapsed * @param collapsedOrigin - 收起时的原点 | origin when collapsed * @param center - 中心点 | center * @param collapsedSize - 折叠尺寸 | folding size * @param expandedSize - 展开尺寸 | expanded size + * @param getCollapsedOrigin - 获取原点相对位置的函数 | function to get the relative position of the origin * @returns 原点实际位置 | actual position of the origin */ export function getXYByCollapsedOrigin( - collapsedOrigin: string | [number, number], + collapsedOrigin: BaseComboProps['collapsedOrigin'], center: Point, collapsedSize: Size, expandedSize: Size, + getCollapsedOrigin: ( + collapsedOrigin: BaseComboProps['collapsedOrigin'], + collapsedSize: Size, + expandedSize: Size, + ) => Position = getRectCollapsedOrigin, ): Position { - const origin = calculateCollapsedOrigin(collapsedOrigin, collapsedSize, expandedSize); + const origin = getCollapsedOrigin(collapsedOrigin, collapsedSize, expandedSize); const [expandedWidth, expandedHeight] = parseSize(expandedSize); const expandedBBox = new AABB(); expandedBBox.setMinMax(