• JFreeChart(一)


    package com.supcon.honcomb.basearchives.entity;

    import java.awt.AlphaComposite;
    import java.awt.Color;
    import java.awt.Composite;
    import java.awt.Graphics2D;
    import java.awt.Paint;
    import java.awt.Polygon;
    import java.awt.Rectangle;
    import java.awt.Shape;
    import java.awt.Stroke;
    import java.awt.font.FontRenderContext;
    import java.awt.font.LineMetrics;
    import java.awt.geom.AffineTransform;
    import java.awt.geom.Arc2D;
    import java.awt.geom.Ellipse2D;
    import java.awt.geom.Line2D;
    import java.awt.geom.Point2D;
    import java.awt.geom.Rectangle2D;
    import java.text.NumberFormat;

    import org.jfree.chart.entity.CategoryItemEntity;
    import org.jfree.chart.entity.EntityCollection;
    import org.jfree.chart.plot.PlotRenderingInfo;
    import org.jfree.chart.plot.PlotState;
    import org.jfree.chart.plot.SpiderWebPlot;
    import org.jfree.data.category.CategoryDataset;
    import org.jfree.data.general.DatasetUtilities;
    import org.jfree.ui.RectangleInsets;
    import org.jfree.util.TableOrder;

    /**
     * 刻度蜘蛛环图
     *
     * @author 成尚謙 lhx222@gmail.com
     * @since 2011-09-14
     * @version 1.0
     */
    public class CalibrationSpiderWebPlot extends SpiderWebPlot {
     private static final long serialVersionUID = -11L;
     private NumberFormat format = NumberFormat.getInstance();
     private static final double PERPENDICULAR = 90;
     private static final double TICK_SCALE = 0.015;
     private int valueLabelGap = DEFAULT_GAP;
     private static final int DEFAULT_GAP = 10;
     private static final double THRESHOLD = 15;
     public static final int DEFAULT_TICKS = 5; // 刻度数
     public static final double DEFAULT_MAX_VALUE = 100; // 坐标最大值
     public static final boolean DEFAULT_DRAW_RING = true; // 画换默认值

     /**
      * 刻度数/环数
      */
     private int ticks = DEFAULT_TICKS;

     /**
      * 画环
      */
     private boolean drawRing = false;

     /**
      * 刻度前缀
      */
     private String lablePrefix = "";

     /**
      * 刻度后缀
      */
     private String lableSuffix = "";

     /**
      * 默认坐标最大值和画环
      *
      * @param createCategoryDataset
      */
     public CalibrationSpiderWebPlot(CategoryDataset createCategoryDataset) {
      this(createCategoryDataset, DEFAULT_MAX_VALUE); // 设置坐标最大值为默认的值
     }

     /**
      * 默认画环,与刻度数
      *
      * @param createCategoryDataset
      * @param maxValue
      */
     public CalibrationSpiderWebPlot(CategoryDataset createCategoryDataset,
       double maxValue) {
      this(createCategoryDataset, maxValue, DEFAULT_DRAW_RING); // 设置画换默认值
     }

     /**
      * 自定义坐标最大值和画环
      *
      * @param createCategoryDataset
      * @param maxValue
      * @param drawRing
      */
     public CalibrationSpiderWebPlot(CategoryDataset createCategoryDataset,
       double maxValue, boolean drawRing) {
      this(createCategoryDataset, maxValue, drawRing, DEFAULT_TICKS);// 设置刻度数默认值
     }

     /**
      * 自定义坐标最大值和画环、刻度数
      *
      * @param createCategoryDataset
      * @param maxValue
      * @param drawRing
      */
     public CalibrationSpiderWebPlot(CategoryDataset createCategoryDataset,
       double maxValue, boolean drawRing, int ticks) {
      this(createCategoryDataset, maxValue, drawRing, ticks, "");// 设置刻度前缀默认值
     }

     /**
      * 自定义坐标最大值和画环以及刻度前缀、刻度数
      *
      * @param createCategoryDataset
      * @param maxValue
      * @param drawRing
      */
     public CalibrationSpiderWebPlot(CategoryDataset createCategoryDataset,
       double maxValue, boolean drawRing, int ticks, String lablePrefix) {
      this(createCategoryDataset, maxValue, drawRing, ticks, lablePrefix, "");
      ;// 设置刻度后缀默认值
     }

     /**
      * 自定义坐标最大值和画环以及刻度前/后缀、刻度数
      *
      * @param createCategoryDataset
      * @param maxValue
      * @param drawRing
      */
     public CalibrationSpiderWebPlot(CategoryDataset createCategoryDataset,
       double maxValue, boolean drawRing, int ticks, String lablePrefix,
       String lableSuffix) {
      super(createCategoryDataset);
      this.setMaxValue(maxValue);// 设置坐标最大值
      this.setDrawRing(drawRing);// 设置画换
      // this.setTicks(ticks);//设置刻度数
      this.setLablePrefix(lablePrefix);// 刻度前缀
      this.setLableSuffix(lableSuffix);// 刻度后缀
     }

     /**
      * 画图,支持添加圆环
      *
      * @param g2
      *            the graphics device.
      * @param area
      *            the area within which the plot should be drawn.
      * @param anchor
      *            the anchor point (<code>null</code> permitted).
      * @param parentState
      *            the state from the parent plot, if there is one.
      * @param info
      *            collects info about the drawing.
      */
     public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
       PlotState parentState, PlotRenderingInfo info) {

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

      if (info != null) {
       info.setPlotArea(area);
       info.setDataArea(area);
      }

      drawBackground(g2, area);
      drawOutline(g2, area);

      Shape savedClip = g2.getClip();

      g2.clip(area);
      Composite originalComposite = g2.getComposite();
      g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
        getForegroundAlpha()));

      if (!DatasetUtilities.isEmptyOrNull(this.getDataset())) {
       int seriesCount = 0, catCount = 0;

       if (this.getDataExtractOrder() == TableOrder.BY_ROW) {
        seriesCount = this.getDataset().getRowCount();
        catCount = this.getDataset().getColumnCount();
       } else {
        seriesCount = this.getDataset().getColumnCount();
        catCount = this.getDataset().getRowCount();
       }

       // ensure we have a maximum value to use on the axes
       if (this.getMaxValue() == DEFAULT_MAX_VALUE)
        calculateMaxValue(seriesCount, catCount);

       // Next, setup the plot area

       // adjust the plot area by the interior spacing value

       double gapHorizontal = area.getWidth() * getInteriorGap();
       double gapVertical = area.getHeight() * getInteriorGap();

       double X = area.getX() + gapHorizontal / 2;
       double Y = area.getY() + gapVertical / 2;
       double W = area.getWidth() - gapHorizontal;
       double H = area.getHeight() - gapVertical;

       double headW = area.getWidth() * this.headPercent;
       double headH = area.getHeight() * this.headPercent;

       // make the chart area a square
       double min = Math.min(W, H) / 2;
       X = (X + X + W) / 2 - min;
       Y = (Y + Y + H) / 2 - min;
       W = 2 * min;
       H = 2 * min;

       Point2D centre = new Point2D.Double(X + W / 2, Y + H / 2);
       Rectangle2D radarArea = new Rectangle2D.Double(X, Y, W, H);

       // draw the axis and category label
       for (int cat = 0; cat < catCount; cat++) {
        double angle = getStartAngle()
          + (getDirection().getFactor() * cat * 360 / catCount);

        // 如果只有两个分类,设置固定角度
        if (catCount == 2 && cat == 1) {
         angle = 0;
        }

        Point2D endPoint = getWebPoint(radarArea, angle, 1);
        // 1 = end of axis
        Line2D line = new Line2D.Double(centre, endPoint);
        g2.setPaint(this.getAxisLinePaint());
        g2.setStroke(this.getAxisLineStroke());
        g2.draw(line);
        drawLabel(g2, radarArea, 0.0, cat, angle, 360.0 / catCount);
       }

       // 画环
       if (this.isDrawRing()) {
        Point2D topPoint = getWebPoint(radarArea, 90, 1);// 以90度为轴心,计算各个圆环的x、y坐标
        double topPointR = centre.getY() - topPoint.getY();// 轴心顶点圆的半径
        double step = topPointR / this.getTicks();// 每个刻度的半径长

        for (int p = this.getTicks(); p >= 1; p--) {
         double r = p * step;
         double upperLeftX = centre.getX() - r;
         double upperLeftY = centre.getY() - r;
         double d = 2 * r;
         Ellipse2D ring = new Ellipse2D.Double(upperLeftX,
           upperLeftY, d, d);
         g2.setPaint(Color.WHITE);
         g2.draw(ring);
        }
       }

       // Now actually plot each of the series polygons..
       for (int series = 0; series < seriesCount; series++) {
        drawRadarPoly(g2, radarArea, centre, info, series, catCount,
          headH, headW);
       }
      } else {
       drawNoDataMessage(g2, area);
      }
      g2.setClip(savedClip);
      g2.setComposite(originalComposite);
      drawOutline(g2, area);
     }

     /**
      * 增加刻度
      */
     /*
      * @Override protected void drawLabel(final Graphics2D g2, final Rectangle2D
      * plotArea, final double value, final int cat, final double startAngle,
      * final double extent) { super.drawLabel(g2, plotArea, value, cat,
      * startAngle, extent); final FontRenderContext frc =
      * g2.getFontRenderContext(); final double[] transformed = new double[2];
      * final double[] transformer = new double[2]; final Arc2D arc1 = new
      * Arc2D.Double(plotArea, startAngle, 0, Arc2D.OPEN);
      *//**
      * 设置默认值
      */
     /*
      * if(ticks <= 0){ ticks = DEFAULT_TICKS; }
      *
      * for (int i = 1; i <= ticks; i++) {
      *
      * final Point2D point1 = arc1.getEndPoint();
      *
      * final double deltaX = plotArea.getCenterX(); final double deltaY =
      * plotArea.getCenterY(); double labelX = point1.getX() - deltaX; double
      * labelY = point1.getY() - deltaY;
      *
      * final double scale = ((double) i / (double) ticks); final AffineTransform
      * tx = AffineTransform.getScaleInstance(scale, scale); final
      * AffineTransform pointTrans = AffineTransform.getScaleInstance(scale +
      * TICK_SCALE, scale + TICK_SCALE); transformer[0] = labelX; transformer[1]
      * = labelY; pointTrans.transform(transformer, 0, transformed, 0, 1); final
      * double pointX = transformed[0] + deltaX; final double pointY =
      * transformed[1] + deltaY; tx.transform(transformer, 0, transformed, 0, 1);
      * labelX = transformed[0] + deltaX; labelY = transformed[1] + deltaY;
      *
      * double rotated = (PERPENDICULAR);
      *
      * AffineTransform rotateTrans =
      * AffineTransform.getRotateInstance(Math.toRadians(rotated), labelX,
      * labelY); transformer[0] = pointX; transformer[1] = pointY;
      * rotateTrans.transform(transformer, 0, transformed, 0, 1); final double x1
      * = transformed[0]; final double y1 = transformed[1];
      *
      * rotated = (-PERPENDICULAR); rotateTrans =
      * AffineTransform.getRotateInstance(Math.toRadians(rotated), labelX,
      * labelY);
      *
      * rotateTrans.transform(transformer, 0, transformed, 0, 1);
      *
      * final Composite saveComposite = g2.getComposite();
      * g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
      * 1.0f));
      *
      * g2.draw(new Line2D.Double(transformed[0], transformed[1], x1, y1));
      *
      * if (startAngle == this.getStartAngle()) { String label =
      * format.format(((double) i / (double) ticks) * this.getMaxValue()); final
      * LineMetrics lm = getLabelFont().getLineMetrics(label, frc); final double
      * ascent = lm.getAscent(); if (Math.abs(labelX - plotArea.getCenterX()) <
      * THRESHOLD) { labelX += valueLabelGap; labelY += ascent / (float) 2; }
      * else if (Math.abs(labelY - plotArea.getCenterY()) < THRESHOLD) { labelY
      * += valueLabelGap; } else if (labelX >= plotArea.getCenterX()) { if
      * (labelY < plotArea.getCenterY()) { labelX += valueLabelGap; labelY +=
      * valueLabelGap; } else { labelX -= valueLabelGap; labelY += valueLabelGap;
      * } } else { if (labelY > plotArea.getCenterY()) { labelX -= valueLabelGap;
      * labelY -= valueLabelGap; } else { labelX += valueLabelGap; labelY -=
      * valueLabelGap; } } g2.setPaint(getLabelPaint());
      * g2.setFont(getLabelFont());
      *
      * //添加刻度的前缀和后缀 if(null != this.getLablePrefix() &&
      * !"".equals(this.getLablePrefix())){ label = this.getLablePrefix() +
      * label; } if(null != this.getLableSuffix() &&
      * !"".equals(this.getLableSuffix())){ label = label +
      * this.getLableSuffix(); }
      *
      * g2.drawString(label, (float) labelX, (float) labelY); }
      * g2.setComposite(saveComposite); } }
      */

     /**
      * Draws a radar plot polygon. 如果只有两个分类,设置固定角度
      *
      * @param g2
      *            the graphics device.
      * @param plotArea
      *            the area we are plotting in (already adjusted).
      * @param centre
      *            the centre point of the radar axes
      * @param info
      *            chart rendering info.
      * @param series
      *            the series within the dataset we are plotting
      * @param catCount
      *            the number of categories per radar plot
      * @param headH
      *            the data point height
      * @param headW
      *            the data point width
      */
     protected void drawRadarPoly(Graphics2D g2, Rectangle2D plotArea,
       Point2D centre, PlotRenderingInfo info, int series, int catCount,
       double headH, double headW) {

      Polygon polygon = new Polygon();

      EntityCollection entities = null;
      if (info != null) {
       entities = info.getOwner().getEntityCollection();
      }

      // plot the data...
      for (int cat = 0; cat < catCount; cat++) {

       Number dataValue = getPlotValue(series, cat);

       if (dataValue != null) {
        double value = dataValue.doubleValue();

        if (value >= 0) { // draw the polygon series...

         // Finds our starting angle from the centre for this axis

         double angle = getStartAngle()
           + (getDirection().getFactor() * cat * 360 / catCount);

         // 如果只有两个分类,设置固定角度
         if (catCount == 2 && cat == 1) {
          angle = 0;
         }

         // The following angle calc will ensure there isn't a top
         // vertical axis - this may be useful if you don't want any
         // given criteria to 'appear' move important than the
         // others..
         // + (getDirection().getFactor()
         // * (cat + 0.5) * 360 / catCount);

         // find the point at the appropriate distance end point
         // along the axis/angle identified above and add it to the
         // polygon

         Point2D point = getWebPoint(plotArea, angle, value
           / this.getMaxValue());
         polygon.addPoint((int) point.getX(), (int) point.getY());

         // put an elipse at the point being plotted..

         Paint paint = getSeriesPaint(series);
         Paint outlinePaint = getSeriesOutlinePaint(series);
         Stroke outlineStroke = getSeriesOutlineStroke(series);

         Ellipse2D head = new Ellipse2D.Double(point.getX() - headW
           / 2, point.getY() - headH / 2, headW, headH);
         g2.setPaint(paint);
         g2.fill(head);
         g2.setStroke(outlineStroke);
         g2.setPaint(outlinePaint);
         g2.draw(head);

         if (entities != null) {
          int row = 0;
          int col = 0;
          if (this.getDataExtractOrder() == TableOrder.BY_ROW) {
           row = series;
           col = cat;
          } else {
           row = cat;
           col = series;
          }
          String tip = null;
          if (this.getToolTipGenerator() != null) {
           tip = this.getToolTipGenerator().generateToolTip(
             this.getDataset(), row, col);
          }

          String url = null;
          if (this.getURLGenerator() != null) {
           url = this.getURLGenerator().generateURL(
             this.getDataset(), row, col);
          }

          Shape area = new Rectangle(
            (int) (point.getX() - headW), (int) (point
              .getY() - headH), (int) (headW * 2),
            (int) (headH * 2));
          CategoryItemEntity entity = new CategoryItemEntity(
            area, tip, url, this.getDataset(), this
              .getDataset().getRowKey(row), this
              .getDataset().getColumnKey(col));
          entities.add(entity);
         }

        }
       }
      }
      // Plot the polygon

      Paint paint = getSeriesPaint(series);
      g2.setPaint(paint);
      g2.setStroke(getSeriesOutlineStroke(series));
      g2.draw(polygon);

      // Lastly, fill the web polygon if this is required

      if (this.isWebFilled()) {
       g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
         0.1f));
       g2.fill(polygon);
       g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
         getForegroundAlpha()));
      }
     }

     /**
      *获取分类的最大值
      *
      * @param seriesCount
      *            the number of series
      * @param catCount
      *            the number of categories
      */
     private void calculateMaxValue(int seriesCount, int catCount) {
      double v = 0;
      Number nV = null;

      for (int seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
       for (int catIndex = 0; catIndex < catCount; catIndex++) {
        nV = getPlotValue(seriesIndex, catIndex);
        if (nV != null) {
         v = nV.doubleValue();
         if (v > this.getMaxValue()) {
          this.setMaxValue(v);
         }
        }
       }
      }
     }

     public String getLablePrefix() {
      return lablePrefix;
     }

     public void setLablePrefix(String lablePrefix) {
      this.lablePrefix = lablePrefix;
     }

     public String getLableSuffix() {
      return lableSuffix;
     }

     public void setLableSuffix(String lableSuffix) {
      this.lableSuffix = lableSuffix;
     }

     public boolean isDrawRing() {
      return drawRing;
     }

     public void setDrawRing(boolean drawRing) {
      this.drawRing = drawRing;
     }

     public int getTicks() {
      return ticks;
     }

     public void setTicks(int ticks) {
      this.ticks = ticks;
     }
    }

  • 相关阅读:
    几个 vim 的块操作命令
    图灵社区 : 阅读 : 谁说Vim不是IDE?(三)
    google.sg
    Vim 配置详解_wuyang
    Vim 配置详解_wuyang
    不忘本~结构
    刚刚做了一个菜单导航变亮的效果,共享一下吧!
    不忘本~静态构造函数
    数据结构~时间复杂度和空间复杂度
    数据结构~在页面上渲染树型结构
  • 原文地址:https://www.cnblogs.com/winkey4986/p/2721176.html
Copyright © 2020-2023  润新知