From fc34f6faf6a7f8474c482846860b5d151f96edd0 Mon Sep 17 00:00:00 2001
From: Andre Farzat <andrefarzat@gmail.com>
Date: Sat, 22 Feb 2020 14:47:36 -0300
Subject: [PATCH] Adding performance demo page

---
 src/app/demo/demo.component.html              |  1 +
 src/app/demo/demo.module.ts                   |  3 +
 .../performance/performance.component.css     | 10 +++
 .../performance/performance.component.html    | 12 +++
 .../performance/performance.component.spec.ts | 25 ++++++
 .../demo/performance/performance.component.ts | 83 +++++++++++++++++++
 src/app/shared/plot/plot.component.ts         |  7 +-
 7 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 src/app/demo/performance/performance.component.css
 create mode 100644 src/app/demo/performance/performance.component.html
 create mode 100644 src/app/demo/performance/performance.component.spec.ts
 create mode 100644 src/app/demo/performance/performance.component.ts

diff --git a/src/app/demo/demo.component.html b/src/app/demo/demo.component.html
index 794db6e..d62362e 100644
--- a/src/app/demo/demo.component.html
+++ b/src/app/demo/demo.component.html
@@ -17,6 +17,7 @@ <h5>Angular Plotly</h5>
                     <li><a [routerLink]="['/timeout-update']">Timeout Update</a></li>
                     <li><a [routerLink]="['/huge-memory-usage']">Huge Memory Usage</a></li>
                     <li><a [routerLink]="['/slow-example']">Slow Example</a></li>
+                    <li><a [routerLink]="['/performance']">Performance</a></li>
                 </ul>
             </div>
         </div>
diff --git a/src/app/demo/demo.module.ts b/src/app/demo/demo.module.ts
index 80d2349..6cae6ed 100644
--- a/src/app/demo/demo.module.ts
+++ b/src/app/demo/demo.module.ts
@@ -23,6 +23,7 @@ import { FramesComponent } from './frames/frames.component';
 import { TimeoutUpdateComponent } from './timeout-update/timeout-update.component';
 import { HugeMemoryUsageComponent } from './huge-memory-usage/huge-memory-usage.component';
 import { SlowExampleComponent } from './slow-example/slow-example.component';
+import { PerformanceComponent } from './performance/performance.component';
 
 
 const demoRoutes: Routes = [
@@ -37,6 +38,7 @@ const demoRoutes: Routes = [
     { path: 'timeout-update', component: TimeoutUpdateComponent, data: { title: 'Timeout Update' } },
     { path: 'huge-memory-usage', component: HugeMemoryUsageComponent, data: { title: 'Huge Memory Usage' } },
     { path: 'slow-example', component: SlowExampleComponent, data: { title: 'Slow example' } },
+    { path: 'performance', component: PerformanceComponent, data: { title: 'Performance' } },
 
     { path: '', redirectTo: '/home', pathMatch: 'full' },
 ];
@@ -68,6 +70,7 @@ PlotlyViaCDNModule.plotlyVersion = '1.49.4';
         TimeoutUpdateComponent,
         HugeMemoryUsageComponent,
         SlowExampleComponent,
+        PerformanceComponent,
     ],
     exports: [DemoComponent],
 })
