Search code examples
angulartypescriptangular-componentskendo-chartkendo-angular-ui

Kendo UI for Angular Pie Charts is not responsive with ChangeDetectionStrategy.OnPush


I have created a new component that should show a pie chart inside any place that I place that component, the problem is even with simple component, the pie chart stays as the size of the first render, I got this issue after I changed ChangeDetectionStrategy to ChangeDetectionStrategy.OnPush, the problem that I did that because without even the problem does not persist but the resizing start to be laggy and consume more CPU usage during that.

So I got the option to keep that lag and make chart responsive, or change the ChangeDetectionStrategy and get chart stuck to first time render.

Also, I got many types of charts, like the bar chart and the issue does not seem to be happening with that kind of charts, for now, it is only for my Pie chart.

my.component.ts:

import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-component',
  templateUrl: 'my-component.html',
  styleUrls: ['./my-component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent implements OnInit {
  public pieData: { category: string; value: number; active: boolean }[] = [
    {category: 'Complete', value: 123},
    {category: 'Work In Progress', value: 22},
    {category: 'Other', value: 5},
  ];
  constructor(private _cdRef: ChangeDetectorRef) {
  }
}

my-component.html:

<kendo-chart [seriesColors]="['orange', '#ffe', 'green']">
  <kendo-chart-legend position="top"></kendo-chart-legend>
  <kendo-chart-series>
        <kendo-chart-series-item [type]="'pie'" [data]="pieData" [field]="'value'" [categoryField]="'category'">
</kendo-chart-series-item>
  </kendo-chart-series>
</kendo-chart>

my-component.scss:

:host {
  display: flex;
  overflow: hidden;
  margin: 8px;
  padding: 8px;
  flex-direction: column;

  @media only screen and (max-width: 760px),
  (min-device-width: 768px) and (max-device-width: 1024px) {
    padding: 2px;
  }
}

Solution

  • If you got component with changeDetection: ChangeDetectionStrategy.OnPush (which is a good idea to improve performance) then the good solution is to get markForCheck() fired each time you resize the window, but with debounceTime so you will get some time to wait before you resize the chart:

    import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
    import { fromEvent } from 'rxjs';
    import { debounceTime } from 'rxjs/operators';
    
    @Component({
      selector: 'my-component',
      templateUrl: 'my-component.html',
      styleUrls: ['./my-component.scss'],
      changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class MyComponent implements OnInit {
      constructor(private _cdRef: ChangeDetectorRef) {
      }
    
      ngOnInit(): void {
        fromEvent(window, 'resize') // get the event observable
          .pipe(debounceTime(200)) // you can change debounceTime to whatever you want
          .subscribe((event) => {
            this._cdRef.markForCheck(); // Here we go
          });
      }
    }
    

    As the chart itself seems to be responsive and should be redrawn each window change, this will do the trick.