提交 a204c9ec 编写于 作者: W WeiFeng-mindinsight

Graph code adaptation of the new version

上级 5b12415b
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
"dependencies": { "dependencies": {
"axios": "0.18.1", "axios": "0.18.1",
"core-js": "3.3.2", "core-js": "3.3.2",
"d3": "5.6.0", "d3": "5.9.7",
"d3-graphviz": "2.6.1", "d3-graphviz": "3.0.4",
"element-ui": "2.11.1", "element-ui": "2.11.1",
"vue": "2.6.11", "vue": "2.6.11",
"vue-i18n": "8.9.0", "vue-i18n": "8.9.0",
......
...@@ -183,20 +183,20 @@ limitations under the License. ...@@ -183,20 +183,20 @@ limitations under the License.
v-if="!selectedNode.countShow"> v-if="!selectedNode.countShow">
<div class="item"> <div class="item">
{{ $t('graph.attr') }} ({{ {{ $t('graph.attr') }} ({{
selectedNode.info.Attributes.length selectedNode.info.attributes.length
}}) }})
</div> </div>
</div> </div>
<ul v-if="selectedNode.info && !selectedNode.countShow" <ul v-if="selectedNode.info && !selectedNode.countShow"
class="item-content hover" class="item-content hover"
:class=" :class="
selectedNode.info.Attributes.length > 2 selectedNode.info.attributes.length > 2
? 'item-min2' ? 'item-min2'
: selectedNode.info.Attributes.length > 0 : selectedNode.info.attributes.length > 0
? 'item-min' ? 'item-min'
: '' : ''
"> ">
<li v-for="item in selectedNode.info.Attributes" <li v-for="item in selectedNode.info.attributes"
:key="item.name"> :key="item.name">
<div class="key"> <div class="key">
{{ item.name }} {{ item.name }}
...@@ -421,15 +421,15 @@ export default { ...@@ -421,15 +421,15 @@ export default {
data() { data() {
return { return {
clickScope: {}, // Information about the node that is clicked for the first time. clickScope: {}, // Information about the node that is clicked for the first time.
smallResize: {el: '#small-resize'}, // The container of display area box. smallResize: {}, // The container of display area box.
insideBox: {el: '#inside-box'}, // Basic information about the display area box insideBox: {}, // Basic information about the display area box
graphDom: {}, // Basic information about graph0 in svg graph: {}, // Basic information about graph0 in svg
graphSmall: {}, // Basic information about graph0 in the thumbnail graphSmall: {}, // Basic information about graph0 in the thumbnail
svg: {}, // Basic information about svg svg: {}, // Basic information about svg
eventSmall: {}, // Relative position of the thumbnail in the thumbnail click event eventSmall: {}, // Relative position of the thumbnail in the thumbnail click event
// Which mouse button is triggered when the thumbnail is clicked. -1 indicates that no click event is triggered, // Which mouse button is triggered when the thumbnail is clicked. -1 indicates that no click event is triggered,
// 0 indicates the left key, 1 indicates the middle key, and 2 means right key. // 0 indicates the left key, 1 indicates the middle key, and 2 means right key.
clickSmall: -1, clickSmall: false,
allGraphData: {}, // graph Original input data allGraphData: {}, // graph Original input data
firstFloorNodes: [], // ID array of the first layer node. firstFloorNodes: [], // ID array of the first layer node.
// Information about the selected node // Information about the selected node
...@@ -439,7 +439,7 @@ export default { ...@@ -439,7 +439,7 @@ export default {
input: [], input: [],
outputControl: [], outputControl: [],
output: [], output: [],
Attributes: [], attributes: [],
}, },
showControl: { showControl: {
input: true, input: true,
...@@ -486,6 +486,10 @@ export default { ...@@ -486,6 +486,10 @@ export default {
], ],
title: '', title: '',
}, },
viewBox: {
max: 10000,
scale: {x: 1, y: 1},
},
}; };
}, },
computed: {}, computed: {},
...@@ -512,7 +516,7 @@ export default { ...@@ -512,7 +516,7 @@ export default {
if (!this.$route.query || !this.$route.query.train_id) { if (!this.$route.query || !this.$route.query.train_id) {
this.trainJobID = ''; this.trainJobID = '';
this.$message.error(this.$t('trainingDashboard.invalidId')); this.$message.error(this.$t('trainingDashboard.invalidId'));
document.title = this.$t('graph.titleText') + '-MindInsight'; document.title = `${this.$t('graph.titleText')}-MindInsight`;
return; return;
} }
const showGuide = window.localStorage.getItem('graphShowGuide'); const showGuide = window.localStorage.getItem('graphShowGuide');
...@@ -522,24 +526,23 @@ export default { ...@@ -522,24 +526,23 @@ export default {
} }
this.trainJobID = this.$route.query.train_id; this.trainJobID = this.$route.query.train_id;
document.title = document.title = `${decodeURIComponent(this.trainJobID)}-${this.$t(
decodeURIComponent(this.trainJobID) + 'graph.titleText',
'-' + )}-MindInsight`;
this.$t('graph.titleText') +
'-MindInsight';
this.getDatavisualPlugins(); this.getDatavisualPlugins();
window.onresize = () => { window.onresize = () => {
const graphDom = document.querySelector('#graph #graph0'); if (this.graph.dom) {
if (graphDom) { this.initSvg();
this.initGraphRectData(); this.initGraphRectData();
} }
}; };
}, },
destroyed() { destroyed() {
window.onresize = document.onmousemove = document.onmouseup = null; window.onresize = document.onmouseup = null;
const smallContainer = document.querySelector('#small-container'); const smallContainer = document.querySelector('#small-container');
if (smallContainer) { if (smallContainer) {
smallContainer.onmousedown = smallContainer.onmouseup = null; smallContainer.onmousemove = null;
smallContainer.onmousedown = null;
smallContainer.onmousewheel = null; smallContainer.onmousewheel = null;
} }
}, },
...@@ -585,7 +588,10 @@ export default { ...@@ -585,7 +588,10 @@ export default {
.zoomScaleExtent(this.scaleRange) .zoomScaleExtent(this.scaleRange)
.dot(dot) .dot(dot)
.attributer(this.attributer) .attributer(this.attributer)
.render(this.afterInitGraph); .render(() => {
this.initSvg();
this.afterInitGraph();
});
// Generate the dom of the submap. // Generate the dom of the submap.
if (!d3.select('#graphTemp').size()) { if (!d3.select('#graphTemp').size()) {
d3.select('body') d3.select('body')
...@@ -601,6 +607,72 @@ export default { ...@@ -601,6 +607,72 @@ export default {
.attr('style', 'visibility: collapse'); .attr('style', 'visibility: collapse');
} }
}, },
initSvg() {
this.svg.dom = document.querySelector('#graph svg');
this.svg.rect = this.svg.dom.getBoundingClientRect();
const viewBoxData = this.svg.dom.getAttribute('viewBox').split(' ');
this.viewBox.scale.x = 1;
this.svg.originSize = {width: viewBoxData[2], height: viewBoxData[3]};
if (viewBoxData[2] > this.viewBox.max) {
this.viewBox.scale.x = viewBoxData[2] / this.viewBox.max;
viewBoxData[2] = this.viewBox.max;
}
this.viewBox.scale.y = 1;
if (viewBoxData[3] > this.viewBox.max) {
this.viewBox.scale.y = viewBoxData[3] / this.viewBox.max;
viewBoxData[3] = this.viewBox.max;
}
this.svg.dom.setAttribute('viewBox', viewBoxData.join(' '));
this.svg.viewWidth = viewBoxData[2];
this.svg.viewHeight = viewBoxData[3];
},
/**
* Add the location attribute to each node to facilitate the obtaining of node location parameters.
*/
afterInitGraph() {
setTimeout(() => {
if (this.graphviz) {
this.graphviz._data = null;
this.graphviz._dictionary = null;
this.graphviz = null;
}
if (this.graphvizTemp) {
this.graphvizTemp._data = null;
this.graphvizTemp._dictionary = null;
this.graphvizTemp = null;
}
}, 100);
this.fitGraph('graph');
this.transplantChildrenDom();
const svg = document.querySelector('#subgraphTemp svg');
if (svg) {
svg.remove();
}
this.$nextTick(() => {
this.loading.show = false;
});
const elements = d3
.select('#graph')
.selectAll('g.node, g.edge')
.nodes();
elements.forEach((ele) => {
if (!ele.hasAttribute('transform')) {
ele.setAttribute('transform', 'translate(0,0)');
}
// The title value needs to be manually set for the virtual node.
if (Array.prototype.includes.call(ele.classList, 'plain')) {
const title = ele.querySelector('title');
title.textContent = title.textContent.split('^')[0];
}
});
d3.selectAll('g.edge>title').remove();
// The graph generated by the plug-in has a useless title and needs to be deleted.
document.querySelector('#graph g#graph0 title').remove();
this.initGraphRectData();
this.startApp();
},
/** /**
* Initialization method executed after the graph rendering is complete * Initialization method executed after the graph rendering is complete
*/ */
...@@ -621,7 +693,7 @@ export default { ...@@ -621,7 +693,7 @@ export default {
this.clickScope = {}; this.clickScope = {};
}, 1000); }, 1000);
this.selectedNode.name = nodeId; this.selectedNode.name = nodeId;
this.selectNode(); this.selectNode(false);
if (!event || !event.type || event.type !== 'click') { if (!event || !event.type || event.type !== 'click') {
return; return;
} }
...@@ -637,30 +709,30 @@ export default { ...@@ -637,30 +709,30 @@ export default {
const nodeClass = clickNode.classList.value; const nodeClass = clickNode.classList.value;
let name = nodeId; let name = nodeId;
this.selectedNode.more = this.selectedNode.more =
name.indexOf('more') !== -1 && name.indexOf('more...') !== -1 &&
document document
.querySelector(`#graph g[id="${name}"]`) .querySelector(`#graph g[id="${name}"]`)
.attributes.class.value.indexOf('plain') === -1; .attributes.class.value.indexOf('plain') === -1;
const unfoldFlag = const unfoldFlag =
(nodeClass.includes('aggregation') || (nodeClass.includes('aggregation') ||
nodeClass.includes('cluster') || nodeClass.includes('cluster') ||
this.selectedNode.more) && this.selectedNode.more) &&
(!this.clickScope.id || (!this.clickScope.id ||
(this.clickScope.id && nodeId === this.clickScope.id)); (this.clickScope.id && nodeId === this.clickScope.id));
if (this.selectedNode.more) { if (this.selectedNode.more) {
this.selectedNode.moreDirection = name.indexOf('right') !== -1; const changePage = name.includes('right') ? 1 : -1;
this.selectedNode.moreStart = parseInt( const parentId = document.querySelector(`#graph g[id="${name}"]`)
name.match(/\d+/g)[name.match(/\d+/g).length - 1], .parentNode.id;
); name = parentId.replace('_unfold', '');
const id = document.querySelector(`#graph g[id="${name}"]`).parentNode this.allGraphData[name].index += changePage;
.attributes.id.value;
name = id.replace('_unfold', '');
} }
if (unfoldFlag) { if (unfoldFlag) {
this.dealDoubleClick(name); this.dealDoubleClick(name);
} else if (this.clickScope.id) { } else if (this.clickScope.id) {
this.selectedNode.name = this.clickScope.id; this.selectedNode.name = this.clickScope.id;
this.selectNode(); this.selectNode(false);
} }
if (!event || !event.type || event.type !== 'dblclick') { if (!event || !event.type || event.type !== 'dblclick') {
return; return;
...@@ -670,108 +742,116 @@ export default { ...@@ -670,108 +742,116 @@ export default {
}); });
this.initZooming(); this.initZooming();
if (this.selectedNode.name) { if (this.selectedNode.name) {
const type = this.selectNode(true);
/_unfold$/.exec(this.selectedNode.name) || this.selectedNode.more
? 'unfoldScope'
: 'fold';
this.selectNode(type);
} }
}, },
/** /**
* Initializing the graph zoom * Initializing the graph zoom
*/ */
initZooming() { initZooming() {
let startX = 0; const graphBox = this.graph.dom.getBBox();
let startY = 0; const padding = 4;
let drag = {}; const minDistance = 20;
const graphDomd3 = d3.select('#graph0'); const pointer = {start: {x: 0, y: 0}, end: {x: 0, y: 0}};
const graphDom = document.querySelector('#graph #graph0');
const zoom = d3 const zoom = d3
.zoom() .zoom()
.on('start', (d) => { .on('start', () => {
// Original translate parameter pointer.start.x = event.x;
if (!event || !event.x || !event.y) { pointer.start.y = event.y;
return;
}
startX = event.x;
startY = event.y;
if (!this.graphDom.transform.x || isNaN(this.graphDom.transform.x)) {
this.initGraphRectData();
}
drag = {
k: this.graphDom.transform.k,
x: this.graphDom.transform.x,
y: this.graphDom.transform.y,
};
}) })
.on('zoom', (d) => { .on('zoom', () => {
if (!event || !event.x || !event.y) { const transformData = this.getTransformData(this.graph.dom);
return; let tempStr = '';
} let change = {};
const graphd = d.children[1]; let scale = transformData.scale[0];
const graphRect = this.graph.dom.getBoundingClientRect();
const transRate = graphBox.width / graphRect.width;
if (event.type === 'mousemove') { if (event.type === 'mousemove') {
// transform Value During Dragging pointer.end.x = event.x;
drag.x = pointer.end.y = event.y;
this.graphDom.transform.x + let tempX = pointer.end.x - pointer.start.x;
((event.x - startX) / this.graphDom.initWidth) * let tempY = pointer.end.y - pointer.start.y;
this.svg.viewWidth; const paddingTrans = Math.max(
drag.y = (padding / transRate) * scale,
this.graphDom.transform.y + minDistance,
((event.y - startY) / this.graphDom.initHeight) *
this.svg.viewHeight;
} else if (event.type === 'wheel') {
// Zooms in and zooms out the transform value.
const b = event.wheelDelta ? event.wheelDelta : event.detail;
const lg = b < 0 ? 1 + b / 100 : b > 0 ? b / 100 - 1 : 0;
const scale = drag.k;
drag.k = Math.max(
this.scaleRange[0],
Math.min(drag.k * Math.pow(2, lg), this.scaleRange[1]),
); );
if (
graphRect.left + paddingTrans + tempX >=
this.svg.rect.left + this.svg.rect.width
) {
tempX = Math.min(tempX, 0);
}
if (
graphRect.left + graphRect.width - paddingTrans + tempX <=
this.svg.rect.left
) {
tempX = Math.max(tempX, 0);
}
if (
graphRect.top + paddingTrans + tempY >=
this.svg.rect.top + this.svg.rect.height
) {
tempY = Math.min(tempY, 0);
}
if (
graphRect.top + graphRect.height - paddingTrans + tempY <=
this.svg.rect.top
) {
tempY = Math.max(tempY, 0);
}
this.graphDom.offsetLeft = graphDom.getBoundingClientRect().left; change = {
this.graphDom.offsetTop = graphDom.getBoundingClientRect().top; x: tempX * transRate * scale,
// Zoom in on the mouse. y: tempY * transRate * scale,
const axis = {}; };
axis.x = event.x - this.graphDom.offsetLeft; pointer.start.x = pointer.end.x;
axis.y = pointer.start.y = pointer.end.y;
this.graphDom.offsetTop + } else if (event.type === 'wheel') {
this.graphDom.initHeight * scale - const wheelDelta = event.wheelDelta;
event.y; const rate = Math.abs(wheelDelta / 100);
axis.smallX = (axis.x / scale) * drag.k; scale =
axis.smallY = (axis.y / scale) * drag.k; wheelDelta > 0
drag.x = ? transformData.scale[0] * rate
drag.x + : transformData.scale[0] / rate;
(axis.x - axis.smallX) *
(this.svg.viewWidth / this.graphDom.initWidth); scale = Math.max(this.scaleRange[0], scale, this.graph.minScale);
drag.y = scale = Math.min(this.scaleRange[1], scale);
drag.y - change = {
(axis.y - axis.smallY) * x:
(this.svg.viewHeight / this.graphDom.initHeight); (graphRect.x + padding / transRate - event.x) *
this.insideBox.scale = 1 / drag.k; transRate *
} (scale - transformData.scale[0]),
graphDomd3.attr( y:
'transform', (graphRect.bottom - padding / transRate - event.y) *
`translate(${drag.x},${drag.y}) scale(${drag.k})`, transRate *
); (scale - transformData.scale[0]),
graphd.attributes.transform = `scale(${drag.k}, ${drag.k}) rotate(0) translate(${drag.x} ${drag.y})`; };
graphd.translation.x = drag.x;
graphd.translation.y = drag.y;
this.graphDom.width = graphDom.getBoundingClientRect().width;
this.graphDom.height = graphDom.getBoundingClientRect().height;
this.bigMapPositionChange();
})
.on('end', (d) => {
if (!drag || !drag.x || !drag.y || !drag.k) {
return;
} }
this.graphDom.transform = drag;
this.graph.transform = {
x: transformData.translate[0] + change.x,
y: transformData.translate[1] + change.y,
k: scale,
};
this.graph.transRate =
graphRect.width / graphBox.width / this.graph.transform.k;
tempStr = `translate(${this.graph.transform.x},${this.graph.transform.y}) scale(${this.graph.transform.k})`;
this.graph.dom.setAttribute('transform', tempStr);
this.setInsideBoxData();
event.stopPropagation();
event.preventDefault();
}); });
// Large Map Displacement and Amplification Operation
const svgD3 = d3.select('svg'); const svg = d3.select('#graph svg');
svgD3.on('.zoom', null); svg.on('.zoom', null);
svgD3.call(zoom); svg.call(zoom);
svgD3.on('dblclick.zoom', null); svg.on('dblclick.zoom', null);
svg.on('wheel.zoom', null);
const graph0 = d3.select('#graph #graph0');
graph0.on('.zoom', null);
graph0.call(zoom);
}, },
/** /**
* Double-click the processing to be performed on the node to expand or narrow the namespace or aggregation node. * Double-click the processing to be performed on the node to expand or narrow the namespace or aggregation node.
...@@ -806,52 +886,6 @@ export default { ...@@ -806,52 +886,6 @@ export default {
datum.attributes.stroke = 'rgb(167, 167, 167)'; datum.attributes.stroke = 'rgb(167, 167, 167)';
} }
}, },
/**
* Add the location attribute to each node to facilitate the obtaining of node location parameters.
*/
afterInitGraph() {
setTimeout(() => {
if (this.graphviz) {
this.graphviz._data = null;
this.graphviz._dictionary = null;
this.graphviz = null;
}
if (this.graphvizTemp) {
this.graphvizTemp._data = null;
this.graphvizTemp._dictionary = null;
this.graphvizTemp = null;
}
}, 100);
this.fitGraph('graph');
this.transplantChildrenDom();
const svg = document.querySelector('#subgraphTemp svg');
if (svg) {
svg.remove();
}
this.$nextTick(() => {
this.loading.show = false;
});
const elements = d3
.select('#graph')
.selectAll('g.node, g.edge')
.nodes();
elements.forEach((ele) => {
if (!ele.hasAttribute('transform')) {
ele.setAttribute('transform', 'translate(0,0)');
}
// The title value needs to be manually set for the virtual node.
if (Array.prototype.includes.call(ele.classList, 'plain')) {
const title = ele.querySelector('title');
title.textContent = title.textContent.split('^')[0];
}
});
d3.selectAll('g.edge>title').remove();
// The graph generated by the plug-in has a useless title and needs to be deleted.
document.querySelector('#graph g#graph0 title').remove();
this.initGraphRectData();
this.startApp();
},
/** /**
* When the value of graph is too large, enlarge the value of graph. * When the value of graph is too large, enlarge the value of graph.
* Otherwise, the node cannot be clearly displayed. * Otherwise, the node cannot be clearly displayed.
...@@ -864,11 +898,11 @@ export default { ...@@ -864,11 +898,11 @@ export default {
const graphDom = document.querySelector(`#${id} #graph0`); const graphDom = document.querySelector(`#${id} #graph0`);
const box = graphDom.getBBox(); const box = graphDom.getBBox();
let transformStr = ''; let transformStr = '';
const graphTransformData = this.getTransformData(graphDom);
if (box.width > maxShowWidth || box.height > maxShowHeight) { if (box.width > maxShowWidth || box.height > maxShowHeight) {
const graphTransformData = this.getTransformData(graphDom);
const scale = Math.max( const scale = Math.max(
box.width / maxShowWidth, box.width / maxShowWidth / this.viewBox.scale.x,
box.height / maxShowHeight, box.height / maxShowHeight / this.viewBox.scale.y,
); );
const translate = {x: (box.width - maxShowWidth) / 2}; const translate = {x: (box.width - maxShowWidth) / 2};
...@@ -876,12 +910,15 @@ export default { ...@@ -876,12 +910,15 @@ export default {
graphTransformData.translate[0] = translate.x; graphTransformData.translate[0] = translate.x;
} }
graphTransformData.scale[0] = scale; graphTransformData.scale[0] = scale;
Object.keys(graphTransformData).forEach((key) => {
transformStr += `${key}(${graphTransformData[key].join(',')}) `;
});
} else { } else {
transformStr = `translate(${-box.x},${-box.y}) scale(1)`; graphTransformData.translate = [-box.x, -box.y];
}
if (id === 'graph' && this.selectedNode.more) {
graphTransformData.scale[0] = this.graph.transform.k;
} }
Object.keys(graphTransformData).forEach((key) => {
transformStr += `${key}(${graphTransformData[key].join(',')}) `;
});
graphDom.setAttribute('transform', transformStr.trim()); graphDom.setAttribute('transform', transformStr.trim());
}, },
/** /**
...@@ -890,24 +927,26 @@ export default { ...@@ -890,24 +927,26 @@ export default {
* @param {Boolean} toUnfold Expand the namespace. * @param {Boolean} toUnfold Expand the namespace.
*/ */
layoutNamescope(name, toUnfold) { layoutNamescope(name, toUnfold) {
const dotStr = this.packageNamescope(name); setTimeout(() => {
this.graphvizTemp = d3 const dotStr = this.packageNamescope(name);
.select('#graphTemp') this.graphvizTemp = d3
.graphviz({useWorker: false, totalMemory: this.totalMemory}) .select('#graphTemp')
.dot(dotStr) .graphviz({useWorker: false, totalMemory: this.totalMemory})
.zoomScaleExtent(this.scaleRange) .dot(dotStr)
.attributer((datum, index, nodes) => { .zoomScaleExtent(this.scaleRange)
if ( .attributer((datum, index, nodes) => {
datum.tag === 'polygon' && if (
datum.attributes.stroke !== 'transparent' datum.tag === 'polygon' &&
) { datum.attributes.stroke !== 'transparent'
datum.attributes.stroke = 'rgb(167, 167, 167)'; ) {
} datum.attributes.stroke = 'rgb(167, 167, 167)';
}) }
.render(() => { })
this.fitGraph('graphTemp'); .render(() => {
this.dealNamescopeTempGraph(name); this.fitGraph('graphTemp');
}); this.dealNamescopeTempGraph(name);
});
}, 20);
}, },
/** /**
* To obtain graph data, initialize and expand the namespace or aggregate nodes. * To obtain graph data, initialize and expand the namespace or aggregate nodes.
...@@ -926,66 +965,64 @@ export default { ...@@ -926,66 +965,64 @@ export default {
}; };
this.loading.info = this.$t('graph.queryLoading'); this.loading.info = this.$t('graph.queryLoading');
this.loading.show = true; this.loading.show = true;
setTimeout(() => { RequestService.queryGraphData(params)
RequestService.queryGraphData(params) .then(
.then( (response) => {
(response) => { if (response && response.data && response.data.nodes) {
if (response && response.data && response.data.nodes) { // If the namespace to be expanded is larger than the maximum number of subnodes,
// If the namespace to be expanded is larger than the maximum number of subnodes, // an error is reported and the namespace is highlighted.
// an error is reported and the namespace is highlighted. const nodesCountLimit = name
const nodesCountLimit = name ? this.nodesCountLimit
? this.nodesCountLimit : namescopeChildLimit;
: namescopeChildLimit; if (
if ( !independentLayout &&
!independentLayout && response.data.nodes.length > nodesCountLimit
response.data.nodes.length > nodesCountLimit ) {
) { this.$message.error(this.$t('graph.tooManyNodes'));
this.$message.error(this.$t('graph.tooManyNodes')); this.packageDataToObject(name, false);
this.packageDataToObject(name, false); this.loading.show = false;
this.loading.show = false; } else {
} else { const nodes = JSON.parse(JSON.stringify(response.data.nodes));
const nodes = this.dealAggregationNodes( if (nodes && nodes.length) {
JSON.parse(JSON.stringify(response.data.nodes)), this.packageDataToObject(name, true, nodes);
name, // If the name is empty, it indicates the outermost layer.
); if (!name) {
if (nodes && nodes.length) { const dot = this.packageGraphData();
this.packageDataToObject(name, true, nodes); this.initGraph(dot);
// If the name is empty, it indicates the outermost layer.
if (!name) {
const dot = this.packageGraphData();
this.initGraph(dot);
} else {
this.allGraphData[name].isUnfold = true;
this.selectedNode.name = `${name}_unfold`;
this.layoutNamescope(name, true);
}
} else { } else {
this.initGraphRectData(); if (this.allGraphData[name].type === 'aggregation_scope') {
this.loading.show = false; this.dealAggregationNodes(name);
}
this.allGraphData[name].isUnfold = true;
this.selectedNode.name = `${name}_unfold`;
this.layoutNamescope(name, true);
} }
} else {
this.initGraphRectData();
this.loading.show = false;
} }
} }
}, }
(error) => { },
this.loading.show = false; (error) => {
}, this.loading.show = false;
) },
.catch((error) => { )
// A non-Google Chrome browser may not work properly. .catch((error) => {
this.loading.show = false; // A non-Google Chrome browser may not work properly.
if (error.includes('larger than maximum 65535 allowed')) { this.loading.show = false;
this.$message.error(this.$t('graph.dataTooLarge')); if (error && error.includes('larger than maximum 65535 allowed')) {
} else { this.$message.error(this.$t('graph.dataTooLarge'));
this.$bus.$emit('showWarmText', true); } else {
} this.$bus.$emit('showWarmText', true);
if (name && this.allGraphData[name]) { }
this.allGraphData[name].isUnfold = false; if (name && this.allGraphData[name]) {
this.allGraphData[name].children = []; this.allGraphData[name].isUnfold = false;
this.allGraphData[name].size = []; this.allGraphData[name].children = [];
this.allGraphData[name].html = ''; this.allGraphData[name].size = [];
} this.allGraphData[name].html = '';
}); }
}, 50); });
}, },
/** /**
* To obtain datavisual plugins * To obtain datavisual plugins
...@@ -1032,88 +1069,84 @@ export default { ...@@ -1032,88 +1069,84 @@ export default {
}, },
/** /**
* Process the data returned by the background interface. * Process the data returned by the background interface.
* @param {Array} nodes Current node array
* @param {String} name Node name * @param {String} name Node name
* @return {Array} Node array
*/ */
dealAggregationNodes(nodes, name) { dealAggregationNodes(name) {
// A maximum of 10 subnodes can be displayed on an aggregation node. // A maximum of 10 subnodes can be displayed on an aggregation node.
const aggregationNodeLimit = 10; const aggregationNodeLimit = 10;
const independentLayout = const idsGroup = [];
name && this.allGraphData[name]
? this.allGraphData[name].independent_layout this.allGraphData[name].children.forEach((key) => {
: false; if (!this.allGraphData[key].grouped) {
if (independentLayout && nodes && nodes.length > aggregationNodeLimit) { const ids = this.getAssociatedNode(key, `${name}/`);
const nodesLength = nodes.length; idsGroup.push(ids);
// The selected node must be included. }
let startIndex = 0; });
if (this.selectedNode.more) {
startIndex = this.selectedNode.moreDirection const idsList = [];
? Math.max(0, nodes.length - this.selectedNode.moreStart) let temp = [];
: Math.max(0, this.selectedNode.moreStart - aggregationNodeLimit); for (let i = 0; i < idsGroup.length; i++) {
if (idsGroup[i].length > aggregationNodeLimit) {
idsList.push(idsGroup[i]);
} else { } else {
let nodeIndex = 0; if (temp.length + idsGroup[i].length <= aggregationNodeLimit) {
nodes.some((node, index) => { temp = temp.concat(idsGroup[i]);
if (node.name === this.selectedNode.name) { } else {
nodeIndex = index; idsList.push(temp);
return true; temp = [].concat(idsGroup[i]);
} else { }
return false; }
} if (i === idsGroup.length - 1) {
}); idsList.push(temp);
// The selected node must be included.
startIndex = nodeIndex - (nodeIndex % 10);
}
// If the number of subnodes of the aggregation node is greater than the maximum number of nodes on the
// aggregation node, a simulation node needs to be generated to replace other nodes.
const ellipsisNum = Math.max(
0,
nodes.length - aggregationNodeLimit - startIndex,
);
nodes = nodes.slice(startIndex, startIndex + aggregationNodeLimit);
if (startIndex !== 0) {
const ellipsisNodeL = {
name: `${name}/left/${startIndex} more...`,
attr: {},
input: {},
output: {},
proxy_input: {},
proxy_output: {},
type: '',
};
nodes.splice(0, 0, ellipsisNodeL);
}
if (startIndex + aggregationNodeLimit < nodesLength) {
const ellipsisNode = {
name: `${name}/right/${ellipsisNum} more...`,
attr: {},
input: {},
output: {},
proxy_input: {},
proxy_output: {},
type: '',
};
nodes.push(ellipsisNode);
} }
} }
return nodes || [];
this.allGraphData[name].childIdsList = idsList;
this.allGraphData[name].index = 0;
},
getAssociatedNode(name, prefix) {
const node = this.allGraphData[name];
node.grouped = true;
let ids = [];
ids.push(node.name);
Object.keys(node.input).forEach((i) => {
if (i.startsWith(prefix)) {
if (!this.allGraphData[i].grouped) {
const idsTemp = this.getAssociatedNode(i, prefix);
ids = ids.concat(idsTemp);
}
}
});
Object.keys(node.output).forEach((i) => {
if (i.startsWith(prefix)) {
if (!this.allGraphData[i].grouped) {
const idsTemp = this.getAssociatedNode(i, prefix);
ids = ids.concat(idsTemp);
}
}
});
return ids;
}, },
/** /**
* Encapsulates graph data into dot data. * Encapsulates graph data into dot data.
* @return {String} dot string for packing graph data * @return {String} dot string for packing graph data
*/ */
packageGraphData() { packageGraphData() {
const nodes = this.getChildNodesByName();
const initSetting = const initSetting =
'node[style="filled";fontsize="10px"];edge[fontsize="5px";];'; 'node[style="filled";fontsize="10px"];edge[fontsize="5px";];';
return `digraph {${initSetting}${this.packageNodes()}${this.packageEdges()}}`; return `digraph {${initSetting}${this.packageNodes(
nodes,
)}${this.packageEdges(nodes)}}`;
}, },
/** /**
* Encapsulates node data into dot data. * Encapsulates node data into dot data.
* @param {Array} nodes Nodes of the node to be expanded.
* @param {String} name Name of the node to be expanded. * @param {String} name Name of the node to be expanded.
* @return {String} dot String that are packed into all nodes * @return {String} dot String that are packed into all nodes
*/ */
packageNodes(name) { packageNodes(nodes, name) {
const nodes = this.getChildNodesByName(name);
let tempStr = ''; let tempStr = '';
nodes.forEach((node) => { nodes.forEach((node) => {
const name = node.name.split('/').pop(); const name = node.name.split('/').pop();
...@@ -1207,11 +1240,11 @@ export default { ...@@ -1207,11 +1240,11 @@ export default {
}, },
/** /**
* Encapsulates node data into dot data. * Encapsulates node data into dot data.
* @param {Array} nodes Nodes of the node to be expanded.
* @param {String} name Name of the node to be expanded. * @param {String} name Name of the node to be expanded.
* @return {String} dot string packaged by all edges * @return {String} dot string packaged by all edges
*/ */
packageEdges(name) { packageEdges(nodes, name) {
const nodes = this.getChildNodesByName(name);
let tempStr = ''; let tempStr = '';
const edges = []; const edges = [];
// Construct the input and output virtual nodes and optimize the connection. // Construct the input and output virtual nodes and optimize the connection.
...@@ -1429,12 +1462,67 @@ export default { ...@@ -1429,12 +1462,67 @@ export default {
* @return {Array} Subnode array of the namespace. * @return {Array} Subnode array of the namespace.
*/ */
getChildNodesByName(name) { getChildNodesByName(name) {
const nameList = name let nodes = [];
? this.allGraphData[name].children if (name) {
: this.firstFloorNodes; const node = this.allGraphData[name];
const nodes = nameList.map((i) => { const nameList =
return this.allGraphData[i]; node.type === 'aggregation_scope'
}); ? node.childIdsList[node.index]
: node.children;
nodes = nameList.map((i) => {
return this.allGraphData[i];
});
if (node.type === 'aggregation_scope') {
const idsList = node.childIdsList;
if (idsList && idsList.length > 1) {
if (node.index > 0) {
let ellipsisNodesNumLeft = 0;
for (let j = 0; j < node.index; j++) {
ellipsisNodesNumLeft += idsList[j].length;
}
const ellipsisNodeL = {
name: `${name}/left/${ellipsisNodesNumLeft} more...`,
attr: {},
input: {},
output: {},
proxy_input: {},
proxy_output: {},
type: '',
};
this.allGraphData[ellipsisNodeL.name] = ellipsisNodeL;
nodes.unshift(ellipsisNodeL);
}
if (node.index < idsList.length - 1) {
let ellipsisNodesNumRight = 0;
for (let j = node.index + 1; j < idsList.length; j++) {
ellipsisNodesNumRight += idsList[j].length;
}
const ellipsisNodeR = {
name: `${name}/right/${ellipsisNodesNumRight} more...`,
attr: {},
input: {},
output: {},
proxy_input: {},
proxy_output: {},
type: '',
};
this.allGraphData[ellipsisNodeR.name] = ellipsisNodeR;
nodes.push(ellipsisNodeR);
}
}
}
} else {
nodes = this.firstFloorNodes.map((i) => {
return this.allGraphData[i];
});
}
return nodes; return nodes;
}, },
/** /**
...@@ -1645,8 +1733,9 @@ export default { ...@@ -1645,8 +1733,9 @@ export default {
* @return {String} dot string that is used to package the data of the namespace. * @return {String} dot string that is used to package the data of the namespace.
*/ */
packageNamescope(name) { packageNamescope(name) {
const nodeStr = this.packageNodes(name); const nodes = this.getChildNodesByName(name);
const edgeStr = this.packageEdges(name); const nodeStr = this.packageNodes(nodes, name);
const edgeStr = this.packageEdges(nodes, name);
const initSetting = const initSetting =
`node[style="filled";fontsize="10px";];` + `edge[fontsize="5px";];`; `node[style="filled";fontsize="10px";];` + `edge[fontsize="5px";];`;
const dotStr = const dotStr =
...@@ -1659,21 +1748,26 @@ export default { ...@@ -1659,21 +1748,26 @@ export default {
* @param {String} name The name of the namespace to be closed. * @param {String} name The name of the namespace to be closed.
*/ */
deleteNamespace(name) { deleteNamespace(name) {
this.loading.info = this.$t('graph.queryLoading'); this.loading.info = this.$t('graph.searchLoading');
this.loading.show = true; this.loading.show = true;
setTimeout(() => { if (!this.selectedNode.more) {
this.packageDataToObject(name, false); this.packageDataToObject(name, false);
this.layoutController(name); this.layoutController(name);
if (this.selectedNode.more) { } else {
this.queryGraphData(name); this.allGraphData[name].isUnfold = true;
} this.selectedNode.name = `${name}_unfold`;
}, 150); this.layoutNamescope(name, true);
}
}, },
/** /**
* Controls the invoking method of the next step. * Controls the invoking method of the next step.
* @param {String} name Name of the namespace to be expanded. * @param {String} name Name of the namespace to be expanded.
*/ */
layoutController(name) { layoutController(name) {
if (!this.loading.show) {
this.loading.info = this.$t('graph.searchLoading');
this.loading.show = true;
}
if (name.includes('/')) { if (name.includes('/')) {
const subPath = name const subPath = name
.split('/') .split('/')
...@@ -1794,7 +1888,7 @@ export default { ...@@ -1794,7 +1888,7 @@ export default {
*/ */
getTransformData(node) { getTransformData(node) {
if (!node) { if (!node) {
return []; return {};
} }
const transformData = node.getAttribute('transform'); const transformData = node.getAttribute('transform');
const attrObj = []; const attrObj = [];
...@@ -1819,10 +1913,9 @@ export default { ...@@ -1819,10 +1913,9 @@ export default {
}, },
/** /**
* Selecting a node * Selecting a node
* @param {String} dblclick Click Type * @param {Boolean} needFocus Whether to focus on the node
*/ */
selectNode(dblclick) { selectNode(needFocus = false) {
const graphDom = document.querySelector('#graph #graph0');
window.getSelection().removeAllRanges(); window.getSelection().removeAllRanges();
d3.selectAll( d3.selectAll(
'.node polygon, .node ellipse, .node rect, .node path', '.node polygon, .node ellipse, .node rect, .node path',
...@@ -1833,15 +1926,37 @@ export default { ...@@ -1833,15 +1926,37 @@ export default {
id = this.allGraphData[id].isUnfold ? `${id}_unfold` : id; id = this.allGraphData[id].isUnfold ? `${id}_unfold` : id;
node.eld3 = d3.select(`#graph g[id="${id}"]`); node.eld3 = d3.select(`#graph g[id="${id}"]`);
node.el = node.eld3.node(); node.el = node.eld3.node();
graphDom.style.transition = ''; this.graph.dom.style.transition = '';
if ((dblclick || path.length > 1) && node.el) {
this.selectNodePosition(node, dblclick); const needDelay = path.length > 1;
if ((needFocus || needDelay) && node.el) {
this.selectNodePosition(id, needDelay);
} }
node.eld3 node.eld3
.select('polygon, rect, Mrecord, ellipse, path') .select('polygon, rect, ellipse, path')
.classed('selected', true); .classed('selected', true);
this.highlightProxyNodes(id.replace('_unfold', ''));
this.setNodeData(); this.setNodeData();
}, },
highlightProxyNodes(nodeId) {
const proxyNodes = d3
.selectAll('#graph g.node')
.nodes()
.filter((node) => {
const id = node.id.split('^')[0].replace('_unfold', '');
return id === nodeId;
});
const childTagType = ['polygon', 'ellipse', 'path', 'rect'];
proxyNodes.forEach((i) => {
if (i.childNodes) {
i.childNodes.forEach((k) => {
if (childTagType.includes(k.tagName)) {
k.setAttribute('class', 'selected');
}
});
}
});
},
/** /**
* The node information of the selected node is displayed and highlighted. * The node information of the selected node is displayed and highlighted.
*/ */
...@@ -1851,81 +1966,36 @@ export default { ...@@ -1851,81 +1966,36 @@ export default {
inputControl: [], inputControl: [],
output: [], output: [],
outputControl: [], outputControl: [],
Attributes: [], attributes: [],
}; };
this.selectedNode.showControl = { this.selectedNode.showControl = {
input: true, input: true,
output: true, output: true,
}; };
const path = this.selectedNode.name.split('^'); const path = this.selectedNode.name.split('^');
const select = this.allGraphData[path[0].replace('_unfold', '')] const selectedNode = this.allGraphData[path[0].replace('_unfold', '')];
? [this.allGraphData[path[0].replace('_unfold', '')]]
: []; if (selectedNode && !selectedNode.name.includes('more...')) {
const nodes = d3.selectAll('#graph g.node');
const node = d3.select(`#graph g[id="${this.selectedNode.name}"]`);
const text = node.select('text').node()
? node.select('text').node().innerText ||
node.select('text').node().textContent ||
''
: '';
const nodeId = node.node()
? node
.node()
.id.replace(/_unfold$/g, '')
.split('^')
: [];
const filter = nodes.nodes().filter((k) => {
const nodeItem = d3.select(k);
const nodeText = nodeItem.select('text').node()
? nodeItem.select('text').node().innerText ||
nodeItem.select('text').node().textContent ||
''
: '';
let path = false;
nodeItem
.node()
.id.split('^')
.forEach((i) => {
path = nodeId.filter((j) => j === i).length ? true : path;
});
return nodeText === text && path;
});
filter.forEach((k) => {
if (k.childNodes) {
k.childNodes.forEach((i) => {
if (
i.tagName === 'polygon' ||
i.tagName === 'ellipse' ||
i.tagName === 'path' ||
i.tagName === 'rect'
) {
i.setAttribute('class', 'selected');
}
});
}
});
if (select.length && select[0].name.indexOf('more') === -1) {
this.selectedNode.show = true; this.selectedNode.show = true;
this.selectedNode.name = select[0].name; this.selectedNode.name = selectedNode.name;
this.selectedNode.title = select[0].name.replace('_unfold', ''); this.selectedNode.title = selectedNode.name.replace('_unfold', '');
this.selectedNode.type = this.selectedNode.type =
select[0].type === 'name_scope' || selectedNode.type === 'name_scope' ||
select[0].type === 'aggregation_scope' selectedNode.type === 'aggregation_scope'
? '' ? ''
: select[0].type; : selectedNode.type;
this.selectedNode.countShow = this.selectedNode.countShow =
select[0].type === 'name_scope' || selectedNode.type === 'name_scope' ||
select[0].type === 'aggregation_scope'; selectedNode.type === 'aggregation_scope';
this.selectedNode.count = select[0].subnode_count; this.selectedNode.count = selectedNode.subnode_count;
Object.keys(select[0].attr).forEach((key) => { this.selectedNode.info.attributes = JSON.parse(
this.selectedNode.info.Attributes.push({ JSON.stringify(selectedNode.attr),
name: key, );
value: select[0].attr[key],
}); Object.keys(selectedNode.input).forEach((key) => {
}); const value = this.getEdgeLabel(selectedNode.input[key]);
Object.keys(select[0].input).forEach((key) => { if (selectedNode.input[key].edge_type !== 'control') {
const value = this.getEdgeLabel(select[0].input[key]);
if (select[0].input[key].edge_type !== 'control') {
this.selectedNode.info.input.push({ this.selectedNode.info.input.push({
name: key, name: key,
value: value, value: value,
...@@ -1937,24 +2007,25 @@ export default { ...@@ -1937,24 +2007,25 @@ export default {
}); });
} }
}); });
Object.keys(select[0].output).forEach((key) => {
const value = this.getEdgeLabel(select[0].output[key]); Object.keys(selectedNode.output).forEach((key) => {
if (select[0].output[key].edge_type !== 'control') { const value = this.getEdgeLabel(selectedNode.output[key]);
if (selectedNode.output[key].edge_type !== 'control') {
this.selectedNode.info.output.push({ this.selectedNode.info.output.push({
name: key, name: key,
scope: select[0].output[key].scope, scope: selectedNode.output[key].scope,
value: value, value: value,
}); });
} else { } else {
this.selectedNode.info.outputControl.push({ this.selectedNode.info.outputControl.push({
name: key, name: key,
scope: select[0].output[key].scope, scope: selectedNode.output[key].scope,
value: value, value: value,
}); });
} }
}); });
this.selectedNode.info.output_i = select[0].output_i; this.selectedNode.info.output_i = selectedNode.output_i;
this.highLightEdges(select[0]); this.highLightEdges(selectedNode);
} else { } else {
this.selectedNode.show = false; this.selectedNode.show = false;
this.selectedNode.name = ''; this.selectedNode.name = '';
...@@ -1964,55 +2035,58 @@ export default { ...@@ -1964,55 +2035,58 @@ export default {
}, },
/** /**
* The position is offset to the current node in the center of the screen. * The position is offset to the current node in the center of the screen.
* @param {Object} node Selected Node * @param {String} nodeId Selected Node id
* @param {Boolean} dblclick Double-click * @param {Boolean} needDelay Delay required
*/ */
selectNodePosition(node, dblclick) { selectNodePosition(nodeId, needDelay) {
const graphDom = document.querySelector('#graph #graph0'); const nodeDom = document.querySelector(`#graph0 g[id="${nodeId}"]`);
node.offsetLeft = node.el.getBoundingClientRect().left; const nodeRect = nodeDom.getBoundingClientRect();
node.offsetTop = node.el.getBoundingClientRect().top;
node.initWidth = node.el.getBoundingClientRect().width; const graph = {};
node.initHeight = node.el.getBoundingClientRect().height; graph.rect = this.graph.dom.getBoundingClientRect();
graph.initWidth = graph.rect.width / this.graph.transform.k;
graph.initHeight = graph.rect.height / this.graph.transform.k;
const screenChange = { const screenChange = {
x: x:
node.offsetLeft - nodeRect.left +
(this.svg.offsetLeft + this.svg.initWidth / 2) + nodeRect.width / 2 -
node.initWidth / 2, (this.svg.rect.left + this.svg.rect.width / 2),
y: y:
node.offsetTop - nodeRect.top +
(this.svg.offsetTop + this.svg.initHeight / 2) + nodeRect.height / 2 -
node.initHeight / 2, (this.svg.rect.top + this.svg.rect.height / 2),
}; };
this.graphDom.transform = {
x: this.graph.transform.x -=
this.graphDom.transform.x - screenChange.x * (this.svg.originSize.width / graph.initWidth);
screenChange.x * (this.svg.viewWidth / this.graphDom.initWidth), this.graph.transform.y -=
y: screenChange.y * (this.svg.originSize.height / graph.initHeight);
this.graphDom.transform.y -
screenChange.y * (this.svg.viewHeight / this.graphDom.initHeight), this.graph.dom.setAttribute(
k: this.graphDom.transform.k, 'transform',
}; `translate(${this.graph.transform.x},` +
graphDom.attributes.transform.value = `translate(${this.graphDom.transform.x}, `${this.graph.transform.y}) scale(${this.graph.transform.k})`,
${this.graphDom.transform.y}) scale(${this.graphDom.transform.k})`; );
const transition =
dblclick === 'unfoldScope' const transitionTime = Math.min(
? 0 Math.abs(screenChange.x) * 2,
: Math.min( Math.abs(screenChange.y) * 2,
Math.abs(screenChange.x) * 2, needDelay ? 800 : 0,
Math.abs(screenChange.y) * 2, );
800,
); this.graph.dom.style.transition = `${transitionTime / 1000}s`;
graphDom.style.transition = `${transition / 1000}s`; this.graph.dom.style['transition-timing-function'] = 'linear';
graphDom.style['transition-timing-function'] = 'linear';
setTimeout(() => { setTimeout(() => {
graphDom.style.transition = ''; this.graph.dom.style.transition = '';
}, transition); }, transitionTime);
let end = 0; let end = 0;
this.bigMapPositionChange(); this.setInsideBoxData();
const timer = setInterval(() => { const timer = setInterval(() => {
this.bigMapPositionChange(); this.setInsideBoxData();
end += 1; end += 1;
if (end > transition) { if (end > transitionTime) {
clearInterval(timer); clearInterval(timer);
} }
}, 1); }, 1);
...@@ -2210,6 +2284,7 @@ export default { ...@@ -2210,6 +2284,7 @@ export default {
node.children = []; node.children = [];
node.size = []; node.size = [];
node.html = ''; node.html = '';
node.grouped = false;
this.allGraphData[node.name] = node; this.allGraphData[node.name] = node;
this.allGraphData[name].children.push(node.name); this.allGraphData[name].children.push(node.name);
}); });
...@@ -2249,7 +2324,7 @@ export default { ...@@ -2249,7 +2324,7 @@ export default {
input: [], input: [],
outputControl: [], outputControl: [],
output: [], output: [],
Attributes: [], attributes: [],
}, },
showControl: { showControl: {
input: true, input: true,
...@@ -2322,11 +2397,40 @@ export default { ...@@ -2322,11 +2397,40 @@ export default {
this.selectedNode.more = false; this.selectedNode.more = false;
// If a node exists on the map, select the node. // If a node exists on the map, select the node.
if (this.allGraphData[option.value]) { if (this.allGraphData[option.value]) {
// If the namespace or aggregation node is expanded, you need to close it and select if (
if (!this.allGraphData[option.value].isUnfold) { d3
this.selectNode('unfold'); .select(`g[id="${option.value}"],g[id="${option.value}_unfold"]`)
.size()
) {
// If the namespace or aggregation node is expanded, you need to close it and select
if (!this.allGraphData[option.value].isUnfold) {
this.selectNode(true);
} else {
this.dealDoubleClick(option.value);
}
} else { } else {
this.dealDoubleClick(option.value); const parentId = option.value.substring(
0,
option.value.lastIndexOf('/'),
);
if (
this.allGraphData[parentId] &&
this.allGraphData[parentId].isUnfold
) {
const aggregationNode = this.allGraphData[parentId];
if (aggregationNode) {
for (let i = 0; i < aggregationNode.childIdsList.length; i++) {
if (aggregationNode.childIdsList[i].includes(option.value)) {
aggregationNode.index = i;
break;
}
}
}
this.loading.info = this.$t('graph.searchLoading');
this.loading.show = true;
this.selectedNode.name = option.value;
this.layoutNamescope(parentId, true);
}
} }
} else { } else {
// If the node does not exist and is not a subnode of the aggregation node, // If the node does not exist and is not a subnode of the aggregation node,
...@@ -2347,17 +2451,8 @@ export default { ...@@ -2347,17 +2451,8 @@ export default {
.then( .then(
(response) => { (response) => {
if (response && response.data && response.data.children) { if (response && response.data && response.data.children) {
const [data, nameScopeIsUnfold] = this.findStartUnfoldNode( const data = this.findStartUnfoldNode(response.data.children);
response.data.children,
);
if (data) { if (data) {
if (nameScopeIsUnfold) {
// If the aggregation node is expanded but is not displayed on the diagram,
// you need to zoom out the aggregated node, query the aggregation node again,
// and intercept the node array again.
this.dealDoubleClick(data.scope_name);
this.selectedNode.name = option.value;
}
this.dealAutoUnfoldNamescopesData(data); this.dealAutoUnfoldNamescopesData(data);
} }
} }
...@@ -2367,6 +2462,7 @@ export default { ...@@ -2367,6 +2462,7 @@ export default {
}, },
) )
.catch((e) => { .catch((e) => {
this.loading.show = false;
this.$message.error(this.$t('public.dataError')); this.$message.error(this.$t('public.dataError'));
}); });
} }
...@@ -2391,21 +2487,39 @@ export default { ...@@ -2391,21 +2487,39 @@ export default {
) { ) {
this.selectedNode.name = data.scope_name; this.selectedNode.name = data.scope_name;
this.querySingleNode({value: data.scope_name}); this.querySingleNode({value: data.scope_name});
this.selectNode('unfold'); this.selectNode(true);
this.$message.error(this.$t('graph.tooManyNodes')); this.$message.error(this.$t('graph.tooManyNodes'));
this.$nextTick(() => { this.$nextTick(() => {
this.loading.show = false; this.loading.show = false;
}); });
} else { } else {
// Normal expansion // Normal expansion
const nodes = this.dealAggregationNodes( const nodes = JSON.parse(JSON.stringify(data.nodes));
data.nodes,
this.allGraphData[data.scope_name].type,
);
this.packageDataToObject(data.scope_name, true, nodes); this.packageDataToObject(data.scope_name, true, nodes);
if (
this.allGraphData[data.scope_name].type === 'aggregation_scope'
) {
this.dealAggregationNodes(data.scope_name);
const aggregationNode = this.allGraphData[data.scope_name];
if (aggregationNode) {
for (let i = 0; i < aggregationNode.childIdsList.length; i++) {
if (
aggregationNode.childIdsList[i].includes(
this.selectedNode.name,
)
) {
aggregationNode.index = i;
break;
}
}
}
}
if (data.children.scope_name) { if (data.children.scope_name) {
this.dealAutoUnfoldNamescopesData(data.children); this.dealAutoUnfoldNamescopesData(data.children);
} else { } else {
this.loading.info = this.$t('graph.searchLoading');
this.loading.show = true;
this.layoutNamescope(data.scope_name, true); this.layoutNamescope(data.scope_name, true);
} }
} }
...@@ -2415,7 +2529,7 @@ export default { ...@@ -2415,7 +2529,7 @@ export default {
/** /**
* Queries the first layer namespace to be expanded for a search node. * Queries the first layer namespace to be expanded for a search node.
* @param {Object} data All data of the node and the namespace to which the node belongs * @param {Object} data All data of the node and the namespace to which the node belongs
* @return {Array} First namespace to be expanded * @return {Object} First namespace to be expanded
*/ */
findStartUnfoldNode(data) { findStartUnfoldNode(data) {
if (data && data.scope_name) { if (data && data.scope_name) {
...@@ -2425,49 +2539,131 @@ export default { ...@@ -2425,49 +2539,131 @@ export default {
return node.name === this.selectedNode.name; return node.name === this.selectedNode.name;
}) })
) { ) {
return [data, true]; return data;
} else { } else {
return this.findStartUnfoldNode(data.children); return this.findStartUnfoldNode(data.children);
} }
} else { } else {
return [data, false]; return data;
} }
} else { } else {
return [null, null]; return null;
} }
}, },
/** /**
* Initialize the svg, width and height of the small image, and transform information. * Initialize the svg, width and height of the small image, and transform information.
*/ */
initGraphRectData() { initGraphRectData() {
// graph attribute this.initSmallContainer();
const graphHtml = document.querySelector('#graph');
// svg attribute if (!this.graph.dom) {
const svg = graphHtml.querySelector('#graph svg'); this.insideBox.width = this.smallResize.width;
if (!svg) { this.insideBox.height = this.smallResize.height;
return; this.insideBox.top = this.insideBox.left = 0;
} this.styleSet('#inside-box', this.insideBox);
const svgRect = svg.getBoundingClientRect(); insideBox.style.cursor = 'not-allowed';
this.svg.initWidth = svgRect.width; // svg width } else {
this.svg.initHeight = svgRect.height; // svg high let transformString = '';
this.svg.offsetLeft = svgRect.left; // svg Distance to the left of the window const transTemp = this.graph.dom.attributes.transform || null;
this.svg.offsetTop = svgRect.top; // svg Distance from the upper part of the window if (transTemp) {
this.svg.viewWidth = parseFloat( // transform information of graph
svg.attributes.viewBox.value.split(' ')[2], transformString = transTemp.nodeValue.split(/[(,)]/);
); // svg viewbox width } else {
this.svg.viewHeight = parseFloat( transformString = ['translate', '0', '0', ' scale', '1'];
svg.attributes.viewBox.value.split(' ')[3], }
); // The viewbox of the svg is high. this.graph.transform = {
k: parseFloat(transformString[4]),
x: parseFloat(transformString[1]),
y: parseFloat(transformString[2]),
};
const graphRect = this.graph.dom.getBoundingClientRect();
this.graph.transRate =
graphRect.width /
this.graph.dom.getBBox().width /
this.graph.transform.k;
this.graph.minScale =
Math.min(
this.svg.rect.width / 2 / graphRect.width,
this.svg.rect.height / 2 / graphRect.height,
) * this.graph.transform.k;
this.setInsideBoxData();
}
this.setSmallMapEvents();
},
setSmallMapEvents() {
// Attributes of smallContainer // Attributes of smallContainer
const smallContainer = document.querySelector('#small-container'); const smallContainer = document.querySelector('#small-container');
// Attributes of smallMap if (this.graph.dom) {
const smallMap = document.querySelector('#small-map'); smallContainer.onmousedown = (e) => {
this.clickSmall = true;
this.insideBoxPositionChange(e);
};
document.onmouseup = (e) => {
this.clickSmall = false;
};
smallContainer.onmousemove = (e) => {
if (this.clickSmall) {
this.insideBoxPositionChange(e);
}
};
// Mouse wheel event
smallContainer.onmousewheel = (e) => {
e = e || window.event;
const wheelDelta = e.wheelDelta ? e.wheelDelta : e.detail;
if (!isNaN(this.graph.transform.k) && this.graph.transform.k !== 0) {
let rate =
wheelDelta > 0 ? wheelDelta / 100 : -1 / (wheelDelta / 100);
let scaleTemp = this.graph.transform.k / rate;
if (scaleTemp <= this.graph.minScale) {
scaleTemp = this.graph.minScale;
rate = this.graph.transform.k / this.graph.minScale;
}
this.graph.transform.k = Math.max(
this.scaleRange[0],
Math.min(scaleTemp, this.scaleRange[1]),
);
this.insideBox.scale = 1 / this.graph.transform.k;
this.insideBox.left += (this.insideBox.width * (1 - rate)) / 2;
this.insideBox.top += (this.insideBox.height * (1 - rate)) / 2;
this.insideBox.height = this.insideBox.height * rate;
this.insideBox.width = this.insideBox.width * rate;
document
.querySelector('#graph0')
.setAttribute(
'transform',
`translate(${this.graph.transform.x},${this.graph.transform.y}) ` +
`scale(${this.graph.transform.k})`,
);
this.styleSet('#inside-box', this.insideBox);
this.graphChange();
}
};
} else {
document.onmouseup = null;
smallContainer.onmousemove = null;
smallContainer.onmousedown = null;
smallContainer.onmousewheel = null;
}
},
initSmallContainer() {
this.graph.dom = document.querySelector('#graph #graph0');
// Attributes of smallContainer
const smallContainer = document.querySelector('#small-container');
// Reset the length and width of the smallResize and locate the fault. // Reset the length and width of the smallResize and locate the fault.
const smallResize = document.querySelector('#small-resize'); const smallResize = document.querySelector('#small-resize');
this.smallResize.width = this.smallResize.initWidth = this.smallResize.width = this.smallResize.initWidth =
smallContainer.offsetWidth - 2; // Initial width of the thumbnail frame smallContainer.offsetWidth - 2; // Initial width of the thumbnail frame
this.smallResize.height = this.smallResize.initHeight = this.smallResize.height = this.smallResize.initHeight =
...@@ -2475,160 +2671,39 @@ export default { ...@@ -2475,160 +2671,39 @@ export default {
this.smallResize.left = this.smallResize.top = 0; this.smallResize.left = this.smallResize.top = 0;
if (Object.keys(this.allGraphData).length) { if (Object.keys(this.allGraphData).length) {
if ( if (
this.svg.initWidth / this.svg.initHeight < this.svg.originSize.width / this.svg.originSize.height <
this.smallResize.initWidth / this.smallResize.initHeight this.smallResize.initWidth / this.smallResize.initHeight
) { ) {
this.smallResize.width = this.smallResize.width =
(this.smallResize.initHeight * this.svg.initWidth) / (this.smallResize.initHeight * this.svg.originSize.width) /
this.svg.initHeight; this.svg.originSize.height;
this.smallResize.left = this.smallResize.left =
(this.smallResize.initWidth - this.smallResize.width) / 2; (this.smallResize.initWidth - this.smallResize.width) / 2;
} else { } else {
this.smallResize.height = this.smallResize.height =
(this.smallResize.initWidth * this.svg.initHeight) / (this.smallResize.initWidth * this.svg.originSize.height) /
this.svg.initWidth; this.svg.originSize.width;
this.smallResize.top = this.smallResize.top =
(this.smallResize.initHeight - this.smallResize.height) / 2; (this.smallResize.initHeight - this.smallResize.height) / 2;
} }
} }
this.styleSet(this.smallResize, true); this.styleSet('#small-resize', this.smallResize);
// Distance between the thumbnail frame and the upper part of the window // Distance between the thumbnail frame and the upper part of the window
this.smallResize.offsetLeft = smallResize.getBoundingClientRect().left; this.smallResize.offsetLeft = smallResize.getBoundingClientRect().left;
// Distance between the thumbnail frame and the upper part of the window // Distance between the thumbnail frame and the upper part of the window
this.smallResize.offsetTop = smallResize.getBoundingClientRect().top; this.smallResize.offsetTop = smallResize.getBoundingClientRect().top;
const insideBox = document.querySelector('#inside-box'); // Attributes of smallMap
// graph0 information const smallMap = document.querySelector('#small-map');
const graphDom = graphHtml.querySelector('#graph #graph0'); const svgOuterHtml =
smallMap.innerHTML = graphHtml.innerHTML; `<svg xmlns="http://www.w3.org/2000/svg" ` +
if (!graphDom) { `xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" ` +
document.onmousemove = document.onmouseup = null; `viewBox="0.00 0.00 ${this.svg.originSize.width} ${this.svg.originSize.height}"` +
if (smallContainer) { `><g id="smallGraph" class="graph" transform="translate(4,${this.svg
smallContainer.onmousedown = smallContainer.onmouseup = null; .originSize.height - 4}) scale(1)"` +
smallContainer.onmousewheel = null; `>${this.graph.dom.innerHTML}</g></svg>`;
}
this.insideBox.width = this.smallResize.width;
this.insideBox.height = this.smallResize.height;
this.insideBox.top = this.insideBox.left = 0;
this.styleSet(this.insideBox, true);
insideBox.style.cursor = 'not-allowed';
} else {
let transformString = '';
if (graphDom.attributes && graphDom.attributes.transform) {
// transform information of graph
transformString = graphDom.attributes.transform.nodeValue.split(
/[(,)]/,
);
} else {
transformString = ['translate', '0', '0', ' scale', '1'];
}
this.graphDom.transform = {
k: parseFloat(transformString[4]),
x: parseFloat(transformString[1]),
y: parseFloat(transformString[2]),
};
graphDom.childNodes.forEach((k) => {
if (k.tagName === 'polygon') {
this.graphDom.pointStartX = parseFloat(
k.attributes.points.nodeValue.split(/[\s,]/)[0],
); // Start point x
this.graphDom.pointStartY = parseFloat(
k.attributes.points.nodeValue.split(/[\s,]/)[1],
); // Start point y
}
});
this.graphDom.initScale = 1; // Initial amplified value of graph
this.graphDom.initTranslateY =
this.svg.viewHeight - this.graphDom.pointStartY; // Initial y of graph
this.graphDom.initTranslateX = -this.graphDom.pointStartX; // Initial x of graph
this.graphDom.width = graphDom.getBoundingClientRect().width;
this.graphDom.height = graphDom.getBoundingClientRect().height;
this.graphDom.initWidth =
this.graphDom.width / this.graphDom.transform.k; // Initial width of the graph
this.graphDom.initHeight =
this.graphDom.height / this.graphDom.transform.k; // Initial height of the graph
delete this.graphSmall.el;
this.graphSmall.el = smallMap.getElementsByClassName('graph')[0];
this.graphSmall.el.attributes.transform.value = `translate(${this.graphDom.initTranslateX},
${this.graphDom.initTranslateY}) scale(${this.graphDom.initScale})`;
this.graphSmall.initLeft =
this.graphSmall.el.getBoundingClientRect().left -
this.smallResize.offsetLeft;
this.graphSmall.initTop =
this.graphSmall.el.getBoundingClientRect().top -
this.smallResize.offsetTop;
this.graphSmall.initWidth = this.graphSmall.el.getBoundingClientRect().width;
this.graphSmall.initHeight = this.graphSmall.el.getBoundingClientRect().height;
// Size control of the shadow frame
this.insideBox.scale = 1 / this.graphDom.transform.k; // Enlarged value of the shadow frame
insideBox.style.cursor = 'move';
this.bigMapPositionChange();
// Small image location change event
document.onmousemove = (e) => {
if (this.clickSmall === 0) {
this.insideBoxPositionChange(e);
}
};
document.onmouseup = (e) => {
if (this.clickSmall === 0) {
this.insideBoxPositionChange(e);
this.clickSmall = -1;
}
};
smallContainer.onmousedown = (e) => {
this.clickSmall = e.button;
this.eventSmall.x = e.pageX - this.smallResize.offsetLeft;
this.eventSmall.y = e.pageY - this.smallResize.offsetTop;
};
// Mouse lifting event
smallContainer.onmouseup = (e) => {
if (this.clickSmall === -1) {
this.insideBoxPositionChange(e);
}
};
// Mouse wheel event smallMap.innerHTML = svgOuterHtml;
smallContainer.onmousewheel = (e) => {
e = e || window.event;
const b = e.wheelDelta ? e.wheelDelta : e.detail;
if (
!isNaN(this.graphDom.transform.k) &&
this.graphDom.transform.k !== 0
) {
const lg = b < 0 ? Math.abs(b) / 100 - 1 : 1 - b / 100;
this.graphDom.transform = {
k: Math.max(
this.scaleRange[0],
Math.min(
this.graphDom.transform.k * Math.pow(2, lg),
this.scaleRange[1],
),
),
x: this.graphDom.transform.x,
y: this.graphDom.transform.y,
};
this.insideBox.scale = 1 / this.graphDom.transform.k;
const width = this.insideBox.width;
const height = this.insideBox.height;
this.insideBox.left -=
(this.smallResize.width * this.insideBox.scale - width) / 2;
this.insideBox.top -=
(this.smallResize.height * this.insideBox.scale - height) / 2;
this.insideBox.height =
this.smallResize.height * this.insideBox.scale;
this.insideBox.width =
this.smallResize.width * this.insideBox.scale;
this.styleSet(this.insideBox, true);
this.graphChange();
}
};
}
}, },
/** /**
* Small image moving * Small image moving
...@@ -2637,96 +2712,71 @@ export default { ...@@ -2637,96 +2712,71 @@ export default {
insideBoxPositionChange(e) { insideBoxPositionChange(e) {
this.eventSmall.x = e.pageX - this.smallResize.offsetLeft; this.eventSmall.x = e.pageX - this.smallResize.offsetLeft;
this.eventSmall.y = e.pageY - this.smallResize.offsetTop; this.eventSmall.y = e.pageY - this.smallResize.offsetTop;
this.insideBox.left = this.insideBox.left =
this.eventSmall.x - parseFloat(this.insideBox.width) / 2; this.eventSmall.x - parseFloat(this.insideBox.width) / 2;
this.insideBox.top = this.insideBox.top =
this.eventSmall.y - parseFloat(this.insideBox.height) / 2; this.eventSmall.y - parseFloat(this.insideBox.height) / 2;
this.styleSet(this.insideBox, false);
this.styleSet('#inside-box', this.insideBox);
this.graphChange(); this.graphChange();
}, },
/** /**
* Displacement of the large picture when the small picture is changed * Displacement of the large picture when the small picture is changed
*/ */
graphChange() { graphChange() {
if (!this.graphDom.transform.x || isNaN(this.graphDom.transform.x)) { if (!this.graph.transform.x || isNaN(this.graph.transform.x)) {
this.initGraphRectData(); this.initGraphRectData();
} }
// left and top values in the shadow box when translate is set to the initial value only when the scale is changed const graphRect = this.graph.dom.getBoundingClientRect();
const topInit =
(this.graphSmall.initTop + const graphSizeRate = this.svg.rect.width / this.insideBox.width;
(this.graphSmall.initHeight *
(this.svg.viewHeight - Math.abs(this.graphDom.pointStartY))) / const change = {
this.svg.viewHeight) * x:
(1 - this.insideBox.scale); (this.insideBox.left * graphSizeRate -
const leftInit = (this.svg.rect.left - graphRect.left)) /
(this.graphSmall.initLeft + this.graph.transRate,
(this.graphSmall.initWidth * Math.abs(this.graphDom.pointStartX)) / y:
this.svg.viewWidth) * (this.insideBox.top * graphSizeRate -
(1 - this.insideBox.scale); (this.svg.rect.top - graphRect.top)) /
// Move the translate value of the large image corresponding to the shadow frame. this.graph.transRate,
const topSmall =
(((this.insideBox.top - topInit) * this.svg.viewHeight) /
this.graphSmall.initHeight) *
this.graphDom.transform.k;
const leftSmall =
(((this.insideBox.left - leftInit) * this.svg.viewWidth) /
this.graphSmall.initWidth) *
this.graphDom.transform.k;
this.graphDom.transform = {
k: this.graphDom.transform.k,
x: this.graphDom.initTranslateX - leftSmall,
y: this.graphDom.initTranslateY - topSmall,
}; };
const graphDomd3 = d3.select('#graph0');
const graphDom = document.querySelector('#graph #graph0'); this.graph.transform.x -= change.x;
if (graphDomd3) { this.graph.transform.y -= change.y;
graphDomd3.attr(
'transform', this.graph.dom.setAttribute(
`translate(${this.graphDom.transform.x},${this.graphDom.transform.y}) scale(${this.graphDom.transform.k})`, 'transform',
); `translate(${this.graph.transform.x},${this.graph.transform.y}) ` +
this.graphDom.width = graphDom.getBoundingClientRect().width; `scale(${this.graph.transform.k})`,
this.graphDom.height = graphDom.getBoundingClientRect().height; );
}
}, },
/** /**
* Displacement of the small map when the large picture is changed * Displacement of the small map when the large picture is changed
*/ */
bigMapPositionChange() { setInsideBoxData() {
const graphDom = document.querySelector('#graph #graph0'); const graphRect = this.graph.dom.getBoundingClientRect();
this.graphDom.top = const transRate = graphRect.width / this.smallResize.width;
graphDom.getBoundingClientRect().top - this.svg.offsetTop;
this.graphDom.left = this.insideBox.left = (this.svg.rect.left - graphRect.left) / transRate;
graphDom.getBoundingClientRect().left - this.svg.offsetLeft; this.insideBox.top = (this.svg.rect.top - graphRect.top) / transRate;
this.insideBox.left = parseFloat(
( this.insideBox.width = this.svg.rect.width / transRate;
this.graphSmall.initLeft - this.insideBox.height = this.svg.rect.height / transRate;
(this.graphDom.left / this.graphDom.width) * this.graphSmall.initWidth this.styleSet('#inside-box', this.insideBox);
).toFixed(3),
);
this.insideBox.top = parseFloat(
(
this.graphSmall.initTop -
(this.graphDom.top / this.graphDom.height) *
this.graphSmall.initHeight
).toFixed(3),
);
this.insideBox.height = this.smallResize.height * this.insideBox.scale;
this.insideBox.width = this.smallResize.width * this.insideBox.scale;
this.styleSet(this.insideBox, true);
}, },
/** /**
* Setting the width and height of a node * Setting the width and height of a node
* @param {Object} el dom node whose style needs to be modified * @param {String} id dom id whose style needs to be modified
* @param {Boolean} sizeChange Whether to change the width and height * @param {Object} domData data of dom
*/ */
styleSet(el, sizeChange) { styleSet(id, domData) {
const dom = document.querySelector(el.el); const dom = document.querySelector(id);
dom.style.left = `${el.left}px`; dom.style.left = `${domData.left}px`;
dom.style.top = `${el.top}px`; dom.style.top = `${domData.top}px`;
if (sizeChange) { dom.style.width = `${domData.width}px`;
dom.style.width = `${el.width}px`; dom.style.height = `${domData.height}px`;
dom.style.height = `${el.height}px`;
}
}, },
/** /**
* Expansion and folding of control edges * Expansion and folding of control edges
...@@ -2760,6 +2810,7 @@ export default { ...@@ -2760,6 +2810,7 @@ export default {
toggleRight() { toggleRight() {
this.rightShow = !this.rightShow; this.rightShow = !this.rightShow;
setTimeout(() => { setTimeout(() => {
this.initSvg();
this.initGraphRectData(); this.initGraphRectData();
}, 10); }, 10);
}, },
...@@ -2769,6 +2820,7 @@ export default { ...@@ -2769,6 +2820,7 @@ export default {
toggleScreen() { toggleScreen() {
this.fullScreen = !this.fullScreen; this.fullScreen = !this.fullScreen;
setTimeout(() => { setTimeout(() => {
this.initSvg();
this.initGraphRectData(); this.initGraphRectData();
}, 10); }, 10);
}, },
...@@ -2824,7 +2876,6 @@ export default { ...@@ -2824,7 +2876,6 @@ export default {
.guide { .guide {
cursor: pointer; cursor: pointer;
margin-left: 10px; margin-left: 10px;
line-height: 20px;
display: inline-block; display: inline-block;
line-height: 18px; line-height: 18px;
font-size: 12px; font-size: 12px;
...@@ -2989,7 +3040,7 @@ export default { ...@@ -2989,7 +3040,7 @@ export default {
padding: 0; padding: 0;
} }
#inside-box { #inside-box {
background-color: #c0d3ff; background-color: #5b88f1;
position: absolute; position: absolute;
/* Transparency */ /* Transparency */
opacity: 0.3; opacity: 0.3;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册