diff --git a/packages/g6-extension-react/__tests__/demos/euro-cup.tsx b/packages/g6-extension-react/__tests__/demos/euro-cup.tsx index 7f13dd10f9f..5fd20113521 100644 --- a/packages/g6-extension-react/__tests__/demos/euro-cup.tsx +++ b/packages/g6-extension-react/__tests__/demos/euro-cup.tsx @@ -86,8 +86,6 @@ export const EuroCup = () => { y: 50, width: 480, height: 720, - background: - 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*EmPXQLrX2xIAAAAAAAAAAAAADmJ7AQ/original)no-repeat', node: { type: 'react', style: { @@ -99,6 +97,18 @@ export const EuroCup = () => { component: (data: any) => , }, }, + plugins: [ + { + type: 'background', + width: '480px', + height: '720px', + backgroundImage: + 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*EmPXQLrX2xIAAAAAAAAAAAAADmJ7AQ/original)', + backgroundRepeat: 'no-repeat', + backgroundSize: 'contain', + opacity: 1, + }, + ], }} /> diff --git a/packages/g6/__tests__/demos/index.ts b/packages/g6/__tests__/demos/index.ts index 8dc23fd0e21..e9f0ef6473f 100644 --- a/packages/g6/__tests__/demos/index.ts +++ b/packages/g6/__tests__/demos/index.ts @@ -94,6 +94,7 @@ export { layoutRadialPreventOverlap } from './layout-radial-prevent-overlap'; export { layoutRadialPreventOverlapUnstrict } from './layout-radial-prevent-overlap-unstrict'; export { layoutRadialSort } from './layout-radial-sort'; export { perfFCP } from './perf-fcp'; +export { pluginBackground } from './plugin-background'; export { pluginBubbleSets } from './plugin-bubble-sets'; export { pluginCameraSetting } from './plugin-camera-setting'; export { pluginContextmenu } from './plugin-contextmenu'; diff --git a/packages/g6/__tests__/demos/plugin-background.ts b/packages/g6/__tests__/demos/plugin-background.ts new file mode 100644 index 00000000000..7269b08b427 --- /dev/null +++ b/packages/g6/__tests__/demos/plugin-background.ts @@ -0,0 +1,44 @@ +import { Graph } from '@/src'; +import data from '@@/dataset/cluster.json'; + +export const pluginBackground: TestCase = async (context) => { + const graph = new Graph({ + ...context, + autoResize: true, + data, + layout: { type: 'd3force' }, + behaviors: ['drag-canvas', 'drag-element'], + plugins: [ + { + type: 'background', + key: 'background', + backgroundImage: + 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*0Qq0ToQm1rEAAAAAAAAAAAAADmJ7AQ/original)', + }, + ], + }); + + await graph.render(); + + pluginBackground.form = (panel) => { + const config = { + backgroundSize: 'cover', + }; + return [ + panel + .add(config, 'backgroundSize', { + Cover: 'cover', + Contain: 'contain', + }) + .name('backgroundSize') + .onChange((backgroundSize: string) => { + graph.updatePlugin({ + key: 'background', + backgroundSize, + }); + }), + ]; + }; + + return graph; +}; diff --git a/packages/g6/__tests__/unit/plugins/background.spec.ts b/packages/g6/__tests__/unit/plugins/background.spec.ts new file mode 100644 index 00000000000..93710765684 --- /dev/null +++ b/packages/g6/__tests__/unit/plugins/background.spec.ts @@ -0,0 +1,26 @@ +import { pluginBackground } from '@/__tests__/demos'; +import { createDemoGraph } from '@@/utils'; + +describe('plugin background', () => { + it('background', async () => { + const graph = await createDemoGraph(pluginBackground); + const container = graph.getCanvas().getContainer()!; + + const el = container.querySelector('.g6-background') as HTMLDivElement; + + expect(graph.getPlugins()).toEqual([ + { + type: 'background', + key: 'background', + backgroundImage: + 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*0Qq0ToQm1rEAAAAAAAAAAAAADmJ7AQ/original)', + }, + ]); + expect(el.style.backgroundImage).toContain( + 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*0Qq0ToQm1rEAAAAAAAAAAAAADmJ7AQ/original)', + ); + + await graph.destroy(); + expect(container.querySelector('.g6-background')).toBeFalsy(); + }); +}); diff --git a/packages/g6/__tests__/unit/plugins/history/utils.spec.ts b/packages/g6/__tests__/unit/plugins/history/utils.spec.ts index a6f932704dc..6bee6d752f6 100644 --- a/packages/g6/__tests__/unit/plugins/history/utils.spec.ts +++ b/packages/g6/__tests__/unit/plugins/history/utils.spec.ts @@ -1,4 +1,4 @@ -import { alignFields, parseCommand } from '@/src/plugins/history/utils'; +import { alignFields, parseCommand } from '@/src/plugins/history/util'; import type { DataChange } from '@/src/types'; describe('history utils', () => { diff --git a/packages/g6/__tests__/unit/utils/contextmenu.spec.ts b/packages/g6/__tests__/unit/utils/contextmenu.spec.ts index 7438bed0f37..5c93c6465d5 100644 --- a/packages/g6/__tests__/unit/utils/contextmenu.spec.ts +++ b/packages/g6/__tests__/unit/utils/contextmenu.spec.ts @@ -1,4 +1,4 @@ -import { getContentFromItems } from '../../../src/utils/contextmenu'; +import { getContentFromItems } from '../../../src/plugins/contextmenu/util'; describe('contextmenu', () => { it('getContentFromItems', () => { diff --git a/packages/g6/__tests__/unit/utils/dom.spec.ts b/packages/g6/__tests__/unit/utils/dom.spec.ts index 202cb67ff58..cbdab31d8ff 100644 --- a/packages/g6/__tests__/unit/utils/dom.spec.ts +++ b/packages/g6/__tests__/unit/utils/dom.spec.ts @@ -19,8 +19,7 @@ describe('sizeOf', () => { expect(el.getAttribute('class')).toBe('g6-test'); expect(el.style.position).toBe('absolute'); expect(el.style.display).toBe('block'); - expect(el.style.top).toBe('0px'); - expect(el.style.left).toBe('0px'); + expect(el.style.inset).toBe('0px'); expect(el.style.height).toBe('100%'); expect(el.style.width).toBe('100%'); expect(el.style.overflow).toBe('hidden'); diff --git a/packages/g6/src/plugins/background/index.ts b/packages/g6/src/plugins/background/index.ts new file mode 100644 index 00000000000..3132c2294a6 --- /dev/null +++ b/packages/g6/src/plugins/background/index.ts @@ -0,0 +1,65 @@ +import { omit } from '@antv/util'; +import type { RuntimeContext } from '../../runtime/types'; +import { createPluginContainer } from '../../utils/dom'; +import type { BasePluginOptions } from '../base-plugin'; +import { BasePlugin } from '../base-plugin'; + +/** + * 背景配置项 + * + * Background options + */ +export interface BackgroundOptions extends BasePluginOptions, CSSStyleDeclaration {} + +/** + * 背景图 + * + * Background image + * @remarks + * 支持为图画布设置一个背景图片,让画布更有层次感、叙事性。 + * + * Support setting a background image for the canvas to make the canvas more hierarchical and narrative. + */ +export class Background extends BasePlugin { + static defaultOptions: Partial = { + transition: 'background 0.5s', + backgroundSize: 'cover', + opacity: '0.35', + }; + + private $element: HTMLElement = createPluginContainer('background'); + + constructor(context: RuntimeContext, options: BackgroundOptions) { + super(context, Object.assign({}, Background.defaultOptions, options)); + + const $container = this.context.canvas.getContainer(); + $container!.appendChild(this.$element); + + this.update(options); + } + + /** + * 更新背景图配置 + * + * Update the background image configuration + * @param options - 配置项 | Options + * @internal + */ + public async update(options: Partial) { + super.update(options); + + // Set the background style. + Object.assign(this.$element.style, omit(this.options, ['key', 'type'])); + } + + /** + * 销毁背景图 + * + * Destroy the background image + */ + public destroy(): void { + super.destroy(); + // Remove the background dom. + this.$element.remove(); + } +} diff --git a/packages/g6/src/plugins/contextmenu.ts b/packages/g6/src/plugins/contextmenu/index.ts similarity index 94% rename from packages/g6/src/plugins/contextmenu.ts rename to packages/g6/src/plugins/contextmenu/index.ts index 1255cccd13e..eac48429c4e 100644 --- a/packages/g6/src/plugins/contextmenu.ts +++ b/packages/g6/src/plugins/contextmenu/index.ts @@ -1,10 +1,10 @@ -import type { RuntimeContext } from '../runtime/types'; -import type { IElementEvent } from '../types/event'; -import type { Item } from '../utils/contextmenu'; -import { CONTEXTMENU_CSS, getContentFromItems } from '../utils/contextmenu'; -import { createPluginContainer, insertDOM } from '../utils/dom'; -import type { BasePluginOptions } from './base-plugin'; -import { BasePlugin } from './base-plugin'; +import type { RuntimeContext } from '../../runtime/types'; +import type { IElementEvent } from '../../types/event'; +import { createPluginContainer, insertDOM } from '../../utils/dom'; +import type { BasePluginOptions } from '../base-plugin'; +import { BasePlugin } from '../base-plugin'; +import type { Item } from './util'; +import { CONTEXTMENU_CSS, getContentFromItems } from './util'; /** * 上下文菜单配置项 diff --git a/packages/g6/src/utils/contextmenu.ts b/packages/g6/src/plugins/contextmenu/util.ts similarity index 100% rename from packages/g6/src/utils/contextmenu.ts rename to packages/g6/src/plugins/contextmenu/util.ts diff --git a/packages/g6/src/plugins/history/index.ts b/packages/g6/src/plugins/history/index.ts index 4d290f014ec..0c27c375bed 100644 --- a/packages/g6/src/plugins/history/index.ts +++ b/packages/g6/src/plugins/history/index.ts @@ -8,7 +8,7 @@ import type { GraphLifeCycleEvent } from '../../utils/event'; import { idsOf } from '../../utils/id'; import type { BasePluginOptions } from '../base-plugin'; import { BasePlugin } from '../base-plugin'; -import { parseCommand } from './utils'; +import { parseCommand } from './util'; /** * 历史记录配置项 diff --git a/packages/g6/src/plugins/history/utils.ts b/packages/g6/src/plugins/history/util.ts similarity index 100% rename from packages/g6/src/plugins/history/utils.ts rename to packages/g6/src/plugins/history/util.ts diff --git a/packages/g6/src/plugins/index.ts b/packages/g6/src/plugins/index.ts index 59589837609..20f49d1e0e5 100644 --- a/packages/g6/src/plugins/index.ts +++ b/packages/g6/src/plugins/index.ts @@ -1,3 +1,4 @@ +export { Background } from './background'; export { BasePlugin } from './base-plugin'; export { BubbleSets } from './bubble-sets'; export { CameraSetting } from './camera-setting'; @@ -11,6 +12,7 @@ export { Toolbar } from './toolbar'; export { Tooltip } from './tooltip'; export { Watermark } from './watermark'; +export type { BackgroundOptions } from './background'; export type { BasePluginOptions } from './base-plugin'; export type { BubbleSetsOptions } from './bubble-sets'; export type { CameraSettingOptions } from './camera-setting'; diff --git a/packages/g6/src/plugins/watermark.ts b/packages/g6/src/plugins/watermark/index.ts similarity index 95% rename from packages/g6/src/plugins/watermark.ts rename to packages/g6/src/plugins/watermark/index.ts index cbe4f3d349f..1cc9924b8a1 100644 --- a/packages/g6/src/plugins/watermark.ts +++ b/packages/g6/src/plugins/watermark/index.ts @@ -1,8 +1,8 @@ -import type { RuntimeContext } from '../runtime/types'; -import { createPluginContainer } from '../utils/dom'; -import { getImageWatermark, getTextWatermark } from '../utils/watermark'; -import type { BasePluginOptions } from './base-plugin'; -import { BasePlugin } from './base-plugin'; +import type { RuntimeContext } from '../../runtime/types'; +import { createPluginContainer } from '../../utils/dom'; +import type { BasePluginOptions } from '../base-plugin'; +import { BasePlugin } from '../base-plugin'; +import { getImageWatermark, getTextWatermark } from './util'; /** * 水印配置项 diff --git a/packages/g6/src/utils/watermark.ts b/packages/g6/src/plugins/watermark/util.ts similarity index 100% rename from packages/g6/src/utils/watermark.ts rename to packages/g6/src/plugins/watermark/util.ts diff --git a/packages/g6/src/registry/build-in.ts b/packages/g6/src/registry/build-in.ts index 790cb50f45e..90dcfdf48ad 100644 --- a/packages/g6/src/registry/build-in.ts +++ b/packages/g6/src/registry/build-in.ts @@ -55,6 +55,7 @@ import { } from '../layouts'; import { blues, greens, oranges, spectral, tableau } from '../palettes'; import { + Background, BubbleSets, Contextmenu, GridLine, @@ -172,6 +173,7 @@ export const BUILT_IN_EXTENSIONS: ExtensionRegistry = { toolbar: Toolbar, tooltip: Tooltip, watermark: Watermark, + background: Background, }, transform: { 'update-related-edges': UpdateRelatedEdge, diff --git a/packages/g6/src/runtime/canvas.ts b/packages/g6/src/runtime/canvas.ts index 1319ae3b308..36c749c554c 100644 --- a/packages/g6/src/runtime/canvas.ts +++ b/packages/g6/src/runtime/canvas.ts @@ -151,35 +151,8 @@ export class Canvas { return this.config; } - private backgroundElement!: HTMLDivElement; - - private initBackgroundElement(options: Record) { - if (this.backgroundElement) { - Object.assign(this.backgroundElement.style, options); - return this.backgroundElement; - } - - const { width, height } = this.config; - - const element = document.createElement('div'); - Object.assign(element.style, options, { - width: `${width}px`, - height: `${height}px`, - pointerEvents: 'none', - transition: 'background 0.5s', - backgroundSize: 'contain', - }); - this.backgroundElement = element; - return element; - } - public setBackground(background = this.config.background) { - const container = this.getContainer(); this.config.background = background; - if (container && background) { - const dom = this.initBackgroundElement({ background }); - container.appendChild(dom); - } } public setCursor(cursor: Cursor) { diff --git a/packages/g6/src/utils/dom.ts b/packages/g6/src/utils/dom.ts index 87204822cf0..f972cc812f9 100644 --- a/packages/g6/src/utils/dom.ts +++ b/packages/g6/src/utils/dom.ts @@ -58,8 +58,7 @@ export function createPluginContainer(type: string, cover = true) { el.style.display = 'block'; if (cover) { - el.style.top = '0px'; - el.style.left = '0px'; + el.style.inset = '0px'; el.style.height = '100%'; el.style.width = '100%'; el.style.overflow = 'hidden'; diff --git a/packages/site/common/api/plugins/background.md b/packages/site/common/api/plugins/background.md new file mode 100644 index 00000000000..574be784559 --- /dev/null +++ b/packages/site/common/api/plugins/background.md @@ -0,0 +1,54 @@ +```js | ob { pin: false } +createGraph( + { + data: { + nodes: [ + { id: 'node-0' }, + { id: 'node-1' }, + { id: 'node-2' }, + { id: 'node-3' }, + { id: 'node-4' }, + { id: 'node-5' }, + ], + edges: [ + { source: 'node-0', target: 'node-1' }, + { source: 'node-0', target: 'node-2' }, + { source: 'node-0', target: 'node-3' }, + { source: 'node-0', target: 'node-4' }, + { source: 'node-1', target: 'node-0' }, + { source: 'node-2', target: 'node-0' }, + { source: 'node-3', target: 'node-0' }, + { source: 'node-4', target: 'node-0' }, + { source: 'node-5', target: 'node-0' }, + ], + }, + layout: { type: 'grid' }, + behaviors: ['drag-canvas'], + plugins: ['grid-line', { + type: 'background', + key: 'background', + backgroundImage: 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*0Qq0ToQm1rEAAAAAAAAAAAAADmJ7AQ/original)', + backgrounfRepeat: 'no-repeat', + backgroundSize: 'contain', + }], + }, + { width: 600, height: 300 }, + (gui, graph) => { + const options = { + type: 'background', + backgroundSize: 'contain', + }; + const optionFolder = gui.addFolder('Background Options'); + optionFolder.add(options, 'type').disable(true); + optionFolder.add(options, 'backgroundSize', ['cover', 'contain', 'auto', '50%']); + + optionFolder.onChange(({ property, value }) => { + graph.updatePlugin({ + key: 'background', + [property]: value, + }); + graph.render(); + }); + }, +); +``` diff --git a/packages/site/examples/plugin/watermark/demo/background.js b/packages/site/examples/plugin/background/demo/background.js similarity index 76% rename from packages/site/examples/plugin/watermark/demo/background.js rename to packages/site/examples/plugin/background/demo/background.js index d7d1e459b4b..b36d4d1242f 100644 --- a/packages/site/examples/plugin/watermark/demo/background.js +++ b/packages/site/examples/plugin/background/demo/background.js @@ -24,13 +24,13 @@ const graph = new Graph({ behaviors: ['zoom-canvas', 'drag-canvas', 'drag-element'], plugins: [ { - type: 'watermark', - width: 1280, - height: 830, - rotate: 0, - opacity: 0.7, - imageURL: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*0Qq0ToQm1rEAAAAAAAAAAAAADmJ7AQ/original', + type: 'background', + width: '800px', + height: '600px', + backgroundImage: 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*0Qq0ToQm1rEAAAAAAAAAAAAADmJ7AQ/original)', + backgrounfRepeat: 'no-repeat', backgroundSize: 'cover', + opacity: 0.2, }, ], }); diff --git a/packages/site/examples/plugin/background/demo/meta.json b/packages/site/examples/plugin/background/demo/meta.json new file mode 100644 index 00000000000..ee0352e153d --- /dev/null +++ b/packages/site/examples/plugin/background/demo/meta.json @@ -0,0 +1,16 @@ +{ + "title": { + "zh": "中文分类", + "en": "Category" + }, + "demos": [ + { + "filename": "background.js", + "title": { + "zh": "背景图片", + "en": "Background Image" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*eCkYR7cLfWwAAAAAAAAAAAAADmJ7AQ/original" + } + ] +} diff --git a/packages/site/examples/plugin/background/index.en.md b/packages/site/examples/plugin/background/index.en.md new file mode 100644 index 00000000000..2f09d88cff3 --- /dev/null +++ b/packages/site/examples/plugin/background/index.en.md @@ -0,0 +1,3 @@ +--- +title: Background +--- diff --git a/packages/site/examples/plugin/background/index.zh.md b/packages/site/examples/plugin/background/index.zh.md new file mode 100644 index 00000000000..05137b9ed9e --- /dev/null +++ b/packages/site/examples/plugin/background/index.zh.md @@ -0,0 +1,3 @@ +--- +title: Background 背景图 +--- diff --git a/packages/site/examples/plugin/watermark/demo/meta.json b/packages/site/examples/plugin/watermark/demo/meta.json index 88a19e4b1c7..53235f53623 100644 --- a/packages/site/examples/plugin/watermark/demo/meta.json +++ b/packages/site/examples/plugin/watermark/demo/meta.json @@ -19,14 +19,6 @@ "en": "Repeat Image" }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*8NfwR5QEXvIAAAAAAAAAAAAADmJ7AQ/original" - }, - { - "filename": "background.js", - "title": { - "zh": "背景图片", - "en": "Background Image" - }, - "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*eCkYR7cLfWwAAAAAAAAAAAAADmJ7AQ/original" } ] } diff --git a/packages/site/examples/scene-case/euro-cup/demo/battle-array.jsx b/packages/site/examples/scene-case/euro-cup/demo/battle-array.jsx index 71e484c0b78..71594f82762 100644 --- a/packages/site/examples/scene-case/euro-cup/demo/battle-array.jsx +++ b/packages/site/examples/scene-case/euro-cup/demo/battle-array.jsx @@ -196,8 +196,6 @@ const graph = new Graph({ y: 50, width: 480, height: 720, - background: - 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*EmPXQLrX2xIAAAAAAAAAAAAADmJ7AQ/original)no-repeat', node: { type: 'react', style: { @@ -209,6 +207,17 @@ const graph = new Graph({ component: (data) => , }, }, + plugins: [ + { + type: 'background', + width: '480px', + height: '720px', + backgroundImage: 'url(https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*EmPXQLrX2xIAAAAAAAAAAAAADmJ7AQ/original)', + backgroundRepeat: 'no-repeat', + backgroundSize: 'contain', + opacity: 1, + } + ], }); graph.render();