Package org.timepedia.chronoscope.client.browser

Source Code of org.timepedia.chronoscope.client.browser.Microformats$MicroformatParseResults

package org.timepedia.chronoscope.client.browser;

import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.JsArrayNumber;
import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;

import org.timepedia.chronoscope.client.Chart;
import org.timepedia.chronoscope.client.Dataset;
import org.timepedia.chronoscope.client.Overlay;
import org.timepedia.chronoscope.client.XYPlot;
import org.timepedia.chronoscope.client.HistoryManager;
import org.timepedia.chronoscope.client.browser.json.JsonDatasetJSO;
import org.timepedia.chronoscope.client.canvas.View;
import org.timepedia.chronoscope.client.canvas.ViewReadyCallback;
import org.timepedia.chronoscope.client.overlays.Marker;
import org.timepedia.chronoscope.client.overlays.OverlayClickListener;
import org.timepedia.chronoscope.client.util.DateParser;

import java.util.Date;

/**
* Helper class used to parse microformat annotations in the DOM and turn those
* into charts.
*
* @author Ray Cromwell <ray@timepedia.org>
*/
public class Microformats {

  static Command microformatReadyListener;

  public static void setMicroformatsReadyListener(Command rdy) {
    microformatReadyListener = rdy;
  }

  private static class MicroformatViewReadyCallback
      implements ViewReadyCallback {

    private final Element[] links;

    private final String id;

    private String chartId;

    private final Element elt;

    private MicroformatCountdownLatch latch;

    public MicroformatViewReadyCallback(Element[] links, String id,
        String chartId, Dataset[] ds, Element elt,
        MicroformatCountdownLatch latch) {
      this.links = links;
      this.id = id;
      this.chartId = chartId;
      this.elt = elt;
      this.latch = latch;
    }

    public void onViewReady(View view) {
      Chart chart = view.getChart();
      if (chart == null) {
        return;
      }

      for (int j = 0; j < links.length; j++) {
        String href = DOM.getElementAttribute(links[j], "href");
        int hash = href != null ? href.indexOf("#") : -1;
        if (hash != -1) {
          href = href.substring(hash);
        }

        if (href != null && href.startsWith("#" + chartId)) {

          String date = href.substring(("#" + chartId + ":").length());
          String label = getAttribute(links[j], "accesskey");
          if (label == null) {
            char c[] = new char[1];
            c[0] = (char) ('A' + charCounter);

            label = new String(c);
          }
          final Element[] infoWindow = getElementsByClassName(links[j], "span",
              CMF_PREFIX + "-infowindow");
          final Marker m = new Marker((double) Date.parse(date), label, 0);
          attachOnClick(links[j], m);

          if (infoWindow != null && infoWindow[0] != null) {
            m.addOverlayClickListener(new OverlayClickListener() {
              public void onOverlayClick(Overlay overlay, int x, int y) {
                m.openInfoWindow(DOM.getInnerHTML(infoWindow[0]));
              }
            });
          }
          XYPlot plot = chart.getPlot();
          plot.addOverlay(m);
          String[] hdrs = getTableHeaders(elt);
          if (hdrs != null && hdrs.length > 1) {
            plot.getDomainAxisPanel().getValueAxis().setLabel(hdrs[0]);
            for (int k = 1; k < hdrs.length; k++) {
              plot.getRangeAxis(k - 1).setLabel(hdrs[k]);
            }
          }
        }
      }
      latch.decrement();
      chart.redraw();
    }
  }

  private static final char charCounter = 0;

  private static final String CMF_PREFIX = "cmf";

  private static final String CMF_CHART = CMF_PREFIX + "-chart";

  public static void clickMicroformatLink(Element link, Marker marker) {
    marker.click(1, 1);
  }

  static class MicroformatParseResults {

    public JsArrayString columns = JsArrayString.createArray().cast();

    public JsArray<JsArrayNumber> data = JsArray.createArray().cast();

    public void addColumn(String title) {
      columns.set(columns.length(), title);
    }

    public void setValue(int row, int col, double val) {
      JsArrayNumber arr = data.get(col);
      if (arr == null) {
        arr = JsArrayNumber.createArray().cast();
        data.set(col, arr);
      }
      arr.set(row, val);
    }