diff --git a/src/app/demo/performance/performance.component.css b/src/app/demo/performance/performance.component.css
new file mode 100644
index 0000000..1c1c231
--- /dev/null
+++ b/src/app/demo/performance/performance.component.css
@@ -0,0 +1,10 @@
+.grid {
+    display: grid;
+    grid-template-columns: repeat(5, 1fr);
+    grid-auto-rows: 225px;
+    gap: 4px;
+    
+    max-width: 1200px;
+    margin: 0 auto;
+  }
+  
\ No newline at end of file
diff --git a/src/app/demo/performance/performance.component.html b/src/app/demo/performance/performance.component.html
new file mode 100644
index 0000000..7d2044e
--- /dev/null
+++ b/src/app/demo/performance/performance.component.html
@@ -0,0 +1,12 @@
+
+<h4>Total time: {{ getTotalTime() }}ms</h4>
+
+<div class="grid">
+
+    <div class="item" *ngFor="let data of chartData; let i = index; trackBy: trackByIndex">
+        <div>Time: {{ getTime(i) }}ms</div>
+        <plotly-plot [data]="data" [layout]="layout" [style]="style" [config]="config" (ngInited)="onNgInited(i)" (initialized)="onInitialized(i)"></plotly-plot>
+    </div>
+
+	
+</div>
\ No newline at end of file
diff --git a/src/app/demo/performance/performance.component.spec.ts b/src/app/demo/performance/performance.component.spec.ts
new file mode 100644
index 0000000..1bdc919
--- /dev/null
+++ b/src/app/demo/performance/performance.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PerformanceComponent } from './performance.component';
+
+describe('PerformanceComponent', () => {
+  let component: PerformanceComponent;
+  let fixture: ComponentFixture<PerformanceComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PerformanceComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PerformanceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/demo/performance/performance.component.ts b/src/app/demo/performance/performance.component.ts
new file mode 100644
index 0000000..7919e84
--- /dev/null
+++ b/src/app/demo/performance/performance.component.ts
@@ -0,0 +1,83 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'plotly-performance',
+  templateUrl: './performance.component.html',
+  styleUrls: ['./performance.component.css']
+})
+export class PerformanceComponent implements OnInit {
+  numberOfCharts = 100;
+  indexNumberOfCharts = this.numberOfCharts - 1;
+
+  chartData = [];
+  layout: any;
+  style: any;
+  config: any;
+
+  public mainStartTime: number;
+  public mainEndTime: number;
+  public startTime: number[] = [];
+  public endTime: number[] = [];
+
+  constructor() { }
+
+  ngOnInit(): void {
+    this.initChartSetup();
+    this.initChartData();
+
+    this.mainStartTime = (new Date()).getTime();
+  }
+
+  trackByIndex(i) {
+    return i;
+  }
+
+  initChartSetup() {
+    this.layout = {
+      xaxis: { title: { text: "X" }, automargin: true },
+      yaxis: { title: { text: "Y" }, automargin: true },
+      margin: {
+        t: 12,
+        r: 12,
+        b: 12,
+        l: 12
+      }
+    };
+
+    this.style = { position: "relative", width: "100%", height: '200px' };
+
+    this.config = { staticPlot: true };
+  }
+
+  initChartData() {
+    for (let i = 1; i <= this.numberOfCharts; i++) {
+      const data = [
+        { type: "bar", name: `Chart ${i}`, x: [1, 2, 3], y: [100, 300, 200] }
+      ];
+      this.chartData.push(data);
+    }
+  }
+
+  onNgInited(i: number) {
+    this.startTime[i] = (new Date()).getTime();
+  }
+
+  onInitialized(i: number) {
+    this.endTime[i] = (new Date()).getTime();
+
+    if (i === this.indexNumberOfCharts) {
+      this.mainEndTime = (new Date()).getTime();
+    }
+  }
+
+  getTime(i: number): number {
+    if (i in this.endTime) return this.endTime[i] - this.startTime[i];
+    return 0;
+  }
+
+  getTotalTime(): number {
+    if (this.mainEndTime) return this.mainEndTime - this.mainStartTime;
+    return 0;
+  }
+
+}
diff --git a/src/app/shared/plot/plot.component.ts b/src/app/shared/plot/plot.component.ts
index d684246..d7d1413 100644
--- a/src/app/shared/plot/plot.component.ts
+++ b/src/app/shared/plot/plot.component.ts
@@ -15,6 +15,7 @@ import {
     IterableDiffers,
     KeyValueDiffer,
     KeyValueDiffers,
+    ChangeDetectionStrategy,
 } from '@angular/core';
 
 import { PlotlyService } from '../plotly.service';
@@ -25,6 +26,7 @@ import { Plotly } from '../plotly.interface';
     selector: 'plotly-plot',
     template: `<div #plot [attr.id]="divId" [className]="getClassName()" [ngStyle]="style"></div>`,
     providers: [PlotlyService],
+    changeDetection: ChangeDetectionStrategy.OnPush
 })
 export class PlotComponent implements OnInit, OnChanges, OnDestroy, DoCheck {
     protected defaultClassName = 'js-plotly-plot';
@@ -52,6 +54,7 @@ export class PlotComponent implements OnInit, OnChanges, OnDestroy, DoCheck {
     @Input() updateOnDataChange = true;
     @Input() updateOnlyWithRevision = false;
 
+    @Output() ngInited = new EventEmitter();
     @Output() initialized = new EventEmitter<Plotly.Figure>();
     @Output() update = new EventEmitter<Plotly.Figure>();
     @Output() purge = new EventEmitter<Plotly.Figure>();
@@ -99,7 +102,9 @@ export class PlotComponent implements OnInit, OnChanges, OnDestroy, DoCheck {
     ) { }
 
     ngOnInit() {
-        this.createPlot().then(() => {
+        this.ngInited.emit();
+        setTimeout(async () => {
+            await this.createPlot();
             const figure = this.createFigure();
             this.initialized.emit(figure);
         });