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.

data-map.vue 28 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  1. <!--
  2. Copyright 2020 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-data-map-manage -->
  15. <div class="cl-data-map-manage">
  16. <div class='data-map-p32'>
  17. <div class="cl-title cl-data-map-title">
  18. <div class="cl-title-left">{{$t('dataMap.titleText')}}</div>
  19. <div class="cl-title-right">
  20. <div class="cl-close-btn"
  21. @click="jumpToTrainDashboard">
  22. <img src="@/assets/images/close-page.png">
  23. </div>
  24. </div>
  25. </div>
  26. <div class="cl-content">
  27. <div id="data-maps">
  28. <div class="cl-data-map"
  29. :class="fullScreen? 'full-screen':''">
  30. <!-- data-map -->
  31. <div class="data-map-container"
  32. :class="rightShow?'':'all'">
  33. <div id="graph"></div>
  34. <div class="image-noData"
  35. v-if="noData">
  36. <div>
  37. <img :src="require('@/assets/images/nodata.png')"
  38. alt="" />
  39. </div>
  40. <div class="noData-text">{{$t("public.noData")}}</div>
  41. </div>
  42. <div :title="$t('graph.fullScreen')"
  43. class="full-screen-button"
  44. @click="fullScreen = !fullScreen"></div>
  45. <div :title="$t('graph.fitScreen')"
  46. class="fit-screen"
  47. @click="fit()"></div>
  48. <div :title="$t('graph.downloadPic')"
  49. class="download-button"
  50. @click="downLoadSVG"></div>
  51. </div>
  52. <!-- Right column -->
  53. <div id="sidebar"
  54. :class="rightShow ? '' : 'right-hide'">
  55. <div class="toggle-right"
  56. @click="toggleRight">
  57. <i :class="rightShow?'icon-toggle':'icon-toggle icon-left'"></i>
  58. </div>
  59. <!-- Node information -->
  60. <div class="node-info"
  61. :class="showLegend?'node-info-con node-info-container':'node-info-con node-info-container-long'">
  62. <div class="title">{{$t('graph.nodeInfo')}}</div>
  63. <div class="node-info-list"
  64. v-if="selectedNode && selectedNode.length">
  65. <div class="item"
  66. v-for="item in selectedNode"
  67. :key="item.key">
  68. <div class="label">{{item.key}}</div>
  69. <div class="value">{{item.value}}</div>
  70. </div>
  71. </div>
  72. </div>
  73. <!-- Legend -->
  74. <div class="legend"
  75. v-if="!fullScreen">
  76. <div class="title">
  77. {{ $t('graph.legend') }}
  78. <img :src="require('@/assets/images/all-drop-down.png')"
  79. v-show="!showLegend"
  80. @click="foldLegend"
  81. alt="" />
  82. <img :src="require('@/assets/images/all-uptake.png')"
  83. v-show="showLegend"
  84. @click="foldLegend"
  85. alt="" />
  86. </div>
  87. <div v-show="showLegend"
  88. class="legend-content">
  89. <div class="legend-item">
  90. <div class="pic">
  91. <img :src="require('@/assets/images/creat-dataset.png')"
  92. alt="" />
  93. </div>
  94. <div>Create</div>
  95. </div>
  96. <div class="legend-item">
  97. <div class="pic">
  98. <img :src="require('@/assets/images/map-dataset.png')"
  99. alt="" />
  100. </div>
  101. <div>Map</div>
  102. </div>
  103. <div class="legend-item">
  104. <div class="pic">
  105. <img :src="require('@/assets/images/operator-node.png')"
  106. alt="" />
  107. </div>
  108. <div>Operator</div>
  109. </div>
  110. <div class="legend-item">
  111. <div class="pic">
  112. <img :src="require('@/assets/images/shuffle-dataset.png')"
  113. alt="" />
  114. </div>
  115. <div>Shuffle</div>
  116. </div>
  117. <div class="legend-item">
  118. <div class="pic">
  119. <img :src="require('@/assets/images/name-scope.png')"
  120. alt="" />
  121. </div>
  122. <div>Batch</div>
  123. </div>
  124. <div class="legend-item">
  125. <div class="pic">
  126. <img :src="require('@/assets/images/repeat-dataset.png')"
  127. alt="" />
  128. </div>
  129. <div>Repeat</div>
  130. </div>
  131. </div>
  132. </div>
  133. </div>
  134. </div>
  135. </div>
  136. </div>
  137. </div>
  138. </div>
  139. </template>
  140. <script>
  141. import RequestService from '../../services/request-service';
  142. import CommonProperty from '@/common/common-property.js';
  143. import {select, selectAll, zoom} from 'd3';
  144. import 'd3-graphviz';
  145. const d3 = {select, selectAll, zoom};
  146. export default {
  147. data() {
  148. return {
  149. allGraphData: {},
  150. graphviz: null,
  151. totalMemory: 16777216 * 2, // Memory size of the graph plug-in
  152. scaleRange: [0.0001, 10000], // graph zooms in and zooms out.
  153. rightShow: true,
  154. showLegend: true,
  155. fullScreen: false,
  156. trainJobID: '',
  157. selectedNode: [],
  158. noData: false,
  159. };
  160. },
  161. mounted() {
  162. // Judging from the training job overview.
  163. if (!this.$route.query || !this.$route.query.train_id) {
  164. this.trainJobID = '';
  165. this.$message.error(this.$t('trainingDashboard.invalidId'));
  166. document.title = `${this.$t('trainingDashboard.dataMap')}-MindInsight`;
  167. return;
  168. }
  169. this.trainJobID = this.$route.query.train_id;
  170. document.title = `${decodeURIComponent(this.trainJobID)}-${this.$t(
  171. 'trainingDashboard.dataMap',
  172. )}-MindInsight`;
  173. this.$nextTick(() => {
  174. this.queryGraphData();
  175. });
  176. },
  177. destroyed() {},
  178. methods: {
  179. /**
  180. * To obtain graph data.
  181. */
  182. queryGraphData() {
  183. const params = {
  184. train_id: this.trainJobID,
  185. };
  186. RequestService.queryDatasetGraph(params).then((res) => {
  187. if (res && res.data && res.data.dataset_graph) {
  188. const data = JSON.parse(JSON.stringify(res.data.dataset_graph));
  189. this.dealResponseData(data);
  190. if (Object.keys(this.allGraphData).length) {
  191. this.noData = false;
  192. const dot = this.packageGraphData();
  193. this.initGraph(dot);
  194. } else {
  195. this.noData = true;
  196. }
  197. }
  198. });
  199. },
  200. /**
  201. * Processing Graph Data
  202. * @param {Object} data Data of the graph
  203. * @param {String} parentKey Key value of the parent-level data.
  204. * @param {Number} index Index of a node.
  205. */
  206. dealResponseData(data, parentKey = '', index = 0) {
  207. if (!data) {
  208. return;
  209. }
  210. const key = `${parentKey ? parentKey + '/' : ''}${data.op_type ||
  211. ''}_${index}`;
  212. const obj = {
  213. key: key,
  214. id: '',
  215. };
  216. Object.keys(data).forEach((k) => {
  217. {
  218. if (k !== 'children') {
  219. obj[k] = JSON.parse(JSON.stringify(data[k]));
  220. } else {
  221. obj.children = [];
  222. if (data.children && data.children.length) {
  223. data.children.forEach((data, ind) => {
  224. obj.children.push(`${obj.key}/${data.op_type}_${ind}`);
  225. this.dealResponseData(data, obj.key, ind);
  226. });
  227. }
  228. }
  229. }
  230. });
  231. this.allGraphData[key] = obj;
  232. },
  233. /**
  234. * Encapsulates graph data into dot data.
  235. * @return {String} dot string for packing graph data
  236. */
  237. packageGraphData() {
  238. const nodeType = [
  239. 'BatchDataset',
  240. 'ShuffleDataset',
  241. 'RepeatDataset',
  242. 'MapDataset',
  243. ];
  244. let nodeStr = '';
  245. let edgeStr = '';
  246. Object.keys(this.allGraphData).forEach((key) => {
  247. const node = this.allGraphData[key];
  248. if (node.op_type === 'MapDataset') {
  249. nodeStr += this.packageSubGraph(key);
  250. } else {
  251. node.id = key;
  252. nodeStr +=
  253. `<${node.key}>[id="${node.key}";label="${node.op_type}";` +
  254. `class=${
  255. nodeType.includes(node.op_type) ? node.op_type : 'CreatDataset'
  256. };shape=rect;fillcolor="#9cc3e5";];`;
  257. }
  258. });
  259. Object.keys(this.allGraphData).forEach((key) => {
  260. const node = this.allGraphData[key];
  261. node.children.forEach((k) => {
  262. const child = this.allGraphData[k];
  263. edgeStr += `<${child.id}>-><${node.id}>[${
  264. child.op_type === 'MapDataset'
  265. ? `ltail=<cluster_${child.key}>;`
  266. : ''
  267. }${
  268. node.op_type === 'MapDataset' ? `lhead=<cluster_${node.key}>;` : ''
  269. }];`;
  270. });
  271. });
  272. const initSetting =
  273. 'node[style="filled";fontsize="10px"];edge[fontsize="6px";];';
  274. return `digraph {compound=true;rankdir=LR;${initSetting}${nodeStr}${edgeStr}}`;
  275. },
  276. /**
  277. * Encapsulates the data of a subgraph.
  278. * @param {String} key Key value of a node.
  279. * @return {String} dot string
  280. */
  281. packageSubGraph(key) {
  282. const node = this.allGraphData[key];
  283. let strTemp = '';
  284. if (node.operations && node.operations.length) {
  285. let nodeStr = '';
  286. node.operations.forEach((op, ind) => {
  287. const id = `${node.key}/${op.tensor_op_name}_${ind}`;
  288. op.key = id;
  289. nodeStr += `<${id}>[id="${id}";class=Operator;label="${op.tensor_op_name}";fillcolor="#c5e0b3"];`;
  290. if (!node.id) {
  291. node.id = id;
  292. }
  293. });
  294. strTemp +=
  295. `subgraph <cluster_${key}>{style="filled";id="${key}";` +
  296. `label="${node.op_type}";fillcolor="#9cc3e5";${nodeStr}};`;
  297. }
  298. return strTemp;
  299. },
  300. /**
  301. * Initializing the dataset graph
  302. * @param {String} dot dot statement encapsulated in graph data
  303. */
  304. initGraph(dot) {
  305. this.graphviz = d3
  306. .select('#graph')
  307. .graphviz({useWorker: false, totalMemory: this.totalMemory})
  308. .zoomScaleExtent(this.scaleRange)
  309. .dot(dot)
  310. .attributer(this.attributer)
  311. .render(this.afterInitGraph);
  312. },
  313. /**
  314. * Process other data after the dataset graph is initialized.
  315. */
  316. afterInitGraph() {
  317. setTimeout(() => {
  318. if (this.graphviz) {
  319. this.graphviz._data = null;
  320. this.graphviz._dictionary = null;
  321. this.graphviz = null;
  322. }
  323. }, 100);
  324. d3.select('#graph')
  325. .selectAll('title')
  326. .remove();
  327. this.startApp();
  328. },
  329. /**
  330. * Default method of the graph rendering adjustment. Set the node format.
  331. * @param {Object} datum Object of the current rendering element.
  332. * @param {Number} index Indicates the subscript of the current rendering element.
  333. * @param {Array} nodes An array encapsulated with the current rendering element.
  334. */
  335. attributer(datum, index, nodes) {
  336. if (datum.tag === 'svg') {
  337. const width = '100%';
  338. const height = '100%';
  339. datum.attributes.width = width;
  340. datum.attributes.height = height;
  341. }
  342. },
  343. /**
  344. * Initialization method executed after the graph rendering is complete
  345. */
  346. startApp() {
  347. this.initZooming();
  348. const nodes = d3.selectAll('g.node, g.cluster');
  349. nodes.on('click', (target, index, nodesList) => {
  350. this.selectNodeInfo(target);
  351. const selectedNode = nodesList[index];
  352. nodes.classed('selected', false);
  353. d3.select(`g[id="${selectedNode.id}"]`).classed('selected', true);
  354. });
  355. },
  356. /**
  357. * Initializing the Zoom Function of a Graph
  358. */
  359. initZooming() {
  360. const svgDom = document.querySelector('#graph svg');
  361. const svgRect = svgDom.getBoundingClientRect();
  362. const graphDom = document.querySelector('#graph #graph0');
  363. const graphBox = graphDom.getBBox();
  364. const graphRect = graphDom.getBoundingClientRect();
  365. let graphTransform = {};
  366. const minScale = Math.min(
  367. svgRect.width / 2 / graphRect.width,
  368. svgRect.height / 2 / graphRect.height,
  369. );
  370. const padding = 4;
  371. const minDistance = 50;
  372. const pointer = {start: {x: 0, y: 0}, end: {x: 0, y: 0}};
  373. const zoom = d3
  374. .zoom()
  375. .on('start', () => {
  376. pointer.start.x = event.x;
  377. pointer.start.y = event.y;
  378. })
  379. .on('zoom', () => {
  380. const transformData = this.getTransformData(graphDom);
  381. if (!Object.keys(graphTransform).length) {
  382. graphTransform = {
  383. x: transformData.translate[0],
  384. y: transformData.translate[1],
  385. k: transformData.scale[0],
  386. };
  387. }
  388. let tempStr = '';
  389. let change = {};
  390. let scale = transformData.scale[0];
  391. const graphRect = graphDom.getBoundingClientRect();
  392. const transRate = graphBox.width / graphRect.width;
  393. if (event.type === 'mousemove') {
  394. pointer.end.x = event.x;
  395. pointer.end.y = event.y;
  396. let tempX = pointer.end.x - pointer.start.x;
  397. let tempY = pointer.end.y - pointer.start.y;
  398. const paddingTrans = Math.max(
  399. (padding / transRate) * scale,
  400. minDistance,
  401. );
  402. if (
  403. graphRect.left + paddingTrans + tempX >=
  404. svgRect.left + svgRect.width
  405. ) {
  406. tempX = Math.min(tempX, 0);
  407. }
  408. if (
  409. graphRect.left + graphRect.width - paddingTrans + tempX <=
  410. svgRect.left
  411. ) {
  412. tempX = Math.max(tempX, 0);
  413. }
  414. if (
  415. graphRect.top + paddingTrans + tempY >=
  416. svgRect.top + svgRect.height
  417. ) {
  418. tempY = Math.min(tempY, 0);
  419. }
  420. if (
  421. graphRect.top + graphRect.height - paddingTrans + tempY <=
  422. svgRect.top
  423. ) {
  424. tempY = Math.max(tempY, 0);
  425. }
  426. change = {
  427. x: tempX * transRate * scale,
  428. y: tempY * transRate * scale,
  429. };
  430. pointer.start.x = pointer.end.x;
  431. pointer.start.y = pointer.end.y;
  432. } else if (event.type === 'wheel') {
  433. const wheelDelta = event.wheelDelta;
  434. const rate = Math.abs(wheelDelta / 100);
  435. scale =
  436. wheelDelta > 0
  437. ? transformData.scale[0] * rate
  438. : transformData.scale[0] / rate;
  439. scale = Math.max(this.scaleRange[0], scale, minScale);
  440. scale = Math.min(this.scaleRange[1], scale);
  441. change = {
  442. x:
  443. (graphRect.x + padding / transRate - event.x) *
  444. transRate *
  445. (scale - transformData.scale[0]),
  446. y:
  447. (graphRect.bottom - padding / transRate - event.y) *
  448. transRate *
  449. (scale - transformData.scale[0]),
  450. };
  451. }
  452. graphTransform = {
  453. x: transformData.translate[0] + change.x,
  454. y: transformData.translate[1] + change.y,
  455. k: scale,
  456. };
  457. tempStr = `translate(${graphTransform.x},${graphTransform.y}) scale(${graphTransform.k})`;
  458. graphDom.setAttribute('transform', tempStr);
  459. event.stopPropagation();
  460. event.preventDefault();
  461. });
  462. const svg = d3.select('#graph svg');
  463. svg.on('.zoom', null);
  464. svg.call(zoom);
  465. svg.on('dblclick.zoom', null);
  466. svg.on('wheel.zoom', null);
  467. const graph0 = d3.select('#graph #graph0');
  468. graph0.on('.zoom', null);
  469. graph0.call(zoom);
  470. },
  471. /**
  472. * Obtains the transform data of a node.
  473. * @param {Object} node Node dom data
  474. * @return {Object} transform data of a node
  475. */
  476. getTransformData(node) {
  477. if (!node) {
  478. return [];
  479. }
  480. const transformData = node.getAttribute('transform');
  481. const attrObj = {};
  482. if (transformData) {
  483. const lists = transformData.trim().split(' ');
  484. lists.forEach((item) => {
  485. const index1 = item.indexOf('(');
  486. const index2 = item.indexOf(')');
  487. const name = item.substring(0, index1);
  488. const params = item
  489. .substring(index1 + 1, index2)
  490. .split(',')
  491. .map((i) => {
  492. return parseFloat(i) || 0;
  493. });
  494. attrObj[name] = params;
  495. });
  496. }
  497. return attrObj;
  498. },
  499. /**
  500. * Process the selected node information.
  501. * @param {Object} target Selected Object
  502. */
  503. selectNodeInfo(target) {
  504. this.selectedNode = [];
  505. if (!target || !target.key) {
  506. return;
  507. }
  508. let id = '';
  509. let select = '';
  510. if (target.attributes.class.indexOf('Operator') !== -1) {
  511. id = target.attributes.id.slice(
  512. 0,
  513. target.attributes.id.lastIndexOf('/'),
  514. );
  515. let index = -1;
  516. if (target.attributes.id.match(/\d+$/)) {
  517. index = parseInt(target.attributes.id.match(/\d+$/)[0]);
  518. }
  519. if (this.allGraphData[id] && index > -1) {
  520. select = this.allGraphData[id].operations[index];
  521. }
  522. } else {
  523. id = target.attributes.id;
  524. select = this.allGraphData[id];
  525. }
  526. if (select) {
  527. const ignoreKeys = [
  528. 'op_module',
  529. 'op_type',
  530. 'children',
  531. 'operations',
  532. 'id',
  533. 'key',
  534. ];
  535. Object.keys(select).forEach((item) => {
  536. if (!ignoreKeys.includes(item)) {
  537. const value =
  538. select[item] instanceof Array
  539. ? select[item].join(', ')
  540. : select[item] === null
  541. ? 'None'
  542. : select[item];
  543. this.selectedNode.push({key: item, value: value});
  544. }
  545. });
  546. }
  547. },
  548. /**
  549. * Adapt to the screen
  550. */
  551. fit() {
  552. const graphDom = document.getElementById('graph0');
  553. const box = graphDom.getBBox();
  554. const str = `translate(${-box.x},${-box.y}) scale(1)`;
  555. graphDom.setAttribute('transform', str);
  556. },
  557. /**
  558. * Download svg
  559. */
  560. downLoadSVG() {
  561. const svgXml = document.querySelector('#graph #graph0').innerHTML;
  562. const bbox = document.getElementById('graph0').getBBox();
  563. const viewBoxSize = `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`;
  564. const encodeStr =
  565. `<svg xmlns="http://www.w3.org/2000/svg" ` +
  566. `xmlns:xlink="http://www.w3.org/1999/xlink" ` +
  567. `width="${bbox.width}" height="${bbox.height}" ` +
  568. `viewBox="${viewBoxSize}">${CommonProperty.dataMapDownloadStyle}<g>${svgXml}</g></svg>`;
  569. // Write the svg stream encoded by base64 to the image object.
  570. const src = `data:image/svg+xml;base64,
  571. ${window.btoa(unescape(encodeURIComponent(encodeStr)))}`;
  572. const a = document.createElement('a');
  573. a.href = src; // Export the information in the canvas as image data.
  574. a.download = 'dataMap'; // Set the download name.
  575. a.click(); // Click to trigger download.
  576. },
  577. /**
  578. * Collapse on the right
  579. */
  580. toggleRight() {
  581. this.rightShow = !this.rightShow;
  582. },
  583. /**
  584. * Fold the legend area.
  585. */
  586. foldLegend() {
  587. this.showLegend = !this.showLegend;
  588. },
  589. /**
  590. * jump back to train dashboard
  591. */
  592. jumpToTrainDashboard() {
  593. this.$router.push({
  594. path: '/train-manage/training-dashboard',
  595. query: {
  596. id: this.trainJobID,
  597. },
  598. });
  599. },
  600. },
  601. };
  602. </script>
  603. <style lang="scss">
  604. .cl-data-map-manage {
  605. height: 100%;
  606. .cl-data-map-title {
  607. height: 56px;
  608. line-height: 56px;
  609. }
  610. .data-map-p32 {
  611. height: 100%;
  612. }
  613. .cl-content {
  614. height: calc(100% - 50px);
  615. overflow: auto;
  616. }
  617. #data-maps {
  618. width: 100%;
  619. height: 100%;
  620. font-size: 0;
  621. background: #f0f2f5;
  622. .cl-data-map {
  623. position: relative;
  624. width: 100%;
  625. height: 100%;
  626. background-color: #fff;
  627. padding: 0 32px 24px;
  628. min-height: 700px;
  629. overflow: hidden;
  630. .data-map-container {
  631. height: 100%;
  632. width: calc(100% - 442px);
  633. position: relative;
  634. #graph {
  635. height: 100%;
  636. width: 100%;
  637. padding: 16px;
  638. background-color: #f7faff;
  639. #graph0 > polygon {
  640. fill: transparent;
  641. }
  642. .node,
  643. .cluster {
  644. cursor: pointer;
  645. }
  646. .selected {
  647. polygon,
  648. ellipse {
  649. stroke: red !important;
  650. stroke-width: 2px;
  651. }
  652. }
  653. .CreatDataset > polygon,
  654. .Operator > ellipse {
  655. stroke: #58a4e0;
  656. fill: #d1ebff;
  657. }
  658. .cluster > polygon {
  659. fill: #c1f5d5;
  660. stroke: #56b077;
  661. }
  662. .RepeatDataset > polygon {
  663. stroke: #fdca5a;
  664. fill: #fff2d4;
  665. }
  666. .ShuffleDataset > polygon {
  667. stroke: #f79666;
  668. fill: #fed78e;
  669. }
  670. .BatchDataset > polygon {
  671. stroke: #fa8e5a;
  672. fill: #ffcfb8;
  673. }
  674. .edge {
  675. path {
  676. stroke: rgb(167, 167, 167);
  677. }
  678. polygon {
  679. fill: rgb(167, 167, 167);
  680. stroke: rgb(167, 167, 167);
  681. }
  682. }
  683. }
  684. .full-screen-button {
  685. position: absolute;
  686. right: 10px;
  687. top: 10px;
  688. cursor: pointer;
  689. width: 12px;
  690. height: 12px;
  691. z-index: 999;
  692. display: inline-block;
  693. background-image: url('../../assets/images/full-screen.png');
  694. }
  695. .fit-screen {
  696. position: absolute;
  697. width: 16px;
  698. height: 14px;
  699. right: 32px;
  700. top: 10px;
  701. z-index: 999;
  702. cursor: pointer;
  703. display: inline-block;
  704. background-image: url('../../assets/images/fit.png');
  705. }
  706. .download-button {
  707. position: absolute;
  708. width: 16px;
  709. height: 14px;
  710. right: 54px;
  711. top: 10px;
  712. z-index: 999;
  713. cursor: pointer;
  714. display: inline-block;
  715. background-image: url('../../assets/images/download.png');
  716. background-size: 14px 14px;
  717. background-repeat: no-repeat;
  718. }
  719. }
  720. }
  721. .cl-data-map.full-screen {
  722. position: absolute;
  723. top: 0;
  724. bottom: 0;
  725. left: 0;
  726. right: 0;
  727. width: auto;
  728. height: auto;
  729. padding: 0;
  730. .data-map-container {
  731. width: 100%;
  732. }
  733. #sidebar {
  734. .node-info-con {
  735. height: calc(100% - 280px);
  736. }
  737. }
  738. }
  739. #sidebar.right-hide {
  740. right: -442px;
  741. }
  742. #sidebar {
  743. position: absolute;
  744. right: 0;
  745. top: 0;
  746. width: 442px;
  747. height: 100%;
  748. border-radius: 6px;
  749. text-align: left;
  750. background-color: #ffffff;
  751. display: inline-block;
  752. box-shadow: 0 1px 3px 0px rgba(0, 0, 0, 0.1);
  753. color: #333333;
  754. font-size: 14px;
  755. line-height: 14px;
  756. padding: 24px 32px;
  757. div,
  758. span,
  759. pre {
  760. font-size: 14px;
  761. }
  762. .title {
  763. padding: 24px 0;
  764. font-size: 14px;
  765. color: #333333;
  766. img {
  767. float: right;
  768. margin-right: 10px;
  769. cursor: pointer;
  770. }
  771. }
  772. .node-info-container {
  773. height: calc(100% - 156px);
  774. }
  775. .node-info-container-long {
  776. height: calc(100% - 62px);
  777. }
  778. .node-info {
  779. .title {
  780. padding: 0 0 24px;
  781. font-size: 14px;
  782. color: #333;
  783. }
  784. .node-info-list {
  785. height: calc(100% - 62px);
  786. overflow-y: auto;
  787. }
  788. .item {
  789. line-height: 20px;
  790. padding: 5px 0 5px 20px;
  791. background-color: #f2f2f2;
  792. .label {
  793. vertical-align: top;
  794. width: 30%;
  795. word-break: break-all;
  796. display: inline-block;
  797. }
  798. .value {
  799. padding: 0 10px;
  800. vertical-align: top;
  801. display: inline-block;
  802. width: 70%;
  803. word-break: break-all;
  804. }
  805. }
  806. }
  807. .legend {
  808. .legend-content {
  809. background-color: #f7faff;
  810. padding: 0 32px;
  811. height: 94px;
  812. overflow-y: auto;
  813. }
  814. .legend-item {
  815. padding: 5px 0;
  816. display: inline-block;
  817. width: 50%;
  818. font-size: 14px;
  819. line-height: 20px;
  820. .pic {
  821. width: 45px;
  822. text-align: center;
  823. img {
  824. width: 45px;
  825. height: 15px;
  826. margin-left: -20px;
  827. vertical-align: middle;
  828. }
  829. }
  830. div {
  831. display: inline-block;
  832. padding-left: 20px;
  833. vertical-align: middle;
  834. }
  835. }
  836. }
  837. .toggle-right {
  838. position: absolute;
  839. top: calc(50% - 43px);
  840. left: -16px;
  841. width: 18px;
  842. height: 86px;
  843. cursor: pointer;
  844. background-image: url('../../assets/images/toggle-right-bg.png');
  845. }
  846. .icon-toggle {
  847. width: 6px;
  848. height: 9px;
  849. background-image: url('../../assets/images/toggle-right-icon.png');
  850. position: absolute;
  851. top: calc(50% - 4.5px);
  852. left: calc(50% - 3px);
  853. }
  854. .icon-toggle.icon-left {
  855. transform: rotateY(180deg);
  856. }
  857. }
  858. .data-map-container.all {
  859. width: 100%;
  860. }
  861. // No data available.
  862. .image-noData {
  863. // Set the width and white on the right.
  864. width: 100%;
  865. height: 100%;
  866. background: #fff;
  867. position: absolute;
  868. top: 0;
  869. left: 0;
  870. display: flex;
  871. justify-content: center;
  872. align-items: center;
  873. flex-direction: column;
  874. z-index: 200;
  875. }
  876. .noData-text {
  877. margin-top: 33px;
  878. font-size: 18px;
  879. }
  880. }
  881. .cl-close-btn {
  882. width: 20px;
  883. height: 20px;
  884. vertical-align: -3px;
  885. cursor: pointer;
  886. display: inline-block;
  887. }
  888. .cl-title-right {
  889. padding-right: 32px;
  890. }
  891. }
  892. </style>