jfreechart 学习笔记

1.java 2D主要绘图类描述(jdk1.5)
 Graphics2D //主要绘图对象,每种图形都要通过该对象来绘制
 Rectangle2D //长方形对象
 Point2D //点对象
 Line2D //线对象
 Arc2D.Double //弧形对象
 Ellipse2D //椭圆对象
 Polygon //多边形对象
 Paint //油漆桶对象,用来定义颜色
 Stroke //画笔对象,主要用于描绘轮廓,定义线条样式
 Area //几何建模对象(含几何并交差运算等方法)
 GeneralPath //路径对象
 
 1.1 sample demo eg:
  /**
   * 利用路径对象绘制平面图
   */
  // GeneralPath bar3dRight = new GeneralPath();
  // bar3dRight.moveTo((float) 100.0, (float) 100.0);
  // bar3dRight.lineTo((float) 200.0, (float) 200.0);
  // bar3dRight.lineTo((float) 300.0, (float) 100.0);
  // bar3dRight.lineTo((float) 100.0, (float) 100.0);
  // bar3dRight.closePath();
  // 填充四边形的颜色
  // if (itemPaint instanceof Color) {
  // g2.setPaint(((Color) itemPaint).darker());
  // }
  
  /**
   * 长方形对象加路径对象绘制3D柱状图
   */
  //正视图
  Rectangle2D r2d = new Rectangle2D.Double(
    100.0, //x
    100.0, //y
    30.0, //width
    200.0 //hight
    );
  //右视图
  GeneralPath bar3dRight = new GeneralPath();
  bar3dRight.moveTo((float) 130.0, (float) 100.0);
  bar3dRight.lineTo((float) 150.0, (float) 90.0);
  bar3dRight.lineTo((float) 150.0, (float) 290.0);
  bar3dRight.lineTo((float) 130.0, (float) 300.0);
  bar3dRight.closePath();
  //俯视图
  GeneralPath bar3dTop = new GeneralPath();
  bar3dTop.moveTo((float) 100.0, (float) 100.0);
  bar3dTop.lineTo((float) 130.0, (float) 100.0);
  bar3dTop.lineTo((float) 150.0, (float) 90.0);
  bar3dTop.lineTo((float) 120.0, (float) 90.0);
  bar3dTop.closePath();
  Paint barpaint = Color.PINK; // 实体颜色
  Paint outlinepaint = Color.DARK_GRAY; // 轮廓线颜色
  float dash1[] = { 10.0f };
  // 虚线条描边
  // Stroke stroke = new BasicStroke(1.0f,
  // BasicStroke.CAP_BUTT,
  // BasicStroke.JOIN_MITER,
  // 10.0f, dash1, 0.0f);
  
  // 实线条描边,宽度1.0f
  Stroke stroke = new BasicStroke(1.0f);
  // g2.setColor(Color.PINK);
  // 先设置实体颜色
  g2.setPaint(barpaint);
  g2.setStroke(stroke);
  g2.fill(r2d);
  g2.fill(bar3dRight);
  g2.fill(bar3dTop);
  // 实体填充进绘图对象以后,在设置轮廓线颜色(其实是上面三个实体以外的所有图形的颜色)
  g2.setPaint(outlinepaint);
  g2.draw(r2d);
  g2.draw(bar3dRight);
  g2.draw(bar3dTop);

  /**
   * 利用椭圆对象绘制椭圆
   */
  Ellipse2D ellipse2D = new Ellipse2D.Double(200.0, // x
    100.0, // y
    200.0, // width
    200.0 // hight
  );
  Paint ellipsepaint = Color.blue;
  g2.setPaint(ellipsepaint);
  g2.fill(ellipse2D);
  g2.draw(ellipse2D);

  /**
   * 利用弧形对象绘制弧形
   */
  Arc2D.Double arc = new Arc2D.Double(350.0, // x
    100.0, // y
    200.0, // width
    200.0, // hight
    0.0, // start angle
    90.0, // arc angle
    Arc2D.PIE // pie:3.1415926
  );
  Arc2D.Double arc2 = new Arc2D.Double(350.0, // x
    100.0, // y
    200.0, // width
    200.0, // hight
    -60.0, // start angle
    90.0, // arc angle
    Arc2D.PIE // pie:3.1415926
  );
  Paint arcpaint1 = Color.GREEN;
  Paint arcpaint2 = Color.RED;
  // 设置透明度
  g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
    0.3f));
  g2.setPaint(arcpaint1);
  g2.fill(arc);
  g2.draw(arc);
  g2.setPaint(arcpaint2);
  g2.fill(arc2);
  g2.draw(arc2);

  /**
   * 图形的几何运算
   */
  // Area a = new Area(arc);
  // Area b = new Area(arc2);
  // ab交差运算,去掉两个图形相交的部分得到的图形
  // a.exclusiveOr(b);
  // a交b运算
  // a.intersect(b);
  // a减去b运算,即差运算
  // a.subtract(b);
  // a并b运算
  // a.add(b);
  // g2.setPaint(arcpaint2);
  // g2.fill(a);
  // g2.draw(a);
  
  /**
   * 利用jfreechart的TextBox对象绘制文本框
   */
  // 设置透明度为1,也就是不透明了
  g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
    1.0f));
  TextBox textBox = new TextBox("java" // 想要显示的字符串
  );
  textBox.draw(g2, // 绘图对象
    (float) 550.0, // x坐标
    (float) 100.0, // y坐标
    RectangleAnchor.CENTER // 对齐方式
    );
  Line2D.Double line = new Line2D.Double(522.0, // 线的第一个点的x坐标
    100.0, // 线的第一个点的y坐标
    500.0, // 线的第二个点的x坐标
    120.0 // 线的第二个点的y坐标
  );
  g2.draw(line);

  /**
   * 写字
   */
  // 字体设置
  Font font = new Font(null, // 字体
    Font.ITALIC + Font.BOLD, // 样式(这里设置了两种样式,黑体+斜体)
    10); // 大小
  g2.setFont(font);
  Paint arcpaint3 = Color.BLACK;
  g2.setPaint(arcpaint3);
  g2.drawString("delphi", // 要写的字符串
    550, // x坐标
    150 // y坐标
    );
    
   /**
   * 利用多边形对象绘制多边形
   */
  int []xs = new int[] { 600, 620,
    640, 620 };
  int []ys = new int[] { 100,
    100, 150,
    150};   
  Polygon polygon = new Polygon(
    xs, //多边形x坐标点的数组
    ys, //多边形y坐标点的数组
    4 //数组大小
    );
  g2.setPaint(java.awt.Color.lightGray);
  g2.fill(polygon);
  g2.draw(polygon);
  
  /**
   * 画网格线
   */ 
  for(double i=0.0; i<450.0; i+=30.0){
   // 网格线样式
      Stroke DEFAULT_GRIDLINE_STROKE = new BasicStroke(0.5f,
              BasicStroke.CAP_BUTT,
              BasicStroke.JOIN_BEVEL,
              0.0f,
              new float[] {2.0f, 2.0f},
              0.0f);
      Line2D.Double gridline = new Line2D.Double(0.0,i+30.0,700.0,i+30.0);
      g2.setPaint(Color.GRAY);
      g2.setStroke(DEFAULT_GRIDLINE_STROKE);
      g2.draw(gridline);
  }