    public int getNumDatasets() {
      return data.length();
    }
  }

  static MicroformatParseResults parseMicroformat(String id) {
    com.google.gwt.dom.client.Element e = Document.get().getElementById(id);

    MicroformatParseResults results = new MicroformatParseResults();

    assertTrue("table".equalsIgnoreCase(e.getNodeName()),
        "Table Element with id " + id + " doesn't exist.");

    TableElement te = TableElement.as(e);
    TableSectionElement thead = te.getTHead();
    assertNotNull(thead, "Table must contain THEAD element");
    NodeList<TableRowElement> hrows = thead.getRows();
    assertTrue(hrows.getLength() == 1, "Table THEAD must contain 1 TR element");

    int numCols = 0;

    if (hrows.getLength() == 1) {
      TableRowElement tr = hrows.getItem(0);
      NodeList<TableCellElement> hcols = tr.getCells();
      assertTrue(hcols.getLength() > 1,
          "THEAD TR contains less than 2 columns");
      for (int i = 0; i < hcols.getLength(); i++) {
        TableCellElement th = hcols.getItem(i);
        assertTrue("th".equalsIgnoreCase(th.getNodeName()),
            "Only TH elements should occur in THEAD TR");
        String title = th.getInnerText().trim();
        numCols++;
        if (i == 0) {
          results.addColumn(title);
        } else {
          results.addColumn(title);
        }
      }
    } else {
      throw new JavaScriptException("Table Element must ");
    }

    String dateFormat = "MM-dd-yy";
    NumberFormat numberFormats[] = new NumberFormat[numCols];

    NodeList<com.google.gwt.dom.client.Element> colGroup = te
        .getElementsByTagName("colgroup");
    assertTrue(colGroup != null && colGroup.getLength() == 1,
        "Table must have exactly one COLGROUP element");

    NodeList<com.google.gwt.dom.client.Element> cols = colGroup.getItem(0)
        .getElementsByTagName("col");
    assertTrue(cols != null && cols.getLength() == numCols,
        "COLGROUP must have one COL element for each TH in THEAD");

    for (int i = 0; i < cols.getLength(); i++) {
      com.google.gwt.dom.client.Element col = cols.getItem(i);
      String fmt = col.getAttribute("title");
      String className = col.getClassName();
      if (i == 0) {
        assertTrue(fmt != null && !"".equals(fmt),
            "COL for column 0 must have TITLE attribute containing date");
        assertTrue("cmf-dateformat".equals(className),
            "COL for column 0 must have CLASS of cmf-dateformat");
      }
      if (i == 0) {
        dateFormat = fmt;
      } else {
        if (fmt != null && !"".equals(fmt)) {
          assertTrue("cmf-numberformat".equals(className),
              "Number format COL elements must have class of cmf-numberformat with title containing format according to GWT NumberFormat syntax at http://google-web-toolkit.googlecode.com/svn/javadoc/1.4/com/google/gwt/i18n/client/NumberFormat.html");
          numberFormats[i] = NumberFormat.getFormat(fmt);
        } else if ("cmf-numberformat".equals(className)) {
          assertTrue(fmt != null && !"".equals(fmt),
              "COL has class cmf-numberformat but missing title attribute with format string with syntax http://google-web-toolkit.googlecode.com/svn/javadoc/1.4/com/google/gwt/i18n/client/NumberFormat.html");
          numberFormats[i] = NumberFormat.getFormat(fmt);
        }
      }
    }

    NodeList<TableSectionElement> tbodies = te.getTBodies();
    assertNotNull(tbodies, "Table must contain TBODY elements");
    assertTrue(tbodies.getLength() > 0, "Table must contain TBODY elements");
    int totalAdded = 0;
    for (int i = 0; i < tbodies.getLength(); i++) {
      TableSectionElement tbody = tbodies.getItem(i);
      NodeList<TableRowElement> drows = tbody.getRows();
      for (int j = 0; j < drows.getLength(); j++) {
        TableRowElement row = drows.getItem(j);
        NodeList<TableCellElement> cells = row.getCells();
        assertTrue(cells.getLength() == numCols,
            "Number of TH header columns in THEAD must match number of TD columns in TBODY");

        for (int k = 0; k < cells.getLength(); k++) {
          TableCellElement cell = cells.getItem(k);
          if (k == 0) {
            results.setValue(totalAdded, k,
                DateParser.parse(dateFormat, cell.getInnerText().trim()));
          } else {
            String cellText = cell.getInnerText().trim();
            try {
              double value = numberFormats[k] == null ? Double
                  .parseDouble(cellText) : numberFormats[k].parse(cellText);
              results.setValue(totalAdded, k, value);
            } catch (NumberFormatException e1) {
              // TODO: (ray) ? silently ignore parse errors
            }
          }
        }
        totalAdded++;
      }
    }
    return results;
  }

