Circular gauge flashes when bound value changes

Hello,

I'm working with the ej2 Circular Gauge to display live data in a Circular Gauge within a component. The component's data comes from an observable in a separate service that polls an HTTP endpoint on a 1000ms interval. The data is retrieved and bound correctly, but the Circular Gauge appears to completely redraw itself each time the bound value is updated, which creates a very jarring and unappealing appearance. The other, non gauge data in the component comes from the same endpoint but those datapoints update without the "flashing" appearance of the gauge. 

Is there some way to address this behavior in the gauge's configuration? I'm attaching an archive containing a short video to demonstrate the behavior I'd like to eliminate.

Thanks!

Sean

Attachment: syncfusiondemo_dc8d83af.zip

7 Replies 1 reply marked as answer

SB Swetha Babu Syncfusion Team February 2, 2021 01:50 PM UTC

Hi Sean,

Thank you for contacting Syncfusion support.

We can update the pointer value of Circular gauge control to display the live data. We suspect that you are using the refresh() method to update the pointer value which will re-render the component once called. So you are facing the flickering effect in the control. We can also update the pointer value using the setPointerValue() method. We have created a simple angular sample to demonstrate the same. Please find the StackBlitz link for your reference below.

https://stackblitz.com/edit/angular-zxyhjr?file=app.component.html 

In the above sample, we have rendered a gauge with ranges and a pointer updating within 1000 s using the setInterval.

Please let us know whether you are using the refresh() method to update the pointer value. If you are using that method, please use the setPointerValue() method to update the pointer. If you are still facing the reported issue, please share us the code snippet to reproduce the reported issue. It will be helpful for us to analyze further and assist you better.

Regards,
Swetha Babu 


Marked as answer

SP Sean Parker February 2, 2021 04:58 PM UTC

Hi Swetha,

Thanks for your prompt reply. As it turns out, it was not an issue with the Syncfusion control at all...I had simply neglected to use a trackBy: function in the *ngFor loop in the component's parent, so the entire DOM within the loop was being destroyed/recreated each iteration. I actually wasn't using refresh(), but was instead just binding to a template variable in markup like so: <e-pointer value={{generator.power}} [animation]="animation"...is there any reason not to do it this way?

Sorry for the false alarm! I did learn some useful things from the example you provided, thank you very much for that.

Thanks again,

Sean


SB Swetha Babu Syncfusion Team February 3, 2021 01:15 PM UTC

Hi Sean, 
  
Thank you for your update. 
  
We can also update the pointer value of the Circular Gauge control to display the live data by using the property binding when the animation is not enabled. You can use value property in the pointers or setPointerValue() method to update the pointer. However, we have created a simple angular sample to update the value by property binding and it can be viewed from the below StackBlitz link. 
  
  
Please find the code snippet for the same below. 
this.tooltipInterval1 = setInterval((): void => { 
      let newVal: number = Math.random() * (2500 - 200) + 200; 
      if (document.getElementById("container5")) { 
        this.fifthgauge.axes[0].pointers[0].value = newVal; 
      } else { 
        clearInterval(this.tooltipInterval1); 
      } 
    }, 1000); 
  
Please let us know if you need any further assistance. 
  
Regards, 
Swetha Babu 



SP Sean Parker February 3, 2021 06:56 PM UTC

Swetha,

I actually would like to use the setPointer() approach so that we can take advantage of animation, but am having some trouble. I have configured my component closely following the example you provided, but any call I make to setPointerValue() (even with a hardcoded value) fails with this error: "ERROR TypeError: Cannot read property 'min' of undefined".

This is the relevant code:

Markup:
<ejs-circulargauge #circulargauge id="gauge-{{generator.id}}width="173height="150">
                <e-axes>
                    <e-axis 
                        startAngle=210 
                        endAngle=70 
                        minimum=0
                        maximum=2500
                        [lineStyle]="lineStyle"
                        [labelStyle]="labelStyle"
                        [majorTicks]="majorTicks
                        [minorTicks]="minorTicks"
                        [pointers]="pointers">
                        <e-ranges>
                            <e-range start=250 end=1100 radius="74color="#4BAE40">e-range>
                            <e-range start=1100 end=2500 radius="74color="#C0E4A0">e-range>
                        e-ranges>
                    e-axis>
                e-axes>
            ejs-circulargauge>

