Commit 920fa8c1 by zhaochengxiang

增加资产浏览关系图

parent 06b6ecd8
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/pro-table": "^2.45.0", "@ant-design/pro-table": "^2.45.0",
"@antv/chart-node-g6": "^0.0.4",
"@antv/g2": "^4.1.12", "@antv/g2": "^4.1.12",
"@antv/g6": "^4.2.1", "@antv/g6": "^4.2.1",
"@craco/craco": "^6.1.2", "@craco/craco": "^6.1.2",
......
import React from 'react';
import Chart from '@antv/chart-node-g6';
import G6 from '@antv/g6';
import actionImg from '../assets/1.png';
const raduis = 50, innerRaduis = 20, imageWidth = 20;
const textFontSize = 8;
class Relation extends React.Component {
// componentDidMount() {
// const { data, onClick } = this.props;
// if (data) {
// this.graph = init(this)(this.elem, data, onClick);
// }
// }
componentDidUpdate(prevProps, prevState) {
const { data, onClick } = this.props;
if (data) {
if (data !== prevProps.data) {
const newData = JSON.parse(JSON.stringify(data));
this.graph?.destroy();
this.graph = init(this)(this.elem, newData, onClick);
}
}
}
graph = undefined;
elem = undefined;
render() {
return (
<div ref={ref => this.elem = ref} style={{ position: 'relative', width: '100%', height: '100%' }}></div>
);
}
}
export default Relation;
const init = (ctx) => function (container, data, onClick) {
const width = container.scrollWidth;
const height = container.scrollHeight;
G6.registerNode('tree-node', {
drawShape: function drawShape(cfg, group) {
const keyShape = group.addShape('circle', {
attrs: {
x: raduis,
y: raduis,
r: raduis,
},
name: 'keyShape',
draggable: true,
});
const view = new (Chart || window.Chart)({
group,
width: raduis*2,
height: raduis*2,
x: 0,
y: 0,
});
view.data([]);
view.coordinate('theta', {
radius: 1.0,
innerRadius: 0.45
});
view
.interval()
.adjust('stack')
.position('value')
.color('#b9b9b9')
.style({
stroke: 'white',
lineWidth: 5,
cursor: 'pointer',
})
view.interaction('element-active');
view.legend(false);
view.on('element:click', evt => {
const { data } = evt;
onClick && onClick(data?.data?.type, cfg.id);
})
view.render();
keyShape.set('intervalView', view);
const imageShape1 = group.addShape('image', {
attrs: {
x: (raduis - innerRaduis)/2 - imageWidth/2,
y: raduis-imageWidth/2,
width: imageWidth,
height: imageWidth,
cursor: 'pointer',
img: actionImg,
},
name: 'center-icon',
});
const imageShape2 = group.addShape('image', {
attrs: {
x: raduis + innerRaduis + (raduis - innerRaduis)/2 - imageWidth/2,
y: raduis-imageWidth/2,
height: imageWidth,
width: imageWidth,
cursor: 'pointer',
img: actionImg,
},
name: 'next-icon',
});
imageShape1.hide();
imageShape2.hide();
group.addShape('circle', {
attrs: {
x: raduis,
y: raduis,
r: innerRaduis,
lineWidth: 0,
fill: (cfg.simple)?'#F2F2F2':'#D65DB1',
fillOpacity: 1.0,
stroke: '#fff',
strokeOpacity: 0,
cursor: 'pointer'
},
name: 'innnerCircle',
draggable: true,
});
group.addShape("text", {
attrs: {
text: (cfg.simple)?'':(cfg.label||''),
x: raduis,
y: raduis,
fontSize: textFontSize,
textAlign: 'center',
textBaseline: "middle",
fill: "#fff",
cursor: 'pointer',
},
draggable: true
});
return keyShape;
},
setState(name, value, item) {
const group = item.getContainer();
const keyShape = group.get('children')[0];
const imageShape1 = group.get('children')[4];
const imageShape2 = group.get('children')[5];
if (name === 'active') {
if (value) {
keyShape?.attr('fill', '#fff');
const view = keyShape.get('intervalView');
const data = [
{ type: 'center', value: 50 },
{ type: 'next', value: 50 }
];
view?.changeData(data);
imageShape1?.show();
imageShape2?.show();
} else {
keyShape?.attr('fill', null);
const view = keyShape?.get('intervalView');
view?.changeData([]);
imageShape1?.hide();
imageShape2?.hide();
}
}
},
})
const graph = new G6.TreeGraph({
container,
width,
height,
linkCenter: true,
modes: {
default: [
'drag-canvas',
'zoom-canvas',
],
},
defaultNode: {
type: 'tree-node',
anchorPoints: [
[0, 0.5],
[1, 0.5],
],
},
defaultEdge: {
type: 'line',
},
layout: {
type: 'dendrogram',
direction: 'LR',
nodeSep: (raduis+innerRaduis)/2+30.0,
rankSep: 150,
radial: true,
},
});
const fittingString = (str, maxWidth, fontSize) => {
const ellipsis = '...';
const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0];
let currentWidth = 0;
let res = str;
const pattern = new RegExp('[\u4E00-\u9FA5]+'); // distinguish the Chinese charactors and letters
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength) return;
if (pattern.test(letter)) {
// Chinese charactors
currentWidth += fontSize;
} else {
// get the width of single letter according to the fontSize
currentWidth += G6.Util.getLetterWidth(letter, fontSize);
}
if (currentWidth > maxWidth - ellipsisLength) {
res = `${str.substr(0, i)}${ellipsis}`;
}
});
return res;
};
graph.node(function (node) {
return {
label: fittingString(node.id||'', innerRaduis*2-4.0, textFontSize),
};
});
graph.data(data);
graph.render();
graph.fitView();
graph.on('node:mouseenter', function (e) {
const item = e.item;
graph.setAutoPaint(false);
graph.getNodes().forEach(function (node) {
graph.clearItemStates(node);
});
graph.setItemState(item, 'active', true);
graph.paint();
graph.setAutoPaint(true);
});
graph.on('node:mouseleave', function (e) {
clearAllStats();
});
graph.on('node:click', function(e) {
if (e.target?.cfg?.name === 'center-icon') {
} else {
}
// const item = e.item;
// const model = item.getModel();
// onClick && onClick(model);
})
function clearAllStats() {
graph.setAutoPaint(false);
graph.getNodes().forEach(function (node) {
graph.clearItemStates(node);
graph.setItemState(node, 'active', false);
});
graph.paint();
graph.setAutoPaint(true);
}
if (typeof window !== 'undefined') {
window.onresize = () => {
if (!graph || graph.get('destroyed')) return;
if (!container || !container.scrollWidth || !container.scrollHeight) return;
graph.changeSize(container.scrollWidth, container.scrollHeight);
};
}
return graph;
}
import { useEffect, useState } from 'react';
import Relation from './Relation';
const data = {
"id": "Modeling Methods",
"children": [
{
"id": "Classification",
"children": [
{ "id": "Logistic regression" },
{ "id": "Linear discriminant analysis" },
{ "id": "Rules" },
{ "id": "Decision trees" },
{ "id": "Naive Bayes" },
{ "id": "K nearest neighbor" },
{ "id": "Probabilistic neural network" },
{ "id": "Support vector machine" }
]
},
{
"id": "Consensus",
"children": [
{
"id": "Models diversity",
"children": [
{ "id": "Different initializations" },
{ "id": "Different parameter choices" },
{ "id": "Different architectures" },
{ "id": "Different modeling methods" },
{ "id": "Different training sets" },
{ "id": "Different feature sets" }
]
},
{
"id": "Methods",
"children": [
{ "id": "Classifier selection" },
{ "id": "Classifier fusion" }
]
},
{
"id": "Common",
"children": [
{ "id": "Bagging" },
{ "id": "Boosting" },
{ "id": "AdaBoost" }
]
}
]
},
{
"id": "Regression",
"children": [
{ "id": "Multiple linear regression" },
{ "id": "Partial least squares" },
{ "id": "Multi-layer feedforward neural network" },
{ "id": "General regression neural network" },
{ "id": "Support vector regression" }
]
}
]
};
function App() {
const [ nodes, setNodes ] = useState([]);
const [ relationParams, setRelationParams ] = useState({ relationData: {}, reload: false });
const { relationData, reload } = relationParams;
useEffect(() => {
let newNodes = [{ id: data.id, pid: '', levelId: '0', simple: false, show: true }];
function recursion(subData, parentId, parentLevelId) {
// if (parentLevelId.split('-').length > 2) return;
(subData||[]).forEach((item, index) => {
let currentLevelId = `${parentLevelId}-${index}`;
newNodes.push({ id: item.id, pid: parentId, levelId: currentLevelId, simple: (currentLevelId.split('-').length>=3)?true: false, show: (currentLevelId.split('-').length>3)?false:true });
recursion(item.children, item.id, currentLevelId);
})
}
recursion(data.children, data.id, '0');
setNodes(newNodes);
generateRelationData(newNodes);
}, [])
const generateRelationData = (nodes, reload=true) => {
const rootNode = nodes[0];
let newRelationData = {...rootNode, children: []};
function recursion(subData, parentId) {
(nodes||[]).forEach(node => {
if (!node.show) return;
if (node.pid === parentId) {
let newNode = { ...node, children: [] };
(subData||[]).push(newNode);
recursion(newNode.children, newNode.id);
}
})
}
recursion(newRelationData.children, rootNode.id);
setRelationParams({ relationData: newRelationData, reload });
}
const onClick = (type, id) => {
// console.log('type', type);
// console.log('id', id);
const index = (nodes||[]).findIndex((node) => node.id === id);
if (index !== -1) {
const currentNode = nodes[index];
(nodes||[]).forEach(node => {
if (((node.levelId.split('-').length===currentNode.levelId.split('-').length+1)||(node.levelId.split('-').length===currentNode.levelId.split('-').length+2)) && node.levelId.slice(0, currentNode.levelId.length)===currentNode.levelId) {
node.show = true;
}
if (node.levelId.split('-').length >2) {
if (node.levelId.split('-').length<=currentNode.levelId.split('-').length) {
node.simple = !(currentNode.levelId.slice(0, node.levelId.length)===node.levelId);
} else if (node.levelId.split('-').length===currentNode.levelId.split('-').length+1) {
node.simple = !(node.levelId.slice(0, currentNode.levelId.length)===currentNode.levelId);
} else if (node.levelId.slice(0, currentNode.levelId.length)!==currentNode.levelId) {
node.simple = true;
}
}
})
setNodes(nodes);
generateRelationData(nodes, false);
}
}
return (
<div style={{ width: '100%', height: '100%' }}>
<Relation data={relationData} reload={reload} onClick={onClick} />
</div>
);
}
export default App;
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Row, Col } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons'; import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import AssetTable from "../AssetManage/Component/AssetTable";
import AssetTree from '../AssetManage/Component/AssetTree'; import AssetTree from '../AssetManage/Component/AssetTree';
import RelationContainer from './Component/RelationContainer';
import AssetTable from "../AssetManage/Component/AssetTable";
import { AssetBrowseReference } from '../../../util/constant'; import { AssetBrowseReference } from '../../../util/constant';
import './index.less'; import './index.less';
...@@ -11,12 +14,10 @@ import './index.less'; ...@@ -11,12 +14,10 @@ import './index.less';
const AssetBrowse = (props) => { const AssetBrowse = (props) => {
const [ nodeId, setNodeId ] = useState(''); const [ nodeId, setNodeId ] = useState('');
const [ nodeType, setNodeType ] = useState('');
const [ expandTree, setExpandTree ] = useState(true); const [ expandTree, setExpandTree ] = useState(true);
const onTreeSelect = (value, type) => { const onTreeSelect = (value, type) => {
setNodeId(value||''); setNodeId(value||'');
setNodeType(type);
} }
const treeToggleClick = () => { const treeToggleClick = () => {
...@@ -38,7 +39,14 @@ const AssetBrowse = (props) => { ...@@ -38,7 +39,14 @@ const AssetBrowse = (props) => {
</div> </div>
</div> </div>
<div className='right'> <div className='right'>
<AssetTable nodeId={nodeId} reference={AssetBrowseReference} reference='asset-browse' {...props} /> <Row>
<Col span={12}>
<RelationContainer />
</Col>
<Col span={12}>
<AssetTable nodeId={nodeId} reference={AssetBrowseReference} {...props} />
</Col>
</Row>
</div> </div>
</div> </div>
) )
......
...@@ -15,7 +15,7 @@ import "./AssetTable.less"; ...@@ -15,7 +15,7 @@ import "./AssetTable.less";
const AssetTable = (props) => { const AssetTable = (props) => {
const { className, nodeId, nodeType, elementsChanged, assetActionChanged, onSelect, onCountChange, reference = AssetManageReference } = props; const { className, nodeId, elementsChanged, assetActionChanged, onSelect, onCountChange, reference = AssetManageReference } = props;
const [ loading, setLoading ] = useState(false); const [ loading, setLoading ] = useState(false);
const [ columns, setColumns ] = useState([]); const [ columns, setColumns ] = useState([]);
const [ assets, setAssets ] = useState([]); const [ assets, setAssets ] = useState([]);
......
...@@ -15,7 +15,6 @@ import './index.less'; ...@@ -15,7 +15,6 @@ import './index.less';
const AssetManage = (props) => { const AssetManage = (props) => {
const [ nodeId, setNodeId ] = useState(''); const [ nodeId, setNodeId ] = useState('');
const [ nodeType, setNodeType ] = useState('');
const [ assetId, setAssetId ] = useState(''); const [ assetId, setAssetId ] = useState('');
const [ expandTree, setExpandTree ] = useState(true); const [ expandTree, setExpandTree ] = useState(true);
...@@ -27,7 +26,6 @@ const AssetManage = (props) => { ...@@ -27,7 +26,6 @@ const AssetManage = (props) => {
const onTreeSelect = (value, type) => { const onTreeSelect = (value, type) => {
setNodeId(value||''); setNodeId(value||'');
setNodeType(type);
} }
const onTableSelect = (value) => { const onTableSelect = (value) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment