甜甜圈节点 Donut
概述
甜甜圈节点是一个环形几何形状,由内外两个同心圆组成。
适用场景:
-
用于表示比例数据,如完成进度、占比分析。
-
适合表示多层数据,如嵌套的环形图。
-
常用于数据可视化、仪表盘、进度图等。
在线体验
import { createGraph } from '/demo-runtime.ts';
createGraph(
{
autoFit: 'center',
data: {
nodes: [
{
id: 'node1',
style: {
fill: 'transparent',
size: 60,
donuts: [30, 30, 20, 20],
donutPalette: ['#1783FF', '#00C9C9', '#F08F56', '#D580FF'],
},
},
],
},
node: { type: 'donut' },
plugins: [{ type: 'grid-line', size: 30 }],
},
{ width: 600, height: 220 },
(gui, graph) => {
gui.add({ type: 'donut' }, 'type').disable();
const options = {
size: 60,
innerR: 50,
donutPalette: ['#1783FF', '#00C9C9', '#F08F56', '#D580FF'],
};
const optionFolder = gui.addFolder('donut.style');
optionFolder.add(options, 'size', 0, 100, 1);
optionFolder.add(options, 'innerR', 0, 100, 1).name('innerR(%)');
optionFolder.add(options, 'donutPalette', ['spectral', 'tableau', ['#1783FF', '#00C9C9', '#F08F56', '#D580FF']]);
optionFolder.onChange(({ property, value }) => {
if (property === 'innerR') value = value + '%';
graph.updateNodeData([{ id: 'node1', style: { [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;
}设置 node.type 为 donut 以使用甜甜圈节点。
样式配置
如果元素有其特定的属性,我们将在下面列出。对于所有的通用样式属性,见 BaseNode
| 属性 | 描述 | 类型 | 默认值 | 必选 |
|---|---|---|---|---|
| donutFill | 填充色 | string | #1783FF |
|
| donutFillOpacity | 填充色透明度 | number | string | 1 | |
| donutLineCap | 描边端点样式 | round | square | butt |
butt |
|
| donutLineDash | 描边虚线样式 | number[] | - | |
| donutLineDashOffset | 描边虚线偏移量 | number | - | |
| donutLineJoin | 描边连接处样式 | round | bevel | miter |
miter |
|
| donutLineWidth | 描边宽度 | number | 1 | |
| donutOpacity | 透明度 | number | string | 1 | |
| donutPalette | 颜色或者色板名 | string | string[] | tableau |
|
| donuts | 圆环数据 | number[] | DonutRound[] | - | |
| donutShadowBlur | 阴影模糊度 | number | - | |
| donutShadowColor | 阴影颜色 | string | - | |
| donutShadowOffsetX | 阴影在 x 轴方向上的偏移量 | number | string | - | |
| donutShadowOffsetY | 阴影在 y 轴方向上的偏移量 | number | string | - | |
| donutShadowType | 阴影类型 | inner | outer |
outer |
|
| donutStroke | 描边色 | string | #000 |
|
| donutStrokeOpacity | 描边色透明度 | number | string | 1 | |
| donutVisibility | 图形是否可见 | visible | hidden |
visible |
|
| innerR | 内环半径,使用百分比或者像素值 | string | number | 50% |
DonutRound
| 属性 | 描述 | 类型 | 默认值 | 必选 |
|---|---|---|---|---|
| color | 颜色 | string | - | |
| fill | 填充色 | string | #1783FF |
|
| fillOpacity | 填充色透明度 | number | string | 1 | |
| lineCap | 描边端点样式 | round | square | butt |
butt |
|
| lineDash | 描边虚线样式 | number[] | - | |
| lineDashOffset | 描边虚线偏移量 | number | - | |
| lineJoin | 描边连接处样式 | round | bevel | miter |
miter |
|
| lineWidth | 描边宽度 | number | 1 | |
| opacity | 透明度 | number | string | 1 | |
| shadowBlur | 阴影模糊度 | number | - | |
| shadowColor | 阴影颜色 | string | - | |
| shadowOffsetX | 阴影在 x 轴方向上的偏移量 | number | string | - | |
| shadowOffsetY | 阴影在 y 轴方向上的偏移量 | number | string | - | |
| shadowType | 阴影类型 | inner | outer |
outer |
|
| stroke | 描边色 | string | #000 |
|
| strokeOpacity | 描边色透明度 | number | string | 1 | |
| value | 数值,用于计算比例 | number | - | ✓ |
| visibility | 图形是否可见 | visible | hidden |
visible |
示例
内置甜甜圈节点效果
import { Graph, iconfont } from '@antv/g6';
const style = document.createElement('style');
style.innerHTML = `@import url('${iconfont.css}');`;
document.head.appendChild(style);
const data = {
nodes: [
{ id: 'default', index: 0 },
{ id: 'halo', index: 1 },
{ id: 'badges', index: 2 },
{ id: 'ports', index: 3 },
{
id: 'active',
states: ['active'],
index: 4,
},
{
id: 'selected',
states: ['selected'],
index: 5,
},
{
id: 'highlight',
states: ['highlight'],
index: 6,
},
{
id: 'inactive',
states: ['inactive'],
index: 7,
},
{
id: 'disabled',
states: ['disabled'],
index: 8,
},
],
};
const graph = new Graph({
container: 'container',
animation: false,
data,
node: {
type: 'donut',
style: {
size: 80,
fill: '#DB9D0D',
innerR: 20,
donuts: (item) => {
const { index } = item;
if (index === 0) return [1, 2, 3]; // donuts数据类型为number[]时,根据值的大小决定环的占比
if (index === 1) {
return [
{ value: 50, color: 'red' },
{ value: 150, color: 'green' },
{ value: 100, color: 'blue' },
];
}
if (index === 4) {
return [
{ value: 150, fill: 'pink', stroke: '#fff', lineWidth: 1 },
{ value: 250, stroke: '#fff', lineWidth: 1 },
{ value: 200, stroke: '#fff', lineWidth: 1 },
];
}
return [100, 200, 100, 200];
},
labelText: (d) => d.id,
iconFontFamily: 'iconfont',
iconText: '\ue602',
halo: (d) => (d.id === 'halo' ? true : false),
badges: (d) =>
d.id === 'badges'
? [
{
text: 'A',
placement: 'right-top',
},
{
text: 'Important',
placement: 'right',
},
{
text: 'Notice',
placement: 'right-bottom',
},
]
: [],
badgeFontSize: 8,
badgePadding: [1, 4],
portR: 3,
ports: (d) =>
d.id === 'ports'
? [{ placement: 'left' }, { placement: 'right' }, { placement: 'top' }, { placement: 'bottom' }]
: [],
},
},
layout: {
type: 'grid',
},
});
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;
}