Skip to content

Commit

Permalink
feat: add grid line plugin (#5498)
Browse files Browse the repository at this point in the history
* refactor(test): demo support disable default grid

* refactor(runtime): uniform graph lifecycle event, emit size change event

* feat(utils): add mod util

* feat(plugin): add grid plugin

* refactor(register): adjust extension type definitions

* refactor(runtime): adjust rest widget define

* refactor(test): add test case
  • Loading branch information
Aarebecca authored Mar 6, 2024
1 parent 21d5e46 commit 673546e
Show file tree
Hide file tree
Showing 26 changed files with 394 additions and 82 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"afterelementzindexchange",
"afterlayout",
"afterrender",
"aftersizechange",
"aftertransform",
"afterviewportanimate",
"bbox",
Expand All @@ -26,6 +27,7 @@
"beforeelementzindexchange",
"beforelayout",
"beforerender",
"beforesizechange",
"beforetransform",
"beforeviewportanimate",
"cancelviewportanimate",
Expand Down
54 changes: 54 additions & 0 deletions packages/g6/__tests__/demo/case/graph-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Graph, GraphEvent } from '@/src';
import data from '@@/dataset/cluster.json';
import type { STDTestCase } from '../types';

export const graphEvent: STDTestCase = async (context) => {
const graph = new Graph({
...context,
data,
node: {
style: {
size: 20,
},
},
autoResize: true,
layout: { type: 'd3force' },
});

const events = [
GraphEvent.BEFORE_RENDER,
GraphEvent.AFTER_RENDER,
GraphEvent.BEFORE_DRAW,
GraphEvent.AFTER_DRAW,
GraphEvent.BEFORE_LAYOUT,
GraphEvent.AFTER_LAYOUT,
GraphEvent.BEFORE_SIZE_CHANGE,
GraphEvent.AFTER_SIZE_CHANGE,
];

const now = performance.now();
events.forEach((event) => {
graph.on(event, (e: any) => {
console.log('Time: ', performance.now() - now);
console.log(event, e);
});
});

await graph.render();

graphEvent.form = (panel) => {
const config = {
note: 'See The Console',
resize: () => {
const $container = document.getElementById('container')!;
Object.assign($container.style, { width: '600px', height: '600px' });
window.dispatchEvent(new Event('resize'));
},
follow: false,
size: 20,
};
return [panel.add(config, 'note').name('⚠️ Note').disable()];
};

return graph;
};
2 changes: 2 additions & 0 deletions packages/g6/__tests__/demo/case/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ export * from './behavior-drag-canvas';
export * from './behavior-zoom-canvas';
export * from './combo-circle';
export * from './common-graph';
export * from './graph-event';
export * from './plugin-grid-line';
export * from './viewport-fit';
61 changes: 61 additions & 0 deletions packages/g6/__tests__/demo/case/plugin-grid-line.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Graph } from '@/src';
import data from '@@/dataset/cluster.json';
import { isObject } from '@antv/util';
import type { STDTestCase } from '../types';

