Java:D2D实现绘制简单的直方图片

Java:D2D实现绘制简单的直方图片_第1张图片

class Bar {
    String name;
    int value;

    public Bar(String name,int value) {
        this.name=name;
        this.value=value;
    }
}
class Point{
    public Point(float x,float y) {
        this.x=x;
        this.y=y;
    }
    float x;
    float y;
}
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.imageio.ImageIO;


/****
 *** author:lao
 *** name:LineChartMaker
 *** date:2024/1/30  16:29
 *** filename:Main
 *** desc:折线图生成器
 ***/
public class LineChartMaker {
    // 图片宽度
    private int width;
    // 图片高度
    private int height;
    // img对象
    private BufferedImage img;
    // 绘图环境
    private Graphics2D g2d;
    // 垂直方向起点
    private int yStart;
    // 垂直方向终点
    private int yEnd;
    // 直方图数据列表
    private List<Bar> bars;

    // 构造函数
    public LineChartMaker(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<Bar>();
        }

        bars.add(new Bar(name, value));
    }

    // 重置屏幕坐标系为笛卡尔坐标系
    private void resetCoordinate() {
        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() {
        //消除线条锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        resetCoordinate();

        // 设置背景为天蓝色
        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 < barCnt; 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));
            }
        }

        List<Point> points = new ArrayList<>();

        // --往下是画柱状图
        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));

            // 记录折线端点
            float lx = x + CW / 2;
            float ly = y + h;
            points.add(new Point(lx, ly));

            // 在柱子顶写文字
            g2d.setFont(new Font("宋体",Font.BOLD,16));
            g2d.setColor(Color.black);
            putString(g2d,bar.name+"="+bar.value,(int)(x+CW/2),(int)(h-15));
        }

        // 画折线
        for(int i = 0; i < points.size() - 1; i++) {
            Point p1 = points.get(i);
            Point p2 = points.get(i+1);

            g2d.setColor(Color.black);
            g2d.setStroke(new BasicStroke(2.0f));
            g2d.drawLine((int)p1.x,(int)p1.y, (int)p2.x, (int)p2.y);
        }

        // 写标题
        g2d.setFont(new Font("宋体",Font.BOLD,36));
        g2d.setColor(Color.black);
        putString(g2d,"高中科目成绩",this.width / 2,this.yEnd+50);

        // 写作者
        g2d.setFont(new Font("宋体",Font.BOLD,12));
        g2d.setColor(Color.black);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format(new Date());
        System.out.println(time);
        putString(g2d,"绘制于" + time,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) {
        LineChartMaker pm = new LineChartMaker(1200 ,960 ,50 ,800);
        pm.addBar("语文", 150);
        pm.addBar("数学", 146);
        pm.addBar("英语", 130);
        pm.addBar("物理", 92);
        pm.addBar("化学", 89);
        pm.addBar("生物", 94);
        pm.addBar("历史", 90);
        pm.addBar("政治", 98);
        pm.draw();
        //图片不存位置
        pm.write2File("E:\\test.png");
        System.out.println("折线图已经已经生成");
    }
}

你可能感兴趣的:(JavaFx,java,python,开发语言)