Kevin Workman
Kevin Workman

Reputation: 42176

GWT Google Charts grow but don't shrink

I'm using GWT (version 2.7) and the Google Charts JavaScript API to draw a series of charts inside a GWT application.

I'm trying to display multiple charts in a scroll panel, with a data section on the right. The data section is a fixed width, and the scroll panel containing the charts should take up the rest of the window width. The size of the charts should change when the window size changes. Here's a picture:

I have this mostly working. The charts grow as I increase the size of the window, but then the chart area doesn't shrink as I decrease the size of the window!

I would like the chart area to grow and shrink according to the size of the window. Right now the growing part works, but not the shrinking part.

Here's the code for the example:

package com.example.gwtcharttest.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;


public class GwtChartTest implements EntryPoint {

    public void onModuleLoad() {

        final SimplePanel chartDivOne = new SimplePanel();
        chartDivOne.getElement().setId("chartDiv_1");
        chartDivOne.setHeight("300px");
        chartDivOne.setWidth("100%");

        final SimplePanel chartDivTwo = new SimplePanel();
        chartDivTwo.getElement().setId("chartDiv_2");
        chartDivTwo.setHeight("300px");
        chartDivTwo.setWidth("100%");

        final SimplePanel chartDivThree = new SimplePanel();
        chartDivThree.getElement().setId("chartDiv_3");
        chartDivThree.setHeight("300px");
        chartDivThree.setWidth("100%");

        VerticalPanel chartsPanel = new VerticalPanel();
        chartsPanel.setWidth("100%");
        chartsPanel.add(chartDivOne);
        chartsPanel.add(chartDivTwo);
        chartsPanel.add(chartDivThree);

        ScrollPanel chartsScrollPanel = new ScrollPanel(chartsPanel);

        DockLayoutPanel dlp = new DockLayoutPanel(Unit.PX);
        dlp.addEast(new Label("some data here"), 200);
        dlp.add(chartsScrollPanel);

        RootLayoutPanel.get().add(dlp);

        loadLibrary();

        Window.addResizeHandler(new ResizeHandler() {

            @Override
            public void onResize(ResizeEvent event) {
                drawChart("chartDiv_1");
                drawChart("chartDiv_2");
                drawChart("chartDiv_3");
            }
        });
    }

    private native void drawChart(String chartDivId)/*-{

          var data = $wnd.google.visualization.arrayToDataTable([
            ['City', '2010 Population',],
            ['New York City, NY', 8175000],
            ['Los Angeles, CA', 3792000],
            ['Chicago, IL', 2695000],
            ['Houston, TX', 2099000],
            ['Philadelphia, PA', 1526000]
          ]);

          var options = {
            title: 'Population of Largest U.S. Cities',

            hAxis: {
              title: 'Total Population',
              minValue: 0
            },
            vAxis: {
              title: 'City'
            }
          };

          var chart = new $wnd.google.visualization.ColumnChart($wnd.document.getElementById(chartDivId));
          chart.draw(data, options);
    }-*/;

    private native void loadLibrary()/*-{
        $wnd.google.charts.load('current', {
            packages : [ 'corechart' ]
        });
    }-*/;
}

And here is the html file. The only thing of note here is that I'm including the Google Charts JavaScript api in the head section:

<!doctype html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link type="text/css" rel="stylesheet" href="GwtChartTest.css">
    <title>GWT Chart Test</title>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript" language="javascript" src="gwtcharttest/gwtcharttest.nocache.js"></script>
  </head>

  <body>
  </body>
</html>

I gather that the ScrollPanel is never decreasing its size even when its parent DockLayoutPanel decreases in size. How can I guarantee that the charts continue to respect the size of the window, even when it decreases?

Upvotes: 0

Views: 519

Answers (1)

Andrei Volgin
Andrei Volgin

Reputation: 41089

You may need to wrap your calls to draw charts in a Scheduler. They are made before Window > DockLayoutPanel > ScrollPanel chain has a chance to resize.

Alternatively, if you support only modern browsers, I would recommend moving to a flexbox layout model, which is much more efficient and flexible (pun intended) as it uses native browser reflow instead of JavaScript.

EDIT:

The solution was to replace VerticalPanel with FlowPanel.

VerticalPanel extends CellPanel, which resolves to a table in HTML. It has a different layout mechanism than a simple div, and generally should be avoided unless there is a very specific reason to use it and no CSS-based solution is available. In general, we should try to stay as close to browser native layout mechanism (FlowPanel, HTMLPanel, CSS) as possible both for performance reasons and to get predictable consistent behavior. Once you mix native and JS-forced layouts, you have to be very careful about the sequence of events as changes made by JS code (e.g. resizing an element) may force the browser to reflow/re-render the entire page again, which may in turn result in more JS changes through ProvidesResize/RequiresResize mechanism implemented in many widgets (DockLayoutPanel, ScrollPanel, etc.)

Upvotes: 2

Related Questions