From 9170d6ae0be5b8618d4d7276006e4320b73e75a6 Mon Sep 17 00:00:00 2001 From: mgechev Date: Fri, 15 May 2020 15:41:09 -0700 Subject: [PATCH] refactor(devtools): remove dependency on ngx-charts --- package.json | 1 - .../bargraph-formatter/bargraph-formatter.ts | 7 ++-- .../bar-chart/bar-chart.component.html | 7 ++++ .../bar-chart/bar-chart.component.scss | 31 +++++++++++++++++ .../bar-chart/bar-chart.component.ts | 34 +++++++++++++++++++ .../bargraph-visualizer.component.html | 24 ++----------- .../bargraph-visualizer.component.ts | 29 +++++++--------- .../execution-details.component.html | 20 +++++++++++ .../execution-details.component.scss | 13 +++++++ .../execution-details.component.ts | 16 +++++++++ .../flamegraph-visualizer.component.html | 11 +----- .../flamegraph-visualizer.component.ts | 9 +++-- .../recording-visualizer.module.ts | 13 ++++--- 13 files changed, 154 insertions(+), 61 deletions(-) create mode 100644 projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html create mode 100644 projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.scss create mode 100644 projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts create mode 100644 projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.html create mode 100644 projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.scss create mode 100644 projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.ts diff --git a/package.json b/package.json index 4ac77e1bbe2..a3e03f4db15 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "@angular/material": "~9.2.0", "@angular/platform-browser": "github:angular/platform-browser-builds#77ea10310c138f2fedf5fd625b567d8097ef8bf8", "@angular/platform-browser-dynamic": "github:angular/platform-browser-dynamic-builds#d4a24f6679d86655a650ded46d78b4e290529f94", - "@swimlane/ngx-charts": "^14.0.0", "memo-decorator": "^2.0.1", "ngx-flamegraph": "0.0.7", "rxjs": "~6.5.3", diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/record-formatter/bargraph-formatter/bargraph-formatter.ts b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/record-formatter/bargraph-formatter/bargraph-formatter.ts index 2aea1347711..b984b051e28 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/record-formatter/bargraph-formatter/bargraph-formatter.ts +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/record-formatter/bargraph-formatter/bargraph-formatter.ts @@ -5,7 +5,7 @@ import memo from 'memo-decorator'; export interface BargraphNode { parents: ElementProfile[]; value: number; - name: string; + label: string; original: ElementProfile; } @@ -31,11 +31,10 @@ export class BarGraphFormatter extends RecordFormatter { timeSpent += super.getValue(element); element.directives.forEach((dir) => { - const suffix = addSpaces(nodes.length); const innerNode: BargraphNode = { parents, value: super.getDirectiveValue(dir), - name: dir.name + suffix, + label: dir.name, original: element, }; nodes.push(innerNode); @@ -44,5 +43,3 @@ export class BarGraphFormatter extends RecordFormatter { return timeSpent; } } - -const addSpaces = (length: number) => ' '.repeat(length); diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html new file mode 100644 index 00000000000..54df3cdde74 --- /dev/null +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.html @@ -0,0 +1,7 @@ +
+
+
+ {{ bar.label }} +
+
+
diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.scss b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.scss new file mode 100644 index 00000000000..0568265a156 --- /dev/null +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.scss @@ -0,0 +1,31 @@ +.bar { + height: 20px; + width: 0%; + margin-bottom: 7px; + padding-top: 3px; + padding-bottom: 3px; + opacity: 0.8; + cursor: pointer; + transition: opacity 0.3s ease-out, width 0.3s ease; +} + +.bar span { + margin-left: 10px; + max-width: calc(100% - 20px); + display: inline-block; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + padding-top: 3px; +} + +.bar:hover { + opacity: 1; +} + +:host, +.wrapper { + width: 100%; + height: 100%; + display: block; +} diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts new file mode 100644 index 00000000000..9e6c0cb2b93 --- /dev/null +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bar-chart/bar-chart.component.ts @@ -0,0 +1,34 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +interface Data { + label: string; + value: number; +} + +@Component({ + selector: 'ng-bar-chart', + templateUrl: './bar-chart.component.html', + styleUrls: ['./bar-chart.component.scss'], +}) +export class BarChartComponent { + @Input() set data(nodes: Data[]) { + this._originals = nodes; + this.internalData = []; + const max = nodes.reduce((a: number, c) => Math.max(a, c.value), -Infinity); + for (const node of nodes) { + this.internalData.push({ + label: node.label, + value: (node.value / max) * 100, + }); + } + } + @Input() color: string; + @Output() pick = new EventEmitter(); + private _originals: Data[]; + + internalData: Data[] = []; + + select(idx: number): void { + this.pick.emit(this._originals[idx]); + } +} diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.html b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.html index 90c16e80e84..2593e91c329 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.html +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.html @@ -1,31 +1,13 @@
- - +
-
{{ selectedEntry.name }} details
+
{{ selectedEntry.label }} details
{{ selectedEntry.value | number }}ms
- - +
diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.ts b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.ts index cf8aebf59fe..abbe6646f88 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.ts +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/bargraph-visualizer/bargraph-visualizer.component.ts @@ -3,7 +3,8 @@ import { BargraphNode, BarGraphFormatter } from '../../record-formatter/bargraph import { ProfilerFrame } from 'protocol'; export interface GraphNode { - name: string; + directive: string; + method: string; value: number; } @@ -13,17 +14,10 @@ export interface GraphNode { styleUrls: ['./bargraph-visualizer.component.scss'], }) export class BargraphVisualizerComponent { - view: [number, number] = [600, 600]; - colorScheme = { - domain: ['rgb(237, 213, 94)'], - }; + barColor = 'rgb(237, 213, 94)'; profileRecords: BargraphNode[]; selectedEntry: BargraphNode | null = null; - pieChartView: [number, number] = [235, 200]; - pieChartColorScheme = { - domain: ['#E71D36', '#2EC4B6', '#FF9F1C', '#011627'], - }; - pieChartData: GraphNode[] = []; + selectedDirectives: GraphNode[] = []; parentHierarchy: { name: string }[] = []; private _formatter = new BarGraphFormatter(); @@ -31,22 +25,23 @@ export class BargraphVisualizerComponent { @Input() set frame(data: ProfilerFrame) { this.profileRecords = this._formatter.formatFrame(data); this.selectedEntry = null; - this.view = [1000, this.profileRecords.length * 30]; } formatPieChartData(bargraphNode: BargraphNode): GraphNode[] { const graphData: GraphNode[] = []; bargraphNode.original.directives.forEach((node) => { - const {changeDetection} = node; + const { changeDetection } = node; if (changeDetection) { graphData.push({ - name: `${node.name} changeDetection`, + directive: node.name, + method: 'changes', value: parseFloat(changeDetection.toFixed(2)), }); } Object.keys(node.lifecycle).forEach((key) => { graphData.push({ - name: `${node.name} ${key}`, + directive: node.name, + method: key, value: +node.lifecycle[key].toFixed(2), }); }); @@ -54,13 +49,13 @@ export class BargraphVisualizerComponent { return graphData; } - selectNode(data: any): void { - const index = this.profileRecords.findIndex((element) => element.name === data.name); + selectNode(data: BargraphNode): void { + const index = this.profileRecords.findIndex((element) => element.label === data.label); this.selectedEntry = this.profileRecords[index]; this.parentHierarchy = this.selectedEntry.parents.map((element) => { return { name: element.directives[0].name }; }); - this.pieChartData = this.formatPieChartData(this.selectedEntry); + this.selectedDirectives = this.formatPieChartData(this.selectedEntry); } formatToolTip(data: any): string { diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.html b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.html new file mode 100644 index 00000000000..40887ac7436 --- /dev/null +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + +
DirectiveMethodTime
+ {{ entry.directive }} + + {{ entry.method }} + + {{ entry.value }} +
diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.scss b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.scss new file mode 100644 index 00000000000..1939ab86700 --- /dev/null +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.scss @@ -0,0 +1,13 @@ +.name { + width: 80px; + overflow: hidden; + text-overflow: ellipsis; +} + +.value { + width: 30px; +} + +.method { + width: 50px; +} diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.ts b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.ts new file mode 100644 index 00000000000..719e12e1846 --- /dev/null +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/execution-details/execution-details.component.ts @@ -0,0 +1,16 @@ +import { Component, Input } from '@angular/core'; + +export interface GraphNode { + directive: string; + method: string; + value: number; +} + +@Component({ + selector: 'ng-execution-details', + templateUrl: './execution-details.component.html', + styleUrls: ['./execution-details.component.scss'], +}) +export class ExecutionDetailsComponent { + @Input() data: GraphNode[]; +} diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.html b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.html index 648a69cae8d..0fa1e346ea7 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.html +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.html @@ -20,16 +20,7 @@
- - +
diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.ts b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.ts index a5cd9fe785c..5f490e6fef2 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.ts +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/flamegraph-visualizer/flamegraph-visualizer.component.ts @@ -10,7 +10,8 @@ import { RawData } from 'ngx-flamegraph/lib/utils'; import { ProfilerFrame } from 'protocol'; export interface GraphNode { - name: string; + directive: string; + method: string; value: number; } @@ -60,13 +61,15 @@ export class FlamegraphVisualizerComponent { const changeDetection = node.changeDetection; if (changeDetection !== undefined) { graphData.push({ - name: `${node.name} changeDetection`, + directive: node.name, + method: 'changes', value: parseFloat(changeDetection.toFixed(2)), }); } Object.keys(node.lifecycle).forEach((key) => { graphData.push({ - name: `${node.name} ${key}`, + directive: node.name, + method: key, value: +node.lifecycle[key].toFixed(2), }); }); diff --git a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/recording-visualizer.module.ts b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/recording-visualizer.module.ts index a8fb0153cad..0b677bb2bcf 100644 --- a/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/recording-visualizer.module.ts +++ b/projects/ng-devtools/src/lib/devtools-tabs/profiler/recording/timeline/recording-visualizer/recording-visualizer.module.ts @@ -1,21 +1,26 @@ import { NgModule } from '@angular/core'; -import { TimelineVisualizerComponent } from './timeline-visualizer.component'; import { CommonModule } from '@angular/common'; +import { MatCheckboxModule } from '@angular/material/checkbox'; + import { NgxFlamegraphModule } from 'ngx-flamegraph'; -import { NgxChartsModule } from '@swimlane/ngx-charts'; + import { FlamegraphVisualizerComponent } from './flamegraph-visualizer/flamegraph-visualizer.component'; import { BargraphVisualizerComponent } from './bargraph-visualizer/bargraph-visualizer.component'; import { TreeMapVisualizerComponent } from './tree-map-visualizer/tree-map-visualizer.component'; -import { MatCheckboxModule } from '@angular/material/checkbox'; +import { TimelineVisualizerComponent } from './timeline-visualizer.component'; +import { BarChartComponent } from './bar-chart/bar-chart.component'; +import { ExecutionDetailsComponent } from './execution-details/execution-details.component'; @NgModule({ declarations: [ + ExecutionDetailsComponent, + BarChartComponent, TimelineVisualizerComponent, FlamegraphVisualizerComponent, TreeMapVisualizerComponent, BargraphVisualizerComponent, ], - imports: [CommonModule, NgxFlamegraphModule, NgxChartsModule, MatCheckboxModule], + imports: [CommonModule, NgxFlamegraphModule, MatCheckboxModule], exports: [TimelineVisualizerComponent], }) export class RecordingVisualizerModule {}