export const pluginGridLine: STDTestCase = async (context) => {
const graph = new Graph({
...context,
data,
node: {
style: {
size: 20,
},
},
autoResize: true,
layout: { type: 'd3force' },
behaviors: ['drag-canvas'],
plugins: [{ type: 'grid-line', follow: false }],
});

await graph.render();

pluginGridLine.form = (panel) => {
const config = {
resize: () => {
const $container = document.getElementById('container')!;
Object.assign($container.style, { width: '600px', height: '600px' });
window.dispatchEvent(new Event('resize'));
},
follow: false,
size: 20,
};
return [
panel.add(config, 'resize').name('Emit Resize'),
panel
.add(config, 'follow')
.name('Follow The Graph')
.onChange((follow: boolean) => {
graph.setPlugins((plugins) =>
plugins.map((plugin) => {
if (isObject(plugin) && plugin.type === 'grid-line') return { ...plugin, follow };
return plugin;
}),
);
}),
panel
.add(config, 'size', 10, 50, 5)
.name('Grid Size')
.onChange((size: number) => {
graph.setPlugins((plugins) =>
plugins.map((plugin) => {
if (isObject(plugin) && plugin.type === 'grid-line') return { ...plugin, size };
return plugin;
}),
);
}),
];
};

return graph;
};
52 changes: 41 additions & 11 deletions packages/g6/__tests__/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const options: Options = {
Type: 'statics',
Demo: Object.keys(demos['statics'])[0],
Renderer: 'canvas',
GridLine: true,
Theme: 'light',
Animation: true,
interval: 0,
Expand All @@ -29,7 +30,7 @@ const options: Options = {
forms: [],
};

const params = ['Type', 'Demo', 'Renderer', 'Theme', 'Animation'] as const;
const params = ['Type', 'Demo', 'Renderer', 'GridLine', 'Theme', 'Animation'] as const;

syncParamsFromSearch();

Expand All @@ -47,23 +48,25 @@ function initPanel() {
const Demo = panel.add(options, 'Demo', getDemos()).onChange(render);
const Renderer = panel.add(options, 'Renderer', { Canvas: 'canvas', SVG: 'svg', WebGL: 'webgl' }).onChange(render);
const Theme = panel.add(options, 'Theme', { Light: 'light', Dark: 'dark' }).onChange(render);
const GridLine = panel.add(options, 'GridLine').onChange(() => {
syncParamsToSearch();
applyGridLine();
});
const Animation = panel.add(options, 'Animation').onChange(render);
const Timer = panel.add(options, 'Timer').disable();
const reload = panel.add(options, 'Reload').onChange(render);
return { panel, Type, Demo, Renderer, Theme, Animation, Timer, reload };
return { panel, Type, Demo, Renderer, GridLine, Theme, Animation, Timer, reload };
}

async function render() {
setParamsToSearch(options);
document.documentElement.setAttribute('data-theme', options.Theme);
syncParamsToSearch();
applyTheme();
destroyForm();
panels.Timer.setValue('0ms');

// container
document.getElementById('container')?.remove();
const $container = document.createElement('div');
$container.id = 'container';
document.getElementById('app')?.appendChild($container);
const $container = initContainer();

applyGridLine();

// render
const { Renderer, Type, Demo, Animation, Theme } = options;
Expand Down Expand Up @@ -101,15 +104,42 @@ function syncParamsFromSearch() {
params.forEach((key) => {
const value = searchParams.get(key);
if (!value) return;
if (key === 'Animation') options[key] = value === 'true';
if (key === 'Animation' || key === 'GridLine') options[key] = value === 'true';
else options[key] = value;
});
}

function setParamsToSearch(options: Options) {
function syncParamsToSearch() {
const searchParams = new URLSearchParams(window.location.search);
Object.entries(options).forEach(([key, value]) => {
if (params.includes(key as (typeof params)[number])) searchParams.set(key, value.toString());
});
window.history.replaceState(null, '', `?${searchParams.toString()}`);
}

function initContainer() {
document.getElementById('container')?.remove();
const $container = document.createElement('div');
$container.id = 'container';
document.getElementById('app')?.appendChild($container);
return $container;
}

function applyTheme() {
document.documentElement.setAttribute('data-theme', options.Theme);
}

function applyGridLine() {
const show = options.GridLine;

const element = document.getElementById('container');
if (!element) return;
syncParamsToSearch();
if (show) {
document.body.style.backgroundSize = '25px 25px';
element.style.border = '1px solid #e8e8e8';
} else {
document.body.style.backgroundSize = '0';
element.style.border = 'none';
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { CommonEvent, type Graph } from '@/src';
import type { Graph } from '@/src';
import { CommonEvent } from '@/src';
import { behaviorDragCanvas } from '@@/demo/case';
import { createDemoGraph } from '@@/utils';
import { isObject } from '@antv/util';
Expand Down
45 changes: 45 additions & 0 deletions packages/g6/__tests__/unit/plugins/plugin-grid-line.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Graph } from '@/src';
import { pluginGridLine } from '@@/demo/case';
import { createDemoGraph } from '@@/utils';

describe('plugin grid line', () => {
let graph: Graph;
let gridLineElement: HTMLCollectionOf<HTMLElement>;

beforeAll(async () => {
graph = await createDemoGraph(pluginGridLine, { animation: false });
gridLineElement = graph
.getCanvas()
.getContainer()!
.getElementsByClassName('g6-grid-line')! as HTMLCollectionOf<HTMLElement>;
});

it('default status', () => {
expect(graph.getPlugins()).toEqual([{ type: 'grid-line', follow: false }]);
expect(gridLineElement.length).toBe(1);
expect(gridLineElement[0].style.backgroundSize).toBe('20px 20px');
});

it('update grid line', () => {
graph.setPlugins((plugins) =>
plugins.map((plugin) => {
if (typeof plugin === 'object') {
return {
...plugin,
follow: true,
size: 30,
};
}
return plugin;
}),
);

expect(graph.getPlugins()).toEqual([{ type: 'grid-line', follow: true, size: 30 }]);
expect(gridLineElement[0].style.backgroundSize).toBe('30px 30px');
});

it('drag', () => {
graph.emit('aftertransform', { data: { translate: [10, 10] } });
expect(gridLineElement[0].style.backgroundPosition).toBe('10px 10px');
});
});
6 changes: 3 additions & 3 deletions packages/g6/__tests__/unit/runtime/graph/graph.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ describe('Graph', () => {
expect(graph.getBehaviors()).toEqual(['drag-canvas']);
});

it('getWidgets/setWidgets', () => {
expect(graph.getWidgets()).toEqual([]);
it('getPlugins/setPlugins', () => {
expect(graph.getPlugins()).toEqual([]);
graph.setPlugins([{ type: 'test' }]);
expect(graph.getWidgets()).toEqual([{ type: 'test' }]);
expect(graph.getPlugins()).toEqual([{ type: 'test' }]);
graph.setPlugins([]);
});

Expand Down
6 changes: 6 additions & 0 deletions packages/g6/__tests__/unit/utils/vector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
dot,
exactEquals,
manhattanDistance,
mod,
multiply,
normalize,
perpendicular,
Expand Down Expand Up @@ -87,6 +88,11 @@ describe('Vector Functions', () => {
expect(perpendicular([1, 0])).toEqual([-0, -1]);
});

it('mode', () => {
expect(mod([1, 2], 2)).toEqual([1, 0]);
expect(mod([1, 2, 3], 2)).toEqual([1, 0, 1]);
});

it('toVector2', () => {
expect(toVector2([1, 2, 3])).toEqual([1, 2]);
expect(toVector2([1, 2])).toEqual([1, 2]);
Expand Down
7 changes: 2 additions & 5 deletions packages/g6/src/behaviors/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import type { DragCanvasOptions } from './drag-canvas';
import type { ZoomCanvasOptions } from './zoom-canvas';

export { BaseBehavior } from './base-behavior';
export { DragCanvas } from './drag-canvas';
export { ZoomCanvas } from './zoom-canvas';

export type { BaseBehaviorOptions } from './base-behavior';
export type { DragCanvasOptions, ZoomCanvasOptions };
export type BuiltInBehaviorOptions = DragCanvasOptions | ZoomCanvasOptions;
export type { DragCanvasOptions } from './drag-canvas';
export type { ZoomCanvasOptions } from './zoom-canvas';
4 changes: 4 additions & 0 deletions packages/g6/src/constants/events/graph.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export const enum GraphEvent {
/** <zh/> 视口尺寸变更之前 | <en/> Before the viewport size changes */
BEFORE_SIZE_CHANGE = 'beforesizechange',
/** <zh/> 视口尺寸变更之后 | <en/> After the viewport size changes */
AFTER_SIZE_CHANGE = 'aftersizechange',
/** <zh/> 元素创建之前 | <en/> Before creating element */
BEFORE_ELEMENT_CREATE = 'beforeelementcreate',
/** <zh/> 元素创建之后 | <en/> After creating element */
Expand Down
Loading

0 comments on commit 673546e

Please sign in to comment.