mirror of
https://gitee.com/antv/g6.git
synced 2024-11-29 18:28:19 +08:00
fix: drag group node
This commit is contained in:
parent
a367e01878
commit
862357583c
194
demos/area-chart-node.html
Normal file
194
demos/area-chart-node.html
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>面积图节点</title>
|
||||||
|
<style>
|
||||||
|
#mountNode {
|
||||||
|
background:#001528;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mountNode"></div>
|
||||||
|
<script src="../build/g6.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 该案例演示如何使用G6自定义面积图节点
|
||||||
|
* by 镜曦
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 自定义面积图节点
|
||||||
|
G6.registerNode('area', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
|
||||||
|
// Ref line
|
||||||
|
let refR = baseR;
|
||||||
|
const refInc = 10;
|
||||||
|
for(let i = 0; i< 6; i++){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: refR += refInc,
|
||||||
|
stroke:'rgba(255,255,255,0.4)',
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 ) / 360;
|
||||||
|
const tempIncValues = [baseR, baseR, baseR, baseR, baseR];
|
||||||
|
const allRs = [];
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
|
||||||
|
const oneRs = [];
|
||||||
|
cat.values.forEach((v, i) =>{
|
||||||
|
const R = tempIncValues[i] + v * 0.4;
|
||||||
|
oneRs.push(R);
|
||||||
|
tempIncValues[i] = R;
|
||||||
|
});
|
||||||
|
allRs.push(oneRs);
|
||||||
|
|
||||||
|
});
|
||||||
|
const strokeColors = [
|
||||||
|
'rgba(37,203,253,1)',
|
||||||
|
'rgba(254,255,123,1)',
|
||||||
|
'rgba(254,171,58,1)',
|
||||||
|
'rgba(254,87,102,1)',
|
||||||
|
'rgba(22,193,118,1)',
|
||||||
|
];
|
||||||
|
const fillColors = [
|
||||||
|
'rgba(37,203,253,0.5)',
|
||||||
|
'rgba(254,255,123,0.5)',
|
||||||
|
'rgba(254,171,58,0.5)',
|
||||||
|
'rgba(254,87,102,0.5)',
|
||||||
|
'rgba(22,193,118,0.5)',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
allRs.reverse().forEach((Rs, index) =>{
|
||||||
|
let curAngle = 0;
|
||||||
|
const poss = [];
|
||||||
|
Rs.forEach(r=>{
|
||||||
|
const xPos = r * Math.cos(curAngle);
|
||||||
|
const yPos = r * Math.sin(curAngle);
|
||||||
|
curAngle += everyIncAngle;
|
||||||
|
poss.push([xPos, yPos]);
|
||||||
|
});
|
||||||
|
const Ls = poss.map((p, i)=>{
|
||||||
|
if( i === 0 ){
|
||||||
|
return ["M", ...p]
|
||||||
|
}
|
||||||
|
return ["L", ...p]
|
||||||
|
});
|
||||||
|
console.log('Ls', ...Ls);
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
...Ls,
|
||||||
|
['Z'] // 封闭
|
||||||
|
],
|
||||||
|
stroke:strokeColors[index] ,
|
||||||
|
fill:fillColors[index],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
let nowAngle2 = 0;
|
||||||
|
const everyIncAngleCat = 2 * Math.PI * (360 / 5 ) / 360;
|
||||||
|
for(let i = 0; i < 5; i++){
|
||||||
|
const r = 30 + 60;
|
||||||
|
const xPos = r * Math.cos(nowAngle2);
|
||||||
|
const yPos = r * Math.sin(nowAngle2);
|
||||||
|
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ],
|
||||||
|
['L', xPos, yPos],
|
||||||
|
|
||||||
|
],
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
stroke: 'darkgray' // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nowAngle2 += everyIncAngleCat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加一个和背景色相同的圆形
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const graph = new G6.Graph({
|
||||||
|
container: 'mountNode',
|
||||||
|
width: 500,
|
||||||
|
height: 500
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'nodeD',
|
||||||
|
x: 150,
|
||||||
|
y: 200,
|
||||||
|
label: 'Area',
|
||||||
|
shape:'area',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.data(data)
|
||||||
|
graph.render()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
141
demos/bar-chart-node.html
Normal file
141
demos/bar-chart-node.html
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>环形柱状图节点</title>
|
||||||
|
<style>
|
||||||
|
#mountNode {
|
||||||
|
background:#001528;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mountNode"></div>
|
||||||
|
<script src="../build/g6.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 该案例演示如何自定义一个类似南丁格尔玫瑰一样的节点
|
||||||
|
* by 镜曦
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个类似南丁格尔玫瑰一样的节点
|
||||||
|
*/
|
||||||
|
G6.registerNode('circleBar', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
/*
|
||||||
|
G:
|
||||||
|
Fan
|
||||||
|
x: 扇形圆心的 x 坐标
|
||||||
|
y: 扇形圆心的 y 坐标
|
||||||
|
rs: 内圈半径
|
||||||
|
re: 外圈半径
|
||||||
|
startAngle: 起点弧度
|
||||||
|
endAngle: 终点弧度
|
||||||
|
clockwise: 为true时顺时针渲染,为false时逆时针渲染
|
||||||
|
*/
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
cat.values.forEach(item =>{
|
||||||
|
const re = item+baseR;
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:baseR,
|
||||||
|
re:item+baseR,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle: nowAngle += everyIncAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 加上交互动画
|
||||||
|
fan.on('mouseenter', function(evt) {
|
||||||
|
fan.animate({
|
||||||
|
re: re + 8,
|
||||||
|
repeat: false
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
fan.on('mouseleave', function(evt) {
|
||||||
|
fan.animate({
|
||||||
|
re:re,
|
||||||
|
repeat: false
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 设置class
|
||||||
|
fan.set("className", 'littleCircle');
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const graph = new G6.Graph({
|
||||||
|
container: 'mountNode',
|
||||||
|
width: 500,
|
||||||
|
height: 500
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'nodeA',
|
||||||
|
x: 150,
|
||||||
|
y: 150,
|
||||||
|
label: 'Bar',
|
||||||
|
shape:'circleBar',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.data(data)
|
||||||
|
graph.render()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
936
demos/chart-node.html
Normal file
936
demos/chart-node.html
Normal file
@ -0,0 +1,936 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>统计图表节点</title>
|
||||||
|
<style>
|
||||||
|
#mountNode {
|
||||||
|
background:#001528;
|
||||||
|
}
|
||||||
|
.graph-tooltip {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
border: 1px solid #e2e2e2;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #545454;
|
||||||
|
background-color: rgba(255, 255, 255, 0.9);
|
||||||
|
padding: 10px 8px;
|
||||||
|
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mountNode"></div>
|
||||||
|
<script src="../build/g6.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 该案例演示如何使用G6自定义面积图节点
|
||||||
|
* by 镜曦
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 注册一个类似南丁格尔玫瑰一样的节点
|
||||||
|
*/
|
||||||
|
G6.registerNode('circleBar', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
/*
|
||||||
|
G:
|
||||||
|
Fan
|
||||||
|
x: 扇形圆心的 x 坐标
|
||||||
|
y: 扇形圆心的 y 坐标
|
||||||
|
rs: 内圈半径
|
||||||
|
re: 外圈半径
|
||||||
|
startAngle: 起点弧度
|
||||||
|
endAngle: 终点弧度
|
||||||
|
clockwise: 为true时顺时针渲染,为false时逆时针渲染
|
||||||
|
*/
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
cat.values.forEach(item =>{
|
||||||
|
const re = item+baseR;
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:baseR,
|
||||||
|
re:item+baseR,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle: nowAngle += everyIncAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 加上交互动画
|
||||||
|
fan.on('mouseenter', function(evt) {
|
||||||
|
fan.animate({
|
||||||
|
re: re + 8,
|
||||||
|
repeat: false
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
fan.on('mouseleave', function(evt) {
|
||||||
|
fan.animate({
|
||||||
|
re:re,
|
||||||
|
repeat: false
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 设置class
|
||||||
|
fan.set("className", 'littleCircle');
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个 分布在圆周上的折线图
|
||||||
|
*/
|
||||||
|
G6.registerNode('circleLine', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
|
||||||
|
// Ref line
|
||||||
|
let refR = baseR;
|
||||||
|
const refInc = 10;
|
||||||
|
for(let i = 0; i< 5; i++){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: refR += refInc,
|
||||||
|
stroke:'rgba(255,255,255,0.4)',
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
// 计算一系列点的位置
|
||||||
|
const postions = [];
|
||||||
|
cat.values.forEach((item, index) =>{
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle);
|
||||||
|
const yPos = r * Math.sin(nowAngle);
|
||||||
|
nowAngle += everyIncAngle;
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
if(index === 4){
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle );
|
||||||
|
const yPos = r * Math.sin(nowAngle );
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const pathArrayL = postions.map(item =>(["L", ...item]));
|
||||||
|
// 添加连线
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ], // 上部顶点
|
||||||
|
...pathArrayL,
|
||||||
|
['Z'] // 封闭
|
||||||
|
],
|
||||||
|
stroke: cat.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 添加标注点
|
||||||
|
postions.forEach(( pos, index )=>{
|
||||||
|
if(index !== 5){
|
||||||
|
const littleCircle = group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: pos[0], // 居中
|
||||||
|
y: pos[1],
|
||||||
|
r: 2,
|
||||||
|
fill: 'black',
|
||||||
|
stroke:cat.color,
|
||||||
|
cursor: "pointer",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 加上交互动画
|
||||||
|
littleCircle.on('mouseenter', function(evt) {
|
||||||
|
littleCircle.animate({
|
||||||
|
r: 5,
|
||||||
|
repeat: false
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
littleCircle.on('mouseleave', function(evt) {
|
||||||
|
littleCircle.animate({
|
||||||
|
r: 2,
|
||||||
|
repeat: false
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
// 设置class
|
||||||
|
littleCircle.set("className", 'littleCircle');
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ], // 上部顶点
|
||||||
|
['L', width / 2, 0], // 右侧点
|
||||||
|
['L', 0, height / 2], // 下部
|
||||||
|
['L', - width / 2, 0], // 左侧
|
||||||
|
['Z'] // 封闭
|
||||||
|
],
|
||||||
|
stroke: cfg.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加一个和背景色相同的圆形
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个 只有标注点
|
||||||
|
*/
|
||||||
|
G6.registerNode('justPoints', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
|
||||||
|
// Ref line
|
||||||
|
let refR = baseR;
|
||||||
|
const refInc = 10;
|
||||||
|
for(let i = 0; i< 5; i++){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: refR += refInc,
|
||||||
|
stroke:'rgba(255,255,255,0.4)',
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
nowAngle = nowAngle + everyIncAngle / 2;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
// 计算一系列点的位置
|
||||||
|
const postions = [];
|
||||||
|
cat.values.forEach((item, index) =>{
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle);
|
||||||
|
const yPos = r * Math.sin(nowAngle);
|
||||||
|
nowAngle += everyIncAngle;
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
if(index === 4){
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle );
|
||||||
|
const yPos = r * Math.sin(nowAngle );
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// 添加标注点
|
||||||
|
postions.forEach(( pos, index )=>{
|
||||||
|
if(index !== 5){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: pos[0], // 居中
|
||||||
|
y: pos[1],
|
||||||
|
r: 2,
|
||||||
|
fill: 'black',
|
||||||
|
stroke:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ], // 上部顶点
|
||||||
|
['L', width / 2, 0], // 右侧点
|
||||||
|
['L', 0, height / 2], // 下部
|
||||||
|
['L', - width / 2, 0], // 左侧
|
||||||
|
['Z'] // 封闭
|
||||||
|
],
|
||||||
|
stroke: cfg.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
let nowAngle2 = 0;
|
||||||
|
const everyIncAngleCat = 2 * Math.PI * (360 / 5 ) / 360;
|
||||||
|
for(let i = 0; i < 5; i++){
|
||||||
|
const r = 30 + 50;
|
||||||
|
const xPos = r * Math.cos(nowAngle2);
|
||||||
|
const yPos = r * Math.sin(nowAngle2);
|
||||||
|
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ],
|
||||||
|
['L', xPos, yPos],
|
||||||
|
|
||||||
|
],
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
stroke: 'darkgray' // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nowAngle2 += everyIncAngleCat;
|
||||||
|
}
|
||||||
|
// 添加一个和背景色相同的圆形
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个 面积图节点
|
||||||
|
*/
|
||||||
|
G6.registerNode('area', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
|
||||||
|
// Ref line
|
||||||
|
let refR = baseR;
|
||||||
|
const refInc = 10;
|
||||||
|
for(let i = 0; i< 6; i++){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: refR += refInc,
|
||||||
|
stroke:'rgba(255,255,255,0.4)',
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 ) / 360;
|
||||||
|
const tempIncValues = [baseR, baseR, baseR, baseR, baseR];
|
||||||
|
const allRs = [];
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
|
||||||
|
const oneRs = [];
|
||||||
|
cat.values.forEach((v, i) =>{
|
||||||
|
const R = tempIncValues[i] + v * 0.4;
|
||||||
|
oneRs.push(R);
|
||||||
|
tempIncValues[i] = R;
|
||||||
|
});
|
||||||
|
allRs.push(oneRs);
|
||||||
|
|
||||||
|
});
|
||||||
|
const strokeColors = [
|
||||||
|
'rgba(37,203,253,1)',
|
||||||
|
'rgba(254,255,123,1)',
|
||||||
|
'rgba(254,171,58,1)',
|
||||||
|
'rgba(254,87,102,1)',
|
||||||
|
'rgba(22,193,118,1)',
|
||||||
|
];
|
||||||
|
const fillColors = [
|
||||||
|
'rgba(37,203,253,0.5)',
|
||||||
|
'rgba(254,255,123,0.5)',
|
||||||
|
'rgba(254,171,58,0.5)',
|
||||||
|
'rgba(254,87,102,0.5)',
|
||||||
|
'rgba(22,193,118,0.5)',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
allRs.reverse().forEach((Rs, index) =>{
|
||||||
|
let curAngle = 0;
|
||||||
|
const poss = [];
|
||||||
|
Rs.forEach(r=>{
|
||||||
|
const xPos = r * Math.cos(curAngle);
|
||||||
|
const yPos = r * Math.sin(curAngle);
|
||||||
|
curAngle += everyIncAngle;
|
||||||
|
poss.push([xPos, yPos]);
|
||||||
|
});
|
||||||
|
const Ls = poss.map((p, i)=>{
|
||||||
|
if( i === 0 ){
|
||||||
|
return ["M", ...p]
|
||||||
|
}
|
||||||
|
return ["L", ...p]
|
||||||
|
});
|
||||||
|
console.log('Ls', ...Ls);
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
...Ls,
|
||||||
|
['Z'] // 封闭
|
||||||
|
],
|
||||||
|
stroke:strokeColors[index] ,
|
||||||
|
fill:fillColors[index],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
let nowAngle2 = 0;
|
||||||
|
const everyIncAngleCat = 2 * Math.PI * (360 / 5 ) / 360;
|
||||||
|
for(let i = 0; i < 5; i++){
|
||||||
|
const r = 30 + 60;
|
||||||
|
const xPos = r * Math.cos(nowAngle2);
|
||||||
|
const yPos = r * Math.sin(nowAngle2);
|
||||||
|
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ],
|
||||||
|
['L', xPos, yPos],
|
||||||
|
|
||||||
|
],
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
stroke: 'darkgray' // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nowAngle2 += everyIncAngleCat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加一个和背景色相同的圆形
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
环 1
|
||||||
|
*/
|
||||||
|
G6.registerNode('rings1', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
/*
|
||||||
|
G:
|
||||||
|
Fan
|
||||||
|
x: 扇形圆心的 x 坐标
|
||||||
|
y: 扇形圆心的 y 坐标
|
||||||
|
rs: 内圈半径
|
||||||
|
re: 外圈半径
|
||||||
|
startAngle: 起点弧度
|
||||||
|
endAngle: 终点弧度
|
||||||
|
clockwise: 为true时顺时针渲染,为false时逆时针渲染
|
||||||
|
*/
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
cat.values.forEach(item =>{
|
||||||
|
const baseNbr = Math.ceil(item / 10);
|
||||||
|
const baseIncR = 7;
|
||||||
|
let nowStartR = baseR;
|
||||||
|
const last = item % 10;
|
||||||
|
const endAngle = nowAngle + everyIncAngle;
|
||||||
|
for (let i = 0; i < baseNbr ; i ++ ) {
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:nowStartR,
|
||||||
|
re:nowStartR + baseIncR,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle:endAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nowStartR = nowStartR + baseIncR + 2
|
||||||
|
if(i === baseNbr -1 && last !== 0){
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:nowStartR,
|
||||||
|
re:nowStartR + baseIncR * last / 10,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle:endAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nowAngle = endAngle
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个 面积图节点
|
||||||
|
*/
|
||||||
|
G6.registerNode('rings2', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
|
||||||
|
// Ref line
|
||||||
|
let refR = baseR;
|
||||||
|
const refInc = 10;
|
||||||
|
for(let i = 0; i< 6; i++){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: refR += refInc,
|
||||||
|
stroke:'rgba(255,255,255,0.4)',
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 ) / 360;
|
||||||
|
const tempIncValues = [baseR, baseR, baseR, baseR, baseR];
|
||||||
|
const allRs = [];
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
|
||||||
|
const oneRs = [];
|
||||||
|
cat.values.forEach((v, i) =>{
|
||||||
|
const R = tempIncValues[i] + v * 0.4;
|
||||||
|
oneRs.push(R);
|
||||||
|
tempIncValues[i] = R;
|
||||||
|
});
|
||||||
|
allRs.push(oneRs);
|
||||||
|
|
||||||
|
});
|
||||||
|
const strokeColors = [
|
||||||
|
'rgba(37,203,253,1)',
|
||||||
|
'rgba(254,255,123,1)',
|
||||||
|
'rgba(254,171,58,1)',
|
||||||
|
'rgba(254,87,102,1)',
|
||||||
|
'rgba(22,193,118,1)',
|
||||||
|
];
|
||||||
|
const fillColors = [
|
||||||
|
'rgba(37,203,253,0.5)',
|
||||||
|
'rgba(254,255,123,0.5)',
|
||||||
|
'rgba(254,171,58,0.5)',
|
||||||
|
'rgba(254,87,102,0.5)',
|
||||||
|
'rgba(22,193,118,0.5)',
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
allRs.reverse().forEach((Rs, index) =>{
|
||||||
|
let curAngle = 0;
|
||||||
|
const poss = [];
|
||||||
|
Rs.forEach(r=>{
|
||||||
|
|
||||||
|
const baseNbr = Math.ceil(r / 10);
|
||||||
|
const baseIncR = 7;
|
||||||
|
let nowStartR = baseR;
|
||||||
|
const last = r % 10;
|
||||||
|
|
||||||
|
for(let i = 0; i < baseNbr; i++){
|
||||||
|
|
||||||
|
const endAngle = nowAngle + everyIncAngle;
|
||||||
|
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:nowStartR,
|
||||||
|
re:nowStartR + baseIncR,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle:endAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:strokeColors[index],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nowStartR = nowStartR + baseIncR + 2
|
||||||
|
if(i === baseNbr -1 && last !== 0){
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:nowStartR,
|
||||||
|
re:nowStartR + baseIncR * last / 10,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle:endAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:strokeColors[index],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
nowAngle = endAngle
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加一个和背景色相同的圆形
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 数据 */
|
||||||
|
const data = {
|
||||||
|
nodes: [{
|
||||||
|
id: 'nodeA',
|
||||||
|
x: 150,
|
||||||
|
y: 150,
|
||||||
|
label: 'Bar',
|
||||||
|
shape:'circleBar',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'nodeB',
|
||||||
|
x: 400,
|
||||||
|
y: 150,
|
||||||
|
label: 'Line',
|
||||||
|
shape:'circleLine',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'nodeC',
|
||||||
|
x: 650,
|
||||||
|
y: 150,
|
||||||
|
label: 'Point',
|
||||||
|
shape:'justPoints',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'nodeD',
|
||||||
|
x: 150,
|
||||||
|
y: 400,
|
||||||
|
label: 'Area',
|
||||||
|
shape:'area',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'nodeF',
|
||||||
|
x: 400,
|
||||||
|
y: 400,
|
||||||
|
label: 'Rings1',
|
||||||
|
shape:'rings1',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,48,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,4,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,25,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
],
|
||||||
|
edges: [
|
||||||
|
//{source:'nodeA', target:'nodeB', color:"rgba(0, 255, 255, 0.5)"},
|
||||||
|
//{source:'nodeB', target:'nodeC', color:"rgba(0, 255, 255, 0.5)"},
|
||||||
|
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const graph = new G6.Graph({
|
||||||
|
container: 'mountNode',
|
||||||
|
width: 1000,
|
||||||
|
height: 600
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.on("node:mouseenter", function(event) {
|
||||||
|
var node = event.item;
|
||||||
|
var nodeId = node.get("model").id;
|
||||||
|
var shape = event.target;
|
||||||
|
|
||||||
|
if (shape.get("className") === "littleCircle") {
|
||||||
|
// 如果点击是发生在节点里面的小圆上,显示tooltip
|
||||||
|
console.log('x', event);
|
||||||
|
console.log('Y', event);
|
||||||
|
|
||||||
|
showTooltip("tooltip for " + nodeId, {
|
||||||
|
x: event.x,
|
||||||
|
y: event.y
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 否则隐藏tooltip
|
||||||
|
hideTooltip();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
graph.on("node:mouseleave", function(event) {
|
||||||
|
hideTooltip();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
graph.data(data);
|
||||||
|
graph.render();
|
||||||
|
|
||||||
|
var tooltipEl = null;
|
||||||
|
// 在指定的位置显示tooltip
|
||||||
|
function showTooltip(message, position) {
|
||||||
|
const offSetX = 50;
|
||||||
|
if (!tooltipEl) {
|
||||||
|
var container = document.getElementById("mountNode");
|
||||||
|
tooltipEl = document.createElement("div");
|
||||||
|
tooltipEl.setAttribute("class", "graph-tooltip");
|
||||||
|
container.appendChild(tooltipEl);
|
||||||
|
}
|
||||||
|
tooltipEl.textContent = message;
|
||||||
|
// tooltip是相对于画布canvas element绝对定位,所以position的x,y必须是相对于画布的坐标
|
||||||
|
tooltipEl.style.left = position.x + offSetX+ "px";
|
||||||
|
tooltipEl.style.top = position.y + "px";
|
||||||
|
tooltipEl.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏tooltip
|
||||||
|
function hideTooltip() {
|
||||||
|
if (!tooltipEl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tooltipEl.style.display = "none";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -40,6 +40,33 @@
|
|||||||
},
|
},
|
||||||
modes: {
|
modes: {
|
||||||
default: [ 'drag-canvas', 'zoom-canvas', 'collapse-expand-group' ]
|
default: [ 'drag-canvas', 'zoom-canvas', 'collapse-expand-group' ]
|
||||||
|
},
|
||||||
|
groupStyle: {
|
||||||
|
default: {
|
||||||
|
lineWidth: 2,
|
||||||
|
stroke: '#A3B1BF',
|
||||||
|
radius: 10,
|
||||||
|
lineDash: [ 5, 5 ],
|
||||||
|
strokeOpacity: 0.9,
|
||||||
|
fill: '#F3F9FF',
|
||||||
|
fillOpacity: 0.8,
|
||||||
|
opacity: 0.8
|
||||||
|
},
|
||||||
|
hover: {
|
||||||
|
stroke: '#faad14',
|
||||||
|
fill: '#ffe58f',
|
||||||
|
fillOpacity: 0.3,
|
||||||
|
opacity: 0.3,
|
||||||
|
lineWidth: 3
|
||||||
|
},
|
||||||
|
// 收起状态样式
|
||||||
|
collapseStyle: {
|
||||||
|
r: 50,
|
||||||
|
// lineDash: [ 5, 5 ],
|
||||||
|
stroke: '#ffa39e',
|
||||||
|
lineWidth: 3,
|
||||||
|
fill: '#ffccc7'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
587
demos/custom-tree-interactive.html
Normal file
587
demos/custom-tree-interactive.html
Normal file
@ -0,0 +1,587 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mountNode"></div>
|
||||||
|
<script src="../build/g6.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 该案例演示如何交互复杂的列表组件
|
||||||
|
* 内网可以参考:https://riddle.alibaba-inc.com/riddles/3acae792
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const COLLAPSE_ICON = (x, y, r) => {
|
||||||
|
return [
|
||||||
|
['M', x, y],
|
||||||
|
['a', r, r, 0, 1, 0, r * 2, 0],
|
||||||
|
['a', r, r, 0, 1, 0, -r * 2, 0],
|
||||||
|
['M', x + 2, y],
|
||||||
|
['L', x + 2 * r - 2, y],
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPAND_ICON = (x, y, r) => {
|
||||||
|
return [
|
||||||
|
['M', x, y],
|
||||||
|
['a', r, r, 0, 1, 0, r * 2, 0],
|
||||||
|
['a', r, r, 0, 1, 0, -r * 2, 0],
|
||||||
|
['M', x + 2, y],
|
||||||
|
['L', x + 2 * r - 2, y],
|
||||||
|
['M', x + r, y - r + 2],
|
||||||
|
['L', x + r, y + r - 2],
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
//注册边
|
||||||
|
G6.registerEdge('hvh', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const startPoint = cfg.startPoint;
|
||||||
|
const endPoint = cfg.endPoint;
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
endArrow: true,
|
||||||
|
endArrow: {
|
||||||
|
path: 'M 10,0 L -10,-10 L -10,10 Z',
|
||||||
|
d: 10,
|
||||||
|
},
|
||||||
|
stroke: '#A3B1BF',
|
||||||
|
path: [
|
||||||
|
['M', startPoint.x, startPoint.y],
|
||||||
|
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y],
|
||||||
|
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y],
|
||||||
|
['L', endPoint.x, endPoint.y],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return shape;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//root节点
|
||||||
|
G6.registerNode(
|
||||||
|
'tree-node',
|
||||||
|
{
|
||||||
|
drawShape: (cfg, group) => {
|
||||||
|
const rect = group.addShape('rect', {
|
||||||
|
attrs: {
|
||||||
|
fill: '#0096e0',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const content = cfg.name;
|
||||||
|
const text = group.addShape('text', {
|
||||||
|
attrs: {
|
||||||
|
text: content,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'left',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
fill: '#fff',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const bbox = text.getBBox();
|
||||||
|
const hasChildren = cfg.children && cfg.children.length > 0;
|
||||||
|
if (hasChildren) {
|
||||||
|
group.addShape('marker', {
|
||||||
|
attrs: {
|
||||||
|
x: bbox.maxX + 6,
|
||||||
|
y: bbox.minX + bbox.height / 2 - 6,
|
||||||
|
r: 6,
|
||||||
|
symbol: COLLAPSE_ICON,
|
||||||
|
stroke: '#fff',
|
||||||
|
lineWidth: 2,
|
||||||
|
},
|
||||||
|
className: 'collapse-icon',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//节点高度(getVGap值保持一致)
|
||||||
|
let height = 50;
|
||||||
|
//根节点高度:子节点高度+节点间距
|
||||||
|
let rootHeight = height * count + height * (count - 1);
|
||||||
|
//节点Y坐标
|
||||||
|
let nodeY = bbox.minY - 6;
|
||||||
|
//根节点Y坐标:节点Y坐标上移节点高度*count
|
||||||
|
let rootY = nodeY - height * (count - 1) + 12.5;
|
||||||
|
|
||||||
|
//console.log('rootHeight');
|
||||||
|
//console.log(rootHeight);
|
||||||
|
//console.log('rootY');
|
||||||
|
//console.log(rootY);
|
||||||
|
|
||||||
|
rect.attr({
|
||||||
|
x: bbox.minX - 4,
|
||||||
|
y: hasChildren ? rootY : nodeY,
|
||||||
|
width: bbox.width + (hasChildren ? 26 : 8),
|
||||||
|
height: hasChildren ? rootHeight : height,
|
||||||
|
});
|
||||||
|
return rect;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'single-shape',
|
||||||
|
);
|
||||||
|
|
||||||
|
//子节点
|
||||||
|
G6.registerNode('expandNode', {
|
||||||
|
draw: function draw(cfg, group) {
|
||||||
|
var mainGroup = group.addGroup({
|
||||||
|
id: 'main-group',
|
||||||
|
});
|
||||||
|
var keyShape = mainGroup.addShape('rect', {
|
||||||
|
attrs: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 100 + 60 * cfg.values.length,
|
||||||
|
height: 50,
|
||||||
|
fill: '#f5f5f5',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// name text
|
||||||
|
mainGroup.addShape('text', {
|
||||||
|
attrs: {
|
||||||
|
text: cfg.name,
|
||||||
|
fill: '#000',
|
||||||
|
width: 130,
|
||||||
|
x: 10,
|
||||||
|
y: 32,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var subGroup = group.addGroup({
|
||||||
|
id: 'sub-group',
|
||||||
|
});
|
||||||
|
cfg.values.forEach(function(data, index) {
|
||||||
|
subGroup.addShape('rect', {
|
||||||
|
attrs: {
|
||||||
|
x: 110 + index * 60,
|
||||||
|
y: 0,
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
subGroup.addShape('text', {
|
||||||
|
attrs: {
|
||||||
|
text: data.key,
|
||||||
|
fill: '#000',
|
||||||
|
x: 130 + index * 60,
|
||||||
|
y: 20,
|
||||||
|
fontSize: 10,
|
||||||
|
textBaseline: 'middle',
|
||||||
|
className: 'sub-group-text',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
subGroup.addShape('text', {
|
||||||
|
attrs: {
|
||||||
|
text: data.value,
|
||||||
|
fill: '#000',
|
||||||
|
x: 130 + index * 60,
|
||||||
|
y: 30,
|
||||||
|
fontSize: 10,
|
||||||
|
textBaseline: 'middle',
|
||||||
|
textAlign: 'left',
|
||||||
|
className: 'sub-group-text',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var listGroup = group.addGroup({
|
||||||
|
id: 'detail-list-group',
|
||||||
|
});
|
||||||
|
|
||||||
|
listGroup.addShape('rect', {
|
||||||
|
attrs: {
|
||||||
|
width: 100 + 60 * cfg.values.length - 70,
|
||||||
|
height: 30 * cfg.properties.length + 20,
|
||||||
|
fill: '#fff',
|
||||||
|
x: 70,
|
||||||
|
y: 30,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var rectWidth = 100 + 60 * cfg.values.length - 80;
|
||||||
|
cfg.properties.forEach(function(property, index) {
|
||||||
|
listGroup.addShape('rect', {
|
||||||
|
attrs: {
|
||||||
|
width: rectWidth,
|
||||||
|
height: 30,
|
||||||
|
fill: '#e8e8e8',
|
||||||
|
x: 80,
|
||||||
|
y: 40 * index + 40,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
var count = 0;
|
||||||
|
for (var p in property) {
|
||||||
|
// 每个rect中添加5个文本
|
||||||
|
listGroup.addShape('text', {
|
||||||
|
attrs: {
|
||||||
|
text: property[p],
|
||||||
|
fill: '#000',
|
||||||
|
x: 85 + count * (rectWidth / cfg.values.length) - count * 10,
|
||||||
|
y: 40 * index + 40 + 15,
|
||||||
|
fontSize: 10,
|
||||||
|
textBaseline: 'middle',
|
||||||
|
textAlign: 'left',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
listGroup.hide();
|
||||||
|
return keyShape;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//graph
|
||||||
|
const graph = new G6.TreeGraph({
|
||||||
|
container: 'mountNode',
|
||||||
|
width: window.innerWidth - 100,
|
||||||
|
height: window.innerHeight - 100,
|
||||||
|
modes: {
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
type: 'collapse-expand',
|
||||||
|
onChange: (item, collapsed) => {
|
||||||
|
const data = item.get('model').data;
|
||||||
|
const icon = item.get('group').findByClassName('collapse-icon');
|
||||||
|
if (collapsed) {
|
||||||
|
icon.attr('symbol', EXPAND_ICON);
|
||||||
|
} else {
|
||||||
|
icon.attr('symbol', COLLAPSE_ICON);
|
||||||
|
}
|
||||||
|
data.collapsed = collapsed;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'drag-canvas',
|
||||||
|
'zoom-canvas',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
defaultNode: {
|
||||||
|
shape: 'tree-node',
|
||||||
|
anchorPoints: [[0, 0.5], [1, 0.5]],
|
||||||
|
},
|
||||||
|
defaultEdge: {
|
||||||
|
shape: 'hvh',
|
||||||
|
},
|
||||||
|
edgeStyle: {
|
||||||
|
default: {
|
||||||
|
stroke: '#A3B1BF',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
type: 'compactBox',
|
||||||
|
direction: 'LR',
|
||||||
|
getId: d => {
|
||||||
|
return d.id;
|
||||||
|
},
|
||||||
|
getHeight: () => {
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
getWidth: () => {
|
||||||
|
return 16;
|
||||||
|
},
|
||||||
|
getVGap: d => {
|
||||||
|
return 50
|
||||||
|
},
|
||||||
|
getHGap: () => {
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
id: 'root',
|
||||||
|
name: 'root',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: 'shape2',
|
||||||
|
//x: 0,
|
||||||
|
//y: 50,
|
||||||
|
shape: 'expandNode',
|
||||||
|
name: '网站引流1',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
key: '曝光率',
|
||||||
|
value: '1938.33w',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '流入UV',
|
||||||
|
value: '1938.33w',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '点击率',
|
||||||
|
value: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '占比',
|
||||||
|
value: '99.9%',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
name: '宫格',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '更多应用',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '扫一扫',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '我的Tab',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'shape30',
|
||||||
|
//x: 0,
|
||||||
|
//y: 50,
|
||||||
|
shape: 'expandNode',
|
||||||
|
name: '网站引流',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
key: '曝光率',
|
||||||
|
value: '19.09',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '流入UV',
|
||||||
|
value: '910',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '点击率',
|
||||||
|
value: '90',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '占比',
|
||||||
|
value: '90',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
name: '宫格',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '更多应用',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '扫一扫',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '我的Tab',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'shape3',
|
||||||
|
//x: 0,
|
||||||
|
//y: 50,
|
||||||
|
shape: 'expandNode',
|
||||||
|
name: '网站引流',
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
key: '曝光率',
|
||||||
|
value: '19.09',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '流入UV',
|
||||||
|
value: '910',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '点击率',
|
||||||
|
value: '90',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '占比',
|
||||||
|
value: '90',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
name: '宫格',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '更多应用',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '扫一扫',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '我的Tab',
|
||||||
|
value1: '1938.33w',
|
||||||
|
value2: '1938.33w',
|
||||||
|
value3: '99.9%',
|
||||||
|
value4: '99.9%',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
//统计子节点个数
|
||||||
|
let count = -1;
|
||||||
|
|
||||||
|
G6.Util.traverseTree(data, e => {
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.data(data);
|
||||||
|
graph.render();
|
||||||
|
graph.fitView();
|
||||||
|
|
||||||
|
// 点击node,展开详情
|
||||||
|
graph.on('node:click', function(evt) {
|
||||||
|
console.log(graph);
|
||||||
|
|
||||||
|
var target = evt.target;
|
||||||
|
var parentGroup = target.get('parent').get('parent');
|
||||||
|
var detailGroup = parentGroup.findById('detail-list-group');
|
||||||
|
// 将sub-group中的内容网上移动一段距离
|
||||||
|
var subGroup = parentGroup.findById('sub-group');
|
||||||
|
var keyTexts = subGroup.findAll(function(item) {
|
||||||
|
return item.attr('className') === 'sub-group-text';
|
||||||
|
});
|
||||||
|
var isVisible = detailGroup.get('visible');
|
||||||
|
if (isVisible) {
|
||||||
|
detailGroup.hide();
|
||||||
|
keyTexts.forEach(function(text) {
|
||||||
|
var top = text.attr('y');
|
||||||
|
text.attr('y', top + 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
const layout = {
|
||||||
|
type: 'compactBox',
|
||||||
|
direction: 'LR',
|
||||||
|
getId: d => {
|
||||||
|
return d.id;
|
||||||
|
},
|
||||||
|
getHeight: () => {
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
getWidth: () => {
|
||||||
|
return 16;
|
||||||
|
},
|
||||||
|
getVGap: d => {
|
||||||
|
return 50
|
||||||
|
},
|
||||||
|
getHGap: () => {
|
||||||
|
return 80;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.changeLayout(layout)
|
||||||
|
} else {
|
||||||
|
keyTexts.forEach(function(text) {
|
||||||
|
var top = text.attr('y');
|
||||||
|
text.attr('y', top - 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
detailGroup.show();
|
||||||
|
|
||||||
|
const layout = {
|
||||||
|
type: 'compactBox',
|
||||||
|
direction: 'LR',
|
||||||
|
getId: d => {
|
||||||
|
return d.id;
|
||||||
|
},
|
||||||
|
getHeight: () => {
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
getWidth: () => {
|
||||||
|
return 16;
|
||||||
|
},
|
||||||
|
getVGap: d => {
|
||||||
|
console.log('ok', d, evt);
|
||||||
|
const id = evt.item.get('id');
|
||||||
|
if (d.id === id) {
|
||||||
|
return 120;
|
||||||
|
} else {
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getHGap: () => {
|
||||||
|
return 80;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.changeLayout(layout)
|
||||||
|
|
||||||
|
}
|
||||||
|
//graph.paint();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -60,7 +60,6 @@
|
|||||||
document.getElementById('changeView').addEventListener('click', (evt) => {
|
document.getElementById('changeView').addEventListener('click', (evt) => {
|
||||||
const edge=graph.findById('edge1')
|
const edge=graph.findById('edge1')
|
||||||
const nodeGroup = graph.get('nodeGroup')
|
const nodeGroup = graph.get('nodeGroup')
|
||||||
const edgeGroup = graph.get('edgeGroup')
|
|
||||||
const edge1G = edge.get('group')
|
const edge1G = edge.get('group')
|
||||||
edge1G.toFront()
|
edge1G.toFront()
|
||||||
nodeGroup.toBack();
|
nodeGroup.toBack();
|
||||||
|
194
demos/line-chart-node.html
Normal file
194
demos/line-chart-node.html
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>折线图节点</title>
|
||||||
|
<style>
|
||||||
|
#mountNode {
|
||||||
|
background:#001528;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mountNode"></div>
|
||||||
|
<script src="../build/g6.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 该案例演示如何自定义一个折线图节点
|
||||||
|
* by 镜曦
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 自定义折线图节点
|
||||||
|
G6.registerNode('circleLine', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
|
||||||
|
// Ref line
|
||||||
|
let refR = baseR;
|
||||||
|
const refInc = 10;
|
||||||
|
for(let i = 0; i< 5; i++){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: refR += refInc,
|
||||||
|
stroke:'rgba(255,255,255,0.4)',
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
// 计算一系列点的位置
|
||||||
|
const postions = [];
|
||||||
|
cat.values.forEach((item, index) =>{
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle);
|
||||||
|
const yPos = r * Math.sin(nowAngle);
|
||||||
|
nowAngle += everyIncAngle;
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
if(index === 4){
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle );
|
||||||
|
const yPos = r * Math.sin(nowAngle );
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const pathArrayL = postions.map(item =>(["L", ...item]));
|
||||||
|
// 添加连线
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ], // 上部顶点
|
||||||
|
...pathArrayL,
|
||||||
|
['Z'] // 封闭
|
||||||
|
],
|
||||||
|
stroke: cat.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 添加标注点
|
||||||
|
postions.forEach(( pos, index )=>{
|
||||||
|
if(index !== 5){
|
||||||
|
const littleCircle = group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: pos[0], // 居中
|
||||||
|
y: pos[1],
|
||||||
|
r: 2,
|
||||||
|
fill: 'black',
|
||||||
|
stroke:cat.color,
|
||||||
|
cursor: "pointer",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 加上交互动画
|
||||||
|
littleCircle.on('mouseenter', function(evt) {
|
||||||
|
littleCircle.animate({
|
||||||
|
r: 5,
|
||||||
|
repeat: false
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
littleCircle.on('mouseleave', function(evt) {
|
||||||
|
littleCircle.animate({
|
||||||
|
r: 2,
|
||||||
|
repeat: false
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
// 设置class
|
||||||
|
littleCircle.set("className", 'littleCircle');
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ], // 上部顶点
|
||||||
|
['L', width / 2, 0], // 右侧点
|
||||||
|
['L', 0, height / 2], // 下部
|
||||||
|
['L', - width / 2, 0], // 左侧
|
||||||
|
['Z'] // 封闭
|
||||||
|
],
|
||||||
|
stroke: cfg.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加一个和背景色相同的圆形
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const graph = new G6.Graph({
|
||||||
|
container: 'mountNode',
|
||||||
|
width: 500,
|
||||||
|
height: 500
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'nodeB',
|
||||||
|
x: 400,
|
||||||
|
y: 150,
|
||||||
|
label: 'Line',
|
||||||
|
shape:'circleLine',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.data(data)
|
||||||
|
graph.render()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
173
demos/point-chart-node.html
Normal file
173
demos/point-chart-node.html
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>标注图节点</title>
|
||||||
|
<style>
|
||||||
|
#mountNode {
|
||||||
|
background:#001528;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mountNode"></div>
|
||||||
|
<script src="../build/g6.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 该案例演示如何自定义一个标注点节点
|
||||||
|
* by 镜曦
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 自定义标注点节点
|
||||||
|
G6.registerNode('justPoints', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
|
||||||
|
// Ref line
|
||||||
|
let refR = baseR;
|
||||||
|
const refInc = 10;
|
||||||
|
for(let i = 0; i< 5; i++){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: refR += refInc,
|
||||||
|
stroke:'rgba(255,255,255,0.4)',
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
nowAngle = nowAngle + everyIncAngle / 2;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
// 计算一系列点的位置
|
||||||
|
const postions = [];
|
||||||
|
cat.values.forEach((item, index) =>{
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle);
|
||||||
|
const yPos = r * Math.sin(nowAngle);
|
||||||
|
nowAngle += everyIncAngle;
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
if(index === 4){
|
||||||
|
const r = baseR + item;
|
||||||
|
const xPos = r * Math.cos(nowAngle );
|
||||||
|
const yPos = r * Math.sin(nowAngle );
|
||||||
|
postions.push([xPos, yPos]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// 添加标注点
|
||||||
|
postions.forEach(( pos, index )=>{
|
||||||
|
if(index !== 5){
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: pos[0], // 居中
|
||||||
|
y: pos[1],
|
||||||
|
r: 2,
|
||||||
|
fill: 'black',
|
||||||
|
stroke:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
let nowAngle2 = 0;
|
||||||
|
const everyIncAngleCat = 2 * Math.PI * (360 / 5 ) / 360;
|
||||||
|
for(let i = 0; i < 5; i++){
|
||||||
|
const r = 30 + 50;
|
||||||
|
const xPos = r * Math.cos(nowAngle2);
|
||||||
|
const yPos = r * Math.sin(nowAngle2);
|
||||||
|
|
||||||
|
const shape = group.addShape('path', {
|
||||||
|
attrs: {
|
||||||
|
path: [
|
||||||
|
['M', 0, 0 ],
|
||||||
|
['L', xPos, yPos],
|
||||||
|
|
||||||
|
],
|
||||||
|
lineDash:[4, 4],
|
||||||
|
|
||||||
|
stroke: 'darkgray' // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nowAngle2 += everyIncAngleCat;
|
||||||
|
}
|
||||||
|
// 添加一个和背景色相同的圆形
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const graph = new G6.Graph({
|
||||||
|
container: 'mountNode',
|
||||||
|
width: 500,
|
||||||
|
height: 500
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'nodeC',
|
||||||
|
x: 250,
|
||||||
|
y: 150,
|
||||||
|
label: 'Point',
|
||||||
|
shape:'justPoints',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.data(data)
|
||||||
|
graph.render()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
146
demos/stacked-bar-chart-node.html
Normal file
146
demos/stacked-bar-chart-node.html
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>堆叠柱状图节点</title>
|
||||||
|
<style>
|
||||||
|
#mountNode {
|
||||||
|
background:#001528;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="mountNode"></div>
|
||||||
|
<script src="../build/g6.js"></script>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 该案例演示如何自定义一个堆叠柱状图节点
|
||||||
|
* by 镜曦
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 自定义标注点节点
|
||||||
|
G6.registerNode('stacked-bar-node', {
|
||||||
|
draw(cfg, group) {
|
||||||
|
const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
||||||
|
const width = size[0];
|
||||||
|
const height = size[1];
|
||||||
|
/*
|
||||||
|
G:
|
||||||
|
Fan
|
||||||
|
x: 扇形圆心的 x 坐标
|
||||||
|
y: 扇形圆心的 y 坐标
|
||||||
|
rs: 内圈半径
|
||||||
|
re: 外圈半径
|
||||||
|
startAngle: 起点弧度
|
||||||
|
endAngle: 终点弧度
|
||||||
|
clockwise: 为true时顺时针渲染,为false时逆时针渲染
|
||||||
|
*/
|
||||||
|
const baseR = 30;
|
||||||
|
let nowAngle = 0;
|
||||||
|
const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
||||||
|
cfg.details.forEach(cat =>{
|
||||||
|
cat.values.forEach(item =>{
|
||||||
|
const baseNbr = Math.ceil(item / 10);
|
||||||
|
const baseIncR = 7;
|
||||||
|
let nowStartR = baseR;
|
||||||
|
const last = item % 10;
|
||||||
|
const endAngle = nowAngle + everyIncAngle;
|
||||||
|
for (let i = 0; i < baseNbr ; i ++ ) {
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:nowStartR,
|
||||||
|
re:nowStartR + baseIncR,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle:endAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nowStartR = nowStartR + baseIncR + 2
|
||||||
|
if(i === baseNbr -1 && last !== 0){
|
||||||
|
const fan = group.addShape('fan', {
|
||||||
|
attrs:{
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
rs:nowStartR,
|
||||||
|
re:nowStartR + baseIncR * last / 10,
|
||||||
|
startAngle:nowAngle,
|
||||||
|
endAngle:endAngle,
|
||||||
|
clockwise:false,
|
||||||
|
stroke: 'darkgray',
|
||||||
|
fill:cat.color,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nowAngle = endAngle
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.addShape('circle', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
r: baseR,
|
||||||
|
fill: cfg.centerColor,
|
||||||
|
stroke:'darkgray',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(cfg.label) {
|
||||||
|
group.addShape('text', {
|
||||||
|
// attrs: style
|
||||||
|
attrs: {
|
||||||
|
x: 0, // 居中
|
||||||
|
y: 0,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'middle',
|
||||||
|
text: cfg.label,
|
||||||
|
fill: 'white',
|
||||||
|
fontStyle:'bold',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const graph = new G6.Graph({
|
||||||
|
container: 'mountNode',
|
||||||
|
width: 500,
|
||||||
|
height: 500
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
id: 'nodeF',
|
||||||
|
x: 100,
|
||||||
|
y: 100,
|
||||||
|
label: 'StackedBar',
|
||||||
|
shape:'stacked-bar-node',
|
||||||
|
anchorPoints: [
|
||||||
|
[0, 0.5], [1, 0.5]
|
||||||
|
],
|
||||||
|
details:[
|
||||||
|
{cat:'pv', values:[20,30,48,30,30], color:"#25cbfd"},
|
||||||
|
{cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
||||||
|
{cat:'uv', values:[40,30,30,4,40], color:"#feab3a"},
|
||||||
|
{cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
||||||
|
{cat:'cal', values:[10,10,25,20,20], color:"#16c176"},
|
||||||
|
],
|
||||||
|
centerColor:'#0066FF'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.data(data)
|
||||||
|
graph.render()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -98,7 +98,7 @@
|
|||||||
"screenshot": "node ./bin/screenshot.js",
|
"screenshot": "node ./bin/screenshot.js",
|
||||||
"start": "npm run dev",
|
"start": "npm run dev",
|
||||||
"test": "torch --compile --renderer --opts test/mocha.opts --recursive ./test/unit",
|
"test": "torch --compile --renderer --opts test/mocha.opts --recursive ./test/unit",
|
||||||
"test-live": "torch --compile --interactive --watch --opts test/mocha.opts --recursive ./test/unit/behavior/drag-group-spec.js",
|
"test-live": "torch --compile --interactive --watch --opts test/mocha.opts --recursive ./test/unit/graph/controller/custom-group-spec.js",
|
||||||
"test-live-tree": "torch --compile --interactive --watch --opts test/mocha.opts --recursive ./test/unit/graph/tree-graph-spec.js",
|
"test-live-tree": "torch --compile --interactive --watch --opts test/mocha.opts --recursive ./test/unit/graph/tree-graph-spec.js",
|
||||||
"test-bugs": "torch --compile --renderer --recursive ./test/bugs",
|
"test-bugs": "torch --compile --renderer --recursive ./test/bugs",
|
||||||
"test-bugs-live": "torch --compile --interactive --watch --recursive ./test/bugs",
|
"test-bugs-live": "torch --compile --interactive --watch --recursive ./test/bugs",
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* @LastEditTime: 2019-08-23 11:13:43
|
* @LastEditTime: 2019-08-23 11:13:43
|
||||||
* @Description: 拖动群组
|
* @Description: 拖动群组
|
||||||
*/
|
*/
|
||||||
const { merge } = require('lodash');
|
const deepMix = require('@antv/util/lib/deep-mix');
|
||||||
|
|
||||||
const delegateStyle = {
|
const delegateStyle = {
|
||||||
fill: '#F3F9FF',
|
fill: '#F3F9FF',
|
||||||
@ -275,7 +275,7 @@ module.exports = {
|
|||||||
height,
|
height,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
...merge({}, delegateStyle, this.delegateStyle)
|
...deepMix({}, delegateStyle, this.delegateStyle)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 如果delegate是circle
|
// 如果delegate是circle
|
||||||
@ -289,7 +289,7 @@ module.exports = {
|
|||||||
x: cx,
|
x: cx,
|
||||||
y: cy,
|
y: cy,
|
||||||
r,
|
r,
|
||||||
...merge({}, delegateStyle, this.delegateStyle)
|
...deepMix({}, delegateStyle, this.delegateStyle)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.shapeOrigin = { x: cx, y: cy };
|
self.shapeOrigin = { x: cx, y: cy };
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* @LastEditTime: 2019-08-23 13:54:53
|
* @LastEditTime: 2019-08-23 13:54:53
|
||||||
* @Description: 有group的情况下,拖动节点的Behavior
|
* @Description: 有group的情况下,拖动节点的Behavior
|
||||||
*/
|
*/
|
||||||
const { merge } = require('lodash');
|
const deepMix = require('@antv/util/lib/deep-mix');
|
||||||
const { delegateStyle } = require('../global');
|
const { delegateStyle } = require('../global');
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
|
|
||||||
@ -15,8 +15,8 @@ module.exports = {
|
|||||||
updateEdge: true,
|
updateEdge: true,
|
||||||
delegate: true,
|
delegate: true,
|
||||||
delegateStyle: {},
|
delegateStyle: {},
|
||||||
maxMultiple: 1.2,
|
maxMultiple: 0.9,
|
||||||
minMultiple: 0.8
|
minMultiple: 1
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getEvents() {
|
getEvents() {
|
||||||
@ -26,12 +26,16 @@ module.exports = {
|
|||||||
'node:dragend': 'onDragEnd',
|
'node:dragend': 'onDragEnd',
|
||||||
'canvas:mouseleave': 'onOutOfRange',
|
'canvas:mouseleave': 'onOutOfRange',
|
||||||
mouseenter: 'onMouseEnter',
|
mouseenter: 'onMouseEnter',
|
||||||
mouseout: 'onMouseOut'
|
mouseleave: 'onMouseLeave'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onMouseEnter(evt) {
|
onMouseEnter(evt) {
|
||||||
const { target } = evt;
|
const { target } = evt;
|
||||||
const groupId = target.get('groupId');
|
const groupId = target.get('groupId');
|
||||||
|
const type = target.get('type');
|
||||||
|
if (type !== 'circle') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (groupId && this.origin) {
|
if (groupId && this.origin) {
|
||||||
const graph = this.graph;
|
const graph = this.graph;
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
const customGroupControll = graph.get('customGroupControll');
|
||||||
@ -47,7 +51,7 @@ module.exports = {
|
|||||||
* 拖动节点移除Group时的事件
|
* 拖动节点移除Group时的事件
|
||||||
* @param {Event} evt 事件句柄
|
* @param {Event} evt 事件句柄
|
||||||
*/
|
*/
|
||||||
onMouseOut(evt) {
|
onMouseLeave(evt) {
|
||||||
const { target } = evt;
|
const { target } = evt;
|
||||||
const groupId = target.get('groupId');
|
const groupId = target.get('groupId');
|
||||||
if (groupId && this.origin) {
|
if (groupId && this.origin) {
|
||||||
@ -59,7 +63,10 @@ module.exports = {
|
|||||||
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'default');
|
customGroupControll.setGroupStyle(keyShape, 'default');
|
||||||
}
|
}
|
||||||
this.inGroupId = null;
|
|
||||||
|
if (!groupId) {
|
||||||
|
this.inGroupId = null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onDragStart(e) {
|
onDragStart(e) {
|
||||||
if (!this.shouldBegin.call(this, e)) {
|
if (!this.shouldBegin.call(this, e)) {
|
||||||
@ -93,6 +100,9 @@ module.exports = {
|
|||||||
const customGroup = customGroupControll.customGroup;
|
const customGroup = customGroupControll.customGroup;
|
||||||
const currentGroup = customGroup[groupId].nodeGroup;
|
const currentGroup = customGroup[groupId].nodeGroup;
|
||||||
customGroupControll.setGroupStyle(currentGroup.get('keyShape'), 'hover');
|
customGroupControll.setGroupStyle(currentGroup.get('keyShape'), 'hover');
|
||||||
|
|
||||||
|
// 初始拖动时候,如果是在当前群组中拖动,则赋值为当前groupId
|
||||||
|
this.inGroupId = groupId;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 拖动多个节点
|
// 拖动多个节点
|
||||||
@ -137,13 +147,8 @@ module.exports = {
|
|||||||
const currentGroup = customGroup[groupId].nodeGroup;
|
const currentGroup = customGroup[groupId].nodeGroup;
|
||||||
const keyShape = currentGroup.get('keyShape');
|
const keyShape = currentGroup.get('keyShape');
|
||||||
|
|
||||||
const currentGroupBBox = keyShape.getBBox();
|
// 当前
|
||||||
|
if (this.inGroupId !== groupId) {
|
||||||
const delegateShape = this.target.get('delegateShape');
|
|
||||||
const { x, y } = delegateShape.getBBox();
|
|
||||||
const { minX, minY, maxX, maxY } = currentGroupBBox;
|
|
||||||
|
|
||||||
if (x > maxX || x < minX || y > maxY || y < minY) {
|
|
||||||
customGroupControll.setGroupStyle(keyShape, 'default');
|
customGroupControll.setGroupStyle(keyShape, 'default');
|
||||||
} else {
|
} else {
|
||||||
customGroupControll.setGroupStyle(keyShape, 'hover');
|
customGroupControll.setGroupStyle(keyShape, 'hover');
|
||||||
@ -224,11 +229,12 @@ module.exports = {
|
|||||||
// 检测操作的群组中是否包括子群组
|
// 检测操作的群组中是否包括子群组
|
||||||
const groups = graph.get('groups');
|
const groups = graph.get('groups');
|
||||||
const hasSubGroup = !!groups.filter(g => g.parentId === groupId).length > 0;
|
const hasSubGroup = !!groups.filter(g => g.parentId === groupId).length > 0;
|
||||||
const r = width > height ? width / 2 : height / 2 + (hasSubGroup ? 20 : 0);
|
const addR = hasSubGroup ? 20 : 10;
|
||||||
|
const r = width > height ? width / 2 : height / 2;
|
||||||
const cx = (width + 2 * x) / 2;
|
const cx = (width + 2 * x) / 2;
|
||||||
const cy = (height + 2 * y) / 2;
|
const cy = (height + 2 * y) / 2;
|
||||||
keyShape.attr({
|
keyShape.attr({
|
||||||
r: r + groupNodes[groupId].length * 10,
|
r: r + groupNodes[groupId].length * 10 + addR,
|
||||||
x: cx,
|
x: cx,
|
||||||
y: cy
|
y: cy
|
||||||
});
|
});
|
||||||
@ -247,7 +253,6 @@ module.exports = {
|
|||||||
// 节点所在的GroupId
|
// 节点所在的GroupId
|
||||||
const { groupId, id } = model;
|
const { groupId, id } = model;
|
||||||
|
|
||||||
// console.log(groupId, this.inGroupId)
|
|
||||||
const customGroupControll = graph.get('customGroupControll');
|
const customGroupControll = graph.get('customGroupControll');
|
||||||
const customGroup = customGroupControll.customGroup;
|
const customGroup = customGroupControll.customGroup;
|
||||||
const groupNodes = graph.get('groupNodes');
|
const groupNodes = graph.get('groupNodes');
|
||||||
@ -262,7 +267,11 @@ module.exports = {
|
|||||||
const { minX, minY, maxX, maxY } = currentGroupBBox;
|
const { minX, minY, maxX, maxY } = currentGroupBBox;
|
||||||
|
|
||||||
// 在自己的group中拖动,判断是否拖出了自己的group
|
// 在自己的group中拖动,判断是否拖出了自己的group
|
||||||
if (!(x < maxX * this.maxMultiple && x > minX * this.minMultiple && y < maxY * this.maxMultiple && y > minY * this.minMultiple)) {
|
// this.inGroupId !== groupId,则说明拖出了原来的group,拖到了其他group上面,
|
||||||
|
// 则删除item中的groupId字段,同时删除group中的nodeID
|
||||||
|
if (
|
||||||
|
!(x < maxX * this.maxMultiple && x > minX * this.minMultiple && y < maxY * this.maxMultiple && y > minY * this.minMultiple)
|
||||||
|
|| this.inGroupId !== groupId) {
|
||||||
// 拖出了group,则删除item中的groupId字段,同时删除group中的nodeID
|
// 拖出了group,则删除item中的groupId字段,同时删除group中的nodeID
|
||||||
const currentGroupNodes = groupNodes[groupId];
|
const currentGroupNodes = groupNodes[groupId];
|
||||||
groupNodes[groupId] = currentGroupNodes.filter(node => node !== id);
|
groupNodes[groupId] = currentGroupNodes.filter(node => node !== id);
|
||||||
@ -274,8 +283,10 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
// 拖动到其他的group上面
|
// 拖动到其他的group上面
|
||||||
if (this.inGroupId !== groupId) {
|
if (this.inGroupId !== groupId) {
|
||||||
|
|
||||||
|
// 拖动新的group后,更新groupNodes及model中的groupId
|
||||||
const nodeInGroup = customGroup[this.inGroupId].nodeGroup;
|
const nodeInGroup = customGroup[this.inGroupId].nodeGroup;
|
||||||
const keyShape = nodeInGroup.get('keyShape');
|
const targetKeyShape = nodeInGroup.get('keyShape');
|
||||||
// 将该节点添加到inGroupId中
|
// 将该节点添加到inGroupId中
|
||||||
if (groupNodes[this.inGroupId].indexOf(id) === -1) {
|
if (groupNodes[this.inGroupId].indexOf(id) === -1) {
|
||||||
groupNodes[this.inGroupId].push(id);
|
groupNodes[this.inGroupId].push(id);
|
||||||
@ -284,7 +295,7 @@ module.exports = {
|
|||||||
model.groupId = this.inGroupId;
|
model.groupId = this.inGroupId;
|
||||||
|
|
||||||
// 拖入节点后,根据最新的节点数量,重新计算群组大小
|
// 拖入节点后,根据最新的节点数量,重新计算群组大小
|
||||||
this.dynamicChangeGroupSize(evt, nodeInGroup, keyShape);
|
this.dynamicChangeGroupSize(evt, nodeInGroup, targetKeyShape);
|
||||||
}
|
}
|
||||||
customGroupControll.setGroupStyle(keyShape, 'default');
|
customGroupControll.setGroupStyle(keyShape, 'default');
|
||||||
} else if (this.inGroupId && !groupId) {
|
} else if (this.inGroupId && !groupId) {
|
||||||
@ -372,7 +383,7 @@ module.exports = {
|
|||||||
if (!this.shape) {
|
if (!this.shape) {
|
||||||
// 拖动多个
|
// 拖动多个
|
||||||
const parent = graph.get('group');
|
const parent = graph.get('group');
|
||||||
const attrs = merge({}, delegateStyle, this.delegateStyle);
|
const attrs = deepMix({}, delegateStyle, this.delegateStyle);
|
||||||
if (this.targets.length > 0) {
|
if (this.targets.length > 0) {
|
||||||
const nodes = graph.findAllByState('node', 'selected');
|
const nodes = graph.findAllByState('node', 'selected');
|
||||||
if (nodes.length === 0) {
|
if (nodes.length === 0) {
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
* @LastEditTime: 2019-08-22 18:41:45
|
* @LastEditTime: 2019-08-22 18:41:45
|
||||||
* @Description: 拖动节点的Behavior
|
* @Description: 拖动节点的Behavior
|
||||||
*/
|
*/
|
||||||
const { merge, isString } = require('lodash');
|
const isString = require('@antv/util/lib/type/is-string');
|
||||||
|
const deepMix = require('@antv/util/lib/deep-mix');
|
||||||
const { delegateStyle } = require('../global');
|
const { delegateStyle } = require('../global');
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ module.exports = {
|
|||||||
if (!this.shape) {
|
if (!this.shape) {
|
||||||
// 拖动多个
|
// 拖动多个
|
||||||
const parent = this.graph.get('group');
|
const parent = this.graph.get('group');
|
||||||
const attrs = merge({}, delegateStyle, this.delegateStyle);
|
const attrs = deepMix({}, delegateStyle, this.delegateStyle);
|
||||||
if (this.targets.length > 0) {
|
if (this.targets.length > 0) {
|
||||||
const { x, y, width, height, minX, minY } = this.calculationGroupPosition();
|
const { x, y, width, height, minX, minY } = this.calculationGroupPosition();
|
||||||
this.originPoint = { x, y, width, height, minX, minY };
|
this.originPoint = { x, y, width, height, minX, minY };
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
* @LastEditTime: 2019-08-23 11:44:32
|
* @LastEditTime: 2019-08-23 11:44:32
|
||||||
* @Description: Group Controller
|
* @Description: Group Controller
|
||||||
*/
|
*/
|
||||||
const { merge, isString } = require('lodash');
|
const isString = require('@antv/util/lib/type/is-string');
|
||||||
|
const deepMix = require('@antv/util/lib/deep-mix');
|
||||||
class CustomGroup {
|
class CustomGroup {
|
||||||
getDefaultCfg() {
|
getDefaultCfg() {
|
||||||
return {
|
return {
|
||||||
@ -60,7 +60,8 @@ class CustomGroup {
|
|||||||
// const { cfg = {} } = options;
|
// const { cfg = {} } = options;
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
window.graph = graph;
|
window.graph = graph;
|
||||||
this.styles = this.getDefaultCfg();
|
const groupStyle = graph.get('groupStyle');
|
||||||
|
this.styles = deepMix({}, this.getDefaultCfg(), groupStyle);
|
||||||
// 创建的群组集合
|
// 创建的群组集合
|
||||||
this.customGroup = {};
|
this.customGroup = {};
|
||||||
// 群组初始位置集合
|
// 群组初始位置集合
|
||||||
@ -154,12 +155,12 @@ class CustomGroup {
|
|||||||
const { hover: hoverStyle, default: defaultStyle } = this.styles;
|
const { hover: hoverStyle, default: defaultStyle } = this.styles;
|
||||||
if (isString(style)) {
|
if (isString(style)) {
|
||||||
if (style === 'default') {
|
if (style === 'default') {
|
||||||
styles = merge({}, defaultStyle);
|
styles = deepMix({}, defaultStyle);
|
||||||
} else if (style === 'hover') {
|
} else if (style === 'hover') {
|
||||||
styles = merge({}, hoverStyle);
|
styles = deepMix({}, hoverStyle);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
styles = merge({}, defaultStyle, style);
|
styles = deepMix({}, defaultStyle, style);
|
||||||
}
|
}
|
||||||
for (const s in styles) {
|
for (const s in styles) {
|
||||||
keyShape.attr(s, styles[s]);
|
keyShape.attr(s, styles[s]);
|
||||||
@ -328,7 +329,7 @@ class CustomGroup {
|
|||||||
} else {
|
} else {
|
||||||
// 更新时候merge配置项
|
// 更新时候merge配置项
|
||||||
const { groupStyle } = customGroupStyle;
|
const { groupStyle } = customGroupStyle;
|
||||||
const styles = merge({}, groupStyle, property);
|
const styles = deepMix({}, groupStyle, property);
|
||||||
this.customGroup[groupId] = {
|
this.customGroup[groupId] = {
|
||||||
nodeGroup: deletage,
|
nodeGroup: deletage,
|
||||||
groupStyle: styles
|
groupStyle: styles
|
||||||
@ -536,7 +537,7 @@ class CustomGroup {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 缓存群组groupId下的edge和临时生成的node节点
|
// 缓存群组groupId下的edge和临时生成的node节点
|
||||||
this.delegateInGroup[groupId] = merge({
|
this.delegateInGroup[groupId] = deepMix({
|
||||||
sourceOutTargetInEdges,
|
sourceOutTargetInEdges,
|
||||||
sourceInTargetOutEdges,
|
sourceInTargetOutEdges,
|
||||||
edgesOuts,
|
edgesOuts,
|
||||||
@ -571,7 +572,7 @@ class CustomGroup {
|
|||||||
|
|
||||||
const { default: defaultStyle } = this.styles;
|
const { default: defaultStyle } = this.styles;
|
||||||
|
|
||||||
// const styles = merge({}, defaultStyle, { x: cx, y: cy });
|
// const styles = deepMix({}, defaultStyle, { x: cx, y: cy });
|
||||||
for (const style in defaultStyle) {
|
for (const style in defaultStyle) {
|
||||||
keyShape.attr(style, defaultStyle[style]);
|
keyShape.attr(style, defaultStyle[style]);
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,7 @@
|
|||||||
* @Date: 2019-06-27 18:12:06
|
* @Date: 2019-06-27 18:12:06
|
||||||
* @LastEditors: moyee
|
* @LastEditors: moyee
|
||||||
* @LastEditTime: 2019-08-22 11:22:16
|
* @LastEditTime: 2019-08-22 11:22:16
|
||||||
* @Description: file content
|
* @Description: Graph
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @fileOverview graph
|
|
||||||
* @author huangtonger@aliyun.com
|
|
||||||
*/
|
*/
|
||||||
const { groupBy } = require('lodash');
|
const { groupBy } = require('lodash');
|
||||||
const G = require('@antv/g/lib');
|
const G = require('@antv/g/lib');
|
||||||
@ -200,7 +196,8 @@ class Graph extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* 群组的原始数据
|
* 群组的原始数据
|
||||||
*/
|
*/
|
||||||
groups: []
|
groups: [],
|
||||||
|
groupStyle: {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,7 +594,7 @@ describe.only('signle layer group', () => {
|
|||||||
expect(isVisible).to.be.true;
|
expect(isVisible).to.be.true;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(keyShape.attr('r')).eql(groupStyle.r);
|
expect(keyShape.attr('r')).eql(30);
|
||||||
expect(keyShape.attr('x')).eql(groupStyle.x);
|
expect(keyShape.attr('x')).eql(groupStyle.x);
|
||||||
expect(keyShape.attr('y')).eql(groupStyle.y);
|
expect(keyShape.attr('y')).eql(groupStyle.y);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user