Browse Source

!1299 UI fix the bug of abnormal graph zoom function and extract the common code of graph and debugger

From: @huang_wei_feng4
Reviewed-by: @ouwenchang,@weiyanxi,@feng_xue_feng,@yelihua
Signed-off-by: @yelihua
pull/1299/MERGE
mindspore-ci-bot Gitee 4 years ago
parent
commit
6d85ba4774
5 changed files with 365 additions and 531 deletions
  1. +164
    -131
      mindinsight/ui/src/mixins/common-graph.vue
  2. +1
    -3
      mindinsight/ui/src/mixins/debugger-mixin.vue
  3. +145
    -152
      mindinsight/ui/src/mixins/small-map.vue
  4. +17
    -88
      mindinsight/ui/src/views/debugger/debugger.vue
  5. +38
    -157
      mindinsight/ui/src/views/train-manage/graph.vue

+ 164
- 131
mindinsight/ui/src/mixins/common-graph.vue View File

@@ -22,33 +22,83 @@ const d3 = {select, selectAll, zoom};
export default {
data() {
return {
graph: {
dom: Object,
size: Object, // When scale = 1
transform: Object,
minScale: Number,
defaultPadding: 4,
}, // Basic information about graph0 in svg
svg: {
size: Object,
},
graphviz: null,
graphvizTemp: null,
scaleRange: [0.001, 10], // graph zooms in and zooms out.
clickScope: {}, // Information about the node that is clicked for the first time.
frameSpace: 25, // Distance between the namespace border and the internal node
curColorIndex: 0,
totalMemory: 16777216 * 2, // Memory size of the graph plug-in
viewBox: {
max: 10000,
scale: {x: 1, y: 1},
},
allGraphData: {}, // graph Original input data
firstFloorNodes: [], // ID array of the first layer node.
nodesCountLimit: 4500, // Maximum number of sub-nodes in a namespace.
maxChainNum: 70,
graphContainer: null,
resizeDelay: 500, // The delay of resize's event
};
},
mounted() {
this.$nextTick(() => {
// Generate the dom of the submap.
if (!d3.select('#graphTemp').size()) {
d3.select('body').append('div').attr('id', 'graphTemp');
}
// Stores the dom of all the sorted subgraphs.
if (!d3.select('#subgraphTemp').size()) {
d3.select('body').append('div').attr('id', 'subgraphTemp');
}

this.graphContainer = document.querySelector('#graph');
if (this.graphContainer) {
this.graphContainer.addEventListener('click', this.controlEvent.bind(null, 'click'));
this.graphContainer.addEventListener('dblclick', this.controlEvent.bind(null, 'dblclick'));
}
});
},
methods: {
/**
* Handles and executes click and double-click events
* @param {String} type Event type
* @param {Object} event Event data
*/
controlEvent(type, event) {
if (!event) return;
const path = Array.from(event.path || (event.composedPath && event.composedPath()) || []);
let target;
for (let i = 0; i < path.length; i++) {
const classList = path[i].classList;
if (classList && classList.contains('node')) {
target = path[i];
break;
}
}

if (target) {
if (type === 'click') {
this.clickEvent(target, 'graph');
} else {
this.dblclickEvent(target, 'graph');
}
}
},
/**
* Initializing the click event
* @param {Object} target The target of the click event
* @param {Number} index Index of the target
* @param {Array} nodesList List of nodes on the page
* @param {String} pageKey Page identification mark
*/
clickEvent(target, index, nodesList, pageKey) {
// The target value of the element converted from the HTML attribute of the variable is null.
const event = currentEvent;
event.stopPropagation();
event.preventDefault();

const clickNode = nodesList[index];
const nodeId = clickNode.id;
const nodeClass = clickNode.classList.value;
clickEvent(target, pageKey) {
const nodeId = target.id;
const nodeClass = target.classList.value;
setTimeout(() => {
this.clickScope = {
id: nodeId,
@@ -69,20 +119,11 @@ export default {
/**
* Initializing the click event
* @param {Object} target The target of the click event
* @param {Number} index Index of the target
* @param {Array} nodesList List of nodes on the page
* @param {String} pageKey Page identification mark
*/
dblclickEvent(target, index, nodesList, pageKey) {
// The target of the element converted from the HTML attribute of the variable is empty and
// needs to be manually encapsulated.
const event = currentEvent;
event.stopPropagation();
event.preventDefault();

const clickNode = nodesList[index];
const nodeId = clickNode.id;
const nodeClass = clickNode.classList.value;
dblclickEvent(target, pageKey) {
const nodeId = target.id;
const nodeClass = target.classList.value;
let name = nodeId;
this.selectedNode.more =
name.indexOf('more...') !== -1 &&
@@ -147,61 +188,64 @@ export default {
.zoomScaleExtent(this.scaleRange)
.dot(dot)
.attributer(this.attributer)
.render(() => {
this.initSvg(true);
this.afterInitGraph();
});
.render(this.afterInitGraph);
} catch (error) {
const svg = document.querySelector('#graph svg');
if (svg) {
svg.remove();
}
if (svg) svg.remove();
this.initGraph(dot);
}

// Generate the dom of the submap.
if (!d3.select('#graphTemp').size()) {
d3.select('body').append('div').attr('id', 'graphTemp');
}
// Stores the dom of all the sorted subgraphs.
if (!d3.select('#subgraphTemp').size()) {
d3.select('body').append('div').attr('id', 'subgraphTemp');
}
},
/**
* Initialize svg
* @param {Bealoon} setSize Weather to set svg origin width and height
* Add the location attribute to each node to facilitate the obtaining of node location parameters.
*/
initSvg(setSize) {
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;
if (setSize) {
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;
}
afterInitGraph() {
const svg = document.querySelector('#graph svg');
if (svg) svg.removeAttribute('viewBox');

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];
setTimeout(() => {
const keys = ['_data', '_dictionary'];
if (this.graphviz) {
for (const key of keys) {
this.graphviz[key] = null;
}
this.graphviz = null;
}

if (this.graphvizTemp) {
for (const key of keys) {
this.graphvizTemp[key] = null;
}
this.graphvizTemp = null;
}
}, 100);

this.fitGraph('graph');
this.transplantChildrenDom();
const tempSvg = document.querySelector('#subgraphTemp svg');
if (tempSvg) tempSvg.remove();

const elements = Array.from(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();
d3.select('#graph g#graph0 title').remove();

this.startApp();
},
/**
* Initializing the graph zoom
* @param {String} pageKey
*/
initZooming(pageKey) {
const graphBox = this.graph.dom.getBBox();
const padding = 4;
const minDistance = 20;
const minDistance = 100;
const pointer = {start: {x: 0, y: 0}, end: {x: 0, y: 0}};
const zoom = d3
.zoom()
@@ -222,45 +266,13 @@ export default {
let tempStr = '';
let change = {};
let scale = transformData.scale[0];
const graphRect = this.graph.dom.getBoundingClientRect();
const transRate = graphBox.width / graphRect.width;
if (event.type === 'mousemove') {
pointer.end.x = event.x;
pointer.end.y = event.y;
let tempX = pointer.end.x - pointer.start.x;
let tempY = pointer.end.y - pointer.start.y;
const paddingTrans = Math.max(
(padding / transRate) / scale,
minDistance,
);
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);
}

change = {
x: tempX * transRate * scale,
y: tempY * transRate * scale,
x: pointer.end.x - pointer.start.x,
y: pointer.end.y - pointer.start.y,
};
pointer.start.x = pointer.end.x;
pointer.start.y = pointer.end.y;
@@ -276,12 +288,12 @@ export default {
scale = Math.min(this.scaleRange[1], scale);
change = {
x:
(graphRect.x + padding / transRate - event.x) *
transRate *
((this.svg.size.left - this.graph.defaultPadding - event.x + this.graph.transform.x) /
transformData.scale[0]) *
(scale - transformData.scale[0]),
y:
(graphRect.bottom - padding / transRate - event.y) *
transRate *
((this.svg.size.top + this.graph.transform.y - this.graph.defaultPadding - event.y) /
transformData.scale[0]) *
(scale - transformData.scale[0]),
};
}
@@ -291,8 +303,14 @@ export default {
y: transformData.translate[1] + change.y,
k: scale,
};
this.graph.transRate =
graphRect.width / graphBox.width / this.graph.transform.k;

this.graph.transform.x = Math.max(minDistance - this.graph.size.width * scale, this.graph.transform.x);
this.graph.transform.x = Math.min(this.svg.size.width - minDistance, this.graph.transform.x);
this.graph.transform.y = Math.max(this.graph.transform.y, minDistance);
this.graph.transform.y = Math.min(
this.graph.size.height * scale + this.svg.size.height - minDistance,
this.graph.transform.y
);

tempStr =
`translate(${this.graph.transform.x},${this.graph.transform.y}) ` +
@@ -335,33 +353,33 @@ export default {
*/
fitGraph(id) {
const graph = document.getElementById(id);
const maxShowWidth = graph.offsetWidth * 1.5;
const maxShowHeight = graph.offsetHeight * 1.5;
const maxShowWidth = graph.offsetWidth;
const maxShowHeight = graph.offsetHeight;
const graphDom = document.querySelector(`#${id} #graph0`);
const box = graphDom.getBBox();
let transformStr = '';
const graphTransformData = this.getTransformData(graphDom);
if (box.width > maxShowWidth || box.height > maxShowHeight) {
const scale = Math.max(
box.width / maxShowWidth / this.viewBox.scale.x,
box.height / maxShowHeight / this.viewBox.scale.y,
);
const translate = {x: (box.width - maxShowWidth) / 2};
let {
translate: [x, y],
scale: [scale],
} = this.getTransformData(graphDom);

if (!this.selectedNode.name) {
graphTransformData.translate[0] = translate.x;
}
graphTransformData.scale[0] = scale;
if (this.selectedNode.more) {
scale = this.graph.transform.k;
} else {
graphTransformData.translate = [-box.x, -box.y];
}
if (id === 'graph' && this.selectedNode.more) {
graphTransformData.scale[0] = this.graph.transform.k;
if (box.width <= maxShowWidth && box.height <= maxShowHeight) {
const showAreaRite = 0.8;
scale = Math.min((maxShowWidth * showAreaRite) / box.width, (maxShowHeight * showAreaRite) / box.height);
x = (maxShowWidth - box.width * scale) / 2 + scale * this.graph.defaultPadding;
y = (maxShowHeight + box.height * scale) / 2 - scale * this.graph.defaultPadding;
} else if (box.width > maxShowWidth && box.height > maxShowHeight) {
x = -(box.width * scale - maxShowWidth) / 2;
} else if (box.width <= maxShowWidth) {
x = (maxShowWidth - box.width * scale) / 2;
} else if (box.height <= maxShowHeight) {
y = maxShowHeight / 2 + box.height / 2;
}
}
Object.keys(graphTransformData).forEach((key) => {
transformStr += `${key}(${graphTransformData[key].join(',')}) `;
});
graphDom.setAttribute('transform', transformStr.trim());

graphDom.setAttribute('transform', `translate(${x},${y}) scale(${scale})`);
},
/**
* Expand a namespace.
@@ -386,7 +404,8 @@ export default {
}
})
.render(() => {
this.fitGraph('graphTemp');
const svg = document.querySelector('#graphTemp svg');
if (svg) svg.removeAttribute('viewBox');
this.dealNamescopeTempGraph(name);
});
} catch (error) {
@@ -1519,5 +1538,19 @@ export default {
}
},
},
destroyed() {
if (this.graphContainer) {
this.graphContainer.removeEventListener('click', this.controlEvent);
this.graphContainer.removeEventListener('dblclick', this.controlEvent);
}
},
};
</script>
<style>
#graphTemp,
#subgraphTemp {
position: absolute;
bottom: 0;
visibility: hidden;
}
</style>

+ 1
- 3
mindinsight/ui/src/mixins/debugger-mixin.vue View File

@@ -136,9 +136,7 @@ export default {
*/
collapseBtnClick() {
this.leftShow = !this.leftShow;
setTimeout(() => {
this.initSvg(false);
}, 500);
setTimeout(this.initSvgSize, this.resizeDelay);
},
/**
* Step input validation


+ 145
- 152
mindinsight/ui/src/mixins/small-map.vue View File

@@ -14,61 +14,135 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
<script>
import CommonProperty from '@/common/common-property.js';
export default {
data() {
return {
smallResize: {}, // The container of display area box.
insideBox: {}, // Basic information about the display area box
eventSmall: {}, // Relative position of the thumbnail in the thumbnail click event
smallContainer: {},
smallMap: {}, // The container of display area box.
insideBox: {
width: 0,
height: 0,
left: 0,
top: 0,
}, // Basic information about the display area box

// 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.
clickSmall: false,
smallMapEventTimer: null,
eventDelay: 200,
};
},

methods: {
initSmallMap() {
this.initSmallContainer();
this.drawCanvas();
this.initGraphRectData();
this.setSmallMapEvents();
},
/**
* Initialize the small image container
*/
initSmallContainer() {
const svgRect = document.querySelector('#graph svg').getBoundingClientRect();
this.svg.size = {width: svgRect.width, height: svgRect.height, left: svgRect.left, top: svgRect.top};
this.graph.dom = document.querySelector('#graph #graph0');
const graphBox = this.graph.dom.getBBox();
this.graph.size = {width: graphBox.width, height: graphBox.height};
// Attributes of smallContainer
const smallContainer = document.querySelector('#small-container');
const containerRect = smallContainer.getBoundingClientRect();
const borderWidth = 1;
this.smallContainer = {
left: containerRect.left + borderWidth,
top: containerRect.top + borderWidth,
height: containerRect.height - borderWidth * 2,
width: containerRect.width - borderWidth * 2,
};

// Initial width of the thumbnail frame
this.smallMap.width = this.smallContainer.width;
// The initial height of the thumbnail frame is high.
this.smallMap.height = this.smallContainer.height;
this.smallMap.left = this.smallMap.top = 0;
if (Object.keys(this.allGraphData).length) {
if (this.graph.size.width / this.graph.size.height < this.smallContainer.width / this.smallContainer.height) {
this.smallMap.width = (this.smallContainer.height * this.graph.size.width) / this.graph.size.height;
this.smallMap.left = (this.smallContainer.width - this.smallMap.width) / 2;
} else {
this.smallMap.height = (this.smallContainer.width * this.graph.size.height) / this.graph.size.width;
this.smallMap.top = (this.smallContainer.height - this.smallMap.height) / 2;
}
}
},
/**
* Draw canvas image with svg
*/
drawCanvas() {
const svgDom = document.querySelector('#graph svg').cloneNode(true);
const style = document.createElement('style');
svgDom.append(style);
style.outerHTML = CommonProperty.graphDownloadStyle;

svgDom.setAttribute('width', this.graph.size.width);
svgDom.setAttribute('height', this.graph.size.height);
const transform = `translate(${this.graph.defaultPadding},${
this.graph.size.height - this.graph.defaultPadding
}) scale(1)`;
svgDom.querySelector('g').setAttribute('transform', transform);

const svgXml = new XMLSerializer().serializeToString(svgDom);
const svg = new Blob([svgXml], {type: 'image/svg+xml;charset=utf-8'});

const domUrl = self.URL || self;
const url = domUrl.createObjectURL(svg);

const image = new Image();
image.onload = () => {
const canvas = this.$refs.canvas;
const context = canvas.getContext('2d');
context.clearRect(0, 0, this.smallContainer.width, this.smallContainer.height);
context.drawImage(
image,
0,
0,
this.graph.size.width,
this.graph.size.height,
this.smallMap.left,
this.smallMap.top,
this.smallMap.width,
this.smallMap.height,
);
};
image.src = url;
},
/**
* Initialize the svg, width and height of the small image, and transform information.
*/
initGraphRectData() {
this.initSmallContainer();

if (!this.graph.dom) {
this.insideBox.width = this.smallResize.width;
this.insideBox.height = this.smallResize.height;
this.insideBox.width = this.smallMap.width;
this.insideBox.height = this.smallMap.height;
this.insideBox.top = this.insideBox.left = 0;
this.styleSet('#inside-box', this.insideBox);
this.insideBox.style.cursor = 'not-allowed';
} else {
let transformString = '';
const transTemp = this.graph.dom.attributes.transform || null;
if (transTemp) {
// transform information of graph
transformString = transTemp.nodeValue.split(/[(,)]/);
} else {
transformString = ['translate', '0', '0', ' scale', '1'];
}
const transform = this.getTransformData(this.graph.dom);

this.graph.transform = {
k: parseFloat(transformString[4]),
x: parseFloat(transformString[1]),
y: parseFloat(transformString[2]),
k: parseFloat(transform.scale[0]),
x: parseFloat(transform.translate[0]),
y: parseFloat(transform.translate[1]),
};

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.graph.minScale = Math.min(
this.svg.size.width / 2 / this.graph.size.width,
this.svg.size.height / 2 / this.graph.size.height,
);

this.setInsideBoxData();
}
this.setSmallMapEvents();
},
/**
* Initialize all events of the small image
@@ -83,14 +157,12 @@ export default {
this.insideBoxPositionChange(e);
};

document.onmouseup = (e) => {
this.clickSmall = false;
};
smallContainer.onmouseup = () => (this.clickSmall = false);
smallContainer.onmouseleave = () => (this.clickSmall = false);

smallContainer.onmousemove = (e) => {
if (this.clickSmall) {
this.insideBoxPositionChange(e);
}
if (!this.clickSmall) return;
this.insideBoxPositionChange(e);
};

// Mouse wheel event
@@ -98,35 +170,20 @@ export default {
e = e || window.event;
const wheelDelta = e.wheelDelta ? e.wheelDelta : -e.deltaY;
if (!isNaN(this.graph.transform.k) && this.graph.transform.k !== 0) {
let rate = wheelDelta > 0 ? 1.2 : 1 / 1.2;
const rate = wheelDelta > 0 ? 1.2 : 1 / 1.2;

let scaleTemp = this.graph.transform.k / rate;
if (scaleTemp <= this.graph.minScale) {
scaleTemp = this.graph.minScale;
rate = this.graph.transform.k / this.graph.minScale;
const scaleTemp = this.graph.transform.k / rate;
if (scaleTemp < this.graph.minScale || scaleTemp < this.scaleRange[0] || scaleTemp > this.scaleRange[1]) {
return;
}

this.graph.transform.k = Math.max(
this.scaleRange[0],
Math.min(scaleTemp, this.scaleRange[1]),
);
this.insideBox.scale = 1 / this.graph.transform.k;

this.graph.transform.k = scaleTemp;
this.insideBox.scale = 1 / scaleTemp;
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();
}
};
@@ -137,130 +194,66 @@ export default {
smallContainer.onmousewheel = null;
}
},
/**
* Initialize the small image container
*/
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.
const smallResize = document.querySelector('#small-resize');

this.smallResize.width = this.smallResize.initWidth =
smallContainer.offsetWidth - 2; // Initial width of the thumbnail frame
this.smallResize.height = this.smallResize.initHeight =
smallContainer.offsetHeight - 2; // The initial height of the thumbnail frame is high.
this.smallResize.left = this.smallResize.top = 0;
if (Object.keys(this.allGraphData).length) {
if (
this.svg.originSize.width / this.svg.originSize.height <
this.smallResize.initWidth / this.smallResize.initHeight
) {
this.smallResize.width =
(this.smallResize.initHeight * this.svg.originSize.width) /
this.svg.originSize.height;
this.smallResize.left =
(this.smallResize.initWidth - this.smallResize.width) / 2;
} else {
this.smallResize.height =
(this.smallResize.initWidth * this.svg.originSize.height) /
this.svg.originSize.width;
this.smallResize.top =
(this.smallResize.initHeight - this.smallResize.height) / 2;
}
}
this.styleSet('#small-resize', this.smallResize);
// Distance between the thumbnail frame and the upper part of the window
this.smallResize.offsetLeft = smallResize.getBoundingClientRect().left;
// Distance between the thumbnail frame and the upper part of the window
this.smallResize.offsetTop = smallResize.getBoundingClientRect().top;

// Attributes of smallMap
const smallMap = document.querySelector('#small-map');
const svgOuterHtml =
`<svg xmlns="http://www.w3.org/2000/svg" ` +
`xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" ` +
`viewBox="0.00 0.00 ${this.svg.originSize.width} ${this.svg.originSize.height}"` +
`><g id="smallGraph" class="graph" transform="translate(4,${
this.svg.originSize.height - 4
}) scale(1)"` +
`>${this.graph.dom.innerHTML}</g></svg>`;

smallMap.innerHTML = svgOuterHtml;
},
/**
* Small image moving
* @param {Object} e Event object
*/
insideBoxPositionChange(e) {
this.eventSmall.x = e.pageX - this.smallResize.offsetLeft;
this.eventSmall.y = e.pageY - this.smallResize.offsetTop;

this.insideBox.left =
this.eventSmall.x - parseFloat(this.insideBox.width) / 2;
this.insideBox.top =
this.eventSmall.y - parseFloat(this.insideBox.height) / 2;
this.insideBox.left = e.x - this.smallContainer.left - parseFloat(this.insideBox.width) / 2;
this.insideBox.top = e.y - this.smallContainer.top - parseFloat(this.insideBox.height) / 2;

this.styleSet('#inside-box', this.insideBox);
this.graphChange();
if (this.smallMapEventTimer) clearTimeout(this.smallMapEventTimer);
this.smallMapEventTimer = setTimeout(this.graphChange, this.eventDelay);
},
/**
* Displacement of the large picture when the small picture is changed
*/
graphChange() {
if (!this.graph.transform.x || isNaN(this.graph.transform.x)) {
this.initGraphRectData();
this.initSmallMap();
}
const graphRect = this.graph.dom.getBoundingClientRect();

const graphSizeRate = this.svg.rect.width / this.insideBox.width;

const change = {
x:
(this.insideBox.left * graphSizeRate -
(this.svg.rect.left - graphRect.left)) /
this.graph.transRate,
y:
(this.insideBox.top * graphSizeRate -
(this.svg.rect.top - graphRect.top)) /
this.graph.transRate,
};

this.graph.transform.x -= change.x;
this.graph.transform.y -= change.y;
const transRate = this.smallMap.width / (this.graph.size.width * this.graph.transform.k);
this.graph.transform.x =
-(this.insideBox.left - this.smallMap.left) / transRate + this.graph.defaultPadding * this.graph.transform.k;
this.graph.transform.y =
-(this.insideBox.top - this.smallMap.top) / transRate +
(this.graph.size.height - this.graph.defaultPadding) * this.graph.transform.k;

this.graph.dom.setAttribute(
'transform',
`translate(${this.graph.transform.x},${this.graph.transform.y}) ` +
`scale(${this.graph.transform.k})`,
`translate(${this.graph.transform.x},${this.graph.transform.y}) scale(${this.graph.transform.k})`,
);
},
/**
* Displacement of the small map when the large picture is changed
*/
setInsideBoxData() {
const graphRect = this.graph.dom.getBoundingClientRect();
const transRate = graphRect.width / this.smallResize.width;

this.insideBox.left = (this.svg.rect.left - graphRect.left) / transRate;
this.insideBox.top = (this.svg.rect.top - graphRect.top) / transRate;
const rate = this.smallMap.width / (this.graph.size.width * this.graph.transform.k);
this.insideBox.left =
this.smallMap.left - (this.graph.transform.x - this.graph.defaultPadding * this.graph.transform.k) * rate;
this.insideBox.top =
this.smallMap.top -
(this.graph.transform.y +
this.graph.defaultPadding * this.graph.transform.k -
this.graph.size.height * this.graph.transform.k) *
rate;

this.insideBox.width = this.svg.rect.width / transRate;
this.insideBox.height = this.svg.rect.height / transRate;
this.styleSet('#inside-box', this.insideBox);
this.insideBox.width = this.svg.size.width * rate;
this.insideBox.height = this.svg.size.height * rate;
},
/**
* Setting the width and height of a node
* @param {String} id Dom id whose style needs to be modified
* @param {Object} domData Data of dom
* @return {Object}
*/
styleSet(id, domData) {
const dom = document.querySelector(id);
dom.style.left = `${domData.left}px`;
dom.style.top = `${domData.top}px`;
dom.style.width = `${domData.width}px`;
dom.style.height = `${domData.height}px`;
styleSet(domData) {
const keys = ['width', 'height', 'left', 'top'];
const styleObj = {};
for (const key of keys) {
styleObj[key] = domData[key] + 'px';
}
return styleObj;
},
},
destroyed() {


+ 17
- 88
mindinsight/ui/src/views/debugger/debugger.vue View File

@@ -833,16 +833,7 @@ export default {
value: '',
},
devices: [],
allGraphData: {}, // Graph Original input data
firstFloorNodes: [], // ID array of the first layer node.
nodesCountLimit: 1500, // Maximum number of sub-nodes in a namespace.
maxChainNum: 70,
scaleRange: [0.001, 1000], // Graph zooms in and zooms out.
graphviz: null,
graphvizTemp: null,
graph: {},
selectedNode: {},
svg: {},
contextmenu: {
point: {},
id: 'contextMenu',
@@ -1217,48 +1208,13 @@ export default {
/** ************************ graph **********************/

/**
* Add the location attribute to each node to facilitate the obtaining of node location parameters.
* Initialization method executed after the graph rendering is complete
*/
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();
}
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];
}
});
// The graph generated by the plug-in has a useless title and needs to be deleted.
const title = document.querySelector('#graph g#graph0 title');
if (title) {
title.remove();
}
d3.selectAll('g.edge>title').remove();

startApp() {
this.initSvgSize();
this.graph.dom = document.querySelector(`#graph #graph0`);
const graphRect = this.graph.dom.getBoundingClientRect();
const graphBox = this.graph.dom.getBBox();
this.graph.size = {width: graphBox.width, height: graphBox.height};
let transform = '';
if (this.graph.dom.getAttribute('transform')) {
// transform information of graph
@@ -1272,31 +1228,9 @@ export default {
y: parseFloat(transform[2]),
};

this.graph.minScale =
Math.min(this.svg.rect.width / 2 / graphRect.width, this.svg.rect.height / 2 / graphRect.height) *
this.graph.transform.k;

this.startApp();
},
/**
* Initialization method executed after the graph rendering is complete
*/
startApp() {
const nodes = d3.selectAll('g.node, g.cluster');
nodes.on(
'click',
(target, index, nodesList) => {
this.clickEvent(target, index, nodesList, 'debugger');
},
false,
);
// namespaces Expansion or Reduction
nodes.on(
'dblclick',
(target, index, nodesList) => {
this.dblclickEvent(target, index, nodesList, 'debugger');
},
false,
this.graph.minScale = Math.min(
this.svg.size.width / 2 / this.graph.size.width,
this.svg.size.height / 2 / this.graph.size.height
);
this.initZooming('debugger');
this.initContextMenu();
@@ -1683,12 +1617,12 @@ export default {
graphObj.initHeight = graphObj.rect.height / this.graph.transform.k;

const screenChange = {
x: nodeRect.left + nodeRect.width / 2 - (this.svg.rect.left + this.svg.rect.width / 2),
y: nodeRect.top + nodeRect.height / 2 - (this.svg.rect.top + this.svg.rect.height / 2),
x: nodeRect.left + nodeRect.width / 2 - (this.svg.size.left + this.svg.size.width / 2),
y: nodeRect.top + nodeRect.height / 2 - (this.svg.size.top + this.svg.size.height / 2),
};

this.graph.transform.x -= screenChange.x * (this.svg.originSize.width / graphObj.initWidth);
this.graph.transform.y -= screenChange.y * (this.svg.originSize.height / graphObj.initHeight);
this.graph.transform.x -= screenChange.x * (this.graph.size.width / graphObj.initWidth);
this.graph.transform.y -= screenChange.y * (this.graph.size.height / graphObj.initHeight);

this.graph.dom.setAttribute(
'transform',
@@ -1852,9 +1786,11 @@ export default {
},
rightCollapse() {
this.collapseTable = !this.collapseTable;
setTimeout(() => {
this.initSvg(false);
}, 500);
setTimeout(this.initSvgSize, this.resizeDelay);
},
initSvgSize() {
const svgRect = document.querySelector('#graph svg').getBoundingClientRect();
this.svg.size = {width: svgRect.width, height: svgRect.height, left: svgRect.left, top: svgRect.top};
},
},
destroyed() {},
@@ -2513,11 +2449,4 @@ export default {
.deb-indent {
padding-left: 40px;
}

#graphTemp,
#subgraphTemp {
position: absolute;
bottom: 0;
visibility: hidden;
}
</style>

+ 38
- 157
mindinsight/ui/src/views/train-manage/graph.vue View File

@@ -221,10 +221,11 @@ limitations under the License.
</div>
<!-- Functional Area -->
<div id="small-container">
<div id="small-resize">
<div id="small-map"></div>
<div id="inside-box"></div>
</div>
<div id="inside-box"
:style="styleSet(insideBox)"></div>
<canvas ref="canvas"
:width="smallContainer.width"
:height="smallContainer.height"></canvas>
</div>
<!-- Node information -->
<div :class="
@@ -507,11 +508,6 @@ export default {
data() {
return {
summaryPath: this.$route.query.summaryPath,
graph: {}, // Basic information about graph0 in svg
svg: {}, // Basic information about svg

allGraphData: {}, // graph Original input data
firstFloorNodes: [], // ID array of the first layer node.
// Information about the selected node
selectedNode: {
info: {
@@ -528,9 +524,6 @@ export default {
},
// Training job id
trainJobID: '',
nodesCountLimit: 1500, // Maximum number of sub-nodes in a namespace.
maxChainNum: 70,

// Node search box
searchBox: {
value: '',
@@ -546,11 +539,8 @@ export default {
show: false,
info: '',
},
scaleRange: [0.001, 1000], // graph zooms in and zooms out.
rightShow: true, // Check whether the right side bar is displayed.
fullScreen: false, // Display Full Screen
graphviz: null,
graphvizTemp: null,
initOver: false,
guide: {
show: false,
@@ -627,20 +617,18 @@ export default {
window.localStorage.setItem('milang', this.language);
}

document.title = `${decodeURIComponent(this.trainJobID)}-${this.$t(
'graph.titleText',
)}-MindInsight`;
this.getDatavisualPlugins();
document.title = `${decodeURIComponent(this.trainJobID)}-${this.$t('graph.titleText')}-MindInsight`;
window.onresize = () => {
if (this.graph.dom) {
this.$nextTick(() => {
setTimeout(() => {
this.initSvg(false);
this.initGraphRectData();
}, 500);
this.initSmallMap();
}, this.resizeDelay);
});
}
};

this.$nextTick(this.getDatavisualPlugins);
},
destroyed() {
window.onresize = null;
@@ -789,69 +777,15 @@ export default {
this.querySingleNode({value: data.name});
}
},
/**
* 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
*/
startApp() {
const nodes = d3.selectAll('g.node, g.cluster');
nodes.on(
'click',
(target, index, nodesList) => {
this.clickEvent(target, index, nodesList, 'graph');
},
false,
);
// namespaces Expansion or Reduction
nodes.on(
'dblclick',
(target, index, nodesList) => {
this.dblclickEvent(target, index, nodesList, 'graph');
},
false,
);
this.$nextTick(() => {
this.loading.show = false;
});
this.initSmallMap();
this.initZooming('graph');
if (this.selectedNode.name) {
this.selectNode(true);
@@ -940,7 +874,7 @@ export default {
this.layoutNamescope(name, true);
}
} else {
this.initGraphRectData();
this.initSmallMap();
this.loading.show = false;
}
const data = response.data.nodes.map((val) => {
@@ -1212,25 +1146,16 @@ export default {
graph.initHeight = graph.rect.height / this.graph.transform.k;

const screenChange = {
x:
nodeRect.left +
nodeRect.width / 2 -
(this.svg.rect.left + this.svg.rect.width / 2),
y:
nodeRect.top +
nodeRect.height / 2 -
(this.svg.rect.top + this.svg.rect.height / 2),
x: nodeRect.left + nodeRect.width / 2 - (this.svg.size.left + this.svg.size.width / 2),
y: nodeRect.top + nodeRect.height / 2 - (this.svg.size.top + this.svg.size.height / 2),
};

this.graph.transform.x -=
screenChange.x * (this.svg.originSize.width / graph.initWidth);
this.graph.transform.y -=
screenChange.y * (this.svg.originSize.height / graph.initHeight);
this.graph.transform.x -= screenChange.x * (this.graph.size.width / graph.initWidth);
this.graph.transform.y -= screenChange.y * (this.graph.size.height / graph.initHeight);

this.graph.dom.setAttribute(
'transform',
`translate(${this.graph.transform.x},` +
`${this.graph.transform.y}) scale(${this.graph.transform.k})`,
`translate(${this.graph.transform.x},${this.graph.transform.y}) scale(${this.graph.transform.k})`
);

const transitionTime = Math.min(
@@ -1625,20 +1550,14 @@ export default {
*/
toggleRight() {
this.rightShow = !this.rightShow;
setTimeout(() => {
this.initSvg(false);
this.initGraphRectData();
}, 500);
setTimeout(this.initSmallMap, this.resizeDelay);
},
/**
* Full-screen display
*/
toggleScreen() {
this.fullScreen = !this.fullScreen;
setTimeout(() => {
this.initSvg(false);
this.initGraphRectData();
}, 500);
setTimeout(this.initSmallMap, this.resizeDelay);
},
/**
* Download svg
@@ -1929,23 +1848,9 @@ export default {
background-color: white;
position: relative;
}
.cl-graph-manage #graphs #sidebar #small-container #small-resize {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.cl-graph-manage #graphs #sidebar #small-container #small-map {
height: 100%;
width: 100%;
position: relative;
padding: 0;
}
.cl-graph-manage #graphs #sidebar #small-container #inside-box {
background-color: #5b88f1;
position: absolute;
/* Transparency */
opacity: 0.3;
width: 100%;
height: 100%;
@@ -2207,8 +2112,7 @@ export default {
stroke: red !important;
stroke-width: 2px;
}
.cl-graph-manage #graphs .graph-container,
.cl-graph-manage #graphs #small-map {
.cl-graph-manage #graphs .graph-container {
font-size: 16px;
position: relative;
display: inline-block;
@@ -2222,76 +2126,60 @@ export default {
-ms-user-select: none;
user-select: none;
}
.cl-graph-manage #graphs .graph-container .graph,
.cl-graph-manage #graphs #small-map .graph {
.cl-graph-manage #graphs .graph-container .graph {
height: 100%;
background-color: #f7faff;
}
.cl-graph-manage #graphs .graph-container #graph0 > polygon,
.cl-graph-manage #graphs #small-map #graph0 > polygon {
.cl-graph-manage #graphs .graph-container #graph0 > polygon {
fill: transparent;
}
.cl-graph-manage #graphs .graph-container .node,
.cl-graph-manage #graphs #small-map .node {
.cl-graph-manage #graphs .graph-container .node {
cursor: pointer;
}
.cl-graph-manage #graphs .graph-container .edge path,
.cl-graph-manage #graphs #small-map .edge path {
.cl-graph-manage #graphs .graph-container .edge path {
stroke: #787878;
}
.cl-graph-manage #graphs .graph-container .edge polygon,
.cl-graph-manage #graphs #small-map .edge polygon {
.cl-graph-manage #graphs .graph-container .edge polygon {
fill: #787878;
}
.cl-graph-manage #graphs .graph-container .edge.highlighted path,
.cl-graph-manage #graphs #small-map .edge.highlighted path {
.cl-graph-manage #graphs .graph-container .edge.highlighted path {
stroke: red;
}
.cl-graph-manage #graphs .graph-container .edge.highlighted polygon,
.cl-graph-manage #graphs #small-map .edge.highlighted polygon {
.cl-graph-manage #graphs .graph-container .edge.highlighted polygon {
stroke: red;
fill: red;
}
.cl-graph-manage #graphs .graph-container .edge.highlighted marker path,
.cl-graph-manage #graphs #small-map .edge.highlighted marker path {
.cl-graph-manage #graphs .graph-container .edge.highlighted marker path {
fill: red;
}
.cl-graph-manage #graphs .graph-container .node.aggregation > polygon,
.cl-graph-manage #graphs #small-map .node.aggregation > polygon {
.cl-graph-manage #graphs .graph-container .node.aggregation > polygon {
stroke: #e3aa00;
fill: #ffe794;
}
.cl-graph-manage #graphs .graph-container .node.cluster.aggregation > rect,
.cl-graph-manage #graphs #small-map .node.cluster.aggregation > rect {
.cl-graph-manage #graphs .graph-container .node.cluster.aggregation > rect {
stroke: #e3aa00;
fill: #ffe794;
stroke-dasharray: 3, 3;
}
.cl-graph-manage #graphs .graph-container .node > polygon,
.cl-graph-manage #graphs #small-map .node > polygon {
.cl-graph-manage #graphs .graph-container .node > polygon {
stroke: #00a5a7;
fill: #8df1f2;
}
.cl-graph-manage #graphs .graph-container .node > ellipse,
.cl-graph-manage #graphs #small-map .node > ellipse {
.cl-graph-manage #graphs .graph-container .node > ellipse {
stroke: #4ea6e6;
fill: #b8e0ff;
}
.cl-graph-manage #graphs .graph-container .plain > path,
.cl-graph-manage #graphs .graph-container .plain ellipse,
.cl-graph-manage #graphs #small-map .plain > path,
.cl-graph-manage #graphs #small-map .plain ellipse {
.cl-graph-manage #graphs .graph-container .plain ellipse {
stroke: #e37d29;
fill: #ffd0a6;
stroke-dasharray: 1.5, 1.5;
}
.cl-graph-manage #graphs .graph-container .edge-point ellipse,
.cl-graph-manage #graphs #small-map .edge-point ellipse {
.cl-graph-manage #graphs .graph-container .edge-point ellipse {
stroke: #a7a7a7;
fill: #a7a7a7;
}
.cl-graph-manage #graphs .graph-container text,
.cl-graph-manage #graphs #small-map text {
.cl-graph-manage #graphs .graph-container text {
fill: black;
}
.cl-graph-manage #graphs .image-noData {
@@ -2328,11 +2216,4 @@ export default {
.cl-graph-manage .cl-title-right {
padding-right: 32px;
}

#graphTemp,
#subgraphTemp {
position: absolute;
bottom: 0;
visibility: hidden;
}
</style>

Loading…
Cancel
Save