  private static void assertNotNull(Object obj, String msg) {
    if (obj == null) {
      throw new JavaScriptException(msg);
    }
  }

  private static void assertTrue(boolean cont, String msg) {
    if (!cont) {
      throw new JavaScriptException(msg);
    }
  }

  public static native JsArray<JsonDatasetJSO> importMicroformatTable0(String id,
      Element table) /*-{

          var label="";
 
          var thead = table.getElementsByTagName("thead");
          var labels=[], axes=[], dateformat=null;
          var colgroup = table.getElementsByTagName("colgroup");
          var rangeFormats = [];
          var i = 0;
          if(colgroup && colgroup.item(0)) {
            var cols = colgroup.item(0).getElementsByTagName("col");
            if(cols && cols.length > 0) {
              var datecol=cols.item(0);
              if(datecol.className == "cmf-dateformat") {
                dateformat = datecol.getAttribute('title');
              }
              for(i=1; i<cols.length; i++) {
                var rcol = cols.item(i);
                if(rcol.className == "cmf-numberformat") {
                  rangeFormats[i] = rcol.getAttribute("title");
                }
              }
            }
          }
         
          if(thead && thead.item(0)) {
            var r = thead.item(0).getElementsByTagName("tr");
            var c= r.item(0).getElementsByTagName("th");
            for(i=0; i<c.length; i++) {
               label = c.item(i).innerHTML;
               labels.push(label);
               var axis=c.item(i).getAttribute("axis");
               if(!axis) { axis="default"; }
               axes.push(axis);
            }
          }
          var tbody = table.getElementsByTagName("tbody");

          if(tbody && tbody.item(0))
          {
            var rowList = tbody.item(0).getElementsByTagName("tr");

            var i;
            var domain=[], range=[];
            var numCols = rowList.item(0).getElementsByTagName("td").length;
            for(i=0; i<numCols-1; i++) {
                range.push([]);
            }
            for(i = 0; i<rowList.length; i++)
            {
             var colList = rowList.item(i).getElementsByTagName("td");
             var date = colList.item(0).innerHTML;
             var t = @org.timepedia.chronoscope.client.util.DateParser::parse(Ljava/lang/String;Ljava/lang/String;)(dateformat, date);
             domain.push(t);
              for(j = 1; j<colList.length; j++) {
                  range[j-1].push(parseFloat(colList.item(j).innerHTML));
              }
            }
            var result=[];
            for(i=0; i<numCols-1; i++) {
               result.push({ id: id, domain: domain, range: range[i], label: labels[i+1], axis: axes[i+1],
               format: rangeFormats[i+1]});
            }
            return result;
          }
          return [];
       }-*/;

  public static native JavaScriptObject importTable(String id) /*-{

       var table = $doc.getElementById(id);
       var rowList = table.getElementsByTagName("tr");
       var i;
       var domain=[], range=[];
       for(i = 0; i<rowList.length; i++)
       {
          var colList = rowList.item(i).getElementsByTagName("td");
          domain.push(colList.item(0).innerHTML);
          range.push(colList.item(1).innerHTML);
       }
       return { domain: domain, range: range }
    }-*/;

