Friday, September 2, 2011

PointConfigurator in GWT HighCharts


This is a special post written specifically as an illustration to an enhancement request for GWT HighCharts project in sourceforge, because unfortunately, I have not found any way that sourceforge discussion editor could allow me to insert pictures. However, it might also be informative to anyone interested in deploying client-side/javascripted charts within GWT.

I need to be able to configure Points while the Points are being created/loaded into a Series object. I would set out to extend the Series class and over-ride the addPoint method. Unfortunately, the lone constructor of Series class is protected by package-private (aka default) access restriction.

I have no-eye-deer over why we should not use protected constructor rather than package-private, except in the case of putting up an ineffective barrier against any extension to the class. Which is pointless because I simply spoof the package namespace. Alternative explanation could be, to catch the exception that if someone had caught a good-eye-deer, to encourage that good-eye-deer be placed into the pot of roast for everyone else to enjoy. Alright then, here is the good-eye-deer that the general public should enjoy.
package org.moxieapps.gwt.highcharts.client;
import org.moxieapps.gwt.highcharts.client.Point;
import org.moxieapps.gwt.highcharts.client.Series;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONValue;

public class QSeries extends Series {
  public QSeries(BaseChart <Chart> chart, PointConfigurator cfgr){
    super(chart);
    this.cfgr = cfgr;
  }

  private PointConfigurator cfgr;

  @Override
  public Series addPoint(Point point, boolean redraw, boolean shift,
      Animation animation) {
    cfgr.configure(point);
    super.addPoint(point, redraw, shift, animation);
    return this;
  }

  public interface PointConfigurator {
    public void configure(Point p);
  }
}
The main eye-deer behind the class extension is the PointConfigurator interface and code inserted into the addPoint method to run the configure method just before the Point is added into the Series object. So that, I could define a PointConfigurator implementation - for example, the following implemetation that would colourise any Point or modify the Marker of any Point that falls into an "interesting" range.
  public class RangeConfigurator
  implements PointConfigurator{

    @Override
    public void configure(Point p) {
      double region =
        // inequality of area within a circle/ellipse:
        Math.pow(p.getX().intValue() -50,2) +
        Math.pow( (p.getY().intValue()-100000)/2000, 2);

      if (region< 100)
        p.setMarker(m1);
      
      else if (region< 300)
          p.setMarker(m2);
    }
    
    final static private Marker m1 = new Marker();
    final static private Marker m2 = new Marker();
    final static private Color red = new Color(222, 63, 63);
    final static private Color green = new Color(63, 222, 63);
    {
      m1.setFillColor(red);
      m2.setFillColor(green);
    }
  }

As a side dish,
  final static private Number[][] mkRandomArray(int count){
    Number[][] ranarray = new Number[count][];
    for(int i=0; i < count; i++ ){
      ranarray[i] = new Number[]{(int)(Random.nextDouble()*100), Math.abs(Random.nextInt()/10000)};
    }
    return ranarray;
  }
The following resulting plot illustrates what HighCharts GWT does not currently do, but why I made the modification to make it do.

2 comments: