| @@ -22,33 +22,83 @@ const d3 = {select, selectAll, zoom}; | |||||
| export default { | export default { | ||||
| data() { | data() { | ||||
| return { | 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. | clickScope: {}, // Information about the node that is clicked for the first time. | ||||
| frameSpace: 25, // Distance between the namespace border and the internal node | frameSpace: 25, // Distance between the namespace border and the internal node | ||||
| curColorIndex: 0, | curColorIndex: 0, | ||||
| totalMemory: 16777216 * 2, // Memory size of the graph plug-in | 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: { | 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 | * Initializing the click event | ||||
| * @param {Object} target The target of 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 | * @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(() => { | setTimeout(() => { | ||||
| this.clickScope = { | this.clickScope = { | ||||
| id: nodeId, | id: nodeId, | ||||
| @@ -69,20 +119,11 @@ export default { | |||||
| /** | /** | ||||
| * Initializing the click event | * Initializing the click event | ||||
| * @param {Object} target The target of 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 | * @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; | let name = nodeId; | ||||
| this.selectedNode.more = | this.selectedNode.more = | ||||
| name.indexOf('more...') !== -1 && | name.indexOf('more...') !== -1 && | ||||
| @@ -147,61 +188,64 @@ export default { | |||||
| .zoomScaleExtent(this.scaleRange) | .zoomScaleExtent(this.scaleRange) | ||||
| .dot(dot) | .dot(dot) | ||||
| .attributer(this.attributer) | .attributer(this.attributer) | ||||
| .render(() => { | |||||
| this.initSvg(true); | |||||
| this.afterInitGraph(); | |||||
| }); | |||||
| .render(this.afterInitGraph); | |||||
| } catch (error) { | } catch (error) { | ||||
| const svg = document.querySelector('#graph svg'); | const svg = document.querySelector('#graph svg'); | ||||
| if (svg) { | |||||
| svg.remove(); | |||||
| } | |||||
| if (svg) svg.remove(); | |||||
| this.initGraph(dot); | 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 | * Initializing the graph zoom | ||||
| * @param {String} pageKey | * @param {String} pageKey | ||||
| */ | */ | ||||
| initZooming(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 pointer = {start: {x: 0, y: 0}, end: {x: 0, y: 0}}; | ||||
| const zoom = d3 | const zoom = d3 | ||||
| .zoom() | .zoom() | ||||
| @@ -222,45 +266,13 @@ export default { | |||||
| let tempStr = ''; | let tempStr = ''; | ||||
| let change = {}; | let change = {}; | ||||
| let scale = transformData.scale[0]; | 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') { | ||||
| pointer.end.x = event.x; | pointer.end.x = event.x; | ||||
| pointer.end.y = event.y; | 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 = { | 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.x = pointer.end.x; | ||||
| pointer.start.y = pointer.end.y; | pointer.start.y = pointer.end.y; | ||||
| @@ -276,12 +288,12 @@ export default { | |||||
| scale = Math.min(this.scaleRange[1], scale); | scale = Math.min(this.scaleRange[1], scale); | ||||
| change = { | change = { | ||||
| x: | 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]), | (scale - transformData.scale[0]), | ||||
| y: | 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]), | (scale - transformData.scale[0]), | ||||
| }; | }; | ||||
| } | } | ||||
| @@ -291,8 +303,14 @@ export default { | |||||
| y: transformData.translate[1] + change.y, | y: transformData.translate[1] + change.y, | ||||
| k: scale, | 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 = | tempStr = | ||||
| `translate(${this.graph.transform.x},${this.graph.transform.y}) ` + | `translate(${this.graph.transform.x},${this.graph.transform.y}) ` + | ||||
| @@ -335,33 +353,33 @@ export default { | |||||
| */ | */ | ||||
| fitGraph(id) { | fitGraph(id) { | ||||
| const graph = document.getElementById(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 graphDom = document.querySelector(`#${id} #graph0`); | ||||
| const box = graphDom.getBBox(); | 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 { | } 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. | * Expand a namespace. | ||||
| @@ -386,7 +404,8 @@ export default { | |||||
| } | } | ||||
| }) | }) | ||||
| .render(() => { | .render(() => { | ||||
| this.fitGraph('graphTemp'); | |||||
| const svg = document.querySelector('#graphTemp svg'); | |||||
| if (svg) svg.removeAttribute('viewBox'); | |||||
| this.dealNamescopeTempGraph(name); | this.dealNamescopeTempGraph(name); | ||||
| }); | }); | ||||
| } catch (error) { | } 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> | </script> | ||||
| <style> | |||||
| #graphTemp, | |||||
| #subgraphTemp { | |||||
| position: absolute; | |||||
| bottom: 0; | |||||
| visibility: hidden; | |||||
| } | |||||
| </style> | |||||
| @@ -136,9 +136,7 @@ export default { | |||||
| */ | */ | ||||
| collapseBtnClick() { | collapseBtnClick() { | ||||
| this.leftShow = !this.leftShow; | this.leftShow = !this.leftShow; | ||||
| setTimeout(() => { | |||||
| this.initSvg(false); | |||||
| }, 500); | |||||
| setTimeout(this.initSvgSize, this.resizeDelay); | |||||
| }, | }, | ||||
| /** | /** | ||||
| * Step input validation | * Step input validation | ||||
| @@ -14,61 +14,135 @@ See the License for the specific language governing permissions and | |||||
| limitations under the License. | limitations under the License. | ||||
| --> | --> | ||||
| <script> | <script> | ||||
| import CommonProperty from '@/common/common-property.js'; | |||||
| export default { | export default { | ||||
| data() { | data() { | ||||
| return { | 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, | // 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: false, | clickSmall: false, | ||||
| smallMapEventTimer: null, | |||||
| eventDelay: 200, | |||||
| }; | }; | ||||
| }, | }, | ||||
| methods: { | 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. | * Initialize the svg, width and height of the small image, and transform information. | ||||
| */ | */ | ||||
| initGraphRectData() { | initGraphRectData() { | ||||
| this.initSmallContainer(); | |||||
| if (!this.graph.dom) { | 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.insideBox.top = this.insideBox.left = 0; | ||||
| this.styleSet('#inside-box', this.insideBox); | |||||
| this.insideBox.style.cursor = 'not-allowed'; | this.insideBox.style.cursor = 'not-allowed'; | ||||
| } else { | } 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 = { | 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.setInsideBoxData(); | ||||
| } | } | ||||
| this.setSmallMapEvents(); | |||||
| }, | }, | ||||
| /** | /** | ||||
| * Initialize all events of the small image | * Initialize all events of the small image | ||||
| @@ -83,14 +157,12 @@ export default { | |||||
| this.insideBoxPositionChange(e); | this.insideBoxPositionChange(e); | ||||
| }; | }; | ||||
| document.onmouseup = (e) => { | |||||
| this.clickSmall = false; | |||||
| }; | |||||
| smallContainer.onmouseup = () => (this.clickSmall = false); | |||||
| smallContainer.onmouseleave = () => (this.clickSmall = false); | |||||
| smallContainer.onmousemove = (e) => { | smallContainer.onmousemove = (e) => { | ||||
| if (this.clickSmall) { | |||||
| this.insideBoxPositionChange(e); | |||||
| } | |||||
| if (!this.clickSmall) return; | |||||
| this.insideBoxPositionChange(e); | |||||
| }; | }; | ||||
| // Mouse wheel event | // Mouse wheel event | ||||
| @@ -98,35 +170,20 @@ export default { | |||||
| e = e || window.event; | e = e || window.event; | ||||
| const wheelDelta = e.wheelDelta ? e.wheelDelta : -e.deltaY; | const wheelDelta = e.wheelDelta ? e.wheelDelta : -e.deltaY; | ||||
| if (!isNaN(this.graph.transform.k) && this.graph.transform.k !== 0) { | 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.left += (this.insideBox.width * (1 - rate)) / 2; | ||||
| this.insideBox.top += (this.insideBox.height * (1 - rate)) / 2; | this.insideBox.top += (this.insideBox.height * (1 - rate)) / 2; | ||||
| this.insideBox.height = this.insideBox.height * rate; | this.insideBox.height = this.insideBox.height * rate; | ||||
| this.insideBox.width = this.insideBox.width * 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(); | this.graphChange(); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -137,130 +194,66 @@ export default { | |||||
| smallContainer.onmousewheel = null; | 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 | * Small image moving | ||||
| * @param {Object} e Event object | * @param {Object} e Event object | ||||
| */ | */ | ||||
| insideBoxPositionChange(e) { | 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 | * Displacement of the large picture when the small picture is changed | ||||
| */ | */ | ||||
| graphChange() { | graphChange() { | ||||
| if (!this.graph.transform.x || isNaN(this.graph.transform.x)) { | 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( | this.graph.dom.setAttribute( | ||||
| 'transform', | '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 | * Displacement of the small map when the large picture is changed | ||||
| */ | */ | ||||
| setInsideBoxData() { | 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 | * 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 | * @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() { | destroyed() { | ||||
| @@ -833,16 +833,7 @@ export default { | |||||
| value: '', | value: '', | ||||
| }, | }, | ||||
| devices: [], | 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: {}, | selectedNode: {}, | ||||
| svg: {}, | |||||
| contextmenu: { | contextmenu: { | ||||
| point: {}, | point: {}, | ||||
| id: 'contextMenu', | id: 'contextMenu', | ||||
| @@ -1217,48 +1208,13 @@ export default { | |||||
| /** ************************ graph **********************/ | /** ************************ 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`); | 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 = ''; | let transform = ''; | ||||
| if (this.graph.dom.getAttribute('transform')) { | if (this.graph.dom.getAttribute('transform')) { | ||||
| // transform information of graph | // transform information of graph | ||||
| @@ -1272,31 +1228,9 @@ export default { | |||||
| y: parseFloat(transform[2]), | 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.initZooming('debugger'); | ||||
| this.initContextMenu(); | this.initContextMenu(); | ||||
| @@ -1683,12 +1617,12 @@ export default { | |||||
| graphObj.initHeight = graphObj.rect.height / this.graph.transform.k; | graphObj.initHeight = graphObj.rect.height / this.graph.transform.k; | ||||
| const screenChange = { | 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( | this.graph.dom.setAttribute( | ||||
| 'transform', | 'transform', | ||||
| @@ -1852,9 +1786,11 @@ export default { | |||||
| }, | }, | ||||
| rightCollapse() { | rightCollapse() { | ||||
| this.collapseTable = !this.collapseTable; | 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() {}, | destroyed() {}, | ||||
| @@ -2513,11 +2449,4 @@ export default { | |||||
| .deb-indent { | .deb-indent { | ||||
| padding-left: 40px; | padding-left: 40px; | ||||
| } | } | ||||
| #graphTemp, | |||||
| #subgraphTemp { | |||||
| position: absolute; | |||||
| bottom: 0; | |||||
| visibility: hidden; | |||||
| } | |||||
| </style> | </style> | ||||
| @@ -221,10 +221,11 @@ limitations under the License. | |||||
| </div> | </div> | ||||
| <!-- Functional Area --> | <!-- Functional Area --> | ||||
| <div id="small-container"> | <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> | </div> | ||||
| <!-- Node information --> | <!-- Node information --> | ||||
| <div :class=" | <div :class=" | ||||
| @@ -507,11 +508,6 @@ export default { | |||||
| data() { | data() { | ||||
| return { | return { | ||||
| summaryPath: this.$route.query.summaryPath, | 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 | // Information about the selected node | ||||
| selectedNode: { | selectedNode: { | ||||
| info: { | info: { | ||||
| @@ -528,9 +524,6 @@ export default { | |||||
| }, | }, | ||||
| // Training job id | // Training job id | ||||
| trainJobID: '', | trainJobID: '', | ||||
| nodesCountLimit: 1500, // Maximum number of sub-nodes in a namespace. | |||||
| maxChainNum: 70, | |||||
| // Node search box | // Node search box | ||||
| searchBox: { | searchBox: { | ||||
| value: '', | value: '', | ||||
| @@ -546,11 +539,8 @@ export default { | |||||
| show: false, | show: false, | ||||
| info: '', | info: '', | ||||
| }, | }, | ||||
| scaleRange: [0.001, 1000], // graph zooms in and zooms out. | |||||
| rightShow: true, // Check whether the right side bar is displayed. | rightShow: true, // Check whether the right side bar is displayed. | ||||
| fullScreen: false, // Display Full Screen | fullScreen: false, // Display Full Screen | ||||
| graphviz: null, | |||||
| graphvizTemp: null, | |||||
| initOver: false, | initOver: false, | ||||
| guide: { | guide: { | ||||
| show: false, | show: false, | ||||
| @@ -627,20 +617,18 @@ export default { | |||||
| window.localStorage.setItem('milang', this.language); | 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 = () => { | window.onresize = () => { | ||||
| if (this.graph.dom) { | if (this.graph.dom) { | ||||
| this.$nextTick(() => { | this.$nextTick(() => { | ||||
| setTimeout(() => { | setTimeout(() => { | ||||
| this.initSvg(false); | |||||
| this.initGraphRectData(); | |||||
| }, 500); | |||||
| this.initSmallMap(); | |||||
| }, this.resizeDelay); | |||||
| }); | }); | ||||
| } | } | ||||
| }; | }; | ||||
| this.$nextTick(this.getDatavisualPlugins); | |||||
| }, | }, | ||||
| destroyed() { | destroyed() { | ||||
| window.onresize = null; | window.onresize = null; | ||||
| @@ -789,69 +777,15 @@ export default { | |||||
| this.querySingleNode({value: data.name}); | 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 | * Initialization method executed after the graph rendering is complete | ||||
| */ | */ | ||||
| startApp() { | 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'); | this.initZooming('graph'); | ||||
| if (this.selectedNode.name) { | if (this.selectedNode.name) { | ||||
| this.selectNode(true); | this.selectNode(true); | ||||
| @@ -940,7 +874,7 @@ export default { | |||||
| this.layoutNamescope(name, true); | this.layoutNamescope(name, true); | ||||
| } | } | ||||
| } else { | } else { | ||||
| this.initGraphRectData(); | |||||
| this.initSmallMap(); | |||||
| this.loading.show = false; | this.loading.show = false; | ||||
| } | } | ||||
| const data = response.data.nodes.map((val) => { | const data = response.data.nodes.map((val) => { | ||||
| @@ -1212,25 +1146,16 @@ export default { | |||||
| graph.initHeight = graph.rect.height / this.graph.transform.k; | graph.initHeight = graph.rect.height / this.graph.transform.k; | ||||
| const screenChange = { | 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( | this.graph.dom.setAttribute( | ||||
| 'transform', | '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( | const transitionTime = Math.min( | ||||
| @@ -1625,20 +1550,14 @@ export default { | |||||
| */ | */ | ||||
| toggleRight() { | toggleRight() { | ||||
| this.rightShow = !this.rightShow; | this.rightShow = !this.rightShow; | ||||
| setTimeout(() => { | |||||
| this.initSvg(false); | |||||
| this.initGraphRectData(); | |||||
| }, 500); | |||||
| setTimeout(this.initSmallMap, this.resizeDelay); | |||||
| }, | }, | ||||
| /** | /** | ||||
| * Full-screen display | * Full-screen display | ||||
| */ | */ | ||||
| toggleScreen() { | toggleScreen() { | ||||
| this.fullScreen = !this.fullScreen; | this.fullScreen = !this.fullScreen; | ||||
| setTimeout(() => { | |||||
| this.initSvg(false); | |||||
| this.initGraphRectData(); | |||||
| }, 500); | |||||
| setTimeout(this.initSmallMap, this.resizeDelay); | |||||
| }, | }, | ||||
| /** | /** | ||||
| * Download svg | * Download svg | ||||
| @@ -1929,23 +1848,9 @@ export default { | |||||
| background-color: white; | background-color: white; | ||||
| position: relative; | 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 { | .cl-graph-manage #graphs #sidebar #small-container #inside-box { | ||||
| background-color: #5b88f1; | background-color: #5b88f1; | ||||
| position: absolute; | position: absolute; | ||||
| /* Transparency */ | |||||
| opacity: 0.3; | opacity: 0.3; | ||||
| width: 100%; | width: 100%; | ||||
| height: 100%; | height: 100%; | ||||
| @@ -2207,8 +2112,7 @@ export default { | |||||
| stroke: red !important; | stroke: red !important; | ||||
| stroke-width: 2px; | stroke-width: 2px; | ||||
| } | } | ||||
| .cl-graph-manage #graphs .graph-container, | |||||
| .cl-graph-manage #graphs #small-map { | |||||
| .cl-graph-manage #graphs .graph-container { | |||||
| font-size: 16px; | font-size: 16px; | ||||
| position: relative; | position: relative; | ||||
| display: inline-block; | display: inline-block; | ||||
| @@ -2222,76 +2126,60 @@ export default { | |||||
| -ms-user-select: none; | -ms-user-select: none; | ||||
| 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%; | height: 100%; | ||||
| background-color: #f7faff; | 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; | 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; | 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; | 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; | 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; | 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; | stroke: red; | ||||
| fill: 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; | 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; | stroke: #e3aa00; | ||||
| fill: #ffe794; | 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; | stroke: #e3aa00; | ||||
| fill: #ffe794; | fill: #ffe794; | ||||
| stroke-dasharray: 3, 3; | 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; | stroke: #00a5a7; | ||||
| fill: #8df1f2; | 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; | stroke: #4ea6e6; | ||||
| fill: #b8e0ff; | fill: #b8e0ff; | ||||
| } | } | ||||
| .cl-graph-manage #graphs .graph-container .plain > path, | .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; | stroke: #e37d29; | ||||
| fill: #ffd0a6; | fill: #ffd0a6; | ||||
| stroke-dasharray: 1.5, 1.5; | 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; | stroke: #a7a7a7; | ||||
| fill: #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; | fill: black; | ||||
| } | } | ||||
| .cl-graph-manage #graphs .image-noData { | .cl-graph-manage #graphs .image-noData { | ||||
| @@ -2328,11 +2216,4 @@ export default { | |||||
| .cl-graph-manage .cl-title-right { | .cl-graph-manage .cl-title-right { | ||||
| padding-right: 32px; | padding-right: 32px; | ||||
| } | } | ||||
| #graphTemp, | |||||
| #subgraphTemp { | |||||
| position: absolute; | |||||
| bottom: 0; | |||||
| visibility: hidden; | |||||
| } | |||||
| </style> | </style> | ||||