2.柱状图2D和3D是通过CategoryPlot的renderer属性来区别的
 BarRenderer //2DBarRenderer
 BarRenderer3D //3DBarRenderer
 CategoryPlot plot = new CategoryPlot(
            dataset, categoryAxis, valueAxis, renderer
        );

3.3D饼图的绘制函数(现在的注释还不够全面,也可能存在错误)
 /**
  * Draws the plot on a Java 2D graphics device (such as the screen or a
  * printer). This method is called by the {@link org.jfree.chart.JFreeChart}
  * class, you don't normally need to call it yourself.
  *
  * @param g2
  *            the graphics device.
  * @param plotArea
  *            the area within which the plot should be drawn.
  * @param anchor
  *            the anchor point.
  * @param parentState
  *            the state from the parent plot, if there is one.
  * @param info
  *            collects info about the drawing (<code>null</code>
  *            permitted).
  */
 public void draw(Graphics2D g2, Rectangle2D plotArea, Point2D anchor,
   PlotState parentState, PlotRenderingInfo info) {

  // adjust for insets...
  RectangleInsets insets = getInsets();
  insets.trim(plotArea);

  Rectangle2D originalPlotArea = (Rectangle2D) plotArea.clone();
  if (info != null) {
   info.setPlotArea(plotArea);
   info.setDataArea(plotArea);
  }

  Shape savedClip = g2.getClip();
  g2.clip(plotArea);

  // adjust the plot area by the interior spacing value
  double gapPercent = getInteriorGap();
  double labelPercent = 0.0;
  if (getLabelGenerator() != null) {
   labelPercent = getLabelGap() + getMaximumLabelWidth()
     + getLabelLinkMargin();
  }

  // 水平方向的间隙
  double gapHorizontal = plotArea.getWidth()
    * (gapPercent + labelPercent);
  // 垂直方向的间隙
  double gapVertical = plotArea.getHeight() * gapPercent;
  // x坐标大小
  double linkX = plotArea.getX() + gapHorizontal / 2;
  // y坐标大小
  double linkY = plotArea.getY() + gapVertical / 2;
  // 图形宽度
  double linkW = plotArea.getWidth() - gapHorizontal;
  // 图形高度
  double linkH = plotArea.getHeight() - gapVertical;

  // make the link area a square if the pie chart is to be circular...
  if (isCircular()) { // is circular?
   double min = Math.min(linkW, linkH) / 2;
   linkX = (linkX + linkX + linkW) / 2 - min;
   linkY = (linkY + linkY + linkH) / 2 - min;
   linkW = 2 * min;
   linkH = 2 * min;
  }

  PiePlotState state = initialise(g2, plotArea, this, null, info);
  // the explode area defines the max circle/ellipse for the exploded pie
  // sections.
  // it is defined by shrinking the linkArea by the linkMargin factor.
  double hh = linkW * getLabelLinkMargin();
  double vv = linkH * getLabelLinkMargin();
  Rectangle2D explodeArea = new Rectangle2D.Double(linkX + hh / 2.0,
    linkY + vv / 2.0, linkW - hh, linkH - vv);

  state.setExplodedPieArea(explodeArea);

  // the pie area defines the circle/ellipse for regular pie sections.
  // it is defined by shrinking the explodeArea by the explodeMargin
  // factor.
  double maximumExplodePercent = getMaximumExplodePercent();
  double percent = maximumExplodePercent / (1.0 + maximumExplodePercent);

  double h1 = explodeArea.getWidth() * percent;
  double v1 = explodeArea.getHeight() * percent;
  Rectangle2D pieArea = new Rectangle2D.Double(explodeArea.getX() + h1
    / 2.0, explodeArea.getY() + v1 / 2.0, explodeArea.getWidth()
    - h1, explodeArea.getHeight() - v1);

  // 定义3D椭圆的高度
  int depth = (int) (pieArea.getHeight() * this.depthFactor);
  // the link area defines the dog-leg point for the linking lines to
  // the labels
  Rectangle2D linkArea = new Rectangle2D.Double(linkX, linkY, linkW,
    linkH - depth);
  state.setLinkArea(linkArea);

  state.setPieArea(pieArea);
  // 定义椭圆中心点
  state.setPieCenterX(pieArea.getCenterX());
  state.setPieCenterY(pieArea.getCenterY() - depth / 2.0);
  // 定义椭圆宽的半径
  state.setPieWRadius(pieArea.getWidth() / 2.0);
  // 定义椭圆高的半径
  state.setPieHRadius((pieArea.getHeight() - depth) / 2.0);
  // 画背景长方形(500*300)区域
  drawBackground(g2, plotArea);
  // 获取外面传进来3D饼图的数据源
  PieDataset dataset = getDataset();  
  // 如果数据源为空则直接返回,整个图表就一个背景长方形没有数据图形
  if (DatasetUtilities.isEmptyOrNull(getDataset())) {
   drawNoDataMessage(g2, plotArea);
   g2.setClip(savedClip);
   drawOutline(g2, plotArea);
   return;
  }

  /**
   * 如果数据源的主键的个数大于图形区域的宽度,则在图形上显示"Too many elements" 数据源示例如下: final
   * DefaultPieDataset result = new DefaultPieDataset();
   * result.setValue("Java", new Double(43.2));
   * result.setValue("VisualBasic", new Double(10.0));
   * result.setValue("C/C++", new Double(17.5));
   * result.setValue("PHP", new Double(32.5));
   * result.setValue("Perl", new Double(1.0));
   * return result;
   * 这个数据源的主键的个数为5
   */
  if (dataset.getKeys().size() > plotArea.getWidth()) {
   String text = "Too many elements";
   Font sfont = new Font("dialog", Font.BOLD, 10);
   g2.setFont(sfont);
   FontMetrics fm = g2.getFontMetrics(sfont);
   int stringWidth = fm.stringWidth(text);

   g2
     .drawString(text, (int) (plotArea.getX() + (plotArea
       .getWidth() - stringWidth) / 2), (int) (plotArea
       .getY() + (plotArea.getHeight() / 2)));
   return;
  }
  
  // if we are drawing a perfect circle, we need to readjust the top left
  // coordinates of the drawing area for the arcs to arrive at this
  // effect.
  // 如果我们画的是一个圆形那只要知道图形的左边距,上边距,和直径
  if (isCircular()) {
   // 圆形半径(取宽高中的小的那个数的一半)
   double min = Math.min(plotArea.getWidth(), plotArea.getHeight()) / 2;
   plotArea = new Rectangle2D.Double(
     plotArea.getCenterX() - min, //左边距(新的图形的中心点x坐标)
     plotArea.getCenterY() - min, //上边距(新的图形的中心点y坐标)
     2 * min, //直径(图形的宽度)
     2 * min //直径(图形的高度)
     );
  }
  
  // 获取数据源主键列表
  List sectionKeys = dataset.getKeys();
  // 如果数据源主键列表为空,退出
  if (sectionKeys.size() == 0) {
   return;
  }

  // establish the coordinates of the top left corner of the drawing area
  //确定pieArea区域的中心点
  double arcX = pieArea.getX();
  double arcY = pieArea.getY();

  // g2.clip(clipArea);
  Composite originalComposite = g2.getComposite();
  g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
    getForegroundAlpha()));
  
  //把数据源每个主键对应的值加起来
  double totalValue = DatasetUtilities.calculatePieDatasetTotal(dataset);
  
  //遍历列表的时候用到
  double runningTotal = 0;
  
  //如果高度<0退出
  if (depth < 0) {
   return; // if depth is negative don't draw anything
  }

  //弧形的列表(用于添加主键的值对应的弧形)
  ArrayList arcList = new ArrayList();
  //定义一个弧行
  Arc2D.Double arc;
  //定义油漆桶,用来填充颜色
  Paint paint;
  Paint outlinePaint;
  //用于描绘轮廓的样式
  Stroke outlineStroke;
  
  //遍历取出主键的值对应的弧形放到弧形列表
  Iterator iterator = sectionKeys.iterator();
  while (iterator.hasNext()) {
   // 取出主键的值
   Comparable currentKey = (Comparable) iterator.next();   
   Number dataValue = dataset.getValue(currentKey);
   
   // 如果主键的值为空,则弧形为空
   if (dataValue == null) {
    arcList.add(null);
    continue;
   }
   
   // 如果主键的值<=0,则弧形为空
   double value = dataValue.doubleValue();
   if (value <= 0) {
    arcList.add(null);
    continue;
   }
   
   //弧形的开始角度(从该角度算起,相当于360度的0度)
   double startAngle = getStartAngle();
   //方向
   double direction = getDirection().getFactor();
   //角度大小1(该主键对应的弧形的开始角度)
   double angle1 = startAngle + (direction * (runningTotal * 360))
     / totalValue;
   //角度大小2(该主键对应的弧形的结束角度)
   double angle2 = startAngle
     + (direction * (runningTotal + value) * 360) / totalValue;
   
   //如果弧形的角度大小<0.00001则该弧形为空
   if (Math.abs(angle2 - angle1) > getMinimumArcAngleToDraw()) {
    arcList.add(new Arc2D.Double(arcX, arcY + depth, pieArea
      .getWidth(), pieArea.getHeight() - depth, angle1,
      angle2 - angle1, Arc2D.PIE));
   } else {
    arcList.add(null);
   }
   
   //转入下个弧形(主键对应的图形)
   runningTotal += value;
  }
  
  //取出剪裁的图形(500*300)
  Shape oldClip = g2.getClip();

  //3D饼图中上面的椭圆
  Ellipse2D top = new Ellipse2D.Double(pieArea.getX(), pieArea.getY(),
    pieArea.getWidth(), pieArea.getHeight() - depth);
  // 3D饼图中底部的椭圆
  Ellipse2D bottom = new Ellipse2D.Double(pieArea.getX(), pieArea.getY()
    + depth, pieArea.getWidth(), pieArea.getHeight() - depth);  
  //底部的长方形
  Rectangle2D lower = new Rectangle2D.Double(top.getX(),
    top.getCenterY(), pieArea.getWidth(), bottom.getMaxY()
      - top.getCenterY());
  //上部的长方形
  Rectangle2D upper = new Rectangle2D.Double(pieArea.getX(), top.getY(),
    pieArea.getWidth(), bottom.getCenterY() - top.getY());
  
  // Area几何建模对象
  Area a = new Area(top);
  a.add(new Area(lower));
  Area b = new Area(bottom);
  b.add(new Area(upper));
  Area pie = new Area(a);
  // 通过几何建模对象对上面的图形进行交叉运算
  pie.intersect(b);

  Area front = new Area(pie);
  // 相减运算
  front.subtract(new Area(top));

  Area back = new Area(pie);
  // 相减运算
  back.subtract(new Area(bottom));

  // draw the bottom circle
  int[] xs;
  int[] ys;
  outlinePaint = getSectionOutlinePaint(0);
  arc = new Arc2D.Double(arcX, arcY + depth, pieArea.getWidth(), pieArea
    .getHeight()
    - depth, 0, 360, Arc2D.PIE);

  // 画出3D饼图下部的椭圆的弧形和有该图形的高度组成的多边形
  int categoryCount = arcList.size();
  for (int categoryIndex = 0; categoryIndex < categoryCount; categoryIndex++) {
   //取出弧形
   arc = (Arc2D.Double) arcList.get(categoryIndex);
   if (arc == null) {
    continue;
   }
   paint = getSectionPaint(categoryIndex);
   outlinePaint = getSectionOutlinePaint(categoryIndex);
   outlineStroke = getSectionOutlineStroke(categoryIndex);
   g2.setPaint(paint);
   //填充弧形
   g2.fill(arc);
   g2.setPaint(outlinePaint);
   g2.setStroke(outlineStroke);
   //绘制弧形
   g2.draw(arc);
   g2.setPaint(paint);
   
   //取得弧形的开始点
   Point2D p1 = arc.getStartPoint();

   // 定义多边形(弧形的高度组成的图形)
   xs = new int[] { (int) arc.getCenterX(), (int) arc.getCenterX(),
     (int) p1.getX(), (int) p1.getX() };
   ys = new int[] { (int) arc.getCenterY(),
     (int) arc.getCenterY() - depth, (int) p1.getY() - depth,
     (int) p1.getY() };   
   Polygon polygon = new Polygon(
     xs, //多边形x坐标点的数组
     ys, //多边形y坐标点的数组
     4 //数组大小
     );
   g2.setPaint(java.awt.Color.lightGray);
   g2.fill(polygon);
   g2.setPaint(outlinePaint);
   g2.setStroke(outlineStroke);
   //绘制该多边形
   g2.draw(polygon);
   g2.setPaint(paint);

  }

  g2.setPaint(Color.gray);
  g2.fill(back);
  g2.fill(front);

  // cycle through once drawing only the sides at the back...
  // 描出背部的边
  int cat = 0;
  iterator = arcList.iterator();
  while (iterator.hasNext()) {
   Arc2D segment = (Arc2D) iterator.next();
   if (segment != null) {
    paint = getSectionPaint(cat);
    outlinePaint = getSectionOutlinePaint(cat);
    outlineStroke = getSectionOutlineStroke(cat);
    drawSide(g2, pieArea, segment, front, back, paint,
      outlinePaint, outlineStroke, false, true);
   }
   cat++;
  }

  // cycle through again drawing only the sides at the front...
  // 描出前面的边
  cat = 0;
  iterator = arcList.iterator();
  while (iterator.hasNext()) {
   Arc2D segment = (Arc2D) iterator.next();
   if (segment != null) {
    paint = getSectionPaint(cat);
    outlinePaint = getSectionOutlinePaint(cat);
    outlineStroke = getSectionOutlineStroke(cat);
    drawSide(g2, pieArea, segment, front, back, paint,
      outlinePaint, outlineStroke, true, false);
   }
   cat++;
  }

  g2.setClip(oldClip);

  // 画出3D饼图上部的椭圆的弧形和相关的标签链接和底部的说明(tooltip)
  Arc2D upperArc;
  for (int sectionIndex = 0; sectionIndex < categoryCount; sectionIndex++) {
   //取出弧形
   arc = (Arc2D.Double) arcList.get(sectionIndex);
   if (arc == null) {
    continue;
   }
   //定义3D饼图上部的椭圆的弧形
   upperArc = new Arc2D.Double(arcX, arcY, pieArea.getWidth(), pieArea
     .getHeight()
     - depth,
     arc.getAngleStart(), //开始角度
     arc.getAngleExtent(), //角度大小
     Arc2D.PIE);
   //g2图形对象所需的油漆桶
   paint = getSectionPaint(sectionIndex);
   //g2图形对象所需的轮廓油漆桶
   outlinePaint = getSectionOutlinePaint(sectionIndex);
   //g2图形对象所需的轮廓样式
   outlineStroke = getSectionOutlineStroke(sectionIndex);
   g2.setPaint(paint);
   //往g2图形对象中填充弧形
   g2.fill(upperArc);
   g2.setStroke(outlineStroke);
   g2.setPaint(outlinePaint);
   //绘制弧形
   g2.draw(upperArc);

   // 为该部分弧形添加说明栏(tooltip)和url链接
   Comparable currentKey = (Comparable) sectionKeys.get(sectionIndex);
   if (info != null) {
    EntityCollection entities = info.getOwner()
      .getEntityCollection();
    if (entities != null) {
     String tip = null;
     PieToolTipGenerator tipster = getToolTipGenerator();
     if (tipster != null) {
      // @mgs: using the method's return value was missing
      tip = tipster.generateToolTip(dataset, currentKey);
     }
     String url = null;
     if (getURLGenerator() != null) {
      url = getURLGenerator().generateURL(dataset,
        currentKey, getPieIndex());
     }
     PieSectionEntity entity = new PieSectionEntity(upperArc,
       dataset, getPieIndex(), sectionIndex, currentKey,
       tip, url);
     entities.add(entity);
    }
   }
   
   List keys = dataset.getKeys();
   //绘制标签的长方形
   Rectangle2D adjustedPlotArea = new Rectangle2D.Double(
     originalPlotArea.getX(), originalPlotArea.getY(),
     originalPlotArea.getWidth(), originalPlotArea.getHeight()
       - depth);
   //绘制标签(如:Perl=1的Textbox)
   drawLabels(g2, keys, totalValue, adjustedPlotArea, linkArea, state);
  }

  g2.setClip(savedClip);
  g2.setComposite(originalComposite);
  //绘制轮廓
  drawOutline(g2, originalPlotArea);
 }
 