  public static void initializeMicroformats(Chronoscope chronoscope) {
    Element[] elements = getElementsByClassName(null, "table", CMF_CHART);
    final ChartPanel[] created = new ChartPanel[elements.length];

    final Element[] links = getElementsByClassName(null, "a",
        CMF_PREFIX + "-marker");

    MicroformatCountdownLatch latch = new MicroformatCountdownLatch(
        created.length, microformatReadyListener);
    for (int i = 0; i < elements.length; i++) {
      final Element elt = elements[i];
      final String id = DOM.getElementAttribute(elt, "id");
      if (HistoryManager.getChartById(id) == null) {
        final Dataset[] ds = importMicroformatTable(id, elt);
        Element div = DOM.createDiv();
        final String cid = id + "chrono";
        DOM.setElementAttribute(div, "id", cid);
        DOM.setElementAttribute(div, "class", "chronoscope");
//                DOM.setStyleAttribute(div, "width", "600px");
//                DOM.setStyleAttribute(div, "height", "300px");

        Element par = DOM.getParent(elt);
        DOM.insertBefore(par, div, elt);
        DOM.setStyleAttribute(elt, "display", "none");

        int candidateWidth = DOM.getElementPropertyInt(elt, "clientWidth");
        if (candidateWidth < 600) {
          candidateWidth = 600;
        }
        int candidateHeight = (int) (candidateWidth / 1.618);
        ChartPanel cp = Chronoscope.createTimeseriesChart(div, ds,
            candidateWidth, candidateHeight,
            new MicroformatViewReadyCallback(links, cid, id, ds, elt, latch));
        created[i] = cp;
      }
    }
  }

  static class MicroformatCountdownLatch {

    private int latchCount;

    private Command microformatReadyListener;

    public MicroformatCountdownLatch(int length,
        Command microformatReadyListener) {
      latchCount = length;
      this.microformatReadyListener = microformatReadyListener;
    }

    public void decrement() {
      latchCount--;
      if (latchCount == 0 && microformatReadyListener != null) {
        microformatReadyListener.execute();
      }
    }
  }

  private static native void attachOnClick(Element link, Marker m) /*-{
         link.onclick = function() {
             @org.timepedia.chronoscope.client.browser.Microformats::clickMicroformatLink(Lcom/google/gwt/user/client/Element;Lorg/timepedia/chronoscope/client/overlays/Marker;)(link, m);
         }
    }-*/;

  private static native Element castToElement(JavaScriptObject elt) /*-{
           return elt;
       }-*/;

  private static native String getAttribute(Element link, String attr) /*-{
        return link.getAttribute(attr);
    }-*/;

  private static Element[] getElementsByClassName(Element elt, String tag,
      String className) {
    JavaScriptObject obj = getElementsByClassName0(elt, tag, className);
    Element elts[] = new Element[JavascriptHelper.jsArrLength(obj)];
    for (int i = 0; i < elts.length; i++) {
      elts[i] = castToElement(JavascriptHelper.jsArrGet(obj, i));
    }
    return elts;
  }

  private static native JavaScriptObject getElementsByClassName0(
      JavaScriptObject elt, String tag, String className) /*-{
           var result=[];
           var elem = elt == null ? $doc : elt;
           var elts = elem.getElementsByTagName(tag);
           var i;
           for(i=0; i<elts.length; i++) {
               var elt = elts.item(i);
               if(elt.className && elt.className.indexOf(className) != -1) {
                  result.push(elt);
               }
           }
           return result;
       }-*/;

  private static native JavaScriptObject getMicroformatHeaders(Element table) /*-{


          var thead = table.getElementsByTagName("thead");
          var hdrs=[];
          if(thead && thead.length > 0) {
             var th = thead.item(0).getElementsByTagName("th");
             var i;
             for(i=0; i<th.length; i++) { hdrs.push(th.item(i).innerHTML); }
          }
       return hdrs;
   }-*/;

  private static String[] getTableHeaders(Element table) {
    JavaScriptObject obj = getMicroformatHeaders(table);
    String hdrs[] = new String[JavascriptHelper.jsArrLength(obj)];
    for (int i = 0; i < hdrs.length; i++) {
      hdrs[i] = JavascriptHelper.jsArrGetS(obj, i);
    }
    return hdrs;
  }

  private static Dataset[] importMicroformatTable(String id, Element elt) {
    return Chronoscope.getInstance().createDatasets(importMicroformatTable0(id, elt));
  }
}
TOP

Related Classes of org.timepedia.chronoscope.client.browser.Microformats$MicroformatParseResults

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
div>