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.

histogram.vue 46 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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428
  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. <div class="cl-histogram-manage">
  15. <div class="histogram-bk">
  16. <!-- Title area -->
  17. <div class="cl-title cl-histogram-title">
  18. <div class="cl-title-left">{{$t('histogram.titleText')}}
  19. <div class="path-message">
  20. <span>{{$t('symbols.leftbracket')}}</span>
  21. <span>{{$t('trainingDashboard.summaryDirPath')}}</span>
  22. <span>{{summaryPath}}</span>
  23. <span>{{$t('symbols.rightbracket')}}</span>
  24. </div>
  25. </div>
  26. <div class="cl-title-right">
  27. <div class="cl-close-btn"
  28. @click="jumpToTrainDashboard">
  29. <img src="@/assets/images/close-page.png" />
  30. </div>
  31. </div>
  32. </div>
  33. <!-- List item operation area -->
  34. <div class="cl-histogram-operate-content">
  35. <multiselectGroupComponents ref="multiselectGroupComponents"
  36. :checkListArr="tagList"
  37. @selectedChange="tagSelectedChanged"></multiselectGroupComponents>
  38. </div>
  39. <!-- Area for selecting a view type -->
  40. <div class="cl-histogram-view-type-select-content">
  41. <div class="view-title">{{$t('histogram.viewType')}}</div>
  42. <el-radio-group v-model="curViewName"
  43. fill="#00A5A7"
  44. text-color="#FFFFFF"
  45. size="small"
  46. @change="viewTypeChange">
  47. <el-radio-button :label=0>{{$t('histogram.overlay')}}</el-radio-button>
  48. <el-radio-button :label=1>{{$t('histogram.offset')}}</el-radio-button>
  49. </el-radio-group>
  50. <div class="view-title"
  51. v-if="!!curViewName">{{$t('histogram.xAxisTitle')}}</div>
  52. <el-radio-group v-model="curAxisName"
  53. fill="#00A5A7"
  54. text-color="#FFFFFF"
  55. size="small"
  56. v-if="!!curViewName"
  57. :disabled="curViewName === 0"
  58. @change="timeTypeChange">
  59. <el-radio-button :label=0>{{$t('histogram.step')}}</el-radio-button>
  60. <el-radio-button :label=1>{{$t('histogram.relativeTime')}}</el-radio-button>
  61. <el-radio-button :label=2>{{$t('histogram.absoluteTime')}}</el-radio-button>
  62. </el-radio-group>
  63. </div>
  64. <!-- Content display area -->
  65. <div class="cl-histogram-show-data-content">
  66. <!-- No data -->
  67. <div class="image-noData"
  68. v-if="!originDataArr.length">
  69. <div>
  70. <img :src="require('@/assets/images/nodata.png')" />
  71. </div>
  72. <div v-if="initOver"
  73. class="noData-text">{{$t('public.noData')}}</div>
  74. <div v-else
  75. class="noData-text">{{$t("public.dataLoading")}}</div>
  76. </div>
  77. <!-- Data -->
  78. <div class="data-content"
  79. v-if="!!originDataArr.length">
  80. <div id="echartTip"
  81. v-show="chartTipFlag">
  82. <table class="char-tip-table borderspacing3">
  83. <tr>
  84. <td>{{$t('histogram.centerValue')}}</td>
  85. <td>{{$t('histogram.step')}}</td>
  86. <td>{{$t('histogram.relativeTime')}}</td>
  87. <td>{{$t('histogram.absoluteTime')}}</td>
  88. </tr>
  89. <tr id="tipTr"></tr>
  90. </table>
  91. </div>
  92. <div class="sample-content"
  93. v-for="sampleItem in originDataArr"
  94. :key="sampleItem.domId"
  95. :class="sampleItem.fullScreen?'char-full-screen':''"
  96. v-show="sampleItem.show">
  97. <div class="chars-container">
  98. <div class="char-item-content"
  99. :id="sampleItem.domId"></div>
  100. <div class="tag-title"
  101. :title="sampleItem.tagName">{{sampleItem.tagName}}</div>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <!-- Page number area -->
  107. <div class="pagination-content"
  108. v-if="originDataArr.length">
  109. <el-pagination @current-change="currentPageChange"
  110. :current-page="pageIndex + 1"
  111. :page-sizes="pageSizes"
  112. :page-size="pageNum"
  113. layout="total, prev, pager, next, jumper"
  114. :total="curFilterSamples.length">
  115. </el-pagination>
  116. </div>
  117. </div>
  118. </div>
  119. </template>
  120. <script>
  121. import multiselectGroupComponents from '../../components/multiselect-group.vue';
  122. import RequestService from '../../services/request-service';
  123. import CommonProperty from '../../common/common-property';
  124. import echarts from 'echarts';
  125. import {format, precisionRound} from 'd3';
  126. import autoUpdate from '../../mixins/auto-update.vue';
  127. const d3 = {format, precisionRound};
  128. export default {
  129. mixins: [autoUpdate],
  130. data() {
  131. return {
  132. tagList: [], // Tag list.
  133. trainingJobId: this.$route.query.train_id, // ID of the current training job.
  134. summaryPath: this.$route.query.summaryPath,
  135. originDataArr: [], // List of all data.
  136. initOver: false, // Indicates whether the initialization is complete.
  137. curAxisName: 0, // Current time type.
  138. curViewName: 1, // Current view type.
  139. curFullTagDic: {}, // Dictionary that contains all the current tags.
  140. multiSelectedTagNames: {}, // Dictionary for storing the name of the selected tags.
  141. curFilterSamples: [], // List of data that meet the current filter criteria.
  142. curPageArr: [], // Data list on the current page.
  143. pageIndex: 0, // Current page number.
  144. pageSizes: [6], // The number of records on each page is optional.
  145. pageNum: 6, // Number of records on each page.
  146. zrDrawElement: {hoverDots: []},
  147. chartTipFlag: false,
  148. charResizeTimer: null,
  149. changeAxisTimer: null,
  150. changeViewTimer: null,
  151. };
  152. },
  153. computed: {},
  154. components: {
  155. multiselectGroupComponents,
  156. },
  157. watch: {},
  158. destroyed() {
  159. window.removeEventListener('resize', this.resizeCallback);
  160. if (this.curPageArr.length) {
  161. this.curPageArr.forEach((item) => {
  162. this.clearZrData(item);
  163. });
  164. }
  165. if (this.changeAxisTimer) {
  166. clearTimeout(this.changeAxisTimer);
  167. this.changeAxisTimer = null;
  168. }
  169. if (this.changeViewTimer) {
  170. clearTimeout(this.changeViewTimer);
  171. this.changeViewTimer = null;
  172. }
  173. },
  174. mounted() {
  175. this.init();
  176. window.addEventListener('resize', this.resizeCallback, false);
  177. },
  178. methods: {
  179. resizeCallback() {
  180. if (this.charResizeTimer) {
  181. clearTimeout(this.charResizeTimer);
  182. this.charResizeTimer = null;
  183. }
  184. this.charResizeTimer = setTimeout(() => {
  185. this.curPageArr.forEach((sampleItem) => {
  186. if (sampleItem.charObj) {
  187. sampleItem.charObj.resize();
  188. }
  189. });
  190. }, 500);
  191. },
  192. /**
  193. * Initialize
  194. */
  195. init() {
  196. if (!this.$route.query || !this.$route.query.train_id) {
  197. this.$message.error(this.$t('trainingDashboard.invalidId'));
  198. document.title = this.$t('histogram.titleText') + '-MindInsight';
  199. return;
  200. }
  201. document.title =
  202. decodeURIComponent(this.$route.query.train_id) +
  203. '-' +
  204. this.$t('histogram.titleText') +
  205. '-MindInsight';
  206. this.getOriginData();
  207. if (this.isTimeReload) {
  208. this.autoUpdateSamples();
  209. }
  210. },
  211. /**
  212. * Jump back to train dashboard
  213. */
  214. jumpToTrainDashboard() {
  215. this.$router.push({
  216. path: '/train-manage/training-dashboard',
  217. query: {
  218. id: this.trainingJobId,
  219. },
  220. });
  221. },
  222. /**
  223. * Obtains original data.
  224. */
  225. getOriginData() {
  226. const params = {
  227. plugin_name: 'histogram',
  228. train_id: this.trainingJobId,
  229. };
  230. RequestService.getSingleTrainJob(params)
  231. .then((res) => {
  232. if (
  233. !res ||
  234. !res.data ||
  235. !res.data.train_jobs ||
  236. !res.data.train_jobs.length
  237. ) {
  238. this.initOver = true;
  239. return;
  240. }
  241. const data = res.data.train_jobs[0];
  242. if (!data.tags) {
  243. return;
  244. }
  245. const tagList = [];
  246. const dataList = [];
  247. data.tags.forEach((tagName) => {
  248. if (!this.curFullTagDic[tagName]) {
  249. this.curFullTagDic[tagName] = true;
  250. tagList.push({
  251. label: tagName,
  252. checked: true,
  253. show: true,
  254. });
  255. dataList.push({
  256. tagName: tagName,
  257. zr: null,
  258. show: false,
  259. fullScreen: false,
  260. domId: `${tagName}`,
  261. oriData: {},
  262. charOption: {},
  263. chartData: [],
  264. charObj: null,
  265. });
  266. }
  267. });
  268. this.tagList = tagList;
  269. this.originDataArr = dataList;
  270. this.$nextTick(() => {
  271. this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic();
  272. this.initOver = true;
  273. this.updateTagInPage();
  274. });
  275. }, this.requestErrorCallback)
  276. .catch((e) => {
  277. this.initOver = true;
  278. this.$message.error(this.$t('public.dataError'));
  279. });
  280. },
  281. /**
  282. * The selected label is changed.
  283. * @param {Object} selectedItemDict Dictionary containing the selected tags
  284. */
  285. tagSelectedChanged(selectedItemDict) {
  286. if (!selectedItemDict) {
  287. return;
  288. }
  289. this.multiSelectedTagNames = selectedItemDict;
  290. // Reset to the first page
  291. this.pageIndex = 0;
  292. this.updateTagInPage();
  293. },
  294. /**
  295. * Page number change event
  296. * @param {Number} pageIndex Changed page number
  297. */
  298. currentPageChange(pageIndex) {
  299. this.pageIndex = pageIndex - 1;
  300. // Load the data on the current page
  301. this.getCurPageDataArr();
  302. },
  303. /**
  304. * Obtains data on the current page
  305. * @param {Boolean} noPageDataNumChange No new data is added or deleted
  306. */
  307. getCurPageDataArr(noPageDataNumChange) {
  308. // Clear the previous page
  309. if (!noPageDataNumChange) {
  310. this.curPageArr.forEach((sampleItem) => {
  311. sampleItem.show = false;
  312. this.clearZrData(sampleItem);
  313. });
  314. }
  315. // This interface is used to obtain the current page group and hide the current page group.
  316. const startIndex = this.pageIndex * this.pageNum;
  317. const endIndex = startIndex + this.pageNum;
  318. const curPageArr = [];
  319. for (let i = startIndex; i < endIndex; i++) {
  320. const sampleItem = this.curFilterSamples[i];
  321. if (sampleItem) {
  322. sampleItem.show = true;
  323. curPageArr.push(sampleItem);
  324. }
  325. }
  326. this.curPageArr = curPageArr;
  327. // Update the data information on the current page
  328. this.freshCurPageData();
  329. },
  330. freshCurPageData() {
  331. this.curPageArr.forEach((item, index) => {
  332. if (!item || !item.tagName) {
  333. return;
  334. }
  335. const params = {
  336. train_id: this.trainingJobId,
  337. tag: item.tagName,
  338. };
  339. RequestService.getHistogramData(params).then((res) => {
  340. if (!res || !res.data) {
  341. return;
  342. }
  343. const data = JSON.parse(JSON.stringify(res.data));
  344. item.chartData = this.formOriData(data);
  345. this.formatDataToChar(item);
  346. this.updateSampleData(item);
  347. this.sampleEventBind(item);
  348. });
  349. });
  350. },
  351. /**
  352. * The time display type is changed
  353. * @param {Number} val Current mode
  354. */
  355. timeTypeChange(val) {
  356. if (this.changeAxisTimer) {
  357. clearTimeout(this.changeAxisTimer);
  358. this.changeAxisTimer = null;
  359. }
  360. this.changeAxisTimer = setTimeout(() => {
  361. this.curPageArr.forEach((item) => {
  362. this.updateSampleData(item);
  363. });
  364. }, 500);
  365. },
  366. /**
  367. * The view display type is changed
  368. * @param {Number} val Current mode
  369. */
  370. viewTypeChange(val) {
  371. if (this.changeViewTimer) {
  372. clearTimeout(this.changeViewTimer);
  373. this.changeViewTimer = null;
  374. }
  375. this.changeViewTimer = setTimeout(() => {
  376. this.curPageArr.forEach((item) => {
  377. this.formatDataToChar(item);
  378. this.updateSampleData(item);
  379. });
  380. }, 200);
  381. },
  382. /**
  383. * Update the data list based on the filtered tags
  384. * @param {Boolean} noPageDataNumChange No new data is added or deleted
  385. */
  386. updateTagInPage(noPageDataNumChange) {
  387. const curFilterSamples = [];
  388. // Obtains data subscript that meets the tag filtering conditions
  389. this.originDataArr.forEach((sampleItem) => {
  390. if (this.multiSelectedTagNames[sampleItem.tagName]) {
  391. curFilterSamples.push(sampleItem);
  392. }
  393. });
  394. this.curFilterSamples = curFilterSamples;
  395. // Obtains data on the current page
  396. this.getCurPageDataArr(noPageDataNumChange);
  397. },
  398. /**
  399. * Clear data
  400. */
  401. clearAllData() {
  402. this.originDataArr.forEach((item) => {
  403. this.clearZrData(item);
  404. });
  405. this.tagList = [];
  406. this.originDataArr = [];
  407. this.curFullTagDic = {};
  408. this.multiSelectedTagNames = {};
  409. this.curFilterSamples = [];
  410. this.pageIndex = 0;
  411. this.curPageArr = [];
  412. this.$nextTick(() => {
  413. this.$refs.multiselectGroupComponents.updateSelectedDic();
  414. });
  415. },
  416. /**
  417. * Error callback
  418. * @param {Object} error error object
  419. */
  420. requestErrorCallback(error) {
  421. if (!this.initOver) {
  422. this.initOver = true;
  423. }
  424. if (this.isReloading) {
  425. this.$store.commit('setIsReload', false);
  426. this.isReloading = false;
  427. }
  428. if (error.response && error.response.data) {
  429. this.clearAllData();
  430. } else {
  431. if (
  432. !(error.code === 'ECONNABORTED' && /^timeout/.test(error.message))
  433. ) {
  434. // Clear data
  435. this.clearAllData();
  436. }
  437. }
  438. },
  439. /**
  440. * Update all data.
  441. * @param {Boolean} ignoreError whether ignore error tip.
  442. */
  443. updateAllData(ignoreError) {
  444. const params = {
  445. plugin_name: 'histogram',
  446. train_id: this.trainingJobId,
  447. };
  448. RequestService.getSingleTrainJob(params, ignoreError)
  449. .then((res) => {
  450. if (this.isReloading) {
  451. this.$store.commit('setIsReload', false);
  452. this.isReloading = false;
  453. }
  454. // Fault tolerance processing
  455. if (
  456. !res ||
  457. !res.data ||
  458. !res.data.train_jobs ||
  459. !res.data.train_jobs.length ||
  460. !res.data.train_jobs[0].tags
  461. ) {
  462. this.clearAllData();
  463. return;
  464. }
  465. const data = res.data.train_jobs[0];
  466. // Remove data that does not exist.
  467. const dataRemoveFlag = this.removeNoneExistentData(data);
  468. // Add new data.
  469. const dataAddFlag = this.checkNewDataAndComplete(data);
  470. this.$nextTick(() => {
  471. this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic();
  472. this.updateTagInPage(!dataAddFlag && !dataRemoveFlag);
  473. });
  474. }, this.requestErrorCallback)
  475. .catch((e) => {
  476. this.$message.error(this.$t('public.dataError'));
  477. });
  478. },
  479. /**
  480. * Delete the data that does not exist
  481. * @param {Object} oriData Raw data with tags
  482. * @return {Boolean} Indicates whether data is removed.
  483. */
  484. removeNoneExistentData(oriData) {
  485. if (!oriData || !oriData.tags) {
  486. return false;
  487. }
  488. const newTagDictionaries = {};
  489. let dataRemoveFlag = false;
  490. // Obtains the current tag list
  491. oriData.tags.forEach((tagName) => {
  492. newTagDictionaries[tagName] = true;
  493. });
  494. // Delete data that do not exist in the operation bar
  495. const oldTagListLength = this.tagList.length;
  496. for (let i = oldTagListLength - 1; i >= 0; i--) {
  497. if (!newTagDictionaries[this.tagList[i].label]) {
  498. dataRemoveFlag = true;
  499. delete this.curFullTagDic[this.tagList[i].label];
  500. this.tagList.splice(i, 1);
  501. }
  502. }
  503. // Delete the data corresponding to the tag that does not exist.
  504. const oldSampleLength = this.originDataArr.length;
  505. for (let i = oldSampleLength - 1; i >= 0; i--) {
  506. if (!newTagDictionaries[this.originDataArr[i].tagName]) {
  507. dataRemoveFlag = true;
  508. this.clearZrData(this.originDataArr[i]);
  509. this.originDataArr[i].charObj.clear();
  510. this.originDataArr.splice(i, 1);
  511. }
  512. }
  513. this.originDataArr.forEach((item, index) => {
  514. item.sampleIndex = index;
  515. });
  516. return dataRemoveFlag;
  517. },
  518. /**
  519. * Check and add new data
  520. * @param {Object} oriData Raw data with tags
  521. * @return {Boolean} Check whether new data is added
  522. */
  523. checkNewDataAndComplete(oriData) {
  524. if (!oriData || !oriData.tags) {
  525. return false;
  526. }
  527. let dataAddFlag = false;
  528. oriData.tags.forEach((tagName) => {
  529. if (!this.curFullTagDic[tagName]) {
  530. this.tagList.push({
  531. label: tagName,
  532. checked: true,
  533. show: false,
  534. });
  535. this.originDataArr.push({
  536. tagName: tagName,
  537. zr: null,
  538. show: false,
  539. fullScreen: false,
  540. domId: `${tagName}`,
  541. oriData: {},
  542. charOption: {},
  543. chartData: [],
  544. charObj: null,
  545. });
  546. this.curFullTagDic[tagName] = true;
  547. dataAddFlag = true;
  548. }
  549. });
  550. return dataAddFlag;
  551. },
  552. /**
  553. * Update sample data
  554. * @param {Object} sampleObject sampleObject
  555. */
  556. updateSampleData(sampleObject) {
  557. sampleObject.charOption = this.formatCharOption(sampleObject);
  558. if (!sampleObject.charObj) {
  559. sampleObject.charObj = echarts.init(
  560. document.getElementById(sampleObject.domId),
  561. null,
  562. );
  563. }
  564. this.removeTooltip(sampleObject);
  565. sampleObject.charObj.setOption(sampleObject.charOption, true);
  566. },
  567. sampleEventBind(sampleObject) {
  568. if (!sampleObject.zr) {
  569. sampleObject.zr = sampleObject.charObj.getZr();
  570. sampleObject.zr.off('mouseout', 'mousemove');
  571. sampleObject.zr.on('mouseout', (e) => {
  572. this.removeTooltip(sampleObject);
  573. this.chartTipFlag = false;
  574. });
  575. sampleObject.zr.on('mousemove', (e) => {
  576. this.removeTooltip(sampleObject);
  577. this.mousemoveEvent(sampleObject, e);
  578. });
  579. }
  580. },
  581. mousemoveEvent(sampleObject, e) {
  582. const unit = 's';
  583. const nearestIndex = this.findNearestValue(sampleObject, [
  584. e.offsetX,
  585. e.offsetY,
  586. ]);
  587. if (
  588. nearestIndex &&
  589. nearestIndex.yIndex !== null &&
  590. nearestIndex.binIndex !== null
  591. ) {
  592. const {binIndex, yIndex} = nearestIndex;
  593. const chartData = sampleObject.chartData;
  594. const hoveredItem = chartData[yIndex];
  595. const p = Math.max(0, d3.precisionRound(0.01, 1.01) - 1);
  596. const yValueFormat = d3.format(`.${p}e`);
  597. const gridRect = sampleObject.charObj
  598. .getModel()
  599. .getComponent('grid', 0)
  600. .coordinateSystem.getRect();
  601. const gridRectY = gridRect.y - 10;
  602. let linePoints = [];
  603. if (!hoveredItem || !hoveredItem.items[binIndex]) {
  604. return;
  605. }
  606. if (!this.chartTipFlag) {
  607. this.chartTipFlag = true;
  608. }
  609. if (this.curViewName === 1 && yIndex !== null) {
  610. linePoints = this.makePolyPoints(
  611. yIndex,
  612. this.getCoord,
  613. gridRectY,
  614. sampleObject,
  615. );
  616. } else if (this.curViewName === 0 && hoveredItem.items) {
  617. hoveredItem.items.forEach((item) => {
  618. linePoints.push(this.getCoord([item[2], item[3]], sampleObject));
  619. });
  620. }
  621. this.zrDrawElement.hoverLine = new echarts.graphic.Polyline({
  622. silent: true,
  623. shape: {
  624. points: linePoints.slice(1, -1),
  625. },
  626. z: 999,
  627. });
  628. sampleObject.zr.add(this.zrDrawElement.hoverLine);
  629. this.zrDrawElement.tooltip = new echarts.graphic.Text({});
  630. let itemX;
  631. const x = hoveredItem.items[binIndex][2];
  632. let z = 0;
  633. chartData.forEach((dataItem, index) => {
  634. const y = dataItem.step;
  635. const pt = this.getCoord([x, y], sampleObject);
  636. if (index === yIndex) {
  637. z = hoveredItem.items[binIndex][3];
  638. } else {
  639. const items = dataItem.items;
  640. for (let k = 1; k < items.length - 1; k++) {
  641. const nextX = items[k + 1][2];
  642. const nextZ = items[k + 1][3];
  643. if (items[k][2] === x) {
  644. z = items[k][3];
  645. break;
  646. } else if (items[k][2] < x && nextX > x) {
  647. const proportionX = (x - items[k][2]) / (nextX - items[k][2]);
  648. z = (nextZ - items[k][3]) * proportionX + items[k][3];
  649. break;
  650. }
  651. }
  652. }
  653. itemX = pt[0];
  654. const circleOption = {
  655. z: 1000,
  656. };
  657. if (this.curViewName === 1) {
  658. pt[1] -=
  659. ((z - sampleObject.oriData.minZ) /
  660. (sampleObject.oriData.maxZ - sampleObject.oriData.minZ)) *
  661. gridRectY;
  662. circleOption.shape = {
  663. cx: itemX,
  664. cy: pt[1],
  665. r: 1.5,
  666. };
  667. } else {
  668. circleOption.shape = {
  669. cx: 0,
  670. cy: 0,
  671. r: 1.5,
  672. };
  673. circleOption.position = sampleObject.charObj.convertToPixel(
  674. 'grid',
  675. [x, z],
  676. );
  677. }
  678. const dot = new echarts.graphic.Circle(circleOption);
  679. sampleObject.zr.add(dot);
  680. this.zrDrawElement.hoverDots.push(dot);
  681. });
  682. this.zrDrawElement.tooltip = new echarts.graphic.Text({});
  683. let htmlStr = '';
  684. const hoveredAxis = hoveredItem.items[binIndex][3];
  685. htmlStr = `<td>${
  686. hoveredAxis.toString().length >= 6
  687. ? yValueFormat(hoveredAxis)
  688. : hoveredAxis
  689. }</td><td style="text-align:center;">${this.formateNUmber(
  690. hoveredItem.step,
  691. )}</td><td>${this.formateNUmber(
  692. hoveredItem.relative_time.toFixed(0),
  693. )}${unit}</td><td>${this.dealrelativeTime(
  694. new Date(hoveredItem.wall_time * 1000).toString(),
  695. )}</td>`;
  696. const dom = document.querySelector('#tipTr');
  697. dom.innerHTML = htmlStr;
  698. if (!sampleObject.fullScreen) {
  699. const chartWidth = document.getElementById(sampleObject.domId)
  700. .parentNode.parentNode.clientWidth;
  701. const chartHeight = document.getElementById(sampleObject.domId)
  702. .parentNode.parentNode.clientHeight;
  703. const left = document.getElementById(sampleObject.domId).parentNode
  704. .parentNode.offsetLeft;
  705. const top = document.getElementById(sampleObject.domId).parentNode
  706. .parentNode.offsetTop;
  707. const echartTip = document.querySelector('#echartTip');
  708. echartTip.style.top = `${top + chartHeight - 60}px`;
  709. if (left > echartTip.clientWidth) {
  710. echartTip.style.left = `${left - echartTip.clientWidth}px`;
  711. } else {
  712. echartTip.style.left = `${left + chartWidth}px`;
  713. }
  714. } else {
  715. const width = document.querySelector('#echartTip').clientWidth;
  716. const height = document.querySelector('#echartTip').clientHeight;
  717. const screenWidth = document.body.scrollWidth;
  718. const screenHeight = document.body.scrollHeight;
  719. const scrollTop = document.querySelector(
  720. '.cl-histogram-show-data-content',
  721. ).scrollTop;
  722. const offsetTop = document.querySelector(
  723. '.cl-histogram-show-data-content',
  724. ).offsetTop;
  725. if (height + e.event.y + 20 > screenHeight && screenHeight > height) {
  726. document.querySelector('#echartTip').style.top = `${
  727. e.event.y + scrollTop - height - 20 - offsetTop
  728. }px`;
  729. } else {
  730. document.querySelector('#echartTip').style.top = `${
  731. e.event.y + scrollTop + 20 - offsetTop
  732. }px`;
  733. }
  734. // Blank area on the right of the chart is 80
  735. if (width + e.event.x + 80 > screenWidth && screenWidth > width) {
  736. document.querySelector('#echartTip').style.left = `${
  737. e.event.x - width - 20
  738. }px`;
  739. } else {
  740. document.querySelector('#echartTip').style.left = `${
  741. e.event.x + 20
  742. }px`;
  743. }
  744. }
  745. this.zrDrawElement.tooltipX = new echarts.graphic.Text({
  746. position: [itemX, gridRect.y + gridRect.height],
  747. style: {
  748. text:
  749. x.toString().length >= 6
  750. ? x.toExponential(3)
  751. : Math.round(x * 1000) / 1000,
  752. textFill: '#fff',
  753. textAlign: 'center',
  754. fontSize: 12,
  755. textBackgroundColor: '#333',
  756. textBorderWidth: 2,
  757. textPadding: [5, 7],
  758. rich: {},
  759. },
  760. z: 2000,
  761. });
  762. sampleObject.zr.add(this.zrDrawElement.tooltipX);
  763. if (this.curViewName === 1 && linePoints && linePoints.length) {
  764. let text = '';
  765. if (yIndex !== null) {
  766. text = this.yAxisFormatter(sampleObject, hoveredItem.step);
  767. }
  768. this.zrDrawElement.tooltipY = new echarts.graphic.Text({
  769. position: [
  770. gridRect.x + gridRect.width,
  771. linePoints[linePoints.length - 1][1],
  772. ],
  773. style: {
  774. text: text,
  775. textFill: '#fff',
  776. textVerticalAlign: 'middle',
  777. fontSize: 12,
  778. textBackgroundColor: '#333',
  779. textBorderWidth: 2,
  780. textPadding: [5, 7],
  781. rich: {},
  782. },
  783. z: 2000,
  784. });
  785. sampleObject.zr.add(this.zrDrawElement.tooltipY);
  786. }
  787. }
  788. },
  789. /**
  790. * Get convert point
  791. * @param {Array} pt Value
  792. * @param {Object} sampleObject SampleObject
  793. * @return {Array}
  794. */
  795. getCoord(pt, sampleObject) {
  796. return sampleObject.charObj.convertToPixel('grid', pt);
  797. },
  798. /**
  799. * Find nearest value
  800. * @param {Object} sampleObject SampleObject
  801. * @param {Array} eventPoint Value
  802. * @return {Object}
  803. */
  804. findNearestValue(sampleObject, eventPoint) {
  805. if (
  806. !eventPoint ||
  807. !eventPoint.length ||
  808. !sampleObject ||
  809. !sampleObject.charObj ||
  810. !sampleObject.oriData
  811. ) {
  812. return;
  813. }
  814. const value = sampleObject.charObj.convertFromPixel('grid', eventPoint);
  815. if (!value || !value.length) {
  816. return;
  817. }
  818. let binIndex = null;
  819. let yIndex = null;
  820. let nearestX = Infinity;
  821. let nearestY = -Infinity;
  822. let nearestYData = Infinity;
  823. const gridRect = sampleObject.charObj
  824. .getModel()
  825. .getComponent('grid', 0)
  826. .coordinateSystem.getRect();
  827. const gridRectY = gridRect.y - 10;
  828. const x = value[0];
  829. sampleObject.chartData.forEach((dataItem, i) => {
  830. let distY;
  831. let yAxis;
  832. for (let k = 0; k < dataItem.items.length - 1; k++) {
  833. const item = dataItem.items[k];
  834. const itemNext = dataItem.items[k + 1];
  835. const nextX = itemNext[2];
  836. const nextZ = itemNext[3];
  837. if (item.length >= 4) {
  838. if (item[2] < x && nextX >= x) {
  839. const proportionX = (x - item[2]) / (nextX - item[2]);
  840. yAxis = (nextZ - item[3]) * proportionX + item[3];
  841. distY = Math.abs(value[1] - yAxis);
  842. break;
  843. }
  844. }
  845. }
  846. if (this.curViewName === 0 && distY < nearestYData) {
  847. nearestYData = distY;
  848. yIndex = i;
  849. } else if (this.curViewName === 1) {
  850. const pt = this.getCoord([x, dataItem.step], sampleObject);
  851. const ptStep = pt[1];
  852. pt[1] -=
  853. ((yAxis - sampleObject.oriData.minZ) /
  854. (sampleObject.oriData.maxZ - sampleObject.oriData.minZ)) *
  855. gridRectY;
  856. if (
  857. eventPoint[1] > pt[1] &&
  858. eventPoint[1] < ptStep &&
  859. ptStep > nearestY
  860. ) {
  861. nearestY = ptStep;
  862. yIndex = i;
  863. }
  864. }
  865. });
  866. if (yIndex === null && this.curViewName === 1) {
  867. sampleObject.chartData.forEach((item, index) => {
  868. if (index >= value[1]) {
  869. yIndex = yIndex === null ? index : Math.min(yIndex, index);
  870. }
  871. });
  872. }
  873. if (yIndex !== null) {
  874. const yData = sampleObject.chartData[yIndex].items;
  875. yData.forEach((ele, index) => {
  876. const distX = Math.abs(ele[2] - value[0]);
  877. if (distX < nearestX) {
  878. nearestX = distX;
  879. binIndex = index;
  880. }
  881. });
  882. binIndex =
  883. binIndex === 0
  884. ? 1
  885. : binIndex === yData.length - 1
  886. ? yData.length - 2
  887. : binIndex;
  888. }
  889. return {
  890. binIndex,
  891. yIndex,
  892. };
  893. },
  894. dealrelativeTime(time) {
  895. const arr = time.split(' ');
  896. const str = arr[0] + ' ' + arr[1] + ' ' + arr[2] + ',' + ' ' + arr[4];
  897. return str;
  898. },
  899. clearZrData(sampleObject) {
  900. if (sampleObject && sampleObject.zr) {
  901. this.removeTooltip(sampleObject);
  902. sampleObject.zr.off('mouseout', 'mousemove');
  903. sampleObject.zr = null;
  904. }
  905. },
  906. /**
  907. * Remove tooltip
  908. * @param {Number} sampleObject SampleObject
  909. */
  910. removeTooltip(sampleObject) {
  911. if (sampleObject && sampleObject.zr) {
  912. if (this.zrDrawElement.hoverDots) {
  913. this.zrDrawElement.hoverDots.forEach((dot) =>
  914. sampleObject.zr.remove(dot),
  915. );
  916. }
  917. if (this.zrDrawElement.hoverLine) {
  918. sampleObject.zr.remove(this.zrDrawElement.hoverLine);
  919. }
  920. if (this.zrDrawElement.tooltip) {
  921. sampleObject.zr.remove(this.zrDrawElement.tooltip);
  922. }
  923. if (this.zrDrawElement.tooltipY) {
  924. sampleObject.zr.remove(this.zrDrawElement.tooltipY);
  925. }
  926. if (this.zrDrawElement.tooltipX) {
  927. sampleObject.zr.remove(this.zrDrawElement.tooltipX);
  928. }
  929. }
  930. },
  931. getValue(seriesData, dataIndex, i) {
  932. return seriesData[dataIndex][i];
  933. },
  934. makePolyPoints(dataIndex, getCoord, yValueMapHeight, sampleObject) {
  935. const points = [];
  936. const rawData = sampleObject.oriData.seriesData;
  937. const maxZ = sampleObject.oriData.maxZ;
  938. const minZ = sampleObject.oriData.minZ;
  939. for (let i = 0; i < rawData[dataIndex].length; ) {
  940. const x = this.getValue(rawData, dataIndex, i++);
  941. const y = this.getValue(rawData, dataIndex, i++);
  942. const z = this.getValue(rawData, dataIndex, i++);
  943. const pt = getCoord([x, y], sampleObject);
  944. // Linear map in z axis
  945. if (maxZ !== minZ) {
  946. pt[1] -= ((z - minZ) / (maxZ - minZ)) * yValueMapHeight;
  947. }
  948. points.push(pt);
  949. }
  950. return points;
  951. },
  952. formOriData(dataItem) {
  953. const chartData = [];
  954. const wallTimeInit = dataItem.histograms.length
  955. ? dataItem.histograms[0].wall_time
  956. : 0;
  957. dataItem.histograms.forEach((histogram, index) => {
  958. const step = histogram.step.toString();
  959. const chartItem = {
  960. wall_time: histogram.wall_time,
  961. relative_time: histogram.wall_time - wallTimeInit,
  962. step: step,
  963. items: [],
  964. };
  965. const chartArr = [];
  966. histogram.buckets.forEach((bucket) => {
  967. const xData = bucket[0] + bucket[1] / 2;
  968. const filter = chartArr.filter((k) => k[0] === xData);
  969. if (!filter.length) {
  970. chartArr.push([
  971. histogram.wall_time,
  972. step,
  973. xData,
  974. Math.floor(bucket[2]),
  975. ]);
  976. }
  977. });
  978. chartArr.sort((a, b) => a[0] - b[0]);
  979. if (chartArr.length) {
  980. const minItem = chartArr[0][2];
  981. const maxItem = chartArr[chartArr.length - 1][2];
  982. const chartAll = [
  983. [histogram.wall_time, step, minItem, 0],
  984. ].concat(chartArr, [[histogram.wall_time, step, maxItem, 0]]);
  985. chartItem.items = chartAll;
  986. chartData.push(chartItem);
  987. }
  988. });
  989. return chartData;
  990. },
  991. formatDataToChar(item) {
  992. const chartData = item.chartData;
  993. const seriesData = [];
  994. let maxX = -Infinity;
  995. let minX = Infinity;
  996. let maxZ = -Infinity;
  997. let minZ = Infinity;
  998. const gridData = [];
  999. if (chartData && chartData.length) {
  1000. chartData.forEach((histogram) => {
  1001. const seriesItem = [];
  1002. gridData.push(histogram.step);
  1003. histogram.items.forEach((bucket) => {
  1004. if (this.curViewName === 0) {
  1005. seriesItem.push([bucket[2], bucket[3]]);
  1006. } else if (this.curViewName === 1) {
  1007. seriesItem.push(bucket[2], histogram.step, bucket[3]);
  1008. }
  1009. maxX = Math.max(maxX, bucket[2]);
  1010. minX = Math.min(minX, bucket[2]);
  1011. minZ = Math.min(minZ, bucket[3]);
  1012. maxZ = Math.max(maxZ, bucket[3]);
  1013. });
  1014. seriesData.push(seriesItem);
  1015. });
  1016. }
  1017. item.oriData = {
  1018. seriesData,
  1019. maxX,
  1020. minX,
  1021. maxZ,
  1022. minZ,
  1023. gridData,
  1024. };
  1025. },
  1026. formatCharOption(sampleObject) {
  1027. const colorMin = '#346E69';
  1028. const colorMax = '#EBFFFD';
  1029. const oriData = sampleObject.oriData;
  1030. const colorArr = this.getGrientColor(
  1031. colorMin,
  1032. colorMax,
  1033. oriData.seriesData.length,
  1034. );
  1035. const fullScreenFun = this.toggleFullScreen;
  1036. const curAxisName = this.curAxisName;
  1037. const that = this;
  1038. const option = {
  1039. grid: {
  1040. left: 40,
  1041. top: 60,
  1042. right: 80,
  1043. bottom: 60,
  1044. },
  1045. xAxis: {
  1046. max: oriData.maxX,
  1047. min: oriData.minX,
  1048. axisLine: {onZero: false},
  1049. axisLabel: {
  1050. fontSize: '11',
  1051. formatter: function(value) {
  1052. return that.formateNUmber(value);
  1053. },
  1054. },
  1055. splitLine: {show: false},
  1056. },
  1057. yAxis: {
  1058. position: 'right',
  1059. axisLine: {onZero: false, show: false},
  1060. splitLine: {show: true},
  1061. axisTick: {show: false},
  1062. boundaryGap: false,
  1063. axisLabel: {
  1064. fontSize: '11',
  1065. formatter: function(value) {
  1066. return that.formateNUmber(value);
  1067. },
  1068. },
  1069. },
  1070. toolbox: {
  1071. top: 20,
  1072. right: 20,
  1073. emphasis: {
  1074. iconStyle: {
  1075. textPosition: 'top',
  1076. borderColor: '#00A5A7',
  1077. },
  1078. },
  1079. // toolbox
  1080. feature: {
  1081. // fullScreen
  1082. myToolFullScreen: {
  1083. show: true,
  1084. title: this.$t('histogram.fullScreen'),
  1085. iconStyle: {
  1086. borderColor: sampleObject.fullScreen ? '#00A5A7' : '#6D7278',
  1087. },
  1088. icon: CommonProperty.fullScreenIcon,
  1089. onclick() {
  1090. fullScreenFun(sampleObject);
  1091. },
  1092. },
  1093. },
  1094. },
  1095. };
  1096. if (this.curViewName === 1) {
  1097. const seriesData = [];
  1098. oriData.seriesData.forEach((item, dataIndex) => {
  1099. const dataItem = {
  1100. name: item[1],
  1101. value: item,
  1102. itemStyle: {
  1103. color: colorArr[dataIndex],
  1104. },
  1105. };
  1106. seriesData.push(dataItem);
  1107. });
  1108. option.series = [
  1109. {
  1110. type: 'custom',
  1111. dimensions: ['x', 'y'],
  1112. renderItem: (params, api) => {
  1113. const points = this.makePolyPoints(
  1114. params.dataIndex,
  1115. api.coord,
  1116. params.coordSys.y - 10,
  1117. sampleObject,
  1118. );
  1119. return {
  1120. type: 'polyline',
  1121. z2: params.dataIndex,
  1122. silent: true,
  1123. shape: {
  1124. points,
  1125. },
  1126. style: api.style({
  1127. stroke: '#bbb',
  1128. lineWidth: 1,
  1129. }),
  1130. };
  1131. },
  1132. data: seriesData,
  1133. },
  1134. ];
  1135. option.yAxis.data = oriData.gridData;
  1136. option.yAxis.type = 'category';
  1137. option.grid.top = 126;
  1138. if (curAxisName === 2 && sampleObject.fullScreen) {
  1139. option.grid.right = 140;
  1140. }
  1141. option.yAxis.inverse = true;
  1142. option.yAxis.axisLabel.formatter = function(value) {
  1143. return that.yAxisFormatter(sampleObject, value);
  1144. };
  1145. } else if (this.curViewName === 0) {
  1146. option.color = colorArr;
  1147. option.series = [];
  1148. oriData.seriesData.forEach((k) => {
  1149. option.series.push({
  1150. type: 'line',
  1151. symbol: 'none',
  1152. lineStyle: {
  1153. width: 1,
  1154. },
  1155. data: k.slice(1, -1),
  1156. });
  1157. });
  1158. }
  1159. return option;
  1160. },
  1161. yAxisFormatter(sampleObject, value) {
  1162. let data = '';
  1163. const filter = sampleObject.chartData.filter((k) => k.step === value);
  1164. if (filter.length) {
  1165. if (this.curAxisName === 2) {
  1166. data = sampleObject.fullScreen
  1167. ? this.dealrelativeTime(
  1168. new Date(filter[0].wall_time * 1000).toString(),
  1169. )
  1170. : [];
  1171. } else if (this.curAxisName === 1) {
  1172. data = `${this.formateNUmber(filter[0].relative_time.toFixed(0))}s`;
  1173. } else {
  1174. data = this.formateNUmber(filter[0].step);
  1175. }
  1176. }
  1177. return data;
  1178. },
  1179. /**
  1180. * Formate time display
  1181. * @param {Number} value
  1182. * @return {Number} Formatted number
  1183. */
  1184. formateNUmber(value) {
  1185. value = Number(value);
  1186. if (value.toString().length > 6) {
  1187. return value.toExponential(3);
  1188. } else {
  1189. return Math.round(value * 1000) / 1000;
  1190. }
  1191. },
  1192. formatColor(str) {
  1193. if (!str) {
  1194. return;
  1195. }
  1196. const colorReg = /^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
  1197. let colorStr = str.toLowerCase().slice(1);
  1198. if (colorReg.test(colorStr)) {
  1199. let colorStrNew = '';
  1200. if (colorStr.length === 3) {
  1201. for (let i = 0; i < 3; i++) {
  1202. colorStrNew += colorStrNew
  1203. .slice(i, i + 1)
  1204. .concat(colorStrNew.slice(i, i + 1));
  1205. }
  1206. colorStr = colorStrNew;
  1207. }
  1208. const colorFormat = [];
  1209. for (let i = 0; i < 6; i += 2) {
  1210. colorFormat.push(parseInt(`0x${colorStr.slice(i, i + 2)}`));
  1211. }
  1212. return colorFormat;
  1213. } else {
  1214. return colorStr;
  1215. }
  1216. },
  1217. formatColorToHex(rgb) {
  1218. const regRgb = /^(rgb|RGB)/g;
  1219. if (regRgb.test(rgb)) {
  1220. const colorSplit = rgb.replace(/(?:(|)|rgb|RGB)*/g, '').split(',');
  1221. let hexStr = '';
  1222. for (let i = 0; i < colorSplit.length; i++) {
  1223. let hexItem = Number(colorSplit[i]).toString(16);
  1224. hexItem = hexItem < 10 ? `0${hexItem}` : hexItem;
  1225. if (hexItem === '0') {
  1226. hexItem += hexItem;
  1227. }
  1228. hexStr += hexItem;
  1229. }
  1230. if (hexStr.length !== 6) {
  1231. hexStr = rgb;
  1232. }
  1233. return hexStr;
  1234. }
  1235. },
  1236. getGrientColor(startColor, endColor, step) {
  1237. const startRgb = this.formatColor(startColor);
  1238. const endRgb = this.formatColor(endColor);
  1239. const gapRgbR = (endRgb[0] - startRgb[0]) / step;
  1240. const gapRgbG = (endRgb[1] - startRgb[1]) / step;
  1241. const gapRgbB = (endRgb[2] - startRgb[2]) / step;
  1242. const colorResult = [];
  1243. for (let i = 0; i < step; i++) {
  1244. const sR = parseInt(gapRgbR * i + startRgb[0]);
  1245. const sG = parseInt(gapRgbG * i + startRgb[1]);
  1246. const sB = parseInt(gapRgbB * i + startRgb[2]);
  1247. const hex = this.formatColorToHex(`rgb(${sR},${sG},${sB})`);
  1248. colorResult.push(hex);
  1249. }
  1250. return colorResult;
  1251. },
  1252. toggleFullScreen(sampleObject) {
  1253. if (!sampleObject) {
  1254. return;
  1255. }
  1256. this.removeTooltip(sampleObject);
  1257. sampleObject.fullScreen = !sampleObject.fullScreen;
  1258. if (sampleObject.fullScreen) {
  1259. if (this.curAxisName === 2) {
  1260. sampleObject.charOption.grid.right = 140;
  1261. }
  1262. sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor =
  1263. '#00A5A7';
  1264. } else {
  1265. sampleObject.charOption.grid.right = 80;
  1266. sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor =
  1267. '#6D7278';
  1268. }
  1269. setTimeout(() => {
  1270. sampleObject.charObj.setOption(sampleObject.charOption);
  1271. sampleObject.charObj.resize();
  1272. document.getElementById(sampleObject.domId).scrollIntoView();
  1273. }, 0);
  1274. },
  1275. },
  1276. };
  1277. </script>
  1278. <style>
  1279. .cl-histogram-manage {
  1280. height: 100%;
  1281. }
  1282. .cl-histogram-manage .histogram-bk {
  1283. height: 100%;
  1284. background-color: #fff;
  1285. display: flex;
  1286. flex-direction: column;
  1287. }
  1288. .cl-histogram-manage .histogram-bk .cl-histogram-title {
  1289. height: 56px;
  1290. line-height: 56px;
  1291. }
  1292. .cl-histogram-manage .histogram-bk .cl-histogram-title .path-message {
  1293. display: inline-block;
  1294. line-height: 20px;
  1295. padding: 0px 4px 15px 4px;
  1296. font-weight: bold;
  1297. vertical-align: bottom;
  1298. }
  1299. .cl-histogram-manage .histogram-bk .cl-histogram-title .cl-close-btn {
  1300. width: 20px;
  1301. height: 20px;
  1302. vertical-align: -3px;
  1303. cursor: pointer;
  1304. display: inline-block;
  1305. }
  1306. .cl-histogram-manage .histogram-bk .cl-histogram-operate-content {
  1307. width: 100%;
  1308. padding: 8px 32px 22px 32px;
  1309. background: #ffffff;
  1310. }
  1311. .cl-histogram-manage .histogram-bk .cl-histogram-view-type-select-content {
  1312. background: #ffffff;
  1313. padding: 0 32px 21px 32px;
  1314. height: 58px;
  1315. display: flex;
  1316. align-items: center;
  1317. border-bottom: 2px solid #e6ebf5;
  1318. }
  1319. .cl-histogram-manage .histogram-bk .cl-histogram-view-type-select-content .view-title {
  1320. font-size: 14px;
  1321. line-height: 14px;
  1322. vertical-align: middle;
  1323. margin-right: 16px;
  1324. flex-shrink: 0;
  1325. }
  1326. .cl-histogram-manage .histogram-bk .cl-histogram-view-type-select-content .el-radio-group {
  1327. margin-right: 64px;
  1328. flex-shrink: 0;
  1329. }
  1330. .cl-histogram-manage .histogram-bk .cl-histogram-show-data-content {
  1331. background: #ffffff;
  1332. padding: 0 23px;
  1333. flex: 1;
  1334. overflow: auto;
  1335. }
  1336. .cl-histogram-manage .histogram-bk .cl-histogram-show-data-content .data-content {
  1337. display: flex;
  1338. height: 100%;
  1339. width: 100%;
  1340. flex-wrap: wrap;
  1341. min-height: 400px;
  1342. position: relative;
  1343. }
  1344. .cl-histogram-manage .histogram-bk .cl-histogram-show-data-content .data-content .sample-content {
  1345. width: 33.3%;
  1346. height: 400px;
  1347. display: flex;
  1348. flex-direction: column;
  1349. flex-shrink: 0;
  1350. background-color: #fff;
  1351. position: relative;
  1352. }
  1353. .cl-histogram-manage .histogram-bk .cl-histogram-show-data-content .data-content .char-full-screen {
  1354. width: 100%;
  1355. height: 400px;
  1356. }
  1357. .cl-histogram-manage .histogram-bk .cl-histogram-show-data-content .data-content .chars-container {
  1358. flex: 1;
  1359. padding: 0 15px 0 15px;
  1360. position: relative;
  1361. }
  1362. .cl-histogram-manage .histogram-bk .cl-histogram-show-data-content .data-content .chars-container .char-item-content {
  1363. width: 100%;
  1364. height: calc(100% - 26px);
  1365. }
  1366. .cl-histogram-manage .histogram-bk .cl-histogram-show-data-content .data-content .chars-container .tag-title {
  1367. width: 100%;
  1368. font-size: 16px;
  1369. font-weight: 600;
  1370. text-align: center;
  1371. text-overflow: ellipsis;
  1372. white-space: nowrap;
  1373. overflow: hidden;
  1374. }
  1375. .cl-histogram-manage .histogram-bk .pagination-content {
  1376. padding: 24px 32px;
  1377. text-align: right;
  1378. }
  1379. .cl-histogram-manage .histogram-bk .image-noData {
  1380. width: 100%;
  1381. height: 100%;
  1382. display: flex;
  1383. justify-content: center;
  1384. align-items: center;
  1385. flex-direction: column;
  1386. }
  1387. .cl-histogram-manage .content {
  1388. position: relative;
  1389. }
  1390. .cl-histogram-manage #echart {
  1391. width: 500px;
  1392. height: 500px;
  1393. border: 1px solid black;
  1394. position: relative;
  1395. }
  1396. .cl-histogram-manage #echartTip {
  1397. position: absolute;
  1398. padding: 5px;
  1399. z-index: 9999;
  1400. font-size: 14px;
  1401. font-family: "Microsoft YaHei";
  1402. background-color: rgba(50, 50, 50, 0.7);
  1403. border: 0;
  1404. border-radius: 4px;
  1405. color: #fff;
  1406. }
  1407. .cl-histogram-manage .char-tip-table td {
  1408. padding-left: 5px;
  1409. padding-right: 5px;
  1410. text-overflow: ellipsis;
  1411. white-space: nowrap;
  1412. max-width: 150px;
  1413. overflow: hidden;
  1414. }
  1415. .cl-histogram-manage .borderspacing3 {
  1416. border-spacing: 3px;
  1417. }
  1418. </style>