4.3D柱状图的绘制函数(现在的注释还不够全面,也可能存在错误)
    /**
     * Draws a 3D bar to represent one data item.
     *
     * @param g2  the graphics device.
     * @param state  the renderer state.
     * @param dataArea  the area for plotting the data.
     * @param plot  the plot.
     * @param domainAxis  the domain axis.
     * @param rangeAxis  the range axis.
     * @param dataset  the dataset.
     * @param row  the row index (zero-based).
     * @param column  the column index (zero-based).
     * @param pass  the pass index.
     */
    public void drawItem(Graphics2D g2,
                         CategoryItemRendererState state,
                         Rectangle2D dataArea,
                         CategoryPlot plot,
                         CategoryAxis domainAxis,
                         ValueAxis rangeAxis,
                         CategoryDataset dataset,
                         int row,
                         int column,
                         int pass) {
   
        // check the value we are plotting...
        Number dataValue = dataset.getValue(row, column);
        if (dataValue == null) {
            return;
        }
       
        double value = dataValue.doubleValue();
       
        Rectangle2D adjusted = new Rectangle2D.Double(
            dataArea.getX(),
            dataArea.getY() + getYOffset(),
            dataArea.getWidth() - getXOffset(),
            dataArea.getHeight() - getYOffset()
        );

        PlotOrientation orientation = plot.getOrientation();
       
        double barW0 = calculateBarW0(
            plot, orientation, adjusted, domainAxis, state, row, column
        );
        double[] barL0L1 = calculateBarL0L1(value);
        if (barL0L1 == null) {
            return;  // the bar is not visible
        }

        RectangleEdge edge = plot.getRangeAxisEdge();
        double transL0 = rangeAxis.valueToJava2D(barL0L1[0], adjusted, edge);
        double transL1 = rangeAxis.valueToJava2D(barL0L1[1], adjusted, edge);
        double barL0 = Math.min(transL0, transL1);
        double barLength = Math.abs(transL1 - transL0);
       
        // draw the bar...
        //柱子的正视图
        Rectangle2D bar = null;
        if (orientation == PlotOrientation.HORIZONTAL) {
            bar = new Rectangle2D.Double(
                barL0, barW0, barLength, state.getBarWidth()
            );
        }
        else {
            bar = new Rectangle2D.Double(
                barW0, barL0, state.getBarWidth(), barLength
            );
        }
        Paint itemPaint = getItemPaint(row, column);
        g2.setPaint(itemPaint);
        g2.fill(bar);

        // 柱子的俯视图上的四个点的x坐标值
        double x0 = bar.getMinX();
        double x1 = x0 + getXOffset(); //x0+12
        double x2 = bar.getMaxX();
        double x3 = x2 + getXOffset(); //x2+12
        // 柱子的右视图上的四个点的y坐标值
        double y0 = bar.getMinY() - getYOffset(); //正视图的最小y值-8
        double y1 = bar.getMinY();
        double y2 = bar.getMaxY() - getYOffset(); //正视图的最大y值-8
        double y3 = bar.getMaxY();
       
        GeneralPath bar3dRight = null;
        GeneralPath bar3dTop = null;
        // 柱子的右视图
        if (barLength > 0.0) {
            bar3dRight = new GeneralPath();
            bar3dRight.moveTo((float) x2, (float) y3);
            bar3dRight.lineTo((float) x2, (float) y1);
            bar3dRight.lineTo((float) x3, (float) y0);
            bar3dRight.lineTo((float) x3, (float) y2);
            bar3dRight.closePath();

            if (itemPaint instanceof Color) {
                g2.setPaint(((Color) itemPaint).darker());
            }
            g2.fill(bar3dRight);
        }
        // 柱子的俯视图
        bar3dTop = new GeneralPath();
        bar3dTop.moveTo((float) x0, (float) y1);
        bar3dTop.lineTo((float) x1, (float) y0);
        bar3dTop.lineTo((float) x3, (float) y0);
        bar3dTop.lineTo((float) x2, (float) y1);
        bar3dTop.closePath();
        g2.fill(bar3dTop);

        //绘制3D柱状图
        if (isDrawBarOutline()
                && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
            g2.setStroke(getItemOutlineStroke(row, column));
            g2.setPaint(getItemOutlinePaint(row, column));
            g2.draw(bar);
            if (bar3dRight != null) {
                g2.draw(bar3dRight);
            }
            if (bar3dTop != null) {
                g2.draw(bar3dTop);
            }
        }

        //绘制标签
        CategoryItemLabelGenerator generator
            = getItemLabelGenerator(row, column);
        if (generator != null && isItemLabelVisible(row, column)) {
            drawItemLabel(
                g2, dataset, row, column, plot, generator, bar, (value < 0.0)
            );
        }       

        // add an item entity, if this information is being collected
        EntityCollection entities = state.getEntityCollection();
        if (entities != null) {
            GeneralPath barOutline = new GeneralPath();
            barOutline.moveTo((float) x0, (float) y3);
            barOutline.lineTo((float) x0, (float) y1);
            barOutline.lineTo((float) x1, (float) y0);
            barOutline.lineTo((float) x3, (float) y0);
            barOutline.lineTo((float) x3, (float) y2);
            barOutline.lineTo((float) x2, (float) y3);
            barOutline.closePath();
            addItemEntity(entities, dataset, row, column, barOutline);
        }

    }

posted on 2006-05-12 15:22 JGAO编程随笔 阅读(1471) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
<2006年5月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

常用链接

留言簿(1)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