Browse Source

feat:火焰图加兜底+图例+背景icon

liujing 9 months ago
parent
commit
09c1337449
1 changed files with 108 additions and 107 deletions
  1. 108 107
      src/views/latency/components/FlameGraph.vue

+ 108 - 107
src/views/latency/components/FlameGraph.vue

@@ -4,13 +4,14 @@
 
 <script>
 import resize from '@/components/Charts/mixins/resize'
-// import chartResdata from './data.js'
-import { getFlameData } from '@/api/trace'
+// import { getFlameData } from '@/api/trace'
 export default {
     mixins: [resize],
     data() {
         return {
-            chart: null
+            chart: null,
+            apis:require("../../../assets/apis.jpg"),
+            apm:require("../../../assets/apm.jpg"),
         }
     },
     props: ['tractID'],
@@ -31,55 +32,7 @@ export default {
             this.chart = this.$echarts5.init(document.getElementById('flameGraphContent'))
 
             var option;
-            const renderItem = (params, api) => {
-                const level = api.value(0);
-                const start = api.coord([api.value(1), level]);
-                const end = api.coord([api.value(2), level]);
-                const height = ((api.size && api.size([0, 1])) || [0, 20])[1];
-                const width = end[0] - start[0];
-                const ProcessName = '进程名称'
-                const CollectionEquipment = '采集设备'
-                const CollectionName = `  ${api.value(6) == 'syscall' ? ProcessName+':'+api.value(5)|| '':(api.value(6) == 'network'?CollectionEquipment+':'+api.value(5)|| '' : '')}`
-                return {
-                    type: 'rect',
-                    transition: ['shape'],
-                    shape: {
-                        x: start[0],
-                        y: start[1] - height / 2,
-                        width,
-                        height: height - 2 /* itemGap */,
-                        r: 2
-                    },
-                    style: {
-                        fill: api.visual('color')
-                    },
-                    emphasis: {
-                        style: {
-                            stroke: '#000'
-                        }
-                    },
-                    textConfig: {
-                        position: 'insideLeft'
-                    },
-                    textContent: {
-                        style: {
-                            text: `${api.value(3)}  耗时:${api.value(7)}ms${CollectionName}`,
-                            fontFamily: 'Verdana',
-                            fill: '#000',
-                            width: width - 4,
-                            overflow: 'truncate',
-                            ellipsis: '..',
-                            truncateMinChar: 1
-                        },
-                        emphasis: {
-                            style: {
-                                stroke: '#000',
-                                lineWidth: 0.5
-                            }
-                        }
-                    }
-                };
-            };
+            
             this.chart.showLoading();
             let para = {
                 'trace_id': this.tractID
@@ -93,8 +46,8 @@ export default {
                 if (res && res.status == 200) {
                     this.chart.hideLoading();
                     const chartResdata = res.data.OPT_STATUS // OPT_STATUS这个对象就是根节点
-                   
                     const levelOfOriginalJson = this.heightOfJson(chartResdata);
+                    let seriesData = this.setSeries(this.recursionJson(chartResdata))
                     option = {
                         backgroundColor: {
                             type: 'linear',
@@ -114,29 +67,18 @@ export default {
                             ]
                         },
                         tooltip: {
+                            className: 'custom-tooltip-box',
                             formatter: (params) => {
-                                const samples = params.value[2] - params.value[1];
                                 let res  = `${params.marker} ${
                                     params.value[3]
                                     }<br/>${params.marker} 耗时: ${params.value[7]}<br/>${params.marker} 比例: ${+params.value[4].toFixed(2)}%<br/>`
                                 for (const key in params.data.detail) {
                                     res+=`${params.marker} ${key}: ${params.data.detail[key] || '--'}<br/>`
                                 }
+                                res+=`<div style='position:absolute;bottom:10px;right:10px;width:80px;height:80px;z-index: -1;backdrop-filter: blur(10px);background-image:url("${params.value[6] =='apm'?this.apm:this.apis}");background-size:cover;background-repeat:no-repeat;background-position: center;'></div>`
                                 return res;
                             }
                         },
-                        title: [
-                            // {
-                            //     text: 'Flame Graph',
-                            //     left: 'center',
-                            //     top: 10,
-                            //     textStyle: {
-                            //         fontFamily: 'Verdana',
-                            //         fontWeight: 'normal',
-                            //         fontSize: 20
-                            //     }
-                            // }
-                        ],
                         toolbox: {
                             feature: {
                                 restore: {}
@@ -152,32 +94,15 @@ export default {
                             max: levelOfOriginalJson
                         },
                         series: [
-                            {
-                                type: 'custom',
-                                // name: this.formatCategoryData(chartResdata),
-                                renderItem,
-                                encode: {
-                                    x: [0, 1, 2],
-                                    y: 0
-                                },
-                                data: this.recursionJson(chartResdata)
-                            }
-                            // ...dataList.map(function (data, index) {
-                            //     return {
-                            //         type: 'bar',
-                            //         animation: false,
-                            //         name: legendData[index + 1],
-                            //         itemStyle: {
-                            //         opacity: 0.5
-                            //         },
-                            //         data: data
-                            //     };
-                            // })
-                        ]
-                        // legend: {
-                        //     show:true,
-                        //     data: this.formatCategoryData(chartResdata)
-                        // }
+                            ...seriesData
+                        ],
+                        color: ['#f2d643', '#eb8146', '#ffb248', '#d95850'], // 图例的颜色
+                        legend: {
+                            show:true,
+                            // data: this.formatCategoryData(chartResdata),
+                            data: ['apm', 'syscall', 'network', 'unknown']
+                        }
+                        
                     };
                     this.chart.setOption(option);
                     this.chart.on('click', (params) => {
@@ -192,6 +117,75 @@ export default {
             })
 
         },
+        setSeries(chartResdata){
+            const renderItem = (params, api) => {
+                const level = api.value(0);
+                const start = api.coord([api.value(1), level]);
+                const end = api.coord([api.value(2), level]);
+                const height = ((api.size && api.size([0, 1])) || [0, 20])[1];
+                const width = end[0] - start[0];
+                const ProcessName = '进程名称'
+                const CollectionEquipment = '采集设备'
+                const CollectionName = `  ${api.value(6) == 'syscall' ? ProcessName+':'+api.value(5)|| '':(api.value(6) == 'network'?CollectionEquipment+':'+api.value(5)|| '' : '')}`
+                return {
+                    type: 'rect',
+                    transition: ['shape'],
+                    shape: {
+                        x: start[0],
+                        y: start[1] - height / 2,
+                        width,
+                        height: height - 2 /* itemGap */,
+                        r: 2
+                    },
+                    style: {
+                        fill: api.visual('color')
+                    },
+                    emphasis: {
+                        style: {
+                            stroke: '#000'
+                        }
+                    },
+                    textConfig: {
+                        position: 'insideLeft'
+                    },
+                    textContent: {
+                        style: {
+                            text: `${api.value(3)}  耗时:${api.value(7)}ms${CollectionName}`,
+                            fontFamily: 'Verdana',
+                            fill: '#000',
+                            width: width - 4,
+                            overflow: 'truncate',
+                            ellipsis: '..',
+                            truncateMinChar: 1
+                        },
+                        emphasis: {
+                            style: {
+                                stroke: '#000',
+                                lineWidth: 0.5
+                            }
+                        }
+                    }
+                };
+            };
+            let res = []
+            chartResdata.forEach(item=>{
+                if (item){
+                    let obj =  {
+                        type: 'custom',
+                        name:item?.value[6] || '',
+                        renderItem,
+                        encode: {
+                            x: [0, 1, 2],
+                            y: 0
+                        },
+                        data: [item]
+                    }
+                    res.push(obj)
+                }
+                
+            })
+            return res
+        },
         filterJson(json, id) {
             if (id == null) {
                 return json;
@@ -201,12 +195,15 @@ export default {
                     return item;
                 }
                 for (const child of item.children || []) {
-                    const temp = recur(child, id);
-                    if (temp) {
-                        item.children = [temp];
-                        item.value = temp.duration; // change the parents' values
-                        return item;
+                    if (item.children.length > 0){
+                        const temp = recur(child, id);
+                        if (temp) {
+                            item.children = [temp];
+                            item.value = temp.duration; // change the parents' values
+                            return item;
+                        }
                     }
+                    
                 }
             };
             return recur(json, id) || json;
@@ -215,7 +212,7 @@ export default {
             const data = [];
             const ColorTypes = {
                 root:'#8fd3e8',
-                apm: '#b5c334',
+                apm: '#f2d643',
                 syscall: '#eb8146',
                 network: '#ffb248',
                 unknown:'#d95850'
@@ -228,7 +225,7 @@ export default {
                     const CollectionEquipment = '采集设备'
                     const collectionName = `${item.span_category == 'syscall' ? item.detail[ProcessName]|| '': (item.span_category == 'network'?item.detail[CollectionEquipment] || '' : '')}`
                     const temp = {
-                        name: item.id,
+                        name: item?.id,
                         value: [
                             level,
                             start,
@@ -262,12 +259,14 @@ export default {
             const data = [];
             const filteredJson = this.filterJson(structuredClone(jsonObj), id);
             const recur = (item) => {
-                if(item){
-                    data.push(item.span_category);
-                }
-                if(item) {
+                // console.log('item-=======23421342342====', item, data)
+                if(item !== null && item !== undefined && Object.keys(item).length > 0){
+                    // console.log('data----', item)
+                    data.push(item?.span_category);
                     for (const child of item.children || []) {
-                        recur(child);
+                        if(item.children.length > 0){
+                            recur(child);
+                        }
                     }
                 }
                 
@@ -288,9 +287,7 @@ export default {
                 return maxLevel;
             };
             return recur(json);
-        },
-
-
+        }
     }
 }
 </script>
@@ -299,4 +296,8 @@ export default {
     width: 100%;
     height: calc(100vh - 200px);
 }
+::v-deep .custom-tooltip-box{
+    background-color: rgba(0, 0, 0, 0.6) !important;
+    color:white !important;
+}
 </style>