【Java/Graphics】Graphics2D绘制直方图例子


先上图:

代码:

package graphics;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

class Bar{
    String name;
    int value;
    
    public Bar(String name,int value) {
        this.name=name;
        this.value=value;
    }
}
/**
 * 直方图生成器
 * @author ufo
 * 2022年1月31日
 */
public class BarchartMaker {
    // 图片宽度
    private int width;
    
    // 图片高度
    private int height;
    
    // img对象
    private BufferedImage img;
    
    // 绘图环境
    private Graphics2D g2d;
    
    // 垂直方向起点
    private int yStart;
    
    // 垂直方向终点
    private int yEnd;
    
    // 直方图数据
    private List bars;
    
    // 构造函数
    public BarchartMaker(int width,int height,int yStart,int yEnd){
        this.width=width;
        this.height=height;
        this.img=new BufferedImage(this.width,this.height,BufferedImage.TYPE_INT_RGB);
        this.g2d=(Graphics2D)img.getGraphics();
        this.yStart=yStart;
        this.yEnd=yEnd;
    }
    
    // 添加一项直方图数据
    public void addBar(String name,int value) {
        if(bars==null) {
            bars=new ArrayList();
        }
        
        bars.add(new Bar(name,value));
    }

    // 重置屏幕坐标系为笛卡尔坐标系
    private void resetCoodinate() {
        AffineTransform trans = new AffineTransform();
        trans.translate(0,this.height-this.yStart);
        trans.rotate(getRad(180.0),0,0);
        trans.scale(-1,1);        
        this.g2d.setTransform(trans);
    }
    
    // 绘制图案
    public void draw() {
        resetCoodinate();
        
        // 设置背景为天蓝色
        g2d.setColor(new Color(135,206,235));
        g2d.fillRect(0, -this.yStart, this.width, this.height);
        
        final int yMax=this.yEnd;
        final int barCnt=this.bars.size();
        
        // --往下是竖向网格线
        final float stepx=this.width/barCnt;
        final float CW=stepx/3;// CW:Column Width

        // LINE_TYPE_DASHED   
        Stroke dashed=new BasicStroke(1,BasicStroke.CAP_BUTT,   
                                                  BasicStroke.JOIN_BEVEL,   0,   
                                                  new   float[]{16,   4},   0);
        
        g2d.setColor(Color.gray);
        
        for(int i=0;i) {
            float x=i*stepx;
            float y=yMax;
            
            g2d.setStroke(new BasicStroke(1.0f));
            g2d.drawLine((int)x, 0, (int)x, (int)y);
            
            g2d.setStroke(dashed);
            g2d.drawLine((int)(x+CW), 0, (int)(x+CW), (int)y);
            g2d.drawLine((int)(x+2*CW), 0, (int)(x+2*CW), (int)y);
        }
        
        // 以最高点定比例
        float maxCnt=-1;
        for(Bar b:bars) {
            if(b.value>maxCnt) {
                maxCnt=b.value;
            }
        }
        final float ratio=yMax/maxCnt;
        
        // --往下是画横向网格线
        final float stepy=yMax/barCnt;
        final float GH=stepy/3;// GH:Grid Width
        
        for(int i=0;i<=barCnt;i++){
            float y=i*stepy;
            
            g2d.setStroke(new BasicStroke(1.0f));
            g2d.drawLine(0,(int)y, this.width, (int)y);
            
            g2d.setFont(new Font("宋体",Font.BOLD,16));
            g2d.setColor(Color.black);
            int yValue=(int)(y*maxCnt/yMax);
            putString(g2d,yValue+"",15,(int)y);
            
            if(i>0) {
                g2d.setStroke(dashed);
                g2d.drawLine(0,(int)(y-GH), this.width, (int)(y-GH));
                g2d.drawLine(0,(int)(y-2*GH), this.width, (int)(y-2*GH));
            }
        }
        
        // --往下是画柱状图
        for(int i=0;i<this.bars.size();i++){
            Bar bar=this.bars.get(i);
            
            float x=i*stepx+(CW);
            float y=0;
            float w=CW;
            float h=bar.value*ratio;
            
            g2d.setColor(getColor(i));
            g2d.fillRect((int)x, (int)y, (int)(w), (int)(h));
            
            // 在柱子顶写文字
            g2d.setFont(new Font("宋体",Font.BOLD,16));
            g2d.setColor(Color.black);
            putString(g2d,bar.name+"="+bar.value,(int)(x+CW/2),(int)(h-15));
        }
        
        // 写标题
        g2d.setFont(new Font("宋体",Font.BOLD,36));
        g2d.setColor(Color.black);
        putString(g2d,"g2d绘制直方图示例",this.width/2,this.yEnd+50);
        
        // 写作者
        g2d.setFont(new Font("宋体",Font.BOLD,12));
        g2d.setColor(Color.black);
        putString(g2d,"逆火绘制于2022年1月31日",this.width-100,-25);

        g2d.dispose();// g2d使命完成
    }
    
    // 写入图片
    public void write2File(String path) {
        try {
            ImageIO.write(img, "PNG", new FileOutputStream(path));
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
    
    // 写文字
    private void putString(Graphics2D g2d,String text,int x,int y) {
        AffineTransform previousTrans = g2d.getTransform();
        
        AffineTransform newtrans = new AffineTransform();

        FontMetrics fm2=g2d.getFontMetrics();
        int textWidth=fm2.stringWidth(text);
        
        newtrans.translate(x-textWidth/2, (this.height-this.yStart)-y);
        
        g2d.setTransform(newtrans);
        g2d.drawString(text,0,0);
        
        g2d.setTransform(previousTrans);
    }
    
    // 传入度数,返回弧度
    private static double getRad(double degree) {
        return degree*Math.PI/180.0f;
    }
    
    // 取一种颜色
    private static Color getColor(int idx) {
        Color[] colors= {Color.red,Color.yellow,Color.blue,Color.magenta,Color.green,Color.orange,Color.cyan};
        
        int i=idx % colors.length;
        return colors[i];
    }
    
    public static void main(String[] args) {
        BarchartMaker pm=new BarchartMaker(1200,960,50,800);
        pm.addBar("勇气", 80);
        pm.addBar("毅力", 120);
        pm.addBar("果敢", 450);
        pm.addBar("机敏", 32);
        pm.addBar("决心", 360);
        pm.addBar("明智", 230);
        pm.addBar("忍耐", 420);
        
        pm.draw();
        
        pm.write2File("c:\\hy\\4.png");
        System.out.println("直方图做成");
    }
}

谨以以上代码纪念即将逝去的牛年,愿各位读者在新年里都健康多福!

2022年1月31日19点44分

END

相关