You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

graph.vue 78 kB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338
  1. <!--
  2. Copyright 2019-2021 Huawei Technologies Co., Ltd.All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. -->
  13. <template>
  14. <!--cl-graph-manage -->
  15. <div class="cl-graph-manage">
  16. <div class="graph-p32">
  17. <div class="guide-content"
  18. v-if="guide.show">
  19. <el-popover placement="top-start"
  20. ref="popover"
  21. :style="{ position: 'absolute', top: guide.top, left: guide.left }"
  22. :title="guide.title"
  23. width="370"
  24. v-model="guide.show">
  25. <i class="el-icon-close"
  26. @click="closeUserGuide"></i>
  27. <div v-for="item in guide.content"
  28. :key="item"
  29. class="guide-span">{{ item }}</div>
  30. <div class="step-pic">
  31. <img :src="require(`@/assets/images/graph-stepimg${guide.step}.svg`)" />
  32. </div>
  33. <el-button type="primary"
  34. @click="guideNext">{{
  35. guide.step === 3 ? $t('graph.finish') : $t('graph.next')
  36. }}</el-button>
  37. </el-popover>
  38. <div class="step"
  39. v-show="guide.step == 1">
  40. <img :src="require(`@/assets/images/graph-step1${language === 'en-us' ? '-en' : ''}.svg`)"
  41. alt="" />
  42. </div>
  43. <div class="step"
  44. v-show="guide.step == 2">
  45. <img :src="require(`@/assets/images/graph-step2${language === 'en-us' ? '-en' : ''}.svg`)"
  46. alt="" />
  47. </div>
  48. <div class="step"
  49. v-show="guide.step == 3">
  50. <img :src="require(`@/assets/images/graph-step3${language === 'en-us' ? '-en' : ''}.svg`)"
  51. alt="" />
  52. </div>
  53. </div>
  54. <div class="cl-title cl-graph-title">
  55. <div class="cl-title-left">
  56. {{ $t('graph.titleText') }}
  57. <div class="path-message">
  58. <span>{{$t('symbols.leftbracket')}}</span>
  59. <span>{{$t('trainingDashboard.summaryDirPath')}}</span>
  60. <span>{{summaryPath}}</span>
  61. <span>{{$t('symbols.rightbracket')}}</span>
  62. </div>
  63. <span @click="showUserGuide"
  64. class="guide">
  65. <i class="guide-icon"></i>
  66. {{$t('graph.guide')}}
  67. </span>
  68. </div>
  69. <div class="cl-title-right">
  70. <div class="cl-close-btn"
  71. @click="jumpToTrainDashboard">
  72. <img src="@/assets/images/close-page.png" />
  73. </div>
  74. </div>
  75. </div>
  76. <div class="cl-content">
  77. <div id="graphs">
  78. <div class="cl-graph"
  79. :class="fullScreen ? 'full-screen' : ''">
  80. <!-- graph -->
  81. <div class="graph-container"
  82. :class="rightShow ? '' : 'all'">
  83. <!-- No data is displayed. -->
  84. <div class="image-noData"
  85. v-if="!loading.show && !Object.keys(allGraphData).length">
  86. <div>
  87. <img :src="require('@/assets/images/nodata.png')"
  88. alt="" />
  89. </div>
  90. <div class="noData-text">{{ $t('public.noData') }}</div>
  91. </div>
  92. <!-- Operation button column -->
  93. <div class="operate-button-list">
  94. <!-- Download button. -->
  95. <div :title="$t('graph.fullScreen')"
  96. class="full-screen-button"
  97. @click="toggleScreen"></div>
  98. <div :title="$t('graph.downloadPic')"
  99. class="download-button"
  100. @click="downLoadSVG"></div>
  101. </div>
  102. <div id="graph"
  103. class="graph"
  104. v-loading.fullscreen.lock="loading.show"
  105. element-loading-background="rgba(0, 0, 0, 0.3)"
  106. :element-loading-text="loading.info"></div>
  107. </div>
  108. <!-- Right column -->
  109. <div id="sidebar"
  110. :class="rightShow ? '' : 'right-hide'">
  111. <div class="toggle-right"
  112. @click="toggleRight">
  113. <i :class="rightShow ? 'icon-toggle' : 'icon-toggle icon-left'"></i>
  114. </div>
  115. <!-- Search box -->
  116. <div class="sidebar-tooltip">
  117. <el-tooltip placement="top"
  118. effect="light">
  119. <div slot="content"
  120. class="tooltip-container">
  121. <div class="cl-graph-sidebar-tip">
  122. {{$t('graph.sidebarTip')}}
  123. </div>
  124. </div>
  125. <i class="el-icon-info"></i>
  126. </el-tooltip>
  127. </div>
  128. <el-select @change="fileChange"
  129. @visible-change="getSelectList"
  130. :popper-append-to-body="false"
  131. class="search"
  132. v-model="fileSearchBox.value">
  133. <el-option v-for="item in fileSearchBox.suggestions"
  134. :key="item.value"
  135. :title="item.value"
  136. :label="item.value"
  137. :value="item.value">
  138. </el-option>
  139. </el-select>
  140. <!-- Search box -->
  141. <div class="search-wrap">
  142. <el-input class="search"
  143. :placeholder="$t('graph.inputNodeName')"
  144. v-model="searchBox.value"
  145. @input="filterChange"
  146. @keyup.enter.native="searchNodesNames"
  147. clearable>
  148. <el-button slot="append"
  149. @click="treeWrapFlag=!treeWrapFlag"
  150. class="collapse_i">
  151. <i class="el-icon-caret-bottom"
  152. v-if="!treeWrapFlag"></i>
  153. <i class="el-icon-caret-top"
  154. v-else></i>
  155. </el-button>
  156. </el-input>
  157. <div class="tree-wrap"
  158. v-show="treeWrapFlag">
  159. <el-tree v-show="treeFlag"
  160. :props="props"
  161. :load="loadNode"
  162. @node-collapse="nodeCollapse"
  163. @node-click="handleNodeClick"
  164. node-key="name"
  165. :expand-on-click-node="false"
  166. :lazy="true"
  167. :highlight-current="true"
  168. ref="tree">
  169. <span class="custom-tree-node"
  170. slot-scope="{ node ,data }">
  171. <span>
  172. <img v-if="data.type ==='name_scope'"
  173. :src="require('@/assets/images/name-scope.svg')"
  174. class="image-type" />
  175. <img v-else-if="data.type ==='Const'"
  176. :src="require('@/assets/images/constant-node.svg')"
  177. class="image-type" />
  178. <img v-else-if="data.type ==='aggregation_scope'"
  179. :src="require('@/assets/images/polymetric.svg')"
  180. class="image-type" />
  181. <img v-else
  182. :src="require('@/assets/images/operator-node.svg')"
  183. class="image-type" />
  184. </span>
  185. <span class="custom-tree-node">{{ node.label }}</span>
  186. </span>
  187. </el-tree>
  188. <el-tree v-show="!treeFlag"
  189. :props="defaultProps"
  190. :load="loadSearchNode"
  191. :lazy="true"
  192. node-key="name"
  193. @node-click="handleNodeClick"
  194. :expand-on-click-node="false"
  195. ref="searchTree">
  196. <span class="custom-tree-node"
  197. slot-scope="{ node ,data }">
  198. <span>
  199. <img v-if="data.type ==='name_scope'"
  200. :src="require('@/assets/images/name-scope.svg')"
  201. class="image-type" />
  202. <img v-else-if="data.type ==='Const'"
  203. :src="require('@/assets/images/constant-node.svg')"
  204. class="image-type" />
  205. <img v-else-if="data.type ==='aggregation_scope'"
  206. :src="require('@/assets/images/polymetric.svg')"
  207. class="image-type" />
  208. <img v-else
  209. :src="require('@/assets/images/operator-node.svg')"
  210. class="image-type" />
  211. </span>
  212. <span class="custom-tree-node">{{ node.label }}</span>
  213. </span>
  214. </el-tree>
  215. </div>
  216. </div>
  217. <!-- Functional Area -->
  218. <div id="small-container">
  219. <div id="small-resize">
  220. <div id="small-map"></div>
  221. <div id="inside-box"></div>
  222. </div>
  223. </div>
  224. <!-- Node information -->
  225. <div :class="
  226. showLegend
  227. ? 'node-info-con node-info-container'
  228. : 'node-info-con node-info-container-long'
  229. ">
  230. <div class="title">
  231. {{ $t('graph.nodeInfo') }}
  232. <img :src="require('@/assets/images/all-drop-down.png')"
  233. fun="fold"
  234. hidden
  235. alt="" />
  236. <img :src="require('@/assets/images/all-uptake.png')"
  237. fun="fold"
  238. hidden
  239. alt="" />
  240. </div>
  241. <div class="node-info"
  242. v-show="selectedNode.show">
  243. <div class="items">
  244. <div class="label item">{{ $t('graph.name') }}</div>
  245. <div class="value">
  246. <span class="cl-display-block"
  247. @dblclick="nodeNameClick">{{ selectedNode.title }}</span>
  248. </div>
  249. </div>
  250. <div class="items"
  251. v-if="selectedNode.countShow">
  252. <div class="label item">{{ $t('graph.count') }}</div>
  253. <div class="value items-over">{{ selectedNode.count }}</div>
  254. </div>
  255. <div class="items"
  256. v-if="!selectedNode.countShow">
  257. <div class="label item">{{ $t('graph.type') }}</div>
  258. <div class="value items-over">{{ selectedNode.type }}</div>
  259. </div>
  260. <div class="items itemHeight"
  261. v-if="!selectedNode.countShow">
  262. <div class="item">
  263. {{ $t('graph.attr') }} ({{
  264. selectedNode.info.attributes.length
  265. }})
  266. </div>
  267. </div>
  268. <ul v-if="selectedNode.info && !selectedNode.countShow"
  269. class="item-content hover"
  270. :class="
  271. selectedNode.info.attributes.length > 2
  272. ? 'item-min2'
  273. : selectedNode.info.attributes.length > 0
  274. ? 'item-min'
  275. : ''
  276. ">
  277. <li v-for="item in selectedNode.info.attributes"
  278. :key="item.name">
  279. <div class="key">
  280. {{ item.name }}
  281. </div>
  282. <div class="input cl-input-value">
  283. <pre>{{ item.value }}</pre>
  284. </div>
  285. </li>
  286. </ul>
  287. <div class="items itemHeight">
  288. <div class="item">
  289. {{ $t('graph.inputs') }} (
  290. {{
  291. selectedNode.info.input.length +
  292. selectedNode.info.inputControl.length
  293. }})
  294. </div>
  295. </div>
  296. <ul v-if="selectedNode.info"
  297. class="item-content hover"
  298. :class="
  299. selectedNode.info.input.length > 1
  300. ? 'item-min2'
  301. : selectedNode.info.input.length > 0
  302. ? 'item-min'
  303. : ''
  304. ">
  305. <li v-for="item in selectedNode.info.input"
  306. :key="item.$index"
  307. @click="querySingleNode({ value: item.name })"
  308. class="pointer">
  309. <div class="input">{{ item.name }}</div>
  310. <div class="size">{{ item.value }}</div>
  311. <div class="clear"></div>
  312. </li>
  313. <li class="control-list"
  314. v-if="
  315. selectedNode.info &&
  316. selectedNode.info.inputControl.length
  317. ">
  318. <div class="dependence-title"
  319. @click="toggleControl('input')"
  320. :class="selectedNode.showControl.input ? '' : 'hide'">
  321. <img :src="require('@/assets/images/all-uptake.png')"
  322. alt="" />
  323. {{ $t('graph.controlDependencies') }}
  324. </div>
  325. <ul v-show="selectedNode.showControl.input">
  326. <li v-for="item in selectedNode.info.inputControl"
  327. :key="item.$index"
  328. @click="querySingleNode({ value: item.name })"
  329. class="pointer">
  330. <div class="input">{{ item.name }}</div>
  331. <div class="size">{{ item.value }}</div>
  332. <div class="clear"></div>
  333. </li>
  334. </ul>
  335. </li>
  336. </ul>
  337. <div class="items">
  338. <div class="item">
  339. {{ $t('graph.outputs') }} (
  340. {{
  341. selectedNode.info.output.length +
  342. selectedNode.info.outputControl.length
  343. }})
  344. </div>
  345. </div>
  346. <ul v-if="selectedNode.info"
  347. class="item-content hover"
  348. :class="
  349. selectedNode.info.output.length > 1
  350. ? 'item-min2'
  351. : selectedNode.info.output.length > 0
  352. ? 'item-min'
  353. : ''
  354. ">
  355. <li v-for="item in selectedNode.info.output"
  356. :key="item.$index"
  357. @click="querySingleNode({ value: item.name })"
  358. class="pointer">
  359. <div class="input">{{ item.name }}</div>
  360. <div class="size">{{ item.value }}</div>
  361. <div class="clear"></div>
  362. </li>
  363. <li class="control-list"
  364. v-if="
  365. selectedNode.info &&
  366. selectedNode.info.outputControl.length
  367. ">
  368. <div class="dependence-title"
  369. @click="toggleControl('output')"
  370. :class="selectedNode.showControl.output ? '' : 'hide'">
  371. <img :src="require('@/assets/images/all-uptake.png')"
  372. alt="" />
  373. {{ $t('graph.controlDependencies') }}
  374. </div>
  375. <ul v-show="selectedNode.showControl.output">
  376. <li v-for="item in selectedNode.info.outputControl"
  377. :key="item.$index"
  378. @click="querySingleNode({ value: item.name })"
  379. class="pointer">
  380. <div class="input">{{ item.name }}</div>
  381. <div class="size">{{ item.value }}</div>
  382. <div class="clear"></div>
  383. </li>
  384. </ul>
  385. </li>
  386. </ul>
  387. <div class="items"
  388. v-if="selectedNode.info && selectedNode.info.output_i !== 0">
  389. <div class="label item">{{ $t('graph.outputs_i') }}</div>
  390. <span class="value">{{ selectedNode.info.output_i }}</span>
  391. </div>
  392. </div>
  393. </div>
  394. <!-- Legend -->
  395. <div class="legend"
  396. v-if="!fullScreen">
  397. <div class="title">
  398. {{ $t('graph.legend') }}
  399. <img :src="require('@/assets/images/all-drop-down.png')"
  400. v-show="!showLegend"
  401. @click="foldLegend"
  402. alt="" />
  403. <img :src="require('@/assets/images/all-uptake.png')"
  404. v-show="showLegend"
  405. @click="foldLegend"
  406. alt="" />
  407. </div>
  408. <div v-show="showLegend"
  409. class="legend-content">
  410. <div class="legend-item">
  411. <div class="pic">
  412. <img :src="require('@/assets/images/name-scope.svg')"
  413. alt="" />
  414. </div>
  415. <div class="legend-text"
  416. :title="$t('graph.nameSpace')">
  417. {{ $t('graph.nameSpace') }}
  418. </div>
  419. </div>
  420. <div class="legend-item">
  421. <div class="pic">
  422. <img :src="require('@/assets/images/polymetric.svg')"
  423. alt="" />
  424. </div>
  425. <div class="legend-text"
  426. :title="$t('graph.polymetric')">
  427. {{ $t('graph.polymetric') }}
  428. </div>
  429. </div>
  430. <div class="legend-item">
  431. <div class="pic">
  432. <img :src="require('@/assets/images/virtual-node.svg')"
  433. alt="" />
  434. </div>
  435. <div class="legend-text"
  436. :title="$t('graph.virtualNode')">
  437. {{ $t('graph.virtualNode') }}
  438. </div>
  439. </div>
  440. <div class="legend-item">
  441. <div class="pic">
  442. <img :src="require('@/assets/images/operator-node.svg')"
  443. alt="" />
  444. </div>
  445. <div class="legend-text"
  446. :title="$t('graph.operatorNode')">
  447. {{ $t('graph.operatorNode') }}
  448. </div>
  449. </div>
  450. <div class="legend-item">
  451. <div class="pic">
  452. <img :src="require('@/assets/images/constant-node.svg')"
  453. alt="" />
  454. </div>
  455. <div class="legend-text"
  456. :title="$t('graph.constantNode')">
  457. {{ $t('graph.constantNode') }}
  458. </div>
  459. </div>
  460. <br>
  461. <div class="legend-item">
  462. <div class="pic">
  463. <img :src="require('@/assets/images/data-flow.png')"
  464. alt="" />
  465. </div>
  466. <div class="legend-text"
  467. :title="$t('graph.dataFlowEdge')">
  468. {{ $t('graph.dataFlowEdge') }}
  469. </div>
  470. </div>
  471. <div class="legend-item">
  472. <div class="pic">
  473. <img :src="require('@/assets/images/control-dep.png')"
  474. alt="" />
  475. </div>
  476. <div class="legend-text"
  477. :title="$t('graph.controllDepEdge')">
  478. {{ $t('graph.controllDepEdge') }}
  479. </div>
  480. </div>
  481. </div>
  482. </div>
  483. </div>
  484. </div>
  485. </div>
  486. </div>
  487. </div>
  488. </div>
  489. </template>
  490. <script>
  491. import CommonProperty from '@/common/common-property.js';
  492. import RequestService from '@/services/request-service';
  493. import {select, selectAll, zoom} from 'd3';
  494. import 'd3-graphviz';
  495. const d3 = {select, selectAll, zoom};
  496. import commonGraph from '../../mixins/common-graph.vue';
  497. import smallMap from '../../mixins/small-map.vue';
  498. export default {
  499. mixins: [commonGraph, smallMap],
  500. data() {
  501. return {
  502. summaryPath: this.$route.query.summaryPath,
  503. graph: {}, // Basic information about graph0 in svg
  504. svg: {}, // Basic information about svg
  505. allGraphData: {}, // graph Original input data
  506. firstFloorNodes: [], // ID array of the first layer node.
  507. // Information about the selected node
  508. selectedNode: {
  509. info: {
  510. inputControl: [],
  511. input: [],
  512. outputControl: [],
  513. output: [],
  514. attributes: [],
  515. },
  516. showControl: {
  517. input: true,
  518. output: true,
  519. },
  520. },
  521. // Training job id
  522. trainJobID: '',
  523. nodesCountLimit: 1500, // Maximum number of sub-nodes in a namespace.
  524. maxChainNum: 70,
  525. // Node search box
  526. searchBox: {
  527. value: '',
  528. suggestions: [],
  529. },
  530. fileSearchBox: {
  531. value: '',
  532. suggestions: [],
  533. },
  534. showLegend: true, // Display Legend
  535. // Controls whether the loading is displayed.
  536. loading: {
  537. show: false,
  538. info: '',
  539. },
  540. scaleRange: [0.001, 1000], // graph zooms in and zooms out.
  541. rightShow: true, // Check whether the right side bar is displayed.
  542. fullScreen: false, // Display Full Screen
  543. graphviz: null,
  544. graphvizTemp: null,
  545. initOver: false,
  546. guide: {
  547. show: false,
  548. step: 1,
  549. top: '0%',
  550. left: '0%',
  551. content: [
  552. this.$t('graph.guideContent11'),
  553. this.$t('graph.guideContent12'),
  554. this.$t('graph.guideContent13'),
  555. this.$t('graph.guideContent14'),
  556. ],
  557. title: '',
  558. },
  559. language: '',
  560. defaultProps: {
  561. children: 'nodes',
  562. label: 'label',
  563. isLeaf: 'leaf',
  564. },
  565. treeFlag: true,
  566. props: {
  567. label: 'label',
  568. children: 'children',
  569. isLeaf: 'leaf',
  570. },
  571. node: null,
  572. resolve: null,
  573. treeWrapFlag: true,
  574. searchNode: null,
  575. searchResolve: null,
  576. isIntoView: true,
  577. };
  578. },
  579. computed: {},
  580. watch: {
  581. guide: {
  582. handler(newVal) {
  583. if (newVal.step === 1) {
  584. this.guide.top = '20%';
  585. this.guide.left = '48%';
  586. } else if (newVal.step === 2) {
  587. this.guide.top = '47%';
  588. this.guide.left = '62%';
  589. } else if (newVal.step === 3) {
  590. this.guide.top = '45%';
  591. this.guide.left = '52%';
  592. }
  593. this.guide.title = this.$t(`graph.guideTitle${newVal.step}`);
  594. },
  595. deep: true,
  596. },
  597. },
  598. mounted() {
  599. // Judging from the training job overview.
  600. if (!this.$route.query || !this.$route.query.train_id) {
  601. this.trainJobID = '';
  602. this.$message.error(this.$t('trainingDashboard.invalidId'));
  603. document.title = `${this.$t('graph.titleText')}-MindInsight`;
  604. return;
  605. }
  606. const showGuide = window.localStorage.getItem('graphShowGuide');
  607. if (!showGuide) {
  608. this.guide.show = true;
  609. window.localStorage.setItem('graphShowGuide', true);
  610. }
  611. this.trainJobID = this.$route.query.train_id;
  612. this.language = window.localStorage.getItem('milang');
  613. const languageList = ['zh-cn', 'en-us'];
  614. if (!this.language || !languageList.includes(this.language)) {
  615. this.language = languageList[0];
  616. window.localStorage.setItem('milang', this.language);
  617. }
  618. document.title = `${decodeURIComponent(this.trainJobID)}-${this.$t(
  619. 'graph.titleText',
  620. )}-MindInsight`;
  621. this.getDatavisualPlugins();
  622. window.onresize = () => {
  623. if (this.graph.dom) {
  624. this.$nextTick(() => {
  625. setTimeout(() => {
  626. this.initSvg(false);
  627. this.initGraphRectData();
  628. }, 500);
  629. });
  630. }
  631. };
  632. },
  633. destroyed() {
  634. window.onresize = null;
  635. },
  636. methods: {
  637. /**
  638. * Tree linkage with graph Expand of current node
  639. * @param {Obeject} nodes Data of children of current node
  640. * @param {Obeject} name The name of the current node
  641. */
  642. nodeExpandLinkage(nodes, name) {
  643. const curNodeData = nodes.map((val) => {
  644. return {
  645. label: val.name.split('/').pop(),
  646. ...val,
  647. };
  648. });
  649. const node = this.$refs.tree.getNode(name);
  650. curNodeData.forEach((val) => {
  651. this.$refs.tree.append(val, name);
  652. });
  653. node.childNodes.forEach((val) => {
  654. if (
  655. val.data.type !== 'name_scope' &&
  656. val.data.type !== 'aggregation_scope'
  657. ) {
  658. val.isLeaf = true;
  659. }
  660. });
  661. node.expanded = true;
  662. node.loading = false;
  663. this.$refs.tree.setCurrentKey(name);
  664. this.$nextTick(() => {
  665. setTimeout(() => {
  666. const dom = document.querySelector('.el-tree-node.is-current.is-focusable');
  667. if (dom && this.rightShow) {
  668. dom.scrollIntoView();
  669. }
  670. }, 800);
  671. });
  672. },
  673. /**
  674. * Collapse node
  675. * @param {Object} _
  676. * @param {Object} node node data
  677. */
  678. nodeCollapse(_, node) {
  679. node.loaded = false;
  680. if (this.treeFlag) {
  681. this.dealDoubleClick(node.data.name);
  682. }
  683. },
  684. /**
  685. * Draw the tree
  686. * @param {Object} node tree root node
  687. * @param {Function} resolve callback function ,return next node data
  688. */
  689. loadNode(node, resolve) {
  690. if (node.level === 0) {
  691. node.childNodes = [];
  692. if (!this.node && !this.resolve) {
  693. this.node = node;
  694. this.resolve = resolve;
  695. }
  696. } else if (node.level >= 1) {
  697. this.isIntoView = false;
  698. this.loading.info = this.$t('graph.queryLoading');
  699. this.loading.show = true;
  700. setTimeout(() => {
  701. this.queryGraphData(node.data.name, resolve);
  702. }, 200);
  703. }
  704. },
  705. /**
  706. * Draw the tree
  707. * @param {Object} node tree root node
  708. * @param {Function} resolve callback function ,return next node data
  709. */
  710. loadSearchNode(node, resolve) {
  711. if (node.level === 0) {
  712. node.childNodes = [];
  713. if (!this.searchNode && !this.searchResolve) {
  714. this.searchNode = node;
  715. this.searchResolve = resolve;
  716. }
  717. } else if (node.level >= 1) {
  718. const params = {
  719. name: node.data.name,
  720. train_id: this.trainJobID,
  721. tag: this.fileSearchBox.value,
  722. };
  723. if (node.childNodes && node.childNodes.length) {
  724. node.expanded = true;
  725. node.loaded = true;
  726. node.loading = false;
  727. return;
  728. }
  729. RequestService.queryGraphData(params).then((res) => {
  730. if (res && res.data && res.data.nodes) {
  731. const data = res.data.nodes.map((val) => {
  732. return {
  733. label: val.name.split('/').pop(),
  734. leaf:
  735. val.type === 'name_scope' || val.type === 'aggregation_scope'
  736. ? false
  737. : true,
  738. ...val,
  739. };
  740. });
  741. resolve(data);
  742. }
  743. });
  744. }
  745. },
  746. /**
  747. * Deal search data
  748. * @param {Array} arr search tree data
  749. */
  750. dealSearchResult(arr) {
  751. arr.forEach((val) => {
  752. if (val.nodes) {
  753. this.dealSearchResult(val.nodes);
  754. }
  755. val.label = val.name.split('/').pop();
  756. });
  757. },
  758. filterChange() {
  759. if (this.searchBox.value === '') {
  760. this.treeFlag = true;
  761. this.$nextTick(() => {
  762. setTimeout(() => {
  763. const dom = document.querySelector('.el-tree-node.is-current.is-focusable');
  764. if (dom && this.rightShow) {
  765. dom.scrollIntoView();
  766. }
  767. }, 800);
  768. });
  769. }
  770. },
  771. handleNodeClick(data) {
  772. this.isIntoView = false;
  773. this.selectedNode.name = data.name;
  774. if (this.treeFlag) {
  775. this.selectNode(true);
  776. } else {
  777. this.querySingleNode({value: data.name});
  778. }
  779. },
  780. /**
  781. * Add the location attribute to each node to facilitate the obtaining of node location parameters.
  782. */
  783. afterInitGraph() {
  784. setTimeout(() => {
  785. if (this.graphviz) {
  786. this.graphviz._data = null;
  787. this.graphviz._dictionary = null;
  788. this.graphviz = null;
  789. }
  790. if (this.graphvizTemp) {
  791. this.graphvizTemp._data = null;
  792. this.graphvizTemp._dictionary = null;
  793. this.graphvizTemp = null;
  794. }
  795. }, 100);
  796. this.fitGraph('graph');
  797. this.transplantChildrenDom();
  798. const svg = document.querySelector('#subgraphTemp svg');
  799. if (svg) {
  800. svg.remove();
  801. }
  802. this.$nextTick(() => {
  803. this.loading.show = false;
  804. });
  805. const elements = d3.select('#graph').selectAll('g.node, g.edge').nodes();
  806. elements.forEach((ele) => {
  807. if (!ele.hasAttribute('transform')) {
  808. ele.setAttribute('transform', 'translate(0,0)');
  809. }
  810. // The title value needs to be manually set for the virtual node.
  811. if (Array.prototype.includes.call(ele.classList, 'plain')) {
  812. const title = ele.querySelector('title');
  813. title.textContent = title.textContent.split('^')[0];
  814. }
  815. });
  816. d3.selectAll('g.edge>title').remove();
  817. // The graph generated by the plug-in has a useless title and needs to be deleted.
  818. document.querySelector('#graph g#graph0 title').remove();
  819. this.initGraphRectData();
  820. this.startApp();
  821. },
  822. /**
  823. * Initialization method executed after the graph rendering is complete
  824. */
  825. startApp() {
  826. const nodes = d3.selectAll('g.node, g.cluster');
  827. nodes.on(
  828. 'click',
  829. (target, index, nodesList) => {
  830. this.clickEvent(target, index, nodesList, 'graph');
  831. },
  832. false,
  833. );
  834. // namespaces Expansion or Reduction
  835. nodes.on(
  836. 'dblclick',
  837. (target, index, nodesList) => {
  838. this.dblclickEvent(target, index, nodesList, 'graph');
  839. },
  840. false,
  841. );
  842. this.initZooming('graph');
  843. if (this.selectedNode.name) {
  844. this.selectNode(true);
  845. }
  846. },
  847. /**
  848. * Double-click the processing to be performed on the node to expand or narrow the namespace or aggregation node.
  849. * @param {String} name Name of the current node (also the ID of the node)
  850. */
  851. dealDoubleClick(name) {
  852. this.loading.info = this.$t('graph.queryLoading');
  853. this.loading.show = true;
  854. this.$nextTick(() => {
  855. // DOM tree needs time to respond, otherwise the loading icon will not be displayed
  856. const timeOut = 500;
  857. setTimeout(() => {
  858. name = name.replace('_unfold', '');
  859. if (this.allGraphData[name].isUnfold) {
  860. this.selectedNode.name = name;
  861. this.deleteNamespace(name);
  862. } else {
  863. this.queryGraphData(name);
  864. }
  865. }, timeOut);
  866. });
  867. },
  868. /**
  869. * To obtain graph data, initialize and expand the namespace or aggregate nodes.
  870. * @param {String} name Name of the current node.
  871. * @param {Function} resolve Callback function.
  872. */
  873. queryGraphData(name, resolve) {
  874. const namescopeChildLimit = 3500;
  875. const independentLayout = this.allGraphData[name]
  876. ? this.allGraphData[name].independent_layout
  877. : false;
  878. const params = {
  879. name: name,
  880. train_id: this.trainJobID,
  881. tag: this.fileSearchBox.value,
  882. };
  883. this.loading.info = this.$t('graph.queryLoading');
  884. this.loading.show = true;
  885. RequestService.queryGraphData(params)
  886. .then(
  887. (response) => {
  888. if (response && response.data && response.data.nodes) {
  889. // If the namespace to be expanded is larger than the maximum number of subnodes,
  890. // an error is reported and the namespace is highlighted.
  891. const nodesCountLimit = name
  892. ? this.nodesCountLimit
  893. : namescopeChildLimit;
  894. if (
  895. !independentLayout &&
  896. response.data.nodes.length > nodesCountLimit
  897. ) {
  898. this.$message.error(this.$t('graph.tooManyNodes'));
  899. this.packageDataToObject(name, false);
  900. this.loading.show = false;
  901. this.$refs.tree.getNode(name).loading = false;
  902. } else {
  903. const nodes = JSON.parse(JSON.stringify(response.data.nodes));
  904. if (nodes && nodes.length) {
  905. this.packageDataToObject(name, true, nodes);
  906. // If the name is empty, it indicates the outermost layer.
  907. if (!name) {
  908. const dot = this.packageGraphData();
  909. this.initGraph(dot);
  910. } else {
  911. if (this.allGraphData[name].type === 'aggregation_scope') {
  912. this.dealAggregationNodes(name);
  913. if (
  914. this.allGraphData[name].maxChainNum > this.maxChainNum
  915. ) {
  916. this.$message.error(this.$t('graph.tooManyChain'));
  917. this.allGraphData[name].isUnfold = true;
  918. this.selectedNode.name = name;
  919. this.loading.show = false;
  920. this.deleteNamespace(name);
  921. this.$refs.tree.getNode(name).loading = false;
  922. return;
  923. }
  924. }
  925. this.allGraphData[name].isUnfold = true;
  926. this.selectedNode.name = `${name}_unfold`;
  927. this.layoutNamescope(name, true);
  928. }
  929. } else {
  930. this.initGraphRectData();
  931. this.loading.show = false;
  932. }
  933. const data = response.data.nodes.map((val) => {
  934. return {
  935. label: val.name.split('/').pop(),
  936. leaf:
  937. val.type === 'name_scope' ||
  938. val.type === 'aggregation_scope'
  939. ? false
  940. : true,
  941. ...val,
  942. };
  943. });
  944. if (name) {
  945. if (resolve) {
  946. resolve(JSON.parse(JSON.stringify(data)));
  947. } else {
  948. this.nodeExpandLinkage(response.data.nodes, name);
  949. }
  950. } else {
  951. this.node.childNodes = [];
  952. this.resolve(JSON.parse(JSON.stringify(data)));
  953. }
  954. }
  955. }
  956. },
  957. (error) => {
  958. this.loading.show = false;
  959. },
  960. )
  961. .catch((error) => {
  962. // A non-Google Chrome browser may not work properly.
  963. this.loading.show = false;
  964. if (error && error.includes('larger than maximum 65535 allowed')) {
  965. this.$message.error(this.$t('graph.dataTooLarge'));
  966. } else {
  967. this.$bus.$emit('showWarmText', true);
  968. }
  969. if (name && this.allGraphData[name]) {
  970. this.allGraphData[name].isUnfold = false;
  971. this.allGraphData[name].children = [];
  972. this.allGraphData[name].size = [];
  973. this.allGraphData[name].html = '';
  974. }
  975. });
  976. },
  977. /**
  978. * To obtain datavisual plugins
  979. */
  980. getDatavisualPlugins() {
  981. const params = {
  982. train_id: this.trainJobID,
  983. };
  984. RequestService.getDatavisualPlugins(params)
  985. .then((res) => {
  986. this.fileSearchBox.suggestions = [];
  987. if (
  988. !res ||
  989. !res.data ||
  990. !res.data.plugins ||
  991. !res.data.plugins.graph ||
  992. !res.data.plugins.graph.length
  993. ) {
  994. this.initOver = true;
  995. return;
  996. }
  997. const tags = res.data.plugins.graph;
  998. let hasFileSearchValue = false;
  999. tags.forEach((k) => {
  1000. this.fileSearchBox.suggestions.push({
  1001. value: k,
  1002. });
  1003. hasFileSearchValue =
  1004. k === this.fileSearchBox.value || hasFileSearchValue;
  1005. });
  1006. if (!this.initOver) {
  1007. this.initOver = true;
  1008. this.fileSearchBox.value = tags.length ? tags[0] : '';
  1009. this.queryGraphData();
  1010. } else if (!hasFileSearchValue) {
  1011. this.fileSearchBox.value = '';
  1012. }
  1013. })
  1014. .catch(() => {
  1015. this.fileSearchBox.suggestions = [];
  1016. this.initOver = true;
  1017. this.loading.show = false;
  1018. });
  1019. },
  1020. /**
  1021. * Close the expanded namespace.
  1022. * @param {String} name The name of the namespace to be closed.
  1023. */
  1024. deleteNamespace(name) {
  1025. this.loading.info = this.$t('graph.searchLoading');
  1026. this.loading.show = true;
  1027. if (!this.selectedNode.more) {
  1028. this.packageDataToObject(name, false);
  1029. this.layoutController(name);
  1030. } else {
  1031. this.allGraphData[name].isUnfold = true;
  1032. this.selectedNode.name = `${name}_unfold`;
  1033. this.layoutNamescope(name, true);
  1034. }
  1035. },
  1036. /**
  1037. * Controls the invoking method of the next step.
  1038. * @param {String} name Name of the namespace to be expanded.
  1039. */
  1040. layoutController(name) {
  1041. if (!this.loading.show) {
  1042. this.loading.info = this.$t('graph.searchLoading');
  1043. this.loading.show = true;
  1044. }
  1045. if (name.includes('/')) {
  1046. const subPath = name.split('/').slice(0, -1).join('/');
  1047. this.layoutNamescope(subPath, true);
  1048. } else {
  1049. const svg = document.querySelector('#graph svg');
  1050. if (svg) {
  1051. svg.remove();
  1052. }
  1053. const dot = this.packageGraphData();
  1054. this.initGraph(dot);
  1055. }
  1056. },
  1057. /**
  1058. * Selecting a node
  1059. * @param {Boolean} needFocus Whether to focus on the node
  1060. */
  1061. selectNode(needFocus = false) {
  1062. window.getSelection().removeAllRanges();
  1063. d3.selectAll(
  1064. '.node polygon, .node ellipse, .node rect, .node path',
  1065. ).classed('selected', false);
  1066. const path = this.selectedNode.name.split('^');
  1067. const node = {};
  1068. let id = path[0].replace('_unfold', '');
  1069. id = this.allGraphData[id].isUnfold ? `${id}_unfold` : id;
  1070. node.eld3 = d3.select(`#graph g[id="${id}"]`);
  1071. node.el = node.eld3.node();
  1072. this.graph.dom.style.transition = '';
  1073. const needDelay = path.length > 1;
  1074. if ((needFocus || needDelay) && node.el) {
  1075. this.selectNodePosition(id, needDelay);
  1076. }
  1077. node.eld3
  1078. .select('polygon, rect, ellipse, path')
  1079. .classed('selected', true);
  1080. this.highlightProxyNodes(id.replace('_unfold', ''));
  1081. this.$refs.tree.setCurrentKey(id.replace('_unfold', ''));
  1082. if (this.isIntoView) {
  1083. this.$nextTick(() => {
  1084. setTimeout(() => {
  1085. const dom = document.querySelector('.el-tree-node.is-current.is-focusable');
  1086. if (dom && this.rightShow) {
  1087. dom.scrollIntoView();
  1088. }
  1089. }, 800);
  1090. });
  1091. }
  1092. this.isIntoView = true;
  1093. this.setNodeData();
  1094. },
  1095. /**
  1096. * The node information of the selected node is displayed and highlighted.
  1097. */
  1098. setNodeData() {
  1099. this.selectedNode.info = {
  1100. input: [],
  1101. inputControl: [],
  1102. output: [],
  1103. outputControl: [],
  1104. attributes: [],
  1105. };
  1106. this.selectedNode.showControl = {
  1107. input: true,
  1108. output: true,
  1109. };
  1110. const path = this.selectedNode.name.split('^');
  1111. const selectedNode = this.allGraphData[path[0].replace('_unfold', '')];
  1112. if (selectedNode && !selectedNode.name.includes('more...')) {
  1113. this.selectedNode.show = true;
  1114. this.selectedNode.name = selectedNode.name;
  1115. this.selectedNode.title = selectedNode.name.replace('_unfold', '');
  1116. this.selectedNode.type =
  1117. selectedNode.type === 'name_scope' ||
  1118. selectedNode.type === 'aggregation_scope'
  1119. ? ''
  1120. : selectedNode.type;
  1121. this.selectedNode.countShow =
  1122. selectedNode.type === 'name_scope' ||
  1123. selectedNode.type === 'aggregation_scope';
  1124. this.selectedNode.count = selectedNode.subnode_count;
  1125. const attrTemp = JSON.parse(JSON.stringify(selectedNode.attr || {}));
  1126. if (attrTemp.shape) {
  1127. const shape = JSON.parse(attrTemp.shape);
  1128. if (shape.length) {
  1129. let str = '';
  1130. for (let i = 0; i < shape.length; i++) {
  1131. str += (str ? ',' : '') + JSON.stringify(shape[i]);
  1132. }
  1133. attrTemp.shape = str;
  1134. }
  1135. }
  1136. this.selectedNode.info.attributes = Object.keys(attrTemp).map((key) => {
  1137. return {
  1138. name: key,
  1139. value: attrTemp[key],
  1140. };
  1141. });
  1142. Object.keys(selectedNode.input).forEach((key) => {
  1143. const value = this.getEdgeLabel(selectedNode.input[key]);
  1144. if (selectedNode.input[key].edge_type !== 'control') {
  1145. this.selectedNode.info.input.push({
  1146. name: key,
  1147. value: value,
  1148. });
  1149. } else {
  1150. this.selectedNode.info.inputControl.push({
  1151. name: key,
  1152. value: value,
  1153. });
  1154. }
  1155. });
  1156. Object.keys(selectedNode.output).forEach((key) => {
  1157. const value = this.getEdgeLabel(selectedNode.output[key]);
  1158. if (selectedNode.output[key].edge_type !== 'control') {
  1159. this.selectedNode.info.output.push({
  1160. name: key,
  1161. scope: selectedNode.output[key].scope,
  1162. value: value,
  1163. });
  1164. } else {
  1165. this.selectedNode.info.outputControl.push({
  1166. name: key,
  1167. scope: selectedNode.output[key].scope,
  1168. value: value,
  1169. });
  1170. }
  1171. });
  1172. this.selectedNode.info.output_i = selectedNode.output_i;
  1173. this.highLightEdges(selectedNode);
  1174. } else {
  1175. this.selectedNode.show = false;
  1176. this.selectedNode.name = '';
  1177. this.selectedNode.title = '';
  1178. this.selectedNode.type = '';
  1179. }
  1180. },
  1181. /**
  1182. * The position is offset to the current node in the center of the screen.
  1183. * @param {String} nodeId Selected Node id
  1184. * @param {Boolean} needDelay Delay required
  1185. */
  1186. selectNodePosition(nodeId, needDelay) {
  1187. const nodeDom = document.querySelector(`#graph0 g[id="${nodeId}"]`);
  1188. const nodeRect = nodeDom.getBoundingClientRect();
  1189. const graph = {};
  1190. graph.rect = this.graph.dom.getBoundingClientRect();
  1191. graph.initWidth = graph.rect.width / this.graph.transform.k;
  1192. graph.initHeight = graph.rect.height / this.graph.transform.k;
  1193. const screenChange = {
  1194. x:
  1195. nodeRect.left +
  1196. nodeRect.width / 2 -
  1197. (this.svg.rect.left + this.svg.rect.width / 2),
  1198. y:
  1199. nodeRect.top +
  1200. nodeRect.height / 2 -
  1201. (this.svg.rect.top + this.svg.rect.height / 2),
  1202. };
  1203. this.graph.transform.x -=
  1204. screenChange.x * (this.svg.originSize.width / graph.initWidth);
  1205. this.graph.transform.y -=
  1206. screenChange.y * (this.svg.originSize.height / graph.initHeight);
  1207. this.graph.dom.setAttribute(
  1208. 'transform',
  1209. `translate(${this.graph.transform.x},` +
  1210. `${this.graph.transform.y}) scale(${this.graph.transform.k})`,
  1211. );
  1212. const transitionTime = Math.min(
  1213. Math.abs(screenChange.x) * 2,
  1214. Math.abs(screenChange.y) * 2,
  1215. needDelay ? 800 : 0,
  1216. );
  1217. this.graph.dom.style.transition = `${transitionTime / 1000}s`;
  1218. this.graph.dom.style['transition-timing-function'] = 'linear';
  1219. setTimeout(() => {
  1220. this.graph.dom.style.transition = '';
  1221. }, transitionTime);
  1222. let end = 0;
  1223. this.setInsideBoxData();
  1224. const timer = setInterval(() => {
  1225. this.setInsideBoxData();
  1226. end += 1;
  1227. if (end > transitionTime) {
  1228. clearInterval(timer);
  1229. }
  1230. }, 1);
  1231. },
  1232. /**
  1233. * The drop-down list box of the search drop-down list box is controlled.
  1234. * @param {Object} event Operation event of a component.
  1235. */
  1236. selectBoxVisibleTriggle(event) {
  1237. setTimeout(() => {
  1238. document.querySelector('.el-autocomplete-suggestion').style.display =
  1239. event.type === 'blur' ? 'none' : 'block';
  1240. }, 300);
  1241. },
  1242. /**
  1243. * file select change
  1244. */
  1245. fileChange() {
  1246. this.selectedNode = {
  1247. info: {
  1248. inputControl: [],
  1249. input: [],
  1250. outputControl: [],
  1251. output: [],
  1252. attributes: [],
  1253. },
  1254. showControl: {
  1255. input: true,
  1256. output: true,
  1257. },
  1258. };
  1259. this.clickScope = {};
  1260. this.searchBox.value = '';
  1261. Object.keys(this.allGraphData).forEach((key) => {
  1262. delete this.allGraphData[key];
  1263. });
  1264. d3.select('#graph svg').remove();
  1265. this.firstFloorNodes = [];
  1266. this.queryGraphData();
  1267. this.treeFlag = true;
  1268. },
  1269. /**
  1270. * refresh select list
  1271. * @param {Boolean} expanded Should get data visual plugins or not.
  1272. */
  1273. getSelectList(expanded) {
  1274. if (expanded) {
  1275. this.getDatavisualPlugins();
  1276. }
  1277. },
  1278. /**
  1279. * The search drop-down list box displays the matched data by entering data.
  1280. * @param {String} content Input parameters
  1281. * @param {Object} callback Callback Function
  1282. */
  1283. searchNodesNames() {
  1284. const params = {
  1285. search: this.searchBox.value,
  1286. train_id: this.trainJobID,
  1287. tag: this.fileSearchBox.value,
  1288. offset: 0,
  1289. limit: 1000,
  1290. };
  1291. RequestService.searchNodesNames(params)
  1292. .then(
  1293. (response) => {
  1294. if (response && response.data) {
  1295. this.treeFlag = false;
  1296. this.treeWrapFlag = true;
  1297. this.searchNode.childNodes = [];
  1298. const data = response.data.nodes.map((val) => {
  1299. return {
  1300. label: val.name.split('/').pop(),
  1301. ...val,
  1302. };
  1303. });
  1304. const currentData = JSON.parse(JSON.stringify(data));
  1305. currentData.forEach((val) => {
  1306. val.nodes = [];
  1307. });
  1308. this.searchResolve(currentData);
  1309. data.forEach((val, key) => {
  1310. if (val.nodes && val.nodes.length) {
  1311. val.nodes.forEach((value) => {
  1312. value.parentName = val.name;
  1313. });
  1314. this.dealSearchTreeData(val.nodes);
  1315. }
  1316. });
  1317. }
  1318. },
  1319. (e) => {
  1320. this.loading.show = false;
  1321. },
  1322. )
  1323. .catch((e) => {
  1324. this.$message.error(this.$t('public.dataError'));
  1325. });
  1326. },
  1327. /**
  1328. * Draw the tree
  1329. * @param {Object} children child node
  1330. */
  1331. dealSearchTreeData(children) {
  1332. children.forEach((val) => {
  1333. const node = this.$refs.searchTree.getNode(val.parentName);
  1334. val.label = val.name.split('/').pop();
  1335. val.leaf =
  1336. val.type === 'name_scope' || val.type === 'aggregation_scope'
  1337. ? false
  1338. : true;
  1339. this.$refs.searchTree.append(val, node);
  1340. node.expanded = true;
  1341. if (val.nodes && val.nodes.length) {
  1342. val.nodes.forEach((value) => {
  1343. value.parentName = val.name;
  1344. });
  1345. this.dealSearchTreeData(val.nodes);
  1346. }
  1347. });
  1348. },
  1349. /**
  1350. * Search for all data of a specific node and its namespace.
  1351. * @param {Object} option Selected node data object
  1352. */
  1353. querySingleNode(option) {
  1354. this.selectedNode.name = option.value;
  1355. this.selectedNode.more = false;
  1356. // If a node exists on the map, select the node.
  1357. if (this.allGraphData[option.value]) {
  1358. if (
  1359. d3
  1360. .select(`g[id="${option.value}"], g[id="${option.value}_unfold"]`)
  1361. .size()
  1362. ) {
  1363. // If the namespace or aggregation node is expanded, you need to close it and select
  1364. if (!this.allGraphData[option.value].isUnfold) {
  1365. this.selectNode(true);
  1366. } else {
  1367. this.dealDoubleClick(option.value);
  1368. }
  1369. } else {
  1370. const parentId = option.value.substring(
  1371. 0,
  1372. option.value.lastIndexOf('/'),
  1373. );
  1374. if (
  1375. this.allGraphData[parentId] &&
  1376. this.allGraphData[parentId].isUnfold
  1377. ) {
  1378. const aggregationNode = this.allGraphData[parentId];
  1379. if (aggregationNode && aggregationNode.childIdsList) {
  1380. for (let i = 0; i < aggregationNode.childIdsList.length; i++) {
  1381. if (aggregationNode.childIdsList[i].includes(option.value)) {
  1382. aggregationNode.index = i;
  1383. break;
  1384. }
  1385. }
  1386. }
  1387. this.loading.info = this.$t('graph.searchLoading');
  1388. this.loading.show = true;
  1389. this.selectedNode.name = option.value;
  1390. this.$nextTick(() => {
  1391. setTimeout(() => {
  1392. this.layoutNamescope(parentId, true);
  1393. }, 500);
  1394. });
  1395. }
  1396. }
  1397. } else {
  1398. // If the node does not exist and is not a subnode of the aggregation node,
  1399. // directly invoke the background for query.
  1400. // If the node does not exist and is a subnode of the aggregation node, and the aggregation node is not
  1401. // expanded, directly invoke the background to check the node.
  1402. // If the node does not exist and is a child node in the aggregation node,
  1403. // and the aggregation node is expanded but is not displayed on the diagram, you need to zoom out the
  1404. // aggregated node, query the aggregation node again, and intercept the node array again.
  1405. const params = {
  1406. name: option.value,
  1407. train_id: this.trainJobID,
  1408. tag: this.fileSearchBox.value,
  1409. };
  1410. this.loading.info = this.$t('graph.searchLoading');
  1411. this.loading.show = true;
  1412. RequestService.querySingleNode(params)
  1413. .then(
  1414. (response) => {
  1415. if (response && response.data && response.data.children) {
  1416. const data = this.findStartUnfoldNode(response.data.children);
  1417. if (data) {
  1418. this.dealAutoUnfoldNamescopesData(data);
  1419. }
  1420. if (response.data.children) {
  1421. this.dealTreeData(response.data.children, option.value);
  1422. }
  1423. }
  1424. },
  1425. (e) => {
  1426. this.loading.show = false;
  1427. },
  1428. )
  1429. .catch((e) => {
  1430. this.loading.show = false;
  1431. this.$message.error(this.$t('public.dataError'));
  1432. });
  1433. }
  1434. },
  1435. /**
  1436. * Draw the tree
  1437. * @param {Object} children child node
  1438. * @param {String} name The name of the node that needs to be highlighted
  1439. */
  1440. dealTreeData(children, name) {
  1441. if (children.nodes) {
  1442. if (
  1443. (children.nodes.length > this.nodesCountLimit &&
  1444. this.$refs.tree.getNode(children.scope_name).data.type === 'name_scope') ||
  1445. this.allGraphData[children.scope_name].maxChainNum > this.maxChainNum
  1446. ) {
  1447. return;
  1448. }
  1449. const data = children.nodes.map((val) => {
  1450. return {
  1451. label: val.name.split('/').pop(),
  1452. ...val,
  1453. };
  1454. });
  1455. data.forEach((val) => {
  1456. const node = this.$refs.tree.getNode(children.scope_name);
  1457. if (node.childNodes) {
  1458. if (
  1459. node.childNodes
  1460. .map((value) => value.data.name)
  1461. .indexOf(val.name) === -1
  1462. ) {
  1463. this.$refs.tree.append(val, node);
  1464. }
  1465. } else {
  1466. this.$refs.tree.append(val, node);
  1467. }
  1468. });
  1469. const node = this.$refs.tree.getNode(children.scope_name);
  1470. node.childNodes.forEach((val) => {
  1471. if (
  1472. val.data.type !== 'name_scope' &&
  1473. val.data.type !== 'aggregation_scope'
  1474. ) {
  1475. val.isLeaf = true;
  1476. }
  1477. });
  1478. node.expanded = true;
  1479. node.loading = false;
  1480. } else {
  1481. this.$refs.tree.setCurrentKey(name);
  1482. this.$nextTick(() => {
  1483. setTimeout(() => {
  1484. const dom = document.querySelector('.el-tree-node.is-current.is-focusable');
  1485. if (dom && this.rightShow) {
  1486. dom.scrollIntoView();
  1487. }
  1488. }, 800);
  1489. });
  1490. }
  1491. if (children.children && Object.keys(children.children).length) {
  1492. this.dealTreeData(children.children, name);
  1493. }
  1494. },
  1495. /**
  1496. * Processes all data of the queried node and the namespace to which the node belongs.
  1497. * @param {Object} data All data of the node and the namespace to which the node belongs
  1498. * @return {Object} The data object of the namespace to expand.
  1499. */
  1500. dealAutoUnfoldNamescopesData(data) {
  1501. if (!data.scope_name) {
  1502. return this.dealAutoUnfoldNamescopesData(data.children);
  1503. } else {
  1504. if (this.allGraphData[data.scope_name].isUnfold) {
  1505. return this.dealAutoUnfoldNamescopesData(data.children);
  1506. } else {
  1507. // If the namespace is a namespace and the number of subnodes exceeds the upper limit,
  1508. // an error is reported and the namespace is selected.
  1509. if (
  1510. this.allGraphData[data.scope_name].type === 'name_scope' &&
  1511. data.nodes.length > this.nodesCountLimit
  1512. ) {
  1513. this.selectedNode.name = data.scope_name;
  1514. this.querySingleNode({value: data.scope_name});
  1515. this.$message.error(this.$t('graph.tooManyNodes'));
  1516. this.$nextTick(() => {
  1517. this.loading.show = false;
  1518. });
  1519. } else {
  1520. // Normal expansion
  1521. const nodes = JSON.parse(JSON.stringify(data.nodes));
  1522. this.packageDataToObject(data.scope_name, true, nodes);
  1523. if (
  1524. this.allGraphData[data.scope_name].type === 'aggregation_scope'
  1525. ) {
  1526. this.dealAggregationNodes(data.scope_name);
  1527. const aggregationNode = this.allGraphData[data.scope_name];
  1528. if (aggregationNode) {
  1529. for (let i = 0; i < aggregationNode.childIdsList.length; i++) {
  1530. if (
  1531. aggregationNode.childIdsList[i].includes(
  1532. this.selectedNode.name,
  1533. )
  1534. ) {
  1535. aggregationNode.index = i;
  1536. break;
  1537. }
  1538. }
  1539. }
  1540. if (
  1541. this.allGraphData[data.scope_name].maxChainNum >
  1542. this.maxChainNum
  1543. ) {
  1544. this.selectedNode.name = data.scope_name;
  1545. this.allGraphData[data.scope_name].isUnfold = false;
  1546. this.deleteNamespace(data.scope_name);
  1547. this.$message.error(this.$t('graph.tooManyChain'));
  1548. this.$nextTick(() => {
  1549. this.loading.show = false;
  1550. });
  1551. return;
  1552. }
  1553. }
  1554. if (data.children.scope_name) {
  1555. this.dealAutoUnfoldNamescopesData(data.children);
  1556. } else {
  1557. this.loading.info = this.$t('graph.searchLoading');
  1558. this.loading.show = true;
  1559. this.$nextTick(() => {
  1560. setTimeout(() => {
  1561. this.layoutNamescope(data.scope_name, true);
  1562. }, 200);
  1563. });
  1564. }
  1565. }
  1566. }
  1567. }
  1568. },
  1569. /**
  1570. * Expansion and folding of control edges
  1571. * @param {String} item Determines the control edge of the input or output.
  1572. */
  1573. toggleControl(item) {
  1574. this.selectedNode.showControl[item] = !this.selectedNode.showControl[
  1575. item
  1576. ];
  1577. },
  1578. /**
  1579. * Click the node information name.
  1580. */
  1581. nodeNameClick() {
  1582. const nodeNameText = event.target;
  1583. if (document.body.createTextRange) {
  1584. const nodeNameTextRange = document.body.createTextRange();
  1585. nodeNameTextRange.moveToElementText(nodeNameText);
  1586. nodeNameTextRange.select();
  1587. } else if (window.getSelection) {
  1588. const nodeNameSelection = window.getSelection();
  1589. const nodeNameTextRange = document.createRange();
  1590. nodeNameTextRange.selectNodeContents(nodeNameText);
  1591. nodeNameSelection.removeAllRanges();
  1592. nodeNameSelection.addRange(nodeNameTextRange);
  1593. }
  1594. },
  1595. /**
  1596. * Collapse on the right
  1597. */
  1598. toggleRight() {
  1599. this.rightShow = !this.rightShow;
  1600. setTimeout(() => {
  1601. this.initSvg(false);
  1602. this.initGraphRectData();
  1603. }, 500);
  1604. },
  1605. /**
  1606. * Full-screen display
  1607. */
  1608. toggleScreen() {
  1609. this.fullScreen = !this.fullScreen;
  1610. setTimeout(() => {
  1611. this.initSvg(false);
  1612. this.initGraphRectData();
  1613. }, 500);
  1614. },
  1615. /**
  1616. * Download svg
  1617. */
  1618. downLoadSVG() {
  1619. const svgXml = document.querySelector('#graph #graph0').innerHTML;
  1620. const bbox = document.getElementById('graph0').getBBox();
  1621. const viewBoxSize = `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`;
  1622. const encodeStr =
  1623. `<svg xmlns="http://www.w3.org/2000/svg" ` +
  1624. `xmlns:xlink="http://www.w3.org/1999/xlink" ` +
  1625. `width="${bbox.width}" height="${bbox.height}" ` +
  1626. `viewBox="${viewBoxSize}">${CommonProperty.graphDownloadStyle}<g>${svgXml}</g></svg>`;
  1627. const downloadLink = document.createElement('a');
  1628. downloadLink.download = 'graph.svg';
  1629. downloadLink.style.display = 'none';
  1630. const blob = new Blob([encodeStr], {type: 'text/html'});
  1631. downloadLink.href = URL.createObjectURL(blob);
  1632. document.body.appendChild(downloadLink);
  1633. downloadLink.click();
  1634. document.body.removeChild(downloadLink);
  1635. },
  1636. /**
  1637. * Fold the legend area.
  1638. */
  1639. foldLegend() {
  1640. this.showLegend = !this.showLegend;
  1641. },
  1642. /**
  1643. * Control Display User Guide
  1644. */
  1645. showUserGuide() {
  1646. this.guide.content = [
  1647. this.$t('graph.guideContent11'),
  1648. this.$t('graph.guideContent12'),
  1649. this.$t('graph.guideContent13'),
  1650. this.$t('graph.guideContent14'),
  1651. ];
  1652. this.guide.show = true;
  1653. this.guide.step = 1;
  1654. },
  1655. /**
  1656. * Close user guide
  1657. */
  1658. closeUserGuide() {
  1659. this.guide.show = false;
  1660. },
  1661. /**
  1662. * Show the next step
  1663. */
  1664. guideNext() {
  1665. if (this.guide.step < 3) {
  1666. this.guide.step++;
  1667. switch (this.guide.step) {
  1668. case 2:
  1669. this.guide.content = [this.$t('graph.guideContent2')];
  1670. break;
  1671. case 3:
  1672. this.guide.content = [this.$t('graph.guideContent3')];
  1673. break;
  1674. default:
  1675. break;
  1676. }
  1677. } else if (this.guide.step >= 3) {
  1678. this.guide.show = false;
  1679. }
  1680. },
  1681. /**
  1682. * jump back to train dashboard
  1683. */
  1684. jumpToTrainDashboard() {
  1685. this.$router.push({
  1686. path: '/train-manage/training-dashboard',
  1687. query: {
  1688. id: this.trainJobID,
  1689. },
  1690. });
  1691. },
  1692. },
  1693. // Components imported by the page
  1694. components: {},
  1695. };
  1696. </script>
  1697. <style>
  1698. .tooltip-container .cl-graph-sidebar-tip {
  1699. word-break: normal;
  1700. }
  1701. .cl-graph-manage {
  1702. height: 100%;
  1703. }
  1704. .cl-graph-manage .cl-graph-title {
  1705. height: 50px;
  1706. line-height: 50px;
  1707. }
  1708. .cl-graph-manage .cl-graph-title .path-message {
  1709. display: inline-block;
  1710. line-height: 20px;
  1711. padding: 0px 4px 15px 4px;
  1712. font-weight: bold;
  1713. vertical-align: bottom;
  1714. }
  1715. .cl-graph-manage .cl-graph-title .guide {
  1716. cursor: pointer;
  1717. margin-left: 10px;
  1718. display: inline-block;
  1719. line-height: 18px;
  1720. font-size: 12px;
  1721. }
  1722. .cl-graph-manage .cl-graph-title .guide .guide-icon {
  1723. display: inline-block;
  1724. width: 16px;
  1725. height: 16px;
  1726. vertical-align: -2.5px;
  1727. margin-right: 4px;
  1728. background: url("../../assets/images/guideIcon.svg");
  1729. }
  1730. .cl-graph-manage .cl-graph-title .guide:hover {
  1731. color: #00a5a7;
  1732. }
  1733. .cl-graph-manage .cl-graph-title .guide:hover .guide-icon {
  1734. background: url("../../assets/images/guideIconHover.svg");
  1735. }
  1736. .cl-graph-manage .graph-p32 {
  1737. height: 100%;
  1738. position: relative;
  1739. }
  1740. .cl-graph-manage .graph-p32 .guide-content {
  1741. height: 100%;
  1742. width: 100%;
  1743. position: absolute;
  1744. background-color: #c6c8cc;
  1745. z-index: 9999;
  1746. }
  1747. .cl-graph-manage .graph-p32 .guide-content .step-pic {
  1748. text-align: center;
  1749. margin-top: 8px;
  1750. }
  1751. .cl-graph-manage .graph-p32 .guide-content .step {
  1752. height: 100%;
  1753. background-repeat: round;
  1754. user-select: none;
  1755. }
  1756. .cl-graph-manage .graph-p32 .guide-content .step img {
  1757. width: 100%;
  1758. }
  1759. .cl-graph-manage .graph-p32 .guide-content .guide-span {
  1760. font-size: 12px;
  1761. color: #575d6c;
  1762. line-height: 18px;
  1763. text-align: left;
  1764. display: inline-block;
  1765. }
  1766. .cl-graph-manage .graph-p32 .guide-content .el-popover .el-icon-close {
  1767. cursor: pointer;
  1768. position: absolute;
  1769. right: 10px;
  1770. top: 13px;
  1771. font-size: 20px;
  1772. }
  1773. .cl-graph-manage .graph-p32 .guide-content .el-popover .el-icon-close:hover {
  1774. color: #00a5a7;
  1775. }
  1776. .cl-graph-manage .graph-p32 .guide-content .el-popover__title {
  1777. font-size: 16px;
  1778. color: #252b3a;
  1779. line-height: 24px;
  1780. font-weight: bold;
  1781. }
  1782. .cl-graph-manage .graph-p32 .guide-content .el-button {
  1783. display: block;
  1784. float: right;
  1785. height: 28px;
  1786. line-height: 27px;
  1787. border-radius: 0;
  1788. padding: 0 20px;
  1789. }
  1790. .cl-graph-manage .cl-content {
  1791. height: calc(100% - 50px);
  1792. overflow: auto;
  1793. }
  1794. .cl-graph-manage #graphs {
  1795. width: 100%;
  1796. height: 100%;
  1797. font-size: 0;
  1798. background: #f0f2f5;
  1799. }
  1800. .cl-graph-manage #graphs .search {
  1801. margin-bottom: 15px;
  1802. width: 100%;
  1803. }
  1804. .cl-graph-manage #graphs .search-wrap {
  1805. position: relative;
  1806. }
  1807. .cl-graph-manage #graphs .search-wrap .tree-wrap {
  1808. position: absolute;
  1809. left: 0;
  1810. top: 32px;
  1811. z-index: 101;
  1812. width: 100%;
  1813. max-height: 224px;
  1814. overflow: auto;
  1815. border: 1px solid #dcdfe6;
  1816. border-top: none;
  1817. background: #fff;
  1818. }
  1819. .cl-graph-manage #graphs .search-wrap .tree-wrap .image-type {
  1820. width: 20px;
  1821. height: 10px;
  1822. margin-right: 10px;
  1823. }
  1824. .cl-graph-manage #graphs .search-wrap .tree-wrap .el-tree > .el-tree-node {
  1825. min-width: 100%;
  1826. display: inline-block;
  1827. }
  1828. .cl-graph-manage #graphs .search-wrap .tree-wrap .el-tree .custom-tree-node {
  1829. padding-right: 8px;
  1830. }
  1831. .cl-graph-manage #graphs .search-wrap .collapse_i {
  1832. cursor: pointer;
  1833. }
  1834. .cl-graph-manage #graphs .cl-graph {
  1835. position: relative;
  1836. width: 100%;
  1837. height: 100%;
  1838. background-color: #fff;
  1839. padding: 0 32px 10px;
  1840. min-height: 700px;
  1841. overflow: hidden;
  1842. }
  1843. .cl-graph-manage #graphs .cl-graph.full-screen {
  1844. position: absolute;
  1845. top: 0;
  1846. bottom: 0;
  1847. left: -280px;
  1848. right: 0;
  1849. width: auto;
  1850. height: auto;
  1851. padding: 0;
  1852. }
  1853. .cl-graph-manage #graphs .cl-graph.full-screen #sidebar .node-info-con {
  1854. height: calc(100% - 300px);
  1855. }
  1856. .cl-graph-manage #graphs .cl-graph.full-screen .graph-container {
  1857. width: 100%;
  1858. }
  1859. .cl-graph-manage #graphs #sidebar.right-hide {
  1860. right: -442px;
  1861. }
  1862. .cl-graph-manage #graphs #sidebar {
  1863. position: absolute;
  1864. right: 0;
  1865. top: 0;
  1866. width: 442px;
  1867. height: 100%;
  1868. border-radius: 6px;
  1869. text-align: left;
  1870. background-color: #ffffff;
  1871. display: inline-block;
  1872. box-shadow: 0 1px 3px 0px rgba(0, 0, 0, 0.1);
  1873. color: #333333;
  1874. font-size: 14px;
  1875. line-height: 14px;
  1876. padding: 18px 32px 10px;
  1877. }
  1878. .cl-graph-manage #graphs #sidebar .sidebar-tooltip {
  1879. position: absolute;
  1880. height: 32px;
  1881. top: 18px;
  1882. left: 10px;
  1883. display: flex;
  1884. align-items: center;
  1885. font-size: 16px;
  1886. color: #6c7280;
  1887. }
  1888. .cl-graph-manage #graphs #sidebar div,
  1889. .cl-graph-manage #graphs #sidebar span,
  1890. .cl-graph-manage #graphs #sidebar pre {
  1891. font-size: 14px;
  1892. }
  1893. .cl-graph-manage #graphs #sidebar #small-container {
  1894. height: 209px;
  1895. width: 100%;
  1896. z-index: 100;
  1897. border: 1px solid #e6ebf5;
  1898. overflow: hidden;
  1899. background-color: white;
  1900. position: relative;
  1901. }
  1902. .cl-graph-manage #graphs #sidebar #small-container #small-resize {
  1903. width: 100%;
  1904. height: 100%;
  1905. position: absolute;
  1906. left: 0;
  1907. top: 0;
  1908. }
  1909. .cl-graph-manage #graphs #sidebar #small-container #small-map {
  1910. height: 100%;
  1911. width: 100%;
  1912. position: relative;
  1913. padding: 0;
  1914. }
  1915. .cl-graph-manage #graphs #sidebar #small-container #inside-box {
  1916. background-color: #5b88f1;
  1917. position: absolute;
  1918. /* Transparency */
  1919. opacity: 0.3;
  1920. width: 100%;
  1921. height: 100%;
  1922. left: 0px;
  1923. top: 0px;
  1924. z-index: 200;
  1925. cursor: move;
  1926. }
  1927. .cl-graph-manage #graphs #sidebar .title {
  1928. padding: 20px 0;
  1929. font-size: 14px;
  1930. color: #333333;
  1931. }
  1932. .cl-graph-manage #graphs #sidebar .title img {
  1933. float: right;
  1934. margin-right: 10px;
  1935. cursor: pointer;
  1936. }
  1937. .cl-graph-manage #graphs #sidebar .graph-controls {
  1938. padding: 10px 20px 0 20px;
  1939. }
  1940. .cl-graph-manage #graphs #sidebar .graph-controls div {
  1941. cursor: pointer;
  1942. display: inline-block;
  1943. margin-left: 20px;
  1944. }
  1945. .cl-graph-manage #graphs #sidebar .graph-controls img {
  1946. cursor: pointer;
  1947. vertical-align: middle;
  1948. }
  1949. .cl-graph-manage #graphs #sidebar .node-info-con ::-webkit-scrollbar-button {
  1950. z-index: 200;
  1951. width: 10px;
  1952. height: 10px;
  1953. background: #fff;
  1954. cursor: pointer;
  1955. }
  1956. .cl-graph-manage #graphs #sidebar .node-info-con ::-webkit-scrollbar-button:horizontal:single-button:start {
  1957. background-image: url("../../assets/images/scroll-btn-left.png");
  1958. background-position: center;
  1959. }
  1960. .cl-graph-manage #graphs #sidebar .node-info-con ::-webkit-scrollbar-button:horizontal:single-button:end {
  1961. background-image: url("../../assets/images/scroll-btn-right.png");
  1962. background-position: center;
  1963. }
  1964. .cl-graph-manage #graphs #sidebar .node-info-con ::-webkit-scrollbar-button:vertical:single-button:start {
  1965. background-image: url("../../assets/images/scroll-btn-up.png");
  1966. background-position: center;
  1967. }
  1968. .cl-graph-manage #graphs #sidebar .node-info-con ::-webkit-scrollbar-button:vertical:single-button:end {
  1969. background-image: url("../../assets/images/scroll-btn-down.png");
  1970. background-position: center;
  1971. }
  1972. .cl-graph-manage #graphs #sidebar .node-info-con ::-webkit-scrollbar-thumb {
  1973. background-color: #bac5cc;
  1974. }
  1975. .cl-graph-manage #graphs #sidebar .node-info-con ::-webkit-scrollbar {
  1976. width: 6px;
  1977. height: 6px;
  1978. }
  1979. .cl-graph-manage #graphs #sidebar .node-info-container {
  1980. height: calc(100% - 451px);
  1981. }
  1982. .cl-graph-manage #graphs #sidebar .node-info-container-long {
  1983. height: calc(100% - 357px);
  1984. }
  1985. .cl-graph-manage #graphs #sidebar .node-info {
  1986. font-size: 14px;
  1987. padding: 0 20px;
  1988. height: calc(100% - 54px);
  1989. overflow: auto;
  1990. color: #333;
  1991. background-color: #f7faff;
  1992. }
  1993. .cl-graph-manage #graphs #sidebar .node-info .clear {
  1994. clear: both;
  1995. }
  1996. .cl-graph-manage #graphs #sidebar .node-info .hover li:hover {
  1997. background: #fce8b2;
  1998. }
  1999. .cl-graph-manage #graphs #sidebar .node-info .hover .control-list .dependence-title {
  2000. line-height: 30px;
  2001. cursor: pointer;
  2002. font-weight: bold;
  2003. }
  2004. .cl-graph-manage #graphs #sidebar .node-info .hover .control-list .dependence-title img {
  2005. vertical-align: middle;
  2006. margin-right: 3px;
  2007. }
  2008. .cl-graph-manage #graphs #sidebar .node-info .hover .control-list .dependence-title.hide img {
  2009. margin-top: -3px;
  2010. transform: rotate(-90deg);
  2011. }
  2012. .cl-graph-manage #graphs #sidebar .node-info .hover .control-list li:hover {
  2013. background: #fce8b2;
  2014. }
  2015. .cl-graph-manage #graphs #sidebar .node-info .hover .control-list:hover {
  2016. background: none;
  2017. }
  2018. .cl-graph-manage #graphs #sidebar .node-info .pointer {
  2019. cursor: pointer;
  2020. }
  2021. .cl-graph-manage #graphs #sidebar .node-info .item-content {
  2022. max-height: calc(50% - 95px);
  2023. overflow: auto;
  2024. }
  2025. .cl-graph-manage #graphs #sidebar .node-info .item-content li {
  2026. min-width: 100%;
  2027. width: max-content;
  2028. }
  2029. .cl-graph-manage #graphs #sidebar .node-info .item-min {
  2030. min-height: 50px;
  2031. }
  2032. .cl-graph-manage #graphs #sidebar .node-info .item-min2 {
  2033. min-height: 87px;
  2034. }
  2035. .cl-graph-manage #graphs #sidebar .node-info .items {
  2036. line-height: 20px;
  2037. padding: 9px 0;
  2038. }
  2039. .cl-graph-manage #graphs #sidebar .node-info .items .items-over {
  2040. max-height: 60px;
  2041. overflow: auto;
  2042. }
  2043. .cl-graph-manage #graphs #sidebar .node-info .items .item {
  2044. color: #999;
  2045. }
  2046. .cl-graph-manage #graphs #sidebar .node-info .shape {
  2047. vertical-align: top;
  2048. width: 50px;
  2049. word-break: break-all;
  2050. display: inline-table;
  2051. position: absolute;
  2052. left: 0;
  2053. }
  2054. .cl-graph-manage #graphs #sidebar .node-info .key {
  2055. vertical-align: top;
  2056. width: 60px;
  2057. word-break: break-all;
  2058. display: inline-table;
  2059. }
  2060. .cl-graph-manage #graphs #sidebar .node-info .label {
  2061. vertical-align: top;
  2062. width: 70px;
  2063. word-break: break-all;
  2064. display: inline-block;
  2065. }
  2066. .cl-graph-manage #graphs #sidebar .node-info .value {
  2067. vertical-align: top;
  2068. display: inline-block;
  2069. width: calc(100% - 70px);
  2070. white-space: nowrap;
  2071. overflow: auto;
  2072. }
  2073. .cl-graph-manage #graphs #sidebar .node-info .size {
  2074. width: 310px;
  2075. font-size: 12px;
  2076. text-align: right;
  2077. }
  2078. .cl-graph-manage #graphs #sidebar .node-info .input {
  2079. width: 100%;
  2080. position: relative;
  2081. display: inline-block;
  2082. white-space: nowrap;
  2083. }
  2084. .cl-graph-manage #graphs #sidebar .node-info ul li {
  2085. line-height: 20px;
  2086. }
  2087. .cl-graph-manage #graphs #sidebar .legend .legend-content {
  2088. background-color: #f7faff;
  2089. padding: 0 32px;
  2090. height: 94px;
  2091. overflow-y: auto;
  2092. }
  2093. .cl-graph-manage #graphs #sidebar .legend .legend-item {
  2094. padding: 5px 0;
  2095. display: inline-block;
  2096. width: 50%;
  2097. font-size: 14px;
  2098. line-height: 20px;
  2099. }
  2100. .cl-graph-manage #graphs #sidebar .legend .legend-item .pic {
  2101. width: 45px;
  2102. text-align: center;
  2103. display: inline-block;
  2104. padding-left: 20px;
  2105. vertical-align: middle;
  2106. }
  2107. .cl-graph-manage #graphs #sidebar .legend .legend-item .pic img {
  2108. max-width: 45px;
  2109. max-height: 15px;
  2110. margin-left: -20px;
  2111. vertical-align: middle;
  2112. }
  2113. .cl-graph-manage #graphs #sidebar .legend .legend-item .legend-text {
  2114. display: inline-block;
  2115. padding-left: 20px;
  2116. width: calc(100% - 45px);
  2117. vertical-align: middle;
  2118. overflow: hidden;
  2119. text-overflow: ellipsis;
  2120. white-space: nowrap;
  2121. }
  2122. .cl-graph-manage #graphs #sidebar .legend .legend-item .legend-text:hover {
  2123. cursor: default;
  2124. }
  2125. .cl-graph-manage #graphs #sidebar .toggle-right {
  2126. position: absolute;
  2127. top: calc(50% - 43px);
  2128. left: -16px;
  2129. width: 18px;
  2130. height: 86px;
  2131. cursor: pointer;
  2132. background-image: url("../../assets/images/toggle-right-bg.png");
  2133. }
  2134. .cl-graph-manage #graphs #sidebar .icon-toggle {
  2135. width: 6px;
  2136. height: 9px;
  2137. background-image: url("../../assets/images/toggle-right-icon.png");
  2138. position: absolute;
  2139. top: calc(50% - 4.5px);
  2140. left: calc(50% - 3px);
  2141. }
  2142. .cl-graph-manage #graphs #sidebar .icon-toggle.icon-left {
  2143. transform: rotateY(180deg);
  2144. }
  2145. .cl-graph-manage #graphs .operate-button-list {
  2146. position: absolute;
  2147. right: 0;
  2148. top: 0;
  2149. z-index: 100;
  2150. }
  2151. .cl-graph-manage #graphs .operate-button-list div {
  2152. cursor: pointer;
  2153. width: 12px;
  2154. height: 12px;
  2155. display: inline-block;
  2156. margin: 5px;
  2157. }
  2158. .cl-graph-manage #graphs .operate-button-list .download-button {
  2159. background-image: url("../../assets/images/download.png");
  2160. }
  2161. .cl-graph-manage #graphs .operate-button-list .full-screen-button {
  2162. background-image: url("../../assets/images/full-screen.png");
  2163. }
  2164. .cl-graph-manage #graphs .graph-container.all {
  2165. width: 100%;
  2166. }
  2167. .cl-graph-manage #graphs .graph-container .node:hover > path,
  2168. .cl-graph-manage #graphs .graph-container .node:hover > ellipse,
  2169. .cl-graph-manage #graphs .graph-container .node:hover > polygon,
  2170. .cl-graph-manage #graphs .graph-container .node:hover > rect {
  2171. stroke-width: 2px;
  2172. }
  2173. .cl-graph-manage #graphs .graph-container .node.cluster > rect:hover {
  2174. stroke: #8df1f2;
  2175. }
  2176. .cl-graph-manage #graphs .graph-container .selected {
  2177. stroke: red !important;
  2178. stroke-width: 2px;
  2179. }
  2180. .cl-graph-manage #graphs .graph-container,
  2181. .cl-graph-manage #graphs #small-map {
  2182. font-size: 16px;
  2183. position: relative;
  2184. display: inline-block;
  2185. width: calc(100% - 442px);
  2186. height: calc(100% - 5px);
  2187. text-align: left;
  2188. -webkit-touch-callout: none;
  2189. -webkit-user-select: none;
  2190. -khtml-user-select: none;
  2191. -moz-user-select: none;
  2192. -ms-user-select: none;
  2193. user-select: none;
  2194. }
  2195. .cl-graph-manage #graphs .graph-container .graph,
  2196. .cl-graph-manage #graphs #small-map .graph {
  2197. height: 100%;
  2198. background-color: #f7faff;
  2199. }
  2200. .cl-graph-manage #graphs .graph-container #graph0 > polygon,
  2201. .cl-graph-manage #graphs #small-map #graph0 > polygon {
  2202. fill: transparent;
  2203. }
  2204. .cl-graph-manage #graphs .graph-container .node,
  2205. .cl-graph-manage #graphs #small-map .node {
  2206. cursor: pointer;
  2207. }
  2208. .cl-graph-manage #graphs .graph-container .edge path,
  2209. .cl-graph-manage #graphs #small-map .edge path {
  2210. stroke: #787878;
  2211. }
  2212. .cl-graph-manage #graphs .graph-container .edge polygon,
  2213. .cl-graph-manage #graphs #small-map .edge polygon {
  2214. fill: #787878;
  2215. }
  2216. .cl-graph-manage #graphs .graph-container .edge.highlighted path,
  2217. .cl-graph-manage #graphs #small-map .edge.highlighted path {
  2218. stroke: red;
  2219. }
  2220. .cl-graph-manage #graphs .graph-container .edge.highlighted polygon,
  2221. .cl-graph-manage #graphs #small-map .edge.highlighted polygon {
  2222. stroke: red;
  2223. fill: red;
  2224. }
  2225. .cl-graph-manage #graphs .graph-container .edge.highlighted marker path,
  2226. .cl-graph-manage #graphs #small-map .edge.highlighted marker path {
  2227. fill: red;
  2228. }
  2229. .cl-graph-manage #graphs .graph-container .node.aggregation > polygon,
  2230. .cl-graph-manage #graphs #small-map .node.aggregation > polygon {
  2231. stroke: #e3aa00;
  2232. fill: #ffe794;
  2233. }
  2234. .cl-graph-manage #graphs .graph-container .node.cluster.aggregation > rect,
  2235. .cl-graph-manage #graphs #small-map .node.cluster.aggregation > rect {
  2236. stroke: #e3aa00;
  2237. fill: #ffe794;
  2238. stroke-dasharray: 3, 3;
  2239. }
  2240. .cl-graph-manage #graphs .graph-container .node > polygon,
  2241. .cl-graph-manage #graphs #small-map .node > polygon {
  2242. stroke: #00a5a7;
  2243. fill: #8df1f2;
  2244. }
  2245. .cl-graph-manage #graphs .graph-container .node > ellipse,
  2246. .cl-graph-manage #graphs #small-map .node > ellipse {
  2247. stroke: #4ea6e6;
  2248. fill: #b8e0ff;
  2249. }
  2250. .cl-graph-manage #graphs .graph-container .plain > path,
  2251. .cl-graph-manage #graphs .graph-container .plain ellipse,
  2252. .cl-graph-manage #graphs #small-map .plain > path,
  2253. .cl-graph-manage #graphs #small-map .plain ellipse {
  2254. stroke: #e37d29;
  2255. fill: #ffd0a6;
  2256. stroke-dasharray: 1.5, 1.5;
  2257. }
  2258. .cl-graph-manage #graphs .graph-container .edge-point ellipse,
  2259. .cl-graph-manage #graphs #small-map .edge-point ellipse {
  2260. stroke: #a7a7a7;
  2261. fill: #a7a7a7;
  2262. }
  2263. .cl-graph-manage #graphs .graph-container text,
  2264. .cl-graph-manage #graphs #small-map text {
  2265. fill: black;
  2266. }
  2267. .cl-graph-manage #graphs .image-noData {
  2268. width: 100%;
  2269. height: 100%;
  2270. background: #fff;
  2271. position: absolute;
  2272. top: 0;
  2273. left: 0;
  2274. display: flex;
  2275. justify-content: center;
  2276. align-items: center;
  2277. flex-direction: column;
  2278. z-index: 200;
  2279. }
  2280. .cl-graph-manage #graphs .noData-text {
  2281. margin-top: 33px;
  2282. font-size: 18px;
  2283. }
  2284. .cl-graph-manage .cl-display-block {
  2285. display: block;
  2286. }
  2287. .cl-graph-manage .cl-input-value {
  2288. width: calc(100% - 70px) !important;
  2289. margin-left: 10px !important;
  2290. }
  2291. .cl-graph-manage .cl-close-btn {
  2292. width: 20px;
  2293. height: 20px;
  2294. vertical-align: -3px;
  2295. cursor: pointer;
  2296. display: inline-block;
  2297. }
  2298. .cl-graph-manage .cl-title-right {
  2299. padding-right: 32px;
  2300. }
  2301. #graphTemp,
  2302. #subgraphTemp {
  2303. position: absolute;
  2304. bottom: 0;
  2305. visibility: hidden;
  2306. }
  2307. </style>