11<template >
22 <div
3+ ref =" container"
34 class =" profiler-page-call-graph"
45 :class =" { 'profiler-page-call-graph--fullscreen': isFullscreen }"
56 >
6- <div v-if =" metricLoading" class =" profiler-page-call-graph__loading-wr" >
7- <div class =" profiler-page-call-graph__loading" >
8- <div ></div >
9- <div ></div >
10- <div ></div >
11- </div >
12- </div >
7+ <RenderGraph
8+ v-if =" isReadyGraph && graphKey"
9+ :key =" graphKey"
10+ :elements =" graphElements"
11+ :height =" graphHeight"
12+ >
13+ <template #default =" { data: { name , cost } } " >
14+ <div class =" profiler-page-call-graph__board" >
15+ <h4 class =" profiler-page-call-graph__board-title" >
16+ {{ name }}
17+ </h4 >
1318
14- <div ref =" graphviz" class =" profiler-page-call-graph__graphviz" ></div >
19+ <StatBoard :cost =" cost" />
20+ </div >
21+ </template >
22+ </RenderGraph >
1523
1624 <div class =" profiler-page-call-graph__toolbar" >
1725 <button title =" Full screen" @click =" isFullscreen = !isFullscreen" >
2230 </button >
2331 <button
2432 class =" profiler-page-call-graph__toolbar-action"
25- :class =" { 'font-bold': metric === 'cpu' }"
26- @click =" setMetric('cpu' )"
33+ :class =" { 'font-bold': metric === graphMetrics.CPU }"
34+ @click =" setMetric(graphMetrics.CPU )"
2735 >
2836 CPU
2937 </button >
3038 <button
3139 class =" profiler-page-call-graph__toolbar-action"
32- :class =" { 'font-bold': metric === 'pmu' }"
33- @click =" setMetric('pmu' )"
40+ :class =" { 'font-bold': metric === graphMetrics.MEMORY_CHANGE }"
41+ @click =" setMetric(graphMetrics.MEMORY_CHANGE )"
3442 >
3543 Memory change
3644 </button >
3745 <button
3846 class =" profiler-page-call-graph__toolbar-action"
39- :class =" { 'font-bold': metric === 'mu' }"
40- @click =" setMetric('mu' )"
47+ :class =" { 'font-bold': metric === graphMetrics.MEMORY }"
48+ @click =" setMetric(graphMetrics.MEMORY )"
4149 >
4250 Memory usage
4351 </button >
6371</template >
6472
6573<script lang="ts">
66- import { selectAll } from " d3-selection" ;
67- import { graphviz } from " d3-graphviz" ;
68- import { Graphviz } from " @hpcc-js/wasm/graphviz" ;
69-
7074import IconSvg from " ~/components/IconSvg/IconSvg.vue" ;
7175
7276import { defineComponent , PropType } from " vue" ;
73- import { Profiler , ProfilerEdge } from " ~/config/types" ;
74- import { addSlashes , DigraphBuilder } from " ~/utils/digraph-builder" ;
75- import debounce from " lodash.debounce" ;
77+ import { GraphTypes , Profiler } from " ~/config/types" ;
78+ import { calcGraphData } from " ~/utils/calc-graph-data" ;
79+ import RenderGraph from " ~/components/RenderGraph/RenderGraph.vue" ;
80+ import StatBoard from " ~/components/StatBoard/StatBoard.vue" ;
7681
7782export default defineComponent ({
78- components: { IconSvg },
83+ components: { StatBoard , RenderGraph , IconSvg },
7984 props: {
8085 event: {
8186 type: Object as PropType <Profiler >,
@@ -86,95 +91,40 @@ export default defineComponent({
8691 data() {
8792 return {
8893 isFullscreen: false ,
89- metric: " cpu" ,
90- metricLoading: false ,
94+ metric: GraphTypes .CPU as GraphTypes ,
9195 threshold: 1 ,
96+ isReadyGraph: false ,
9297 };
9398 },
94- created(): void {
95- Graphviz .load ().then (() => {
96- this .graph = graphviz (this .$refs .graphviz , {})
97- .width (" 100%" )
98- .height (" 100%" )
99- .fit (true );
100-
101- this .renderGraph ();
102- });
99+ computed: {
100+ graphElements() {
101+ return calcGraphData (this .event .edges , this .metric , this .threshold );
102+ },
103+ graphKey() {
104+ return ` ${this .metric }-${this .threshold } ` ;
105+ },
106+ graphMetrics() {
107+ return GraphTypes ;
108+ },
109+ graphHeight() {
110+ return this .isFullscreen
111+ ? window .innerHeight
112+ : (this .$refs .container as HTMLElement ).offsetHeight ;
113+ },
103114 },
104- beforeUnmount() {
105- this .graph .destroy ();
115+ mounted() {
116+ // NOTE: need to show graph after parent render
117+ this .setReadyGraph ();
106118 },
107119 methods: {
108- setMetric(metric : string ): void {
109- this .metricLoading = true ;
110-
111- setTimeout (() => {
112- this .metric = metric ;
113- this .renderGraph ();
114- this .metricLoading = false ;
115- }, 0 );
120+ setMetric(metric : GraphTypes ): void {
121+ this .metric = metric ;
116122 },
117123 setThreshold(threshold : number ): void {
118- this .metricLoading = true ;
119-
120- const prevThreshold = this .threshold ;
121124 this .threshold = threshold ;
122-
123- return debounce (() => {
124- if (! threshold || prevThreshold === threshold ) {
125- return ;
126- }
127-
128- setTimeout (() => {
129- this .renderGraph ();
130- this .metricLoading = false ;
131- }, 0 );
132- }, 1000 )();
133- },
134-
135- findEdge(name : string ): ProfilerEdge | null {
136- const found = Object .values (this .event .edges ).filter (
137- (v ) => addSlashes (v .callee ) === name
138- );
139-
140- if (! found || found .length === 0 ) {
141- return null ;
142- }
143-
144- return found [0 ] || null ;
145125 },
146- nodeHandler(): void {
147- selectAll (" g.node" )
148- .on (" mouseover" , (e , tag ) => {
149- const edge = this .findEdge (tag .key );
150-
151- if (! edge ) {
152- return ;
153- }
154-
155- this .$emit (" hover" , {
156- callee: edge .callee ,
157- cost: edge .cost ,
158- position: {
159- x: e .pageX ,
160- y: e .pageY ,
161- },
162- });
163- })
164- .on (" mouseout" , () => {
165- this .$emit (" hide" );
166- });
167- },
168- renderGraph(): void {
169- this .graph
170- .renderDot (
171- new DigraphBuilder (this .event .edges ).build (
172- this .metric ,
173- this .threshold
174- ),
175- this .nodeHandler
176- )
177- .resetZoom ();
126+ setReadyGraph(): void {
127+ this .isReadyGraph = true ;
178128 },
179129 },
180130});
@@ -184,11 +134,19 @@ export default defineComponent({
184134@import " assets/mixins" ;
185135
186136.profiler-page-call-graph {
187- @apply relative flex rounded border border-gray-900 h-full ;
137+ @apply relative flex rounded border border-gray-900 min-h-min min-w-min ;
188138}
189139
190140.profiler-page-call-graph--fullscreen {
191- @apply rounded-none mt-0 top-0 left-0 fixed w-full h-full ;
141+ @apply rounded-none mt-0 top-0 left-0 fixed w-full h-full bg-gray-800 z- [99999 ];
142+ }
143+
144+ .profiler-page-call-graph__board {
145+ @apply border border-gray-600 bg-gray-800 h-full ;
146+ }
147+
148+ .profiler-page-call-graph__board-title {
149+ @apply px-4 py-2 font-bold truncate text-gray- 300;
192150}
193151
194152.profiler-page-call-graph__toolbar {
@@ -214,20 +172,4 @@ export default defineComponent({
214172.profiler-page-call-graph__toolbar-input {
215173 @apply border-b bg-transparent border-gray-600 text-gray-600 w- 8;
216174}
217-
218- .profiler-page-call-graph__loading-wr {
219- @apply absolute m-auto top-0 left-0 right-0 bottom-0 flex justify-center items-center ;
220- }
221-
222- .profiler-page-call-graph__loading {
223- @apply z- 50;
224-
225- @include loading ;
226- }
227-
228- .profiler-page-call-graph__graphviz {
229- @apply flex-1 justify-items-stretch items-stretch bg-white ;
230-
231- max-height : 100vh ;
232- }
233175 </style >
0 commit comments