Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Flashing/Blinking while replacing Chart canvas on timer thread in IE only

    Hi Isomorphic,

    We are experiencing a Chart flashing/blinking behaviour in IE11 when the replacement of the canvas happens in a timer thread. This is not a problem for Chrome or Firefox.

    This is a regression, as it did not occur in the following SmartGWT version.

    SmartClient Version: SNAPSHOT_v10.1d_2015-10-25/Pro Deployment (built 2015-10-25)

    We don't know exactly when the issue starting happening, however, we have confirmed it became an issue as far back as the following SmartGWT version.

    SmartClient Version: v10.1p_2016-04-28/Pro Deployment (built 2016-04-28)

    We are currently using the following SmartGWT version, which still exhibits the issue.

    SmartClient Version: v10.1p_2016-11-13/Pro Deployment (built 2016-11-13)

    We have created a very simple test case to demonstrate the behaviour.

    Click the Flash button to replace the canvas using a Timer thread. (Reproduces the issue)
    Click the No Flash button to replace the canvas not using a Timer thread.

    Sandbox9.java
    Code:
    package com.sandbox.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.user.client.Timer;
    import com.sandbox.client.data.SimpleChartData1;
    import com.sandbox.client.data.SimpleChartData2;
    import com.smartgwt.client.core.KeyIdentifier;
    import com.smartgwt.client.types.ChartType;
    import com.smartgwt.client.util.Page;
    import com.smartgwt.client.util.PageKeyHandler;
    import com.smartgwt.client.util.SC;
    import com.smartgwt.client.widgets.Button;
    import com.smartgwt.client.widgets.Canvas;
    import com.smartgwt.client.widgets.Window;
    import com.smartgwt.client.widgets.chart.FacetChart;
    import com.smartgwt.client.widgets.cube.Facet;
    import com.smartgwt.client.widgets.events.ClickEvent;
    import com.smartgwt.client.widgets.events.ClickHandler;
    import com.smartgwt.client.widgets.layout.VLayout;
    
    public class Sandbox9 implements EntryPoint {
    
        private Canvas currentCanvas;
        private int counter = 0;
    
        @Override
        public void onModuleLoad() {
            final Window window = new Window();
            window.setHeight100();
            window.setWidth100();
    
            VLayout layout = new VLayout();
            layout.setWidth100();
            layout.setHeight100();
            Button buttonFlash = new Button();
            buttonFlash.setTitle("Flash");
            buttonFlash.addClickHandler(new ClickHandler() {
    
                @Override
                public void onClick(ClickEvent event) {
                    Timer scheduleReplace = new Timer() {
                        @Override
                        public void run() {
                            replaceCanvas(window);
                        }
                    };
                    scheduleReplace.schedule(0);
                }
            });
    
            Button buttonNoFlash = new Button();
            buttonNoFlash.setTitle("No Flash");
            buttonNoFlash.addClickHandler(new ClickHandler() {
    
                @Override
                public void onClick(ClickEvent event) {
                    replaceCanvas(window);
                }
            });
    
            layout.addMember(buttonFlash);
            layout.addMember(buttonNoFlash);
            layout.addMember(window);
            layout.draw();
        };
    
        private void replaceCanvas(Window window) {
            if (currentCanvas != null) {
                window.removeItem(currentCanvas);
                if (currentCanvas instanceof FacetChart) {
                    ((FacetChart) currentCanvas).destroyItems();
                }
                currentCanvas.destroy();
            }
            FacetChart chart = getChart();
            currentCanvas = chart;
            window.setTitle("Some Title");
            window.addItem(chart);
            window.show();
        }
    
        private FacetChart getChart() {
            FacetChart chart;
            if ((counter % 2) == 0) {
                chart = new FacetChart();
                chart.setData(SimpleChartData1.getData());
                chart.setFacets(new Facet("product", "Product"));
                chart.setValueProperty("sales");
            } else {
                chart = new FacetChart();
                chart.setData(SimpleChartData2.getData());
                chart.setFacets(new Facet("other", "Other"));
                chart.setValueProperty("count");
            }
            counter++;
            chart.setChartType(ChartType.PIE);
            return chart;
        }
    }
    SimpleChartData1.java
    Code:
    package com.sandbox.client.data;
    
    import com.smartgwt.client.data.Record;
    
    public class SimpleChartData1 extends Record {
        public SimpleChartData1(String product, Integer sales) {
            setAttribute("product", product);
            setAttribute("sales", sales);
        }
    
        public static SimpleChartData1[] getData() {
            return new SimpleChartData1[] { new SimpleChartData1("West-Cars", 37), new SimpleChartData1("North-Cars", 29),
                    new SimpleChartData1("East-Cars", 80), new SimpleChartData1("South-Cars", 87),
    
                    new SimpleChartData1("West-Trucks", 23), new SimpleChartData1("North-Trucks", 45), new SimpleChartData1("East-Trucks", 32),
                    new SimpleChartData1("South-Trucks", 67),
    
                    new SimpleChartData1("West-Motorcycles", 12), new SimpleChartData1("North-Motorcycles", 4), new SimpleChartData1("East-Motorcycles", 23),
                    new SimpleChartData1("South-Motorcycles", 45) };
        }
    }
    SimpleChartData2.java
    Code:
    package com.sandbox.client.data;
    
    import com.smartgwt.client.data.Record;
    
    public class SimpleChartData2 extends Record {
        public SimpleChartData2(String other, Integer sales) {
            setAttribute("other", other);
            setAttribute("count", sales);
        }
    
        public static SimpleChartData2[] getData() {
            return new SimpleChartData2[] { new SimpleChartData2("A", 10), new SimpleChartData2("B", 20), new SimpleChartData2("C", 30),
                    new SimpleChartData2("D", 40) };
        }
    }
    Thanks

    Click image for larger version

