g6/demos/others-interactive-custom-tree.html
2019-10-10 20:01:23 +08:00

585 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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',
style: {
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>