GridLine
Overview
The GridLine plugin provides visual auxiliary lines for the canvas, helping users precisely position and align graphic elements. It is an indispensable tool in graphic drawing.
Use Cases
The GridLine plugin is mainly suitable for the following scenarios:
- Assisting users in precise drawing and element alignment
- Providing visual references to enhance spatial awareness
- Building a structured reference system when designing and editing graphics
Basic Usage
Below is a simple example of initializing the GridLine plugin:
const graph = new Graph({
plugins: [
{
type: 'grid-line',
key: 'my-grid-line', // Specify a unique identifier for dynamic updates
size: 20,
stroke: '#0001',
follow: true,
},
],
});
Online Experience
import { createGraph } from '/demo-runtime.ts';
createGraph(
{
data: { nodes: [{ id: 'node-1' }] },
node: { style: { fill: '#7e3feb' } },
edge: { style: { stroke: '#8b9baf' } },
layout: { type: 'force' },
behaviors: ['drag-canvas'],
plugins: [{ type: 'grid-line', key: 'grid-line', size: 30 }],
},
{ width: 600, height: 300 },
(gui, graph) => {
const LINE_STYLE = ['none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset'];
const options = {
type: 'grid-line',
border: true,
borderLineWidth: 1,
borderStroke: '#eee',
borderStyle: 'solid',
follow: false,
lineWidth: 1,
size: 20,
stroke: '#eee',
};
const optionFolder = gui.addFolder('Gird Line Options');
optionFolder.add(options, 'type').disable(true);
optionFolder.add(options, 'size', 1, 50, 1);
optionFolder.add(options, 'lineWidth', 1, 10, 1);
optionFolder.addColor(options, 'stroke');
optionFolder.add(options, 'border');
optionFolder.add(options, 'borderLineWidth', 1, 10, 1);
optionFolder.add(options, 'borderStyle', LINE_STYLE);
optionFolder.addColor(options, 'borderStroke');
optionFolder.add(options, 'follow');
optionFolder.onChange(({ property, value }) => {
graph.updatePlugin({
key: 'grid-line',
[property]: value,
});
graph.render();
});
},
);
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';
export function addPanel(renderPanel: (gui: GUI) => void) {
const gui = new GUI({ container: document.body });
gui.title('Control');
Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
renderPanel(gui);
addEventListener('pagehide', () => gui.destroy(), { once: true });
}
export async function createGraph(
options: ConstructorParameters<typeof Graph>[0],
size: { width?: number; height?: number } = {},
renderPanel?: (gui: GUI, graph: Graph) => void,
) {
const container = document.createElement('div');
Object.assign(container.style, {
width: '100%',
maxWidth: `${size.width || 600}px`,
height: `${size.height || 400}px`,
});
document.getElementById('container')!.append(container);
const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
addEventListener('pagehide', () => graph.destroy(), { once: true });
await graph.render();
if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
return container;
}Configuration Options
| Property | Description | Type | Default | Required |
|---|---|---|---|---|
| type | Plugin type | string | grid-line |
✓ |
| key | Unique identifier for the plugin, used to get the plugin instance or update plugin options | string | - | |
| border | Whether to display the border | boolean | true | |
| borderLineWidth | Border line width | number | 1 | |
| borderStroke | Border color, see CSS border-color | string | #eee |
|
| borderStyle | Border style, see CSS border-style | string | solid |
|
| follow | Whether to follow canvas movements | boolean | {translate ?: boolean, zoom?: boolean} | false | |
| lineWidth | Grid line width | number | string | 1 | |
| size | Grid unit size in pixels | number | 20 | |
| stroke | Grid line color | string | #eee |
follow
The follow property controls whether the grid lines follow the canvas transformations. It supports two configuration methods:
- Boolean Configuration: When set to
true, the grid lines follow both canvas translation and zoom; when set tofalse, they remain static.
// Enable both translation and zoom following
const graph = new Graph({
plugins: [
{
type: 'grid-line',
follow: true,
},
],
});
- Object Configuration: Allows more precise control over the grid line following behavior.
// Follow translation only, not zoom
const graph = new Graph({
plugins: [
{
type: 'grid-line',
follow: {
translate: true, // Follow translation
zoom: false, // Do not follow zoom
},
},
],
});
// Follow zoom only, not translation
const graph = new Graph({
plugins: [
{
type: 'grid-line',
follow: {
translate: false, // Do not follow translation
zoom: true, // Follow zoom
},
},
],
});
When grid lines follow zoom, they maintain a relative position to the canvas content, making alignment references more precise. Following translation allows the grid to move with the canvas content, enhancing the visual experience of spatial continuity.
Code Examples
Basic Grid Line
The simplest way is to use the preset configuration directly:
const graph = new Graph({
// Other configurations...
plugins: ['grid-line'],
});
The effect is as follows:
import { Graph } from '@antv/g6';
const graph = new Graph({
container: 'container',
width: 300,
height: 150,
data: { nodes: [{ id: 'node-1', style: { x: 150, y: 75 } }] },
behaviors: ['drag-canvas'],
plugins: ['grid-line'],
});
graph.render();
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';
export function addPanel(renderPanel: (gui: GUI) => void) {
const gui = new GUI({ container: document.body });
gui.title('Control');
Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
renderPanel(gui);
addEventListener('pagehide', () => gui.destroy(), { once: true });
}
export async function createGraph(
options: ConstructorParameters<typeof Graph>[0],
size: { width?: number; height?: number } = {},
renderPanel?: (gui: GUI, graph: Graph) => void,
) {
const container = document.createElement('div');
Object.assign(container.style, {
width: '100%',
maxWidth: `${size.width || 600}px`,
height: `${size.height || 400}px`,
});
document.getElementById('container')!.append(container);
const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
addEventListener('pagehide', () => graph.destroy(), { once: true });
await graph.render();
if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
return container;
}Custom Style
You can customize the grid line style as needed:
const graph = new Graph({
// Other configurations...
plugins: [
{
type: 'grid-line',
stroke: '#1890ff33', // Blue semi-transparent grid line
lineWidth: 2,
size: 40, // Larger grid unit
borderStroke: '#1890ff', // Blue border
borderLineWidth: 2,
},
],
});
The effect is as follows:
import { Graph } from '@antv/g6';
const graph = new Graph({
container: 'container',
width: 300,
height: 150,
data: { nodes: [{ id: 'node-1', style: { x: 150, y: 75 } }] },
behaviors: ['drag-canvas'],
plugins: [
{
type: 'grid-line',
stroke: '#1890ff33', // Blue semi-transparent grid line
lineWidth: 2,
size: 40, // Larger grid
borderStroke: '#1890ff', // Blue border
borderLineWidth: 2,
},
],
});
graph.render();
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';
export function addPanel(renderPanel: (gui: GUI) => void) {
const gui = new GUI({ container: document.body });
gui.title('Control');
Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
renderPanel(gui);
addEventListener('pagehide', () => gui.destroy(), { once: true });
}
export async function createGraph(
options: ConstructorParameters<typeof Graph>[0],
size: { width?: number; height?: number } = {},
renderPanel?: (gui: GUI, graph: Graph) => void,
) {
const container = document.createElement('div');
Object.assign(container.style, {
width: '100%',
maxWidth: `${size.width || 600}px`,
height: `${size.height || 400}px`,
});
document.getElementById('container')!.append(container);
const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
addEventListener('pagehide', () => graph.destroy(), { once: true });
await graph.render();
if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
return container;
}Follow Movement
Enabling the follow option allows the grid to move with the canvas, enhancing user experience:
const graph = new Graph({
// Other configurations...
behaviors: ['drag-canvas', 'zoom-canvas'],
plugins: [
{
type: 'grid-line',
follow: true, // Grid follows canvas movement
},
],
});
Try dragging/zooming the canvas to observe the grid following effect:
import { Graph } from '@antv/g6';
const graph = new Graph({
container: 'container',
width: 300,
height: 150,
data: { nodes: [{ id: 'node-1', style: { x: 150, y: 75 } }] },
behaviors: ['drag-canvas', 'zoom-canvas'],
plugins: [
{
type: 'grid-line',
follow: true, // Grid follows canvas movement
},
],
});
graph.render();
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';
export function addPanel(renderPanel: (gui: GUI) => void) {
const gui = new GUI({ container: document.body });
gui.title('Control');
Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
renderPanel(gui);
addEventListener('pagehide', () => gui.destroy(), { once: true });
}
export async function createGraph(
options: ConstructorParameters<typeof Graph>[0],
size: { width?: number; height?: number } = {},
renderPanel?: (gui: GUI, graph: Graph) => void,
) {
const container = document.createElement('div');
Object.assign(container.style, {
width: '100%',
maxWidth: `${size.width || 600}px`,
height: `${size.height || 400}px`,
});
document.getElementById('container')!.append(container);
const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
addEventListener('pagehide', () => graph.destroy(), { once: true });
await graph.render();
if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
return container;
}Dynamic Grid Update
Use the key identifier to dynamically update grid properties at runtime:
// Initial configuration
const graph = new Graph({
// Other configurations...
plugins: [
{
type: 'grid-line',
key: 'my-grid',
size: 20,
},
],
});
// Subsequent dynamic updates
graph.updatePlugin({
key: 'my-grid',
size: 40, // Update grid size
stroke: '#ff4d4f', // Update grid color
});
Cases
import { addPanel } from '/demo-runtime.ts';
import { Graph } from '@antv/g6';
const 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' },
],
};
const graph = new Graph({
container: 'container',
data,
layout: { type: 'grid' },
behaviors: ['drag-canvas'],
plugins: [{ key: 'grid-line', type: 'grid-line', follow: false }],
});
graph.render();
addPanel((gui) => {
gui
.add({ follow: false }, 'follow')
.name('Follow')
.onChange((value) => {
graph.updatePlugin({
key: 'grid-line',
follow: value,
});
});
});
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';
export function addPanel(renderPanel: (gui: GUI) => void) {
const gui = new GUI({ container: document.body });
gui.title('Control');
Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
renderPanel(gui);
addEventListener('pagehide', () => gui.destroy(), { once: true });
}
export async function createGraph(
options: ConstructorParameters<typeof Graph>[0],
size: { width?: number; height?: number } = {},
renderPanel?: (gui: GUI, graph: Graph) => void,
) {
const container = document.createElement('div');
Object.assign(container.style, {
width: '100%',
maxWidth: `${size.width || 600}px`,
height: `${size.height || 400}px`,
});
document.getElementById('container')!.append(container);
const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
addEventListener('pagehide', () => graph.destroy(), { once: true });
await graph.render();
if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
return container;
}