Name:	IE11_version.jpg
Views:	221
Size:	18.2 KB
ID:	241541

    #2
    Could you better characterize the flashing/blinking? We may not see the same thing due to differences in machine speed, OS, OS themes etc.

    Why are you calling destroyItems() when you already call destroy() on the chart as a whole in the next line? This isn't necessary, and could be the cause of the flashing/blinking.

    Comment


      #3
      For example, if we had a pie chart, with the pie solid red, you can see a transition from solid red, to white, back to solid red (if no change in chart and/or data), or in the case of a change of chart and/or data, from solid red, to white, to say 1/2 red and 1/2 green. This creates what we call a "flashing" or "blinking" effect that we only see on IE11. In other browsers, or in IE11 with the earlier SmartGWT release, you don't see the transition "white", so the transition from solid red to solid red would appear as if nothing changed during the refresh, and a transition from solid red to 1/2 red, 1/2 green would switch instantly from solid red to 1/2 red, 1/2 green with no transition "white" flashing in-between.
      I hope that helps.

      Comment


        #4
        Why are you calling destroyItems() when you already call destroy() on the chart as a whole in the next line? This isn't necessary, and could be the cause of the flashing/blinking.
        This was written and originally tested quite some time ago, however, I recall during that original testing, there were indications of growing memory usage that pointed to the destruction of the chart canvases that this strategy resolved for us. These refreshes are automatic and can happen quite frequently. There might have been some other quirks that we were addressing at the time as well, but honestly, it was quite some time ago. This is something we wouldn't want to change lightly at this point, given it worked exceptionally when originally released.

        Comment


          #5
          I want to provide an additional detail to avoid you going down the wrong path. We can actually reproduce this where the canvas is a ListGrid, rather than a Chart, which would indicate the call to destroyItems() is not the source of the issue, and ultimately not specifically related to Charts either.

          Comment


            #6
            The general issue is that we don't really have complete control over when the browser performs a low-level repaint. Even when perform operations as close to "atomically" as we can, sometimes the browser chooses to do a repaint that shows partially completed actions, and this can differ by machine or from run to run. We've even seen the behavior change in a minor update.

            Please try out removing the destroyItems() call - if that's the culprit, we need to know that before considering various options.

            As far as a grid similarly flashing, does that happen for you only in IE11, or across multiple browsers?

            Comment


              #7
              The grid similarly flashing is happening only in IE too. I would have to confirm if these issues are present in other IE versions or isolated to IE11.
              I will experiment with the removal of destroyItems() for charts and follow up on that question.
              Regards

              Comment


                #8
                Hi Isomorphic,

                I wanted to follow up to let you know that in the sample provided, if you remove the call to destroyItems(), the same flashing problem persists (only in IE). The flashing does not appear to be related to destroyItems(), which is consistent with the finding that the ListGrid scenario flashes too (only in IE).

                Regards

                Comment


                  #9
                  A quick follow-up here. So far, we're seeing a flash of white in redrawing Charts, like you describe, on all browsers (IE11, FF50, Chrome 54 on Windows 8) on both older 2015 builds and recent builds.

                  As we mentioned, we don't have control over whether/when the browser repaints.

                  How many machines have you tried and what OS are they running?

                  Are all the machines you've tried using identical hardware?

                  Comment


                    #10
                    How many machines have you tried and what OS are they running?
                    >> I personally have used MacOS and Windows7, and have never experienced the white flash on anything other than IE.
                    >> QA uses a variety of OSs.

                    Are all the machines you've tried using identical hardware?
                    >> No.

                    Given your feedback, I would say that perhaps we are not referring to the same "flash". With the sample code, running on IE, the difference is night and day between clicking the "Flash" and "No Flash" buttons. The behaviour on all browsers (FF, Chrome) in our experience, other than IE, is as expected, no complaints there what so ever. On IE, there is a clear difference, where the entire canvas turns white and a delay before the canvas redraws. On other browsers, for example, the chart simply changes from one set of pie slice colors to another set of pie slice colors seamlessly. In the case of the ListGrid canvas, it is as if the ListGrid never disappeared when using the other browsers, yet on IE, it clearly disappears and redraws after a slight delay. Unfortunately, IE clearly behaves differently with respect to how it is choosing to repaint under this scenario based on our observations. I will note that from time to time, IE does repaint as expected, but that is an exception, not the norm.

                    Regards

                    Comment


                      #11
                      OK, we will try a few more machines and people, and see if we can find an environment where there's a clear IE-specific flash.

                      Comment


                        #12
                        Just an update: we know what the cause is. It has nothing to do with IE and we have yet to find a single machine that only flashes on IE, so we are now treating that as a "red herring".

                        For background: like all UI frameworks, we delay doing certain redrawing or re-layout tasks because applications frequently do several changes at once (eg, making multiple changes to a complex layout) and running redraw/relayout code over and over makes this extremely slow.

                        Using timers to do delayed redraw/relayout work causes flashing, so to avoid this we run required redrawing/relayout actions at the end of the JavaScript thread when all other processing is done. We are able to figure out the thread entry and exit points for all UI events via listeners, and for timers via providing our own setTimeout() in JavaScript.

                        The problem is, when GWT's Scheduler API is used we don't have a way to detect thread exit, and so delayed redraw/relayout actions happen on a timer, hence all browsers intermittently show a visible flash, depending on random details of how fast the machine is, how many tabs are open, what other processes are running in the OS, etc.

                        We're looking at different approaches to avoid this; we may need to provide a thin wrapper around the Scheduler API that you can call instead, so we can detect thread start and exit in that case too.

                        Comment


                          #13
                          We've applied a fix to SGWT 5.1p and newer releases to help address the flashing issue you reported. It will be in the nightly builds dated 2016-12-23 and beyond. You'll still need to make a change to your sample code, though, to ensure it doesn't generate a "flash" - after the call to addItem() in replaceCanvas() you'll need to add the line:
                          Code:
                          ((Layout)window.getBody()).reflowNow();
                          This will ensure that the new chart gets drawn immediately, inside the replaceCanvas() method, rather than happening on a delay.

                          More generally, if you encounter a specific scenario of "flashing" in the future that only happens when running code from a GWT Timer, adding a reflowNow() to the parent of the affected layout member may correct the problem. However, you definitely must not start adding reflowNow() calls "just in case" as this will severely degrade performance. You should only add a call like that in this very specific circumstance of a "flash" or similar delayed update that only happens when running code from a GWT Timer.

                          In the future, we do plan to add a wrapper to SmartGWT for GWT Timers that will avoid the need for the above workaround, but we don't have a specific timeline or release for that.

                          Comment


                            #14
                            Note that we've added a new class, SmartGwtTimer, documented here, that offers the same public APIs as GWT's Timer and should avoid the "flash." It's now present in SGWT 6.0p and newer releases and is in the nightly builds dated 2017-01-05 and beyond

                            Comment


                              #15
                              Thank you. I will experiment with this and follow up as soon as I have some feedback.
                              Regards

                              Comment

                              Working...
                              X