Menu

Chart does not deliver any InnerHTML

Huan-Hai
2011-08-19
2012-07-13
  • Shawn Quinn

    Shawn Quinn - 2011-08-21

    Hi Huan-Hai,

    Creating sparklines via Highcharts sounds like a pretty slick idea!

    We haven't tried to render a chart via just invoking the widget.getElement().getInnerHTML() method, but I'm doubtful that would work as-is since much of the work to actually render the chart doesn't occur until the Widget's "onLoad()" method is invoked (as we need the widget's primary element to be somewhere in the DOM before we can kick off the Highcharts JS API to actually render the chart into the DOM element.)

    GWT's "onLoad()" and "onUnload()" methods are protected, so unfortunately you wouldn't be able to invoke them manually. Can you post a simplified version of the GWT scenario you're trying, with the CellTable and attempt to place a GWT Highcharts widget within it via getInnerHTML()? I can then give it a closer look here and see if there's a cleaner way to make that case work. One possibility may be for us to move the logic that actually performs the Highcharts rendering into a public method so you could invoke it manually after you know the widget's HTML has been added to the DOM.

    Thanks,

       -Shawn
    
     
  • Huan-Hai

    Huan-Hai - 2011-08-22

    Hi Shawn!

    Thank you for your response.

    private static class PerformanceCell extends AbstractCell<HierarchyElementDto> implements Cell<HierarchyElementDto> {
    
            @Override
            public void render(com.google.gwt.cell.client.Cell.Context context,
                    HierarchyElementDto value, SafeHtmlBuilder sb) {
    
                  if (value == null) {
                    return;
                  }
    
                  PerformanceWidget widget = new PerformanceWidget(value, true,true);
                  sb.append(SafeHtmlUtils.fromSafeConstant(widget.getElement().getInnerHTML()));
            }
        }
    

    This is the part were we define our own cell for the CellTable
    The PerformanceWidget is our self-defined widget containing the sparkline created by Highcharts.

    Inside the PerformanceWidget we have a Panel, were we add a new object of our Sparkline class:

    sparklinePanel.add(new Sparkline(hierarchyElement));
    

    This is the upper part of our Sparkline class:

    public class Sparkline extends Composite {
    
        public Sparkline(HierarchyElementDto hierarchyElement) {
            initWidget(addSparkline(hierarchyElement).asWidget());
        }
    
        private Chart addSparkline(HierarchyElementDto hierarchyElement) {
            ArrayList<ValuePeriodNamePairDto> performanceList = Util.getPerformanceList(hierarchyElement, true);
            if (!performanceList.isEmpty()) {
    
                Chart chart = new Chart();
    
                chart.setType(Type.LINE);
                chart.setMargin(0, 0, 0, 0);
    
                chart.setChartTitleText("");
                chart.setWidth(60);
                chart.setHeight(25);
    
                chart.getXAxis().setOption("labels/enabled", false);
                chart.setOption("legend/enabled", false);
                chart.setOption("tooltip/enabled", false);
                chart.getYAxis().setMaxPadding(0);
                chart.getYAxis().setMinPadding(0);
                chart.getYAxis().setEndOnTick(false);
                chart.getYAxis().setOption("labels/enabled", false);
                chart.getYAxis().setMax(1);
                chart.getYAxis().setMin(0);
    ...
    ...
    ...
    

    I really appreciate our efforts! Thank you a lot!

    Huan-Hai

     

    Last edit: Huan-Hai 2011-08-22
  • Shawn Quinn

    Shawn Quinn - 2011-08-25

    Hello Huan-Hai,

    Ok, I did a bit of investigation into this, and I don't have a wonderful solution - but I wanted to let you know what I've discovered.

    1. The way the core Highcharts library works is that when a chart is rendered you need to tell it which DOM element to render the chart into. So, you can't render a chart until the element is somewhere in the browser's DOM tree.

    2. The GWT Highcharts library deals with this by waiting until the GWT "onLoad()" method of the widget to be invoked.

    3. When you call a method like "widget.getElement().getInnerHTML()" or "widget.getElement().getString()", you're never giving GWT a chance to invoke the "onLoad()" method of the widget - which is why you aren't seeing anything appear. Note that you actually do want to use the "getString()" method instead of "getInnerHTML()", as you'll need the full HTML of the widget (not just the inner HTML parts.)

    4. So, in order to make this work, you need to somehow invoke the "onLoad()" method of the widget, after you know that the HTML you got from the "toString()" method has been added to the DOM.

    I'm not an expert on the CellTable workings, so there must be a better way to do this. But, as an example that you can start with, the following does work (but uses a terrible hack of relying on a timer to invoke the "onLoad()" method, so that we know it won't be invoked until after the HTML has been inserted into the DOM):

        private static class ChartCell extends AbstractCell<Contact> implements Cell<Contact> {
    
            @Override
            public void render(com.google.gwt.cell.client.Cell.Context context,
                               Contact value, SafeHtmlBuilder sb) {
                final TestChart widget = new TestChart();
                widget.setChartTitleText("Test")
                    .setMargin(0, 0, 0, 0)
                    .setSize(100, 50)
                    .setCredits(new Credits().setEnabled(false));
                sb.append(SafeHtmlUtils.fromSafeConstant(widget.getElement().getString()));
                Timer timer = new Timer() {
                    @Override
                    public void run() {
                        widget.render();
                    }
                };
                timer.schedule(100);
            }
        }
    
        private static class TestChart extends Chart {
            public void render() {
                onLoad();
            }
        }
    

    I hope that helps! If you figure out a more appropriate way to invoke the "onLoad()" method after the element is safely in the DOM, can you add a post to this thread?

     

    Last edit: Shawn Quinn 2011-08-25

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.