Component:
  public pointers: Object[] = [{
    value: 0,
    animation: { enable: true, duration: 300 }, 
    cap: { radius: 5, color: '#000' }, 
    needleTail: { length: '5', width: 2 }, 
    color: '#333', 
    radius: '80%', 
    pointerWidth: 5
  }];
  @ViewChild('circulargauge', { static: true })
  public circulargauge: CircularGaugeComponent;

  ngAfterViewInit(): void {
    console.log('gauge', this.circulargauge);
    this.circulargauge.setPointerValue(0, 0, 500);
  }


The gauge object is present and is logged to the console (see screenshot), but the setPointer() call fails with the error I mentioned. What am I missing?

** EDIT: I have just confirmed that you can recreate the problem I'm talking about in your StackBlitz example (the first one) by removing the timeout. For example, this edit to the StackBlitz component produces the same error:

import { Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { CircularGaugeComponent, ILoadedEventArgs, GaugeTheme } from '@syncfusion/ej2-angular-circulargauge';

/**
 * Sample for default circular gauge
 */
@Component({
    selector: 'app-root',
    templateUrl: 'app.component.html',
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    @ViewChild('fifthgauge')
    public fifthgauge: CircularGaugeComponent;
    public tooltipInterval1: number;
  public lineStyle5: Object = { width: 5, color: 'grey' };
    public labelStyle5: Object = {
        position: 'Inside',
        font: { size: '12px', color: 'grey' }
    };
    public majorTicks1: Object = {
        width: 1,
        height: 10,
        interval: 625
    };
    public minorTicks1: Object = {
        height: 5,
        width: 1,
        interval: 208
    };
    public pointers5: Object[] = [{
        radius: '100%',
        animation: { enable: true, duration: 900 },
        value: 70,
        pointerWidth: 6,
        cap: { radius: 7 },
        needleTail: { length: '7%', color: '#923C99' }

    }];
    ngAfterViewInit(): void {
        if (document.getElementById('container5')) {
            this.fifthgauge.setPointerValue(0, 0, 500);
        }
    }

    constructor() {
        // code
    };
}

Thanks, 

Sean





Attachment: Capture_6e278422.zip


SB Swetha Babu Syncfusion Team February 4, 2021 03:42 PM UTC

Hi Sean,

Thank you for your update.

When we set the pointer value in the ngAfterViewInit() method, the circular gauge will be not rendered at that instance. So the variables in the component will not be available and the value of the minimum value of the range will be undefined. We need to check whether the circular gauge gets rendered or not using the isRendered property in the Circular gauge control. Please find the StackBlitz sample link below for your reference.

https://stackblitz.com/edit/angular-zxyhjr-33uqim?file=app.component.ts 

We have also captured a video when we tested the reported scenario. Please find the video from the below link. 

https://www.syncfusion.com/downloads/support/forum/162086/ze/Circulargauge-2013461376

Please let us know if you need any further assistance.

Regards,
Swetha Babu 



SP Sean Parker February 4, 2021 08:15 PM UTC

Thanks, Swetha, just what I needed. FYI, it might be a good idea to consider making the isRendered property public in a future release. It is currently protected, and attempting to access it can cause compilation errors when using an Angular project hosted in an ASP.NET Core project. I was able to get around the compilation error by using this property accessor syntax, though: this.circulargauge['isRendered'].

One last question: when the pointer's value is set for the first time, the pointer animates from a zero value. Is it possible to enable animation only after the first explicit value is set, so that the pointer is not animating unless changing from an explicitly set value?

Thanks again for your help.

Sean


SB Swetha Babu Syncfusion Team February 5, 2021 02:33 PM UTC

Hi Sean,

Thank you for your update.

 
The isRendered property in the Circular gauge control is a protected property since it is used for internal purposes. Please use the property as you have called (ie. this.circulargauge['isRendered']) in the application to resolve the compilation error.

 
When the Circular gauge is rendered initially the value of the pointer will be zero. So when the value set in the pointers property is rendered, the animation will start from zero. This is the behavior of the component. So we cannot make animation when pointer value is set explicitly in the control. 

Please let us know if you need any further assistance.

Regards,
Swetha Babu 


Loader.
Up arrow icon