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


    先上图:

    代码:

    package graphics.line;
    
    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    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;
        }
    }
    
    class Point{
        public Point(float x,float y) {
            this.x=x;
            this.y=y;
        }
        float x;
        float y;
    }
    /**
     * 折线图生成器
     * @author ufo
     * 2022年2月1日
     * 转眼间一年又过去了
     */
    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 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() {
            //消除线条锯齿  
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
            
            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<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,"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) {
            LinechartMaker pm=new LinechartMaker(1200,960,50,800);
            pm.addBar("勇气", 800);
            pm.addBar("毅力", 120);
            pm.addBar("果敢", 450);
            pm.addBar("机敏", 320);
            pm.addBar("决心", 360);
            pm.addBar("明智", 230);
            pm.addBar("忍耐", 420);
            pm.addBar("实干", 900);
            
            pm.draw();
            
            pm.write2File("c:\\hy\\5.png");
            System.out.println("折线图做成");
        }
    }

    END

  • 相关阅读:
    如何提高IT团队的执行力?
    Internet Explorer 安全区域注册表项说明
    用C#编写ActiveX控件(一) 转载
    用C#编写ActiveX控件(二) 转载
    关于《用C#编写ActiveX控件》的几点说明 转载
    【经典】单调栈+离线+线段树区间更新——求所有子区间gcd之和 icpc cerc 2019 b
    SQL语句
    Windows 程序设计学习记录(1)类的定义和应用
    Windows 程序设计学习记录(2)数据链表删除,增加的算法
    推荐一些博客网站
  • 原文地址:https://www.cnblogs.com/heyang78/p/15858853.html
Copyright © 2020-2023  润新知