org/objectweb/proactive/benchmarks/timit/util/charts/renderer/HierarchicalBarRenderer.java

00001 /* 
00002  * ################################################################
00003  * 
00004  * ProActive: The Java(TM) library for Parallel, Distributed, 
00005  *            Concurrent computing with Security and Mobility
00006  * 
00007  * Copyright (C) 1997-2007 INRIA/University of Nice-Sophia Antipolis
00008  * Contact: proactive@objectweb.org
00009  * 
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or any later version.
00014  *  
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  * 
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00023  * USA
00024  *  
00025  *  Initial developer(s):               The ProActive Team
00026  *                        http://www.inria.fr/oasis/ProActive/contacts.html
00027  *  Contributor(s): 
00028  * 
00029  * ################################################################
00030  */ 
00031 package org.objectweb.proactive.benchmarks.timit.util.charts.renderer;
00032 
00033 import java.awt.Color;
00034 import java.awt.GradientPaint;
00035 import java.awt.Graphics2D;
00036 import java.awt.Paint;
00037 import java.awt.Stroke;
00038 import java.awt.geom.Rectangle2D;
00039 import java.awt.geom.RoundRectangle2D;
00040 import java.util.Iterator;
00041 
00042 import org.jdom.Element;
00043 import org.jfree.chart.axis.CategoryAxis;
00044 import org.jfree.chart.axis.ValueAxis;
00045 import org.jfree.chart.entity.CategoryItemEntity;
00046 import org.jfree.chart.entity.EntityCollection;
00047 import org.jfree.chart.labels.CategoryItemLabelGenerator;
00048 import org.jfree.chart.labels.CategoryToolTipGenerator;
00049 import org.jfree.chart.plot.CategoryPlot;
00050 import org.jfree.chart.renderer.category.BarRenderer;
00051 import org.jfree.chart.renderer.category.CategoryItemRendererState;
00052 import org.jfree.data.category.CategoryDataset;
00053 import org.jfree.ui.GradientPaintTransformer;
00054 import org.jfree.ui.RectangleEdge;
00055 import org.jfree.util.ObjectList;
00056 
00063 public class HierarchicalBarRenderer extends BarRenderer {
00064 
00068     private static final long serialVersionUID = -9139779432077336720L;
00069 
00070     public static final int INCLUSION_MARGIN = 3;
00071 
00072     public static final int CORNER = 2;
00073 
00074     private int alpha;
00075 
00077     protected ObjectList seriesBarWidthList;
00078 
00079     protected Element[] datasetTree;
00080 
00081     protected Comparable[] series;
00082 
00086     public HierarchicalBarRenderer() {
00087         super();
00088         this.seriesBarWidthList = new ObjectList();
00089         this.alpha = 255; // Bars are opaque by default
00090     }
00091 
00101     public double getSeriesBarWidth(int series) {
00102         double result = Double.NaN;
00103         Number n = (Number) this.seriesBarWidthList.get(series);
00104         if (n != null) {
00105             result = n.doubleValue();
00106         }
00107         return result;
00108     }
00109 
00119     public void setSeriesBarWidth(int series, double width) {
00120         this.seriesBarWidthList.set(series, new Double(width));
00121     }
00122 
00123     public Element[] getDatasetTree() {
00124         return this.datasetTree.clone();
00125     }
00126 
00127     public void setDatasetTree(Element[] datasetTree) {
00128         this.datasetTree = datasetTree.clone();
00129 
00130         // Some value in dataset are used as temp variables
00131         // so we have to init them
00132         for (int i = 0; i < datasetTree.length; i++) {
00133             Iterator it = this.datasetTree[i].getDescendants();
00134             while (it.hasNext()) {
00135                 try {
00136                     ((Element) it.next()).setAttribute("max", "0");
00137                 } catch (ClassCastException e) {
00138                     continue;
00139                 }
00140             }
00141         }
00142     }
00143 
00144     public void setSeries(Comparable[] series) {
00145         this.series = series.clone();
00146     }
00147 
00148     public void setAlpha(int alpha) {
00149         this.alpha = alpha;
00150     }
00151 
00164     protected void calculateBarWidth(CategoryPlot plot, Rectangle2D dataArea,
00165             int rendererIndex, CategoryItemRendererState state) {
00166 
00167         // calculate the bar width - this calculation differs from the
00168         // BarRenderer calculation because the bars are layered on top of one
00169         // another, so there is effectively only one bar per category for
00170         // the purpose of the bar width calculation
00171         CategoryAxis domainAxis = this.getDomainAxis(plot, rendererIndex);
00172         CategoryDataset dataset = plot.getDataset(rendererIndex);
00173         if (dataset != null) {
00174             int columns = dataset.getColumnCount();
00175             int rows = dataset.getRowCount();
00176             double space = dataArea.getWidth();
00177             double maxWidth = space * this.getMaximumBarWidth();
00178             double categoryMargin = 0.0;
00179             if (columns > 1) {
00180                 categoryMargin = domainAxis.getCategoryMargin();
00181             }
00182             double used = space
00183                     * (1 - domainAxis.getLowerMargin()
00184                             - domainAxis.getUpperMargin() - categoryMargin);
00185             if ((rows * columns) > 0) {
00186                 state.setBarWidth(Math.min(used / (dataset.getColumnCount()),
00187                         maxWidth));
00188             } else {
00189                 state.setBarWidth(Math.min(used, maxWidth));
00190             }
00191         }
00192     }
00193 
00218     public void drawItem(Graphics2D g2, CategoryItemRendererState state,
00219             Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
00220             ValueAxis rangeAxis, CategoryDataset data, int row, int column,
00221             int pass) {
00222         // nothing is drawn for null values...
00223         Number dataValue = data.getValue(row, column);
00224         if (dataValue == null) {
00225             return;
00226         }
00227 
00228         // BAR X
00229         double rectX = domainAxis.getCategoryMiddle(column, this
00230                 .getColumnCount(), dataArea, plot.getDomainAxisEdge())
00231                 - state.getBarWidth() / 2.0;
00232 
00233         int seriesCount = this.getRowCount();
00234 
00235         // BAR Y
00236         double value = dataValue.doubleValue();
00237         double base = 0.0;
00238         double lclip = this.getLowerClip();
00239         double uclip = this.getUpperClip();
00240 
00241         if (uclip <= 0.0) { // cases 1, 2, 3 and 4
00242             if (value >= uclip) {
00243                 return; // bar is not visible
00244             }
00245             base = uclip;
00246             if (value <= lclip) {
00247                 value = lclip;
00248             }
00249         } else if (lclip <= 0.0) { // cases 5, 6, 7 and 8
00250             if (value >= uclip) {
00251                 value = uclip;
00252             } else {
00253                 if (value <= lclip) {
00254                     value = lclip;
00255                 }
00256             }
00257         } else { // cases 9, 10, 11 and 12
00258             if (value <= lclip) {
00259                 return; // bar is not visible
00260             }
00261             base = this.getLowerClip();
00262             if (value >= uclip) {
00263                 value = uclip;
00264             }
00265         }
00266 
00267         RectangleEdge edge = plot.getRangeAxisEdge();
00268         double transY1 = rangeAxis.valueToJava2D(base, dataArea, edge);
00269         double transY2 = rangeAxis.valueToJava2D(value, dataArea, edge);
00270         double rectY = Math.min(transY2, transY1);
00271 
00272         double rectWidth = state.getBarWidth();
00273         double rectHeight = Math.abs(transY2 - transY1);
00274 
00275         // draw the bar...
00276         double shift = 0.0;
00277         rectWidth = 0.0;
00278         double widthFactor = 1.0;
00279         double seriesBarWidth = this.getSeriesBarWidth(row);
00280         if (!Double.isNaN(seriesBarWidth)) {
00281             widthFactor = seriesBarWidth;
00282         }
00283         rectWidth = widthFactor * state.getBarWidth();
00284         rectX = rectX + (1 - widthFactor) * state.getBarWidth() / 2.0;
00285         if (seriesCount > 1) {
00286             // needs to be improved !!!
00287             shift = rectWidth * 0.20 / (seriesCount - 1);
00288         }
00289 
00290         Rectangle2D bar = new Rectangle2D.Double(
00291                 (rectX + ((seriesCount - 1 - row) * shift)), rectY,
00292                 (rectWidth - (seriesCount - 1 - row) * shift * 2), rectHeight);
00293 
00294         double rrX, rrY, rrW, rrH;
00295         if (row == 0) {
00296             Iterator it = this.datasetTree[column].getDescendants();
00297             int numElement = -1;
00298             while (it.hasNext()) {
00299                 try {
00300                     Element elt = (Element) it.next();
00301                     numElement++;
00302                     String name = elt.getAttributeValue("name");
00303                     dataValue = Double.valueOf(elt.getAttributeValue("avg"));
00304                     // System.out.println("["+column+"] "+name+" \t-->
00305                     // "+dataValue);
00306                     // BAR X
00307                     rectX = domainAxis.getCategoryMiddle(column, this
00308                             .getColumnCount(), dataArea, plot
00309                             .getDomainAxisEdge())
00310                             - state.getBarWidth() / 2.0;
00311 
00312                     seriesCount = this.getRowCount();
00313 
00314                     // BAR Y
00315                     value = dataValue.doubleValue();
00316                     base = 0.0;
00317                     lclip = this.getLowerClip();
00318                     uclip = this.getUpperClip();
00319 
00320                     if (uclip <= 0.0) { // cases 1, 2, 3 and 4
00321                         if (value >= uclip) {
00322                             return; // bar is not visible
00323                         }
00324                         base = uclip;
00325                         if (value <= lclip) {
00326                             value = lclip;
00327                         }
00328                     } else if (lclip <= 0.0) { // cases 5, 6, 7 and 8
00329                         if (value >= uclip) {
00330                             value = uclip;
00331                         } else {
00332                             if (value <= lclip) {
00333                                 value = lclip;
00334                             }
00335                         }
00336                     } else { // cases 9, 10, 11 and 12
00337                         if (value <= lclip) {
00338                             return; // bar is not visible
00339                         }
00340                         base = this.getLowerClip();
00341                         if (value >= uclip) {
00342                             value = uclip;
00343                         }
00344                     }
00345 
00346                     edge = plot.getRangeAxisEdge();
00347                     transY1 = rangeAxis.valueToJava2D(base, dataArea, edge);
00348                     transY2 = rangeAxis.valueToJava2D(value, dataArea, edge);
00349                     rectY = Math.min(transY2, transY1);
00350 
00351                     rectWidth = state.getBarWidth();
00352                     rectHeight = Math.abs(transY2 - transY1);
00353 
00354                     // draw the bar...
00355                     shift = 0.0;
00356                     rectWidth = 0.0;
00357                     widthFactor = 1.0;
00358                     seriesBarWidth = this.getSeriesBarWidth(row);
00359                     if (!Double.isNaN(seriesBarWidth)) {
00360                         widthFactor = seriesBarWidth;
00361                     }
00362                     rectWidth = widthFactor * state.getBarWidth();
00363                     rectX = rectX + (1 - widthFactor) * state.getBarWidth()
00364                             / 2.0;
00365                     if (seriesCount > 1) {
00366                         // needs to be improved !!!
00367                         shift = rectWidth * 0.20 / (seriesCount - 1);
00368                     }
00369                     rrX = (rectX + ((seriesCount - 1 - row) * shift));
00370                     rrY = rectY;
00371                     rrW = (rectWidth - (seriesCount - 1 - row) * shift * 2);
00372                     rrH = rectHeight;
00373 
00374                     // IMPORTANT NOTE :
00375                     // dev attribute is used to save width of the element
00376                     // min attribute is used to save X position of the element
00377                     // max attribute is used to save the number of child already
00378                     // managed
00379                     if (numElement == 0) {
00380                         elt.setAttribute("dev", "" + rrW);
00381                         elt.setAttribute("min", "" + rrX);
00382                         elt.setAttribute("max", "0");
00383                     } else {
00384                         Element parent = elt.getParentElement();
00385                         // System.out.println(" Parent
00386                         // "+parent.getAttributeValue("name")
00387                         // + " rrX/rrW/child -> "
00388                         // + parent.getAttributeValue("min")+"/"
00389                         // + parent.getAttributeValue("dev")+"/"
00390                         // + parent.getAttributeValue("max") );
00391                         double pW = Double.valueOf(parent
00392                                 .getAttributeValue("dev"));
00393                         double pX = Double.valueOf(parent
00394                                 .getAttributeValue("min"));
00395                         int numChild = Integer.valueOf(parent
00396                                 .getAttributeValue("max"));
00397 
00398                         rrW = pW / parent.getChildren().size();
00399                         rrX = pX + rrW * numChild;
00400                         rrX += HierarchicalBarRenderer.INCLUSION_MARGIN;
00401                         rrW -= HierarchicalBarRenderer.INCLUSION_MARGIN * 2;
00402                         elt.setAttribute("dev", "" + rrW);
00403                         elt.setAttribute("min", "" + rrX);
00404                         parent.setAttribute("max", "" + (numChild + 1));
00405                     }
00406 
00407                     RoundRectangle2D rbar = new RoundRectangle2D.Double(rrX,
00408                             rrY, rrW, rrH, HierarchicalBarRenderer.CORNER,
00409                             HierarchicalBarRenderer.CORNER);
00410 
00411                     Rectangle2D childSumLine = null;
00412                     double childSum = Double.valueOf(elt
00413                             .getAttributeValue("sum"));
00414                     transY1 = rangeAxis.valueToJava2D(base, dataArea, edge);
00415                     transY2 = rangeAxis.valueToJava2D(childSum, dataArea, edge);
00416                     rectY = Math.min(transY2, transY1);
00417 
00418                     childSum = (childSum / dataValue.doubleValue()) * rrH;
00419                     if (childSum < rrH && childSum > 0 && childSum / rrH < 0.95) {
00420                         childSumLine = new Rectangle2D.Double(rrX, rectY, rrW,
00421                                 1);
00422                     }
00423                     Paint itemPaint = this.getItemPaintFromName(name,
00424                             this.series, column);
00425                     GradientPaintTransformer t = this
00426                             .getGradientPaintTransformer();
00427                     if (t != null && itemPaint instanceof GradientPaint) {
00428                         itemPaint = t.transform((GradientPaint) itemPaint, bar);
00429                     }
00430                     g2.setPaint(itemPaint);
00431 
00432                     Color c = g2.getColor();
00433                     g2.setColor(new Color(c.getRed(), c.getGreen(),
00434                             c.getBlue(), this.alpha));
00435                     g2.fill(rbar);
00436                     g2.setColor(Color.DARK_GRAY);
00437                     if (childSumLine != null) {
00438                         g2.fill(childSumLine);
00439                     }
00440 
00441                     // draw the outline...
00442                     if (this.isDrawBarOutline()
00443                             && state.getBarWidth() > BarRenderer.BAR_OUTLINE_WIDTH_THRESHOLD) {
00444                         Stroke stroke = this.getItemOutlineStroke(row, column);
00445                         Paint paint = this.getItemOutlinePaint(row, column);
00446                         if (stroke != null && paint != null) {
00447                             g2.setStroke(stroke);
00448                             g2.setPaint(paint);
00449                             g2.draw(rbar);
00450                         }
00451                     }
00452                 } catch (ClassCastException e) {
00453                     continue;
00454                 }
00455             }
00456         }
00457         // ////////////////////////////
00458 
00459         // draw the item labels if there are any...
00460         double transX1 = rangeAxis.valueToJava2D(base, dataArea, edge);
00461         double transX2 = rangeAxis.valueToJava2D(value, dataArea, edge);
00462 
00463         CategoryItemLabelGenerator generator = this.getItemLabelGenerator(row,
00464                 column);
00465         if (generator != null && this.isItemLabelVisible(row, column)) {
00466             this.drawItemLabel(g2, data, row, column, plot, generator, bar,
00467                     (transX1 > transX2));
00468         }
00469 
00470         // collect entity and tool tip information...
00471         if (state.getInfo() != null) {
00472             EntityCollection entities = state.getEntityCollection();
00473             if (entities != null) {
00474                 String tip = null;
00475                 CategoryToolTipGenerator tipster = this.getToolTipGenerator(
00476                         row, column);
00477                 if (tipster != null) {
00478                     tip = tipster.generateToolTip(data, row, column);
00479                 }
00480                 String url = null;
00481                 if (this.getItemURLGenerator(row, column) != null) {
00482                     url = this.getItemURLGenerator(row, column).generateURL(
00483                             data, row, column);
00484                 }
00485                 CategoryItemEntity entity = new CategoryItemEntity(bar, tip,
00486                         url, data, row, data.getColumnKey(column), column);
00487                 entities.add(entity);
00488             }
00489         }
00490     }
00491 
00492     private Paint getItemPaintFromName(String name, Comparable[] series,
00493             int column) {
00494         for (int i = 0; i < series.length; i++) {
00495             if (series[i].equals(name)) {
00496                 return this.getItemPaint(i, column);
00497             }
00498         }
00499         return null;
00500     }
00501 }

Generated on Mon Jan 22 15:16:04 2007 for ProActive by  doxygen 1.5.1