0

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?

Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
  • If you on your ReziseHandler read the actual width that you want your charts to be, you could pass this as a parameter to the `drawChart` function and then specify the width in the options of the chart, maybe? – Henrik Aronsson Jul 08 '16 at 08:02
  • @HenrikAronsson The problem isn't really the charts, it's the component that the charts are drawn on. The `ScrollPanel` grows, and the `VerticalPanel` takes up `100%` of its width, and then the `SimplePanels` that the charts are drawn on take up `100%` of that. Those are all the correct size. The problem is that what `100%` is doesn't change as the size decreases. – Kevin Workman Jul 08 '16 at 13:08

1 Answers1

2

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.)

Community
  • 1
  • 1
Andrei Volgin
  • 40,755
  • 6
  • 49
  • 58
  • Thanks for the reply, but wrapping the calls inside a `Scheduler` doesn't seem to have an effect. And flexbox seems to be an html and css thing, but I'm using GWT. My real project is much larger than this example project, and I can't simply redo the layout in flexbox instead of GWT. – Kevin Workman Jul 08 '16 at 13:12
  • Replace VerticalPanel with FlowPanel - it's a good idea regardless of this issue. Note that there is no need to set width of a FlowPanel or SimplePanel to 100% - all `div` elements by default take all the width available to them. – Andrei Volgin Jul 08 '16 at 23:54
  • All of my recent apps are in GWT and flexbox, and I try to avoid LayoutPanels of all kinds wherever possible. Google Daniel Kurka's video explaining why MGWT is using flexbox model and no layout panels - the same logic applies to all GWT projects. – Andrei Volgin Jul 08 '16 at 23:55
  • Switching to FlowPanel does seem to fix it. I don't really understand why it fixes it though. I'll google for that video whenever I'm not behind a firewall that blocks me from watching it, but having the explanation in one place would be great too. Either way, thanks for the help. – Kevin Workman Jul 11 '16 at 13:09
  • I added a brief explanation to the answer - it did not fit into the comment. – Andrei Volgin Jul 11 '16 at 18:10
  • A related svg / flexbox issue that I'm trying to figure out: https://stackoverflow.com/questions/49034455/d3-chart-grows-but-wont-shrink-inside-a-flex-div – bentedder Feb 28 '18 at 16:39